93 Commits
0.5.2 ... 0.6.0

Author SHA1 Message Date
Johns
eab051f5e6 Release Version 0.6.0. 2013-03-17 15:53:01 +01:00
e058302a08 Update german translation. 2013-03-17 15:51:11 +01:00
Johns
efcf3a1d2d Fix Bug #1286: typo. 2013-03-12 23:27:09 +01:00
Johns
1f0d5878b1 Adds H264 only hardware decoder for still-pictures. 2013-03-11 16:32:00 +01:00
Johns
f09a37a941 Enable optional VDR-SPU deocder support. 2013-03-11 12:18:11 +01:00
Johns
a7562eb2be Removes "static" warning. 2013-03-06 17:31:01 +01:00
a747829ffb Adds raise softhddevice video window support. 2013-03-06 17:07:30 +01:00
Johns
7db63875d0 Adds optional only complete mpeg packets support. 2013-03-06 10:30:27 +01:00
Johns
637c04655a Fixes text of EAC-3 pass-through setup. 2013-03-05 14:39:13 +01:00
Johns
9954b939ef Try to connect to X11 server, when start fails. 2013-02-27 16:48:42 +01:00
Johns
e65572c2e2 Updated ebuild for new vdr-plugin-2.eclass. 2013-02-25 16:40:44 +01:00
Johns
b3ddc47cb5 Removes "unused parameter" warnings. 2013-02-25 16:39:32 +01:00
Johns
4d9e3a71f4 More informations in short description. 2013-02-25 16:34:28 +01:00
Johns
21e4f4ee04 Workaround for ffmpeg 1.1.x get_format bug. 2013-02-25 16:33:40 +01:00
Johns
746746d5b7 Workaround for ffmpeg 1.1.2 bug. 2013-02-25 16:32:52 +01:00
Johns
936566c642 Show vaapi droped/missed messages with info level. 2013-02-23 15:56:24 +01:00
Johns
d6f557c6f7 Removes warnings, when compiles without VDPAU. 2013-02-15 15:58:49 +01:00
Johns
2d2ea53d16 Quote spaces to get correct ouput. 2013-02-13 22:47:16 +01:00
Johns
bccd959833 Fix .pot file generation, support _ and _N macros. 2013-02-13 22:46:08 +01:00
Johns
240fc17471 Store pass-through on/off state in setup. 2013-02-13 17:23:18 +01:00
Johns
7b2caac901 Fix bug: still old CodecPassthroughAC3 used. 2013-02-12 22:03:52 +01:00
Johns
56aae221e7 Adds missing USE_SCREENSAVER to old Makefile. 2013-02-12 18:11:40 +01:00
Johns
54255e7b57 Try to use HBR (High Bit-Rate) for EAC3. 2013-02-11 23:40:09 +01:00
Johns
2cd667fb44 Improved pass-through (PCM+EAC3) support. 2013-02-11 16:53:51 +01:00
Johns
145d65ff01 Debug time for channel switch. 2013-02-11 15:11:52 +01:00
Johns
8faff0fd1e Try to detect wrong Makefile use. 2013-02-11 14:41:19 +01:00
Johns
d31ff55b12 Clear buffers quicker, when replay stops. 2013-02-08 21:03:06 +01:00
Johns
d4535a34c9 Fix xcb deadlock while closing PIP decoder.
Close video decoder from inside the decoder thread,
otherwise xcb hangs in a lock.
2013-02-07 16:54:16 +01:00
Johns
ebd2f85f90 Update for new Makefiles. 2013-02-07 10:17:48 +01:00
Johns
dce7ef9110 Adds PIP hot-key support. 2013-02-06 16:27:25 +01:00
Johns
780e2989ae Makes audio mixer optional. 2013-02-06 16:02:22 +01:00
Johns
2661fdf333 Plugin needs -D_GNU_SOURCE. 2013-01-30 18:04:53 +01:00
Johns
2557418e81 No longer needed. 2013-01-29 20:48:04 +01:00
Johns
b48e0d0638 Support VDR 1.7.36 new build system. 2013-01-29 17:04:50 +01:00
Johns
2c27d83b9e Makes buffers soft limit configurable. 2013-01-28 23:13:23 +01:00
Johns
8b22585748 Never trust the docs: fix ffmpeg downsample. 2013-01-26 00:18:59 +01:00
Johns
7ed6975330 Support upsampling 3,5 to 8 channels.
Improve next ring buffer handling.
Improve audio/video sync debug.
2013-01-25 17:05:53 +01:00
Johns
d5e111238d Improves VDPAU dissplay preemption handling. 2013-01-25 16:55:25 +01:00
2733e47af7 Add modifiers to X11 remote key names. 2013-01-25 16:52:23 +01:00
Johns
f9998e7664 Add audio compatibility with >=ffmpeg 1.1. 2013-01-24 21:42:39 +01:00
Johns
04286fb2ad Add video compatibility with >=ffmpeg 1.1. 2013-01-23 21:54:56 +01:00
Johns
cd82ee8e4a Fix bug: no sound with video output "none". 2013-01-22 17:18:18 +01:00
Johns
a1f17199d6 Crop setup is done by VdpauSetupOutput. 2013-01-22 17:08:44 +01:00
Johns
849ca7cfd6 Stronger H264/Mpeg detection tests. 2013-01-12 19:13:43 +01:00
Johns
308742a927 React faster only with mpeg. 2013-01-11 18:54:45 +01:00
Johns
1a730ef90b Fix build without USE_PIP. 2013-01-09 00:39:27 +01:00
Johns
d59c2ad40b Must guard CodecVideoDecode. 2013-01-08 23:52:41 +01:00
Johns
3366faece2 Fixes close PIP threading bug. 2013-01-08 21:11:46 +01:00
Johns
2bb2875cd7 Update PIP only, when visible. 2013-01-07 19:31:05 +01:00
Johns
e88403d044 Close pip before switching channel. 2013-01-07 17:47:05 +01:00
Johns
11293e8dc1 Split mpeg packets in receiver thread. 2013-01-07 16:55:42 +01:00
Johns
3bcc3d280e fprints only when building debug version. 2013-01-06 19:17:02 +01:00
Johns
55587c86f0 Switch PIP to only available channels. 2013-01-06 19:15:46 +01:00
Johns
7cc74795be Fix bug: missing external reference with -DUSE_PIP. 2013-01-06 19:14:46 +01:00
Johns
534b4094b5 Fix thread exit problem. 2013-01-06 14:47:00 +01:00
Johns
7cd025a023 Cosmetic cleanups. 2013-01-06 14:06:08 +01:00
Johns
b14a67b601 New features documented. 2013-01-05 23:16:03 +01:00
Johns
b24409323d Fix detach and attach bug. 2013-01-05 22:48:01 +01:00
Johns
9ec2716026 PIP function update. 2013-01-05 20:47:14 +01:00
Johns
fa09d940c5 Fix PIP threading problems. 2013-01-05 20:44:54 +01:00
Johns
d4702b9a9e Include softhddevice.cpp in indent target.
Fix constconst after indent.  Hello GNU who many years until it will be
fixed?
2013-01-05 19:49:59 +01:00
Johns
6a3a560857 Adds PIP channel switch functions. 2013-01-05 17:17:50 +01:00
Johns
8ee1e84b2e Restore video position, when PIP closes. 2013-01-05 16:37:25 +01:00
Johns
7e96a292eb First video surface clears complete window. 2013-01-05 15:41:57 +01:00
Johns
d89ada9aad Makes PIP+Video position configurable. 2013-01-04 21:50:55 +01:00
Johns
59d1a6b1f2 Adds function to stop PIP. 2013-01-04 18:50:14 +01:00
Johns
1a744a8eb8 Sync to audio only with the first video stream. 2013-01-04 18:04:53 +01:00
Johns
78100cba00 Use second stream for PIP. 2013-01-04 15:56:26 +01:00
Johns
b54ddd4549 Enable more than 1 vdpau video stream. 2013-01-04 15:54:32 +01:00
Johns
d42475f2dc Prepared reentrant video stream. 2013-01-03 18:52:34 +01:00
Johns
7cf6c1ab2b va-api has problems with h264 interlace. 2013-01-03 01:03:22 +01:00
Johns
06b8e3d784 Fix video size not updated for VAAPI. 2013-01-02 23:59:46 +01:00
63c22a13cf Adds VDR SeduAtmo Plugin support. 2013-01-01 17:58:54 +01:00
Johns
3d5e59a6e5 Support multiple streams with ScaleVideo. 2013-01-01 15:21:28 +01:00
Johns
acf377ec60 Makes 4:3 and 16:9 display format configurable.
Don't use DVB display format.
2013-01-01 14:48:51 +01:00
87c1c7be84 Add support for new vdr ScaleVideo API. 2013-01-01 12:51:08 +01:00
Johns
5bacd0cf7b Comments cleanup. 2013-01-01 12:40:12 +01:00
Johns
b1beb49798 Add support for old PES HDTV recording. 2013-01-01 12:09:54 +01:00
Johns
33b14be516 Change VideoSetOutputPosition to work OSD relative. 2012-12-31 17:51:43 +01:00
Johns
3907f3eb2f Change +%d to %+d, which is more general. 2012-12-31 17:11:22 +01:00
Johns
00d314dcd1 Disable trickspeed hack, to prevent ffmpeg crash. 2012-12-31 14:03:19 +01:00
Johns
9719fef55b Fix video size not updated, when window size change. 2012-12-30 17:05:42 +01:00
Johns
9b69045a20 Use 1 surface reserve. 2012-12-24 12:59:35 +01:00
Johns
966ff4229a Better video stream window position support. 2012-12-24 12:23:16 +01:00
Johns
e0c0c2021f Need LOCALEDIR to build as user. 2012-12-24 11:56:10 +01:00
Johns
a3907d11a5 Spam syslog with a/v sync infos. 2012-12-24 11:55:32 +01:00
Johns
b94d19e7b8 Make clear what downmix is enabled. 2012-12-24 11:53:16 +01:00
Johns
943ee22aa5 Makes X11 server arguments configurable. 2012-12-14 17:24:54 +01:00
Johns
b6154a988f Fix build with NO_TS_AUDIO. 2012-12-14 17:04:50 +01:00
Johns
932871dea9 Use vdr-plugin-2. 2012-11-30 20:46:13 +01:00
Johns
5ec6963398 Missing space added. 2012-11-25 00:38:32 +01:00
Johns
b04323704d Missing space added. 2012-11-25 00:35:39 +01:00
38011d51b6 Add german translation. 2012-11-18 21:17:09 +01:00
19 changed files with 5351 additions and 1215 deletions

View File

@@ -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
View File

@@ -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
View 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 $@

View File

@@ -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
View File

@@ -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
View File

@@ -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;

View File

@@ -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
View File

@@ -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
View File

@@ -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
//----------------------------------------------------------------------------

View File

@@ -1,2 +0,0 @@
#!/bin/sh
exec make VDRDIR=/usr/include/vdr LIBDIR=. "$@"

1366
po/de_DE.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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;

View 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
}

View File

@@ -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
}

1304
video.c

File diff suppressed because it is too large Load Diff

35
video.h
View File

@@ -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();
/// @}