79 Commits
0.4.0 ... 0.4.8

Author SHA1 Message Date
Johns
a7f0cf6d6f Version 0.4.8 released. 2012-02-16 09:59:40 +01:00
Johns
346953d209 Fix message, if no hq scaling is supported. 2012-02-16 09:58:13 +01:00
Johns
97af9c6de2 Fix bug: wrong start of video packet. 2012-02-15 22:19:50 +01:00
Johns
8dd95dab5e VDPAU: Enable inverse telecine configuration. 2012-02-14 22:29:17 +01:00
Johns
6775173e4f Fix bug: local id variable overwrites argument. 2012-02-14 21:51:13 +01:00
Johns
9170fcf485 Removed stupid gcc warnings. 2012-02-14 21:48:42 +01:00
Johns
919428cb80 Find AC3 (Dolby Digital) inside PES packet. 2012-02-14 21:18:24 +01:00
Johns
4331692ee5 Fix bug: audio increments invalid audio PTS. 2012-02-14 16:03:08 +01:00
Johns
5aa826bdb0 Fix bug: dvd plugin not working. 2012-02-14 15:12:48 +01:00
Johns
6736db082e Fix bug: used frame-> instead of video_ctx->. 2012-02-14 14:46:49 +01:00
Johns
807b4df381 Release Version 0.4.7. 2012-02-13 23:21:11 +01:00
56edfd4f54 Fix bug: unscaled jpeg includes PNG header. 2012-02-13 20:15:25 +01:00
Johns
0a1a258d2a Update dependencies and install README. 2012-02-13 14:58:26 +01:00
Johns
09a0880d07 Update readme for new featurs. 2012-02-13 14:25:38 +01:00
Johns
a98a4adc7e Studio levels could be configured in setup menu. 2012-02-13 14:13:24 +01:00
Johns
f872f54e2a Window defaults to fullscreen without geometry. 2012-02-13 14:00:53 +01:00
33c638d538 Jpeg screengrab use VDR RgbToJpeg function. 2012-02-12 20:30:50 +01:00
Johns
0a2a221fa9 Add play/pause audio support. 2012-02-12 20:14:43 +01:00
Johns
24a065e5de Fix bug: audible glitch toggling AC-3 pass-through 2012-02-12 17:50:10 +01:00
Johns
6df970ca9e Fix bug: mpeg stills not displayed. 2012-02-12 16:57:32 +01:00
Johns
616cd9e133 Forgot to reenable FindAudioSync. 2012-02-11 18:29:20 +01:00
Johns
a91533f6d1 Detect audio stream type only after stream switch. 2012-02-11 18:22:48 +01:00
Johns
baa4500a2c Detect more h264 streams with leading zeros. 2012-02-11 17:18:44 +01:00
Johns
f28a737a9a VDPAU: support for studio levels added. 2012-02-10 15:47:52 +01:00
Johns
19cec561ba Fix bug #876: Keypad not working. 2012-02-10 10:43:31 +01:00
Johns
d8f63adaad Software deinterlacer (config/skip chroma deint):
Add support for skip chroma deinterlace to software deinterlacer.
Type of software deinterlacer now configurable from setup menu.
2012-02-09 21:22:42 +01:00
Johns
8c16466d31 Set mixer channel through command line option 2012-02-09 16:01:36 +01:00
Johns
ced54a5cf1 Fix bug: LFE moved to wrong position. 2012-02-09 00:46:02 +01:00
Johns
08246b5ac3 Guard suspend/resume against multiple calls. 2012-02-08 23:26:49 +01:00
Johns
c3a1de8c7b jpeg_mem_dest only supported by jpeg 8.0. 2012-02-08 22:32:47 +01:00
Johns
918170d00b Add support for AAC LATM audio streams. 2012-02-08 15:19:18 +01:00
Johns
bc50f37c4d Spatial deinterlacer for VA-API. 2012-02-07 18:18:13 +01:00
Johns
09cf1f5c85 Fix bug: alsa+ffmpeg use different channel layout. 2012-02-07 17:08:59 +01:00
Johns
947f6b312e Support more LPCM sample rates and channels. 2012-02-06 23:54:22 +01:00
Johns
99728258f1 Quick&dirty support for mpeg LPCM streams. 2012-02-06 22:58:42 +01:00
Johns
c972f8c4dd Workaround for text2skin undrawn OSD areas. 2012-02-06 20:54:20 +01:00
Johns
7d38dff5bf Detect dvb LPCM stream and ignore it. 2012-02-05 14:17:46 +01:00
Johns
8db8b68edd Makes Workarounds command line configurable. 2012-02-04 16:38:10 +01:00
Johns
00cafd18ed Release Version 0.4.6. 2012-02-02 23:32:51 +01:00
Johns
ab4e89132e Auto-crop improvement and nicer a-v sync display. 2012-02-02 16:01:38 +01:00
Johns
3585f1df19 Increase audio buffer, if bigger audio delay used. 2012-02-02 16:01:08 +01:00
Johns
e258c35537 Makes SkipLines configure in setup menu. 2012-02-02 16:00:26 +01:00
Johns
91dbe46786 Add A-V info output and compile time option. 2012-02-01 23:12:45 +01:00
Johns
a7389111ff Fix bug: VA-API intel software decoder broken. 2012-02-01 18:36:24 +01:00
Johns
27e9a88e2f Video updates and bug fix.
Check if surface is ready in VaapiGetSurface.
Set PTS/DTS only in the first split video packet.
Add support for 4:3 output modes.
Quicker auto-crop after channel switch.
Add auto-crop support for Intel VA-API backend.
Fix bug: Auto-Crop logo skip didn't use displayed width.
2012-02-01 16:50:48 +01:00
Johns
33e9c71aea Removed debug printf. 2012-01-31 20:48:47 +01:00
Johns
bd84e3f3b9 Workaround for mpeg2 FFMpeg+VA-API+Intel GPU hung. 2012-01-31 20:45:09 +01:00
Johns
364cc04736 Fix bug: Only black picture with VA-API hw decoder. 2012-01-30 23:09:53 +01:00
ec4a899bb8 Add support to start the plugin in suspended mode. 2012-01-30 17:03:15 +01:00
Johns
dab31e2367 Finished rewrite of video code, to support modules. 2012-01-30 15:58:21 +01:00
Johns
e613ff1f7e Add aspect change support to software decoder path 2012-01-29 23:57:22 +01:00
Johns
1886b745e5 Repair software decoder with vaapi vdpau backend. 2012-01-29 19:28:46 +01:00
Johns
422c378a5e Add workaround for Intel VA-API MPEG GPU hung. 2012-01-29 11:28:10 +01:00
Johns
eed708b9ea Release version 0.4.5. 2012-01-28 13:44:50 +01:00
Johns
60a7c36fa6 Add configurable skip lines at video top + bottom. 2012-01-28 01:44:50 +01:00
Johns
4d74ed1bfc Add auto-crop tolerance configuration. 2012-01-27 23:49:05 +01:00
Johns
c3b924a239 Reduces audio latency, increases audio buffer time. 2012-01-27 23:33:10 +01:00
Johns
f8d198636b Video bug fix.
Made video_test working again.
Disabled VA-API Intel vaAssociateSubpicture workaround.
Fix bug: Must release lock for VideoPollEvent.
Allow faster video and audio sync.
Fix bug: Software decoder use vaPutImage with Intel backend.
Fix bug: Artefacts are shown after mpeg2 channel switch.
Fix bug: VideoReleaseSurface called after VideoExit.
2012-01-27 21:08:37 +01:00
Johns
bcf6ecabc1 Support external players. 2012-01-26 15:00:49 +01:00
Johns
9063b4e3ff Add VDPAU display preemption support. 2012-01-25 15:31:49 +01:00
Johns
e3681812bd Remove pass-through test code. 2012-01-25 15:31:18 +01:00
Johns
9d14522121 Add jpeg support to ebuild. 2012-01-25 15:30:22 +01:00
2dff69dc14 Add support for grab jpeg image. 2012-01-24 22:40:06 +01:00
Johns
5668fa22d2 Video cleanup.
More functions uses new module interface.
Fix bug: VaapiOsdExit doesn't deassociate osd surface.
Fix bug: First OSD can show random pixels.
2012-01-24 22:25:33 +01:00
Johns
c7cebe1aeb Wait for X11 exit and kill it, if not. 2012-01-24 22:20:17 +01:00
Johns
037f582bad Fix still picture handling. 2012-01-24 16:37:11 +01:00
Johns
6ca4d3c44f Fix dead-lock in VdpauExit. 2012-01-24 10:02:39 +01:00
Johns
2ac2eb39c6 Workaround for dead-lock in VdpauExit. 2012-01-24 00:32:07 +01:00
Johns
217545542d Add ac3 pass-through device to OSS module. 2012-01-23 20:23:05 +01:00
Johns
5f43803236 VDPAU: Add primitive software scaler to grab image 2012-01-23 20:04:15 +01:00
Johns
993d831190 VA-API: Add auto-crop support. 2012-01-23 15:40:59 +01:00
Johns
1969b2a0a7 Fix bug: close codec missing. 2012-01-22 22:46:52 +01:00
Johns
0fad02285d AC3 device should be called 'ALSA_AC3_DEVICE'. 2012-01-22 20:53:27 +01:00
Johns
9546233175 Suspend can close and open video and audio device. 2012-01-22 20:49:43 +01:00
Johns
98d2e0f728 Cleanups and Codec..Del.. prototypes. 2012-01-22 17:07:08 +01:00
970493fb23 Use different alsa device for AC3/pass-through. 2012-01-22 16:54:22 +01:00
Johns
329dbc5f07 Add dummy player and control for suspend mode. 2012-01-22 11:12:57 +01:00
Johns
bc8a13e1ef Call VdpauMixerSetup only, if mixer setup. 2012-01-21 21:56:19 +01:00
Johns
bd7e6143c7 Buffertime compile time configurable in ms. 2012-01-21 21:46:47 +01:00
15 changed files with 4024 additions and 1380 deletions

130
ChangeLog
View File

@@ -1,4 +1,134 @@
User johns
Date: Thu Feb 16 09:59:14 CET 2012
Release Version 0.4.8
Fix bug: wrong start of video packet.
VDPAU: Enables inverse telecine configuration.
Find AC3 (Dolby Digital) inside PES packet.
Fix bug: audio increments invalid audio PTS.
Fix bug: dvd plugin not working.
Fix bug: used frame-> instead of video_ctx-> for old libav/ffmpeg.
User johns
Date: Mon Feb 13 23:20:26 CET 2012
Release Version 0.4.7
User FireFly
Date: Mon Feb 13 20:14:11 CET 2012
Fix bug: unscaled jpeg includes PNG header.
User johns
Date: Mon Feb 13 14:58:26 CET 2012
VDPAU: Studio levels could be configured in the setup menu.
Window size defaults to fullscreen, if no geometry is given.
User m.Rcu
Date: Sun Feb 12 20:28:22 CET 2012
Jpeg screengrab use VDR RgbToJpeg function.
User johns
Date: Sun Feb 12 20:14:43 CET 2012
Add play/pause audio support.
Fix bug: audible glitch when switching AC-3 pass-through <-> none.
Fix bug: mpeg stills not displayed.
Detect audio stream type only after stream switch.
Detect more h264 streams with leading zeros.
VDPAU: support for studio levels added.
Add support for skip chroma deinterlace to software deinterlacer.
Type of software deinterlacer now configurable from setup menu.
Mixer channel could be set through command line option.
Fix bug: LFE moved to wrong position.
Guard suspend/resume against multiple calls.
Add support for AAC LATM audio streams.
Fix bug: alsa and ffmpeg use different channel layout.
Support more LPCM sample rates and number of channels.
Quick&dirty support for mpeg LPCM streams.
Workaround for text2skin undrawn OSD areas.
Detect dvb LPCM stream and ignore it.
User johns
Date: Thu Feb 2 23:29:35 CET 2012
Release Version 0.4.6
Warn only on the first duplicated frame in sequence.
Increase audio buffer, if bigger audio delay is used.
Makes SkipLines configure in setup menu.
Auto-crop only enabled with normal 4:3 display mode.
Vaapi updates OSD when cropping changes.
Add A-V info output and compile time option.
Fix bug: VA-API intel software decoder broken by aspect commit.
Add support for 4:3 output modes.
Quicker auto-crop after channel switch.
Add auto-crop support for Intel VA-API backend.
Fix bug: Auto-Crop logo skip didn't use displayed width.
Workaround for mpeg2 FFMpeg + VA-API + Intel GPU hung.
Fix bug: Missing vaSyncSurface and vaDestroyImage.
Fix bug: Only black picture with VA-API hw decoder.
User HelAu
Date: Mon Jan 30 16:54:47 CET 2012
Add support to start the plugin in suspended mode.
User johns
Date: Mon Jan 30 15:58:21 CET 2012
Finished rewrite of video code, to support output modules.
Add aspect change support to software decoder path.
Repair software decoder with vaapi vdpau backend.
Add workaround for Intel VA-API MPEG GPU hung.
User johns
Date: Sat Jan 28 13:32:12 CET 2012
Release Version 0.4.5
Add configurable skip lines at video top and bottom.
Add auto-crop tolerance configuration.
Reduces audio latency, increases audio buffer time.
Made video_test working again.
Disabled VA-API Intel vaAssociateSubpicture workaround.
Fix bug: Must release lock for VideoPollEvent.
Allow faster video and audio sync.
Fix bug: Software decoder use vaPutImage with intel backend.
Fix bug: Artefacts are shown after mpeg2 channel switch.
Fix bug: VideoReleaseSurface called after VideoExit.
Support external players.
Add VDPAU display preemption support.
User m.Rcu
Date: Tue Jan 24 22:38:30 CET 2012
Add support for grab jpeg image.
User johns
Date: Tue Jan 24 22:25:33 CET 2012
Fix bug: VaapiOsdExit doesn't deassociate osd surface.
Fix bug: First OSD can show random pixels.
Wait for X11 exit and kill it, if not.
Fix still picture handling.
Fix for dead-lock in VdpauExit.
Workaround for dead-lock in VdpauExit.
VDPAU: Add very primitive software scaler for grab image.
VA-API: Add auto-crop support.
Suspend can close/open X11 window, connection and audio device.
User Morone
Date: Sun Jan 22 16:43:23 CET 2012
Use different alsa devices for AC3/pass-through and pcm.
User johns
Date: Sun Jan 22 11:12:57 CET 2012
Add dummy player and control for suspend mode.
Buffertime compile time configurable in ms.
Date: Sat Jan 21 15:49:16 CET 2012
Release Version 0.4.0

View File

@@ -19,6 +19,7 @@ GIT_REV = $(shell git describe --always 2>/dev/null)
### Configuration (edit this for your needs)
CONFIG := #-DDEBUG
CONFIG += -DAV_INFO
#CONFIG += -DHAVE_PTHREAD_NAME
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
@@ -27,10 +28,11 @@ CONFIG += -DUSE_OSS
### The C++ compiler and options:
CC ?= gcc
CXX ?= g++
CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \
-Wdeclaration-after-statement
CC ?= gcc
CXX ?= g++
CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \
-Wdeclaration-after-statement \
-ftree-vectorize -msse3 -flax-vector-conversions
CXXFLAGS ?= -g -O2 -W -Wall -Wextra -Woverloaded-virtual
### The directory environment:
@@ -69,15 +71,15 @@ _CFLAGS = $(DEFINES) $(INCLUDES) \
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
`pkg-config --cflags gl glu` \
$(if $(findstring USE_VDPAU,$(CONFIG)), \
`pkg-config --cflags vdpau`) \
`pkg-config --cflags vdpau`) \
$(if $(findstring USE_VAAPI,$(CONFIG)), \
`pkg-config --cflags libva-x11 libva-glx libva`) \
`pkg-config --cflags libva-x11 libva-glx libva`) \
$(if $(findstring USE_ALSA,$(CONFIG)), \
`pkg-config --cflags alsa`)
`pkg-config --cflags alsa`)
#override _CFLAGS += -Werror
override CXXFLAGS += $(_CFLAGS)
override CFLAGS += $(_CFLAGS)
override CFLAGS += $(_CFLAGS)
LIBS += -lrt \
$(shell pkg-config --libs libavcodec libavformat) \
@@ -85,11 +87,11 @@ LIBS += -lrt \
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
`pkg-config --libs gl glu` \
$(if $(findstring USE_VDPAU,$(CONFIG)), \
`pkg-config --libs vdpau`) \
`pkg-config --libs vdpau`) \
$(if $(findstring USE_VAAPI,$(CONFIG)), \
`pkg-config --libs libva-x11 libva-glx libva`) \
`pkg-config --libs libva-x11 libva-glx libva`) \
$(if $(findstring USE_ALSA,$(CONFIG)), \
`pkg-config --libs alsa`)
`pkg-config --libs alsa`)
### The object files (add further files here):
@@ -118,11 +120,11 @@ $(OBJS): Makefile
### Internationalization (I18N):
PODIR = po
PODIR = po
LOCALEDIR = $(VDRDIR)/locale
I18Npo = $(wildcard $(PODIR)/*.po)
I18Npo = $(wildcard $(PODIR)/*.po)
I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
I18Npot = $(PODIR)/$(PLUGIN).pot
I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
msgfmt -c -o $@ $<
@@ -171,6 +173,6 @@ indent:
indent $$i; unexpand -a $$i > $$i.up; mv $$i.up $$i; \
done
video_test: video.c
video_test: video.c Makefile
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $< $(LIBS) \
-o $@

View File

@@ -76,16 +76,28 @@ Setup: environment
DISPLAY=:0.0
x11 display name
NO_HW=1
if set don't use the hardware decoders
NO_MPEG_HW=1
if set don't use the hardware decoder for mpeg1/2
STUDIO_LEVELS=1
if set use studio levels with vdpau (deprecated use setup)
only if alsa is configured
ALSA_DEVICE=default
alsa PCM device name
ALSA_AC3_DEVICE=
alsa AC3/pass-though device name
ALSA_MIXER=default
alsa control device name
ALSA_MIXER_CHANNEL=PCM
alsa control channel name
only if oss is configured
OSS_AUDIODEV=/dev/dsp
oss dsp device name
OSS_AC3_AUDIODEV=
oss AC3/pass-though device name
OSS_MIXERDEV=/dev/mixer
oss mixer device name
OSS_MIXER_CHANNEL=pcm
@@ -101,7 +113,7 @@ Setup: /etc/vdr/setup.conf
softhddevice.HideMainMenuEntry = 0
0 = show softhddevice main menu entry, 1 = hide entry
<res> of the next parameters is 567i, 720p, 1080i_fake or 1080i.
<res> of the next parameters is 576i, 720p, 1080i_fake or 1080i.
1080i_fake is 1280x1080 or 1440x1080
1080i is "real" 1920x1080
@@ -115,6 +127,9 @@ Setup: /etc/vdr/setup.conf
softhddevice.<res>.SkipChromaDeinterlace = 0
0 = disabled, 1 = enabled (for slower cards, poor qualit<69>t)
softhddevice.<res>.InverseTelecine = 0
0 = disabled, 1 = enabled
softhddevice.<res>.Denoise = 0
0 .. 1000 noise reduction level (0 off, 1000 max)
@@ -128,14 +143,39 @@ Setup: /etc/vdr/setup.conf
softhddevice.AudioPassthrough = 0
0 = none, 1 = AC-3
for AC-3 the pass-through device is used.
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
if auto-crop is over 'n' intervals the same, the cropping is
used.
softhddevice.AutoCrop.Tolerance = 0
if detected crop area is too small, cut max 'n' pixels at top and
bottom.
softhddevice.SkipLines = 0
skip 'n' lines at top and bottom of the video picture.
softhddevice.StudioLevels = 0
0 use PC levels (0-255) with vdpau.
1 use studio levels (16-235) with vdpau.
softhddevice.Suspend.Close = 0
1 suspend closes x11 window, connection and audio device.
(use svdrpsend plug softhddevice RESU to resume, if you have no lirc)
softhddevice.Suspend.X11 = 0
1 suspend stops X11 server (not working yet)
VideoDisplayFormat = ?
0 pan and scan
1 letter box
2 center cut-out
Setup: /etc/vdr/remote.conf
------
@@ -155,7 +195,7 @@ Setup: /etc/vdr/remote.conf
Commandline:
------------
Use vdr -h to see the command line arguments support by the plugin.
Use vdr -h to see the command line arguments supported by the plugin.
-a audio_device
@@ -166,6 +206,12 @@ Commandline:
other to use alsa audio module (if compiled with alsa
support)
SVDRP:
------
Use 'svdrpsend.pl plug softhddevice HELP' to see the SVDRP commands
help and which are supported by the plugin.
Running:
--------

52
Todo
View File

@@ -21,53 +21,68 @@ $Id: $
missing:
software deinterlace (yadif, ...)
software decoder with software deinterlace
zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
suspend output / energie saver: stop audio, stop video, configurable
suspend output / energie saver: stop and restart X11
suspend plugin didn't restore full-screen (is this wanted?)
Option deinterlace off / deinterlace force!
Make output drivers better modular (under construction).
ColorSpace aren't configurable with the gui.
Inverse telecine isn't configurable with the gui.
crash:
AudioPlayHandlerThread -> pthread_cond_wait
video:
subtitle not cleared
subtitle could be asyncron
reduce warnings after channel switch
grab image with hardware and better scaling support
hard channel switch
OSD can only be shown after some stream could be shown
yaepghd changed position is lost on channel switch
pause (live tv) has sometime problems with SAT1 HD Pro7 HD
vdpau:
VdpPreemptionCallback handling (under construction)
hard channel switch
suspendoutput didn't show logo or black picture.
software decoder path not working
libva:
hard channel switch
yaepghd (VaapiSetOutputPosition) support
can associate ony displayed part of osd
auto crop for va-api
can associate only displayed part of osd
grab image for va-api
remove stderr output of libva init
still many: (workaround export NO_MPEG_HW=1)
[drm:i915_hangcheck_elapsed] *ERROR* Hangcheck timer elapsed... GPU hung
[drm:i915_wait_request] *ERROR* i915_wait_request returns -11 ...
libva: branch vaapi-ext
add support for vaapi-ext
libva-intel-driver:
intel still has hangups most with 1080i
1080i does no v-sync (workaround written, fixed with vaapi-ext)
deinterlace only supported with vaapi-ext
1080i does no v-sync (sometimes correct working with vaapi-ext)
OSD has sometimes wrong size (workaround written)
sometimes software decoder deinterlace isn't working and 1080i channels
show artefacts
libva-vdpau-driver:
G210/GT520 OSD update too slow (needs hardware problem workaround)
hangup on exit (VaapiDelDecoder -> VaapiCleanup
-> vaDestroyContext -> pthread_rwlock_wrlock)
OSD still has some problems with auto-crop and 4:3 zoom.
libva-xvba-driver:
x11:
disable screensaver
skip multiple configure-notify, handle only the last one.
support embedded mode
audio:
write TS -> PES parser, which feeds audio before the next start packet
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.
software volume support (could be done with asound.conf)
Mute should do a real mute and not only set volume to zero.
Starting suspended and muted, didn't register the mute.
audio/alsa:
better downmix of >2 channels on 2 channel hardware
@@ -77,13 +92,11 @@ audio/alsa:
audio/oss:
alsa oss emulation mixer "pcm" not working
oss4 mixer channel not working
ring buffer overflow with alsa oss emulation
HDMI/SPDIF Passthrough:
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
pause is not reset, when replay exit
@@ -98,8 +111,7 @@ setup:
Can a notice be added to the setup menu?
unsorted:
Menu -> Setup -> Plugins -> skingenigmang -> General
-> Try 8bpp single area: no, has missing parts.
stoping vdr while plugin is suspended opens and closes a window.
future features (not planed for 1.0 - 1.5)
@@ -110,6 +122,6 @@ future features (not planed for 1.0 - 1.5)
atmolight support
multistream handling
pip support
grab image with jpeg
save and use auto-crop with channel zapping
upmix stereo to AC-3
upmix stereo to AC-3 (supported by alsa plugin)

335
audio.c
View File

@@ -112,7 +112,9 @@ typedef struct _audio_module_
int (*FreeBytes) (void); ///< number of bytes free in buffer
uint64_t(*GetDelay) (void); ///< get current audio delay
void (*SetVolume) (int); ///< set output volume
int (*Setup) (int *, int *); ///< setup channels, samplerate
int (*Setup) (int *, int *, int); ///< setup channels, samplerate
void (*Play) (void); ///< play
void (*Pause) (void); ///< pause
void (*Init) (void); ///< initialize audio output module
void (*Exit) (void); ///< cleanup audio output module
} AudioModule;
@@ -123,19 +125,23 @@ static const AudioModule NoopModule; ///< forward definition of noop module
// Variables
//----------------------------------------------------------------------------
char AudioAlsaDriverBroken; ///< disable broken driver message
static const char *AudioModuleName; ///< which audio module to use
/// Selected audio module.
static const AudioModule *AudioUsedModule = &NoopModule;
static const char *AudioPCMDevice; ///< alsa/OSS PCM device name
static const char *AudioAC3Device; ///< alsa/OSS AC3 device name
static const char *AudioMixerDevice; ///< alsa/OSS mixer device name
static const char *AudioMixerChannel; ///< alsa/OSS mixer channel name
static volatile char AudioRunning; ///< thread running / stopped
static int AudioPaused; ///< audio paused
static volatile char AudioPaused; ///< audio paused
static unsigned AudioSampleRate; ///< audio sample rate in hz
static unsigned AudioChannels; ///< number of audio channels
static const int AudioBytesProSample = 2; ///< number of bytes per sample
static int64_t AudioPTS; ///< audio pts clock
static const int AudioBufferTime = 350; ///< audio buffer time in ms
#ifdef USE_AUDIO_THREAD
static pthread_t AudioThread; ///< audio play thread
@@ -145,6 +151,8 @@ static pthread_cond_t AudioStartCond; ///< condition variable
static const int AudioThread; ///< dummy audio thread
#endif
extern int VideoAudioDelay; /// import audio/video delay
#ifdef USE_AUDIORING
//----------------------------------------------------------------------------
@@ -281,10 +289,12 @@ static int AlsaAddToRingbuffer(const void *samples, int count)
// too many bytes are lost
// FIXME: should skip more, longer skip, but less often?
}
// Update audio clock
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
// Update audio clock (stupid gcc developers thinks INT64_C is unsigned)
if (AudioPTS != (int64_t) INT64_C(0x8000000000000000)) {
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
}
if (!AudioRunning) {
if (AlsaStartThreshold < RingBufferUsedBytes(AlsaRingBuffer)) {
@@ -330,7 +340,9 @@ static int AlsaPlayRingbuffer(void)
if (first) {
// happens with broken alsa drivers
if (AudioThread) {
Error(_("audio/alsa: broken driver %d\n"), avail);
if (!AudioAlsaDriverBroken) {
Error(_("audio/alsa: broken driver %d\n"), avail);
}
usleep(5 * 1000);
}
}
@@ -559,7 +571,6 @@ static void AlsaEnqueue(const void *samples, int count)
state = snd_pcm_state(AlsaPCMHandle);
Debug(3, "audio/alsa: state %s\n", snd_pcm_state_name(state));
Debug(3, "audio/alsa: unpaused\n");
AudioPaused = 0;
}
}
// Update audio clock
@@ -574,6 +585,8 @@ static void AlsaEnqueue(const void *samples, int count)
// direct play produces underuns on some hardware
#ifndef USE_AUDIO_THREAD
/**
** Place samples in audio output queue.
**
@@ -587,6 +600,8 @@ static void AlsaEnqueue(const void *samples, int count)
}
}
#endif
#ifdef USE_AUDIO_THREAD
//----------------------------------------------------------------------------
@@ -614,6 +629,9 @@ static void AlsaThread(void)
AlsaFlushBuffer = 0;
break;
}
if (AudioPaused) {
break;
}
// wait for space in kernel buffers
if ((err = snd_pcm_wait(AlsaPCMHandle, 100)) < 0) {
Error(_("audio/alsa: wait underrun error?\n"));
@@ -625,7 +643,7 @@ static void AlsaThread(void)
usleep(100 * 1000);
continue;
}
if (AlsaFlushBuffer) {
if (AlsaFlushBuffer || AudioPaused) {
continue;
}
if ((err = AlsaPlayRingbuffer())) { // empty / error
@@ -691,18 +709,25 @@ static void AlsaThreadFlushBuffers(void)
/**
** Open alsa pcm device.
**
** @param use_ac3 use ac3/pass-through device
*/
static snd_pcm_t *AlsaOpenPCM(void)
static snd_pcm_t *AlsaOpenPCM(int use_ac3)
{
const char *device;
snd_pcm_t *handle;
int err;
if (!(device = AudioPCMDevice)) {
if (!(device = getenv("ALSA_DEVICE"))) {
device = "default";
}
// &&|| hell
if (!(use_ac3 && ((device = AudioAC3Device)
|| (device = getenv("ALSA_AC3_DEVICE"))
|| (device = getenv("ALSA_PASSTHROUGH_DEVICE"))))
&& !(device = AudioPCMDevice) && !(device = getenv("ALSA_DEVICE"))) {
device = "default";
}
Debug(3, "audio/alsa: &&|| hell '%s'\n", device);
// open none blocking; if device is already used, we don't want wait
if ((err =
snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK)) < 0) {
@@ -729,7 +754,7 @@ static void AlsaInitPCM(void)
int err;
snd_pcm_uframes_t buffer_size;
if (!(handle = AlsaOpenPCM())) {
if (!(handle = AlsaOpenPCM(0))) {
return;
}
@@ -803,7 +828,7 @@ static void AlsaInitMixer(void)
const char *name;
name = snd_mixer_selem_get_name(alsa_mixer_elem);
if (strcasecmp(name, alsa_mixer_elem_name) == 0) {
if (!strcasecmp(name, alsa_mixer_elem_name)) {
snd_mixer_selem_get_playback_volume_range(alsa_mixer_elem,
&alsa_mixer_elem_min, &alsa_mixer_elem_max);
AlsaRatio =
@@ -873,6 +898,7 @@ static uint64_t AlsaGetDelay(void)
**
** @param freq sample frequency
** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
**
** @retval 0 everything ok
** @retval 1 didn't support frequency/channels combination
@@ -880,12 +906,13 @@ static uint64_t AlsaGetDelay(void)
**
** @todo audio changes must be queued and done when the buffer is empty
*/
static int AlsaSetup(int *freq, int *channels)
static int AlsaSetup(int *freq, int *channels, int use_ac3)
{
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size;
int err;
int ret;
int delay;
snd_pcm_t *handle;
if (!AlsaPCMHandle) { // alsa not running yet
@@ -899,7 +926,7 @@ static int AlsaSetup(int *freq, int *channels)
handle = AlsaPCMHandle;
AlsaPCMHandle = NULL;
snd_pcm_close(handle);
if (!(handle = AlsaOpenPCM())) {
if (!(handle = AlsaOpenPCM(use_ac3))) {
return -1;
}
AlsaPCMHandle = handle;
@@ -1070,9 +1097,15 @@ static int AlsaSetup(int *freq, int *channels)
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
AlsaStartThreshold = snd_pcm_frames_to_bytes(AlsaPCMHandle, period_size);
// min 333ms
if (AlsaStartThreshold < (*freq * *channels * AudioBytesProSample) / 3U) {
AlsaStartThreshold = (*freq * *channels * AudioBytesProSample) / 3U;
// buffer time/delay in ms
delay = AudioBufferTime;
if (VideoAudioDelay > -100) {
delay += 100 + VideoAudioDelay / 90;
}
if (AlsaStartThreshold <
(*freq * *channels * AudioBytesProSample * delay) / 1000U) {
AlsaStartThreshold =
(*freq * *channels * AudioBytesProSample * delay) / 1000U;
}
// no bigger, than the buffer
if (AlsaStartThreshold > RingBufferFreeBytes(AlsaRingBuffer)) {
@@ -1084,6 +1117,47 @@ static int AlsaSetup(int *freq, int *channels)
return ret;
}
/**
** Play audio.
*/
void AlsaPlay(void)
{
int err;
if (AlsaCanPause) {
if ((err = snd_pcm_pause(AlsaPCMHandle, 0))) {
Error(_("audio/alsa: snd_pcm_pause(): %s\n"), snd_strerror(err));
}
} else {
if ((err = snd_pcm_prepare(AlsaPCMHandle)) < 0) {
Error(_("audio/alsa: snd_pcm_prepare(): %s\n"), snd_strerror(err));
}
}
#ifdef DEBUG
if (snd_pcm_state(AlsaPCMHandle) == SND_PCM_STATE_PAUSED) {
Error(_("audio/alsa: still paused\n"));
}
#endif
}
/**
** Pause audio.
*/
void AlsaPause(void)
{
int err;
if (AlsaCanPause) {
if ((err = snd_pcm_pause(AlsaPCMHandle, 1))) {
Error(_("snd_pcm_pause(): %s\n"), snd_strerror(err));
}
} else {
if ((err = snd_pcm_drop(AlsaPCMHandle)) < 0) {
Error(_("snd_pcm_drop(): %s\n"), snd_strerror(err));
}
}
}
/**
** Empty log callback
*/
@@ -1131,6 +1205,7 @@ static void AlsaExit(void)
RingBufferDel(AlsaRingBuffer);
AlsaRingBuffer = NULL;
}
AlsaFlushBuffer = 0;
}
/**
@@ -1151,6 +1226,8 @@ static const AudioModule AlsaModule = {
.GetDelay = AlsaGetDelay,
.SetVolume = AlsaSetVolume,
.Setup = AlsaSetup,
.Play = AlsaPlay,
.Pause = AlsaPause,
.Init = AlsaInit,
.Exit = AlsaExit,
};
@@ -1199,10 +1276,12 @@ static int OssAddToRingbuffer(const void *samples, int count)
// too many bytes are lost
// FIXME: should skip more, longer skip, but less often?
}
// Update audio clock
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
// Update audio clock (stupid gcc developers thinks INT64_C is unsigned)
if (AudioPTS != (int64_t) INT64_C(0x8000000000000000)) {
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
}
if (!AudioRunning) {
if (OssStartThreshold < RingBufferUsedBytes(OssRingBuffer)) {
@@ -1286,6 +1365,8 @@ static void OssFlushBuffers(void)
// OSS pcm polled
//----------------------------------------------------------------------------
#ifndef USE_AUDIO_THREAD
/**
** Place samples in audio output queue.
**
@@ -1312,6 +1393,8 @@ static void OssEnqueue(const void *samples, int count)
}
}
#endif
/**
** Play all samples possible, without blocking.
*/
@@ -1356,6 +1439,9 @@ static void OssThread(void)
OssFlushBuffer = 0;
break;
}
if (AudioPaused) {
break;
}
fds[0].fd = OssPcmFildes;
fds[0].events = POLLOUT | POLLERR;
@@ -1367,7 +1453,7 @@ static void OssThread(void)
continue;
}
if (OssFlushBuffer) {
if (OssFlushBuffer || AudioPaused) {
continue;
}
@@ -1420,6 +1506,32 @@ static void OssThreadFlushBuffers(void)
//----------------------------------------------------------------------------
/**
** Open OSS pcm device.
**
** @param use_ac3 use ac3/pass-through device
*/
static int OssOpenPCM(int use_ac3)
{
const char *device;
int fildes;
// &&|| hell
if (!(use_ac3 && ((device = AudioAC3Device)
|| (device = getenv("OSS_AC3_AUDIODEV"))))
&& !(device = AudioPCMDevice) && !(device = getenv("OSS_AUDIODEV"))) {
device = "/dev/dsp";
}
Debug(3, "audio/oss: &&|| hell '%s'\n", device);
if ((fildes = open(device, O_WRONLY)) < 0) {
Error(_("audio/oss: can't open dsp device '%s': %s\n"), device,
strerror(errno));
return -1;
}
return fildes;
}
/**
** Initialize OSS pcm device.
**
@@ -1427,19 +1539,9 @@ static void OssThreadFlushBuffers(void)
*/
static void OssInitPCM(void)
{
const char *device;
int fildes;
if (!(device = AudioPCMDevice)) {
if (!(device = getenv("OSS_AUDIODEV"))) {
device = "/dev/dsp";
}
}
if ((fildes = open(device, O_WRONLY)) < 0) {
Error(_("audio/oss: can't open dsp device '%s': %s\n"), device,
strerror(errno));
return;
}
fildes = OssOpenPCM(0);
OssPcmFildes = fildes;
}
@@ -1572,6 +1674,7 @@ static uint64_t OssGetDelay(void)
**
** @param freq sample frequency
** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
**
** @retval 0 everything ok
** @retval 1 didn't support frequency/channels combination
@@ -1579,10 +1682,11 @@ static uint64_t OssGetDelay(void)
**
** @todo audio changes must be queued and done when the buffer is empty
*/
static int OssSetup(int *freq, int *channels)
static int OssSetup(int *freq, int *channels, int use_ac3)
{
int ret;
int tmp;
int delay;
if (OssPcmFildes == -1) { // OSS not ready
return -1;
@@ -1590,6 +1694,18 @@ static int OssSetup(int *freq, int *channels)
// flush any buffered data
AudioFlushBuffers();
if (1) { // close+open for pcm / ac3
int fildes;
fildes = OssPcmFildes;
OssPcmFildes = -1;
close(fildes);
if (!(fildes = OssOpenPCM(use_ac3))) {
return -1;
}
OssPcmFildes = fildes;
}
ret = 0;
tmp = AFMT_S16_NE; // native 16 bits
@@ -1656,9 +1772,15 @@ static int OssSetup(int *freq, int *channels)
}
// start when enough bytes for initial write
OssStartThreshold = bi.bytes + tmp;
// min 333ms
if (OssStartThreshold < (*freq * *channels * AudioBytesProSample) / 3U) {
OssStartThreshold = (*freq * *channels * AudioBytesProSample) / 3U;
// buffer time/delay in ms
delay = AudioBufferTime;
if (VideoAudioDelay > -100) {
delay += 100 + VideoAudioDelay / 90;
}
if (OssStartThreshold <
(*freq * *channels * AudioBytesProSample * delay) / 1000U) {
OssStartThreshold =
(*freq * *channels * AudioBytesProSample * delay) / 1000U;
}
// no bigger, than the buffer
if (OssStartThreshold > RingBufferFreeBytes(OssRingBuffer)) {
@@ -1672,6 +1794,20 @@ static int OssSetup(int *freq, int *channels)
return ret;
}
/**
** Play audio.
*/
void OssPlay(void)
{
}
/**
** Pause audio.
*/
void OssPause(void)
{
}
/**
** Initialize OSS audio output module.
*/
@@ -1696,6 +1832,7 @@ static void OssExit(void)
close(OssMixerFildes);
OssMixerFildes = -1;
}
OssFlushBuffer = 0;
}
/**
@@ -1716,6 +1853,8 @@ static const AudioModule OssModule = {
.GetDelay = OssGetDelay,
.SetVolume = OssSetVolume,
.Setup = OssSetup,
.Play = OssPlay,
.Pause = OssPause,
.Init = OssInit,
.Exit = OssExit,
};
@@ -1774,7 +1913,8 @@ static void NoopSetVolume( __attribute__ ((unused))
*/
static int NoopSetup( __attribute__ ((unused))
int *channels, __attribute__ ((unused))
int *freq)
int *freq, __attribute__ ((unused))
int use_ac3)
{
return -1;
}
@@ -1798,6 +1938,8 @@ static const AudioModule NoopModule = {
.GetDelay = NoopGetDelay,
.SetVolume = NoopSetVolume,
.Setup = NoopSetup,
.Play = NoopVoid,
.Pause = NoopVoid,
.Init = NoopVoid,
.Exit = NoopVoid,
};
@@ -1851,17 +1993,6 @@ static void *AudioPlayHandlerThread(void *dummy)
}
Debug(3, "audio: thread channels %d sample-rate %d hz\n",
AudioChannels, AudioSampleRate);
if (1) {
int16_t buf[6144 / 2];
buf[0] = htole16(0xF872); // iec 61937 sync word
buf[1] = htole16(0x4E1F);
buf[2] = htole16((7 << 5) << 8 | 0x00);
buf[3] = htole16(0x0000);
memset(buf + 4, 0, 6144 - 8);
AlsaEnqueue(buf, 6144);
}
#endif
}
#endif
@@ -1903,6 +2034,7 @@ static void AudioExitThread(void)
}
pthread_cond_destroy(&AudioStartCond);
pthread_mutex_destroy(&AudioMutex);
AudioThread = 0;
}
}
@@ -1993,7 +2125,8 @@ void AudioSetClock(int64_t pts)
*/
int64_t AudioGetClock(void)
{
if ((uint64_t) AudioPTS != INT64_C(0x8000000000000000)) {
// (cast) needed for the evil gcc
if (AudioPTS != (int64_t) INT64_C(0x8000000000000000)) {
int64_t delay;
if ((delay = AudioGetDelay())) {
@@ -2010,13 +2143,7 @@ int64_t AudioGetClock(void)
*/
void AudioSetVolume(int volume)
{
#ifdef USE_ALSA
AlsaSetVolume(volume);
#endif
#ifdef USE_OSS
OssSetVolume(volume);
#endif
(void)volume;
return AudioUsedModule->SetVolume(volume);
}
/**
@@ -2024,6 +2151,7 @@ void AudioSetVolume(int volume)
**
** @param freq sample frequency
** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
**
** @retval 0 everything ok
** @retval 1 didn't support frequency/channels combination
@@ -2031,9 +2159,10 @@ void AudioSetVolume(int volume)
**
** @todo audio changes must be queued and done when the buffer is empty
*/
int AudioSetup(int *freq, int *channels)
int AudioSetup(int *freq, int *channels, int use_ac3)
{
Debug(3, "audio: channels %d frequency %d hz\n", *channels, *freq);
Debug(3, "audio: channels %d frequency %d hz %s\n", *channels, *freq,
use_ac3 ? "ac3" : "pcm");
// invalid parameter
if (!freq || !channels || !*freq || !*channels) {
@@ -2043,9 +2172,35 @@ int AudioSetup(int *freq, int *channels)
}
#ifdef USE_AUDIORING
// FIXME: need to store possible combination and report this
return AudioRingAdd(*freq, *channels);
return AudioRingAdd(*freq, *channels, use_ac3);
#endif
return AudioUsedModule->Setup(freq, channels);
return AudioUsedModule->Setup(freq, channels, use_ac3);
}
/**
** Play audio.
*/
void AudioPlay(void)
{
if (!AudioPaused) {
Warning("audio: not paused, check the code\n");
return;
}
Debug(3, "audio: resumed\n");
AudioPaused = 0;
}
/**
** Pause audio.
*/
void AudioPause(void)
{
if (AudioPaused) {
Warning("audio: already paused, check the code\n");
return;
}
Debug(3, "audio: paused\n");
AudioPaused = 1;
}
/**
@@ -2057,15 +2212,49 @@ int AudioSetup(int *freq, int *channels)
*/
void AudioSetDevice(const char *device)
{
AudioModuleName = "alsa"; // detect alsa/OSS
if (!device[0]) {
AudioModuleName = "noop";
} else if (device[0] == '/') {
AudioModuleName = "oss";
if (!AudioModuleName) {
AudioModuleName = "alsa"; // detect alsa/OSS
if (!device[0]) {
AudioModuleName = "noop";
} else if (device[0] == '/') {
AudioModuleName = "oss";
}
}
AudioPCMDevice = device;
}
/**
** Set pass-through audio device.
**
** @param device name of pass-through device (fe. "hw:0,1")
**
** @note this is currently usable with alsa only.
*/
void AudioSetDeviceAC3(const char *device)
{
if (!AudioModuleName) {
AudioModuleName = "alsa"; // detect alsa/OSS
if (!device[0]) {
AudioModuleName = "noop";
} else if (device[0] == '/') {
AudioModuleName = "oss";
}
}
AudioAC3Device = device;
}
/**
** Set pcm audio mixer channel.
**
** @param channel name of the mixer channel (fe. PCM or Master)
**
** @note this is currently used to select alsa/OSS output module.
*/
void AudioSetChannel(const char *channel)
{
AudioMixerChannel = channel;
}
/**
** Initialize audio output module.
**
@@ -2109,7 +2298,7 @@ void AudioInit(void)
AudioUsedModule->Init();
freq = 48000;
chan = 2;
if (AudioSetup(&freq, &chan)) { // set default parameters
if (AudioSetup(&freq, &chan, 0)) { // set default parameters
Error(_("audio: can't do initial setup\n"));
}
#ifdef USE_AUDIO_THREAD
@@ -2117,8 +2306,7 @@ void AudioInit(void)
AudioInitThread();
}
#endif
AudioPaused = 1;
AudioPaused = 0;
}
/**
@@ -2134,6 +2322,7 @@ void AudioExit(void)
#ifdef USE_AUDIORING
AudioRingExit();
#endif
AudioRunning = 0;
}
#ifdef AUDIO_TEST

14
audio.h
View File

@@ -37,13 +37,21 @@ extern uint64_t AudioGetDelay(void); ///< get current audio delay
extern void AudioSetClock(int64_t); ///< set audio clock base
extern int64_t AudioGetClock(); ///< get current audio clock
extern void AudioSetVolume(int); ///< set volume
extern int AudioSetup(int *, int *); ///< setup audio output
extern int AudioSetup(int *, int *, int); ///< setup audio output
//extern void AudioPlay(void); ///< play audio
//extern void AudioPause(void); ///< pause audio
extern void AudioPlay(void); ///< play audio
extern void AudioPause(void); ///< pause audio
extern void AudioSetDevice(const char *); ///< set PCM audio device
extern void AudioSetDeviceAC3(const char *); ///< set pass-through device
extern void AudioSetChannel(const char *); ///< set mixer channel
extern void AudioInit(void); ///< setup audio module
extern void AudioExit(void); ///< cleanup and exit audio module
//----------------------------------------------------------------------------
// Variables
//----------------------------------------------------------------------------
extern char AudioAlsaDriverBroken; ///< disable broken driver message
/// @}

122
codec.c
View File

@@ -320,20 +320,30 @@ static void Codec_draw_horiz_band(AVCodecContext * video_ctx,
**
** @param hw_decoder video hardware decoder
**
** @returns private decoder pointer for audio/video decoder.
** @returns private decoder pointer for video decoder.
*/
VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder * hw_decoder)
{
VideoDecoder *decoder;
if (!(decoder = calloc(1, sizeof(*decoder)))) {
Fatal(_("codec: Can't allocate vodeo decoder\n"));
Fatal(_("codec: can't allocate vodeo decoder\n"));
}
decoder->HwDecoder = hw_decoder;
return decoder;
}
/**
** Deallocate a video decoder context.
**
** @param decoder private video decoder
*/
void CodecVideoDelDecoder(VideoDecoder * decoder)
{
free(decoder);
}
/**
** Open video decoder.
**
@@ -347,6 +357,9 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id)
Debug(3, "codec: using codec %s or ID %#04x\n", name, codec_id);
if (decoder->VideoCtx) {
Error(_("codec: missing close\n"));
}
//
// ffmpeg compatibility hack
//
@@ -548,13 +561,13 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
video_ctx->frame_number, used);
}
if (used != pkt->size) {
if (used >= 0) {
if (used >= 0 && used < pkt->size) {
// some tv channels, produce this
Debug(4,
"codec: ooops didn't use complete video packet used %d of %d\n",
used, pkt->size);
pkt->data += used;
pkt->size -= used;
pkt->data += used;
goto next_part;
}
Debug(3, "codec: bad frame %d\n", used);
@@ -592,6 +605,7 @@ struct _audio_decoder_
/// audio parser to support insane dvb streaks
AVCodecParserContext *AudioParser;
int PassthroughAC3; ///< current ac-3 pass-through
int SampleRate; ///< current stream sample rate
int Channels; ///< current stream channels
@@ -608,26 +622,37 @@ static char CodecPassthroughAC3; ///< pass ac3 through
//static char CodecPassthroughDTS; ///< pass dts through (unsupported)
//static char CodecPassthroughMPA; ///< pass mpa through (unsupported)
#else
static const int CodecPassthroughAC3 = 0;
#endif
/**
** Allocate a new audio decoder context.
**
** @param hw_decoder video hardware decoder
**
** @returns private decoder pointer for audio/video decoder.
** @returns private decoder pointer for audio decoder.
*/
AudioDecoder *CodecAudioNewDecoder(void)
{
AudioDecoder *audio_decoder;
if (!(audio_decoder = calloc(1, sizeof(*audio_decoder)))) {
Fatal(_("codec: Can't allocate audio decoder\n"));
Fatal(_("codec: can't allocate audio decoder\n"));
}
return audio_decoder;
}
/**
** Deallocate an audio decoder context.
**
** @param decoder private audio decoder
*/
void CodecAudioDelDecoder(AudioDecoder * decoder)
{
free(decoder);
}
/**
** Open audio decoder.
**
@@ -714,10 +739,65 @@ void CodecSetAudioPassthrough(int mask)
#ifdef USE_PASSTHROUGH
CodecPassthroughAC3 = mask & 1 ? 1 : 0;
#endif
// FIXME: must update audio decoder (nr. of channels wrong)
(void)mask;
}
/**
** Reorder audio frame.
**
** ffmpeg L R C Ls Rs -> alsa L R Ls Rs C
** ffmpeg L R C LFE Ls Rs -> alsa L R Ls Rs C LFE
** ffmpeg L R C LFE Ls Rs Rl Rr -> alsa L R Ls Rs C LFE Rl Rr
*/
static void CodecReorderAudioFrame(int16_t * buf, int size, int channels)
{
int i;
int c;
int ls;
int rs;
int lfe;
switch (channels) {
case 5:
size /= 2;
for (i = 0; i < size; i += 5) {
c = buf[i + 2];
ls = buf[i + 3];
rs = buf[i + 4];
buf[i + 2] = ls;
buf[i + 3] = rs;
buf[i + 4] = c;
}
break;
case 6:
size /= 2;
for (i = 0; i < size; i += 6) {
c = buf[i + 2];
lfe = buf[i + 3];
ls = buf[i + 4];
rs = buf[i + 5];
buf[i + 2] = ls;
buf[i + 3] = rs;
buf[i + 4] = c;
buf[i + 5] = lfe;
}
break;
case 8:
size /= 2;
for (i = 0; i < size; i += 8) {
c = buf[i + 2];
lfe = buf[i + 3];
ls = buf[i + 4];
rs = buf[i + 5];
buf[i + 2] = ls;
buf[i + 3] = rs;
buf[i + 4] = c;
buf[i + 5] = lfe;
}
break;
}
}
#ifdef USE_AVPARSER
/**
@@ -775,6 +855,10 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
dpkt->dts = audio_decoder->AudioParser->dts;
buf_sz = sizeof(buf);
l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt);
if (l == AVERROR(EAGAIN)) {
index += n; // this is needed for aac latm
continue;
}
if (l < 0) { // no audio frame could be decompressed
Error(_("codec: error audio data at %d\n"), index);
break;
@@ -791,10 +875,15 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
AudioSetClock(dpkt->pts);
}
// FIXME: must first play remainings bytes, than change and play new.
if (audio_decoder->SampleRate != audio_ctx->sample_rate
if (audio_decoder->PassthroughAC3 != CodecPassthroughAC3
|| audio_decoder->SampleRate != audio_ctx->sample_rate
|| audio_decoder->Channels != audio_ctx->channels) {
int err;
int isAC3;
audio_decoder->PassthroughAC3 = CodecPassthroughAC3;
// FIXME: use swr_convert from swresample (only in ffmpeg!)
// FIXME: tell ac3 decoder to use downmix
if (audio_decoder->ReSample) {
audio_resample_close(audio_decoder->ReSample);
audio_decoder->ReSample = NULL;
@@ -803,20 +892,19 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
audio_decoder->SampleRate = audio_ctx->sample_rate;
audio_decoder->HwSampleRate = audio_ctx->sample_rate;
audio_decoder->Channels = audio_ctx->channels;
#ifdef USE_PASSTHROUGH
// SPDIF/HDMI passthrough
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
audio_decoder->HwChannels = 2;
} else
#endif
{
isAC3 = 1;
} else {
audio_decoder->HwChannels = audio_ctx->channels;
isAC3 = 0;
}
// channels not support?
if ((err =
AudioSetup(&audio_decoder->HwSampleRate,
&audio_decoder->HwChannels))) {
&audio_decoder->HwChannels, isAC3))) {
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
audio_ctx->sample_rate, audio_ctx->channels,
audio_decoder->HwSampleRate,
@@ -869,6 +957,8 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
audio_decoder->HwChannels *
av_get_bytes_per_sample(audio_ctx->sample_fmt);
Debug(4, "codec/audio: %d -> %d\n", buf_sz, outlen);
CodecReorderAudioFrame(outbuf, outlen,
audio_decoder->HwChannels);
AudioEnqueue(outbuf, outlen);
}
} else {
@@ -947,6 +1037,8 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
// True HD?
#endif
#endif
CodecReorderAudioFrame(buf, buf_sz,
audio_decoder->HwChannels);
AudioEnqueue(buf, buf_sz);
}
}

View File

@@ -40,6 +40,9 @@ typedef struct _audio_decoder_ AudioDecoder;
/// Allocate a new video decoder context.
extern VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder *);
/// Deallocate a video decoder context.
extern void CodecVideoDelDecoder(VideoDecoder *);
/// Open video codec.
extern void CodecVideoOpen(VideoDecoder *, const char *, int);
@@ -55,6 +58,9 @@ extern void CodecVideoFlushBuffers(VideoDecoder *);
/// Allocate a new audio decoder context.
extern AudioDecoder *CodecAudioNewDecoder(void);
/// Deallocate an audio decoder context.
extern void CodecAudioDelDecoder(AudioDecoder *);
/// Open audio codec.
extern void CodecAudioOpen(AudioDecoder *, const char *, int);

2
misc.h
View File

@@ -86,7 +86,7 @@ static inline void Syslog(const int level, const char *format, ...)
/**
** Show fatal error.
*/
#define Fatal(fmt...) do { Error(fmt); exit(-1); } while (0)
#define Fatal(fmt...) do { Error(fmt); abort(); } while (0)
/**
** Show warning.

File diff suppressed because it is too large Load Diff

View File

@@ -79,7 +79,7 @@ extern "C"
extern void MainThreadHook(void);
/// Suspend plugin
extern void Suspend(void);
extern void Suspend(int, int, int);
/// Resume plugin
extern void Resume(void);
#ifdef __cplusplus

View File

@@ -42,7 +42,7 @@ extern "C"
//////////////////////////////////////////////////////////////////////////////
static const char *const VERSION = "0.4.0";
static const char *const VERSION = "0.4.8";
static const char *const DESCRIPTION =
trNOOP("A software and GPU emulated HD device");
@@ -61,12 +61,18 @@ static const char *const Resolution[RESOLUTIONS] = {
static char ConfigMakePrimary; ///< config primary wanted
static char ConfigHideMainMenuEntry; ///< config hide main menu entry
static int ConfigVideoSkipLines; ///< config skip lines top/bottom
static int ConfigVideoStudioLevels; ///< config use studio levels
/// config deinterlace
static int ConfigVideoDeinterlace[RESOLUTIONS];
/// config skip chroma
static int ConfigVideoSkipChromaDeinterlace[RESOLUTIONS];
/// config inverse telecine
static int ConfigVideoInverseTelecine[RESOLUTIONS];
/// config denoise
static int ConfigVideoDenoise[RESOLUTIONS];
@@ -81,6 +87,10 @@ static int ConfigAudioPassthrough; ///< config audio pass-through
static int ConfigAutoCropInterval; ///< auto crop detection interval
static int ConfigAutoCropDelay; ///< auto crop detection delay
static int ConfigAutoCropTolerance; ///< auto crop detection tolerance
static char ConfigSuspendClose; ///< suspend should close devices
static char ConfigSuspendX11; ///< suspend should stop x11
static volatile char DoMakePrimary; ///< flag switch primary
@@ -142,9 +152,34 @@ class cSoftOsd:public cOsd
cSoftOsd(int, int, uint);
virtual ~ cSoftOsd(void);
virtual void Flush(void);
// virtual void SetActive(bool);
virtual void SetActive(bool);
};
static volatile char OsdDirty; ///< flag force redraw everything
/**
** Sets this OSD to be the active one.
**
** @param on true on, false off
**
** @note only needed as workaround for text2skin plugin with
** undrawn areas.
*/
void cSoftOsd::SetActive(bool on)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on);
if (Active() == on) {
return; // already active, no action
}
cOsd::SetActive(on);
if (on) {
OsdDirty = 1;
} else {
OsdClose();
}
}
cSoftOsd::cSoftOsd(int left, int top, uint level)
:cOsd(left, top, level)
{
@@ -161,6 +196,7 @@ cSoftOsd::~cSoftOsd(void)
{
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
SetActive(false);
// done by SetActive: OsdClose();
#ifdef USE_YAEPG
// support yaepghd, video window
@@ -174,12 +210,11 @@ cSoftOsd::~cSoftOsd(void)
VideoSetOutputPosition(0, 0, width, height);
}
#endif
OsdClose();
}
///
/// Actually commits all data to the OSD hardware.
///
/**
** Actually commits all data to the OSD hardware.
*/
void cSoftOsd::Flush(void)
{
cPixmapMemory *pm;
@@ -222,43 +257,32 @@ void cSoftOsd::Flush(void)
int y2;
// get dirty bounding box
if (!bitmap->Dirty(x1, y1, x2, y2)) {
if (OsdDirty) { // forced complete update
x1 = 0;
y1 = 0;
x2 = bitmap->Width() - 1;
y2 = bitmap->Height() - 1;
} else if (!bitmap->Dirty(x1, y1, x2, y2)) {
continue; // nothing dirty continue
}
#if 0
// FIXME: need only to convert and upload dirty areas
// DrawBitmap(bitmap);
w = bitmap->Width();
h = bitmap->Height();
argb = (uint8_t *) malloc(w * h * sizeof(uint32_t));
for (y = 0; y < h; ++y) {
for (x = 0; x < w; ++x) {
((uint32_t *) argb)[x + y * w] = bitmap->GetColor(x, y);
}
}
// check if subtitles
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(), w, h, argb);
} else {
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(), w, h,
argb);
}
#else
// convert and upload only dirty areas
w = x2 - x1 + 1;
h = y2 - y1 + 1;
if (1) { // just for the case it makes trouble
int width;
int height;
double video_aspect;
::GetOsdSize(&width, &height, &video_aspect);
if (w > width) {
w = width;
x2 = x1 + width - 1;
}
if (h > height) {
h = height;
y2 = y1 + height - 1;
}
}
#ifdef DEBUG
if (w > bitmap->Width() || h > bitmap->Height()) {
esyslog(tr("softhdev: dirty area too big\n"));
@@ -272,14 +296,14 @@ void cSoftOsd::Flush(void)
bitmap->GetColor(x, y);
}
}
// check if subtitles
OsdDrawARGB(Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1,
w, h, argb);
#endif
bitmap->Clean();
// FIXME: reuse argb
free(argb);
}
OsdDirty = 0;
return;
}
@@ -324,6 +348,10 @@ cOsd *cSoftOsdProvider::Osd; ///< single osd
/**
** Create a new OSD.
**
** @param left x-coordinate of OSD
** @param top y-coordinate of OSD
** @param level layer level of OSD
*/
cOsd *cSoftOsdProvider::CreateOsd(int left, int top, uint level)
{
@@ -359,15 +387,21 @@ class cMenuSetupSoft:public cMenuSetupPage
protected:
int MakePrimary;
int HideMainMenuEntry;
int SkipLines;
int StudioLevels;
int Scaling[RESOLUTIONS];
int Deinterlace[RESOLUTIONS];
int SkipChromaDeinterlace[RESOLUTIONS];
int InverseTelecine[RESOLUTIONS];
int Denoise[RESOLUTIONS];
int Sharpen[RESOLUTIONS];
int AudioDelay;
int AudioPassthrough;
int AutoCropInterval;
int AutoCropDelay;
int AutoCropTolerance;
int SuspendClose;
int SuspendX11;
protected:
virtual void Store(void);
public:
@@ -395,7 +429,8 @@ static inline cOsdItem *SeparatorItem(const char *label)
cMenuSetupSoft::cMenuSetupSoft(void)
{
static const char *const deinterlace[] = {
"Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software"
"Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software Bob",
"Software Spatial",
};
static const char *const scaling[] = {
"Normal", "Fast", "HQ", "Anamorphic"
@@ -420,16 +455,27 @@ cMenuSetupSoft::cMenuSetupSoft(void)
// video
//
Add(SeparatorItem(tr("Video")));
SkipLines = ConfigVideoSkipLines;
Add(new cMenuEditIntItem(tr("Skip lines top+bot (pixel)"), &SkipLines, 0,
64));
StudioLevels = ConfigVideoStudioLevels;
Add(new cMenuEditBoolItem(tr("Use studio levels (vdpau only)"),
&StudioLevels, trVDR("no"), trVDR("yes")));
for (i = 0; i < RESOLUTIONS; ++i) {
Add(SeparatorItem(resolution[i]));
Scaling[i] = ConfigVideoScaling[i];
Add(new cMenuEditStraItem(tr("Scaling"), &Scaling[i], 4, scaling));
Deinterlace[i] = ConfigVideoDeinterlace[i];
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace[i], 5,
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace[i], 6,
deinterlace));
SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i];
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),
&SkipChromaDeinterlace[i], trVDR("no"), trVDR("yes")));
InverseTelecine[i] = ConfigVideoInverseTelecine[i];
Add(new cMenuEditBoolItem(tr("Inverse Telecine (vdpau)"),
&InverseTelecine[i], trVDR("no"), trVDR("yes")));
Denoise[i] = ConfigVideoDenoise[i];
Add(new cMenuEditIntItem(tr("Denoise (0..1000) (vdpau)"), &Denoise[i],
0, 1000));
@@ -457,6 +503,19 @@ cMenuSetupSoft::cMenuSetupSoft(void)
AutoCropDelay = ConfigAutoCropDelay;
Add(new cMenuEditIntItem(tr("autocrop delay (n * interval)"),
&AutoCropDelay, 0, 200));
AutoCropTolerance = ConfigAutoCropTolerance;
Add(new cMenuEditIntItem(tr("autocrop tolerance (pixel)"),
&AutoCropTolerance, 0, 32));
//
// suspend
//
Add(SeparatorItem(tr("Suspend")));
SuspendClose = ConfigSuspendClose;
Add(new cMenuEditBoolItem(tr("suspend closes video+audio"), &SuspendClose,
trVDR("no"), trVDR("yes")));
SuspendX11 = ConfigSuspendX11;
Add(new cMenuEditBoolItem(tr("suspend stops x11"), &SuspendX11,
trVDR("no"), trVDR("yes")));
}
/**
@@ -470,6 +529,11 @@ void cMenuSetupSoft::Store(void)
SetupStore("HideMainMenuEntry", ConfigHideMainMenuEntry =
HideMainMenuEntry);
SetupStore("SkipLines", ConfigVideoSkipLines = SkipLines);
VideoSetSkipLines(ConfigVideoSkipLines);
SetupStore("StudioLevels", ConfigVideoStudioLevels = StudioLevels);
VideoSetStudioLevels(ConfigVideoStudioLevels);
for (i = 0; i < RESOLUTIONS; ++i) {
char buf[128];
@@ -481,6 +545,8 @@ void cMenuSetupSoft::Store(void)
"SkipChromaDeinterlace");
SetupStore(buf, ConfigVideoSkipChromaDeinterlace[i] =
SkipChromaDeinterlace[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "InverseTelecine");
SetupStore(buf, ConfigVideoInverseTelecine[i] = InverseTelecine[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");
@@ -489,6 +555,7 @@ void cMenuSetupSoft::Store(void)
VideoSetScaling(ConfigVideoScaling);
VideoSetDeinterlace(ConfigVideoDeinterlace);
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
VideoSetInverseTelecine(ConfigVideoInverseTelecine);
VideoSetDenoise(ConfigVideoDenoise);
VideoSetSharpen(ConfigVideoSharpen);
@@ -499,8 +566,94 @@ void cMenuSetupSoft::Store(void)
SetupStore("AutoCrop.Interval", ConfigAutoCropInterval = AutoCropInterval);
SetupStore("AutoCrop.Delay", ConfigAutoCropDelay = AutoCropDelay);
SetupStore("AutoCrop.Tolerance", ConfigAutoCropTolerance =
AutoCropTolerance);
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay,
ConfigAutoCropTolerance);
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay);
SetupStore("Suspend.Close", ConfigSuspendClose = SuspendClose);
SetupStore("Suspend.X11", ConfigSuspendX11 = SuspendX11);
}
//////////////////////////////////////////////////////////////////////////////
// cPlayer
//////////////////////////////////////////////////////////////////////////////
/**
** Dummy player for suspend mode.
*/
class cSoftHdPlayer:public cPlayer
{
protected:
public:
cSoftHdPlayer(void);
virtual ~ cSoftHdPlayer();
};
cSoftHdPlayer::cSoftHdPlayer(void)
{
}
cSoftHdPlayer::~cSoftHdPlayer()
{
Detach();
}
//////////////////////////////////////////////////////////////////////////////
// cControl
//////////////////////////////////////////////////////////////////////////////
/**
** Dummy control for suspend mode.
*/
class cSoftHdControl:public cControl
{
public:
static cSoftHdPlayer *Player; ///< dummy player
virtual void Hide(void)
{
}
virtual eOSState ProcessKey(eKeys);
cSoftHdControl(void);
virtual ~ cSoftHdControl();
};
cSoftHdPlayer *cSoftHdControl::Player;
/**
** Handle a key event.
**
** @param key key pressed
*/
eOSState cSoftHdControl::ProcessKey(eKeys key)
{
if (!ISMODELESSKEY(key) || key == kBack || key == kStop) {
if (Player) {
delete Player;
Player = NULL;
}
Resume();
return osEnd;
}
return osContinue;
}
cSoftHdControl::cSoftHdControl(void)
: cControl(Player = new cSoftHdPlayer)
{
}
cSoftHdControl::~cSoftHdControl()
{
if (Player) {
delete Player;
Player = NULL;
}
Resume();
}
//////////////////////////////////////////////////////////////////////////////
@@ -511,7 +664,7 @@ class cSoftHdDevice:public cDevice
{
public:
cSoftHdDevice(void);
virtual ~ cSoftHdDevice(void);
virtual ~ cSoftHdDevice(void);
virtual bool HasDecoder(void) const;
virtual bool CanReplay(void) const;
@@ -521,11 +674,11 @@ class cSoftHdDevice:public cDevice
virtual void Play(void);
virtual void Freeze(void);
virtual void Mute(void);
virtual void SetVolumeDevice(int);
virtual void StillPicture(const uchar *, int);
virtual bool Poll(cPoller &, int = 0);
virtual bool Flush(int = 0);
virtual int64_t GetSTC(void);
virtual void SetVideoDisplayFormat(eVideoDisplayFormat);
virtual void GetVideoSize(int &, int &, double &);
virtual void GetOsdSize(int &, int &, double &);
virtual int PlayVideo(const uchar *, int);
@@ -538,6 +691,7 @@ class cSoftHdDevice:public cDevice
virtual int GetAudioChannelDevice(void);
virtual void SetDigitalAudioDevice(bool);
virtual void SetAudioTrackDevice(eTrackType);
virtual void SetVolumeDevice(int);
virtual int PlayAudio(const uchar *, int, uchar);
// Image Grab facilities
@@ -547,13 +701,13 @@ class cSoftHdDevice:public cDevice
#if 0
// SPU facilities
private:
cDvbSpuDecoder * spuDecoder;
cDvbSpuDecoder * spuDecoder;
public:
virtual cSpuDecoder * GetSpuDecoder(void);
virtual cSpuDecoder * GetSpuDecoder(void);
#endif
protected:
virtual void MakePrimaryDevice(bool);
virtual void MakePrimaryDevice(bool);
};
cSoftHdDevice::cSoftHdDevice(void)
@@ -563,6 +717,7 @@ cSoftHdDevice::cSoftHdDevice(void)
#if 0
spuDecoder = NULL;
#endif
SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
}
cSoftHdDevice::~cSoftHdDevice(void)
@@ -604,16 +759,22 @@ bool cSoftHdDevice::HasDecoder(void) const
return true;
}
/**
** Returns true if this device can currently start a replay session.
*/
bool cSoftHdDevice::CanReplay(void) const
{
return true;
}
bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
/**
** Sets the device into the given play mode.
*/
bool cSoftHdDevice::SetPlayMode(ePlayMode play_mode)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, PlayMode);
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, play_mode);
switch (PlayMode) {
switch (play_mode) {
case pmAudioVideo:
break;
case pmAudioOnly:
@@ -624,18 +785,24 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
case pmNone:
return true;
case pmExtern_THIS_SHOULD_BE_AVOIDED:
break;
dsyslog("[softhddev] play mode external\n");
Suspend(1, 1, 0);
return true;
default:
dsyslog("[softhddev]playmode not implemented... %d\n", PlayMode);
dsyslog("[softhddev]playmode not implemented... %d\n", play_mode);
break;
}
::SetPlayMode();
return true;
}
/**
** Gets the current System Time Counter, which can be used to
** synchronize audio, video and subtitles.
*/
int64_t cSoftHdDevice::GetSTC(void)
{
// dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
return::VideoGetClock();
}
@@ -677,6 +844,9 @@ void cSoftHdDevice::Freeze(void)
::Freeze();
}
/**
** Turns off audio while replaying.
*/
void cSoftHdDevice::Mute(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
@@ -685,20 +855,13 @@ void cSoftHdDevice::Mute(void)
::Mute();
}
void cSoftHdDevice::SetVolumeDevice(int volume)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
::SetVolumeDevice(volume);
}
/**
** Display the given I-frame as a still picture.
*/
void cSoftHdDevice::StillPicture(const uchar * data, int length)
{
dsyslog("[softhddev]%s: %s\n", __FUNCTION__,
data[0] == 0x47 ? "ts" : "pes");
dsyslog("[softhddev]%s: %s %p %d\n", __FUNCTION__,
data[0] == 0x47 ? "ts" : "pes", data, length);
if (data[0] == 0x47) { // ts sync
cDevice::StillPicture(data, length);
@@ -717,7 +880,7 @@ void cSoftHdDevice::StillPicture(const uchar * data, int length)
bool cSoftHdDevice::Poll(
__attribute__ ((unused)) cPoller & poller, int timeout_ms)
{
// dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms);
//dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms);
return::Poll(timeout_ms);
}
@@ -736,6 +899,30 @@ bool cSoftHdDevice::Flush(int timeout_ms)
// ----------------------------------------------------------------------------
/**
** Sets the video display format to the given one (only useful if this
** device has an MPEG decoder).
**
** @note this function isn't called on the initial channel
*/
void cSoftHdDevice::SetVideoDisplayFormat(
eVideoDisplayFormat video_display_format)
{
static int last = -1;
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, video_display_format);
cDevice::SetVideoDisplayFormat(video_display_format);
// called on every channel switch, no need to kill osd...
if (last != video_display_format) {
last = video_display_format;
::VideoSetDisplayFormat(video_display_format);
OsdDirty = 1;
}
}
/**
** Returns the width, height and video_aspect ratio of the currently
** displayed video material.
@@ -792,11 +979,23 @@ int cSoftHdDevice::GetAudioChannelDevice(void)
return 0;
}
/**
** Sets the audio volume on this device (Volume = 0...255).
**
** @param volume device volume
*/
void cSoftHdDevice::SetVolumeDevice(int volume)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
::SetVolumeDevice(volume);
}
// ----------------------------------------------------------------------------
///
/// Play a video packet.
///
/**
** Play a video packet.
*/
int cSoftHdDevice::PlayVideo(const uchar * data, int length)
{
//dsyslog("[softhddev]%s: %p %d\n", __FUNCTION__, data, length);
@@ -851,6 +1050,16 @@ uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int width,
return::GrabImage(&size, jpeg, quality, width, height);
}
/**
** Call rgb to jpeg for C Plugin.
*/
extern "C" uint8_t * CreateJpeg(uint8_t * image, int *size, int quality,
int width, int height)
{
return (uint8_t *) RgbToJpeg((uchar *) image, width, height, *size,
quality);
}
//////////////////////////////////////////////////////////////////////////////
// cPlugin
//////////////////////////////////////////////////////////////////////////////
@@ -867,7 +1076,7 @@ class cPluginSoftHdDevice:public cPlugin
virtual bool Initialize(void);
virtual bool Start(void);
virtual void Stop(void);
// virtual void Housekeeping(void);
// virtual void Housekeeping(void);
virtual void MainThreadHook(void);
virtual const char *MainMenuEntry(void);
virtual cOsdObject *MainMenuAction(void);
@@ -966,9 +1175,14 @@ void cPluginSoftHdDevice::Stop(void)
#if 0
/**
** Perform any cleanup or other regular tasks.
*/
void cPluginSoftHdDevice::Housekeeping(void)
{
// Perform any cleanup or other regular tasks.
dsyslog("[softhddev]%s:\n", __FUNCTION__);
// ::Housekeeping();
}
#endif
@@ -988,12 +1202,17 @@ const char *cPluginSoftHdDevice::MainMenuEntry(void)
*/
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
cDevice::PrimaryDevice()->StopReplay();
Suspend();
if (ShutdownHandler.GetUserInactiveTime()) {
ShutdownHandler.SetUserInactive();
//MyDevice->StopReplay();
if (!cSoftHdControl::Player) { // not already suspended
cControl::Launch(new cSoftHdControl);
cControl::Attach();
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
if (ShutdownHandler.GetUserInactiveTime()) {
dsyslog("[softhddev]%s: set user inactive\n", __FUNCTION__);
ShutdownHandler.SetUserInactive();
}
}
return NULL;
@@ -1015,7 +1234,7 @@ void cPluginSoftHdDevice::MainThreadHook(void)
// check if user is inactive, automatic enter suspend mode
if (ShutdownHandler.IsUserInactive()) {
// this is regular called, but guarded against double calls
Suspend();
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
}
::MainThreadHook();
@@ -1053,6 +1272,14 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
ConfigHideMainMenuEntry = atoi(value);
return true;
}
if (!strcmp(name, "SkipLines")) {
VideoSetSkipLines(ConfigVideoSkipLines = atoi(value));
return true;
}
if (!strcmp(name, "StudioLevels")) {
VideoSetStudioLevels(ConfigVideoStudioLevels = atoi(value));
return true;
}
for (i = 0; i < RESOLUTIONS; ++i) {
char buf[128];
@@ -1075,6 +1302,12 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "InverseTelecine");
if (!strcmp(name, buf)) {
ConfigVideoInverseTelecine[i] = atoi(value);
VideoSetInverseTelecine(ConfigVideoInverseTelecine);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise");
if (!strcmp(name, buf)) {
ConfigVideoDenoise[i] = atoi(value);
@@ -1100,15 +1333,28 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
if (!strcmp(name, "AutoCrop.Interval")) {
VideoSetAutoCrop(ConfigAutoCropInterval =
atoi(value), ConfigAutoCropDelay);
atoi(value), ConfigAutoCropDelay, ConfigAutoCropTolerance);
return true;
}
if (!strcmp(name, "AutoCrop.Delay")) {
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay =
atoi(value));
atoi(value), ConfigAutoCropTolerance);
return true;
}
if (!strcmp(name, "AutoCrop.Tolerance")) {
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay,
ConfigAutoCropTolerance = atoi(value));
return true;
}
if (!strcmp(name, "Suspend.Close")) {
ConfigSuspendClose = atoi(value);
return true;
}
if (!strcmp(name, "Suspend.X11")) {
ConfigSuspendX11 = atoi(value);
return true;
}
return false;
}
@@ -1137,8 +1383,8 @@ const char **cPluginSoftHdDevice::SVDRPHelpPages(void)
{
// FIXME: translation?
static const char *text[] = {
"SUSP\n",
" Suspend plugin",
"SUSP\n" " Suspend plugin.\n",
"RESU\n" " Resume plugin.\n",
NULL
};
@@ -1153,9 +1399,25 @@ cString cPluginSoftHdDevice::SVDRPCommand(const char *command,
__attribute__ ((unused)) int &reply_code)
{
if (!strcasecmp(command, "SUSP")) {
Suspend();
if (cSoftHdControl::Player) { // already suspended
return "SoftHdDevice already suspended";
}
// should be after suspend, but SetPlayMode resumes
cControl::Launch(new cSoftHdControl);
cControl::Attach();
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
return "SoftHdDevice is suspended";
}
if (!strcasecmp(command, "RESU")) {
if (ShutdownHandler.GetUserInactiveTime()) {
ShutdownHandler.SetUserInactiveTimeout();
}
if (cSoftHdControl::Player) { // suspended
cControl::Shutdown(); // not need, if not suspended
}
Resume();
return "SoftHdDevice is resumed";
}
return NULL;
}

View File

@@ -21,25 +21,26 @@ SRC_URI=""
LICENSE="AGPL-3"
SLOT="0"
KEYWORDS="~x86 ~amd64"
IUSE="vaapi vdpau alsa oss yaepg opengl"
IUSE="vaapi vdpau alsa oss yaepg opengl jpeg"
DEPEND=">=x11-libs/libxcb-1.7
DEPEND=">=x11-libs/libxcb-1.8
x11-libs/xcb-util
x11-libs/xcb-util-wm
x11-libs/xcb-util-keysyms
x11-libs/xcb-util-renderutil
x11-libs/libX11
opengl? ( virtual/opengl )
>=media-video/ffmpeg-0.7
>=virtual/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 )
yaepg? ( >=media-video/vdr-1.7.23[yaepg] )
!yaepg? ( >=media-video/vdr-1.7.23 )
vdpau? ( x11-libs/libvdpau )
vaapi? ( x11-libs/libva )
alsa? ( media-libs/alsa-lib )
oss? ( sys-kernel/linux-headers )
jpeg? ( virtual/jpeg )
"
src_prepare() {
@@ -49,11 +50,12 @@ src_prepare() {
src_compile() {
local myconf
myconf=""
myconf="-DHAVE_PTHREAD_NAME"
use vdpau && myconf="${myconf} -DUSE_VDPAU"
use vaapi && myconf="${myconf} -DUSE_VAAPI"
use alsa && myconf="${myconf} -DUSE_ALSA"
use oss && myconf="${myconf} -DUSE_OSS"
use jpeg && myconf="${myconf} -DUSE_JPEG"
emake all CC="$(tc-getCC)" CFLAGS="${CFLAGS}" \
LDFLAGS="${LDFLAGS}" CONFIG="${myconf}" LIBDIR="." || die
@@ -62,10 +64,11 @@ src_compile() {
src_install() {
vdr-plugin_src_install
dodir /etc/vdr/plugins || die
dodoc README.txt
insinto /etc/vdr/plugins
fowners -R vdr:vdr /etc/vdr || die
#dodir /etc/vdr/plugins || die
#insinto /etc/vdr/plugins
#fowners -R vdr:vdr /etc/vdr || die
#insinto /etc/conf.d
#doins vdr.softhddevice

3380
video.c

File diff suppressed because it is too large Load Diff

29
video.h
View File

@@ -47,16 +47,17 @@ extern unsigned VideoGetSurface(VideoHwDecoder *);
extern void VideoReleaseSurface(VideoHwDecoder *, unsigned);
#ifdef LIBAVCODEC_VERSION
/// Render a ffmpeg frame.
extern void VideoRenderFrame(VideoHwDecoder *, AVCodecContext *, AVFrame *);
/// Get ffmpeg vaapi context.
extern struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder *);
/// Callback to negotiate the PixelFormat.
extern enum PixelFormat Video_get_format(VideoHwDecoder *, AVCodecContext *,
const enum PixelFormat *);
/// Render a ffmpeg frame.
extern void VideoRenderFrame(VideoHwDecoder *, const AVCodecContext *,
const AVFrame *);
/// Get ffmpeg vaapi context.
extern struct vaapi_context *VideoGetVaapiContext(VideoHwDecoder *);
#ifdef AVCODEC_VDPAU_H
/// Draw vdpau render state.
extern void VideoDrawRenderState(VideoHwDecoder *,
@@ -79,6 +80,9 @@ extern void VideoSetOutputPosition(int, int, int, int);
/// Set video mode.
extern void VideoSetVideoMode(int, int, int, int);
/// Set display format.
extern void VideoSetDisplayFormat(int);
/// Set video fullscreen mode.
extern void VideoSetFullscreen(int);
@@ -88,6 +92,9 @@ extern void VideoSetDeinterlace(int[]);
/// Set skip chroma deinterlace.
extern void VideoSetSkipChromaDeinterlace(int[]);
/// Set inverse telecine.
extern void VideoSetInverseTelecine(int[]);
/// Set scaling.
extern void VideoSetScaling(int[]);
@@ -97,11 +104,17 @@ extern void VideoSetDenoise(int[]);
/// Set sharpen.
extern void VideoSetSharpen(int[]);
/// Set skip lines.
extern void VideoSetSkipLines(int);
/// Set studio levels.
extern void VideoSetStudioLevels(int);
/// Set audio delay.
extern void VideoSetAudioDelay(int);
/// Set auto-crop parameters.
extern void VideoSetAutoCrop(int, int);
extern void VideoSetAutoCrop(int, int, int);
/// Clear OSD.
extern void VideoOsdClear(void);
@@ -115,7 +128,7 @@ extern void VideoGetOsdSize(int *, int *);
extern int64_t VideoGetClock(void); ///< Get video clock.
/// Grab screen.
extern uint8_t *VideoGrab(int *, int *, int *);
extern uint8_t *VideoGrab(int *, int *, int *, int);
extern void VideoOsdInit(void); ///< Setup osd.
extern void VideoOsdExit(void); ///< Cleanup osd.