mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 17:16:51 +00:00
Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eab051f5e6 | ||
| e058302a08 | |||
|
|
efcf3a1d2d | ||
|
|
1f0d5878b1 | ||
|
|
f09a37a941 | ||
|
|
a7562eb2be | ||
| a747829ffb | |||
|
|
7db63875d0 | ||
|
|
637c04655a | ||
|
|
9954b939ef | ||
|
|
e65572c2e2 | ||
|
|
b3ddc47cb5 | ||
|
|
4d9e3a71f4 | ||
|
|
21e4f4ee04 | ||
|
|
746746d5b7 | ||
|
|
936566c642 | ||
|
|
d6f557c6f7 | ||
|
|
2d2ea53d16 | ||
|
|
bccd959833 | ||
|
|
240fc17471 | ||
|
|
7b2caac901 | ||
|
|
56aae221e7 | ||
|
|
54255e7b57 | ||
|
|
2cd667fb44 | ||
|
|
145d65ff01 | ||
|
|
8faff0fd1e | ||
|
|
d31ff55b12 | ||
|
|
d4535a34c9 | ||
|
|
ebd2f85f90 | ||
|
|
dce7ef9110 | ||
|
|
780e2989ae | ||
|
|
2661fdf333 | ||
|
|
2557418e81 | ||
|
|
b48e0d0638 | ||
|
|
2c27d83b9e | ||
|
|
8b22585748 | ||
|
|
7ed6975330 | ||
|
|
d5e111238d | ||
| 2733e47af7 | |||
|
|
f9998e7664 | ||
|
|
04286fb2ad | ||
|
|
cd82ee8e4a | ||
|
|
a1f17199d6 | ||
|
|
849ca7cfd6 | ||
|
|
308742a927 | ||
|
|
1a730ef90b | ||
|
|
d59c2ad40b | ||
|
|
3366faece2 | ||
|
|
2bb2875cd7 | ||
|
|
e88403d044 | ||
|
|
11293e8dc1 | ||
|
|
3bcc3d280e | ||
|
|
55587c86f0 | ||
|
|
7cc74795be | ||
|
|
534b4094b5 | ||
|
|
7cd025a023 | ||
|
|
b14a67b601 | ||
|
|
b24409323d | ||
|
|
9ec2716026 | ||
|
|
fa09d940c5 | ||
|
|
d4702b9a9e | ||
|
|
6a3a560857 | ||
|
|
8ee1e84b2e | ||
|
|
7e96a292eb | ||
|
|
d89ada9aad | ||
|
|
59d1a6b1f2 | ||
|
|
1a744a8eb8 | ||
|
|
78100cba00 | ||
|
|
b54ddd4549 | ||
|
|
d42475f2dc | ||
|
|
7cf6c1ab2b | ||
|
|
06b8e3d784 | ||
| 63c22a13cf | |||
|
|
3d5e59a6e5 | ||
|
|
acf377ec60 | ||
| 87c1c7be84 | |||
|
|
5bacd0cf7b | ||
|
|
b1beb49798 | ||
|
|
33b14be516 | ||
|
|
3907f3eb2f | ||
|
|
00d314dcd1 | ||
|
|
9719fef55b | ||
|
|
9b69045a20 | ||
|
|
966ff4229a | ||
|
|
e0c0c2021f | ||
|
|
a3907d11a5 | ||
|
|
b94d19e7b8 | ||
|
|
943ee22aa5 | ||
|
|
b6154a988f | ||
|
|
932871dea9 | ||
|
|
5ec6963398 | ||
|
|
b04323704d | ||
| 38011d51b6 |
62
ChangeLog
62
ChangeLog
@@ -1,3 +1,65 @@
|
||||
User johns
|
||||
Date: Sun Mar 17 15:52:42 CET 2013
|
||||
|
||||
Release Version 0.6.0
|
||||
Adds H264 only hardware decoder for still-pictures.
|
||||
Enable optional VDR-SPU deocder support.
|
||||
|
||||
User anbr
|
||||
Date: Sun Mar 17 15:49:46 CET 2013
|
||||
|
||||
Update german translation.
|
||||
|
||||
User cyril
|
||||
Date: Wed Mar 6 17:05:10 CET 2013
|
||||
|
||||
Adds raise softhddevice video window support.
|
||||
|
||||
User johns
|
||||
Date: Wed Mar 6 10:30:27 CET 2013
|
||||
|
||||
Adds optional only complete mpeg packets support.
|
||||
Fixes text of EAC-3 pass-through setup.
|
||||
Try to start or connect to X11 server with -xx.
|
||||
Try to use HBR (High Bit-Rate) for EAC3.
|
||||
Improved pass-through (PCM+EAC3) support.
|
||||
Support VDR 1.7.36 new build system.
|
||||
Improves VDPAU display preemption handling.
|
||||
Add modifiers to X11 remote key names (from Sibbi).
|
||||
Add compatibility with >=ffmpeg 1.1.
|
||||
Adds PIP (Picture-in-Picture) support.
|
||||
Split mpeg packets in receiver thread.
|
||||
|
||||
User horchi
|
||||
Date: Tue Jan 1 17:58:54 CET 2013
|
||||
|
||||
Adds VDR SeduAtmo Plugin support.
|
||||
|
||||
User johns
|
||||
Date: Tue Jan 1 15:21:28 CET 2013
|
||||
|
||||
Support multiple streams with ScaleVideo.
|
||||
Makes 4:3 and 16:9 display format configurable.
|
||||
Don't use DVB display format.
|
||||
|
||||
User Zoolook
|
||||
Date: Tue Jan 1 12:49:19 CET 2013
|
||||
|
||||
Add support for new vdr ScaleVideo API.
|
||||
|
||||
User johns
|
||||
Date: Tue Jan 1 12:40:12 CET 2013
|
||||
|
||||
Add support for old PES HDTV recording.
|
||||
Disable trickspeed hack, to prevent ffmpeg crash.
|
||||
Makes X11 server arguments configurable.
|
||||
Add german translation.
|
||||
|
||||
User FireFly
|
||||
Date: Sun Nov 18 21:15:50 CET 2012
|
||||
|
||||
Add german translation.
|
||||
|
||||
User johns
|
||||
Date: Thu Nov 15 22:28:55 CET 2012
|
||||
|
||||
|
||||
218
Makefile
218
Makefile
@@ -6,152 +6,183 @@
|
||||
# The official name of this plugin.
|
||||
# This name will be used in the '-P...' option of VDR to load the plugin.
|
||||
# By default the main source file also carries this name.
|
||||
# IMPORTANT: the presence of this macro is important for the Make.config
|
||||
# file. So it must be defined, even if it is not used here!
|
||||
#
|
||||
|
||||
PLUGIN = softhddevice
|
||||
|
||||
### Configuration (edit this for your needs)
|
||||
|
||||
# support alsa audio output module
|
||||
ALSA ?= $(shell pkg-config --exists alsa && echo 1)
|
||||
# support OSS audio output module
|
||||
OSS ?= 1
|
||||
# support VDPAU video output modue
|
||||
VDPAU ?= $(shell pkg-config --exists vdpau && echo 1)
|
||||
# support VA-API video output modue
|
||||
VAAPI ?= $(shell pkg-config --exists libva && echo 1)
|
||||
# screensaver disable/enable
|
||||
SCREENSAVER ?= 1
|
||||
# use ffmpeg libswresample
|
||||
SWRESAMPLE ?= $(shell pkg-config --exists libswresample && echo 1)
|
||||
|
||||
CONFIG := # -DDEBUG #-DOSD_DEBUG # enable debug output+functions
|
||||
#CONFIG += -DSTILL_DEBUG=2 # still picture debug verbose level
|
||||
|
||||
CONFIG += -DAV_INFO -DAV_INFO_TIME=3000 # info/debug a/v sync
|
||||
CONFIG += -DUSE_PIP # PIP support
|
||||
#CONFIG += -DHAVE_PTHREAD_NAME # supports new pthread_setname_np
|
||||
#CONFIG += -DNO_TS_AUDIO # disable ts audio parser
|
||||
#CONFIG += -DUSE_TS_VIDEO # build new ts video parser
|
||||
#CONFIG += -DUSE_MPEG_COMPLETE # support only complete mpeg packets
|
||||
#CONFIG += -DUSE_VDR_SPU # use VDR SPU decoder.
|
||||
|
||||
ifeq ($(ALSA),1)
|
||||
CONFIG += -DUSE_ALSA
|
||||
_CFLAGS += $(shell pkg-config --cflags alsa)
|
||||
LIBS += $(shell pkg-config --libs alsa)
|
||||
endif
|
||||
ifeq ($(OSS),1)
|
||||
CONFIG += -DUSE_OSS
|
||||
endif
|
||||
ifeq ($(VDPAU),1)
|
||||
CONFIG += -DUSE_VDPAU
|
||||
_CFLAGS += $(shell pkg-config --cflags vdpau)
|
||||
LIBS += $(shell pkg-config --libs vdpau)
|
||||
endif
|
||||
ifeq ($(VAAPI),1)
|
||||
CONFIG += -DUSE_VAAPI
|
||||
_CFLAGS += $(shell pkg-config --cflags libva-x11 libva)
|
||||
LIBS += $(shell pkg-config --libs libva-x11 libva)
|
||||
endif
|
||||
ifeq ($(SCREENSAVER),1)
|
||||
CONFIG += -DUSE_SCREENSAVER
|
||||
_CFLAGS += $(shell pkg-config --cflags xcb-screensaver xcb-dpms)
|
||||
LIBS += $(shell pkg-config --libs xcb-screensaver xcb-dpms)
|
||||
endif
|
||||
ifeq ($(SWRESAMPLE),1)
|
||||
CONFIG += -DUSE_SWRESAMPLE
|
||||
_CFLAGS += $(shell pkg-config --cflags libswresample)
|
||||
LIBS += $(shell pkg-config --libs libswresample)
|
||||
endif
|
||||
|
||||
_CFLAGS += $(shell pkg-config --cflags libavcodec x11 x11-xcb xcb xcb-icccm)
|
||||
LIBS += -lrt $(shell pkg-config --libs libavcodec x11 x11-xcb xcb xcb-icccm)
|
||||
|
||||
### The version number of this plugin (taken from the main source file):
|
||||
|
||||
VERSION = $(shell grep 'static const char \*const VERSION *=' $(PLUGIN).cpp | awk '{ print $$7 }' | sed -e 's/[";]//g')
|
||||
GIT_REV = $(shell git describe --always 2>/dev/null)
|
||||
|
||||
### Configuration (edit this for your needs)
|
||||
|
||||
CONFIG := #-DDEBUG #-DOSD_DEBUG
|
||||
CONFIG += -DAV_INFO -DAV_INFO_TIME=3000 # debug a/v sync
|
||||
#CONFIG += -DHAVE_PTHREAD_NAME # supports new pthread_setname_np
|
||||
#CONFIG += -DNO_TS_AUDIO # disable ts audio parser
|
||||
#CONFIG += -DUSE_TS_VIDEO # build new ts video parser
|
||||
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
|
||||
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
||||
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
|
||||
CONFIG += -DUSE_OSS
|
||||
|
||||
### The C++ compiler and options:
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \
|
||||
-Wdeclaration-after-statement \
|
||||
-ftree-vectorize -msse3 -flax-vector-conversions
|
||||
CXXFLAGS ?= -g -O2 -W -Wall -Wextra -Werror=overloaded-virtual
|
||||
|
||||
### The directory environment:
|
||||
|
||||
VDRDIR ?= ../../..
|
||||
LIBDIR ?= ../../lib
|
||||
# Use package data if installed...otherwise assume we're under the VDR source directory:
|
||||
PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
|
||||
LIBDIR = $(call PKGCFG,libdir)
|
||||
LOCDIR = $(call PKGCFG,locdir)
|
||||
PLGCFG = $(call PKGCFG,plgcfg)
|
||||
#
|
||||
TMPDIR ?= /tmp
|
||||
|
||||
### Make sure that necessary options are included:
|
||||
### The compiler options:
|
||||
|
||||
-include $(VDRDIR)/Make.global
|
||||
export CFLAGS = $(call PKGCFG,cflags)
|
||||
export CXXFLAGS = $(call PKGCFG,cxxflags)
|
||||
|
||||
ifeq ($(CFLAGS),)
|
||||
$(error CFLAGS not set)
|
||||
endif
|
||||
ifeq ($(CXXFLAGS),)
|
||||
$(error CXXFLAGS not set)
|
||||
endif
|
||||
|
||||
### The version number of VDR's plugin API:
|
||||
|
||||
APIVERSION = $(call PKGCFG,apiversion)
|
||||
|
||||
### Allow user defined options to overwrite defaults:
|
||||
|
||||
-include $(VDRDIR)/Make.config
|
||||
|
||||
### The version number of VDR's plugin API (taken from VDR's "config.h"):
|
||||
|
||||
APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h)
|
||||
-include $(PLGCFG)
|
||||
|
||||
### The name of the distribution archive:
|
||||
|
||||
ARCHIVE = $(PLUGIN)-$(VERSION)
|
||||
PACKAGE = vdr-$(ARCHIVE)
|
||||
|
||||
### Includes, Defines and dependencies (add further entries here):
|
||||
### The name of the shared object file:
|
||||
|
||||
INCLUDES += -I$(VDRDIR)/include
|
||||
SOFILE = libvdr-$(PLUGIN).so
|
||||
|
||||
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' \
|
||||
### Includes and Defines (add further entries here):
|
||||
|
||||
INCLUDES +=
|
||||
|
||||
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -D_GNU_SOURCE $(CONFIG) \
|
||||
$(if $(GIT_REV), -DGIT_REV='"$(GIT_REV)"')
|
||||
|
||||
_CFLAGS = $(DEFINES) $(INCLUDES) \
|
||||
$(shell pkg-config --cflags libavcodec) \
|
||||
`pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --cflags gl glu` \
|
||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
||||
`pkg-config --cflags vdpau`) \
|
||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||
`pkg-config --cflags libva-x11 libva-glx libva`) \
|
||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||
`pkg-config --cflags alsa`)
|
||||
### Make it standard
|
||||
|
||||
#override _CFLAGS += -Werror
|
||||
override CXXFLAGS += $(_CFLAGS)
|
||||
override CFLAGS += $(_CFLAGS)
|
||||
|
||||
LIBS += -lrt \
|
||||
$(shell pkg-config --libs libavcodec) \
|
||||
`pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --libs gl glu` \
|
||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
||||
`pkg-config --libs vdpau`) \
|
||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||
`pkg-config --libs libva-x11 libva-glx libva`) \
|
||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||
`pkg-config --libs alsa`)
|
||||
override CXXFLAGS += $(_CFLAGS) $(DEFINES) $(INCLUDES) \
|
||||
-g -W -Wall -Wextra -Winit-self -Werror=overloaded-virtual
|
||||
override CFLAGS += $(_CFLAGS) $(DEFINES) $(INCLUDES) \
|
||||
-g -W -Wall -Wextra -Winit-self -Wdeclaration-after-statement
|
||||
|
||||
### The object files (add further files here):
|
||||
|
||||
OBJS = $(PLUGIN).o softhddev.o video.o audio.o codec.o ringbuffer.o
|
||||
|
||||
SRCS = $(wildcard $(OBJS:.o=.c)) $(PLUGIN).cpp
|
||||
|
||||
### The main target:
|
||||
|
||||
all: libvdr-$(PLUGIN).so i18n
|
||||
|
||||
### Implicit rules:
|
||||
#
|
||||
#%.o: %.cpp
|
||||
# $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
|
||||
all: $(SOFILE) i18n
|
||||
|
||||
### Dependencies:
|
||||
|
||||
MAKEDEP = $(CC) -MM -MG
|
||||
MAKEDEP = $(CXX) -MM -MG
|
||||
DEPFILE = .dependencies
|
||||
$(DEPFILE): Makefile
|
||||
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(SRCS) >$@
|
||||
|
||||
$(OBJS): Makefile
|
||||
@$(MAKEDEP) $(CXXFLAGS) $(SRCS) > $@
|
||||
|
||||
-include $(DEPFILE)
|
||||
|
||||
### Internationalization (I18N):
|
||||
|
||||
PODIR = po
|
||||
LOCALEDIR = $(VDRDIR)/locale
|
||||
I18Npo = $(wildcard $(PODIR)/*.po)
|
||||
I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
|
||||
I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file))))
|
||||
I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
|
||||
I18Npot = $(PODIR)/$(PLUGIN).pot
|
||||
|
||||
%.mo: %.po
|
||||
msgfmt -c -o $@ $<
|
||||
|
||||
$(I18Npot): $(wildcard *.cpp) $(wildcard *.c)
|
||||
$(I18Npot): $(SRCS)
|
||||
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP \
|
||||
-k_ -k_N --package-name=VDR --package-version=$(VDRVERSION) \
|
||||
--msgid-bugs-address='<see README>' -o $@ $^
|
||||
-k_ -k_N --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) \
|
||||
--msgid-bugs-address='<see README>' -o $@ `ls $^`
|
||||
|
||||
%.po: $(I18Npot)
|
||||
msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
|
||||
msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
|
||||
@touch $@
|
||||
|
||||
$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
|
||||
@mkdir -p $(dir $@)
|
||||
cp $< $@
|
||||
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
|
||||
install -D -m644 $< $@
|
||||
|
||||
.PHONY: i18n
|
||||
i18n: $(I18Nmsgs) $(I18Npot)
|
||||
i18n: $(I18Nmo) $(I18Npot)
|
||||
|
||||
install-i18n: $(I18Nmsgs)
|
||||
|
||||
### Targets:
|
||||
|
||||
libvdr-$(PLUGIN).so: $(OBJS) Makefile
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -fPIC $(OBJS) -o $@ $(LIBS)
|
||||
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
|
||||
$(OBJS): Makefile
|
||||
|
||||
$(SOFILE): $(OBJS)
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
|
||||
|
||||
install-lib: $(SOFILE)
|
||||
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
|
||||
|
||||
install: install-lib install-i18n
|
||||
|
||||
dist: $(I18Npo) clean
|
||||
@-rm -rf $(TMPDIR)/$(ARCHIVE)
|
||||
@@ -162,19 +193,20 @@ dist: $(I18Npo) clean
|
||||
@echo Distribution package created as $(PACKAGE).tgz
|
||||
|
||||
clean:
|
||||
@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot
|
||||
@-rm -f $(PODIR)/*.mo $(PODIR)/*.pot
|
||||
@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
|
||||
|
||||
install: libvdr-$(PLUGIN).so
|
||||
cp --remove-destination libvdr-$(PLUGIN).so \
|
||||
/usr/lib/vdr/plugins/libvdr-$(PLUGIN).so.$(APIVERSION)
|
||||
## Private Targets:
|
||||
|
||||
HDRS= $(wildcard *.h)
|
||||
|
||||
indent:
|
||||
for i in $(wildcard $(OBJS:.o=.c)) $(HDRS); do \
|
||||
indent $$i; unexpand -a $$i > $$i.up; mv $$i.up $$i; \
|
||||
for i in $(SRCS) $(HDRS); do \
|
||||
indent $$i; \
|
||||
unexpand -a $$i | sed -e s/constconst/const/ > $$i.up; \
|
||||
mv $$i.up $$i; \
|
||||
done
|
||||
|
||||
video_test: video.c Makefile
|
||||
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $< $(LIBS) \
|
||||
-o $@
|
||||
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $< \
|
||||
$(LIBS) -o $@
|
||||
|
||||
188
Makefile-pre1.7.36
Normal file
188
Makefile-pre1.7.36
Normal file
@@ -0,0 +1,188 @@
|
||||
#
|
||||
# Makefile for a Video Disk Recorder plugin
|
||||
#
|
||||
# $Id$
|
||||
|
||||
# The official name of this plugin.
|
||||
# This name will be used in the '-P...' option of VDR to load the plugin.
|
||||
# By default the main source file also carries this name.
|
||||
# IMPORTANT: the presence of this macro is important for the Make.config
|
||||
# file. So it must be defined, even if it is not used here!
|
||||
#
|
||||
PLUGIN = softhddevice
|
||||
|
||||
### The version number of this plugin (taken from the main source file):
|
||||
|
||||
VERSION = $(shell grep 'static const char \*const VERSION *=' $(PLUGIN).cpp | awk '{ print $$7 }' | sed -e 's/[";]//g')
|
||||
GIT_REV = $(shell git describe --always 2>/dev/null)
|
||||
|
||||
### Configuration (edit this for your needs)
|
||||
|
||||
CONFIG := #-DDEBUG #-DOSD_DEBUG
|
||||
CONFIG += -DAV_INFO -DAV_INFO_TIME=3000 # debug a/v sync
|
||||
CONFIG += -DUSE_PIP # PIP support
|
||||
#CONFIG += -DHAVE_PTHREAD_NAME # supports new pthread_setname_np
|
||||
#CONFIG += -DNO_TS_AUDIO # disable ts audio parser
|
||||
#CONFIG += -DUSE_TS_VIDEO # build new ts video parser
|
||||
# use ffmpeg libswresample
|
||||
CONFIG += $(shell pkg-config --exists libswresample && echo "-DUSE_SWRESAMPLE")
|
||||
CONFIG += -DUSE_SCREENSAVER # use functions to disable screensaver
|
||||
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
|
||||
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
||||
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
|
||||
CONFIG += -DUSE_OSS
|
||||
|
||||
### The C++ compiler and options:
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \
|
||||
-Wdeclaration-after-statement \
|
||||
-ftree-vectorize -msse3 -flax-vector-conversions -fPIC
|
||||
CXXFLAGS ?= -g -O2 -W -Wall -Wextra -Werror=overloaded-virtual -fPIC
|
||||
|
||||
### The directory environment:
|
||||
|
||||
VDRDIR ?= ../../..
|
||||
LIBDIR ?= ../../lib
|
||||
TMPDIR ?= /tmp
|
||||
|
||||
### Make sure that necessary options are included:
|
||||
|
||||
-include $(VDRDIR)/Make.global
|
||||
|
||||
### Allow user defined options to overwrite defaults:
|
||||
|
||||
-include $(VDRDIR)/Make.config
|
||||
|
||||
### The version number of VDR's plugin API (taken from VDR's "config.h"):
|
||||
|
||||
APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h)
|
||||
|
||||
### The name of the distribution archive:
|
||||
|
||||
ARCHIVE = $(PLUGIN)-$(VERSION)
|
||||
PACKAGE = vdr-$(ARCHIVE)
|
||||
|
||||
### Includes, Defines and dependencies (add further entries here):
|
||||
|
||||
INCLUDES += -I$(VDRDIR)/include
|
||||
|
||||
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' \
|
||||
$(if $(GIT_REV), -DGIT_REV='"$(GIT_REV)"')
|
||||
|
||||
_CFLAGS = $(DEFINES) $(INCLUDES) \
|
||||
$(shell pkg-config --cflags libavcodec) \
|
||||
`pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --cflags gl glu` \
|
||||
$(if $(findstring USE_SWRESAMPLE,$(CONFIG)), \
|
||||
$(shell pkg-config --cflags libswresample)) \
|
||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||
`pkg-config --cflags libva-x11 libva-glx libva`) \
|
||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||
`pkg-config --cflags alsa`)
|
||||
|
||||
#override _CFLAGS += -Werror
|
||||
override CXXFLAGS += $(_CFLAGS)
|
||||
override CFLAGS += $(_CFLAGS)
|
||||
|
||||
LIBS += -lrt \
|
||||
$(shell pkg-config --libs libavcodec) \
|
||||
`pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --libs gl glu` \
|
||||
$(if $(findstring USE_SWRESAMPLE,$(CONFIG)), \
|
||||
$(shell pkg-config --libs libswresample)) \
|
||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
||||
`pkg-config --libs vdpau`) \
|
||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||
`pkg-config --libs libva-x11 libva-glx libva`) \
|
||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||
`pkg-config --libs alsa`)
|
||||
|
||||
### The object files (add further files here):
|
||||
|
||||
OBJS = $(PLUGIN).o softhddev.o video.o audio.o codec.o ringbuffer.o
|
||||
SRCS = $(wildcard $(OBJS:.o=.c)) $(PLUGIN).cpp
|
||||
|
||||
### The main target:
|
||||
|
||||
all: libvdr-$(PLUGIN).so i18n
|
||||
|
||||
### Implicit rules:
|
||||
#
|
||||
#%.o: %.cpp
|
||||
# $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
|
||||
|
||||
### Dependencies:
|
||||
|
||||
MAKEDEP = $(CC) -MM -MG
|
||||
DEPFILE = .dependencies
|
||||
$(DEPFILE): Makefile
|
||||
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(SRCS) >$@
|
||||
|
||||
$(OBJS): Makefile
|
||||
|
||||
-include $(DEPFILE)
|
||||
|
||||
### Internationalization (I18N):
|
||||
|
||||
PODIR = po
|
||||
LOCALEDIR = $(VDRDIR)/locale
|
||||
I18Npo = $(wildcard $(PODIR)/*.po)
|
||||
I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
|
||||
I18Npot = $(PODIR)/$(PLUGIN).pot
|
||||
|
||||
%.mo: %.po
|
||||
msgfmt -c -o $@ $<
|
||||
|
||||
$(I18Npot): $(wildcard *.cpp) $(wildcard *.c)
|
||||
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP \
|
||||
-k_ -k_N --package-name=VDR --package-version=$(VDRVERSION) \
|
||||
--msgid-bugs-address='<see README>' -o $@ $^
|
||||
|
||||
%.po: $(I18Npot)
|
||||
msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
|
||||
@touch $@
|
||||
|
||||
$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
|
||||
@mkdir -p $(dir $@)
|
||||
cp $< $@
|
||||
|
||||
.PHONY: i18n
|
||||
i18n: $(I18Nmsgs) $(I18Npot)
|
||||
|
||||
### Targets:
|
||||
|
||||
libvdr-$(PLUGIN).so: $(OBJS) Makefile
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -fPIC $(OBJS) -o $@ $(LIBS)
|
||||
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
|
||||
|
||||
dist: $(I18Npo) clean
|
||||
@-rm -rf $(TMPDIR)/$(ARCHIVE)
|
||||
@mkdir $(TMPDIR)/$(ARCHIVE)
|
||||
@cp -a * $(TMPDIR)/$(ARCHIVE)
|
||||
@tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
|
||||
@-rm -rf $(TMPDIR)/$(ARCHIVE)
|
||||
@echo Distribution package created as $(PACKAGE).tgz
|
||||
|
||||
clean:
|
||||
@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot
|
||||
|
||||
install: libvdr-$(PLUGIN).so
|
||||
cp --remove-destination libvdr-$(PLUGIN).so \
|
||||
/usr/lib/vdr/plugins/libvdr-$(PLUGIN).so.$(APIVERSION)
|
||||
|
||||
HDRS= $(wildcard *.h)
|
||||
|
||||
indent:
|
||||
for i in $(SRCS) $(HDRS); do \
|
||||
indent $$i; \
|
||||
unexpand -a $$i | sed -e s/constconst/const/ > $$i.up; \
|
||||
mv $$i.up $$i; \
|
||||
done
|
||||
|
||||
video_test: video.c Makefile
|
||||
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $< $(LIBS) \
|
||||
-o $@
|
||||
73
README.txt
73
README.txt
@@ -1,6 +1,6 @@
|
||||
@file README.txt @brief A software HD output device for VDR
|
||||
|
||||
Copyright (c) 2011, 2012 by Johns. All Rights Reserved.
|
||||
Copyright (c) 2011 - 2013 by Johns. All Rights Reserved.
|
||||
|
||||
Contributor(s):
|
||||
|
||||
@@ -27,13 +27,14 @@ A software and GPU emulated HD output device plugin for VDR.
|
||||
o Audio FFMpeg / OSS / Analog
|
||||
o HDMI/SPDIF pass-through
|
||||
o Software volume, compression, normalize and channel resample
|
||||
o YaepgHD support
|
||||
o YaepgHD support / new >1.7.33 VDR ScaleVideo API support
|
||||
o Software deinterlacer Bob (VA-API only)
|
||||
o Autocrop
|
||||
o Grab image (VDPAU only)
|
||||
o Suspend
|
||||
o Suspend / Dettach
|
||||
o Letterbox, Stretch and Center cut-out video display modes
|
||||
o atmo light support with plugin http://github.com/durchflieger/DFAtmo
|
||||
o PIP (Picture-in-Picture) (VDPAU only)
|
||||
|
||||
o planned: Video decoder VA-API Branch: vaapi-ext/staging
|
||||
o planned: Video output XvBA / Opengl / Xv
|
||||
@@ -56,8 +57,8 @@ Install:
|
||||
|
||||
git clone git://projects.vdr-developer.org/vdr-plugin-softhddevice.git
|
||||
cd vdr-plugin-softhddevice
|
||||
make VDRDIR=<path-to-your-vdr-files> LIBDIR=.
|
||||
gentoo: make VDRDIR=/usr/include/vdr LIBDIR=.
|
||||
make
|
||||
make install
|
||||
|
||||
2a) tarball
|
||||
|
||||
@@ -66,10 +67,11 @@ Install:
|
||||
|
||||
tar vxf vdr-softhddevice-*.tar.bz2
|
||||
cd softhddevice-*
|
||||
make VDRDIR=<path-to-your-vdr-files> LIBDIR=.
|
||||
make
|
||||
make install
|
||||
|
||||
You can edit Makefile to enable/disable VDPAU / VA-API / Alsa / OSS
|
||||
support.
|
||||
support. The default is to autodetect as much as possible.
|
||||
|
||||
Setup: environment
|
||||
------
|
||||
@@ -87,8 +89,8 @@ Setup: environment
|
||||
only if alsa is configured
|
||||
ALSA_DEVICE=default
|
||||
alsa PCM device name
|
||||
ALSA_AC3_DEVICE=
|
||||
alsa AC3/pass-though device name
|
||||
ALSA_PASSTHROUGH_DEVICE=
|
||||
alsa pass-though (AC3,EAC3,DTS,...) device name
|
||||
ALSA_MIXER=default
|
||||
alsa control device name
|
||||
ALSA_MIXER_CHANNEL=PCM
|
||||
@@ -97,8 +99,8 @@ Setup: environment
|
||||
only if oss is configured
|
||||
OSS_AUDIODEV=/dev/dsp
|
||||
oss dsp device name
|
||||
OSS_AC3_AUDIODEV=
|
||||
oss AC3/pass-though device name
|
||||
OSS_PASSTHROUGHDEV=
|
||||
oss pass-though (AC3,EAC3,DTS,...) device name
|
||||
OSS_MIXERDEV=/dev/mixer
|
||||
oss mixer device name
|
||||
OSS_MIXER_CHANNEL=pcm
|
||||
@@ -154,13 +156,17 @@ Setup: /etc/vdr/setup.conf
|
||||
delay audio or delay video
|
||||
|
||||
softhddevice.AudioPassthrough = 0
|
||||
0 = none, 1 = AC-3
|
||||
0 = none, 1 = PCM, 2 = MPA, 4 = AC-3, 8 = EAC-3, -X disable
|
||||
|
||||
for AC-3 the pass-through device is used.
|
||||
for PCM/AC-3/EAC-3 the pass-through device is used and the audio
|
||||
stream is passed undecoded to the output device.
|
||||
z.b. 12 = AC-3+EAC-3, 13 = PCM+AC-3+EAC-3
|
||||
note: MPA/DTS/TrueHD/... aren't supported yet
|
||||
negative values disable passthrough
|
||||
|
||||
softhddevice.AudioDownmix = 0
|
||||
0 = none, 1 = downmix
|
||||
downmix AC-3 to stero.
|
||||
Use ffmpeg/libav downmix of AC-3/EAC-3 audio to stereo.
|
||||
|
||||
softhddevice.AudioSoftvol = 0
|
||||
0 = off, use hardware volume control
|
||||
@@ -228,11 +234,41 @@ Setup: /etc/vdr/setup.conf
|
||||
0 disable black picture during channel switch
|
||||
1 enable black picture during channel switch
|
||||
|
||||
VideoDisplayFormat = ?
|
||||
softhddevice.Video4to3DisplayFormat = 1
|
||||
0 pan and scan
|
||||
1 letter box
|
||||
2 center cut-out
|
||||
|
||||
softhddevice.VideoOtherDisplayFormat = 1
|
||||
0 pan and scan
|
||||
1 pillar box
|
||||
2 center cut-out
|
||||
|
||||
softhddevice.pip.X = 79
|
||||
softhddevice.pip.Y = 78
|
||||
softhddevice.pip.Width = 18
|
||||
softhddevice.pip.Height = 18
|
||||
PIP pip window position and size in percent.
|
||||
|
||||
softhddevice.pip.VideoX = 0
|
||||
softhddevice.pip.VideoY = 0
|
||||
softhddevice.pip.VideoWidth = 0
|
||||
softhddevice.pip.VideoHeight = 0
|
||||
PIP video window position and size in percent.
|
||||
|
||||
softhddevice.pip.Alt.X = 0
|
||||
softhddevice.pip.Alt.Y = 50
|
||||
softhddevice.pip.Alt.Width = 0
|
||||
softhddevice.pip.Alt.Height = 50
|
||||
PIP alternative pip window position and size in percent.
|
||||
|
||||
softhddevice.pip.Alt.VideoX = 0
|
||||
softhddevice.pip.Alt.VideoY = 0
|
||||
softhddevice.pip.Alt.VideoWidth = 0
|
||||
softhddevice.pip.Alt.VideoHeight = 50
|
||||
PIP alternative video window position and size in percent.
|
||||
|
||||
|
||||
Setup: /etc/vdr/remote.conf
|
||||
------
|
||||
|
||||
@@ -305,11 +341,16 @@ Warning:
|
||||
|
||||
Known Bugs:
|
||||
-----------
|
||||
VA-API doesn't v-sync 1080i streams
|
||||
VA-API doesn't v-sync h264 interlaced streams
|
||||
vdr-image not working
|
||||
|
||||
Requires:
|
||||
---------
|
||||
media-video/vdr (version >=1.7.xx)
|
||||
Video Disk Recorder - turns a pc into a powerful set top box
|
||||
for DVB.
|
||||
http://www.tvdr.de/
|
||||
|
||||
media-video/ffmpeg (version >=0.7)
|
||||
Complete solution to record, convert and stream audio and
|
||||
video. Includes libavcodec.
|
||||
|
||||
10
Todo
10
Todo
@@ -39,6 +39,7 @@ video:
|
||||
some low-bandwidth tv channels have hiccups.
|
||||
check start with 24Hz display rate
|
||||
crash with ffmpeg without vaapi and vdpau.
|
||||
still-picture of PES recordings should use VideoMpegEnqueue.
|
||||
|
||||
vdpau:
|
||||
software deinterlace path not working.
|
||||
@@ -54,6 +55,8 @@ libva:
|
||||
[drm:i915_hangcheck_elapsed] *ERROR* Hangcheck timer elapsed... GPU hung
|
||||
[drm:i915_wait_request] *ERROR* i915_wait_request returns -11 ...
|
||||
missing OSD support for 3d SBS / Top-Bottom streams, like VPDAU.
|
||||
PIP support / multistream handling
|
||||
VA-AP VaapiCleanup crash after channel without video.
|
||||
|
||||
libva: branch vaapi-ext / staging
|
||||
add support for vaapi-ext / staging
|
||||
@@ -110,23 +113,20 @@ plugins:
|
||||
setup:
|
||||
Setup of decoder type.
|
||||
Setup of output type.
|
||||
Setup of display type.
|
||||
Setup 4:3 zoom type
|
||||
Some setup parameters are not used until restart.
|
||||
Can a notice be added to the setup menu?
|
||||
|
||||
unsorted:
|
||||
stoping vdr while plugin is suspended opens and closes a window.
|
||||
svdrp prim: support plugin names for device numbers.
|
||||
Workaround exists: hangup PipVideoStream -> Vdpau_get_format -> xcb -> poll
|
||||
+ lock DecoderLockMutex
|
||||
|
||||
future features (not planed for 1.0 - 1.5)
|
||||
|
||||
video out with xv
|
||||
video out with opengl
|
||||
video out with xvba
|
||||
software decoder for xv / opengl
|
||||
multistream handling
|
||||
pip support
|
||||
save and use auto-crop with channel zapping
|
||||
|
||||
upmix stereo to AC-3 (supported by alsa plugin)
|
||||
|
||||
254
audio.c
254
audio.c
@@ -1,7 +1,7 @@
|
||||
///
|
||||
/// @file audio.c @brief Audio module
|
||||
///
|
||||
/// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
|
||||
/// Copyright (c) 2009 - 2013 by Johns. All Rights Reserved.
|
||||
///
|
||||
/// Contributor(s):
|
||||
///
|
||||
@@ -40,6 +40,7 @@
|
||||
//#define USE_ALSA ///< enable alsa support
|
||||
//#define USE_OSS ///< enable OSS support
|
||||
#define USE_AUDIO_THREAD ///< use thread for audio playback
|
||||
#define USE_AUDIO_MIXER ///< use audio module mixer
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
@@ -128,7 +129,7 @@ static const char *AudioModuleName; ///< which audio module to use
|
||||
/// Selected audio module.
|
||||
static const AudioModule *AudioUsedModule = &NoopModule;
|
||||
static const char *AudioPCMDevice; ///< PCM device name
|
||||
static const char *AudioAC3Device; ///< AC3 device name
|
||||
static const char *AudioPassthroughDevice; ///< Passthrough device name
|
||||
static const char *AudioMixerDevice; ///< mixer device name
|
||||
static const char *AudioMixerChannel; ///< mixer channel name
|
||||
static char AudioDoingInit; ///> flag in init, reduce error
|
||||
@@ -163,7 +164,6 @@ static int AudioStereoDescent; ///< volume descent for stereo
|
||||
static int AudioVolume; ///< current volume (0 .. 1000)
|
||||
|
||||
extern int VideoAudioDelay; ///< import audio/video delay
|
||||
extern int VideoGetBuffers(void); ///< Get number of input buffers.
|
||||
|
||||
/// default ring buffer size ~2s 8ch 16bit (3 * 5 * 7 * 8)
|
||||
static const unsigned AudioRingBufferSize = 3 * 5 * 7 * 8 * 2 * 1000;
|
||||
@@ -178,7 +178,7 @@ enum _audio_rates
|
||||
//Audio88200, ///< 88.2Khz
|
||||
//Audio96000, ///< 96.0Khz
|
||||
//Audio176400, ///< 176.4Khz
|
||||
//Audio192000, ///< 192.0Khz
|
||||
Audio192000, ///< 192.0Khz
|
||||
AudioRatesMax ///< max index
|
||||
};
|
||||
|
||||
@@ -188,9 +188,9 @@ static int AudioRatesInHw[AudioRatesMax];
|
||||
/// input to hardware channel matrix
|
||||
static int AudioChannelMatrix[AudioRatesMax][9];
|
||||
|
||||
/// rates tables
|
||||
/// rates tables (must be sorted by frequency)
|
||||
static const unsigned AudioRatesTable[AudioRatesMax] = {
|
||||
44100, 48000,
|
||||
44100, 48000, 192000
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -401,6 +401,8 @@ static void AudioSoftAmplifier(int16_t * samples, int count)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_AUDIO_MIXER
|
||||
|
||||
/**
|
||||
** Upmix mono to stereo.
|
||||
**
|
||||
@@ -547,6 +549,13 @@ static void AudioUpmix(const int16_t * in, int in_chan, int frames,
|
||||
/**
|
||||
** Resample ffmpeg sample format to hardware format.
|
||||
**
|
||||
** FIXME: use libswresample for this and move it to codec.
|
||||
** FIXME: ffmpeg to alsa conversion is already done in codec.c.
|
||||
**
|
||||
** ffmpeg L R C Ls Rs -> alsa L R Ls Rs C
|
||||
** ffmpeg L R C LFE Ls Rs -> alsa L R Ls Rs C LFE
|
||||
** ffmpeg L R C LFE Ls Rs Rl Rr -> alsa L R Ls Rs C LFE Rl Rr
|
||||
**
|
||||
** @param in input sample buffer
|
||||
** @param in_chan nr. of input channels
|
||||
** @param frames number of frames in sample buffer
|
||||
@@ -582,6 +591,9 @@ static void AudioResample(const int16_t * in, int in_chan, int frames,
|
||||
AudioSurround2Stereo(in, in_chan, frames, out);
|
||||
break;
|
||||
case 5 * 8 + 6:
|
||||
case 3 * 8 + 8:
|
||||
case 5 * 8 + 8:
|
||||
case 6 * 8 + 8:
|
||||
AudioUpmix(in, in_chan, frames, out, out_chan);
|
||||
break;
|
||||
|
||||
@@ -594,6 +606,8 @@ static void AudioResample(const int16_t * in, int in_chan, int frames,
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ring buffer
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -606,7 +620,7 @@ static void AudioResample(const int16_t * in, int in_chan, int frames,
|
||||
typedef struct _audio_ring_ring_
|
||||
{
|
||||
char FlushBuffers; ///< flag: flush buffers
|
||||
char UseAc3; ///< flag: use ac3 pass-through
|
||||
char Passthrough; ///< flag: use pass-through (AC3, ...)
|
||||
int16_t PacketSize; ///< packet size
|
||||
unsigned HwSampleRate; ///< hardware sample rate in Hz
|
||||
unsigned HwChannels; ///< hardware number of channels
|
||||
@@ -624,29 +638,34 @@ static atomic_t AudioRingFilled; ///< how many of the ring is used
|
||||
static unsigned AudioStartThreshold; ///< start play, if filled
|
||||
|
||||
/**
|
||||
** Add sample-rate, number of channel change to ring.
|
||||
** Add sample-rate, number of channels change to ring.
|
||||
**
|
||||
** @param sample_rate sample-rate frequency
|
||||
** @param channels number of channels
|
||||
** @param use_ac3 use ac3/pass-through device
|
||||
** @param passthrough use /pass-through (AC3, ...) device
|
||||
**
|
||||
** @retval -1 error
|
||||
** @retval 0 okay
|
||||
**
|
||||
** @note this function shouldn't fail. Checks are done during AudoInit.
|
||||
*/
|
||||
static int AudioRingAdd(unsigned sample_rate, int channels, int use_ac3)
|
||||
static int AudioRingAdd(unsigned sample_rate, int channels, int passthrough)
|
||||
{
|
||||
unsigned u;
|
||||
|
||||
// search supported sample-rates
|
||||
for (u = 0; u < AudioRatesMax; ++u) {
|
||||
if (AudioRatesTable[u] == sample_rate) {
|
||||
goto found;
|
||||
}
|
||||
if (AudioRatesTable[u] > sample_rate) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (u == AudioRatesMax) { // unsupported sample-rate
|
||||
Error(_("audio: %dHz sample-rate unsupported\n"), sample_rate);
|
||||
return -1;
|
||||
}
|
||||
Error(_("audio: %dHz sample-rate unsupported\n"), sample_rate);
|
||||
return -1; // unsupported sample-rate
|
||||
|
||||
found:
|
||||
if (!AudioChannelMatrix[u][channels]) {
|
||||
Error(_("audio: %d channels unsupported\n"), channels);
|
||||
return -1; // unsupported nr. of channels
|
||||
@@ -661,7 +680,7 @@ static int AudioRingAdd(unsigned sample_rate, int channels, int use_ac3)
|
||||
|
||||
// FIXME: don't flush buffers here
|
||||
AudioRing[AudioRingWrite].FlushBuffers = 1;
|
||||
AudioRing[AudioRingWrite].UseAc3 = use_ac3;
|
||||
AudioRing[AudioRingWrite].Passthrough = passthrough;
|
||||
AudioRing[AudioRingWrite].PacketSize = 0;
|
||||
AudioRing[AudioRingWrite].InSampleRate = sample_rate;
|
||||
AudioRing[AudioRingWrite].InChannels = channels;
|
||||
@@ -817,8 +836,9 @@ static int AlsaPlayRingbuffer(void)
|
||||
if (!avail) { // full or buffer empty
|
||||
break;
|
||||
}
|
||||
// muting ac3, can produce disturbance
|
||||
if (AudioMute || (AudioSoftVolume && !AudioRing[AudioRingRead].UseAc3)) {
|
||||
// muting pass-through ac3, can produce disturbance
|
||||
if (AudioMute || (AudioSoftVolume
|
||||
&& !AudioRing[AudioRingRead].Passthrough)) {
|
||||
// FIXME: quick&dirty cast
|
||||
AudioSoftAmplifier((int16_t *) p, avail);
|
||||
// FIXME: if not all are written, we double amplify them
|
||||
@@ -965,23 +985,23 @@ static int AlsaThread(void)
|
||||
/**
|
||||
** Open alsa pcm device.
|
||||
**
|
||||
** @param use_ac3 use ac3/pass-through device
|
||||
** @param passthrough use pass-through (AC3, ...) device
|
||||
*/
|
||||
static snd_pcm_t *AlsaOpenPCM(int use_ac3)
|
||||
static snd_pcm_t *AlsaOpenPCM(int passthrough)
|
||||
{
|
||||
const char *device;
|
||||
snd_pcm_t *handle;
|
||||
int err;
|
||||
|
||||
// &&|| hell
|
||||
if (!(use_ac3 && ((device = AudioAC3Device)
|
||||
|| (device = getenv("ALSA_AC3_DEVICE"))))
|
||||
if (!(passthrough && ((device = AudioPassthroughDevice)
|
||||
|| (device = getenv("ALSA_PASSTHROUGH_DEVICE"))))
|
||||
&& !(device = AudioPCMDevice) && !(device = getenv("ALSA_DEVICE"))) {
|
||||
device = "default";
|
||||
}
|
||||
if (!AudioDoingInit) { // reduce blabla during init
|
||||
Info(_("audio/alsa: using %sdevice '%s'\n"), use_ac3 ? "ac3 " : "",
|
||||
device);
|
||||
Info(_("audio/alsa: using %sdevice '%s'\n"),
|
||||
passthrough ? "pass-through " : "", device);
|
||||
}
|
||||
// open none blocking; if device is already used, we don't want wait
|
||||
if ((err =
|
||||
@@ -1148,7 +1168,7 @@ static int64_t AlsaGetDelay(void)
|
||||
**
|
||||
** @param freq sample frequency
|
||||
** @param channels number of channels
|
||||
** @param use_ac3 use ac3/pass-through device
|
||||
** @param passthrough use pass-through (AC3, ...) device
|
||||
**
|
||||
** @retval 0 everything ok
|
||||
** @retval 1 didn't support frequency/channels combination
|
||||
@@ -1156,7 +1176,7 @@ static int64_t AlsaGetDelay(void)
|
||||
**
|
||||
** @todo FIXME: remove pointer for freq + channels
|
||||
*/
|
||||
static int AlsaSetup(int *freq, int *channels, int use_ac3)
|
||||
static int AlsaSetup(int *freq, int *channels, int passthrough)
|
||||
{
|
||||
snd_pcm_uframes_t buffer_size;
|
||||
snd_pcm_uframes_t period_size;
|
||||
@@ -1164,7 +1184,7 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
|
||||
int delay;
|
||||
|
||||
if (!AlsaPCMHandle) { // alsa not running yet
|
||||
// FIXME: if open fails for ac3, we never recover
|
||||
// FIXME: if open fails for fe. pass-through, we never recover
|
||||
return -1;
|
||||
}
|
||||
if (1) { // close+open to fix HDMI no sound bug
|
||||
@@ -1174,7 +1194,7 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
|
||||
// FIXME: need lock
|
||||
AlsaPCMHandle = NULL; // other threads should check handle
|
||||
snd_pcm_close(handle);
|
||||
if (!(handle = AlsaOpenPCM(use_ac3))) {
|
||||
if (!(handle = AlsaOpenPCM(passthrough))) {
|
||||
return -1;
|
||||
}
|
||||
AlsaPCMHandle = handle;
|
||||
@@ -1434,7 +1454,7 @@ static int OssPlayRingbuffer(void)
|
||||
break; // bi.bytes could become negative!
|
||||
}
|
||||
|
||||
if (AudioSoftVolume && !AudioRing[AudioRingRead].UseAc3) {
|
||||
if (AudioSoftVolume && !AudioRing[AudioRingRead].Passthrough) {
|
||||
// FIXME: quick&dirty cast
|
||||
AudioSoftAmplifier((int16_t *) p, bi.bytes);
|
||||
// FIXME: if not all are written, we double amplify them
|
||||
@@ -1541,22 +1561,22 @@ static int OssThread(void)
|
||||
/**
|
||||
** Open OSS pcm device.
|
||||
**
|
||||
** @param use_ac3 use ac3/pass-through device
|
||||
** @param passthrough use pass-through (AC3, ...) device
|
||||
*/
|
||||
static int OssOpenPCM(int use_ac3)
|
||||
static int OssOpenPCM(int passthrough)
|
||||
{
|
||||
const char *device;
|
||||
int fildes;
|
||||
|
||||
// &&|| hell
|
||||
if (!(use_ac3 && ((device = AudioAC3Device)
|
||||
|| (device = getenv("OSS_AC3_AUDIODEV"))))
|
||||
if (!(passthrough && ((device = AudioPassthroughDevice)
|
||||
|| (device = getenv("OSS_PASSTHROUGHDEV"))))
|
||||
&& !(device = AudioPCMDevice) && !(device = getenv("OSS_AUDIODEV"))) {
|
||||
device = "/dev/dsp";
|
||||
}
|
||||
if (!AudioDoingInit) {
|
||||
Info(_("audio/oss: using %sdevice '%s'\n"), use_ac3 ? "ac3 " : "",
|
||||
device);
|
||||
Info(_("audio/oss: using %sdevice '%s'\n"),
|
||||
passthrough ? "pass-through " : "", device);
|
||||
}
|
||||
|
||||
if ((fildes = open(device, O_WRONLY)) < 0) {
|
||||
@@ -1703,15 +1723,15 @@ static int64_t OssGetDelay(void)
|
||||
/**
|
||||
** Setup OSS audio for requested format.
|
||||
**
|
||||
** @param sample_rate sample rate/frequency
|
||||
** @param sample_rate sample rate/frequency
|
||||
** @param channels number of channels
|
||||
** @param use_ac3 use ac3/pass-through device
|
||||
** @param passthrough use pass-through (AC3, ...) device
|
||||
**
|
||||
** @retval 0 everything ok
|
||||
** @retval 1 didn't support frequency/channels combination
|
||||
** @retval -1 something gone wrong
|
||||
*/
|
||||
static int OssSetup(int *sample_rate, int *channels, int use_ac3)
|
||||
static int OssSetup(int *sample_rate, int *channels, int passthrough)
|
||||
{
|
||||
int ret;
|
||||
int tmp;
|
||||
@@ -1719,7 +1739,7 @@ static int OssSetup(int *sample_rate, int *channels, int use_ac3)
|
||||
audio_buf_info bi;
|
||||
|
||||
if (OssPcmFildes == -1) { // OSS not ready
|
||||
// FIXME: if open fails for ac3, we never recover
|
||||
// FIXME: if open fails for fe. pass-through, we never recover
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1729,7 +1749,7 @@ static int OssSetup(int *sample_rate, int *channels, int use_ac3)
|
||||
fildes = OssPcmFildes;
|
||||
OssPcmFildes = -1;
|
||||
close(fildes);
|
||||
if (!(fildes = OssOpenPCM(use_ac3))) {
|
||||
if (!(fildes = OssOpenPCM(passthrough))) {
|
||||
return -1;
|
||||
}
|
||||
OssPcmFildes = fildes;
|
||||
@@ -1910,13 +1930,14 @@ static void NoopSetVolume( __attribute__ ((unused))
|
||||
/**
|
||||
** Noop setup.
|
||||
**
|
||||
** @param freq sample frequency
|
||||
** @param channels number of channels
|
||||
** @param freq sample frequency
|
||||
** @param channels number of channels
|
||||
** @param passthrough use pass-through (AC3, ...) device
|
||||
*/
|
||||
static int NoopSetup( __attribute__ ((unused))
|
||||
int *channels, __attribute__ ((unused))
|
||||
int *freq, __attribute__ ((unused))
|
||||
int use_ac3)
|
||||
int passthrough)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -1954,16 +1975,17 @@ static const AudioModule NoopModule = {
|
||||
*/
|
||||
static int AudioNextRing(void)
|
||||
{
|
||||
int use_ac3;
|
||||
int passthrough;
|
||||
int sample_rate;
|
||||
int channels;
|
||||
size_t used;
|
||||
|
||||
// update audio format
|
||||
// not always needed, but check if needed is too complex
|
||||
use_ac3 = AudioRing[AudioRingRead].UseAc3;
|
||||
passthrough = AudioRing[AudioRingRead].Passthrough;
|
||||
sample_rate = AudioRing[AudioRingRead].HwSampleRate;
|
||||
channels = AudioRing[AudioRingRead].HwChannels;
|
||||
if (AudioUsedModule->Setup(&sample_rate, &channels, use_ac3)) {
|
||||
if (AudioUsedModule->Setup(&sample_rate, &channels, passthrough)) {
|
||||
Error(_("audio: can't set channels %d sample-rate %dHz\n"), channels,
|
||||
sample_rate);
|
||||
// FIXME: handle error
|
||||
@@ -1976,12 +1998,18 @@ static int AudioNextRing(void)
|
||||
AudioResetCompressor();
|
||||
AudioResetNormalizer();
|
||||
|
||||
Debug(3, "audio: a/v next buf(%d,%4zdms)\n", atomic_read(&AudioRingFilled),
|
||||
(RingBufferUsedBytes(AudioRing[AudioRingRead].RingBuffer) * 1000)
|
||||
/ (AudioRing[AudioRingWrite].HwSampleRate *
|
||||
AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample));
|
||||
|
||||
// stop, if not enough in next buffer
|
||||
if (AudioStartThreshold >=
|
||||
RingBufferUsedBytes(AudioRing[AudioRingRead].RingBuffer)) {
|
||||
return 1;
|
||||
used = RingBufferUsedBytes(AudioRing[AudioRingRead].RingBuffer);
|
||||
if (AudioStartThreshold * 4 < used || (AudioVideoIsReady
|
||||
&& AudioStartThreshold < used)) {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2030,19 +2058,22 @@ static void *AudioPlayHandlerThread(void *dummy)
|
||||
}
|
||||
|
||||
if (flush) {
|
||||
Debug(3, "audio: flush\n");
|
||||
AudioUsedModule->FlushBuffers();
|
||||
if (AudioNextRing()) {
|
||||
Debug(3, "audio: break after flush\n");
|
||||
break;
|
||||
}
|
||||
Debug(3, "audio: continue after flush\n");
|
||||
}
|
||||
// try to play some samples
|
||||
err = AudioUsedModule->Thread();
|
||||
// underrun, check if new ring buffer is available
|
||||
if (!err) {
|
||||
int use_ac3;
|
||||
int passthrough;
|
||||
int sample_rate;
|
||||
int channels;
|
||||
int old_use_ac3;
|
||||
int old_passthrough;
|
||||
int old_sample_rate;
|
||||
int old_channels;
|
||||
|
||||
@@ -2052,20 +2083,21 @@ static void *AudioPlayHandlerThread(void *dummy)
|
||||
}
|
||||
|
||||
Debug(3, "audio: next ring buffer\n");
|
||||
old_use_ac3 = AudioRing[AudioRingRead].UseAc3;
|
||||
old_passthrough = AudioRing[AudioRingRead].Passthrough;
|
||||
old_sample_rate = AudioRing[AudioRingRead].HwSampleRate;
|
||||
old_channels = AudioRing[AudioRingRead].HwChannels;
|
||||
|
||||
atomic_dec(&AudioRingFilled);
|
||||
AudioRingRead = (AudioRingRead + 1) % AUDIO_RING_MAX;
|
||||
|
||||
use_ac3 = AudioRing[AudioRingRead].UseAc3;
|
||||
passthrough = AudioRing[AudioRingRead].Passthrough;
|
||||
sample_rate = AudioRing[AudioRingRead].HwSampleRate;
|
||||
channels = AudioRing[AudioRingRead].HwChannels;
|
||||
Debug(3, "audio: thread channels %d frequency %dHz %s\n",
|
||||
channels, sample_rate, use_ac3 ? "ac3" : "pcm");
|
||||
channels, sample_rate, passthrough ? "pass-through" : "");
|
||||
// audio config changed?
|
||||
if (old_use_ac3 != use_ac3 || old_sample_rate != sample_rate
|
||||
if (old_passthrough != passthrough
|
||||
|| old_sample_rate != sample_rate
|
||||
|| old_channels != channels) {
|
||||
// FIXME: wait for buffer drain
|
||||
if (AudioNextRing()) {
|
||||
@@ -2144,7 +2176,6 @@ void AudioEnqueue(const void *samples, int count)
|
||||
{
|
||||
size_t n;
|
||||
int16_t *buffer;
|
||||
int frames;
|
||||
|
||||
#ifdef noDEBUG
|
||||
static uint32_t last_tick;
|
||||
@@ -2166,28 +2197,40 @@ void AudioEnqueue(const void *samples, int count)
|
||||
AudioRing[AudioRingWrite].PacketSize = count;
|
||||
Debug(3, "audio: a/v packet size %d bytes\n", count);
|
||||
}
|
||||
if (AudioRing[AudioRingWrite].UseAc3) {
|
||||
buffer = (void *)samples;
|
||||
} else {
|
||||
//
|
||||
// Convert / resample input to hardware format
|
||||
//
|
||||
// audio sample modification allowed and needed?
|
||||
buffer = (void *)samples;
|
||||
if (!AudioRing[AudioRingWrite].Passthrough && (AudioCompression
|
||||
|| AudioNormalize
|
||||
|| AudioRing[AudioRingWrite].InChannels !=
|
||||
AudioRing[AudioRingWrite].HwChannels)) {
|
||||
int frames;
|
||||
|
||||
// resample into ring-buffer is too complex in the case of a roundabout
|
||||
// just use a temporary buffer
|
||||
frames =
|
||||
count / (AudioRing[AudioRingWrite].InChannels *
|
||||
AudioBytesProSample);
|
||||
buffer =
|
||||
alloca(frames * AudioRing[AudioRingWrite].HwChannels *
|
||||
AudioBytesProSample);
|
||||
#ifdef USE_AUDIO_MIXER
|
||||
// Convert / resample input to hardware format
|
||||
AudioResample(samples, AudioRing[AudioRingWrite].InChannels, frames,
|
||||
buffer, AudioRing[AudioRingWrite].HwChannels);
|
||||
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
if (AudioRing[AudioRingWrite].InChannels !=
|
||||
AudioRing[AudioRingWrite].HwChannels) {
|
||||
Debug(3, "audio: internal failure channels mismatch\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
memcpy(buffer, samples, count);
|
||||
#endif
|
||||
count =
|
||||
frames * AudioRing[AudioRingWrite].HwChannels *
|
||||
AudioBytesProSample;
|
||||
|
||||
// resample into ring-buffer is too complex in the case of a roundabout
|
||||
// just use a temporary buffer
|
||||
|
||||
if (AudioCompression) { // in place operation
|
||||
AudioCompressor(buffer, count);
|
||||
}
|
||||
@@ -2276,11 +2319,12 @@ void AudioVideoReady(int64_t pts)
|
||||
(used * 90 * 1000) / (AudioRing[AudioRingWrite].HwSampleRate *
|
||||
AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample);
|
||||
|
||||
Debug(3, "audio: a/v buf:%4zdms %s|%s = %dms video ready\n",
|
||||
Debug(3, "audio: a/v sync buf(%d,%4zdms) %s|%s = %dms %s\n",
|
||||
atomic_read(&AudioRingFilled),
|
||||
(used * 1000) / (AudioRing[AudioRingWrite].HwSampleRate *
|
||||
AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample),
|
||||
Timestamp2String(audio_pts), Timestamp2String(pts),
|
||||
(int)(pts - audio_pts) / 90);
|
||||
Timestamp2String(pts), Timestamp2String(audio_pts),
|
||||
(int)(pts - audio_pts) / 90, AudioRunning ? "running" : "ready");
|
||||
|
||||
if (!AudioRunning) {
|
||||
int skip;
|
||||
@@ -2291,7 +2335,7 @@ void AudioVideoReady(int64_t pts)
|
||||
pts - 15 * 20 * 90 - AudioBufferTime * 90 - audio_pts +
|
||||
VideoAudioDelay;
|
||||
#ifdef DEBUG
|
||||
printf("%dms %dms %dms\n", (int)(pts - audio_pts) / 90,
|
||||
fprintf(stderr, "%dms %dms %dms\n", (int)(pts - audio_pts) / 90,
|
||||
VideoAudioDelay / 90, skip / 90);
|
||||
#endif
|
||||
// guard against old PTS
|
||||
@@ -2304,7 +2348,7 @@ void AudioVideoReady(int64_t pts)
|
||||
AudioSkip = skip - used;
|
||||
skip = used;
|
||||
}
|
||||
Debug(3, "audio: advance %dms %d/%zd\n",
|
||||
Debug(3, "audio: sync advance %dms %d/%zd\n",
|
||||
(skip * 1000) / (AudioRing[AudioRingWrite].HwSampleRate *
|
||||
AudioRing[AudioRingWrite].HwChannels *
|
||||
AudioBytesProSample), skip, used);
|
||||
@@ -2375,7 +2419,7 @@ void AudioFlushBuffers(void)
|
||||
old = AudioRingWrite;
|
||||
AudioRingWrite = (AudioRingWrite + 1) % AUDIO_RING_MAX;
|
||||
AudioRing[AudioRingWrite].FlushBuffers = 1;
|
||||
AudioRing[AudioRingWrite].UseAc3 = AudioRing[old].UseAc3;
|
||||
AudioRing[AudioRingWrite].Passthrough = AudioRing[old].Passthrough;
|
||||
AudioRing[AudioRingWrite].HwSampleRate = AudioRing[old].HwSampleRate;
|
||||
AudioRing[AudioRingWrite].HwChannels = AudioRing[old].HwChannels;
|
||||
AudioRing[AudioRingWrite].InSampleRate = AudioRing[old].InSampleRate;
|
||||
@@ -2487,7 +2531,7 @@ int64_t AudioGetClock(void)
|
||||
|
||||
// delay zero, if no valid time stamp
|
||||
if ((delay = AudioGetDelay())) {
|
||||
if (AudioRing[AudioRingRead].UseAc3) {
|
||||
if (AudioRing[AudioRingRead].Passthrough) {
|
||||
return AudioRing[AudioRingRead].PTS + 0 * 90 - delay;
|
||||
}
|
||||
return AudioRing[AudioRingRead].PTS + 0 * 90 - delay;
|
||||
@@ -2507,7 +2551,7 @@ void AudioSetVolume(int volume)
|
||||
AudioMute = !volume;
|
||||
// reduce loudness for stereo output
|
||||
if (AudioStereoDescent && AudioRing[AudioRingRead].InChannels == 2
|
||||
&& !AudioRing[AudioRingRead].UseAc3) {
|
||||
&& !AudioRing[AudioRingRead].Passthrough) {
|
||||
volume -= AudioStereoDescent;
|
||||
if (volume < 0) {
|
||||
volume = 0;
|
||||
@@ -2524,18 +2568,20 @@ void AudioSetVolume(int volume)
|
||||
/**
|
||||
** Setup audio for requested format.
|
||||
**
|
||||
** @param freq sample frequency
|
||||
** @param channels number of channels
|
||||
** @param use_ac3 use ac3/pass-through device
|
||||
** @param freq sample frequency
|
||||
** @param channels number of channels
|
||||
** @param passthrough use pass-through (AC3, ...) device
|
||||
**
|
||||
** @retval 0 everything ok
|
||||
** @retval 1 didn't support frequency/channels combination
|
||||
** @retval -1 something gone wrong
|
||||
**
|
||||
** @todo add support to report best fitting format.
|
||||
*/
|
||||
int AudioSetup(int *freq, int *channels, int use_ac3)
|
||||
int AudioSetup(int *freq, int *channels, int passthrough)
|
||||
{
|
||||
Debug(3, "audio: setup channels %d frequency %dHz %s\n", *channels, *freq,
|
||||
use_ac3 ? "ac3" : "pcm");
|
||||
passthrough ? "pass-through" : "");
|
||||
|
||||
// invalid parameter
|
||||
if (!freq || !channels || !*freq || !*channels) {
|
||||
@@ -2543,7 +2589,7 @@ int AudioSetup(int *freq, int *channels, int use_ac3)
|
||||
// FIXME: set flag invalid setup
|
||||
return -1;
|
||||
}
|
||||
return AudioRingAdd(*freq, *channels, use_ac3);
|
||||
return AudioRingAdd(*freq, *channels, passthrough);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2679,7 +2725,7 @@ void AudioSetDevice(const char *device)
|
||||
**
|
||||
** @note this is currently usable with alsa only.
|
||||
*/
|
||||
void AudioSetDeviceAC3(const char *device)
|
||||
void AudioSetPassthroughDevice(const char *device)
|
||||
{
|
||||
if (!AudioModuleName) {
|
||||
AudioModuleName = "alsa"; // detect alsa/OSS
|
||||
@@ -2689,7 +2735,7 @@ void AudioSetDeviceAC3(const char *device)
|
||||
AudioModuleName = "oss";
|
||||
}
|
||||
}
|
||||
AudioAC3Device = device;
|
||||
AudioPassthroughDevice = device;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2748,10 +2794,16 @@ void AudioInit(void)
|
||||
// Check which channels/rates/formats are supported
|
||||
// FIXME: we force 44.1Khz and 48Khz must be supported equal
|
||||
// FIXME: should use bitmap of channels supported in RatesInHw
|
||||
// FIXME: use loop over sample-rates
|
||||
freq = 44100;
|
||||
AudioRatesInHw[Audio44100] = 0;
|
||||
for (chan = 1; chan < 9; ++chan) {
|
||||
if (AudioUsedModule->Setup(&freq, &chan, 0)) {
|
||||
int tchan;
|
||||
int tfreq;
|
||||
|
||||
tchan = chan;
|
||||
tfreq = freq;
|
||||
if (AudioUsedModule->Setup(&tfreq, &tchan, 0)) {
|
||||
AudioChannelsInHw[chan] = 0;
|
||||
} else {
|
||||
AudioChannelsInHw[chan] = chan;
|
||||
@@ -2761,16 +2813,39 @@ void AudioInit(void)
|
||||
freq = 48000;
|
||||
AudioRatesInHw[Audio48000] = 0;
|
||||
for (chan = 1; chan < 9; ++chan) {
|
||||
int tchan;
|
||||
int tfreq;
|
||||
|
||||
if (!AudioChannelsInHw[chan]) {
|
||||
continue;
|
||||
}
|
||||
if (AudioUsedModule->Setup(&freq, &chan, 0)) {
|
||||
AudioChannelsInHw[chan] = 0;
|
||||
tchan = chan;
|
||||
tfreq = freq;
|
||||
if (AudioUsedModule->Setup(&tfreq, &tchan, 0)) {
|
||||
//AudioChannelsInHw[chan] = 0;
|
||||
} else {
|
||||
AudioChannelsInHw[chan] = chan;
|
||||
AudioRatesInHw[Audio48000] |= (1 << chan);
|
||||
}
|
||||
}
|
||||
freq = 192000;
|
||||
AudioRatesInHw[Audio192000] = 0;
|
||||
for (chan = 1; chan < 9; ++chan) {
|
||||
int tchan;
|
||||
int tfreq;
|
||||
|
||||
if (!AudioChannelsInHw[chan]) {
|
||||
continue;
|
||||
}
|
||||
tchan = chan;
|
||||
tfreq = freq;
|
||||
if (AudioUsedModule->Setup(&tfreq, &tchan, 0)) {
|
||||
//AudioChannelsInHw[chan] = 0;
|
||||
} else {
|
||||
AudioChannelsInHw[chan] = chan;
|
||||
AudioRatesInHw[Audio192000] |= (1 << chan);
|
||||
}
|
||||
}
|
||||
// build channel support and conversion table
|
||||
for (u = 0; u < AudioRatesMax; ++u) {
|
||||
for (chan = 1; chan < 9; ++chan) {
|
||||
@@ -2852,13 +2927,16 @@ void AudioInit(void)
|
||||
*/
|
||||
void AudioExit(void)
|
||||
{
|
||||
const AudioModule *module;
|
||||
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
if (AudioUsedModule->Thread) { // supports threads
|
||||
AudioExitThread();
|
||||
}
|
||||
#endif
|
||||
AudioUsedModule->Exit();
|
||||
module = AudioUsedModule;
|
||||
AudioUsedModule = &NoopModule;
|
||||
module->Exit();
|
||||
AudioRingExit();
|
||||
AudioRunning = 0;
|
||||
AudioPaused = 0;
|
||||
@@ -2905,7 +2983,7 @@ static void PrintVersion(void)
|
||||
#ifdef GIT_REV
|
||||
"(GIT-" GIT_REV ")"
|
||||
#endif
|
||||
",\n\t(c) 2009 - 2012 by Johns\n"
|
||||
",\n\t(c) 2009 - 2013 by Johns\n"
|
||||
"\tLicense AGPLv3: GNU Affero General Public License version 3\n");
|
||||
}
|
||||
|
||||
@@ -2962,7 +3040,7 @@ int main(int argc, char *const argv[])
|
||||
return -1;
|
||||
default:
|
||||
PrintVersion();
|
||||
fprintf(stderr, "Unkown option '%c'\n", optopt);
|
||||
fprintf(stderr, "Unknown option '%c'\n", optopt);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
6
audio.h
6
audio.h
@@ -1,7 +1,7 @@
|
||||
///
|
||||
/// @file audio.h @brief Audio module headerfile
|
||||
///
|
||||
/// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
|
||||
/// Copyright (c) 2009 - 2013 by Johns. All Rights Reserved.
|
||||
///
|
||||
/// Contributor(s):
|
||||
///
|
||||
@@ -48,7 +48,9 @@ extern void AudioSetCompression(int, int); ///< set compression parameters
|
||||
extern void AudioSetStereoDescent(int); ///< set stereo loudness descent
|
||||
|
||||
extern void AudioSetDevice(const char *); ///< set PCM audio device
|
||||
extern void AudioSetDeviceAC3(const char *); ///< set pass-through device
|
||||
|
||||
/// set pass-through device
|
||||
extern void AudioSetPassthroughDevice(const char *);
|
||||
extern void AudioSetChannel(const char *); ///< set mixer channel
|
||||
extern void AudioInit(void); ///< setup audio module
|
||||
extern void AudioExit(void); ///< cleanup and exit audio module
|
||||
|
||||
681
codec.c
681
codec.c
@@ -1,7 +1,7 @@
|
||||
///
|
||||
/// @file codec.c @brief Codec functions
|
||||
///
|
||||
/// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
|
||||
/// Copyright (c) 2009 - 2013 by Johns. All Rights Reserved.
|
||||
///
|
||||
/// Contributor(s):
|
||||
///
|
||||
@@ -30,12 +30,14 @@
|
||||
/// many bugs and incompatiblity in it. Don't use this shit.
|
||||
///
|
||||
|
||||
/// compile with passthrough support (stable, ac3 only)
|
||||
/// compile with pass-through support (stable, AC-3, E-AC-3 only)
|
||||
#define USE_PASSTHROUGH
|
||||
/// compile audio drift correction support (experimental)
|
||||
/// compile audio drift correction support (very experimental)
|
||||
#define USE_AUDIO_DRIFT_CORRECTION
|
||||
/// compile AC3 audio drift correction support (experimental)
|
||||
/// compile AC-3 audio drift correction support (very experimental)
|
||||
#define USE_AC3_DRIFT_CORRECTION
|
||||
/// use ffmpeg libswresample API (autodected, Makefile)
|
||||
#define noUSE_SWRESAMPLE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
@@ -58,6 +60,9 @@
|
||||
#ifdef USE_VDPAU
|
||||
#include <libavcodec/vdpau.h>
|
||||
#endif
|
||||
#ifdef USE_SWRESAMPLE
|
||||
#include <libswresample/swresample.h>
|
||||
#endif
|
||||
|
||||
#ifndef __USE_GNU
|
||||
#define __USE_GNU
|
||||
@@ -115,9 +120,11 @@ struct _video_decoder_
|
||||
/**
|
||||
** Callback to negotiate the PixelFormat.
|
||||
**
|
||||
** @param fmt is the list of formats which are supported by the codec,
|
||||
** it is terminated by -1 as 0 is a valid format, the
|
||||
** formats are ordered by quality.
|
||||
** @param video_ctx codec context
|
||||
** @param fmt is the list of formats which are supported by
|
||||
** the codec, it is terminated by -1 as 0 is a
|
||||
** valid format, the formats are ordered by
|
||||
** quality.
|
||||
*/
|
||||
static enum PixelFormat Codec_get_format(AVCodecContext * video_ctx,
|
||||
const enum PixelFormat *fmt)
|
||||
@@ -125,7 +132,24 @@ static enum PixelFormat Codec_get_format(AVCodecContext * video_ctx,
|
||||
VideoDecoder *decoder;
|
||||
|
||||
decoder = video_ctx->opaque;
|
||||
//Debug(3, "codec: %s: %18p\n", __FUNCTION__, decoder);
|
||||
#if LIBAVCODEC_VERSION_INT == AV_VERSION_INT(54,86,100)
|
||||
// this begins to stink, 1.1.2 calls get_format for each frame
|
||||
// 1.1.3 has the same version, but works again
|
||||
if (decoder->GetFormatDone) {
|
||||
if (decoder->GetFormatDone < 10) {
|
||||
++decoder->GetFormatDone;
|
||||
Error
|
||||
("codec/video: ffmpeg/libav buggy: get_format called again\n");
|
||||
}
|
||||
return *fmt; // FIXME: this is hack
|
||||
}
|
||||
#endif
|
||||
|
||||
// bug in ffmpeg 1.1.1, called with zero width or height
|
||||
if (!video_ctx->width || !video_ctx->height) {
|
||||
Error("codec/video: ffmpeg/libav buggy: width or height zero\n");
|
||||
}
|
||||
|
||||
decoder->GetFormatDone = 1;
|
||||
return Video_get_format(decoder->HwDecoder, video_ctx, fmt);
|
||||
}
|
||||
@@ -143,11 +167,15 @@ static int Codec_get_buffer(AVCodecContext * video_ctx, AVFrame * frame)
|
||||
VideoDecoder *decoder;
|
||||
|
||||
decoder = video_ctx->opaque;
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54,86,100)
|
||||
// ffmpeg has this already fixed
|
||||
// libav 0.8.5 53.35.0 still needs this
|
||||
#endif
|
||||
if (!decoder->GetFormatDone) { // get_format missing
|
||||
enum PixelFormat fmts[2];
|
||||
|
||||
fprintf(stderr, "codec: buggy ffmpeg/libav\n");
|
||||
Warning(_("codec: buggy ffmpeg/libav\n"));
|
||||
fprintf(stderr, "codec: buggy libav, use ffmpeg\n");
|
||||
Warning(_("codec: buggy libav, use ffmpeg\n"));
|
||||
fmts[0] = video_ctx->pix_fmt;
|
||||
fmts[1] = PIX_FMT_NONE;
|
||||
Codec_get_format(video_ctx, fmts);
|
||||
@@ -160,7 +188,7 @@ static int Codec_get_buffer(AVCodecContext * video_ctx, AVFrame * frame)
|
||||
unsigned surface;
|
||||
struct vdpau_render_state *vrs;
|
||||
|
||||
surface = VideoGetSurface(decoder->HwDecoder);
|
||||
surface = VideoGetSurface(decoder->HwDecoder, video_ctx);
|
||||
vrs = av_mallocz(sizeof(struct vdpau_render_state));
|
||||
vrs->surface = surface;
|
||||
|
||||
@@ -189,7 +217,7 @@ static int Codec_get_buffer(AVCodecContext * video_ctx, AVFrame * frame)
|
||||
if (video_ctx->hwaccel_context) {
|
||||
unsigned surface;
|
||||
|
||||
surface = VideoGetSurface(decoder->HwDecoder);
|
||||
surface = VideoGetSurface(decoder->HwDecoder, video_ctx);
|
||||
|
||||
//Debug(3, "codec: use surface %#010x\n", surface);
|
||||
|
||||
@@ -413,8 +441,11 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id)
|
||||
}
|
||||
if (video_codec->capabilities & CODEC_CAP_TRUNCATED) {
|
||||
Debug(3, "codec: video can use truncated packets\n");
|
||||
#ifndef USE_MPEG_COMPLETE
|
||||
// we send incomplete frames, for old PES recordings
|
||||
// this breaks the decoder for some stations
|
||||
decoder->VideoCtx->flags |= CODEC_FLAG_TRUNCATED;
|
||||
#endif
|
||||
}
|
||||
// FIXME: own memory management for video frames.
|
||||
if (video_codec->capabilities & CODEC_CAP_DR1) {
|
||||
@@ -619,14 +650,27 @@ struct _audio_decoder_
|
||||
AVCodec *AudioCodec; ///< audio codec
|
||||
AVCodecContext *AudioCtx; ///< audio codec context
|
||||
|
||||
int PassthroughAC3; ///< current ac-3 pass-through
|
||||
char Passthrough; ///< current pass-through flags
|
||||
int SampleRate; ///< current stream sample rate
|
||||
int Channels; ///< current stream channels
|
||||
|
||||
int HwSampleRate; ///< hw sample rate
|
||||
int HwChannels; ///< hw channels
|
||||
|
||||
#ifndef USE_SWRESAMPLE
|
||||
ReSampleContext *ReSample; ///< audio resampling context
|
||||
#endif
|
||||
#ifdef USE_SWRESAMPLE
|
||||
#if LIBSWRESAMPLE_VERSION_INT < AV_VERSION_INT(0, 15, 100)
|
||||
struct SwrContext *Resample; ///< audio software resample context
|
||||
#else
|
||||
SwrContext *Resample; ///< audio software resample context
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uint16_t Spdif[24576 / 2]; ///< SPDIF output buffer
|
||||
int SpdifIndex; ///< index into SPDIF output buffer
|
||||
int SpdifCount; ///< SPDIF repeat counter
|
||||
|
||||
int64_t LastDelay; ///< last delay
|
||||
struct timespec LastTime; ///< last time
|
||||
@@ -636,6 +680,7 @@ struct _audio_decoder_
|
||||
int DriftCorr; ///< audio drift correction value
|
||||
int DriftFrac; ///< audio drift fraction for ac3
|
||||
|
||||
#ifndef USE_SWRESAMPLE
|
||||
struct AVResampleContext *AvResample; ///< second audio resample context
|
||||
#define MAX_CHANNELS 8 ///< max number of channels supported
|
||||
int16_t *Buffer[MAX_CHANNELS]; ///< deinterleave sample buffers
|
||||
@@ -643,24 +688,35 @@ struct _audio_decoder_
|
||||
int16_t *Remain[MAX_CHANNELS]; ///< filter remaining samples
|
||||
int RemainSize; ///< size of remain buffer
|
||||
int RemainCount; ///< number of remaining samples
|
||||
#endif
|
||||
};
|
||||
|
||||
///
|
||||
/// IEC Data type enumeration.
|
||||
///
|
||||
enum IEC61937
|
||||
{
|
||||
IEC61937_AC3 = 0x01, ///< AC-3 data
|
||||
// FIXME: more data types
|
||||
IEC61937_EAC3 = 0x15, ///< E-AC-3 data
|
||||
};
|
||||
|
||||
#ifdef USE_AUDIO_DRIFT_CORRECTION
|
||||
#define CORRECT_PCM 1 ///< do PCM audio-drift correction
|
||||
#define CORRECT_AC3 2 ///< do AC3 audio-drift correction
|
||||
static char CodecAudioDrift; ///< flag: enable audio-drift correction
|
||||
#else
|
||||
static const int CodecAudioDrift = 0;
|
||||
#endif
|
||||
#ifdef USE_PASSTHROUGH
|
||||
//static char CodecPassthroughPCM; ///< pass pcm through (unsupported)
|
||||
static char CodecPassthroughAC3; ///< pass ac3 through
|
||||
|
||||
//static char CodecPassthroughDTS; ///< pass dts through (unsupported)
|
||||
//static char CodecPassthroughMPA; ///< pass mpa through (unsupported)
|
||||
///
|
||||
/// Pass-through flags: CodecPCM, CodecAC3, CodecEAC3, ...
|
||||
///
|
||||
static char CodecPassthrough;
|
||||
#else
|
||||
|
||||
static const int CodecPassthroughAC3 = 0;
|
||||
static const int CodecPassthrough = 0;
|
||||
#endif
|
||||
static char CodecDownmix; ///< enable ac-3 downmix
|
||||
static char CodecDownmix; ///< enable AC-3 decoder downmix
|
||||
|
||||
/**
|
||||
** Allocate a new audio decoder context.
|
||||
@@ -715,10 +771,16 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name,
|
||||
}
|
||||
|
||||
if (CodecDownmix) {
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53,61,100) || FF_API_REQUEST_CHANNELS
|
||||
audio_decoder->AudioCtx->request_channels = 2;
|
||||
#endif
|
||||
audio_decoder->AudioCtx->request_channel_layout =
|
||||
AV_CH_LAYOUT_STEREO_DOWNMIX;
|
||||
}
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,61,100)
|
||||
// this has no effect
|
||||
// audio_decoder->AudioCtx->request_sample_fmt = AV_SAMPLE_FMT_S16;
|
||||
#endif
|
||||
pthread_mutex_lock(&CodecLockMutex);
|
||||
// open codec
|
||||
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(53,5,0)
|
||||
@@ -765,6 +827,7 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name,
|
||||
void CodecAudioClose(AudioDecoder * audio_decoder)
|
||||
{
|
||||
// FIXME: output any buffered data
|
||||
#ifndef USE_SWRESAMPLE
|
||||
if (audio_decoder->AvResample) {
|
||||
int ch;
|
||||
|
||||
@@ -784,6 +847,12 @@ void CodecAudioClose(AudioDecoder * audio_decoder)
|
||||
audio_resample_close(audio_decoder->ReSample);
|
||||
audio_decoder->ReSample = NULL;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SWRESAMPLE
|
||||
if (audio_decoder->Resample) {
|
||||
swr_free(&audio_decoder->Resample);
|
||||
}
|
||||
#endif
|
||||
if (audio_decoder->AudioCtx) {
|
||||
pthread_mutex_lock(&CodecLockMutex);
|
||||
avcodec_close(audio_decoder->AudioCtx);
|
||||
@@ -800,7 +869,7 @@ void CodecAudioClose(AudioDecoder * audio_decoder)
|
||||
void CodecSetAudioDrift(int mask)
|
||||
{
|
||||
#ifdef USE_AUDIO_DRIFT_CORRECTION
|
||||
CodecAudioDrift = mask & 3;
|
||||
CodecAudioDrift = mask & (CORRECT_PCM | CORRECT_AC3);
|
||||
#endif
|
||||
(void)mask;
|
||||
}
|
||||
@@ -808,12 +877,12 @@ void CodecSetAudioDrift(int mask)
|
||||
/**
|
||||
** Set audio pass-through.
|
||||
**
|
||||
** @param mask enable mask (PCM, AC3)
|
||||
** @param mask enable mask (PCM, AC3, EAC3)
|
||||
*/
|
||||
void CodecSetAudioPassthrough(int mask)
|
||||
{
|
||||
#ifdef USE_PASSTHROUGH
|
||||
CodecPassthroughAC3 = mask & 1 ? 1 : 0;
|
||||
CodecPassthrough = mask & (CodecPCM | CodecAC3 | CodecEAC3);
|
||||
#endif
|
||||
(void)mask;
|
||||
}
|
||||
@@ -892,6 +961,194 @@ static void CodecReorderAudioFrame(int16_t * buf, int size, int channels)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Handle audio format changes helper.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
** @param[out] passthrough pass-through output
|
||||
*/
|
||||
static int CodecAudioUpdateHelper(AudioDecoder * audio_decoder,
|
||||
int *passthrough)
|
||||
{
|
||||
const AVCodecContext *audio_ctx;
|
||||
int err;
|
||||
|
||||
audio_ctx = audio_decoder->AudioCtx;
|
||||
Debug(3, "codec/audio: format change %s %dHz *%d channels%s%s%s%s%s\n",
|
||||
av_get_sample_fmt_name(audio_ctx->sample_fmt), audio_ctx->sample_rate,
|
||||
audio_ctx->channels, CodecPassthrough & CodecPCM ? " PCM" : "",
|
||||
CodecPassthrough & CodecMPA ? " MPA" : "",
|
||||
CodecPassthrough & CodecAC3 ? " AC3" : "",
|
||||
CodecPassthrough & CodecEAC3 ? " EAC3" : "",
|
||||
CodecPassthrough ? " pass-through" : "");
|
||||
|
||||
*passthrough = 0;
|
||||
audio_decoder->SampleRate = audio_ctx->sample_rate;
|
||||
audio_decoder->HwSampleRate = audio_ctx->sample_rate;
|
||||
audio_decoder->Channels = audio_ctx->channels;
|
||||
audio_decoder->HwChannels = audio_ctx->channels;
|
||||
audio_decoder->Passthrough = CodecPassthrough;
|
||||
|
||||
// SPDIF/HDMI pass-through
|
||||
if ((CodecPassthrough & CodecAC3 && audio_ctx->codec_id == CODEC_ID_AC3)
|
||||
|| (CodecPassthrough & CodecEAC3
|
||||
&& audio_ctx->codec_id == CODEC_ID_EAC3)) {
|
||||
if (audio_ctx->codec_id == CODEC_ID_EAC3) {
|
||||
// EAC3 over HDMI some receivers need HBR
|
||||
audio_decoder->HwSampleRate *= 4;
|
||||
}
|
||||
audio_decoder->HwChannels = 2;
|
||||
audio_decoder->SpdifIndex = 0; // reset buffer
|
||||
audio_decoder->SpdifCount = 0;
|
||||
*passthrough = 1;
|
||||
}
|
||||
// channels/sample-rate not support?
|
||||
if ((err =
|
||||
AudioSetup(&audio_decoder->HwSampleRate,
|
||||
&audio_decoder->HwChannels, *passthrough))) {
|
||||
|
||||
// try EAC3 none HBR
|
||||
audio_decoder->HwSampleRate /= 4;
|
||||
if (audio_ctx->codec_id != CODEC_ID_EAC3
|
||||
|| (err =
|
||||
AudioSetup(&audio_decoder->HwSampleRate,
|
||||
&audio_decoder->HwChannels, *passthrough))) {
|
||||
|
||||
Debug(3, "codec/audio: audio setup error\n");
|
||||
// FIXME: handle errors
|
||||
audio_decoder->HwChannels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
Debug(3, "codec/audio: resample %s %dHz *%d -> %s %dHz *%d\n",
|
||||
av_get_sample_fmt_name(audio_ctx->sample_fmt), audio_ctx->sample_rate,
|
||||
audio_ctx->channels, av_get_sample_fmt_name(AV_SAMPLE_FMT_S16),
|
||||
audio_decoder->HwSampleRate, audio_decoder->HwChannels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
** Audio pass-through decoder helper.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
** @param avpkt undecoded audio packet
|
||||
*/
|
||||
static int CodecAudioPassthroughHelper(AudioDecoder * audio_decoder,
|
||||
const AVPacket * avpkt)
|
||||
{
|
||||
#ifdef USE_PASSTHROUGH
|
||||
const AVCodecContext *audio_ctx;
|
||||
|
||||
audio_ctx = audio_decoder->AudioCtx;
|
||||
// SPDIF/HDMI passthrough
|
||||
if (CodecPassthrough & CodecAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
|
||||
uint16_t *spdif;
|
||||
int spdif_sz;
|
||||
|
||||
spdif = audio_decoder->Spdif;
|
||||
spdif_sz = 6144;
|
||||
|
||||
#ifdef USE_AC3_DRIFT_CORRECTION
|
||||
// FIXME: this works with some TVs/AVReceivers
|
||||
// FIXME: write burst size drift correction, which should work with all
|
||||
if (CodecAudioDrift & CORRECT_AC3) {
|
||||
int x;
|
||||
|
||||
x = (audio_decoder->DriftFrac +
|
||||
(audio_decoder->DriftCorr * spdif_sz)) / (10 *
|
||||
audio_decoder->HwSampleRate * 100);
|
||||
audio_decoder->DriftFrac =
|
||||
(audio_decoder->DriftFrac +
|
||||
(audio_decoder->DriftCorr * spdif_sz)) % (10 *
|
||||
audio_decoder->HwSampleRate * 100);
|
||||
// round to word border
|
||||
x *= audio_decoder->HwChannels * 4;
|
||||
if (x < -64) { // limit correction
|
||||
x = -64;
|
||||
} else if (x > 64) {
|
||||
x = 64;
|
||||
}
|
||||
spdif_sz += x;
|
||||
}
|
||||
#endif
|
||||
|
||||
// build SPDIF header and append A52 audio to it
|
||||
// avpkt is the original data
|
||||
if (spdif_sz < avpkt->size + 8) {
|
||||
Error(_("codec/audio: decoded data smaller than encoded\n"));
|
||||
return -1;
|
||||
}
|
||||
spdif[0] = htole16(0xF872); // iec 61937 sync word
|
||||
spdif[1] = htole16(0x4E1F);
|
||||
spdif[2] = htole16(IEC61937_AC3 | (avpkt->data[5] & 0x07) << 8);
|
||||
spdif[3] = htole16(avpkt->size * 8);
|
||||
// copy original data for output
|
||||
// FIXME: not 100% sure, if endian is correct on not intel hardware
|
||||
swab(avpkt->data, spdif + 4, avpkt->size);
|
||||
// FIXME: don't need to clear always
|
||||
memset(spdif + 4 + avpkt->size / 2, 0, spdif_sz - 8 - avpkt->size);
|
||||
// don't play with the ac-3 samples
|
||||
AudioEnqueue(spdif, spdif_sz);
|
||||
return 1;
|
||||
}
|
||||
if (CodecPassthrough & CodecEAC3 && audio_ctx->codec_id == CODEC_ID_EAC3) {
|
||||
uint16_t *spdif;
|
||||
int spdif_sz;
|
||||
int repeat;
|
||||
|
||||
// build SPDIF header and append A52 audio to it
|
||||
// avpkt is the original data
|
||||
spdif = audio_decoder->Spdif;
|
||||
spdif_sz = 24576; // 4 * 6144
|
||||
if (audio_decoder->HwSampleRate == 48000) {
|
||||
spdif_sz = 6144;
|
||||
}
|
||||
if (spdif_sz < audio_decoder->SpdifIndex + avpkt->size + 8) {
|
||||
Error(_("codec/audio: decoded data smaller than encoded\n"));
|
||||
return -1;
|
||||
}
|
||||
// check if we must pack multiple packets
|
||||
repeat = 1;
|
||||
if ((avpkt->data[4] & 0xc0) != 0xc0) { // fscod
|
||||
static const uint8_t eac3_repeat[4] = { 6, 3, 2, 1 };
|
||||
|
||||
// fscod2
|
||||
repeat = eac3_repeat[(avpkt->data[4] & 0x30) >> 4];
|
||||
}
|
||||
// fprintf(stderr, "repeat %d %d\n", repeat, avpkt->size);
|
||||
|
||||
// copy original data for output
|
||||
// pack upto repeat EAC-3 pakets into one IEC 61937 burst
|
||||
// FIXME: not 100% sure, if endian is correct on not intel hardware
|
||||
swab(avpkt->data, spdif + 4 + audio_decoder->SpdifIndex, avpkt->size);
|
||||
audio_decoder->SpdifIndex += avpkt->size;
|
||||
if (++audio_decoder->SpdifCount < repeat) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
spdif[0] = htole16(0xF872); // iec 61937 sync word
|
||||
spdif[1] = htole16(0x4E1F);
|
||||
spdif[2] = htole16(IEC61937_EAC3);
|
||||
spdif[3] = htole16(audio_decoder->SpdifIndex * 8);
|
||||
memset(spdif + 4 + audio_decoder->SpdifIndex / 2, 0,
|
||||
spdif_sz - 8 - audio_decoder->SpdifIndex);
|
||||
|
||||
// don't play with the eac-3 samples
|
||||
AudioEnqueue(spdif, spdif_sz);
|
||||
|
||||
audio_decoder->SpdifIndex = 0;
|
||||
audio_decoder->SpdifCount = 0;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef USE_SWRESAMPLE
|
||||
|
||||
/**
|
||||
** Set/update audio pts clock.
|
||||
**
|
||||
@@ -913,14 +1170,15 @@ static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
|
||||
if (!delay) {
|
||||
return;
|
||||
}
|
||||
clock_gettime(CLOCK_REALTIME, &nowtime);
|
||||
clock_gettime(CLOCK_MONOTONIC, &nowtime);
|
||||
if (!audio_decoder->LastDelay) {
|
||||
audio_decoder->LastTime = nowtime;
|
||||
audio_decoder->LastPTS = pts;
|
||||
audio_decoder->LastDelay = delay;
|
||||
audio_decoder->Drift = 0;
|
||||
audio_decoder->DriftFrac = 0;
|
||||
Debug(3, "codec/audio: inital delay %" PRId64 "ms\n", delay / 90);
|
||||
Debug(3, "codec/audio: inital drift delay %" PRId64 "ms\n",
|
||||
delay / 90);
|
||||
return;
|
||||
}
|
||||
// collect over some time
|
||||
@@ -964,8 +1222,10 @@ static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
|
||||
audio_decoder->Drift = drift;
|
||||
corr = (10 * audio_decoder->HwSampleRate * drift) / (90 * 1000);
|
||||
// SPDIF/HDMI passthrough
|
||||
if ((CodecAudioDrift & 2) && (!CodecPassthroughAC3
|
||||
|| audio_decoder->AudioCtx->codec_id != CODEC_ID_AC3)) {
|
||||
if ((CodecAudioDrift & CORRECT_AC3) && (!(CodecPassthrough & CodecAC3)
|
||||
|| audio_decoder->AudioCtx->codec_id != CODEC_ID_AC3)
|
||||
&& (!(CodecPassthrough & CodecEAC3)
|
||||
|| audio_decoder->AudioCtx->codec_id != CODEC_ID_EAC3)) {
|
||||
audio_decoder->DriftCorr = -corr;
|
||||
}
|
||||
|
||||
@@ -1002,14 +1262,15 @@ static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
|
||||
** Handle audio format changes.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
**
|
||||
** @note this is the old not good supported version
|
||||
*/
|
||||
static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder)
|
||||
{
|
||||
int passthrough;
|
||||
const AVCodecContext *audio_ctx;
|
||||
int err;
|
||||
int isAC3;
|
||||
|
||||
// FIXME: use swr_convert from swresample (only in ffmpeg!)
|
||||
if (audio_decoder->ReSample) {
|
||||
audio_resample_close(audio_decoder->ReSample);
|
||||
audio_decoder->ReSample = NULL;
|
||||
@@ -1021,28 +1282,8 @@ static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder)
|
||||
}
|
||||
|
||||
audio_ctx = audio_decoder->AudioCtx;
|
||||
Debug(3, "codec/audio: format change %dHz %d channels %s\n",
|
||||
audio_ctx->sample_rate, audio_ctx->channels,
|
||||
CodecPassthroughAC3 ? "pass-through" : "");
|
||||
if ((err = CodecAudioUpdateHelper(audio_decoder, &passthrough))) {
|
||||
|
||||
audio_decoder->SampleRate = audio_ctx->sample_rate;
|
||||
audio_decoder->HwSampleRate = audio_ctx->sample_rate;
|
||||
audio_decoder->Channels = audio_ctx->channels;
|
||||
audio_decoder->PassthroughAC3 = CodecPassthroughAC3;
|
||||
|
||||
// SPDIF/HDMI passthrough
|
||||
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
|
||||
audio_decoder->HwChannels = 2;
|
||||
isAC3 = 1;
|
||||
} else {
|
||||
audio_decoder->HwChannels = audio_ctx->channels;
|
||||
isAC3 = 0;
|
||||
}
|
||||
|
||||
// channels not support?
|
||||
if ((err =
|
||||
AudioSetup(&audio_decoder->HwSampleRate,
|
||||
&audio_decoder->HwChannels, isAC3))) {
|
||||
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
|
||||
audio_ctx->sample_rate, audio_ctx->channels,
|
||||
audio_decoder->HwSampleRate, audio_decoder->HwChannels);
|
||||
@@ -1058,19 +1299,21 @@ static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder)
|
||||
Error(_("codec/audio: resample setup error\n"));
|
||||
audio_decoder->HwChannels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Debug(3, "codec/audio: audio setup error\n");
|
||||
// FIXME: handle errors
|
||||
audio_decoder->HwChannels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
return;
|
||||
}
|
||||
Debug(3, "codec/audio: audio setup error\n");
|
||||
// FIXME: handle errors
|
||||
audio_decoder->HwChannels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
return;
|
||||
}
|
||||
if (passthrough) { // pass-through no conversion allowed
|
||||
return;
|
||||
}
|
||||
// prepare audio drift resample
|
||||
#ifdef USE_AUDIO_DRIFT_CORRECTION
|
||||
if ((CodecAudioDrift & 1) && !isAC3) {
|
||||
if (CodecAudioDrift & CORRECT_PCM) {
|
||||
if (audio_decoder->AvResample) {
|
||||
Error(_("codec/audio: overwrite resample\n"));
|
||||
}
|
||||
@@ -1101,7 +1344,7 @@ static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder)
|
||||
void CodecAudioEnqueue(AudioDecoder * audio_decoder, int16_t * data, int count)
|
||||
{
|
||||
#ifdef USE_AUDIO_DRIFT_CORRECTION
|
||||
if ((CodecAudioDrift & 1) && audio_decoder->AvResample) {
|
||||
if ((CodecAudioDrift & CORRECT_PCM) && audio_decoder->AvResample) {
|
||||
int16_t buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16)));
|
||||
int16_t buftmp[MAX_CHANNELS][(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4];
|
||||
@@ -1162,12 +1405,16 @@ void CodecAudioEnqueue(AudioDecoder * audio_decoder, int16_t * data, int count)
|
||||
n *= 2;
|
||||
|
||||
n *= audio_decoder->HwChannels;
|
||||
CodecReorderAudioFrame(buf, n, audio_decoder->HwChannels);
|
||||
if (!(audio_decoder->Passthrough & CodecPCM)) {
|
||||
CodecReorderAudioFrame(buf, n, audio_decoder->HwChannels);
|
||||
}
|
||||
AudioEnqueue(buf, n);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
CodecReorderAudioFrame(data, count, audio_decoder->HwChannels);
|
||||
if (!(audio_decoder->Passthrough & CodecPCM)) {
|
||||
CodecReorderAudioFrame(data, count, audio_decoder->HwChannels);
|
||||
}
|
||||
AudioEnqueue(data, count);
|
||||
}
|
||||
|
||||
@@ -1189,6 +1436,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
|
||||
audio_ctx = audio_decoder->AudioCtx;
|
||||
|
||||
// FIXME: don't need to decode pass-through codecs
|
||||
buf_sz = sizeof(buf);
|
||||
l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, (AVPacket *) avpkt);
|
||||
if (avpkt->size != l) {
|
||||
@@ -1202,20 +1450,12 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
}
|
||||
Error(_("codec: error more than one frame data\n"));
|
||||
}
|
||||
#ifdef notyetFF_API_OLD_DECODE_AUDIO
|
||||
// FIXME: ffmpeg git comeing
|
||||
int got_frame;
|
||||
|
||||
avcodec_decode_audio4(audio_ctx, frame, &got_frame, avpkt);
|
||||
#else
|
||||
#endif
|
||||
|
||||
// update audio clock
|
||||
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
|
||||
CodecAudioSetClock(audio_decoder, avpkt->pts);
|
||||
}
|
||||
// FIXME: must first play remainings bytes, than change and play new.
|
||||
if (audio_decoder->PassthroughAC3 != CodecPassthroughAC3
|
||||
if (audio_decoder->Passthrough != CodecPassthrough
|
||||
|| audio_decoder->SampleRate != audio_ctx->sample_rate
|
||||
|| audio_decoder->Channels != audio_ctx->channels) {
|
||||
CodecAudioUpdateFormat(audio_decoder);
|
||||
@@ -1248,48 +1488,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
CodecAudioEnqueue(audio_decoder, outbuf, outlen);
|
||||
}
|
||||
} else {
|
||||
#ifdef USE_PASSTHROUGH
|
||||
// SPDIF/HDMI passthrough
|
||||
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
|
||||
// build SPDIF header and append A52 audio to it
|
||||
// avpkt is the original data
|
||||
buf_sz = 6144;
|
||||
|
||||
#ifdef USE_AC3_DRIFT_CORRECTION
|
||||
if (CodecAudioDrift & 2) {
|
||||
int x;
|
||||
|
||||
x = (audio_decoder->DriftFrac +
|
||||
(audio_decoder->DriftCorr * buf_sz)) / (10 *
|
||||
audio_decoder->HwSampleRate * 100);
|
||||
audio_decoder->DriftFrac =
|
||||
(audio_decoder->DriftFrac +
|
||||
(audio_decoder->DriftCorr * buf_sz)) % (10 *
|
||||
audio_decoder->HwSampleRate * 100);
|
||||
x *= audio_decoder->HwChannels * 4;
|
||||
if (x < -64) { // limit correction
|
||||
x = -64;
|
||||
} else if (x > 64) {
|
||||
x = 64;
|
||||
}
|
||||
buf_sz += x;
|
||||
}
|
||||
#endif
|
||||
if (buf_sz < avpkt->size + 8) {
|
||||
Error(_
|
||||
("codec/audio: decoded data smaller than encoded\n"));
|
||||
return;
|
||||
}
|
||||
// copy original data for output
|
||||
// FIXME: not 100% sure, if endian is correct
|
||||
buf[0] = htole16(0xF872); // iec 61937 sync word
|
||||
buf[1] = htole16(0x4E1F);
|
||||
buf[2] = htole16(0x01 | (avpkt->data[5] & 0x07) << 8);
|
||||
buf[3] = htole16(avpkt->size * 8);
|
||||
swab(avpkt->data, buf + 4, avpkt->size);
|
||||
memset(buf + 4 + avpkt->size / 2, 0, buf_sz - 8 - avpkt->size);
|
||||
// don't play with the ac-3 samples
|
||||
AudioEnqueue(buf, buf_sz);
|
||||
if (CodecAudioPassthroughHelper(audio_decoder, avpkt)) {
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
@@ -1342,13 +1541,269 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
}
|
||||
// DTS HD?
|
||||
// True HD?
|
||||
#endif
|
||||
#endif
|
||||
CodecAudioEnqueue(audio_decoder, buf, buf_sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_SWRESAMPLE
|
||||
|
||||
/**
|
||||
** Set/update audio pts clock.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
** @param pts presentation timestamp
|
||||
*/
|
||||
static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
|
||||
{
|
||||
struct timespec nowtime;
|
||||
int64_t delay;
|
||||
int64_t tim_diff;
|
||||
int64_t pts_diff;
|
||||
int drift;
|
||||
int corr;
|
||||
|
||||
AudioSetClock(pts);
|
||||
|
||||
delay = AudioGetDelay();
|
||||
if (!delay) {
|
||||
return;
|
||||
}
|
||||
clock_gettime(CLOCK_MONOTONIC, &nowtime);
|
||||
if (!audio_decoder->LastDelay) {
|
||||
audio_decoder->LastTime = nowtime;
|
||||
audio_decoder->LastPTS = pts;
|
||||
audio_decoder->LastDelay = delay;
|
||||
audio_decoder->Drift = 0;
|
||||
audio_decoder->DriftFrac = 0;
|
||||
Debug(3, "codec/audio: inital drift delay %" PRId64 "ms\n",
|
||||
delay / 90);
|
||||
return;
|
||||
}
|
||||
// collect over some time
|
||||
pts_diff = pts - audio_decoder->LastPTS;
|
||||
if (pts_diff < 10 * 1000 * 90) {
|
||||
return;
|
||||
}
|
||||
|
||||
tim_diff = (nowtime.tv_sec - audio_decoder->LastTime.tv_sec)
|
||||
* 1000 * 1000 * 1000 + (nowtime.tv_nsec -
|
||||
audio_decoder->LastTime.tv_nsec);
|
||||
|
||||
drift =
|
||||
(tim_diff * 90) / (1000 * 1000) - pts_diff + delay -
|
||||
audio_decoder->LastDelay;
|
||||
|
||||
// adjust rounding error
|
||||
nowtime.tv_nsec -= nowtime.tv_nsec % (1000 * 1000 / 90);
|
||||
audio_decoder->LastTime = nowtime;
|
||||
audio_decoder->LastPTS = pts;
|
||||
audio_decoder->LastDelay = delay;
|
||||
|
||||
if (0) {
|
||||
Debug(3,
|
||||
"codec/audio: interval P:%5" PRId64 "ms T:%5" PRId64 "ms D:%4"
|
||||
PRId64 "ms %f %d\n", pts_diff / 90, tim_diff / (1000 * 1000),
|
||||
delay / 90, drift / 90.0, audio_decoder->DriftCorr);
|
||||
}
|
||||
// underruns and av_resample have the same time :(((
|
||||
if (abs(drift) > 10 * 90) {
|
||||
// drift too big, pts changed?
|
||||
Debug(3, "codec/audio: drift(%6d) %3dms reset\n",
|
||||
audio_decoder->DriftCorr, drift / 90);
|
||||
audio_decoder->LastDelay = 0;
|
||||
#ifdef DEBUG
|
||||
corr = 0; // keep gcc happy
|
||||
#endif
|
||||
} else {
|
||||
|
||||
drift += audio_decoder->Drift;
|
||||
audio_decoder->Drift = drift;
|
||||
corr = (10 * audio_decoder->HwSampleRate * drift) / (90 * 1000);
|
||||
// SPDIF/HDMI passthrough
|
||||
if ((CodecAudioDrift & CORRECT_AC3) && (!(CodecPassthrough & CodecAC3)
|
||||
|| audio_decoder->AudioCtx->codec_id != CODEC_ID_AC3)
|
||||
&& (!(CodecPassthrough & CodecEAC3)
|
||||
|| audio_decoder->AudioCtx->codec_id != CODEC_ID_EAC3)) {
|
||||
audio_decoder->DriftCorr = -corr;
|
||||
}
|
||||
|
||||
if (audio_decoder->DriftCorr < -20000) { // limit correction
|
||||
audio_decoder->DriftCorr = -20000;
|
||||
} else if (audio_decoder->DriftCorr > 20000) {
|
||||
audio_decoder->DriftCorr = 20000;
|
||||
}
|
||||
}
|
||||
|
||||
if (audio_decoder->Resample && audio_decoder->DriftCorr) {
|
||||
int distance;
|
||||
|
||||
// try workaround for buggy ffmpeg 0.10
|
||||
if (abs(audio_decoder->DriftCorr) < 2000) {
|
||||
distance = (pts_diff * audio_decoder->HwSampleRate) / (900 * 1000);
|
||||
} else {
|
||||
distance = (pts_diff * audio_decoder->HwSampleRate) / (90 * 1000);
|
||||
}
|
||||
if (swr_set_compensation(audio_decoder->Resample,
|
||||
audio_decoder->DriftCorr / 10, distance)) {
|
||||
Debug(3, "codec/audio: swr_set_compensation failed\n");
|
||||
}
|
||||
}
|
||||
if (1) {
|
||||
static int c;
|
||||
|
||||
if (!(c++ % 10)) {
|
||||
Debug(3, "codec/audio: drift(%6d) %8dus %5d\n",
|
||||
audio_decoder->DriftCorr, drift * 1000 / 90, corr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Handle audio format changes.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
*/
|
||||
static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder)
|
||||
{
|
||||
int passthrough;
|
||||
const AVCodecContext *audio_ctx;
|
||||
|
||||
if (CodecAudioUpdateHelper(audio_decoder, &passthrough)) {
|
||||
// FIXME: handle swresample format conversions.
|
||||
return;
|
||||
}
|
||||
if (passthrough) { // pass-through no conversion allowed
|
||||
return;
|
||||
}
|
||||
|
||||
audio_ctx = audio_decoder->AudioCtx;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (audio_ctx->sample_fmt == AV_SAMPLE_FMT_S16
|
||||
&& audio_ctx->sample_rate == audio_decoder->HwSampleRate
|
||||
&& !CodecAudioDrift) {
|
||||
// FIXME: use Resample only, when it is needed!
|
||||
fprintf(stderr, "no resample needed\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
audio_decoder->Resample =
|
||||
swr_alloc_set_opts(audio_decoder->Resample, audio_ctx->channel_layout,
|
||||
AV_SAMPLE_FMT_S16, audio_decoder->HwSampleRate,
|
||||
audio_ctx->channel_layout, audio_ctx->sample_fmt,
|
||||
audio_ctx->sample_rate, 0, NULL);
|
||||
if (audio_decoder->Resample) {
|
||||
swr_init(audio_decoder->Resample);
|
||||
} else {
|
||||
Error(_("codec/audio: can't setup resample\n"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Decode an audio packet.
|
||||
**
|
||||
** PTS must be handled self.
|
||||
**
|
||||
** @note the caller has not aligned avpkt and not cleared the end.
|
||||
**
|
||||
** @param audio_decoder audio decoder data
|
||||
** @param avpkt audio packet
|
||||
*/
|
||||
void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
{
|
||||
AVCodecContext *audio_ctx;
|
||||
AVFrame frame;
|
||||
int got_frame;
|
||||
int n;
|
||||
|
||||
audio_ctx = audio_decoder->AudioCtx;
|
||||
|
||||
// FIXME: don't need to decode pass-through codecs
|
||||
frame.data[0] = NULL;
|
||||
n = avcodec_decode_audio4(audio_ctx, &frame, &got_frame,
|
||||
(AVPacket *) avpkt);
|
||||
if (n != avpkt->size) {
|
||||
if (n == AVERROR(EAGAIN)) {
|
||||
Error(_("codec/audio: latm\n"));
|
||||
return;
|
||||
}
|
||||
if (n < 0) { // no audio frame could be decompressed
|
||||
Error(_("codec/audio: bad audio frame\n"));
|
||||
return;
|
||||
}
|
||||
Error(_("codec/audio: error more than one frame data\n"));
|
||||
}
|
||||
if (!got_frame) {
|
||||
Error(_("codec/audio: no frame\n"));
|
||||
return;
|
||||
}
|
||||
// update audio clock
|
||||
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
|
||||
CodecAudioSetClock(audio_decoder, avpkt->pts);
|
||||
}
|
||||
// format change
|
||||
if (audio_decoder->Passthrough != CodecPassthrough
|
||||
|| audio_decoder->SampleRate != audio_ctx->sample_rate
|
||||
|| audio_decoder->Channels != audio_ctx->channels) {
|
||||
CodecAudioUpdateFormat(audio_decoder);
|
||||
}
|
||||
|
||||
if (!audio_decoder->HwSampleRate || !audio_decoder->HwChannels) {
|
||||
return; // unsupported sample format
|
||||
}
|
||||
|
||||
if (CodecAudioPassthroughHelper(audio_decoder, avpkt)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (0) {
|
||||
char strbuf[32];
|
||||
int data_sz;
|
||||
int plane_sz;
|
||||
|
||||
data_sz =
|
||||
av_samples_get_buffer_size(&plane_sz, audio_ctx->channels,
|
||||
frame.nb_samples, audio_ctx->sample_fmt, 1);
|
||||
fprintf(stderr, "codec/audio: sample_fmt %s\n",
|
||||
av_get_sample_fmt_name(audio_ctx->sample_fmt));
|
||||
av_get_channel_layout_string(strbuf, 32, audio_ctx->channels,
|
||||
audio_ctx->channel_layout);
|
||||
fprintf(stderr, "codec/audio: layout %s\n", strbuf);
|
||||
fprintf(stderr,
|
||||
"codec/audio: channels %d samples %d plane %d data %d\n",
|
||||
audio_ctx->channels, frame.nb_samples, plane_sz, data_sz);
|
||||
}
|
||||
|
||||
if (audio_decoder->Resample) {
|
||||
uint8_t outbuf[8192 * 2 * 8];
|
||||
uint8_t *out[1];
|
||||
|
||||
out[0] = outbuf;
|
||||
n = swr_convert(audio_decoder->Resample, out,
|
||||
sizeof(outbuf) / (2 * audio_decoder->HwChannels),
|
||||
(const uint8_t **)frame.extended_data, frame.nb_samples);
|
||||
if (n > 0) {
|
||||
if (!(audio_decoder->Passthrough & CodecPCM)) {
|
||||
CodecReorderAudioFrame((int16_t *) outbuf,
|
||||
n * 2 * audio_decoder->HwChannels,
|
||||
audio_decoder->HwChannels);
|
||||
}
|
||||
AudioEnqueue(outbuf, n * 2 * audio_decoder->HwChannels);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
// should be never reached
|
||||
fprintf(stderr, "oops\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
** Flush the audio decoder.
|
||||
**
|
||||
|
||||
12
codec.h
12
codec.h
@@ -1,7 +1,7 @@
|
||||
///
|
||||
/// @file codec.h @brief Codec module headerfile
|
||||
///
|
||||
/// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
|
||||
/// Copyright (c) 2009 - 2013 by Johns. All Rights Reserved.
|
||||
///
|
||||
/// Contributor(s):
|
||||
///
|
||||
@@ -23,6 +23,16 @@
|
||||
/// @addtogroup Codec
|
||||
/// @{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Defines
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#define CodecPCM 0x01 ///< PCM bit mask
|
||||
#define CodecMPA 0x02 ///< MPA bit mask (planned)
|
||||
#define CodecAC3 0x04 ///< AC-3 bit mask
|
||||
#define CodecEAC3 0x08 ///< EAC-3 bit mask
|
||||
#define CodecDTS 0x10 ///< DTS bit mask (planned)
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
1366
po/de_DE.po
Normal file
1366
po/de_DE.po
Normal file
File diff suppressed because it is too large
Load Diff
1112
softhddev.c
1112
softhddev.c
File diff suppressed because it is too large
Load Diff
15
softhddev.h
15
softhddev.h
@@ -1,7 +1,7 @@
|
||||
///
|
||||
/// @file softhddev.h @brief software HD device plugin header file.
|
||||
///
|
||||
/// Copyright (c) 2011 - 2012 by Johns. All Rights Reserved.
|
||||
/// Copyright (c) 2011 - 2013 by Johns. All Rights Reserved.
|
||||
///
|
||||
/// Contributor(s):
|
||||
///
|
||||
@@ -95,6 +95,19 @@ extern "C"
|
||||
|
||||
/// Get decoder statistics
|
||||
extern void GetStats(int *, int *, int *, int *);
|
||||
/// C plugin scale video
|
||||
extern void ScaleVideo(int, int, int, int);
|
||||
|
||||
/// Set Pip position
|
||||
extern void PipSetPosition(int, int, int, int, int, int, int, int);
|
||||
/// Pip start
|
||||
extern void PipStart(int, int, int, int, int, int, int, int);
|
||||
/// Pip stop
|
||||
extern void PipStop(void);
|
||||
/// Pip play video packet
|
||||
extern int PipPlayVideo(const uint8_t *, int);
|
||||
|
||||
extern const char *X11DisplayName; ///< x11 display name
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
1046
softhddevice.cpp
1046
softhddevice.cpp
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,7 @@
|
||||
#pragma once
|
||||
|
||||
#define ATMO_GRAB_SERVICE "SoftHDDevice-AtmoGrabService-v1.0"
|
||||
#define ATMO1_GRAB_SERVICE "SoftHDDevice-AtmoGrabService-v1.1"
|
||||
#define OSD_3DMODE_SERVICE "SoftHDDevice-Osd3DModeService-v1.0"
|
||||
|
||||
enum
|
||||
@@ -48,3 +49,17 @@ typedef struct
|
||||
{
|
||||
int Mode;
|
||||
} SoftHDDevice_Osd3DModeService_v1_0_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// request/reply data
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
// reply data
|
||||
|
||||
int size;
|
||||
|
||||
void *img;
|
||||
} SoftHDDevice_AtmoGrabService_v1_1_t;
|
||||
|
||||
74
vdr-softhddevice-9999-pre1.7.36.ebuild
Normal file
74
vdr-softhddevice-9999-pre1.7.36.ebuild
Normal file
@@ -0,0 +1,74 @@
|
||||
# Copyright 1999-2012 Gentoo Foundation
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# $Header: $
|
||||
|
||||
EAPI="4"
|
||||
|
||||
inherit eutils vdr-plugin-2
|
||||
|
||||
if [[ ${PV} == "9999" ]] ; then
|
||||
inherit git-2
|
||||
EGIT_REPO_URI="git://projects.vdr-developer.org/vdr-plugin-softhddevice.git"
|
||||
else
|
||||
SRC_URI="http://projects.vdr-developer.org/attachments/download/838/${P}.tgz"
|
||||
fi
|
||||
|
||||
|
||||
DESCRIPTION="A software and GPU emulated HD output device plugin for VDR."
|
||||
HOMEPAGE="http://projects.vdr-developer.org/projects/show/plg-softhddevice"
|
||||
SRC_URI=""
|
||||
|
||||
LICENSE="AGPL-3"
|
||||
SLOT="0"
|
||||
KEYWORDS="~x86 ~amd64"
|
||||
IUSE="vaapi vdpau alsa oss yaepg opengl debug"
|
||||
|
||||
DEPEND=">=x11-libs/libxcb-1.8
|
||||
x11-libs/xcb-util
|
||||
x11-libs/xcb-util-wm
|
||||
x11-libs/xcb-util-keysyms
|
||||
x11-libs/xcb-util-renderutil
|
||||
x11-libs/libX11
|
||||
opengl? ( virtual/opengl )
|
||||
>=virtual/ffmpeg-0.7
|
||||
sys-devel/gettext
|
||||
sys-devel/make
|
||||
dev-util/pkgconfig
|
||||
yaepg? ( >=media-video/vdr-1.7.23[yaepg] )
|
||||
!yaepg? ( >=media-video/vdr-1.7.23 )
|
||||
vdpau? ( x11-libs/libvdpau virtual/ffmpeg[vdpau] )
|
||||
vaapi? ( x11-libs/libva virtual/ffmpeg[vaapi] )
|
||||
alsa? ( media-libs/alsa-lib )
|
||||
oss? ( sys-kernel/linux-headers )
|
||||
"
|
||||
|
||||
src_prepare() {
|
||||
vdr-plugin-2_src_prepare
|
||||
}
|
||||
|
||||
src_compile() {
|
||||
local myconf
|
||||
|
||||
myconf="-DHAVE_PTHREAD_NAME -DAV_INFO -DAV_INFO_TIME=15000"
|
||||
use vdpau && myconf="${myconf} -DUSE_VDPAU"
|
||||
use vaapi && myconf="${myconf} -DUSE_VAAPI"
|
||||
use alsa && myconf="${myconf} -DUSE_ALSA"
|
||||
use oss && myconf="${myconf} -DUSE_OSS"
|
||||
use debug && myconf="${myconf} -DDEBUG"
|
||||
|
||||
#vdr-plugin-2_src_compile
|
||||
cd "${S}"
|
||||
|
||||
BUILD_TARGETS=${BUILD_TARGETS:-${VDRPLUGIN_MAKE_TARGET:-all}}
|
||||
|
||||
emake ${BUILD_PARAMS} CONFIG="${myconf}" \
|
||||
${BUILD_TARGETS} \
|
||||
LOCALEDIR="${TMP_LOCALE_DIR}" \
|
||||
LIBDIR="${S}" \
|
||||
TMPDIR="${T}" \
|
||||
|| die "emake failed"
|
||||
}
|
||||
|
||||
src_install() {
|
||||
vdr-plugin-2_src_install
|
||||
}
|
||||
@@ -2,73 +2,64 @@
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# $Header: $
|
||||
|
||||
EAPI="3"
|
||||
EAPI="5"
|
||||
|
||||
inherit eutils vdr-plugin
|
||||
inherit flag-o-matic toolchain-funcs vdr-plugin-2 eutils
|
||||
|
||||
if [[ ${PV} == "9999" ]] ; then
|
||||
inherit git-2
|
||||
EGIT_REPO_URI="git://projects.vdr-developer.org/vdr-plugin-softhddevice.git"
|
||||
if [ "${PV}" = "9999" ]; then
|
||||
inherit git-2
|
||||
EGIT_REPO_URI="git://projects.vdr-developer.org/vdr-plugin-softhddevice.git"
|
||||
KEYWORDS=""
|
||||
else
|
||||
SRC_URI="http://projects.vdr-developer.org/attachments/download/838/${P}.tgz"
|
||||
SRC_URI="mirror://vdr-developerorg/889/${P}.tgz"
|
||||
KEYWORDS="~amd64 ~x86"
|
||||
fi
|
||||
|
||||
|
||||
DESCRIPTION="A software and GPU emulated HD output device plugin for VDR."
|
||||
DESCRIPTION="Software and GPU emulated HD output device plugin for VDR"
|
||||
HOMEPAGE="http://projects.vdr-developer.org/projects/show/plg-softhddevice"
|
||||
SRC_URI=""
|
||||
|
||||
LICENSE="AGPL-3"
|
||||
SLOT="0"
|
||||
KEYWORDS="~x86 ~amd64"
|
||||
IUSE="vaapi vdpau alsa oss yaepg opengl debug"
|
||||
IUSE="alsa oss vaapi vdpau yaepg xscreensaver debug"
|
||||
|
||||
DEPEND=">=x11-libs/libxcb-1.8
|
||||
x11-libs/xcb-util
|
||||
x11-libs/xcb-util-wm
|
||||
x11-libs/xcb-util-keysyms
|
||||
x11-libs/xcb-util-renderutil
|
||||
x11-libs/libX11
|
||||
opengl? ( virtual/opengl )
|
||||
>=virtual/ffmpeg-0.7
|
||||
sys-devel/gettext
|
||||
sys-devel/make
|
||||
dev-util/pkgconfig
|
||||
yaepg? ( >=media-video/vdr-1.7.23[yaepg] )
|
||||
!yaepg? ( >=media-video/vdr-1.7.23 )
|
||||
vdpau? ( x11-libs/libvdpau virtual/ffmpeg[vdpau] )
|
||||
vaapi? ( x11-libs/libva virtual/ffmpeg[vaapi] )
|
||||
alsa? ( media-libs/alsa-lib )
|
||||
oss? ( sys-kernel/linux-headers )
|
||||
"
|
||||
|
||||
src_prepare() {
|
||||
vdr-plugin_src_prepare
|
||||
}
|
||||
RDEPEND=">=media-video/vdr-1.7
|
||||
>=virtual/ffmpeg-0.7[vdpau?,vaapi?]
|
||||
x11-libs/libX11
|
||||
>=x11-libs/libxcb-1.8
|
||||
x11-libs/xcb-util-wm
|
||||
alsa? ( media-libs/alsa-lib )
|
||||
vdpau? ( x11-libs/libvdpau )
|
||||
vaapi? ( x11-libs/libva )
|
||||
alsa? ( media-libs/alsa-lib )
|
||||
yaepg? ( >=media-video/vdr-1.7[yaepg] )"
|
||||
DEPEND="${RDEPEND}
|
||||
x11-libs/xcb-util
|
||||
sys-devel/gettext
|
||||
virtual/pkgconfig
|
||||
oss? ( sys-kernel/linux-headers )"
|
||||
|
||||
src_compile() {
|
||||
local myconf
|
||||
local myconf
|
||||
|
||||
myconf="-DHAVE_PTHREAD_NAME"
|
||||
use vdpau && myconf="${myconf} -DUSE_VDPAU"
|
||||
use vaapi && myconf="${myconf} -DUSE_VAAPI"
|
||||
use alsa && myconf="${myconf} -DUSE_ALSA"
|
||||
use oss && myconf="${myconf} -DUSE_OSS"
|
||||
use debug && myconf="${myconf} -DDEBUG"
|
||||
myconf+=" ALSA=$(usex alsa 1 0)"
|
||||
myconf+=" OSS=$(usex oss 1 0)"
|
||||
myconf+=" VDPAU=$(usex vdpau 1 0)"
|
||||
myconf+=" VAAPI=$(usex vaapi 1 0)"
|
||||
myconf+=" SCREENSAVER=$(usex xscreensaver 1 0)"
|
||||
if has_version ">=media-video/ffmpeg-0.8" ; then
|
||||
myconf+=" SWRESAMPLE=1"
|
||||
fi
|
||||
|
||||
emake all CC="$(tc-getCC)" CFLAGS="${CFLAGS}" \
|
||||
LDFLAGS="${LDFLAGS}" CONFIG="${myconf}" LIBDIR="." || die
|
||||
append-cflags -DHAVE_PTHREAD_NAME -D_GNU_SOURCE
|
||||
append-cxxflags -DHAVE_PTHREAD_NAME -D_GNU_SOURCE
|
||||
tc-export CC CXX
|
||||
|
||||
BUILD_PARAMS="${myconf}"
|
||||
vdr-plugin-2_src_compile
|
||||
}
|
||||
|
||||
src_install() {
|
||||
vdr-plugin_src_install
|
||||
vdr-plugin-2_src_install
|
||||
|
||||
dodoc README.txt
|
||||
|
||||
#dodir /etc/vdr/plugins || die
|
||||
#insinto /etc/vdr/plugins
|
||||
#fowners -R vdr:vdr /etc/vdr || die
|
||||
|
||||
#insinto /etc/conf.d
|
||||
#doins vdr.softhddevice
|
||||
dodoc ChangeLog README.txt
|
||||
}
|
||||
|
||||
35
video.h
35
video.h
@@ -1,7 +1,7 @@
|
||||
///
|
||||
/// @file video.h @brief Video module header file
|
||||
///
|
||||
/// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
|
||||
/// Copyright (c) 2009 - 2013 by Johns. All Rights Reserved.
|
||||
///
|
||||
/// Contributor(s):
|
||||
///
|
||||
@@ -30,6 +30,9 @@
|
||||
/// Video hardware decoder typedef
|
||||
typedef struct _video_hw_decoder_ VideoHwDecoder;
|
||||
|
||||
/// Video output stream typedef
|
||||
typedef struct __video_stream__ VideoStream;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Variables
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -37,24 +40,25 @@ typedef struct _video_hw_decoder_ VideoHwDecoder;
|
||||
extern char VideoHardwareDecoder; ///< flag use hardware decoder
|
||||
extern char VideoIgnoreRepeatPict; ///< disable repeat pict warning
|
||||
extern int VideoAudioDelay; ///< audio/video delay
|
||||
extern char ConfigStartX11Server; ///< flag start the x11 server
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/// Allocate new video hardware decoder.
|
||||
extern VideoHwDecoder *VideoNewHwDecoder(void);
|
||||
extern VideoHwDecoder *VideoNewHwDecoder(VideoStream *);
|
||||
|
||||
/// Deallocate video hardware decoder.
|
||||
extern void VideoDelHwDecoder(VideoHwDecoder *);
|
||||
|
||||
#ifdef LIBAVCODEC_VERSION
|
||||
/// Get and allocate a video hardware surface.
|
||||
extern unsigned VideoGetSurface(VideoHwDecoder *);
|
||||
extern unsigned VideoGetSurface(VideoHwDecoder *, const AVCodecContext *);
|
||||
|
||||
/// Release a video hardware surface
|
||||
extern void VideoReleaseSurface(VideoHwDecoder *, unsigned);
|
||||
|
||||
#ifdef LIBAVCODEC_VERSION
|
||||
/// Callback to negotiate the PixelFormat.
|
||||
extern enum PixelFormat Video_get_format(VideoHwDecoder *, AVCodecContext *,
|
||||
const enum PixelFormat *);
|
||||
@@ -110,13 +114,16 @@ extern void VideoSetSaturation(int);
|
||||
extern void VideoSetHue(int);
|
||||
|
||||
/// Set video output position.
|
||||
extern void VideoSetOutputPosition(int, int, int, int);
|
||||
extern void VideoSetOutputPosition(VideoHwDecoder *, int, int, int, int);
|
||||
|
||||
/// Set video mode.
|
||||
extern void VideoSetVideoMode(int, int, int, int);
|
||||
|
||||
/// Set display format.
|
||||
extern void VideoSetDisplayFormat(int);
|
||||
/// Set 4:3 display format.
|
||||
extern void VideoSet4to3DisplayFormat(int);
|
||||
|
||||
/// Set other display format.
|
||||
extern void VideoSetOtherDisplayFormat(int);
|
||||
|
||||
/// Set video fullscreen mode.
|
||||
extern void VideoSetFullscreen(int);
|
||||
@@ -205,8 +212,16 @@ extern void VideoOsdExit(void); ///< Cleanup osd.
|
||||
extern void VideoInit(const char *); ///< Setup video module.
|
||||
extern void VideoExit(void); ///< Cleanup and exit video module.
|
||||
|
||||
extern int VideoPollInput(void); ///< Poll video input buffers.
|
||||
extern int VideoDecodeInput(void); ///< Decode video input buffers.
|
||||
extern int VideoGetBuffers(void); ///< Get number of input buffers.
|
||||
/// Poll video input buffers.
|
||||
extern int VideoPollInput(VideoStream *);
|
||||
|
||||
/// Decode video input buffers.
|
||||
extern int VideoDecodeInput(VideoStream *);
|
||||
|
||||
/// Get number of input buffers.
|
||||
extern int VideoGetBuffers(const VideoStream *);
|
||||
|
||||
/// Raise the frontend window
|
||||
extern int VideoRaiseWindow();
|
||||
|
||||
/// @}
|
||||
|
||||
Reference in New Issue
Block a user