71 Commits
0.1.3 ... 0.4.0

Author SHA1 Message Date
Johns
fa27a1c73a Release Version 0.4.0. 2012-01-21 15:56:45 +01:00
Johns
e32857a27a VDPAU: Add screenshot support. 2012-01-20 21:46:22 +01:00
Johns
5ba88bb822 Use common module prefix. 2012-01-20 19:56:06 +01:00
Johns
0422b6aa5a VDPAU: Add auto-crop support. 2012-01-20 15:33:37 +01:00
Johns
eb024558de VDPAU: Changed OSD alpha calculation. 2012-01-19 22:58:02 +01:00
Johns
1593d5dd83 Fix bug: Used VideoSharpen for denoise settings.
Instant update deinterlace/... configuration changes.
2012-01-19 21:28:38 +01:00
Johns
09f62307d4 Fix bug: AudioExit called without AudioInit crash. 2012-01-19 17:01:02 +01:00
Johns
87f7aa63cc Release Version 0.3.5. 2012-01-19 16:01:05 +01:00
Johns
b1ce88923e Small miscellaneous cleanups. 2012-01-19 00:16:15 +01:00
Johns
c6e66e0787 OSD improvements:
Use OSD size equal to video window.
Update only dirty area(s) of OSD.
Show/mix only used area of OSD.
Fix bug: vpdau use previous resolution for deint, ...
2012-01-18 15:15:37 +01:00
Johns
19d4eeed82 Little speed improved Intel VA-API deinterlace. 2012-01-17 18:53:53 +01:00
Johns
9f668c4750 Fix software deinterlace with VA-API. 2012-01-17 17:41:24 +01:00
Johns
e419742a40 OSS needs kernel headers. 2012-01-16 23:55:45 +01:00
Johns
2cacdc6c90 Debug, if vaapi putsurface is too slow. 2012-01-16 23:54:48 +01:00
Johns
6efe558f78 Fix bug: transposed digits 567 should be 576. 2012-01-16 20:20:01 +01:00
Johns
80100299f3 Disable VA-API if init fails. 2012-01-16 17:05:22 +01:00
Johns
5509d768ac Remove double x11-libs/xcb-util-wm. 2012-01-16 16:39:23 +01:00
Johns
c0d0a4ae7c Audio module cleanup (more to come).
Alsa + OSS can be included/build at the same time.
Alsa or OSS can be runtime selected with -a.
Add audio thread support to OSS module.
Add polled audio support to alsa module.
Removed some debug source code.
2012-01-16 15:42:17 +01:00
Johns
e619f5c836 Release Version 0.3.1. 2012-01-15 16:57:03 +01:00
Johns
973fcfe4dd Support BBC-HD (no clean solution). 2012-01-15 14:31:54 +01:00
Johns
eec30433b6 Fix bug: AudioFreeBytes fails if no audio ready. 2012-01-13 22:39:04 +01:00
Johns
baf577aba5 Fix bug: snd_pcm_state: Assertion `pcm' failed. 2012-01-13 19:33:59 +01:00
Johns
81d7ef9755 Support xcb_ewmh.h for xcb-util <0.3.8. 2012-01-13 17:20:43 +01:00
Johns
7f7de8678f Add support for fullscreen mode. 2012-01-13 16:31:29 +01:00
Johns
92bb00c410 Add vaapi color space conversion. 2012-01-13 12:28:56 +01:00
Johns
d3b98b90f4 Fix bug: devision by zero in ...UpdateOutput, 2012-01-13 10:04:26 +01:00
Johns
788636ee6b Destroy vdpau surface only, when initialized. 2012-01-13 00:58:30 +01:00
Johns
8e53cbd4a9 VAAPI: Instant use new deinterlace configuration. 2012-01-12 23:07:06 +01:00
Johns
54661f90ea Weave is deinterlace disabled. 2012-01-12 20:54:49 +01:00
Johns
30d8e8afe9 Fix subtitle position. 2012-01-12 18:55:07 +01:00
Johns
19a37bb0bf Add SVDRP support. 2012-01-12 15:20:01 +01:00
Johns
2087968d55 Rebuild objects, when Makefile changes. 2012-01-12 15:19:19 +01:00
Johns
d983f780b3 Suspend when user is inactive. 2012-01-11 18:01:18 +01:00
712b2e0de1 Patch collection from Christian Ruppert.
Move objects before $LIBS to avoid link failures with --as-needed.
Do not override CFLAGS for video test.
Rearrange *FLAGS incl. some minor fixes.
Don't override VDRDIR, LIBDIR and TMPDIR in makefile.
Don't abuse LDFLAGS in makefile.
Define CC in makefile.
Include GL/gl.h for the GL_COLOR_BUFFER_BIT definition.
VideoInit() needs an argument.
2012-01-10 22:48:42 +01:00
Johns
54f92e67fc Don't mute hardware while replaying. 2012-01-10 16:41:46 +01:00
Johns
960cd27ab5 Add support for close and resize x11 window. 2012-01-10 15:53:54 +01:00
Johns
3a97700981 Add main menu entry, which suspends the plugin. 2012-01-10 15:52:07 +01:00
Johns
8d624224e9 Version 0.3.0 released. 2012-01-09 22:10:42 +01:00
Johns
96eefca699 Video improvements.
Fix generate of video output from StillPicture.
Add support for resolution dependend video parameterts (Deinterlace,
Scaling, Denoise, Sharpen, ...).
2012-01-09 17:03:04 +01:00
Johns
5e005eeff5 Fix audio crash in ThreadExit and snd_pcm_prepare. 2012-01-09 15:31:47 +01:00
Johns
f6df79e8e6 Improved replay of recordings. 2012-01-08 21:46:00 +01:00
Johns
f1551cd321 Ebuild bug fix. 2012-01-08 14:19:48 +01:00
Johns
9568c5bd93 Fix build with vdr without yaepg support. 2012-01-07 23:47:07 +01:00
Johns
fd60c3c132 Support yaepghd video output position change.
And code and comments cleanups.
2012-01-07 22:36:06 +01:00
Johns
7b6d0ecf94 Gentoo ebuild. 2012-01-07 17:30:27 +01:00
Johns
cac1e5ce17 Release Version 0.2.0. 2012-01-07 13:21:27 +01:00
Johns
d6e2d04505 Fix compiler error with -DDEBUG. 2012-01-07 03:13:33 +01:00
Johns
45a34a3381 Add support for ac3 audio pass through. 2012-01-07 03:05:43 +01:00
Johns
92ffd978b0 Add workaround for alsa not playing hdmi sound.
Without open/close pcm, hdmi is quiet after second snd_pcm_set_params.
2012-01-07 02:35:49 +01:00
Johns
878813f206 Fix bug: broken device plugin stop and exit. 2012-01-06 15:39:32 +01:00
Johns
cb2314837c uwm window manager hide cursor workaround. 2012-01-06 15:37:21 +01:00
Johns
820c246148 Fix bug: old surface stay in video ringbuffer. 2012-01-05 22:55:57 +01:00
Johns
8dda2a0b8a Show transparent cursor to hide cursor. 2012-01-05 22:33:14 +01:00
Johns
761c06eac1 Add color standard support to vdpau. 2012-01-05 20:24:18 +01:00
Johns
0776bc5ee4 VDPAU improvements.
Add denoise, sharpness, skip chroma deinterlace support.
Show OSD only if something is to display, improves performance.
Add deinterlace mode with only 4 surfaces.
2012-01-05 17:20:44 +01:00
Johns
aba14813c0 Add OSS Mixer support. 2012-01-04 16:59:48 +01:00
Johns
0f449c2394 Remove warnings, reduce debug informations. 2012-01-04 16:58:35 +01:00
Johns
9a30d387a1 Crash and thread fixes.
Check if PTS is valid, otherwise debug code does false abort.
Fix bug: audio new stream is not thread safe.
2012-01-03 22:10:04 +01:00
Johns
c8e70ec0fe Audio update.
Alsa: report needed down sampling of 3/5/6 to 2 channels.
Moved alsa code into alsa module.
Initial OSS output support.
2012-01-03 21:42:39 +01:00
Johns
5546354cc7 Version bump. 2012-01-02 19:31:08 +01:00
Johns
442e021d87 Lock av_open/close calls.
New ffmpeg dislikes simultaneous open/close from audio/video.
Prepared audio decoder without av_parser_parse2.
Handle av_audio_resample_init errors.
2012-01-02 17:47:50 +01:00
Johns
4301718329 Documents updates. 2012-01-02 15:27:03 +01:00
Johns
3b7688b78b Print debug only, if compiled with -DDEBUG. 2012-01-02 15:21:58 +01:00
Johns
d2606a5d5f Search audio sync inside PES packets. 2012-01-01 21:14:15 +01:00
Johns
0d63fac2e8 Use only the needed number of surfaces.
Fix problem with video-xvba and too many surfaces used.
Prepare new audio driver "oss".
2011-12-31 18:55:07 +01:00
Johns
c8c760a069 Make pthread_setname_np optional for older glibc. 2011-12-31 17:28:58 +01:00
Johns
0c7170989d Remove warning, when building without vdpau. 2011-12-30 21:50:58 +01:00
Johns
12bfab3f10 Name threads for easier debugging. 2011-12-30 16:47:57 +01:00
Johns
bded2ae5df Prepared vdpau noise reduction support. 2011-12-29 19:45:00 +01:00
Johns
1f2d1d235e Vpdau displays black, when no video available. 2011-12-29 17:47:21 +01:00
Johns
f179264468 Fix bug: CodecVideoDecode destroys avpkt. 2011-12-29 13:43:12 +01:00
15 changed files with 5892 additions and 1541 deletions

106
ChangeLog
View File

@@ -1,4 +1,110 @@
User johns User johns
Date: Sat Jan 21 15:49:16 CET 2012
Release Version 0.4.0
VDPAU: Add grab image support.
VDPAU: Add auto-crop support.
VDPAU: Changed OSD alpha calculation.
Fix bug: Used VideoSharpen for denoise settings.
Instant update deinterlace/... configuration changes.
Fix bug: AudioExit called without AudioInit crash.
Date: Thu Jan 19 15:58:40 CET 2012
Release Version 0.3.5
OSD improvements:
Use OSD size equal to video window.
Update only dirty area(s) of OSD.
Show/mix only used area of OSD.
Fix bug: vpdau use previous resolution for deint, ...
Fix software deinterlace with VA-API.
Fix bug: transposed digits 567 should be 576.
Audio module cleanup:
Alsa + OSS can be included/build at the same time.
Alsa or OSS can be runtime selected with -a.
Add audio thread support to OSS module.
Add polled audio support to alsa module.
Removed some debug source code.
Date: Sun Jan 15 16:56:04 CET 2012
Release Version 0.3.1
Fix bug: AudioFreeBytes didn't check if audio running/compiled.
Fix bug: snd_pcm_state: Assertion `pcm' failed.
Add support for fullscreen and fullscreen toogle.
Instant update deinterlace configuration changes.
Fix subtitle position.
Add SVDRP support.
Suspend when user is inactive.
User Christian Rupper
Date: Tue Jan 10 22:33:14 CET 2012
Move objects before $LIBS to avoid link failures with --as-needed.
Do not override CFLAGS for video test.
Rearrange *FLAGS incl. some minor fixes.
Don't override VDRDIR, LIBDIR and TMPDIR in makefile.
Don't abuse LDFLAGS in makefile.
Define CC in makefile.
Include GL/gl.h for the GL_COLOR_BUFFER_BIT definition.
VideoInit() needs an argument.
User johns
Date: Tue Jan 10 22:32:50 CET 2012
Add main menu entry, which suspends the plugin.
Add support for resize window.
Close window sends "close" as remote key press.
Date: Mon Jan 9 22:09:38 CET 2012
Release Version 0.3.0
Add support of resolution dependend video parameters (deint, scale, ...).
Add support for recording play back.
Add workaround for alsa crash in snd_pcm_prepare.
Fix bug: audio crash on exit.
Fix build with vdr without yaepg support.
Support yaepghd video picture output position change.
Date: Sat Jan 7 13:20:07 CET 2012
Release Version 0.2.0
Add support for ac3 audio pass through.
Add workaround for alsa not playing hdmi sound.
Fix bug: broken device plugin stop and exit.
Show transparent cursor to hide cursor.
VDPAU: Add color standard support.
VDPAU: Add denoise and sharpness support.
VDPAU: Add skip chroma deinterlace support.
VDPAU: Show OSD only if something is to display, improves performance.
VDPAU: Add deinterlace with only 4 surfaces.
Date: Thu Jan 4 17:00:00 CET 2012
Release Version 0.1.5
Adds OSS mixer support.
Fix bug: audio new stream is not thread safe.
New audio driver OSS.
Fix bug: needed down sampling of 3/5/6 to 2 channels not reported.
Search audio sync inside PES packets, for insane dvb streams.
Use only the needed number of surfaces.
Date: Thu Dec 29 19:44:43 CET 2011
Release Version 0.1.4
Prepared vdpau noise reduction support.
Vdpau also displays a black surface, when no video is available.
Fix bug: CodecVideoDecode destroys avpkt.
Date: Thu Dec 29 00:55:57 CET 2011
Release Version 0.1.3
Add missing VdpauDecoderDestroy.
Cleanup video packet ringbuffer.
Allow build without VDPAU.
Fix bug: swapped end and start.
Support other than "PCM" alsa mixer channels.
Date: Sat Dec 24 15:26:27 CET 2011 Date: Sat Dec 24 15:26:27 CET 2011
Release Version 0.1.2 Release Version 0.1.2

View File

@@ -14,36 +14,30 @@ PLUGIN = softhddevice
### The version number of this plugin (taken from the main source file): ### 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') 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) ### Configuration (edit this for your needs)
CONFIG := #-DDEBUG CONFIG := #-DDEBUG
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI") #CONFIG += -DHAVE_PTHREAD_NAME
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU") 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: ### The C++ compiler and options:
CC ?= gcc
CXX ?= g++ CXX ?= g++
CXXFLAGS ?= -g -O2 -W -Wall -Wextra -Woverloaded-virtual -fPIC
override CXXFLAGS += $(DEFINES) $(INCLUDES)
CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \ CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \
-Wdeclaration-after-statement -fPIC -Wdeclaration-after-statement
#CFLAGS += -Werror CXXFLAGS ?= -g -O2 -W -Wall -Wextra -Woverloaded-virtual
override CFLAGS += $(DEFINES) $(INCLUDES) \
$(shell pkg-config --cflags alsa libavcodec libavformat)
override LDFLAGS += -lrt \
$(shell pkg-config --libs alsa libavcodec libavformat) \
`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` \
`pkg-config --libs vdpau` \
`pkg-config --libs libva-x11 libva-glx libva`
### The directory environment: ### The directory environment:
VDRDIR = ../../.. VDRDIR ?= ../../..
LIBDIR = ../../lib LIBDIR ?= ../../lib
TMPDIR = /tmp TMPDIR ?= /tmp
### Make sure that necessary options are included: ### Make sure that necessary options are included:
@@ -62,11 +56,40 @@ APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDI
ARCHIVE = $(PLUGIN)-$(VERSION) ARCHIVE = $(PLUGIN)-$(VERSION)
PACKAGE = vdr-$(ARCHIVE) PACKAGE = vdr-$(ARCHIVE)
### Includes and Defines (add further entries here): ### Includes, Defines and dependencies (add further entries here):
INCLUDES += -I$(VDRDIR)/include INCLUDES += -I$(VDRDIR)/include
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' \
$(if $(GIT_REV), -DGIT_REV='"$(GIT_REV)"')
_CFLAGS = $(DEFINES) $(INCLUDES) \
$(shell pkg-config --cflags libavcodec libavformat) \
`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`)
#override _CFLAGS += -Werror
override CXXFLAGS += $(_CFLAGS)
override CFLAGS += $(_CFLAGS)
LIBS += -lrt \
$(shell pkg-config --libs libavcodec libavformat) \
`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`)
### The object files (add further files here): ### The object files (add further files here):
@@ -89,6 +112,8 @@ DEPFILE = .dependencies
$(DEPFILE): Makefile $(DEPFILE): Makefile
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(SRCS) >$@ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(SRCS) >$@
$(OBJS): Makefile
-include $(DEPFILE) -include $(DEPFILE)
### Internationalization (I18N): ### Internationalization (I18N):
@@ -121,7 +146,7 @@ i18n: $(I18Nmsgs) $(I18Npot)
### Targets: ### Targets:
libvdr-$(PLUGIN).so: $(OBJS) Makefile libvdr-$(PLUGIN).so: $(OBJS) Makefile
$(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@ $(LDFLAGS) $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -fPIC $(OBJS) -o $@ $(LIBS)
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION) @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
dist: $(I18Npo) clean dist: $(I18Npo) clean
@@ -147,5 +172,5 @@ indent:
done done
video_test: video.c video_test: video.c
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $(LIBS) \ $(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $< $(LIBS) \
-O0 -g -o $@ $< -o $@

View File

@@ -1,6 +1,6 @@
@file README.txt @brief A software HD output device for VDR @file README.txt @brief A software HD output device for VDR
Copyright (c) 2011 by Johns. All Rights Reserved. Copyright (c) 2011, 2012 by Johns. All Rights Reserved.
Contributor(s): Contributor(s):
@@ -20,14 +20,24 @@ $Id$
A software and GPU emulated HD output device plugin for VDR. A software and GPU emulated HD output device plugin for VDR.
o Video VA-API/VA-API o Video VA-API/VA-API (with intel, nvidia and amd backend supported)
o Video CPU/VA-API
o Video VDPAU/VDPAU
o Video CPU/VDPAU
o Audio FFMpeg/Alsa/Analog
o Audio FFMpeg/Alsa/Digital
o Audio FFMpeg/OSS/Analog
o HDMI/SPDIF Passthrough
o VA-API bob software deinterlace
o Auto-crop
o planned: Video VA-API/Opengl o planned: Video VA-API/Opengl
o planned: Video VDPAU/Opengl
o planned: Video CPU/Xv o planned: Video CPU/Xv
o planned: Video CPU/Opengl o planned: Video CPU/Opengl
o planned: Software Deinterlacer o planned: Improved Software Deinterlacer (yadif or/and ffmpeg filters)
o Audio FFMpeg/Analog o planned: Video XvBA/XvBA
o Audio FFMpeg/Digital o planned: atmo light support
o planned: HDMI/SPDIF Passthrough
To compile you must have the 'requires' installed. To compile you must have the 'requires' installed.
@@ -54,46 +64,130 @@ Install:
http://projects.vdr-developer.org/projects/plg-softhddevice/files http://projects.vdr-developer.org/projects/plg-softhddevice/files
tar vxf vdr-softhddevice-*.tar.bz2 tar vxf vdr-softhddevice-*.tar.bz2
cd vdr-softhddevice cd softhddevice-*
make VDRDIR=<path-to-your-vdr-files> LIBDIR=. make VDRDIR=<path-to-your-vdr-files> LIBDIR=.
You can edit Makefile to enable/disable VDPAU / VA-API / Alsa / OSS
support.
Setup: environment Setup: environment
------
Following is supported: Following is supported:
DISPLAY=:0.0 DISPLAY=:0.0
x11 display name x11 display name
only if alsa is configured
ALSA_DEVICE=default ALSA_DEVICE=default
alsa PCM device name alsa PCM device name
ALSA_MIXER=default ALSA_MIXER=default
alsa control device name alsa control device name
ALSA_MIXER_CHANNEL=PCM ALSA_MIXER_CHANNEL=PCM
alsa control channel name alsa control channel name
only if oss is configured
OSS_AUDIODEV=/dev/dsp
oss dsp device name
OSS_MIXERDEV=/dev/mixer
oss mixer device name
OSS_MIXER_CHANNEL=pcm
oss mixer channel name
Setup: /etc/vdr/setup.conf Setup: /etc/vdr/setup.conf
------
Following is supported: Following is supported:
softhddevice.Deinterlace = 0
0 = bob, 1 = weave, 2 = temporal, 3 = temporal_spatial, 4 = software
(only 0, 1 supported)
softhddevice.MakePrimary = 1 softhddevice.MakePrimary = 1
0 = no change, 1 make softhddevice primary at start 0 = no change, 1 make softhddevice primary at start
softhddevice.Scaling = 0 softhddevice.HideMainMenuEntry = 0
0 = show softhddevice main menu entry, 1 = hide entry
<res> of the next parameters is 567i, 720p, 1080i_fake or 1080i.
1080i_fake is 1280x1080 or 1440x1080
1080i is "real" 1920x1080
softhddevice.<res>.Scaling = 0
0 = normal, 1 = fast, 2 = HQ, 3 = anamorphic 0 = normal, 1 = fast, 2 = HQ, 3 = anamorphic
softhddevice.<res>.Deinterlace = 0
0 = bob, 1 = weave, 2 = temporal, 3 = temporal_spatial, 4 = software
(only 0, 1 supported with vaapi)
softhddevice.<res>.SkipChromaDeinterlace = 0
0 = disabled, 1 = enabled (for slower cards, poor qualit<69>t)
softhddevice.<res>.Denoise = 0
0 .. 1000 noise reduction level (0 off, 1000 max)
softhddevice.<res>.Sharpness = 0
-1000 .. 1000 noise reduction level (0 off, -1000 max blur,
1000 max sharp)
softhddevice.AudioDelay = 0 softhddevice.AudioDelay = 0
+n or -n ms +n or -n ms
softhddevice.AudioPassthrough = 0
0 = none, 1 = AC-3
softhddevice.AutoCrop.Interval = 0
0 disables auto-crop
n each 'n' frames auto-crop is checked.
softhddevice.AutoCrop.Delay = 0
if auto-crop is over after 'n' intervals the same, the cropping is
used.
Setup: /etc/vdr/remote.conf
------
Add "XKeySym." definitions to /etc/vdr/remote.conf to control
the vdr and plugin with the connected input device.
fe.
XKeySym.Up Up
XKeySym.Down Down
...
Additional to the x11 input sends the window close button "Close".
fe.
XKeySym.Power Close
Commandline:
------------
Use vdr -h to see the command line arguments support by the plugin.
-a audio_device
Selects audio output module and device.
"" to disable audio output
/... to use oss audio module (if compiled with oss
support)
other to use alsa audio module (if compiled with alsa
support)
Running:
--------
Click into video window to toggle fullscreen/window mode, only if you
have a window manager running.
Warning:
--------
libav is not supported, expect many bugs with it.
Requires: Requires:
--------- ---------
media-video/ffmpeg media-video/ffmpeg (version >=0.7)
Complete solution to record, convert and stream audio and Complete solution to record, convert and stream audio and
video. Includes libavcodec. video. Includes libavcodec.
http://ffmpeg.org http://ffmpeg.org
media-libs/alsa-lib media-libs/alsa-lib
Advanced Linux Sound Architecture Library Advanced Linux Sound Architecture Library
http://www.alsa-project.org http://www.alsa-project.org
or
kernel support for oss/oss4 or alsa oss emulation
x11-libs/libva x11-libs/libva
Video Acceleration (VA) API for Linux Video Acceleration (VA) API for Linux
http://www.freedesktop.org/wiki/Software/vaapi http://www.freedesktop.org/wiki/Software/vaapi
@@ -104,7 +198,7 @@ Requires:
x11-libs/vdpau-video x11-libs/vdpau-video
VDPAU Backend for Video Acceleration (VA) API VDPAU Backend for Video Acceleration (VA) API
http://www.freedesktop.org/wiki/Software/vaapi http://www.freedesktop.org/wiki/Software/vaapi
or untested or
x11-libs/xvba-video x11-libs/xvba-video
XVBA Backend for Video Acceleration (VA) API XVBA Backend for Video Acceleration (VA) API
http://www.freedesktop.org/wiki/Software/vaapi http://www.freedesktop.org/wiki/Software/vaapi
@@ -116,7 +210,7 @@ Requires:
x11-libs/xcb-util-keysyms x11-libs/xcb-util-keysyms
X C-language Bindings library X C-language Bindings library
http://xcb.freedesktop.org http://xcb.freedesktop.org
Only versions >= 0.3.8 are supported Only versions >= 0.3.8 are good supported
x11-libs/libX11 x11-libs/libX11
X.Org X11 library X.Org X11 library

122
Todo
View File

@@ -1,53 +1,115 @@
@file Todo @brief A software HD output device for VDR
Copyright (c) 2011, 2012 by Johns. All Rights Reserved.
Contributor(s):
License: AGPLv3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
$Id: $
missing: missing:
video out with xv software deinterlace (yadif, ...)
video out with opengl software decoder with software deinterlace
software decoder for xv / opengl zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
software deinterlace ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
auto crop suspend output / energie saver: stop audio, stop video, configurable
atmolight Option deinterlace off / deinterlace force!
zoom/fit-zoom 4:3 Make output drivers better modular (under construction).
multistream handling
video:
subtitle not cleared
subtitle could be asyncron
reduce warnings after channel switch
vdpau: vdpau:
1080i with temporal spatial too slow GT 520 VdpPreemptionCallback handling (under construction)
VdpPreemptionCallback handling hard channel switch
Loose a surface suspendoutput didn't show logo or black picture.
libva:
hard channel switch
yaepghd (VaapiSetOutputPosition) support
can associate ony displayed part of osd
auto crop for va-api
grab image for va-api
libva: branch vaapi-ext
add support for vaapi-ext
libva-intel-driver: libva-intel-driver:
intel still has hangups most with 1080i intel still has hangups most with 1080i
1080i does no v-sync (workaround written) 1080i does no v-sync (workaround written, fixed with vaapi-ext)
osd has sometimes wrong size (workaround written) OSD has sometimes wrong size (workaround written)
libva-vdpau-driver: libva-vdpau-driver:
G210 osd update too slow (needs hardware problem workaround) G210/GT520 OSD update too slow (needs hardware problem workaround)
OSD update is too slow
hangup on exit (VaapiDelDecoder -> VaapiCleanup hangup on exit (VaapiDelDecoder -> VaapiCleanup
-> vaDestroyContext -> pthread_rwlock_wrlock) -> vaDestroyContext -> pthread_rwlock_wrlock)
libva-xvba-driver: libva-xvba-driver:
mpeg1/2 needs software decoder fixed
x11: x11:
support resize of x11 window disable screensaver
support fullscreen window
support fullscreen / window toggle audio:
close window should send power button write TS -> PES parser, which feeds audio before the next start packet
disable cursor CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
Combine alsa+oss ringbuffer code.
Make alsa thread/polled and oss thread/polled output module runtime
selectable.
audio/alsa: audio/alsa:
video/audio asyncron better downmix of >2 channels on 2 channel hardware
random crash in av_parser_parse2, when switching channels remix support of unsupported sample rates
libav supports only resample of mono to 2 channels
ffmpeg didn't support resample of 5 to 2 channels
playback of >2 channels on 2 channel hardware audio/oss:
done? alsa oss emulation mixer "pcm" not working
ring buffer overflow with alsa oss emulation
on some channels it takes long time until sound can be heared. HDMI/SPDIF Passthrough:
this channels has packet start not at the beginning of the start packet only AC-3 written
Channels are wrong setup, if changing setting during operation.
split pcm and ac-3 out into two devices
support oss pass-through
playback of recording playback of recording
play back is too fast pause is not reset, when replay exit
replay/pause need 100% cpu
setup: setup:
Setup menu parameters aren't automatic loaded? Setup of decoder type.
Setup parameters are not used until restart. 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? Can a notice be added to the setup menu?
unsorted:
Menu -> Setup -> Plugins -> skingenigmang -> General
-> Try 8bpp single area: no, has missing parts.
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
atmolight support
multistream handling
pip support
grab image with jpeg
upmix stereo to AC-3

1737
audio.c

File diff suppressed because it is too large Load Diff

14
audio.h
View File

@@ -1,7 +1,7 @@
/// ///
/// @file audio.h @brief Audio module headerfile /// @file audio.h @brief Audio module headerfile
/// ///
/// Copyright (c) 2009 - 2011 by Johns. All Rights Reserved. /// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
/// ///
/// Contributor(s): /// Contributor(s):
/// ///
@@ -28,21 +28,21 @@
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
extern void AudioEnqueue(const void *, int); ///< buffer audio samples extern void AudioEnqueue(const void *, int); ///< buffer audio samples
extern void AudioFlushBuffers(void); ///< flush audio buffers
extern void AudioPoller(void); ///< poll audio events/handling
extern int AudioFreeBytes(void); ///< free bytes in audio output
//extern int AudioFreeBytes(void); ///< free bytes in audio output
//extern int AudioUsedBytes(void); ///< used bytes in audio output //extern int AudioUsedBytes(void); ///< used bytes in audio output
extern uint64_t AudioGetDelay(void); ///< get current audio delay
extern void AudioSetClock(int64_t); ///< set audio clock base extern void AudioSetClock(int64_t); ///< set audio clock base
extern int64_t AudioGetClock(); ///< get current audio clock extern int64_t AudioGetClock(); ///< get current audio clock
extern void AudioSetVolume(int); ///< set volume
extern uint64_t AudioGetDelay(void); ///< get current audio delay
extern int AudioSetup(int *, int *); ///< setup audio output extern int AudioSetup(int *, int *); ///< setup audio output
//extern void AudioPlay(void); ///< play audio //extern void AudioPlay(void); ///< play audio
//extern void AudioPause(void); ///< pause audio //extern void AudioPause(void); ///< pause audio
extern void AudioSetVolume(int); ///< set volume
extern void AudioSetDevice(const char *); ///< set alsa PCM audio device extern void AudioSetDevice(const char *); ///< set PCM audio device
extern void AudioInit(void); ///< setup audio module extern void AudioInit(void); ///< setup audio module
extern void AudioExit(void); ///< cleanup and exit audio module extern void AudioExit(void); ///< cleanup and exit audio module

325
codec.c
View File

@@ -1,7 +1,7 @@
/// ///
/// @file codec.c @brief Codec functions /// @file codec.c @brief Codec functions
/// ///
/// Copyright (c) 2009 - 2011 by Johns. All Rights Reserved. /// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
/// ///
/// Contributor(s): /// Contributor(s):
/// ///
@@ -26,9 +26,21 @@
/// This module contains all decoder and codec functions. /// This module contains all decoder and codec functions.
/// It is uses ffmpeg (http://ffmpeg.org) as backend. /// It is uses ffmpeg (http://ffmpeg.org) as backend.
/// ///
/// It may work with libav (http://libav.org), but the tests show
/// many bugs and incompatiblity in it. Don't use this shit.
///
/**
** use av_parser to support insane dvb audio streams.
*/
#define USE_AVPARSER
/// compile with passthrough support (experimental)
#define USE_PASSTHROUGH
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <endian.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -44,6 +56,11 @@
#include <libavcodec/vdpau.h> #include <libavcodec/vdpau.h>
#endif #endif
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <pthread.h>
#ifdef MAIN_H #ifdef MAIN_H
#include MAIN_H #include MAIN_H
#endif #endif
@@ -52,6 +69,18 @@
#include "audio.h" #include "audio.h"
#include "codec.h" #include "codec.h"
//----------------------------------------------------------------------------
// Global
//----------------------------------------------------------------------------
///
/// ffmpeg lock mutex
///
/// new ffmpeg dislikes simultanous open/close
/// this breaks our code, until this is fixed use lock.
///
static pthread_mutex_t CodecLockMutex;
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Video // Video
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -348,16 +377,20 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id)
} }
// FIXME: for software decoder use all cpus, otherwise 1 // FIXME: for software decoder use all cpus, otherwise 1
decoder->VideoCtx->thread_count = 1; decoder->VideoCtx->thread_count = 1;
pthread_mutex_lock(&CodecLockMutex);
// open codec // open codec
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(53,5,0) #if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(53,5,0)
if (avcodec_open(decoder->VideoCtx, video_codec) < 0) { if (avcodec_open(decoder->VideoCtx, video_codec) < 0) {
pthread_mutex_unlock(&CodecLockMutex);
Fatal(_("codec: can't open video codec!\n")); Fatal(_("codec: can't open video codec!\n"));
} }
#else #else
if (avcodec_open2(decoder->VideoCtx, video_codec, NULL) < 0) { if (avcodec_open2(decoder->VideoCtx, video_codec, NULL) < 0) {
pthread_mutex_unlock(&CodecLockMutex);
Fatal(_("codec: can't open video codec!\n")); Fatal(_("codec: can't open video codec!\n"));
} }
#endif #endif
pthread_mutex_unlock(&CodecLockMutex);
decoder->VideoCtx->opaque = decoder; // our structure decoder->VideoCtx->opaque = decoder; // our structure
@@ -436,7 +469,9 @@ void CodecVideoClose(VideoDecoder * video_decoder)
// FIXME: play buffered data // FIXME: play buffered data
av_freep(&video_decoder->Frame); av_freep(&video_decoder->Frame);
if (video_decoder->VideoCtx) { if (video_decoder->VideoCtx) {
pthread_mutex_lock(&CodecLockMutex);
avcodec_close(video_decoder->VideoCtx); avcodec_close(video_decoder->VideoCtx);
pthread_mutex_unlock(&CodecLockMutex);
av_freep(&video_decoder->VideoCtx); av_freep(&video_decoder->VideoCtx);
} }
} }
@@ -446,9 +481,9 @@ void CodecVideoClose(VideoDecoder * video_decoder)
/** /**
** Display pts... ** Display pts...
** **
** ffmpeg 0.9 pts always AV_NOPTS_VALUE ** ffmpeg-0.9 pts always AV_NOPTS_VALUE
** ffmpeg 0.9 pkt_pts nice monotonic (only with HD) ** ffmpeg-0.9 pkt_pts nice monotonic (only with HD)
** ffmpeg 0.9 pkt_dts wild jumping -160 - 340 ms ** ffmpeg-0.9 pkt_dts wild jumping -160 - 340 ms
** **
** libav 0.8_pre20111116 pts always AV_NOPTS_VALUE ** libav 0.8_pre20111116 pts always AV_NOPTS_VALUE
** libav 0.8_pre20111116 pkt_pts always 0 (could be fixed?) ** libav 0.8_pre20111116 pkt_pts always 0 (could be fixed?)
@@ -483,32 +518,28 @@ void DisplayPts(AVCodecContext * video_ctx, AVFrame * frame)
** **
** @param decoder video decoder data ** @param decoder video decoder data
** @param avpkt video packet ** @param avpkt video packet
**
** @note this version destroys avpkt!!
*/ */
void CodecVideoDecode(VideoDecoder * decoder, AVPacket * avpkt) void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
{ {
AVCodecContext *video_ctx; AVCodecContext *video_ctx;
AVFrame *frame; AVFrame *frame;
int used; int used;
int got_frame; int got_frame;
AVPacket pkt[1];
video_ctx = decoder->VideoCtx; video_ctx = decoder->VideoCtx;
frame = decoder->Frame; frame = decoder->Frame;
*pkt = *avpkt; // use copy
next_part: next_part:
// FIXME: this function can crash with bad packets // FIXME: this function can crash with bad packets
used = avcodec_decode_video2(video_ctx, frame, &got_frame, avpkt); used = avcodec_decode_video2(video_ctx, frame, &got_frame, pkt);
Debug(4, "%s: %p %d -> %d %d\n", __FUNCTION__, avpkt->data, avpkt->size, Debug(4, "%s: %p %d -> %d %d\n", __FUNCTION__, pkt->data, pkt->size, used,
used, got_frame); got_frame);
if (got_frame) { // frame completed if (got_frame) { // frame completed
//DisplayPts(video_ctx, frame); //DisplayPts(video_ctx, frame);
if (video_ctx->hwaccel_context) { VideoRenderFrame(decoder->HwDecoder, video_ctx, frame);
VideoRenderFrame(decoder->HwDecoder, video_ctx, frame);
} else {
VideoRenderFrame(decoder->HwDecoder, video_ctx, frame);
}
} else { } else {
// some frames are needed for references, interlaced frames ... // some frames are needed for references, interlaced frames ...
// could happen with h264 dvb streams, just drop data. // could happen with h264 dvb streams, just drop data.
@@ -516,23 +547,28 @@ void CodecVideoDecode(VideoDecoder * decoder, AVPacket * avpkt)
Debug(4, "codec: %8d incomplete interlaced frame %d bytes used\n", Debug(4, "codec: %8d incomplete interlaced frame %d bytes used\n",
video_ctx->frame_number, used); video_ctx->frame_number, used);
} }
if (used != avpkt->size) { if (used != pkt->size) {
if (used == 0) {
goto next_part;
}
if (used >= 0) { if (used >= 0) {
// some tv channels, produce this // some tv channels, produce this
Debug(4, Debug(4,
"codec: ooops didn't use complete video packet used %d of %d\n", "codec: ooops didn't use complete video packet used %d of %d\n",
used, avpkt->size); used, pkt->size);
avpkt->data += used; pkt->data += used;
avpkt->size -= used; pkt->size -= used;
goto next_part; goto next_part;
} }
Debug(3, "codec: bad frame %d\n", used); Debug(3, "codec: bad frame %d\n", used);
} }
}
return; /**
** Flush the video decoder.
**
** @param decoder video decoder data
*/
void CodecVideoFlushBuffers(VideoDecoder * decoder)
{
avcodec_flush_buffers(decoder->VideoCtx);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -554,7 +590,7 @@ struct _audio_decoder_
AVCodec *AudioCodec; ///< audio codec AVCodec *AudioCodec; ///< audio codec
AVCodecContext *AudioCtx; ///< audio codec context AVCodecContext *AudioCtx; ///< audio codec context
/// audio parser to support wired dvb streaks /// audio parser to support insane dvb streaks
AVCodecParserContext *AudioParser; AVCodecParserContext *AudioParser;
int SampleRate; ///< current stream sample rate int SampleRate; ///< current stream sample rate
int Channels; ///< current stream channels int Channels; ///< current stream channels
@@ -563,8 +599,17 @@ struct _audio_decoder_
int HwChannels; ///< hw channels int HwChannels; ///< hw channels
ReSampleContext *ReSample; ///< audio resampling context ReSampleContext *ReSample; ///< audio resampling context
}; };
#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)
#endif
/** /**
** Allocate a new audio decoder context. ** Allocate a new audio decoder context.
** **
@@ -606,16 +651,20 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name,
if (!(audio_decoder->AudioCtx = avcodec_alloc_context3(audio_codec))) { if (!(audio_decoder->AudioCtx = avcodec_alloc_context3(audio_codec))) {
Fatal(_("codec: can't allocate audio codec context\n")); Fatal(_("codec: can't allocate audio codec context\n"));
} }
pthread_mutex_lock(&CodecLockMutex);
// open codec // open codec
#if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(53,5,0) #if LIBAVCODEC_VERSION_INT <= AV_VERSION_INT(53,5,0)
if (avcodec_open(audio_decoder->AudioCtx, audio_codec) < 0) { if (avcodec_open(audio_decoder->AudioCtx, audio_codec) < 0) {
pthread_mutex_unlock(&CodecLockMutex);
Fatal(_("codec: can't open audio codec\n")); Fatal(_("codec: can't open audio codec\n"));
} }
#else #else
if (avcodec_open2(audio_decoder->AudioCtx, audio_codec, NULL) < 0) { if (avcodec_open2(audio_decoder->AudioCtx, audio_codec, NULL) < 0) {
pthread_mutex_unlock(&CodecLockMutex);
Fatal(_("codec: can't open audio codec\n")); Fatal(_("codec: can't open audio codec\n"));
} }
#endif #endif
pthread_mutex_unlock(&CodecLockMutex);
Debug(3, "codec: audio '%s'\n", audio_decoder->AudioCtx->codec_name); Debug(3, "codec: audio '%s'\n", audio_decoder->AudioCtx->codec_name);
if (audio_codec->capabilities & CODEC_CAP_TRUNCATED) { if (audio_codec->capabilities & CODEC_CAP_TRUNCATED) {
@@ -650,20 +699,36 @@ void CodecAudioClose(AudioDecoder * audio_decoder)
audio_decoder->AudioParser = NULL; audio_decoder->AudioParser = NULL;
} }
if (audio_decoder->AudioCtx) { if (audio_decoder->AudioCtx) {
pthread_mutex_lock(&CodecLockMutex);
avcodec_close(audio_decoder->AudioCtx); avcodec_close(audio_decoder->AudioCtx);
pthread_mutex_unlock(&CodecLockMutex);
av_freep(&audio_decoder->AudioCtx); av_freep(&audio_decoder->AudioCtx);
} }
} }
/**
** Set audio pass-through.
*/
void CodecSetAudioPassthrough(int mask)
{
#ifdef USE_PASSTHROUGH
CodecPassthroughAC3 = mask & 1 ? 1 : 0;
#endif
// FIXME: must update audio decoder (nr. of channels wrong)
(void)mask;
}
#ifdef USE_AVPARSER
/** /**
** Decode an audio packet. ** Decode an audio packet.
** **
** PTS must be handled self. ** PTS must be handled self.
** **
** @param audio_decoder audio_Decoder data ** @param audio_decoder audio decoder data
** @param avpkt audio packet ** @param avpkt audio packet
*/ */
void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt) void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
{ {
int16_t buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 + int16_t buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 +
FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16))); FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16)));
@@ -683,9 +748,11 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
spkt->pts = avpkt->pts; spkt->pts = avpkt->pts;
spkt->dts = avpkt->dts; spkt->dts = avpkt->dts;
#endif #endif
#ifdef DEBUG
if (!audio_decoder->AudioParser) { if (!audio_decoder->AudioParser) {
Fatal(_("codec: internal error parser freeded while running\n")); Fatal(_("codec: internal error parser freeded while running\n"));
} }
#endif
audio_ctx = audio_decoder->AudioCtx; audio_ctx = audio_decoder->AudioCtx;
index = 0; index = 0;
@@ -700,6 +767,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
!index ? (uint64_t) spkt->pts : AV_NOPTS_VALUE, !index ? (uint64_t) spkt->pts : AV_NOPTS_VALUE,
!index ? (uint64_t) spkt->dts : AV_NOPTS_VALUE, -1); !index ? (uint64_t) spkt->dts : AV_NOPTS_VALUE, -1);
// FIXME: make this a function for both #ifdef cases
if (dpkt->size) { if (dpkt->size) {
int buf_sz; int buf_sz;
@@ -708,7 +776,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
buf_sz = sizeof(buf); buf_sz = sizeof(buf);
l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt); l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt);
if (l < 0) { // no audio frame could be decompressed if (l < 0) { // no audio frame could be decompressed
Error(_("codec: error audio data\n")); Error(_("codec: error audio data at %d\n"), index);
break; break;
} }
#ifdef notyetFF_API_OLD_DECODE_AUDIO #ifdef notyetFF_API_OLD_DECODE_AUDIO
@@ -735,14 +803,24 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
audio_decoder->SampleRate = audio_ctx->sample_rate; audio_decoder->SampleRate = audio_ctx->sample_rate;
audio_decoder->HwSampleRate = audio_ctx->sample_rate; audio_decoder->HwSampleRate = audio_ctx->sample_rate;
audio_decoder->Channels = audio_ctx->channels; audio_decoder->Channels = audio_ctx->channels;
audio_decoder->HwChannels = audio_ctx->channels; #ifdef USE_PASSTHROUGH
// SPDIF/HDMI passthrough
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
audio_decoder->HwChannels = 2;
} else
#endif
{
audio_decoder->HwChannels = audio_ctx->channels;
}
// channels not support? // channels not support?
if ((err = if ((err =
AudioSetup(&audio_decoder->HwSampleRate, AudioSetup(&audio_decoder->HwSampleRate,
&audio_decoder->HwChannels))) { &audio_decoder->HwChannels))) {
Debug(3, "codec/audio: resample %d -> %d\n", Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
audio_ctx->channels, audio_decoder->HwChannels); audio_ctx->sample_rate, audio_ctx->channels,
audio_decoder->HwSampleRate,
audio_decoder->HwChannels);
if (err == 1) { if (err == 1) {
audio_decoder->ReSample = audio_decoder->ReSample =
@@ -750,10 +828,18 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
audio_ctx->channels, audio_decoder->HwSampleRate, audio_ctx->channels, audio_decoder->HwSampleRate,
audio_ctx->sample_rate, audio_ctx->sample_fmt, audio_ctx->sample_rate, audio_ctx->sample_fmt,
audio_ctx->sample_fmt, 16, 10, 0, 0.8); audio_ctx->sample_fmt, 16, 10, 0, 0.8);
// libav-0.8_pre didn't support 6 -> 2 channels
if (!audio_decoder->ReSample) {
Error(_("codec/audio: resample setup error\n"));
audio_decoder->HwChannels = 0;
audio_decoder->HwSampleRate = 0;
}
} else { } else {
Debug(3, "codec/audio: audio setup error\n");
// FIXME: handle errors // FIXME: handle errors
audio_decoder->HwChannels = 0; audio_decoder->HwChannels = 0;
audio_decoder->HwSampleRate = 0; audio_decoder->HwSampleRate = 0;
break;
} }
} }
} }
@@ -766,11 +852,101 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
__attribute__ ((aligned(16))); __attribute__ ((aligned(16)));
int outlen; int outlen;
// FIXME: libav-0.7.2 crash here
outlen = outlen =
audio_resample(audio_decoder->ReSample, outbuf, buf, audio_resample(audio_decoder->ReSample, outbuf, buf,
buf_sz); buf_sz);
AudioEnqueue(outbuf, outlen); #ifdef DEBUG
if (outlen != buf_sz) {
Debug(3, "codec/audio: possible fixed ffmpeg\n");
}
#endif
if (outlen) {
// outlen seems to be wrong in ffmpeg-0.9
outlen /= audio_decoder->Channels *
av_get_bytes_per_sample(audio_ctx->sample_fmt);
outlen *=
audio_decoder->HwChannels *
av_get_bytes_per_sample(audio_ctx->sample_fmt);
Debug(4, "codec/audio: %d -> %d\n", buf_sz, outlen);
AudioEnqueue(outbuf, outlen);
}
} else { } 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
// dpkt is the original data
buf_sz = 6144;
if (buf_sz < dpkt->size + 8) {
Error(_
("codec/audio: decoded data smaller than encoded\n"));
break;
}
// 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 | (dpkt->data[5] & 0x07) << 8);
buf[3] = htole16(dpkt->size * 8);
swab(dpkt->data, buf + 4, dpkt->size);
memset(buf + 4 + dpkt->size / 2, 0,
buf_sz - 8 - dpkt->size);
}
#if 0
//
// old experimental code
//
if (1) {
// FIXME: need to detect dts
// copy original data for output
// FIXME: buf is sint
buf[0] = 0x72;
buf[1] = 0xF8;
buf[2] = 0x1F;
buf[3] = 0x4E;
buf[4] = 0x00;
switch (dpkt->size) {
case 512:
buf[5] = 0x0B;
break;
case 1024:
buf[5] = 0x0C;
break;
case 2048:
buf[5] = 0x0D;
break;
default:
Debug(3,
"codec/audio: dts sample burst not supported\n");
buf[5] = 0x00;
break;
}
buf[6] = (dpkt->size * 8);
buf[7] = (dpkt->size * 8) >> 8;
//buf[8] = 0x0B;
//buf[9] = 0x77;
//printf("%x %x\n", dpkt->data[0],dpkt->data[1]);
// swab?
memcpy(buf + 8, dpkt->data, dpkt->size);
memset(buf + 8 + dpkt->size, 0,
buf_sz - 8 - dpkt->size);
} else if (1) {
// FIXME: need to detect mp2
// FIXME: mp2 passthrough
// see softhddev.c version/layer
// 0x04 mpeg1 layer1
// 0x05 mpeg1 layer23
// 0x06 mpeg2 ext
// 0x07 mpeg2.5 layer 1
// 0x08 mpeg2.5 layer 2
// 0x09 mpeg2.5 layer 3
}
// DTS HD?
// True HD?
#endif
#endif
AudioEnqueue(buf, buf_sz); AudioEnqueue(buf, buf_sz);
} }
} }
@@ -784,10 +960,95 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
} }
#if 1 #if 1
// or av_free_packet, make no difference here
av_destruct_packet(spkt); av_destruct_packet(spkt);
#endif #endif
} }
#else
/**
** Decode an audio packet.
**
** PTS must be handled self.
**
** @param audio_decoder audio decoder data
** @param avpkt audio packet
*/
void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
{
int16_t buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 +
FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16)));
AVCodecContext *audio_ctx;
int index;
//#define spkt avpkt
#if 1
AVPacket spkt[1];
// av_new_packet reserves FF_INPUT_BUFFER_PADDING_SIZE and clears it
if (av_new_packet(spkt, avpkt->size)) {
Error(_("codec: out of memory\n"));
return;
}
memcpy(spkt->data, avpkt->data, avpkt->size);
spkt->pts = avpkt->pts;
spkt->dts = avpkt->dts;
#endif
audio_ctx = audio_decoder->AudioCtx;
index = 0;
while (spkt->size > index) {
int n;
int buf_sz;
AVPacket dpkt[1];
av_init_packet(dpkt);
dpkt->data = spkt->data + index;
dpkt->size = spkt->size - index;
buf_sz = sizeof(buf);
n = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt);
if (n < 0) { // no audio frame could be decompressed
Error(_("codec: error audio data at %d\n"), index);
break;
}
#ifdef DEBUG
Debug(4, "codec/audio: -> %d\n", buf_sz);
if ((unsigned)buf_sz > sizeof(buf)) {
abort();
}
#endif
#ifdef notyetFF_API_OLD_DECODE_AUDIO
// FIXME: ffmpeg git comeing
int got_frame;
avcodec_decode_audio4(audio_ctx, frame, &got_frame, dpkt);
#else
#endif
// FIXME: see above, old code removed
index += n;
}
#if 1
// or av_free_packet, make no difference here
av_destruct_packet(spkt);
#endif
}
#endif
/**
** Flush the audio decoder.
**
** @param decoder audio decoder data
*/
void CodecAudioFlushBuffers(AudioDecoder * decoder)
{
// FIXME: reset audio parser
avcodec_flush_buffers(decoder->AudioCtx);
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Codec // Codec
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -807,6 +1068,7 @@ static void CodecNoopCallback( __attribute__ ((unused))
*/ */
void CodecInit(void) void CodecInit(void)
{ {
pthread_mutex_init(&CodecLockMutex, NULL);
#ifndef DEBUG #ifndef DEBUG
// disable display ffmpeg error messages // disable display ffmpeg error messages
av_log_set_callback(CodecNoopCallback); av_log_set_callback(CodecNoopCallback);
@@ -821,4 +1083,5 @@ void CodecInit(void)
*/ */
void CodecExit(void) void CodecExit(void)
{ {
pthread_mutex_destroy(&CodecLockMutex);
} }

24
codec.h
View File

@@ -1,7 +1,7 @@
/// ///
/// @file codec.h @brief Codec module headerfile /// @file codec.h @brief Codec module headerfile
/// ///
/// Copyright (c) 2009 - 2011 by Johns. All Rights Reserved. /// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
/// ///
/// Contributor(s): /// Contributor(s):
/// ///
@@ -40,26 +40,32 @@ typedef struct _audio_decoder_ AudioDecoder;
/// Allocate a new video decoder context. /// Allocate a new video decoder context.
extern VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder *); extern VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder *);
/// Open video codec /// Open video codec.
extern void CodecVideoOpen(VideoDecoder *, const char *, int); extern void CodecVideoOpen(VideoDecoder *, const char *, int);
/// Close video codec /// Close video codec.
extern void CodecVideoClose(VideoDecoder *); extern void CodecVideoClose(VideoDecoder *);
/// Decode a video packet /// Decode a video packet.
extern void CodecVideoDecode(VideoDecoder *, AVPacket * pkt); extern void CodecVideoDecode(VideoDecoder *, const AVPacket *);
/// Flush video buffers.
extern void CodecVideoFlushBuffers(VideoDecoder *);
/// Allocate a new audio decoder context. /// Allocate a new audio decoder context.
extern AudioDecoder *CodecAudioNewDecoder(void); extern AudioDecoder *CodecAudioNewDecoder(void);
/// Open audio codec /// Open audio codec.
extern void CodecAudioOpen(AudioDecoder *, const char *, int); extern void CodecAudioOpen(AudioDecoder *, const char *, int);
/// Close audio codec /// Close audio codec.
extern void CodecAudioClose(AudioDecoder *); extern void CodecAudioClose(AudioDecoder *);
/// Decode an audio packet /// Decode an audio packet.
extern void CodecAudioDecode(AudioDecoder *, AVPacket * pkt); extern void CodecAudioDecode(AudioDecoder *, const AVPacket *);
/// Flush audio buffers.
extern void CodecAudioFlushBuffers(AudioDecoder *);
/// Setup and initialize codec module. /// Setup and initialize codec module.
extern void CodecInit(void); extern void CodecInit(void);

27
misc.h
View File

@@ -1,7 +1,7 @@
/// ///
/// @file misc.h @brief Misc function header file /// @file misc.h @brief Misc function header file
/// ///
/// Copyright (c) 2009 - 2011 by Lutz Sammer. All Rights Reserved. /// Copyright (c) 2009 - 2012 by Lutz Sammer. All Rights Reserved.
/// ///
/// Contributor(s): /// Contributor(s):
/// Copied from uwm. /// Copied from uwm.
@@ -46,24 +46,28 @@ extern int SysLogLevel; ///< how much information wanted
// Prototypes // Prototypes
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
static inline void Debug(const int, const char *format, ...) static inline void Syslog(const int, const char *format, ...)
__attribute__ ((format(printf, 2, 3))); __attribute__ ((format(printf, 2, 3)));
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Inlines // Inlines
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#ifdef DEBUG
#define DebugLevel 4 /// private debug level #define DebugLevel 4 /// private debug level
#else
#define DebugLevel 0 /// private debug level
#endif
/** /**
** Debug output function. ** Syslog output function.
** **
** - 0 fatal errors and errors ** - 0 fatal errors and errors
** - 1 warnings ** - 1 warnings
** - 2 info ** - 2 info
** - 3 important debug and fixme's ** - 3 important debug and fixme's
*/ */
static inline void Debug(const int level, const char *format, ...) static inline void Syslog(const int level, const char *format, ...)
{ {
if (SysLogLevel > level || DebugLevel > level) { if (SysLogLevel > level || DebugLevel > level) {
va_list ap; va_list ap;
@@ -77,7 +81,7 @@ static inline void Debug(const int level, const char *format, ...)
/** /**
** Show error. ** Show error.
*/ */
#define Error(fmt...) Debug(0, fmt) #define Error(fmt...) Syslog(0, fmt)
/** /**
** Show fatal error. ** Show fatal error.
@@ -87,12 +91,21 @@ static inline void Debug(const int level, const char *format, ...)
/** /**
** Show warning. ** Show warning.
*/ */
#define Warning(fmt...) Debug(1, fmt) #define Warning(fmt...) Syslog(1, fmt)
/** /**
** Show info. ** Show info.
*/ */
#define Info(fmt...) Debug(2, fmt) #define Info(fmt...) Syslog(2, fmt)
/**
** Show debug.
*/
#ifdef DEBUG
#define Debug(level, fmt...) Syslog(level, fmt)
#else
#define Debug(level, fmt...) /* disabled */
#endif
/** /**
** Get ticks in ms. ** Get ticks in ms.

View File

@@ -1,7 +1,7 @@
/// ///
/// @file softhddev.c @brief A software HD device plugin for VDR. /// @file softhddev.c @brief A software HD device plugin for VDR.
/// ///
/// Copyright (c) 2011 by Johns. All Rights Reserved. /// Copyright (c) 2011, 2012 by Johns. All Rights Reserved.
/// ///
/// Contributor(s): /// Contributor(s):
/// ///
@@ -35,6 +35,11 @@
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <pthread.h>
#include "misc.h" #include "misc.h"
#include "softhddev.h" #include "softhddev.h"
@@ -42,18 +47,148 @@
#include "video.h" #include "video.h"
#include "codec.h" #include "codec.h"
static char BrokenThreadsAndPlugins; ///< broken vdr threads and plugins //////////////////////////////////////////////////////////////////////////////
// Variables
//////////////////////////////////////////////////////////////////////////////
#ifdef USE_VDPAU
static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
#else
#define ConfigVdpauDecoder 0 ///< no vdpau decoder configured
#endif
static char ConfigFullscreen; ///< fullscreen modus
static char ConfigSuspendClose = 1; ///< suspend should close devices
static char ConfigSuspendX11 = 1; ///< suspend should stop x11
static pthread_mutex_t SuspendLockMutex; ///< suspend lock mutex
static volatile char VideoFreezed; ///< video freezed
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Audio // Audio
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
static volatile char NewAudioStream; ///< new audio stream
static volatile char SkipAudio; ///< skip audio stream
static AudioDecoder *MyAudioDecoder; ///< audio decoder static AudioDecoder *MyAudioDecoder; ///< audio decoder
static enum CodecID AudioCodecID; ///< current codec id static enum CodecID AudioCodecID; ///< current codec id
extern void AudioTest(void); // FIXME: /**
** mpeg bitrate table.
**
** BitRateTable[Version][Layer][Index]
*/
static const uint16_t BitRateTable[2][4][16] = {
// MPEG Version 1
{{},
{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,
0},
{0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0},
{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0}},
// MPEG Version 2 & 2.5
{{},
{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0},
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0},
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}
}
};
/**
** mpeg samperate table.
*/
static const uint16_t SampleRateTable[4] = {
44100, 48000, 32000, 0
};
/**
** Find sync in audio packet.
**
** @param avpkt audio packet
**
** From: http://www.mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm
**
** AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM
**
** o a 11x frame sync
** o b 2x mpeg audio version (2.5, reserved, 2, 1)
** o c 2x layer (reserved, III, II, I)
** o e 2x BitRate index
** o f 2x SampleRate index
** o g 1x Paddding bit
** o .. doesn't care
**
** frame length:
** Layer I:
** FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4
** Layer II & III:
** FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
*/
static int FindAudioSync(const AVPacket * avpkt)
{
int i;
const uint8_t *data;
i = 0;
data = avpkt->data;
while (i < avpkt->size - 4) {
if (data[i] == 0xFF && (data[i + 1] & 0xFC) == 0xFC) {
int mpeg2;
int mpeg25;
int layer;
int bit_rate_index;
int sample_rate_index;
int padding;
int bit_rate;
int sample_rate;
int frame_size;
mpeg2 = !(data[i + 1] & 0x08) && (data[i + 1] & 0x10);
mpeg25 = !(data[i + 1] & 0x08) && !(data[i + 1] & 0x10);
layer = 4 - ((data[i + 1] >> 1) & 0x03);
bit_rate_index = (data[i + 2] >> 4) & 0x0F;
sample_rate_index = (data[i + 2] >> 2) & 0x03;
padding = (data[i + 2] >> 1) & 0x01;
sample_rate = SampleRateTable[sample_rate_index];
if (!sample_rate) { // no valid sample rate try next
i++;
continue;
}
sample_rate >>= mpeg2; // mpeg 2 half rate
sample_rate >>= mpeg25; // mpeg 2.5 quarter rate
bit_rate = BitRateTable[mpeg2 | mpeg25][layer][bit_rate_index];
bit_rate *= 1000;
switch (layer) {
case 1:
frame_size = (12 * bit_rate) / sample_rate;
frame_size = (frame_size + padding) * 4;
break;
case 2:
case 3:
default:
frame_size = (144 * bit_rate) / sample_rate;
frame_size = frame_size + padding;
break;
}
Debug(3,
"audio: mpeg%s layer%d bitrate=%d samplerate=%d %d bytes\n",
mpeg25 ? "2.5" : mpeg2 ? "2" : "1", layer, bit_rate,
sample_rate, frame_size);
if (i + frame_size < avpkt->size - 4) {
if (data[i + frame_size] == 0xFF
&& (data[i + frame_size + 1] & 0xFC) == 0xFC) {
Debug(3, "audio: mpeg1/2 found at %d\n", i);
return i;
}
}
// no valid frame size or no continuation, try next
}
i++;
}
return -1;
}
/** /**
** Play audio packet. ** Play audio packet.
@@ -62,25 +197,37 @@ extern void AudioTest(void); // FIXME:
** @param size size of PES packet ** @param size size of PES packet
** @param id PES packet type ** @param id PES packet type
*/ */
void PlayAudio(const uint8_t * data, int size, uint8_t id) int PlayAudio(const uint8_t * data, int size,
__attribute__ ((unused)) uint8_t id)
{ {
int n; int n;
int osize;
AVPacket avpkt[1]; AVPacket avpkt[1];
if (BrokenThreadsAndPlugins) { // channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
return;
if (VideoFreezed) { // video freezed
return 0;
}
if (NewAudioStream) {
// FIXME: does this clear the audio ringbuffer?
CodecAudioClose(MyAudioDecoder);
AudioCodecID = CODEC_ID_NONE;
NewAudioStream = 0;
}
if (SkipAudio) { // skip audio
return size;
} }
// PES header 0x00 0x00 0x01 ID // PES header 0x00 0x00 0x01 ID
// ID 0xBD 0xC0-0xCF // ID 0xBD 0xC0-0xCF
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
// Detect audio code
// MPEG-PS mp2 MPEG1, MPEG2, AC3
if (size < 9) { if (size < 9) {
Error(_("[softhddev] invalid audio packet\n")); Error(_("[softhddev] invalid audio packet\n"));
return; return size;
}
// Don't overrun audio buffers on replay
if (AudioFreeBytes() < 3072 * 8 * 8) { // 8 channels 8 packets
return 0;
} }
n = data[8]; // header size n = data[8]; // header size
@@ -101,12 +248,16 @@ void PlayAudio(const uint8_t * data, int size, uint8_t id)
} }
} }
osize = size;
data += 9 + n; data += 9 + n;
size -= 9 + n; // skip pes header size -= 9 + n; // skip pes header
if (size <= 0) { if (size <= 0) {
Error(_("[softhddev] invalid audio packet\n")); Error(_("[softhddev] invalid audio packet\n"));
return; return osize;
} }
// Detect audio code
// MPEG-PS mp2 MPEG1, MPEG2, AC3
// Syncword - 0x0B77 // Syncword - 0x0B77
if (data[0] == 0x0B && data[1] == 0x77) { if (data[0] == 0x0B && data[1] == 0x77) {
if (!MyAudioDecoder) { if (!MyAudioDecoder) {
@@ -137,21 +288,37 @@ void PlayAudio(const uint8_t * data, int size, uint8_t id)
// no start package // no start package
// FIXME: Nick/Viva sends this shit, need to find sync in packet // FIXME: Nick/Viva sends this shit, need to find sync in packet
// FIXME: otherwise it takes too long until sound appears // FIXME: otherwise it takes too long until sound appears
if (AudioCodecID == CODEC_ID_NONE) { if (AudioCodecID == CODEC_ID_NONE) {
Debug(3, "[softhddev]%s: ??? %d\n", __FUNCTION__, id); Debug(3, "[softhddev]%s: ??? %d\n", __FUNCTION__, id);
return; avpkt->data = (void *)data;
avpkt->size = size;
n = FindAudioSync(avpkt);
if (n < 0) {
return osize;
}
if (!MyAudioDecoder) {
MyAudioDecoder = CodecAudioNewDecoder();
}
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
AudioCodecID = CODEC_ID_MP2;
data += n;
size -= n;
} }
} }
// no decoder or codec known // no decoder or codec known
if (!MyAudioDecoder || AudioCodecID == CODEC_ID_NONE) { if (!MyAudioDecoder || AudioCodecID == CODEC_ID_NONE) {
return; return osize;
} }
avpkt->data = (void *)data; avpkt->data = (void *)data;
avpkt->size = size; avpkt->size = size;
//memset(avpkt->data + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE); //memset(avpkt->data + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
CodecAudioDecode(MyAudioDecoder, avpkt); CodecAudioDecode(MyAudioDecoder, avpkt);
return osize;
} }
/** /**
@@ -159,10 +326,8 @@ void PlayAudio(const uint8_t * data, int size, uint8_t id)
*/ */
void Mute(void) void Mute(void)
{ {
if (BrokenThreadsAndPlugins) { SkipAudio = 1;
return; //AudioSetVolume(0);
}
AudioSetVolume(0);
} }
/** /**
@@ -172,9 +337,6 @@ void Mute(void)
*/ */
void SetVolumeDevice(int volume) void SetVolumeDevice(int volume)
{ {
if (BrokenThreadsAndPlugins) {
return;
}
AudioSetVolume((volume * 100) / 255); AudioSetVolume((volume * 100) / 255);
} }
@@ -184,13 +346,13 @@ void SetVolumeDevice(int volume)
#include <alsa/iatomic.h> // portable atomic_t #include <alsa/iatomic.h> // portable atomic_t
uint32_t VideoSwitch; uint32_t VideoSwitch; ///< debug video switch ticks
static int NewVideoStream; ///< new video stream static volatile char NewVideoStream; ///< new video stream
static VideoDecoder *MyVideoDecoder; ///< video decoder static VideoDecoder *MyVideoDecoder; ///< video decoder
static enum CodecID VideoCodecID; ///< current codec id static enum CodecID VideoCodecID; ///< current codec id
static const char *X11DisplayName; ///< x11 display name static const char *X11DisplayName; ///< x11 display name
static volatile int Usr1Signal; ///< true got usr1 signal static volatile char Usr1Signal; ///< true got usr1 signal
/// video PES buffer default size /// video PES buffer default size
#define VIDEO_BUFFER_SIZE (512 * 1024) #define VIDEO_BUFFER_SIZE (512 * 1024)
@@ -200,8 +362,8 @@ static AVPacket VideoPacketRb[VIDEO_PACKET_MAX];
static int VideoPacketWrite; ///< write pointer static int VideoPacketWrite; ///< write pointer
static int VideoPacketRead; ///< read pointer static int VideoPacketRead; ///< read pointer
static atomic_t VideoPacketsFilled; ///< how many of the buffer is used static atomic_t VideoPacketsFilled; ///< how many of the buffer is used
static char VideoFreezed; ///< video freezed static volatile char VideoClearBuffers; ///< clear video buffers
static char VideoClearBuffers; ///< clear video buffers static volatile char SkipVideo; ///< skip video
#ifdef DEBUG #ifdef DEBUG
static int VideoMaxPacketSize; ///< biggest used packet buffer static int VideoMaxPacketSize; ///< biggest used packet buffer
@@ -214,8 +376,6 @@ static void VideoPacketInit(void)
{ {
int i; int i;
Debug(4, "[softhddev]: %s\n", __FUNCTION__);
for (i = 0; i < VIDEO_PACKET_MAX; ++i) { for (i = 0; i < VIDEO_PACKET_MAX; ++i) {
AVPacket *avpkt; AVPacket *avpkt;
@@ -237,16 +397,10 @@ static void VideoPacketExit(void)
{ {
int i; int i;
Debug(4, "[softhddev]: %s\n", __FUNCTION__);
atomic_set(&VideoPacketsFilled, 0); atomic_set(&VideoPacketsFilled, 0);
for (i = 0; i < VIDEO_PACKET_MAX; ++i) { for (i = 0; i < VIDEO_PACKET_MAX; ++i) {
AVPacket *avpkt; av_free_packet(&VideoPacketRb[i]);
avpkt = &VideoPacketRb[i];
// build a clean ffmpeg av packet
av_free_packet(avpkt);
} }
} }
@@ -277,6 +431,9 @@ static void VideoEnqueue(int64_t pts, const void *data, int size)
/ (VIDEO_BUFFER_SIZE / 2)) * (VIDEO_BUFFER_SIZE / 2)); / (VIDEO_BUFFER_SIZE / 2)) * (VIDEO_BUFFER_SIZE / 2));
#ifdef DEBUG #ifdef DEBUG
if (avpkt->size <= avpkt->stream_index + size) { if (avpkt->size <= avpkt->stream_index + size) {
fprintf(stderr, "%d %d %d\n", avpkt->size, avpkt->stream_index,
size);
fflush(stderr);
abort(); abort();
} }
#endif #endif
@@ -294,6 +451,8 @@ static void VideoEnqueue(int64_t pts, const void *data, int size)
/** /**
** Finish current packet advance to next. ** Finish current packet advance to next.
**
** @param codec_id codec id of packet (MPEG/H264)
*/ */
static void VideoNextPacket(int codec_id) static void VideoNextPacket(int codec_id)
{ {
@@ -324,13 +483,13 @@ static void VideoNextPacket(int codec_id)
VideoPacketWrite = (VideoPacketWrite + 1) % VIDEO_PACKET_MAX; VideoPacketWrite = (VideoPacketWrite + 1) % VIDEO_PACKET_MAX;
atomic_inc(&VideoPacketsFilled); atomic_inc(&VideoPacketsFilled);
VideoDisplayWakeup();
// intialize next package to use // intialize next package to use
avpkt = &VideoPacketRb[VideoPacketWrite]; avpkt = &VideoPacketRb[VideoPacketWrite];
avpkt->stream_index = 0; avpkt->stream_index = 0;
avpkt->pts = AV_NOPTS_VALUE; avpkt->pts = AV_NOPTS_VALUE;
avpkt->dts = AV_NOPTS_VALUE; avpkt->dts = AV_NOPTS_VALUE;
VideoDisplayHandler();
} }
/** /**
@@ -348,6 +507,10 @@ int VideoDecode(void)
} }
if (VideoClearBuffers) { if (VideoClearBuffers) {
atomic_set(&VideoPacketsFilled, 0); atomic_set(&VideoPacketsFilled, 0);
VideoPacketRead = VideoPacketWrite;
if (MyVideoDecoder) {
CodecVideoFlushBuffers(MyVideoDecoder);
}
VideoClearBuffers = 0; VideoClearBuffers = 0;
return 1; return 1;
} }
@@ -376,6 +539,7 @@ int VideoDecode(void)
CodecVideoClose(MyVideoDecoder); CodecVideoClose(MyVideoDecoder);
goto skip; goto skip;
} }
goto skip;
break; break;
case CODEC_ID_MPEG2VIDEO: case CODEC_ID_MPEG2VIDEO:
if (last_codec_id != CODEC_ID_MPEG2VIDEO) { if (last_codec_id != CODEC_ID_MPEG2VIDEO) {
@@ -417,23 +581,65 @@ int VideoDecode(void)
/** /**
** Try video start. ** Try video start.
** **
** Could be called, when already started. ** NOT TRUE: Could be called, when already started.
*/ */
static void StartVideo(void) static void StartVideo(void)
{ {
VideoInit(X11DisplayName); VideoInit(X11DisplayName);
if (ConfigFullscreen) {
// FIXME: not good looking, mapped and then resized.
VideoSetFullscreen(1);
}
VideoOsdInit(); VideoOsdInit();
if (!MyVideoDecoder) { if (!MyVideoDecoder) {
VideoHwDecoder *hw_decoder; VideoHwDecoder *hw_decoder;
if ((hw_decoder = VideoNewHwDecoder())) { if ((hw_decoder = VideoNewHwDecoder())) {
MyVideoDecoder = CodecVideoNewDecoder(hw_decoder); MyVideoDecoder = CodecVideoNewDecoder(hw_decoder);
VideoCodecID = CODEC_ID_NONE;
} }
VideoCodecID = CODEC_ID_NONE;
} }
VideoPacketInit(); VideoPacketInit();
} }
#ifdef DEBUG
/**
** Validate mpeg video packet.
**
** Function to validate a mpeg packet, not needed.
*/
static int ValidateMpeg(const uint8_t * data, int size)
{
int pes_l;
do {
if (size < 9) {
return -1;
}
if (data[0] || data[1] || data[2] != 0x01) {
printf("%02x: %02x %02x %02x %02x %02x\n", data[-1], data[0],
data[1], data[2], data[3], data[4]);
return -1;
}
pes_l = (data[4] << 8) | data[5];
if (!pes_l) { // contains unknown length
return 1;
}
if (6 + pes_l > size) {
return -1;
}
data += 6 + pes_l;
size -= 6 + pes_l;
} while (size);
return 0;
}
#endif
/** /**
** Play video packet. ** Play video packet.
** **
@@ -446,6 +652,9 @@ static void StartVideo(void)
** supports complete packets. ** supports complete packets.
** We buffer here until we receive an complete PES Packet, which ** We buffer here until we receive an complete PES Packet, which
** is no problem, the audio is always far behind us. ** is no problem, the audio is always far behind us.
** cTsToPes::GetPes splits the packets.
**
** @todo FIXME: combine the 5 ifs at start of the function
*/ */
int PlayVideo(const uint8_t * data, int size) int PlayVideo(const uint8_t * data, int size)
{ {
@@ -453,9 +662,6 @@ int PlayVideo(const uint8_t * data, int size)
int64_t pts; int64_t pts;
int n; int n;
if (BrokenThreadsAndPlugins) {
return size;
}
if (Usr1Signal) { // x11 server ready if (Usr1Signal) { // x11 server ready
Usr1Signal = 0; Usr1Signal = 0;
StartVideo(); StartVideo();
@@ -463,7 +669,13 @@ int PlayVideo(const uint8_t * data, int size)
if (!MyVideoDecoder) { // no x11 video started if (!MyVideoDecoder) { // no x11 video started
return size; return size;
} }
if (NewVideoStream) { if (SkipVideo) { // skip video
return size;
}
if (VideoFreezed) { // video freezed
return 0;
}
if (NewVideoStream) { // channel switched
Debug(3, "video: new stream %d\n", GetMsTicks() - VideoSwitch); Debug(3, "video: new stream %d\n", GetMsTicks() - VideoSwitch);
// FIXME: hack to test results // FIXME: hack to test results
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) { if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
@@ -482,13 +694,15 @@ int PlayVideo(const uint8_t * data, int size)
} }
n = data[8]; // header size n = data[8]; // header size
// wrong size // wrong size
if (size < 9 + n) { if (size < 9 + n + 4) {
Error(_("[softhddev] invalid video packet\n")); Error(_("[softhddev] invalid video packet %d bytes\n"), size);
return size; return size;
} }
check = data + 9 + n; // buffer full: needed for replay
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
// FIXME: get pts/dts, when we need it return 0;
}
// get pts/dts
pts = AV_NOPTS_VALUE; pts = AV_NOPTS_VALUE;
if (data[7] & 0x80) { if (data[7] & 0x80) {
@@ -496,6 +710,10 @@ int PlayVideo(const uint8_t * data, int size)
(int64_t) (data[9] & 0x0E) << 29 | data[10] << 22 | (data[11] & (int64_t) (data[9] & 0x0E) << 29 | data[10] << 22 | (data[11] &
0xFE) << 14 | data[12] << 7 | (data[13] & 0xFE) >> 1; 0xFE) << 14 | data[12] << 7 | (data[13] & 0xFE) >> 1;
#ifdef DEBUG #ifdef DEBUG
if (!(data[13] & 1) || !(data[11] & 1) || !(data[9] & 1)) {
Error(_("[softhddev] invalid pts in video packet\n"));
return size;
}
//Debug(3, "video: pts %#012" PRIx64 "\n", pts); //Debug(3, "video: pts %#012" PRIx64 "\n", pts);
if (data[13] != (((pts & 0x7F) << 1) | 1)) { if (data[13] != (((pts & 0x7F) << 1) | 1)) {
abort(); abort();
@@ -509,35 +727,46 @@ int PlayVideo(const uint8_t * data, int size)
if (data[10] != ((pts >> 22) & 0xFF)) { if (data[10] != ((pts >> 22) & 0xFF)) {
abort(); abort();
} }
if ((data[9] & 0x0F) != (((pts >> 30) << 1) | 1)) {
abort();
}
#endif #endif
} }
// FIXME: no valid mpeg2/h264 detection yet // FIXME: no valid mpeg2/h264 detection yet
check = data + 9 + n;
if (0) { if (0) {
printf("%02x: %02x %02x %02x %02x %02x\n", data[6], check[0], check[1], printf("%02x: %02x %02x %02x %02x %02x\n", data[6], check[0], check[1],
check[2], check[3], check[4]); check[2], check[3], check[4]);
} }
// PES_VIDEO_STREAM 0xE0 or PES start code // PES_VIDEO_STREAM 0xE0 or PES start code
if ((data[6] & 0xC0) != 0x80 || (!check[0] && !check[1] //(data[6] & 0xC0) != 0x80 ||
&& check[2] == 0x1)) { if ((!check[0] && !check[1] && check[2] == 0x1)) {
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) { if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
// FIXME: hack to test results
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
return 0;
}
VideoNextPacket(CODEC_ID_MPEG2VIDEO); VideoNextPacket(CODEC_ID_MPEG2VIDEO);
} else { } else {
Debug(3, "video: mpeg2 detected\n"); Debug(3, "video: mpeg2 detected ID %02x\n", check[3]);
VideoCodecID = CODEC_ID_MPEG2VIDEO; VideoCodecID = CODEC_ID_MPEG2VIDEO;
} }
#ifdef DEBUG
if (ValidateMpeg(data, size)) {
Debug(3, "softhddev/video: invalid mpeg2 video packet\n");
}
#endif
// Access Unit Delimiter // Access Unit Delimiter
} else if (!check[0] && !check[1] && !check[2] && check[3] == 0x1 } else if ((data[6] & 0xC0) == 0x80 && !check[0] && !check[1]
&& check[4] == 0x09) { && !check[2] && check[3] == 0x1 && check[4] == 0x09) {
if (VideoCodecID == CODEC_ID_H264) {
VideoNextPacket(CODEC_ID_H264);
} else {
Debug(3, "video: h264 detected\n");
VideoCodecID = CODEC_ID_H264;
}
// Access Unit Delimiter (BBC-HD)
// FIXME: the 4 offset are try & error selected
} else if ((data[6] & 0xC0) == 0x80 && !check[4 + 0] && !check[4 + 1]
&& !check[4 + 2] && check[4 + 3] == 0x1 && check[4 + 4] == 0x09) {
if (VideoCodecID == CODEC_ID_H264) { if (VideoCodecID == CODEC_ID_H264) {
// FIXME: hack to test results
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
return 0;
}
VideoNextPacket(CODEC_ID_H264); VideoNextPacket(CODEC_ID_H264);
} else { } else {
Debug(3, "video: h264 detected\n"); Debug(3, "video: h264 detected\n");
@@ -550,11 +779,8 @@ int PlayVideo(const uint8_t * data, int size)
return size; return size;
} }
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) { if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
// mpeg codec supports incomplete packages // mpeg codec supports incomplete packets
// FIXME: hack to test results // waiting for a full complete packages, increases needed delays
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
return 0;
}
VideoNextPacket(CODEC_ID_MPEG2VIDEO); VideoNextPacket(CODEC_ID_MPEG2VIDEO);
} }
} }
@@ -565,6 +791,29 @@ int PlayVideo(const uint8_t * data, int size)
return size; return size;
} }
/**
** Grabs the currently visible screen image.
**
** @param size size of the returned data
** @param jpeg flag true, create JPEG data
** @param quality JPEG quality
** @param width number of horizontal pixels in the frame
** @param height number of vertical pixels in the frame
*/
uint8_t *GrabImage(int *size, int jpeg, int quality, int width, int height)
{
if (jpeg) {
(void)quality;
Error(_("softhddev: jpeg grabbing not supported\n"));
return NULL;
}
if (width != -1 && height != -1) {
Error(_("softhddev: scaling not supported\n"));
return NULL;
}
return VideoGrab(size, &width, &height);
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/** /**
@@ -572,9 +821,7 @@ int PlayVideo(const uint8_t * data, int size)
*/ */
void SetPlayMode(void) void SetPlayMode(void)
{ {
if (BrokenThreadsAndPlugins) { Resume();
return;
}
if (MyVideoDecoder) { if (MyVideoDecoder) {
if (VideoCodecID != CODEC_ID_NONE) { if (VideoCodecID != CODEC_ID_NONE) {
NewVideoStream = 1; NewVideoStream = 1;
@@ -582,10 +829,13 @@ void SetPlayMode(void)
} }
} }
if (MyAudioDecoder) { if (MyAudioDecoder) {
// FIXME: does this clear the audio ringbuffer? if (AudioCodecID != CODEC_ID_NONE) {
CodecAudioClose(MyAudioDecoder); NewAudioStream = 1;
AudioCodecID = CODEC_ID_NONE; }
} }
VideoFreezed = 0;
SkipAudio = 0;
SkipVideo = 0;
} }
/** /**
@@ -593,9 +843,16 @@ void SetPlayMode(void)
*/ */
void Clear(void) void Clear(void)
{ {
int i;
VideoNextPacket(VideoCodecID); // terminate work
VideoClearBuffers = 1; VideoClearBuffers = 1;
// FIXME: avcodec_flush_buffers // FIXME: avcodec_flush_buffers
// FIXME: flush audio buffers AudioFlushBuffers();
for (i = 0; VideoClearBuffers && i < 20; ++i) {
usleep(1 * 1000);
}
} }
/** /**
@@ -604,6 +861,7 @@ void Clear(void)
void Play(void) void Play(void)
{ {
VideoFreezed = 0; VideoFreezed = 0;
SkipAudio = 0;
// FIXME: restart audio // FIXME: restart audio
} }
@@ -614,16 +872,38 @@ void Freeze(void)
{ {
VideoFreezed = 1; VideoFreezed = 1;
// FIXME: freeze audio // FIXME: freeze audio
AudioFlushBuffers();
}
/**
** Display the given I-frame as a still picture.
*/
void StillPicture(const uint8_t * data, int size)
{
int i;
// must be a PES start code
if (size < 9 || !data || data[0] || data[1] || data[2] != 0x01) {
Error(_("[softhddev] invalid PES video packet\n"));
return;
}
Clear(); // flush video buffers
// +1 future for deinterlace
for (i = -1; i < (VideoCodecID == CODEC_ID_MPEG2VIDEO ? 3 : 17); ++i) {
PlayVideo(data, size); // reference frames
}
VideoNextPacket(VideoCodecID); // terminate last packet
} }
/** /**
** Poll if device is ready. Called by replay. ** Poll if device is ready. Called by replay.
**
** @param timeout timeout to become ready in ms
*/ */
int Poll(int timeout) int Poll(int timeout)
{ {
// buffers are too full // buffers are too full
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) { if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) {
Debug(3, "replay: poll %d\n", timeout);
if (timeout) { if (timeout) {
// let display thread work // let display thread work
usleep(timeout * 1000); usleep(timeout * 1000);
@@ -633,6 +913,22 @@ int Poll(int timeout)
return 0; return 0;
} }
/**
** Flush the device output buffers.
**
** @param timeout timeout to flush in ms
*/
int Flush(int timeout)
{
if (atomic_read(&VideoPacketsFilled)) {
if (timeout) { // let display thread work
usleep(timeout * 1000);
}
return !atomic_read(&VideoPacketsFilled);
}
return 1;
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// OSD // OSD
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -642,21 +938,22 @@ int Poll(int timeout)
*/ */
void GetOsdSize(int *width, int *height, double *aspect) void GetOsdSize(int *width, int *height, double *aspect)
{ {
static char done; #ifdef DEBUG
static int done_width;
// FIXME: should be configured! static int done_height;
*width = 1920; #endif
*height = 1080;
//*width = 768;
//*height = 576;
VideoGetOsdSize(width, height);
*aspect = 16.0 / 9.0 / (double)*width * (double)*height; *aspect = 16.0 / 9.0 / (double)*width * (double)*height;
if (!done) { #ifdef DEBUG
if (done_width != *width || done_height != *height) {
Debug(3, "[softhddev]%s: %dx%d %g\n", __FUNCTION__, *width, *height, Debug(3, "[softhddev]%s: %dx%d %g\n", __FUNCTION__, *width, *height,
*aspect); *aspect);
done = 1; done_width = *width;
done_height = *height;
} }
#endif
} }
/** /**
@@ -664,9 +961,6 @@ void GetOsdSize(int *width, int *height, double *aspect)
*/ */
void OsdClose(void) void OsdClose(void)
{ {
if (BrokenThreadsAndPlugins) {
return;
}
VideoOsdClear(); VideoOsdClear();
} }
@@ -675,25 +969,24 @@ void OsdClose(void)
*/ */
void OsdDrawARGB(int x, int y, int height, int width, const uint8_t * argb) void OsdDrawARGB(int x, int y, int height, int width, const uint8_t * argb)
{ {
if (BrokenThreadsAndPlugins) { Resume();
return;
}
VideoOsdDrawARGB(x, y, height, width, argb); VideoOsdDrawARGB(x, y, height, width, argb);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
static char StartX11Server; ///< flag start the x11 server static char ConfigStartX11Server; ///< flag start the x11 server
/** /**
** Return command line help string. ** Return command line help string.
*/ */
const char *CommandLineHelp(void) const char *CommandLineHelp(void)
{ {
return " -a device\talsa audio device (fe. hw:0,0)\n" return " -a device\taudio device (fe. alsa: hw:0,0 oss: /dev/dsp)\n"
" -d display\tdisplay of x11 server (f.e :0.0)\n" " -d display\tdisplay of x11 server (fe. :0.0)\n"
" -f\t\tstart with fullscreen window (only with window manager)\n"
" -g geometry\tx11 window geometry wxh+x+y\n" " -g geometry\tx11 window geometry wxh+x+y\n"
" -x\tstart x11 server\n"; " -x\t\tstart x11 server\n";
} }
/** /**
@@ -708,13 +1001,16 @@ int ProcessArgs(int argc, char *const argv[])
// Parse arguments. // Parse arguments.
// //
for (;;) { for (;;) {
switch (getopt(argc, argv, "-a:d:g:x")) { switch (getopt(argc, argv, "-a:d:fg:x")) {
case 'a': // audio device case 'a': // audio device
AudioSetDevice(optarg); AudioSetDevice(optarg);
continue; continue;
case 'd': // x11 display name case 'd': // x11 display name
X11DisplayName = optarg; X11DisplayName = optarg;
continue; continue;
case 'f': // fullscreen mode
ConfigFullscreen = 1;
continue;
case 'g': // geometry case 'g': // geometry
if (VideoSetGeometry(optarg) < 0) { if (VideoSetGeometry(optarg) < 0) {
fprintf(stderr, fprintf(stderr,
@@ -724,7 +1020,7 @@ int ProcessArgs(int argc, char *const argv[])
} }
continue; continue;
case 'x': // x11 server case 'x': // x11 server
StartX11Server = 1; ConfigStartX11Server = 1;
continue; continue;
case EOF: case EOF:
break; break;
@@ -844,6 +1140,36 @@ static void StartXServer(void)
*/ */
void SoftHdDeviceExit(void) void SoftHdDeviceExit(void)
{ {
// lets hope that vdr does a good thread cleanup
VideoOsdExit();
VideoExit();
AudioExit();
if (MyVideoDecoder) {
CodecVideoClose(MyVideoDecoder);
// FIXME: CodecDelVideoDecoder(MyVideoDecoder);
MyVideoDecoder = NULL;
}
if (MyAudioDecoder) {
CodecAudioClose(MyAudioDecoder);
// FIXME: CodecDelAudioDecoder(MyAudioDecoder);
MyAudioDecoder = NULL;
}
CodecExit();
VideoPacketExit();
if (ConfigStartX11Server) {
Debug(3, "x-setup: Stop x11 server\n");
if (X11ServerPid) {
kill(X11ServerPid, SIGTERM);
// FIXME: wait for x11 finishing
}
}
pthread_mutex_destroy(&SuspendLockMutex);
} }
/** /**
@@ -851,56 +1177,29 @@ void SoftHdDeviceExit(void)
*/ */
void Start(void) void Start(void)
{ {
if (StartX11Server) { if (ConfigStartX11Server) {
StartXServer(); StartXServer();
} }
CodecInit(); CodecInit();
// FIXME: AudioInit for HDMI after X11 startup // FIXME: AudioInit for HDMI after X11 startup
AudioInit(); AudioInit();
if (!StartX11Server) { if (!ConfigStartX11Server) {
StartVideo(); StartVideo();
} }
pthread_mutex_init(&SuspendLockMutex, NULL);
} }
/** /**
** Stop plugin. ** Stop plugin.
**
** @note stop everything, but don't cleanup, module is still called.
*/ */
void Stop(void) void Stop(void)
{ {
#ifdef DEBUG #ifdef DEBUG
Debug(3, "video: max used PES packet size: %d\n", VideoMaxPacketSize); Debug(3, "video: max used PES packet size: %d\n", VideoMaxPacketSize);
#endif #endif
// FIXME:
// don't let any thread enter our plugin, but can still crash, when
// a thread has called any function, while Stop is called.
BrokenThreadsAndPlugins = 1;
usleep(2 * 1000);
// lets hope that vdr does a good thead cleanup
// no it doesn't do a good thread cleanup
if (MyVideoDecoder) {
CodecVideoClose(MyVideoDecoder);
MyVideoDecoder = NULL;
}
if (MyAudioDecoder) {
CodecAudioClose(MyAudioDecoder);
MyAudioDecoder = NULL;
}
VideoOsdExit();
VideoExit();
AudioExit();
CodecExit();
VideoPacketExit();
if (StartX11Server) {
Debug(3, "x-setup: Stop x11 server\n");
if (X11ServerPid) {
kill(X11ServerPid, SIGTERM);
}
}
} }
/** /**
@@ -908,5 +1207,58 @@ void Stop(void)
*/ */
void MainThreadHook(void) void MainThreadHook(void)
{ {
VideoDisplayHandler(); }
//////////////////////////////////////////////////////////////////////////////
// Suspend/Resume
//////////////////////////////////////////////////////////////////////////////
/**
** Suspend plugin.
*/
void Suspend(void)
{
pthread_mutex_lock(&SuspendLockMutex);
if (SkipVideo && SkipAudio) { // already suspended
pthread_mutex_unlock(&SuspendLockMutex);
return;
}
Debug(3, "[softhddev]%s:\n", __FUNCTION__);
SkipVideo = 1;
SkipAudio = 1;
pthread_mutex_unlock(&SuspendLockMutex);
if (ConfigSuspendClose) {
pthread_mutex_lock(&SuspendLockMutex);
// FIXME: close audio
// FIXME: close video
pthread_mutex_unlock(&SuspendLockMutex);
}
if (ConfigSuspendX11) {
// FIXME: stop x11, if started
}
}
/**
** Resume plugin.
*/
void Resume(void)
{
if (!SkipVideo && !SkipAudio) { // we are not suspended
return;
}
Debug(3, "[softhddev]%s:\n", __FUNCTION__);
if (ConfigSuspendX11) {
}
if (ConfigSuspendClose) {
pthread_mutex_lock(&SuspendLockMutex);
pthread_mutex_unlock(&SuspendLockMutex);
}
SkipVideo = 0;
SkipAudio = 0;
} }

View File

@@ -1,7 +1,7 @@
/// ///
/// @file softhddev.h @brief software HD device plugin header file. /// @file softhddev.h @brief software HD device plugin header file.
/// ///
/// Copyright (c) 2011 by Johns. All Rights Reserved. /// Copyright (c) 2011 - 2012 by Johns. All Rights Reserved.
/// ///
/// Contributor(s): /// Contributor(s):
/// ///
@@ -36,7 +36,7 @@ extern "C"
extern void OsdDrawARGB(int, int, int, int, const uint8_t *); extern void OsdDrawARGB(int, int, int, int, const uint8_t *);
/// C plugin play audio packet /// C plugin play audio packet
extern void PlayAudio(const uint8_t *, int, uint8_t); extern int PlayAudio(const uint8_t *, int, uint8_t);
/// C plugin mute audio /// C plugin mute audio
extern void Mute(void); extern void Mute(void);
/// C plugin set audio volume /// C plugin set audio volume
@@ -46,6 +46,8 @@ extern "C"
extern int PlayVideo(const uint8_t *, int); extern int PlayVideo(const uint8_t *, int);
/// C plugin play TS video packet /// C plugin play TS video packet
extern void PlayTsVideo(const uint8_t *, int); extern void PlayTsVideo(const uint8_t *, int);
/// C plugin grab an image
extern uint8_t *GrabImage(int *, int, int, int, int);
/// C plugin set play mode /// C plugin set play mode
extern void SetPlayMode(void); extern void SetPlayMode(void);
@@ -55,8 +57,12 @@ extern "C"
extern void Play(void); extern void Play(void);
/// C plugin sets the device into "freeze frame" mode /// C plugin sets the device into "freeze frame" mode
extern void Freeze(void); extern void Freeze(void);
/// C plugin display I-frame as a still picture.
extern void StillPicture(const uint8_t *, int);
/// C plugin poll if ready /// C plugin poll if ready
extern int Poll(int); extern int Poll(int);
/// C plugin flush output buffers
extern int Flush(int);
/// C plugin command line help /// C plugin command line help
extern const char *CommandLineHelp(void); extern const char *CommandLineHelp(void);
@@ -72,6 +78,10 @@ extern "C"
/// C plugin main thread hook /// C plugin main thread hook
extern void MainThreadHook(void); extern void MainThreadHook(void);
/// Suspend plugin
extern void Suspend(void);
/// Resume plugin
extern void Resume(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $
EAPI="3"
inherit eutils vdr-plugin
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"
DEPEND=">=x11-libs/libxcb-1.7
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 )
>=media-video/ffmpeg-0.7
sys-devel/gettext
sys-devel/make
dev-util/pkgconfig
yaepg? ( >=media-video/vdr-1.7[yaepg] )
!yaepg? ( >=media-video/vdr-1.7 )
vdpau? ( x11-libs/libvdpau )
vaapi? ( x11-libs/libva )
alsa? ( media-libs/alsa-lib )
oss? ( sys-kernel/linux-headers )
"
src_prepare() {
vdr-plugin_src_prepare
}
src_compile() {
local myconf
myconf=""
use vdpau && myconf="${myconf} -DUSE_VDPAU"
use vaapi && myconf="${myconf} -DUSE_VAAPI"
use alsa && myconf="${myconf} -DUSE_ALSA"
use oss && myconf="${myconf} -DUSE_OSS"
emake all CC="$(tc-getCC)" CFLAGS="${CFLAGS}" \
LDFLAGS="${LDFLAGS}" CONFIG="${myconf}" LIBDIR="." || die
}
src_install() {
vdr-plugin_src_install
dodir /etc/vdr/plugins || die
insinto /etc/vdr/plugins
fowners -R vdr:vdr /etc/vdr || die
#insinto /etc/conf.d
#doins vdr.softhddevice
}

3440
video.c

File diff suppressed because it is too large Load Diff

86
video.h
View File

@@ -1,7 +1,7 @@
/// ///
/// @file video.h @brief Video module header file /// @file video.h @brief Video module header file
/// ///
/// Copyright (c) 2009 - 2011 by Johns. All Rights Reserved. /// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
/// ///
/// Contributor(s): /// Contributor(s):
/// ///
@@ -30,13 +30,6 @@
/// Video hardware decoder typedef /// Video hardware decoder typedef
typedef struct _video_hw_decoder_ VideoHwDecoder; typedef struct _video_hw_decoder_ VideoHwDecoder;
//----------------------------------------------------------------------------
// Variables
//----------------------------------------------------------------------------
//extern unsigned VideoWindowWidth; ///< current video output width
//extern unsigned VideoWindowHeight; ///< current video output height
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Prototypes // Prototypes
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -44,17 +37,20 @@ typedef struct _video_hw_decoder_ VideoHwDecoder;
/// Allocate new video hardware decoder. /// Allocate new video hardware decoder.
extern VideoHwDecoder *VideoNewHwDecoder(void); extern VideoHwDecoder *VideoNewHwDecoder(void);
/// Deallocate video hardware decoder.
extern void VideoDelHwDecoder(VideoHwDecoder *);
/// Get and allocate a video hardware surface. /// Get and allocate a video hardware surface.
extern unsigned VideoGetSurface(VideoHwDecoder *); extern unsigned VideoGetSurface(VideoHwDecoder *);
/// Release a video hardware surface. /// Release a video hardware surface
extern void VideoReleaseSurface(VideoHwDecoder *, unsigned); extern void VideoReleaseSurface(VideoHwDecoder *, unsigned);
#ifdef LIBAVCODEC_VERSION #ifdef LIBAVCODEC_VERSION
/// Render a ffmpeg frame /// Render a ffmpeg frame.
extern void VideoRenderFrame(VideoHwDecoder *, AVCodecContext *, AVFrame *); extern void VideoRenderFrame(VideoHwDecoder *, AVCodecContext *, AVFrame *);
/// Get ffmpeg vaapi context /// Get ffmpeg vaapi context.
extern struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder *); extern struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder *);
/// Callback to negotiate the PixelFormat. /// Callback to negotiate the PixelFormat.
@@ -62,48 +58,72 @@ extern enum PixelFormat Video_get_format(VideoHwDecoder *, AVCodecContext *,
const enum PixelFormat *); const enum PixelFormat *);
#ifdef AVCODEC_VDPAU_H #ifdef AVCODEC_VDPAU_H
/// Draw vdpau render state /// Draw vdpau render state.
extern void VideoDrawRenderState(VideoHwDecoder *, extern void VideoDrawRenderState(VideoHwDecoder *,
struct vdpau_render_state *); struct vdpau_render_state *);
#endif #endif
#endif #endif
/// Display video TEST /// Poll video events.
extern void VideoDisplayHandler(void);
/// Poll video events
extern void VideoPollEvent(void); extern void VideoPollEvent(void);
/// set video mode /// Wakeup display handler.
//extern void VideoSetVideoMode(int, int, int, int); extern void VideoDisplayWakeup(void);
/// set video geometry /// Set video geometry.
extern int VideoSetGeometry(const char *); extern int VideoSetGeometry(const char *);
/// set deinterlace /// Set video output position.
extern void VideoSetDeinterlace(int); extern void VideoSetOutputPosition(int, int, int, int);
/// set scaling /// Set video mode.
extern void VideoSetScaling(int); extern void VideoSetVideoMode(int, int, int, int);
/// set audio delay /// Set video fullscreen mode.
extern void VideoSetFullscreen(int);
/// Set deinterlace.
extern void VideoSetDeinterlace(int[]);
/// Set skip chroma deinterlace.
extern void VideoSetSkipChromaDeinterlace(int[]);
/// Set scaling.
extern void VideoSetScaling(int[]);
/// Set denoise.
extern void VideoSetDenoise(int[]);
/// Set sharpen.
extern void VideoSetSharpen(int[]);
/// Set audio delay.
extern void VideoSetAudioDelay(int); extern void VideoSetAudioDelay(int);
/// Clear OSD /// Set auto-crop parameters.
extern void VideoSetAutoCrop(int, int);
/// Clear OSD.
extern void VideoOsdClear(void); extern void VideoOsdClear(void);
/// Draw an OSD ARGB image /// Draw an OSD ARGB image.
extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *); extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *);
extern int64_t VideoGetClock(void); ///< get video clock /// Get OSD size.
extern void VideoGetOsdSize(int *, int *);
extern void VideoOsdInit(void); ///< setup osd extern int64_t VideoGetClock(void); ///< Get video clock.
extern void VideoOsdExit(void); ///< cleanup osd
extern void VideoInit(const char *); ///< setup video module /// Grab screen.
extern void VideoExit(void); ///< cleanup and exit video module extern uint8_t *VideoGrab(int *, int *, int *);
extern void VideoFlushInput(void); ///< flush codec input buffers extern void VideoOsdInit(void); ///< Setup osd.
extern int VideoDecode(void); ///< decode extern void VideoOsdExit(void); ///< Cleanup osd.
extern void VideoInit(const char *); ///< Setup video module.
extern void VideoExit(void); ///< Cleanup and exit video module.
extern void VideoFlushInput(void); ///< Flush video input buffers.
extern int VideoDecode(void); ///< Decode video input buffers.
/// @} /// @}