27 Commits
0.2.0 ... 0.3.1

Author SHA1 Message Date
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
14 changed files with 1726 additions and 746 deletions

View File

@@ -1,5 +1,45 @@
User johns User johns
Data: Sat Jan 7 13:20:07 CET 2012 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 Release Version 0.2.0
Add support for ac3 audio pass through. Add support for ac3 audio pass through.

View File

@@ -26,40 +26,17 @@ CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
### 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 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 LDFLAGS += -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 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:
@@ -78,12 +55,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)"'
_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):
OBJS = $(PLUGIN).o softhddev.o video.o audio.o codec.o ringbuffer.o OBJS = $(PLUGIN).o softhddev.o video.o audio.o codec.o ringbuffer.o
@@ -105,6 +110,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):
@@ -137,7 +144,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
@@ -163,5 +170,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

@@ -33,7 +33,7 @@ A software and GPU emulated HD output device plugin for VDR.
o Audio FFMpeg/Alsa/Analog o Audio FFMpeg/Alsa/Analog
o Audio FFMpeg/Alsa/Digital o Audio FFMpeg/Alsa/Digital
o Audio FFMpeg/OSS/Analog o Audio FFMpeg/OSS/Analog
o planned: Alsa HDMI/SPDIF Passthrough o Alsa HDMI/SPDIF Passthrough
o planned: OSS HDMI/SPDIF Passthrough o planned: OSS HDMI/SPDIF Passthrough
To compile you must have the 'requires' installed. To compile you must have the 'requires' installed.
@@ -95,35 +95,63 @@ Setup: /etc/vdr/setup.conf
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.Deinterlace = 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
softhddevice.<res>.Deinterlace = 0
0 = bob, 1 = weave, 2 = temporal, 3 = temporal_spatial, 4 = software 0 = bob, 1 = weave, 2 = temporal, 3 = temporal_spatial, 4 = software
(only 0, 1 supported with vaapi) (only 0, 1 supported with vaapi)
softhddevice.SkipChromaDeinterlace = 0 softhddevice.<res>.SkipChromaDeinterlace = 0
0 = disabled, 1 = enabled (for slower cards, poor qualit<69>t) 0 = disabled, 1 = enabled (for slower cards, poor qualit<69>t)
softhddevice.Denoise = 0 softhddevice.<res>.Denoise = 0
0 .. 1000 noise reduction level (0 off, 1000 max) 0 .. 1000 noise reduction level (0 off, 1000 max)
softhddevice.Sharpness = 0 softhddevice.<res>.Sharpness = 0
-1000 .. 1000 noise reduction level (0 off, -1000 max blur, -1000 .. 1000 noise reduction level (0 off, -1000 max blur,
1000 max sharp) 1000 max sharp)
softhddevice.Scaling = 0
0 = normal, 1 = fast, 2 = HQ, 3 = anamorphic
softhddevice.AudioDelay = 0 softhddevice.AudioDelay = 0
+n or -n ms +n or -n ms
softhddevice.AudioPassthrough = 0 softhddevice.AudioPassthrough = 0
0 = none, 1 = AC-3 0 = none, 1 = AC-3
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: Commandline:
------------ ------------
Use vdr -h to see the command line arguments support by the plugin. Use vdr -h to see the command line arguments support by the plugin.
Running:
--------
Click into video window to toggle fullscreen/window mode, only if you
have a window manager running.
Warning: Warning:
-------- --------
libav is not supported, expect many bugs with it. libav is not supported, expect many bugs with it.

43
Todo
View File

@@ -19,17 +19,13 @@ GNU Affero General Public License for more details.
$Id: $ $Id: $
missing: missing:
video out with xv
video out with opengl
software decoder for xv / opengl
software deinterlace software deinterlace
auto crop auto crop
atmolight zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
zoom/fit-zoom 4:3
multistream handling
disable screensaver
disable window cursor
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)? ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
suspend output / energie saver: stop audio, stop video, configurable
Option deinterlace off / deinterlace force!
Make output drivers better moduluar.
vdpau: vdpau:
1080i with temporal spatial and level 1 scaling too slow with my GT 520 1080i with temporal spatial and level 1 scaling too slow with my GT 520
@@ -38,9 +34,11 @@ vdpau:
Improve OSD handling, show only what is used. Big OSD costs performance Improve OSD handling, show only what is used. Big OSD costs performance
VdpPreemptionCallback handling VdpPreemptionCallback handling
hard channel switch hard channel switch
suspendoutput didn't show logo or black picture.
libva: libva:
hard channel switch hard channel switch
yaepghd (VaapiSetOutputPosition) support
libva-intel-driver: libva-intel-driver:
intel still has hangups most with 1080i intel still has hangups most with 1080i
@@ -56,16 +54,14 @@ libva-vdpau-driver:
libva-xvba-driver: libva-xvba-driver:
x11: x11:
support resize of x11 window disable screensaver
support fullscreen window
support fullscreen / window toggle
close window should send power button
disable cursor
audio/alsa: audio/alsa:
done? video/audio asyncron done? video/audio asyncron
random crashes in av_parser_parse2, when switching channels random crashes in av_parser_parse2, when switching channels
sometimes alsa hangs sometimes alsa hangs
fixed? snd_pcm_state: Assertion `pcm' failed. while switching channels
(thread problem)
better downmix of >2 channels on 2 channel hardware better downmix of >2 channels on 2 channel hardware
remix support of unsupported sample rates remix support of unsupported sample rates
@@ -73,21 +69,38 @@ audio/alsa:
ffmpeg didn't support resample of 5 to 2 channels ffmpeg didn't support resample of 5 to 2 channels
CodecAudioOpen can fail "can't open audio codec" and does Fatal exit. CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
audio:
write TS -> PES parser, which feeds audio before the next start packet
audio/oss: audio/oss:
alsa oss emulation mixer "pcm" not working alsa oss emulation mixer "pcm" not working
ring buffer overflow with alsa oss emulation ring buffer overflow with alsa oss emulation
HDMI/SPDIF Passthrough: HDMI/SPDIF Passthrough:
only AC-3 written only AC-3 written
Channels are wrong setup, if changing setting during operation.
split pcm and ac-3 out into two devices
playback of recording playback of recording
play back is too fast
pause is not reset, when replay exit pause is not reset, when replay exit
replay/pause need 100% cpu
setup: setup:
Setup of decoder type. Setup of decoder type.
Setup of output type. Setup of output type.
Setup of display type. Setup of display type.
Setup 4:3 zoom type Setup 4:3 zoom type
Setup parameters are not used until restart. 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?
576i, 720p, fake 1080i, 1080i
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
upmix stereo to AC-3

144
audio.c
View File

@@ -296,6 +296,7 @@ static int AlsaPlayRingbuffer(void)
if (first) { if (first) {
// happens with broken alsa drivers // happens with broken alsa drivers
Error(_("audio/alsa: broken driver %d\n"), avail); Error(_("audio/alsa: broken driver %d\n"), avail);
usleep(5 * 1000);
} }
Debug(4, "audio/alsa: break state %s\n", Debug(4, "audio/alsa: break state %s\n",
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle))); snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
@@ -342,6 +343,11 @@ static int AlsaPlayRingbuffer(void)
if (err == -EAGAIN) { if (err == -EAGAIN) {
goto again; goto again;
} }
/*
if (err == -EBADFD) {
goto again;
}
*/
Error(_("audio/alsa: underrun error?\n")); Error(_("audio/alsa: underrun error?\n"));
err = snd_pcm_recover(AlsaPCMHandle, err, 0); err = snd_pcm_recover(AlsaPCMHandle, err, 0);
if (err >= 0) { if (err >= 0) {
@@ -368,11 +374,21 @@ static int AlsaPlayRingbuffer(void)
static void AlsaFlushBuffers(void) static void AlsaFlushBuffers(void)
{ {
int err; int err;
snd_pcm_state_t state;
RingBufferReadAdvance(AlsaRingBuffer, RingBufferUsedBytes(AlsaRingBuffer)); RingBufferReadAdvance(AlsaRingBuffer, RingBufferUsedBytes(AlsaRingBuffer));
if ((err = snd_pcm_drop(AlsaPCMHandle))) { state = snd_pcm_state(AlsaPCMHandle);
Error(_("audio: snd_pcm_drop(): %s\n"), snd_strerror(err)); Debug(3, "audio/alsa: state %d - %s\n", state, snd_pcm_state_name(state));
if (state != SND_PCM_STATE_OPEN) {
if ((err = snd_pcm_drop(AlsaPCMHandle)) < 0) {
Error(_("audio: snd_pcm_drop(): %s\n"), snd_strerror(err));
}
// ****ing alsa crash, when in open state here
if ((err = snd_pcm_prepare(AlsaPCMHandle)) < 0) {
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
}
} }
AudioPTS = INT64_C(0x8000000000000000);
} }
#if 0 #if 0
@@ -567,8 +583,20 @@ static void AlsaThread(void)
for (;;) { for (;;) {
int err; int err;
Debug(4, "audio: play loop\n");
pthread_testcancel(); pthread_testcancel();
if (AlsaFlushBuffer) {
// we can flush too many, but wo cares
Debug(3, "audio/alsa: flushing buffers\n");
AlsaFlushBuffers();
/*
if ((err = snd_pcm_prepare(AlsaPCMHandle))) {
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
}
*/
AlsaFlushBuffer = 0;
break;
}
// wait for space in kernel buffers
if ((err = snd_pcm_wait(AlsaPCMHandle, 100)) < 0) { if ((err = snd_pcm_wait(AlsaPCMHandle, 100)) < 0) {
Error(_("audio/alsa: wait underrun error?\n")); Error(_("audio/alsa: wait underrun error?\n"));
err = snd_pcm_recover(AlsaPCMHandle, err, 0); err = snd_pcm_recover(AlsaPCMHandle, err, 0);
@@ -580,14 +608,7 @@ static void AlsaThread(void)
continue; continue;
} }
if (AlsaFlushBuffer) { if (AlsaFlushBuffer) {
// we can flush too many, but wo cares continue;
Debug(3, "audio/alsa: flushing buffers\n");
AlsaFlushBuffers();
if ((err = snd_pcm_prepare(AlsaPCMHandle))) {
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
}
AlsaFlushBuffer = 0;
break;
} }
if ((err = AlsaPlayRingbuffer())) { // empty / error if ((err = AlsaPlayRingbuffer())) { // empty / error
snd_pcm_state_t state; snd_pcm_state_t state;
@@ -600,7 +621,8 @@ static void AlsaThread(void)
Debug(3, "audio/alsa: stopping play\n"); Debug(3, "audio/alsa: stopping play\n");
break; break;
} }
usleep(20 * 1000); pthread_yield();
usleep(20 * 1000); // let fill the buffers
} }
} }
} }
@@ -834,23 +856,9 @@ static int AlsaSetup(int *freq, int *channels)
if (!AlsaPCMHandle) { // alsa not running yet if (!AlsaPCMHandle) { // alsa not running yet
return -1; return -1;
} }
#if 1 #if 1 // easy alsa hw setup way
// flush any buffered data // flush any buffered data
#ifndef SEARCH_HDMI_BUG2 AudioFlushBuffers();
#ifdef USE_AUDIO_THREAD
if (AudioRunning) {
while (AudioRunning) {
AlsaFlushBuffer = 1;
usleep(1 * 1000);
}
AlsaFlushBuffer = 0;
} else
#endif
{
AlsaFlushBuffers();
}
#endif
AudioPTS = INT64_C(0x8000000000000000);
if (1) { // close+open to fix hdmi no sound bugs if (1) { // close+open to fix hdmi no sound bugs
handle = AlsaPCMHandle; handle = AlsaPCMHandle;
@@ -1195,6 +1203,21 @@ static int OssPlayRingbuffer(void)
return 0; return 0;
} }
/**
** Flush oss buffers.
*/
static void OssFlushBuffers(void)
{
RingBufferReadAdvance(OssRingBuffer, RingBufferUsedBytes(OssRingBuffer));
// flush kernel buffers
if (ioctl(OssPcmFildes, SNDCTL_DSP_HALT_OUTPUT, NULL) < 0) {
Error(_("audio/oss: ioctl(SNDCTL_DSP_HALT_OUTPUT): %s\n"),
strerror(errno));
return;
}
AudioPTS = INT64_C(0x8000000000000000);
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// OSS pcm polled // OSS pcm polled
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -1410,16 +1433,8 @@ static int OssSetup(int *freq, int *channels)
// flush any buffered data // flush any buffered data
{ {
AudioRunning = 0; AudioRunning = 0;
RingBufferReadAdvance(OssRingBuffer, OssFlushBuffers();
RingBufferUsedBytes(OssRingBuffer));
// flush kernel buffers
if (ioctl(OssPcmFildes, SNDCTL_DSP_HALT_OUTPUT, NULL) == -1) {
Error(_("audio/oss: ioctl(SNDCTL_DSP_HALT_OUTPUT): %s\n"),
strerror(errno));
return -1;
}
} }
AudioPTS = INT64_C(0x8000000000000000);
ret = 0; ret = 0;
@@ -1639,14 +1654,16 @@ static void AudioExitThread(void)
{ {
void *retval; void *retval;
if (pthread_cancel(AudioThread)) { if (AudioThread) {
Error(_("audio: can't queue cancel play thread\n")); if (pthread_cancel(AudioThread)) {
Error(_("audio: can't queue cancel play thread\n"));
}
if (pthread_join(AudioThread, &retval) || retval != PTHREAD_CANCELED) {
Error(_("audio: can't cancel play thread\n"));
}
pthread_cond_destroy(&AudioStartCond);
pthread_mutex_destroy(&AudioMutex);
} }
if (pthread_join(AudioThread, &retval) || retval != PTHREAD_CANCELED) {
Error(_("audio: can't cancel play thread\n"));
}
pthread_cond_destroy(&AudioStartCond);
pthread_mutex_destroy(&AudioMutex);
} }
#endif #endif
@@ -1672,6 +1689,31 @@ void AudioEnqueue(const void *samples, int count)
(void)count; (void)count;
} }
/**
** Flush audio buffers.
*/
void AudioFlushBuffers(void)
{
#ifdef USE_ALSA
#ifdef USE_AUDIO_THREAD
// signal thread to flush buffers
if (AudioThread) {
AlsaFlushBuffer = 1;
do {
AudioRunning = 1; // wakeup in case of sleeping
pthread_cond_signal(&AudioStartCond);
usleep(1 * 1000);
} while (AlsaFlushBuffer); // wait until flushed
}
#else
AlsaFlushBuffers();
#endif
#endif
#ifdef USE_OSS
OssFlushBuffers();
#endif
}
/** /**
** Call back to play audio polled. ** Call back to play audio polled.
*/ */
@@ -1687,6 +1729,20 @@ void AudioPoller(void)
#endif #endif
} }
/**
** Get free bytes in audio output.
*/
int AudioFreeBytes(void)
{
#ifdef USE_ALSA
return AlsaRingBuffer ? RingBufferFreeBytes(AlsaRingBuffer) : INT32_MAX;
#endif
#ifdef USE_OSS
return OssRingBuffer ? RingBufferFreeBytes(OssRingBuffer) : INT32_MAX;
#endif
return INT32_MAX; // no driver, much space
}
/** /**
** Set audio clock base. ** Set audio clock base.
** **

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,12 +28,14 @@
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
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 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 uint64_t AudioGetDelay(void); ///< get current audio delay 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

23
codec.c
View File

@@ -561,6 +561,16 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
} }
} }
/**
** Flush the video decoder.
**
** @param decoder video decoder data
*/
void CodecVideoFlushBuffers(VideoDecoder * decoder)
{
avcodec_flush_buffers(decoder->VideoCtx);
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Audio // Audio
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -738,9 +748,11 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const 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;
@@ -1026,6 +1038,17 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
#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
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

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 *, const 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 *, const 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);

View File

@@ -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"
@@ -52,18 +57,23 @@ static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
#define ConfigVdpauDecoder 0 ///< no vdpau decoder configured #define ConfigVdpauDecoder 0 ///< no vdpau decoder configured
#endif #endif
static const char DeviceStopped = 1; ///< flag device stopped 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 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. ** mpeg bitrate table.
** **
@@ -187,26 +197,37 @@ static int FindAudioSync(const AVPacket * avpkt)
** @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, int PlayAudio(const uint8_t * data, int size,
__attribute__ ((unused)) uint8_t id) __attribute__ ((unused)) uint8_t id)
{ {
int n; int n;
int osize;
AVPacket avpkt[1]; AVPacket avpkt[1];
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice: // channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
if (VideoFreezed) { // video freezed
return 0;
}
if (NewAudioStream) { if (NewAudioStream) {
// FIXME: does this clear the audio ringbuffer? // FIXME: does this clear the audio ringbuffer?
CodecAudioClose(MyAudioDecoder); CodecAudioClose(MyAudioDecoder);
AudioCodecID = CODEC_ID_NONE; AudioCodecID = CODEC_ID_NONE;
NewAudioStream = 0; 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
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
@@ -227,11 +248,12 @@ void PlayAudio(const uint8_t * data, int size,
} }
} }
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 // Detect audio code
// MPEG-PS mp2 MPEG1, MPEG2, AC3 // MPEG-PS mp2 MPEG1, MPEG2, AC3
@@ -273,7 +295,7 @@ void PlayAudio(const uint8_t * data, int size,
avpkt->size = size; avpkt->size = size;
n = FindAudioSync(avpkt); n = FindAudioSync(avpkt);
if (n < 0) { if (n < 0) {
return; return osize;
} }
if (!MyAudioDecoder) { if (!MyAudioDecoder) {
MyAudioDecoder = CodecAudioNewDecoder(); MyAudioDecoder = CodecAudioNewDecoder();
@@ -288,13 +310,15 @@ void PlayAudio(const uint8_t * data, int size,
// 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;
} }
/** /**
@@ -302,7 +326,8 @@ void PlayAudio(const uint8_t * data, int size,
*/ */
void Mute(void) void Mute(void)
{ {
AudioSetVolume(0); SkipAudio = 1;
//AudioSetVolume(0);
} }
/** /**
@@ -337,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 volatile char VideoFreezed; ///< video freezed
static volatile char VideoClearBuffers; ///< clear video buffers static volatile 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
@@ -351,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;
@@ -374,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);
} }
} }
@@ -466,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();
} }
/** /**
@@ -490,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;
} }
@@ -560,19 +581,23 @@ 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();
} }
@@ -641,6 +666,12 @@ 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 (SkipVideo) { // skip video
return size;
}
if (VideoFreezed) { // video freezed
return 0;
}
if (NewVideoStream) { // channel switched 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
@@ -661,7 +692,7 @@ 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 + 4) { if (size < 9 + n + 4) {
Error(_("[softhddev] invalid video packet\n")); Error(_("[softhddev] invalid video packet %d bytes\n"), size);
return size; return size;
} }
// FIXME: hack to test results // FIXME: hack to test results
@@ -728,6 +759,16 @@ int PlayVideo(const uint8_t * data, int size)
Debug(3, "video: h264 detected\n"); Debug(3, "video: h264 detected\n");
VideoCodecID = CODEC_ID_H264; 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) {
VideoNextPacket(CODEC_ID_H264);
} else {
Debug(3, "video: h264 detected\n");
VideoCodecID = CODEC_ID_H264;
}
} else { } else {
// this happens when vdr sends incomplete packets // this happens when vdr sends incomplete packets
if (VideoCodecID == CODEC_ID_NONE) { if (VideoCodecID == CODEC_ID_NONE) {
@@ -754,6 +795,7 @@ int PlayVideo(const uint8_t * data, int size)
*/ */
void SetPlayMode(void) void SetPlayMode(void)
{ {
Resume();
if (MyVideoDecoder) { if (MyVideoDecoder) {
if (VideoCodecID != CODEC_ID_NONE) { if (VideoCodecID != CODEC_ID_NONE) {
NewVideoStream = 1; NewVideoStream = 1;
@@ -761,8 +803,13 @@ void SetPlayMode(void)
} }
} }
if (MyAudioDecoder) { if (MyAudioDecoder) {
NewAudioStream = 1; if (AudioCodecID != CODEC_ID_NONE) {
NewAudioStream = 1;
}
} }
VideoFreezed = 0;
SkipAudio = 0;
SkipVideo = 0;
} }
/** /**
@@ -770,9 +817,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);
}
} }
/** /**
@@ -781,6 +835,7 @@ void Clear(void)
void Play(void) void Play(void)
{ {
VideoFreezed = 0; VideoFreezed = 0;
SkipAudio = 0;
// FIXME: restart audio // FIXME: restart audio
} }
@@ -791,16 +846,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);
@@ -810,6 +887,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
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -819,7 +912,9 @@ int Poll(int timeout)
*/ */
void GetOsdSize(int *width, int *height, double *aspect) void GetOsdSize(int *width, int *height, double *aspect)
{ {
#ifdef DEBUG
static char done; static char done;
#endif
// FIXME: should be configured! // FIXME: should be configured!
*width = 1920; *width = 1920;
@@ -829,11 +924,13 @@ void GetOsdSize(int *width, int *height, double *aspect)
*aspect = 16.0 / 9.0 / (double)*width * (double)*height; *aspect = 16.0 / 9.0 / (double)*width * (double)*height;
#ifdef DEBUG
if (!done) { if (!done) {
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 = 1;
} }
#endif
} }
/** /**
@@ -849,22 +946,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)
{ {
Resume();
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";
} }
/** /**
@@ -879,13 +978,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,
@@ -895,7 +997,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;
@@ -1034,13 +1136,16 @@ void SoftHdDeviceExit(void)
CodecExit(); CodecExit();
VideoPacketExit(); VideoPacketExit();
if (StartX11Server) { if (ConfigStartX11Server) {
Debug(3, "x-setup: Stop x11 server\n"); Debug(3, "x-setup: Stop x11 server\n");
if (X11ServerPid) { if (X11ServerPid) {
kill(X11ServerPid, SIGTERM); kill(X11ServerPid, SIGTERM);
// FIXME: wait for x11 finishing
} }
} }
pthread_mutex_destroy(&SuspendLockMutex);
} }
/** /**
@@ -1048,15 +1153,17 @@ 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);
} }
/** /**
@@ -1076,7 +1183,58 @@ void Stop(void)
*/ */
void MainThreadHook(void) void MainThreadHook(void)
{ {
if (!DeviceStopped) { }
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
@@ -55,8 +55,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 +76,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

View File

@@ -42,23 +42,42 @@ extern "C"
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
static const char *const VERSION = "0.2.0"; static const char *const VERSION = "0.3.1";
static const char *const DESCRIPTION = static const char *const DESCRIPTION =
trNOOP("A software and GPU emulated HD device"); trNOOP("A software and GPU emulated HD device");
//static const char *MAINMENUENTRY = trNOOP("Soft-HD-Device"); static const char *MAINMENUENTRY = trNOOP("Suspend Soft-HD-Device");
static class cSoftHdDevice *MyDevice; static class cSoftHdDevice *MyDevice;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#define RESOLUTIONS 4 ///< number of resolutions
static const char *const Resolution[RESOLUTIONS] = {
"576i", "720p", "1080i_fake", "1080i"
};
static char ConfigMakePrimary; ///< config primary wanted static char ConfigMakePrimary; ///< config primary wanted
static char ConfigVideoDeinterlace; ///< config deinterlace static char ConfigHideMainMenuEntry; ///< config hide main menu entry
static char ConfigVideoSkipChromaDeinterlace; ///< config skip chroma
static int ConfigVideoDenoise; ///< config denoise /// config deinterlace
static int ConfigVideoSharpen; ///< config sharpen static int ConfigVideoDeinterlace[RESOLUTIONS];
static char ConfigVideoScaling; ///< config scaling
/// config skip chroma
static int ConfigVideoSkipChromaDeinterlace[RESOLUTIONS];
/// config denoise
static int ConfigVideoDenoise[RESOLUTIONS];
/// config sharpen
static int ConfigVideoSharpen[RESOLUTIONS];
/// config scaling
static int ConfigVideoScaling[RESOLUTIONS];
static int ConfigVideoAudioDelay; ///< config audio delay static int ConfigVideoAudioDelay; ///< config audio delay
static int ConfigAudioPassthrough; ///< config audio pass-through static int ConfigAudioPassthrough; ///< config audio pass-through
static volatile char DoMakePrimary; ///< flag switch primary static volatile char DoMakePrimary; ///< flag switch primary
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -113,8 +132,10 @@ extern "C" void FeedKeyPress(const char *keymap, const char *key, int repeat,
class cSoftOsd:public cOsd class cSoftOsd:public cOsd
{ {
int Level; ///< level: subtitle
public: public:
cSoftOsd(int, int, uint); cSoftOsd(int, int, uint);
virtual ~ cSoftOsd(void); virtual ~ cSoftOsd(void);
virtual void Flush(void); virtual void Flush(void);
// virtual void SetActive(bool); // virtual void SetActive(bool);
@@ -127,6 +148,7 @@ cSoftOsd::cSoftOsd(int left, int top, uint level)
dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(), dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(),
OsdHeight(), left, top, level); OsdHeight(), left, top, level);
this->Level = level;
//SetActive(true); //SetActive(true);
} }
@@ -135,6 +157,11 @@ cSoftOsd::~cSoftOsd(void)
//dsyslog("[softhddev]%s:\n", __FUNCTION__); //dsyslog("[softhddev]%s:\n", __FUNCTION__);
SetActive(false); SetActive(false);
#ifdef USE_YAEPG
if (vidWin.bpp) {
VideoSetOutputPosition(0, 0, 1920, 1080);
}
#endif
OsdClose(); OsdClose();
} }
@@ -148,7 +175,18 @@ void cSoftOsd::Flush(void)
if (!Active()) { if (!Active()) {
return; return;
} }
//dsyslog("[softhddev]%s:\n", __FUNCTION__); // support yaepghd, video window
#ifdef USE_YAEPG
if (vidWin.bpp) {
dsyslog("[softhddev]%s: %dx%d+%d+%d\n", __FUNCTION__, vidWin.Width(),
vidWin.Height(), vidWin.x1, vidWin.y2);
// FIXME: vidWin is OSD relative not video window.
VideoSetOutputPosition(Left() + vidWin.x1, Top() + vidWin.y1,
vidWin.Width(), vidWin.Height());
}
#endif
if (!IsTrueColor()) { if (!IsTrueColor()) {
static char warned; static char warned;
cBitmap *bitmap; cBitmap *bitmap;
@@ -188,8 +226,24 @@ void cSoftOsd::Flush(void)
} }
} }
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(), // check if subtitles
bitmap->Width(), bitmap->Height(), argb); if (this->Level == OSD_LEVEL_SUBTITLES) {
int video_width;
int video_height;
if (0) {
dsyslog("[softhddev]%s: subtitle %d, %d\n", __FUNCTION__,
Left() + bitmap->X0(), Top() + bitmap->Y0());
}
video_width = 1920;
video_height = 1080;
OsdDrawARGB((1920 - video_width) / 2 + Left() + bitmap->X0(),
1080 - video_height + Top() + bitmap->Y0(),
bitmap->Width(), bitmap->Height(), argb);
} else {
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(),
bitmap->Width(), bitmap->Height(), argb);
}
bitmap->Clean(); bitmap->Clean();
free(argb); free(argb);
@@ -255,6 +309,9 @@ bool cSoftOsdProvider::ProvidesTrueColor(void)
return true; return true;
} }
/**
** Create cOsdProvider class.
*/
cSoftOsdProvider::cSoftOsdProvider(void) cSoftOsdProvider::cSoftOsdProvider(void)
: cOsdProvider() : cOsdProvider()
{ {
@@ -269,11 +326,12 @@ class cMenuSetupSoft:public cMenuSetupPage
{ {
protected: protected:
int MakePrimary; int MakePrimary;
int Deinterlace; int HideMainMenuEntry;
int SkipChromaDeinterlace; int Scaling[RESOLUTIONS];
int Denoise; int Deinterlace[RESOLUTIONS];
int Sharpen; int SkipChromaDeinterlace[RESOLUTIONS];
int Scaling; int Denoise[RESOLUTIONS];
int Sharpen[RESOLUTIONS];
int AudioDelay; int AudioDelay;
int AudioPassthrough; int AudioPassthrough;
protected: protected:
@@ -282,13 +340,26 @@ class cMenuSetupSoft:public cMenuSetupPage
cMenuSetupSoft(void); cMenuSetupSoft(void);
}; };
/**
** Create a seperator item.
*/
static inline cOsdItem *SeparatorItem(const char *label)
{
cOsdItem *item;
item = new cOsdItem(cString::sprintf("* %s: ", label));
item->SetSelectable(false);
return item;
}
/** /**
** Constructor setup menu. ** Constructor setup menu.
*/ */
cMenuSetupSoft::cMenuSetupSoft(void) cMenuSetupSoft::cMenuSetupSoft(void)
{ {
static const char *const deinterlace[] = { static const char *const deinterlace[] = {
"Bob", "Weave", "Temporal", "TemporalSpatial", "Software" "Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software"
}; };
static const char *const scaling[] = { static const char *const scaling[] = {
"Normal", "Fast", "HQ", "Anamorphic" "Normal", "Fast", "HQ", "Anamorphic"
@@ -296,26 +367,44 @@ cMenuSetupSoft::cMenuSetupSoft(void)
static const char *const passthrough[] = { static const char *const passthrough[] = {
"None", "AC-3" "None", "AC-3"
}; };
static const char *const resolution[RESOLUTIONS] = {
"576i", "720p", "fake 1080i", "1080i"
};
int i;
// cMenuEditBoolItem cMenuEditBitItem cMenuEditNumItem // cMenuEditBoolItem cMenuEditBitItem cMenuEditNumItem
// cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem // cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem
MakePrimary = ConfigMakePrimary; MakePrimary = ConfigMakePrimary;
Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary, Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary,
tr("no"), tr("yes"))); tr("no"), tr("yes")));
Deinterlace = ConfigVideoDeinterlace; HideMainMenuEntry = ConfigHideMainMenuEntry;
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace, 5, Add(new cMenuEditBoolItem(tr("Hide main menu entry"), &HideMainMenuEntry,
deinterlace)); tr("no"), tr("yes")));
SkipChromaDeinterlace = ConfigVideoSkipChromaDeinterlace; //
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"), // video
&SkipChromaDeinterlace, tr("no"), tr("yes"))); //
Denoise = ConfigVideoDenoise; Add(SeparatorItem(tr("Video")));
Add(new cMenuEditIntItem(tr("Denoise (vdpau 0..1000)"), &Denoise, 0, for (i = 0; i < RESOLUTIONS; ++i) {
1000)); Add(SeparatorItem(resolution[i]));
Sharpen = ConfigVideoSharpen; Scaling[i] = ConfigVideoScaling[i];
Add(new cMenuEditIntItem(tr("Sharpen (vdpau -1000..1000)"), &Sharpen, Add(new cMenuEditStraItem(tr("Scaling"), &Scaling[i], 4, scaling));
-1000, 1000)); Deinterlace[i] = ConfigVideoDeinterlace[i];
Scaling = ConfigVideoScaling; Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace[i], 5,
Add(new cMenuEditStraItem(tr("Scaling"), &Scaling, 4, scaling)); deinterlace));
SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i];
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),
&SkipChromaDeinterlace[i], tr("no"), tr("yes")));
Denoise[i] = ConfigVideoDenoise[i];
Add(new cMenuEditIntItem(tr("Denoise (0..1000) (vdpau)"), &Denoise[i],
0, 1000));
Sharpen[i] = ConfigVideoSharpen[i];
Add(new cMenuEditIntItem(tr("Sharpen (-1000..1000) (vdpau)"),
&Sharpen[i], -1000, 1000));
}
//
// audio
//
Add(SeparatorItem(tr("Audio")));
AudioDelay = ConfigVideoAudioDelay; AudioDelay = ConfigVideoAudioDelay;
Add(new cMenuEditIntItem(tr("Audio delay (ms)"), &AudioDelay, -1000, Add(new cMenuEditIntItem(tr("Audio delay (ms)"), &AudioDelay, -1000,
1000)); 1000));
@@ -329,18 +418,34 @@ cMenuSetupSoft::cMenuSetupSoft(void)
*/ */
void cMenuSetupSoft::Store(void) void cMenuSetupSoft::Store(void)
{ {
int i;
SetupStore("MakePrimary", ConfigMakePrimary = MakePrimary); SetupStore("MakePrimary", ConfigMakePrimary = MakePrimary);
SetupStore("Deinterlace", ConfigVideoDeinterlace = Deinterlace); SetupStore("HideMainMenuEntry", ConfigHideMainMenuEntry =
VideoSetDeinterlace(ConfigVideoDeinterlace); HideMainMenuEntry);
SetupStore("SkipChromaDeinterlace", ConfigVideoSkipChromaDeinterlace =
SkipChromaDeinterlace); for (i = 0; i < RESOLUTIONS; ++i) {
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace); char buf[128];
SetupStore("Denoise", ConfigVideoDenoise = Denoise);
VideoSetDenoise(ConfigVideoDenoise); snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
SetupStore("Sharpen", ConfigVideoSharpen = Sharpen); SetupStore(buf, ConfigVideoScaling[i] = Scaling[i]);
VideoSetSharpen(ConfigVideoSharpen); snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Deinterlace");
SetupStore("Scaling", ConfigVideoScaling = Scaling); SetupStore(buf, ConfigVideoDeinterlace[i] = Deinterlace[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i],
"SkipChromaDeinterlace");
SetupStore(buf, ConfigVideoSkipChromaDeinterlace[i] =
SkipChromaDeinterlace[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise");
SetupStore(buf, ConfigVideoDenoise[i] = Denoise[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Sharpen");
SetupStore(buf, ConfigVideoSharpen[i] = Sharpen[i]);
}
VideoSetScaling(ConfigVideoScaling); VideoSetScaling(ConfigVideoScaling);
VideoSetDeinterlace(ConfigVideoDeinterlace);
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
VideoSetDenoise(ConfigVideoDenoise);
VideoSetSharpen(ConfigVideoSharpen);
SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay); SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay);
VideoSetAudioDelay(ConfigVideoAudioDelay); VideoSetAudioDelay(ConfigVideoAudioDelay);
SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough); SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough);
@@ -370,8 +475,15 @@ class cSoftHdDevice:public cDevice
virtual bool Poll(cPoller &, int = 0); virtual bool Poll(cPoller &, int = 0);
virtual bool Flush(int = 0); virtual bool Flush(int = 0);
virtual int64_t GetSTC(void); virtual int64_t GetSTC(void);
virtual void GetVideoSize(int &width, int &height, double &aspect)
{
width = 1920;
height = 1080;
aspect = (double)width / height;
}
virtual void GetOsdSize(int &, int &, double &); virtual void GetOsdSize(int &, int &, double &);
virtual int PlayVideo(const uchar *, int); virtual int PlayVideo(const uchar *, int);
//virtual int PlayTsVideo(const uchar *, int); //virtual int PlayTsVideo(const uchar *, int);
#ifdef USE_OSS // FIXME: testing only oss #ifdef USE_OSS // FIXME: testing only oss
virtual int PlayTsAudio(const uchar *, int); virtual int PlayTsAudio(const uchar *, int);
@@ -388,11 +500,13 @@ class cSoftHdDevice:public cDevice
virtual int ProvidesCa(const cChannel *) const; virtual int ProvidesCa(const cChannel *) const;
#if 0
// SPU facilities // SPU facilities
private: private:
cDvbSpuDecoder * spuDecoder; cDvbSpuDecoder * spuDecoder;
public: public:
virtual cSpuDecoder * GetSpuDecoder(void); virtual cSpuDecoder * GetSpuDecoder(void);
#endif
protected: protected:
virtual void MakePrimaryDevice(bool); virtual void MakePrimaryDevice(bool);
@@ -402,7 +516,9 @@ cSoftHdDevice::cSoftHdDevice(void)
{ {
//dsyslog("[softhddev]%s\n", __FUNCTION__); //dsyslog("[softhddev]%s\n", __FUNCTION__);
#if 0
spuDecoder = NULL; spuDecoder = NULL;
#endif
} }
cSoftHdDevice::~cSoftHdDevice(void) cSoftHdDevice::~cSoftHdDevice(void)
@@ -420,15 +536,18 @@ void cSoftHdDevice::MakePrimaryDevice(bool on)
} }
} }
int cSoftHdDevice::ProvidesCa( int cSoftHdDevice::ProvidesCa(
__attribute__ ((unused)) const cChannel * channel) const __attribute__ ((unused)) const cChannel *
{ channel) const
//dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel); {
//dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
return 0; return 0;
} }
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void) #if 0
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
{ {
dsyslog("[softhddev]%s:\n", __FUNCTION__); dsyslog("[softhddev]%s:\n", __FUNCTION__);
@@ -438,6 +557,8 @@ cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
return spuDecoder; return spuDecoder;
} }
#endif
bool cSoftHdDevice::HasDecoder(void) const bool cSoftHdDevice::HasDecoder(void) const
{ {
return true; return true;
@@ -461,7 +582,7 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
case pmVideoOnly: case pmVideoOnly:
break; break;
case pmNone: case pmNone:
break; return true;
case pmExtern_THIS_SHOULD_BE_AVOIDED: case pmExtern_THIS_SHOULD_BE_AVOIDED:
break; break;
default: default:
@@ -479,9 +600,14 @@ int64_t cSoftHdDevice::GetSTC(void)
return::VideoGetClock(); return::VideoGetClock();
} }
void cSoftHdDevice::TrickSpeed(int Speed) /**
** Set trick play speed.
**
** @param speed trick speed
*/
void cSoftHdDevice::TrickSpeed(int speed)
{ {
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, Speed); dsyslog("[softhddev]%s: %d\n", __FUNCTION__, speed);
} }
void cSoftHdDevice::Clear(void) void cSoftHdDevice::Clear(void)
@@ -500,6 +626,9 @@ void cSoftHdDevice::Play(void)
::Play(); ::Play();
} }
/**
** Puts the device into "freeze frame" mode.
*/
void cSoftHdDevice::Freeze(void) void cSoftHdDevice::Freeze(void)
{ {
dsyslog("[softhddev]%s:\n", __FUNCTION__); dsyslog("[softhddev]%s:\n", __FUNCTION__);
@@ -513,24 +642,38 @@ void cSoftHdDevice::Mute(void)
dsyslog("[softhddev]%s:\n", __FUNCTION__); dsyslog("[softhddev]%s:\n", __FUNCTION__);
cDevice::Mute(); cDevice::Mute();
::Mute(); ::Mute();
} }
void cSoftHdDevice::SetVolumeDevice(int volume) void cSoftHdDevice::SetVolumeDevice(int volume)
{ {
//dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume); dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
::SetVolumeDevice(volume); ::SetVolumeDevice(volume);
} }
void cSoftHdDevice::StillPicture( /**
__attribute__ ((unused)) const uchar * data, __attribute__ ((unused)) ** Display the given I-frame as a still picture.
int length) */
void cSoftHdDevice::StillPicture(const uchar * data, int length)
{ {
dsyslog("[softhddev]%s:\n", __FUNCTION__); dsyslog("[softhddev]%s: %s\n", __FUNCTION__,
data[0] == 0x47 ? "ts" : "pes");
if (data[0] == 0x47) { // ts sync
cDevice::StillPicture(data, length);
return;
}
::StillPicture(data, length);
} }
/**
** Check if the device is ready for further action.
**
** @param poller file handles (unused)
** @param timeout_ms timeout in ms to become ready
*/
bool cSoftHdDevice::Poll( bool cSoftHdDevice::Poll(
__attribute__ ((unused)) cPoller & poller, int timeout_ms) __attribute__ ((unused)) cPoller & poller, int timeout_ms)
{ {
@@ -539,11 +682,16 @@ bool cSoftHdDevice::Poll(
return::Poll(timeout_ms); return::Poll(timeout_ms);
} }
/**
** Flush the device output buffers.
**
** @param timeout_ms timeout in ms to become ready
*/
bool cSoftHdDevice::Flush(int timeout_ms) bool cSoftHdDevice::Flush(int timeout_ms)
{ {
dsyslog("[softhddev]%s: %d ms\n", __FUNCTION__, timeout_ms); dsyslog("[softhddev]%s: %d ms\n", __FUNCTION__, timeout_ms);
return true; return::Flush(timeout_ms);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -560,13 +708,14 @@ void cSoftHdDevice::GetOsdSize(int &width, int &height, double &pixel_aspect)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/**
** Play a audio packet.
*/
int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id) int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id)
{ {
//dsyslog("[softhddev]%s: %p %p %d %d\n", __FUNCTION__, this, data, length, id); //dsyslog("[softhddev]%s: %p %p %d %d\n", __FUNCTION__, this, data, length, id);
::PlayAudio(data, length, id); return::PlayAudio(data, length, id);
return length;
} }
void cSoftHdDevice::SetAudioTrackDevice( void cSoftHdDevice::SetAudioTrackDevice(
@@ -655,11 +804,13 @@ class cPluginSoftHdDevice:public cPlugin
virtual void Stop(void); virtual void Stop(void);
// virtual void Housekeeping(void); // virtual void Housekeeping(void);
virtual void MainThreadHook(void); virtual void MainThreadHook(void);
// virtual const char *MainMenuEntry(void); virtual const char *MainMenuEntry(void);
// virtual cOsdObject *MainMenuAction(void); virtual cOsdObject *MainMenuAction(void);
virtual cMenuSetupPage *SetupMenu(void); virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *, const char *); virtual bool SetupParse(const char *, const char *);
// virtual bool Service(const char *Id, void *Data = NULL); // virtual bool Service(const char *, void * = NULL);
virtual const char **SVDRPHelpPages(void);
virtual cString SVDRPCommand(const char *, const char *, int &);
}; };
cPluginSoftHdDevice::cPluginSoftHdDevice(void) cPluginSoftHdDevice::cPluginSoftHdDevice(void)
@@ -716,15 +867,14 @@ bool cPluginSoftHdDevice::Initialize(void)
return true; return true;
} }
/**
** Start any background activities the plugin shall perform.
*/
bool cPluginSoftHdDevice::Start(void) bool cPluginSoftHdDevice::Start(void)
{ {
const cDevice *primary;
// Start any background activities the plugin shall perform.
//dsyslog("[softhddev]%s:\n", __FUNCTION__); //dsyslog("[softhddev]%s:\n", __FUNCTION__);
primary = cDevice::PrimaryDevice(); if (!MyDevice->IsPrimaryDevice()) {
if (MyDevice != primary) {
isyslog("[softhddev] softhddevice is not the primary device!"); isyslog("[softhddev] softhddevice is not the primary device!");
if (ConfigMakePrimary) { if (ConfigMakePrimary) {
// Must be done in the main thread // Must be done in the main thread
@@ -756,14 +906,31 @@ void cPluginSoftHdDevice::Housekeeping(void)
// Perform any cleanup or other regular tasks. // Perform any cleanup or other regular tasks.
} }
#endif
/**
** Create main menu entry.
*/
const char *cPluginSoftHdDevice::MainMenuEntry(void) const char *cPluginSoftHdDevice::MainMenuEntry(void)
{ {
//dsyslog("[softhddev]%s:\n", __FUNCTION__); //dsyslog("[softhddev]%s:\n", __FUNCTION__);
return tr(MAINMENUENTRY);
return NULL; return ConfigHideMainMenuEntry ? NULL : tr(MAINMENUENTRY);
} }
#endif /**
** Perform the action when selected from the main VDR menu.
*/
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
cDevice::PrimaryDevice()->StopReplay();
Suspend();
ShutdownHandler.SetUserInactive();
return NULL;
}
/** /**
** Called for every plugin once during every cycle of VDR's main program ** Called for every plugin once during every cycle of VDR's main program
@@ -778,29 +945,15 @@ void cPluginSoftHdDevice::MainThreadHook(void)
cDevice::SetPrimaryDevice(MyDevice->DeviceNumber() + 1); cDevice::SetPrimaryDevice(MyDevice->DeviceNumber() + 1);
DoMakePrimary = 0; DoMakePrimary = 0;
} }
// check if user is inactive, automatic enter suspend mode
if (ShutdownHandler.IsUserInactive()) {
// this is regular called, but guarded against double calls
Suspend();
}
::MainThreadHook(); ::MainThreadHook();
} }
#if 0
bool cPluginSoftHdDevice::Service(const char *Id, void *Data)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
return false;
}
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
{
// Perform the action when selected from the main VDR menu.
dsyslog("[softhddev]%s:\n", __FUNCTION__);
return NULL;
}
#endif
/** /**
** Return our setup menu. ** Return our setup menu.
*/ */
@@ -816,33 +969,51 @@ cMenuSetupPage *cPluginSoftHdDevice::SetupMenu(void)
*/ */
bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value) bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
{ {
int i;
char buf[128];
//dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value); //dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
// FIXME: handle the values
if (!strcmp(name, "MakePrimary")) { if (!strcmp(name, "MakePrimary")) {
ConfigMakePrimary = atoi(value); ConfigMakePrimary = atoi(value);
return true; return true;
} }
if (!strcmp(name, "Deinterlace")) { if (!strcmp(name, "HideMainMenuEntry")) {
VideoSetDeinterlace(ConfigVideoDeinterlace = atoi(value)); ConfigHideMainMenuEntry = atoi(value);
return true; return true;
} }
if (!strcmp(name, "SkipChromaDeinterlace")) { for (i = 0; i < RESOLUTIONS; ++i) {
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace = snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
atoi(value)); if (!strcmp(name, buf)) {
return true; ConfigVideoScaling[i] = atoi(value);
} VideoSetScaling(ConfigVideoScaling);
if (!strcmp(name, "Denoise")) { return true;
VideoSetDenoise(ConfigVideoDenoise = atoi(value)); }
return true; snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Deinterlace");
} if (!strcmp(name, buf)) {
if (!strcmp(name, "Sharpen")) { ConfigVideoDeinterlace[i] = atoi(value);
VideoSetSharpen(ConfigVideoSharpen = atoi(value)); VideoSetDeinterlace(ConfigVideoDeinterlace);
return true; return true;
} }
if (!strcmp(name, "Scaling")) { snprintf(buf, sizeof(buf), "%s.%s", Resolution[i],
VideoSetScaling(ConfigVideoScaling = atoi(value)); "SkipChromaDeinterlace");
return true; if (!strcmp(name, buf)) {
ConfigVideoSkipChromaDeinterlace[i] = atoi(value);
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise");
if (!strcmp(name, buf)) {
ConfigVideoDenoise[i] = atoi(value);
VideoSetDenoise(ConfigVideoDenoise);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Sharpen");
if (!strcmp(name, buf)) {
ConfigVideoSharpen[i] = atoi(value);
VideoSetSharpen(ConfigVideoSharpen);
return true;
}
} }
if (!strcmp(name, "AudioDelay")) { if (!strcmp(name, "AudioDelay")) {
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value)); VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
@@ -856,4 +1027,51 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return false; return false;
} }
#if 0
bool cPluginSoftHdDevice::Service(const char *Id, void *Data)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
return false;
}
#endif
//----------------------------------------------------------------------------
// cPlugin SVDRP
//----------------------------------------------------------------------------
/**
** Return SVDRP commands help pages.
**
** return a pointer to a list of help strings for all of the plugin's
** SVDRP commands.
*/
const char **cPluginSoftHdDevice::SVDRPHelpPages(void)
{
// FIXME: translation?
static const char *text[] = {
"SUSP\n",
" Suspend plugin",
NULL
};
return text;
}
/**
** Handle SVDRP commands.
*/
cString cPluginSoftHdDevice::SVDRPCommand(const char *command,
__attribute__ ((unused)) const char *option,
__attribute__ ((unused)) int &reply_code)
{
if (!strcasecmp(command, "SUSP")) {
Suspend();
return "SoftHdDevice is suspended";
}
return NULL;
}
VDRPLUGINCREATOR(cPluginSoftHdDevice); // Don't touch this! VDRPLUGINCREATOR(cPluginSoftHdDevice); // Don't touch this!

View File

@@ -0,0 +1,71 @@
# 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"
DEPEND=">=x11-libs/libxcb-1.7
x11-libs/xcb-util
x11-libs/xcb-util-wm
x11-libs/xcb-util-wm
x11-libs/xcb-util-keysyms
x11-libs/xcb-util-renderutil
x11-libs/libX11
>=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 )
"
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
}

1241
video.c

File diff suppressed because it is too large Load Diff

75
video.h
View File

@@ -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
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -47,14 +40,14 @@ extern VideoHwDecoder *VideoNewHwDecoder(void);
/// 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,57 +55,63 @@ 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 skip chroma deinterlace /// Set video mode.
extern void VideoSetSkipChromaDeinterlace(int); extern void VideoSetVideoMode(int, int, int, int);
/// set scaling /// Set video fullscreen mode.
extern void VideoSetScaling(int); extern void VideoSetFullscreen(int);
/// set denoise /// Set deinterlace.
extern void VideoSetDenoise(int); extern void VideoSetDeinterlace(int[]);
/// set sharpen /// Set skip chroma deinterlace.
extern void VideoSetSharpen(int); extern void VideoSetSkipChromaDeinterlace(int[]);
/// set audio delay /// 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 /// 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 extern int64_t VideoGetClock(void); ///< Get video clock.
extern void VideoOsdInit(void); ///< setup osd extern void VideoOsdInit(void); ///< Setup osd.
extern void VideoOsdExit(void); ///< cleanup osd extern void VideoOsdExit(void); ///< Cleanup osd.
extern void VideoInit(const char *); ///< setup video module extern void VideoInit(const char *); ///< Setup video module.
extern void VideoExit(void); ///< cleanup and exit video module extern void VideoExit(void); ///< Cleanup and exit video module.
extern void VideoFlushInput(void); ///< flush codec input buffers extern void VideoFlushInput(void); ///< Flush video input buffers.
extern int VideoDecode(void); ///< decode extern int VideoDecode(void); ///< Decode video input buffers.
/// @} /// @}