mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 17:16:51 +00:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00cafd18ed | ||
|
|
ab4e89132e | ||
|
|
3585f1df19 | ||
|
|
e258c35537 | ||
|
|
91dbe46786 | ||
|
|
a7389111ff | ||
|
|
27e9a88e2f | ||
|
|
33e9c71aea | ||
|
|
bd84e3f3b9 | ||
|
|
364cc04736 | ||
| ec4a899bb8 | |||
|
|
dab31e2367 | ||
|
|
e613ff1f7e | ||
|
|
1886b745e5 | ||
|
|
422c378a5e | ||
|
|
eed708b9ea | ||
|
|
60a7c36fa6 | ||
|
|
4d74ed1bfc | ||
|
|
c3b924a239 | ||
|
|
f8d198636b | ||
|
|
bcf6ecabc1 | ||
|
|
9063b4e3ff | ||
|
|
e3681812bd | ||
|
|
9d14522121 | ||
| 2dff69dc14 | |||
|
|
5668fa22d2 | ||
|
|
c7cebe1aeb | ||
|
|
037f582bad | ||
|
|
6ca4d3c44f | ||
|
|
2ac2eb39c6 | ||
|
|
217545542d | ||
|
|
5f43803236 | ||
|
|
993d831190 | ||
|
|
1969b2a0a7 | ||
|
|
0fad02285d | ||
|
|
9546233175 | ||
|
|
98d2e0f728 | ||
| 970493fb23 | |||
|
|
329dbc5f07 | ||
|
|
bc8a13e1ef | ||
|
|
bd7e6143c7 | ||
|
|
fa27a1c73a | ||
|
|
e32857a27a | ||
|
|
5ba88bb822 | ||
|
|
0422b6aa5a | ||
|
|
eb024558de | ||
|
|
1593d5dd83 | ||
|
|
09f62307d4 |
87
ChangeLog
87
ChangeLog
@@ -1,4 +1,91 @@
|
|||||||
User johns
|
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
|
||||||
|
VDPAU: Add grab image support.
|
||||||
|
VDPAU: Add auto-crop support.
|
||||||
|
VDPAU: Changed OSD alpha calculation.
|
||||||
|
Fix bug: Used VideoSharpen for denoise settings.
|
||||||
|
Instant update deinterlace/... configuration changes.
|
||||||
|
Fix bug: AudioExit called without AudioInit crash.
|
||||||
|
|
||||||
Date: Thu Jan 19 15:58:40 CET 2012
|
Date: Thu Jan 19 15:58:40 CET 2012
|
||||||
|
|
||||||
Release Version 0.3.5
|
Release Version 0.3.5
|
||||||
|
|||||||
8
Makefile
8
Makefile
@@ -19,10 +19,12 @@ GIT_REV = $(shell git describe --always 2>/dev/null)
|
|||||||
### Configuration (edit this for your needs)
|
### Configuration (edit this for your needs)
|
||||||
|
|
||||||
CONFIG := #-DDEBUG
|
CONFIG := #-DDEBUG
|
||||||
|
CONFIG += -DAV_INFO
|
||||||
#CONFIG += -DHAVE_PTHREAD_NAME
|
#CONFIG += -DHAVE_PTHREAD_NAME
|
||||||
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
|
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
|
||||||
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
||||||
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
|
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
|
||||||
|
CONFIG += $(shell ls /usr/lib/libjpeg* >/dev/null 2>&1 && echo "-DUSE_JPEG")
|
||||||
CONFIG += -DUSE_OSS
|
CONFIG += -DUSE_OSS
|
||||||
|
|
||||||
### The C++ compiler and options:
|
### The C++ compiler and options:
|
||||||
@@ -89,7 +91,9 @@ LIBS += -lrt \
|
|||||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
$(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)), \
|
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||||
`pkg-config --libs alsa`)
|
`pkg-config --libs alsa`) \
|
||||||
|
$(if $(findstring USE_JPEG,$(CONFIG)), \
|
||||||
|
-ljpeg)
|
||||||
|
|
||||||
### The object files (add further files here):
|
### The object files (add further files here):
|
||||||
|
|
||||||
@@ -171,6 +175,6 @@ indent:
|
|||||||
indent $$i; unexpand -a $$i > $$i.up; mv $$i.up $$i; \
|
indent $$i; unexpand -a $$i > $$i.up; mv $$i.up $$i; \
|
||||||
done
|
done
|
||||||
|
|
||||||
video_test: video.c
|
video_test: video.c Makefile
|
||||||
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $< $(LIBS) \
|
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $< $(LIBS) \
|
||||||
-o $@
|
-o $@
|
||||||
|
|||||||
51
README.txt
51
README.txt
@@ -24,17 +24,20 @@ A software and GPU emulated HD output device plugin for VDR.
|
|||||||
o Video CPU/VA-API
|
o Video CPU/VA-API
|
||||||
o Video VDPAU/VDPAU
|
o Video VDPAU/VDPAU
|
||||||
o Video CPU/VDPAU
|
o Video CPU/VDPAU
|
||||||
|
o Audio FFMpeg/Alsa/Analog
|
||||||
|
o Audio FFMpeg/Alsa/Digital
|
||||||
|
o Audio FFMpeg/OSS/Analog
|
||||||
|
o HDMI/SPDIF Passthrough
|
||||||
|
o VA-API bob software deinterlace
|
||||||
|
o Auto-crop
|
||||||
|
|
||||||
o planned: Video VA-API/Opengl
|
o planned: Video VA-API/Opengl
|
||||||
o planned: Video VDPAU/Opengl
|
o planned: Video VDPAU/Opengl
|
||||||
o planned: Video CPU/Xv
|
o planned: Video CPU/Xv
|
||||||
o planned: Video CPU/Opengl
|
o planned: Video CPU/Opengl
|
||||||
o planned: Software Deinterlacer
|
o planned: Improved Software Deinterlacer (yadif or/and ffmpeg filters)
|
||||||
o planned: Video XvBA/XvBA
|
o planned: Video XvBA/XvBA
|
||||||
o Audio FFMpeg/Alsa/Analog
|
o planned: atmo light support
|
||||||
o Audio FFMpeg/Alsa/Digital
|
|
||||||
o Audio FFMpeg/OSS/Analog
|
|
||||||
o Alsa 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.
|
||||||
|
|
||||||
@@ -76,6 +79,8 @@ Setup: environment
|
|||||||
only if alsa is configured
|
only if alsa is configured
|
||||||
ALSA_DEVICE=default
|
ALSA_DEVICE=default
|
||||||
alsa PCM device name
|
alsa PCM device name
|
||||||
|
ALSA_AC3_DEVICE=
|
||||||
|
alsa AC3/pass-though device name
|
||||||
ALSA_MIXER=default
|
ALSA_MIXER=default
|
||||||
alsa control device name
|
alsa control device name
|
||||||
ALSA_MIXER_CHANNEL=PCM
|
ALSA_MIXER_CHANNEL=PCM
|
||||||
@@ -83,6 +88,8 @@ Setup: environment
|
|||||||
only if oss is configured
|
only if oss is configured
|
||||||
OSS_AUDIODEV=/dev/dsp
|
OSS_AUDIODEV=/dev/dsp
|
||||||
oss dsp device name
|
oss dsp device name
|
||||||
|
OSS_AC3_AUDIODEV=
|
||||||
|
oss AC3/pass-though device name
|
||||||
OSS_MIXERDEV=/dev/mixer
|
OSS_MIXERDEV=/dev/mixer
|
||||||
oss mixer device name
|
oss mixer device name
|
||||||
OSS_MIXER_CHANNEL=pcm
|
OSS_MIXER_CHANNEL=pcm
|
||||||
@@ -125,6 +132,30 @@ Setup: /etc/vdr/setup.conf
|
|||||||
softhddevice.AudioPassthrough = 0
|
softhddevice.AudioPassthrough = 0
|
||||||
0 = none, 1 = AC-3
|
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 '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.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)
|
||||||
|
|
||||||
Setup: /etc/vdr/remote.conf
|
Setup: /etc/vdr/remote.conf
|
||||||
------
|
------
|
||||||
|
|
||||||
@@ -144,7 +175,7 @@ Setup: /etc/vdr/remote.conf
|
|||||||
Commandline:
|
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
|
-a audio_device
|
||||||
|
|
||||||
@@ -155,6 +186,12 @@ Commandline:
|
|||||||
other to use alsa audio module (if compiled with alsa
|
other to use alsa audio module (if compiled with alsa
|
||||||
support)
|
support)
|
||||||
|
|
||||||
|
SVDRP:
|
||||||
|
------
|
||||||
|
|
||||||
|
Use 'svdrpsend.pl plug softhddevice HELP' to see the SVDRP commands
|
||||||
|
help and which are supported by the plugin.
|
||||||
|
|
||||||
Running:
|
Running:
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|||||||
48
Todo
48
Todo
@@ -21,48 +21,66 @@ $Id: $
|
|||||||
missing:
|
missing:
|
||||||
software deinterlace (yadif, ...)
|
software deinterlace (yadif, ...)
|
||||||
software decoder with software deinterlace
|
software decoder with software deinterlace
|
||||||
auto crop
|
|
||||||
zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
|
|
||||||
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
|
suspend output / energie saver: stop and restart X11
|
||||||
|
suspend plugin didn't restore full-screen (is this wanted?)
|
||||||
Option deinterlace off / deinterlace force!
|
Option deinterlace off / deinterlace force!
|
||||||
Make output drivers better modular.
|
|
||||||
|
crash:
|
||||||
|
AudioPlayHandlerThread -> pthread_cond_wait
|
||||||
|
|
||||||
video:
|
video:
|
||||||
subtitle not cleared
|
subtitle not cleared
|
||||||
subtitle could be asyncron
|
subtitle could be asyncron
|
||||||
|
reduce warnings after channel switch
|
||||||
|
grab image with hardware and better scaling support
|
||||||
|
suspendoutput didn't show logo or black pictures
|
||||||
|
(must detect video format to show image)
|
||||||
|
hard channel switch
|
||||||
|
skip lines not configurable from setup menu.
|
||||||
|
OSD can only be shown after some stream could be shown
|
||||||
|
|
||||||
vdpau:
|
vdpau:
|
||||||
VdpPreemptionCallback handling
|
software decoder path not working
|
||||||
hard channel switch
|
|
||||||
suspendoutput didn't show logo or black picture.
|
|
||||||
|
|
||||||
libva:
|
libva:
|
||||||
hard channel switch
|
|
||||||
yaepghd (VaapiSetOutputPosition) support
|
yaepghd (VaapiSetOutputPosition) support
|
||||||
can associate ony displayed part of osd
|
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:
|
libva-intel-driver:
|
||||||
intel still has hangups most with 1080i
|
deinterlace only supported with vaapi-ext
|
||||||
1080i does no v-sync (workaround written)
|
1080i does no v-sync (sometimes correct working with vaapi-ext)
|
||||||
OSD has sometimes wrong size (workaround written)
|
OSD has sometimes wrong size (workaround written)
|
||||||
|
sometimes software decoder deinterlace isn't working and 1080i channels
|
||||||
|
show artefacts
|
||||||
|
|
||||||
libva-vdpau-driver:
|
libva-vdpau-driver:
|
||||||
G210/GT520 OSD update too slow (needs hardware problem workaround)
|
G210/GT520 OSD update too slow (needs hardware problem workaround)
|
||||||
hangup on exit (VaapiDelDecoder -> VaapiCleanup
|
hangup on exit (VaapiDelDecoder -> VaapiCleanup
|
||||||
-> vaDestroyContext -> pthread_rwlock_wrlock)
|
-> vaDestroyContext -> pthread_rwlock_wrlock)
|
||||||
|
OSD still has some problems with auto-crop and 4:3 zoom.
|
||||||
|
|
||||||
libva-xvba-driver:
|
libva-xvba-driver:
|
||||||
|
|
||||||
x11:
|
x11:
|
||||||
disable screensaver
|
disable screensaver
|
||||||
|
skip multiple configure-notify, handle only the last one.
|
||||||
|
support embedded mode
|
||||||
|
|
||||||
audio:
|
audio:
|
||||||
write TS -> PES parser, which feeds audio before the next start packet
|
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.
|
Combine alsa+oss ringbuffer code.
|
||||||
Make alsa thread/polled and oss thread/polled output module runtime
|
Make alsa thread/polled and oss thread/polled output module runtime
|
||||||
selectable.
|
selectable.
|
||||||
|
software volume support
|
||||||
|
|
||||||
audio/alsa:
|
audio/alsa:
|
||||||
better downmix of >2 channels on 2 channel hardware
|
better downmix of >2 channels on 2 channel hardware
|
||||||
@@ -72,12 +90,12 @@ audio/alsa:
|
|||||||
|
|
||||||
audio/oss:
|
audio/oss:
|
||||||
alsa oss emulation mixer "pcm" not working
|
alsa oss emulation mixer "pcm" not working
|
||||||
|
oss4 mixer channel 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.
|
Channels are wrong setup, if changing setting during operation.
|
||||||
split pcm and ac-3 out into two devices
|
|
||||||
support oss pass-through
|
support oss pass-through
|
||||||
|
|
||||||
playback of recording
|
playback of recording
|
||||||
@@ -91,11 +109,11 @@ setup:
|
|||||||
Setup 4:3 zoom type
|
Setup 4:3 zoom type
|
||||||
Some 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
|
|
||||||
|
|
||||||
unsorted:
|
unsorted:
|
||||||
Menu -> Setup -> Plugins -> skingenigmang -> General
|
Menu -> Setup -> Plugins -> skingenigmang -> General
|
||||||
-> Try 8bpp single area: no, has missing parts.
|
-> 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)
|
future features (not planed for 1.0 - 1.5)
|
||||||
|
|
||||||
@@ -105,5 +123,7 @@ future features (not planed for 1.0 - 1.5)
|
|||||||
software decoder for xv / opengl
|
software decoder for xv / opengl
|
||||||
atmolight support
|
atmolight support
|
||||||
multistream handling
|
multistream handling
|
||||||
|
pip support
|
||||||
|
save and use auto-crop with channel zapping
|
||||||
|
|
||||||
upmix stereo to AC-3
|
upmix stereo to AC-3
|
||||||
|
|||||||
212
audio.c
212
audio.c
@@ -99,7 +99,7 @@
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Audio output module typedef.
|
** Audio output module structure and typedef.
|
||||||
*/
|
*/
|
||||||
typedef struct _audio_module_
|
typedef struct _audio_module_
|
||||||
{
|
{
|
||||||
@@ -112,18 +112,23 @@ typedef struct _audio_module_
|
|||||||
int (*FreeBytes) (void); ///< number of bytes free in buffer
|
int (*FreeBytes) (void); ///< number of bytes free in buffer
|
||||||
uint64_t(*GetDelay) (void); ///< get current audio delay
|
uint64_t(*GetDelay) (void); ///< get current audio delay
|
||||||
void (*SetVolume) (int); ///< set output volume
|
void (*SetVolume) (int); ///< set output volume
|
||||||
int (*Setup) (int *, int *); ///< setup channels, samplerate
|
int (*Setup) (int *, int *, int); ///< setup channels, samplerate
|
||||||
void (*Init) (void); ///< initialize audio output module
|
void (*Init) (void); ///< initialize audio output module
|
||||||
void (*Exit) (void); ///< cleanup audio output module
|
void (*Exit) (void); ///< cleanup audio output module
|
||||||
} AudioModule;
|
} AudioModule;
|
||||||
|
|
||||||
|
static const AudioModule NoopModule; ///< forward definition of noop module
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Variables
|
// Variables
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
static const char *AudioModuleName; ///< which audio module to use
|
static const char *AudioModuleName; ///< which audio module to use
|
||||||
static const AudioModule *UsedAudioModule; ///< Selected audio module.
|
|
||||||
|
/// Selected audio module.
|
||||||
|
static const AudioModule *AudioUsedModule = &NoopModule;
|
||||||
static const char *AudioPCMDevice; ///< alsa/OSS PCM device name
|
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 *AudioMixerDevice; ///< alsa/OSS mixer device name
|
||||||
static const char *AudioMixerChannel; ///< alsa/OSS mixer channel name
|
static const char *AudioMixerChannel; ///< alsa/OSS mixer channel name
|
||||||
static volatile char AudioRunning; ///< thread running / stopped
|
static volatile char AudioRunning; ///< thread running / stopped
|
||||||
@@ -132,6 +137,7 @@ static unsigned AudioSampleRate; ///< audio sample rate in hz
|
|||||||
static unsigned AudioChannels; ///< number of audio channels
|
static unsigned AudioChannels; ///< number of audio channels
|
||||||
static const int AudioBytesProSample = 2; ///< number of bytes per sample
|
static const int AudioBytesProSample = 2; ///< number of bytes per sample
|
||||||
static int64_t AudioPTS; ///< audio pts clock
|
static int64_t AudioPTS; ///< audio pts clock
|
||||||
|
static const int AudioBufferTime = 350; ///< audio buffer time in ms
|
||||||
|
|
||||||
#ifdef USE_AUDIO_THREAD
|
#ifdef USE_AUDIO_THREAD
|
||||||
static pthread_t AudioThread; ///< audio play thread
|
static pthread_t AudioThread; ///< audio play thread
|
||||||
@@ -141,6 +147,8 @@ static pthread_cond_t AudioStartCond; ///< condition variable
|
|||||||
static const int AudioThread; ///< dummy audio thread
|
static const int AudioThread; ///< dummy audio thread
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern int VideoAudioDelay; /// import audio/video delay
|
||||||
|
|
||||||
#ifdef USE_AUDIORING
|
#ifdef USE_AUDIORING
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -570,6 +578,8 @@ static void AlsaEnqueue(const void *samples, int count)
|
|||||||
|
|
||||||
// direct play produces underuns on some hardware
|
// direct play produces underuns on some hardware
|
||||||
|
|
||||||
|
#ifndef USE_AUDIO_THREAD
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Place samples in audio output queue.
|
** Place samples in audio output queue.
|
||||||
**
|
**
|
||||||
@@ -583,6 +593,8 @@ static void AlsaEnqueue(const void *samples, int count)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_AUDIO_THREAD
|
#ifdef USE_AUDIO_THREAD
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -687,18 +699,25 @@ static void AlsaThreadFlushBuffers(void)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
** Open alsa pcm device.
|
** 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;
|
const char *device;
|
||||||
snd_pcm_t *handle;
|
snd_pcm_t *handle;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!(device = AudioPCMDevice)) {
|
// &&|| hell
|
||||||
if (!(device = getenv("ALSA_DEVICE"))) {
|
if (!(use_ac3 && ((device = AudioAC3Device)
|
||||||
device = "default";
|
|| (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 =
|
if ((err =
|
||||||
snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK,
|
snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK,
|
||||||
SND_PCM_NONBLOCK)) < 0) {
|
SND_PCM_NONBLOCK)) < 0) {
|
||||||
@@ -725,7 +744,7 @@ static void AlsaInitPCM(void)
|
|||||||
int err;
|
int err;
|
||||||
snd_pcm_uframes_t buffer_size;
|
snd_pcm_uframes_t buffer_size;
|
||||||
|
|
||||||
if (!(handle = AlsaOpenPCM())) {
|
if (!(handle = AlsaOpenPCM(0))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,6 +888,7 @@ static uint64_t AlsaGetDelay(void)
|
|||||||
**
|
**
|
||||||
** @param freq sample frequency
|
** @param freq sample frequency
|
||||||
** @param channels number of channels
|
** @param channels number of channels
|
||||||
|
** @param use_ac3 use ac3/pass-through device
|
||||||
**
|
**
|
||||||
** @retval 0 everything ok
|
** @retval 0 everything ok
|
||||||
** @retval 1 didn't support frequency/channels combination
|
** @retval 1 didn't support frequency/channels combination
|
||||||
@@ -876,12 +896,13 @@ static uint64_t AlsaGetDelay(void)
|
|||||||
**
|
**
|
||||||
** @todo audio changes must be queued and done when the buffer is empty
|
** @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 buffer_size;
|
||||||
snd_pcm_uframes_t period_size;
|
snd_pcm_uframes_t period_size;
|
||||||
int err;
|
int err;
|
||||||
int ret;
|
int ret;
|
||||||
|
int delay;
|
||||||
snd_pcm_t *handle;
|
snd_pcm_t *handle;
|
||||||
|
|
||||||
if (!AlsaPCMHandle) { // alsa not running yet
|
if (!AlsaPCMHandle) { // alsa not running yet
|
||||||
@@ -895,7 +916,7 @@ static int AlsaSetup(int *freq, int *channels)
|
|||||||
handle = AlsaPCMHandle;
|
handle = AlsaPCMHandle;
|
||||||
AlsaPCMHandle = NULL;
|
AlsaPCMHandle = NULL;
|
||||||
snd_pcm_close(handle);
|
snd_pcm_close(handle);
|
||||||
if (!(handle = AlsaOpenPCM())) {
|
if (!(handle = AlsaOpenPCM(use_ac3))) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
AlsaPCMHandle = handle;
|
AlsaPCMHandle = handle;
|
||||||
@@ -1066,9 +1087,15 @@ static int AlsaSetup(int *freq, int *channels)
|
|||||||
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
|
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
|
||||||
|
|
||||||
AlsaStartThreshold = snd_pcm_frames_to_bytes(AlsaPCMHandle, period_size);
|
AlsaStartThreshold = snd_pcm_frames_to_bytes(AlsaPCMHandle, period_size);
|
||||||
// min 333ms
|
// buffer time/delay in ms
|
||||||
if (AlsaStartThreshold < (*freq * *channels * AudioBytesProSample) / 3U) {
|
delay = AudioBufferTime;
|
||||||
AlsaStartThreshold = (*freq * *channels * AudioBytesProSample) / 3U;
|
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
|
// no bigger, than the buffer
|
||||||
if (AlsaStartThreshold > RingBufferFreeBytes(AlsaRingBuffer)) {
|
if (AlsaStartThreshold > RingBufferFreeBytes(AlsaRingBuffer)) {
|
||||||
@@ -1127,6 +1154,7 @@ static void AlsaExit(void)
|
|||||||
RingBufferDel(AlsaRingBuffer);
|
RingBufferDel(AlsaRingBuffer);
|
||||||
AlsaRingBuffer = NULL;
|
AlsaRingBuffer = NULL;
|
||||||
}
|
}
|
||||||
|
AlsaFlushBuffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1282,6 +1310,8 @@ static void OssFlushBuffers(void)
|
|||||||
// OSS pcm polled
|
// OSS pcm polled
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef USE_AUDIO_THREAD
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Place samples in audio output queue.
|
** Place samples in audio output queue.
|
||||||
**
|
**
|
||||||
@@ -1308,6 +1338,8 @@ static void OssEnqueue(const void *samples, int count)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Play all samples possible, without blocking.
|
** Play all samples possible, without blocking.
|
||||||
*/
|
*/
|
||||||
@@ -1416,6 +1448,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.
|
** Initialize OSS pcm device.
|
||||||
**
|
**
|
||||||
@@ -1423,19 +1481,9 @@ static void OssThreadFlushBuffers(void)
|
|||||||
*/
|
*/
|
||||||
static void OssInitPCM(void)
|
static void OssInitPCM(void)
|
||||||
{
|
{
|
||||||
const char *device;
|
|
||||||
int fildes;
|
int fildes;
|
||||||
|
|
||||||
if (!(device = AudioPCMDevice)) {
|
fildes = OssOpenPCM(0);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
OssPcmFildes = fildes;
|
OssPcmFildes = fildes;
|
||||||
}
|
}
|
||||||
@@ -1568,6 +1616,7 @@ static uint64_t OssGetDelay(void)
|
|||||||
**
|
**
|
||||||
** @param freq sample frequency
|
** @param freq sample frequency
|
||||||
** @param channels number of channels
|
** @param channels number of channels
|
||||||
|
** @param use_ac3 use ac3/pass-through device
|
||||||
**
|
**
|
||||||
** @retval 0 everything ok
|
** @retval 0 everything ok
|
||||||
** @retval 1 didn't support frequency/channels combination
|
** @retval 1 didn't support frequency/channels combination
|
||||||
@@ -1575,10 +1624,11 @@ static uint64_t OssGetDelay(void)
|
|||||||
**
|
**
|
||||||
** @todo audio changes must be queued and done when the buffer is empty
|
** @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 ret;
|
||||||
int tmp;
|
int tmp;
|
||||||
|
int delay;
|
||||||
|
|
||||||
if (OssPcmFildes == -1) { // OSS not ready
|
if (OssPcmFildes == -1) { // OSS not ready
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1586,6 +1636,18 @@ static int OssSetup(int *freq, int *channels)
|
|||||||
// flush any buffered data
|
// flush any buffered data
|
||||||
AudioFlushBuffers();
|
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;
|
ret = 0;
|
||||||
|
|
||||||
tmp = AFMT_S16_NE; // native 16 bits
|
tmp = AFMT_S16_NE; // native 16 bits
|
||||||
@@ -1652,9 +1714,15 @@ static int OssSetup(int *freq, int *channels)
|
|||||||
}
|
}
|
||||||
// start when enough bytes for initial write
|
// start when enough bytes for initial write
|
||||||
OssStartThreshold = bi.bytes + tmp;
|
OssStartThreshold = bi.bytes + tmp;
|
||||||
// min 333ms
|
// buffer time/delay in ms
|
||||||
if (OssStartThreshold < (*freq * *channels * AudioBytesProSample) / 3U) {
|
delay = AudioBufferTime;
|
||||||
OssStartThreshold = (*freq * *channels * AudioBytesProSample) / 3U;
|
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
|
// no bigger, than the buffer
|
||||||
if (OssStartThreshold > RingBufferFreeBytes(OssRingBuffer)) {
|
if (OssStartThreshold > RingBufferFreeBytes(OssRingBuffer)) {
|
||||||
@@ -1692,6 +1760,7 @@ static void OssExit(void)
|
|||||||
close(OssMixerFildes);
|
close(OssMixerFildes);
|
||||||
OssMixerFildes = -1;
|
OssMixerFildes = -1;
|
||||||
}
|
}
|
||||||
|
OssFlushBuffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1770,7 +1839,8 @@ static void NoopSetVolume( __attribute__ ((unused))
|
|||||||
*/
|
*/
|
||||||
static int NoopSetup( __attribute__ ((unused))
|
static int NoopSetup( __attribute__ ((unused))
|
||||||
int *channels, __attribute__ ((unused))
|
int *channels, __attribute__ ((unused))
|
||||||
int *freq)
|
int *freq, __attribute__ ((unused))
|
||||||
|
int use_ac3)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1847,23 +1917,12 @@ static void *AudioPlayHandlerThread(void *dummy)
|
|||||||
}
|
}
|
||||||
Debug(3, "audio: thread channels %d sample-rate %d hz\n",
|
Debug(3, "audio: thread channels %d sample-rate %d hz\n",
|
||||||
AudioChannels, AudioSampleRate);
|
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
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Debug(3, "audio: play start\n");
|
Debug(3, "audio: play start\n");
|
||||||
UsedAudioModule->Thread();
|
AudioUsedModule->Thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
return dummy;
|
return dummy;
|
||||||
@@ -1899,6 +1958,7 @@ static void AudioExitThread(void)
|
|||||||
}
|
}
|
||||||
pthread_cond_destroy(&AudioStartCond);
|
pthread_cond_destroy(&AudioStartCond);
|
||||||
pthread_mutex_destroy(&AudioMutex);
|
pthread_mutex_destroy(&AudioMutex);
|
||||||
|
AudioThread = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1928,7 +1988,7 @@ static const AudioModule *AudioModules[] = {
|
|||||||
*/
|
*/
|
||||||
void AudioEnqueue(const void *samples, int count)
|
void AudioEnqueue(const void *samples, int count)
|
||||||
{
|
{
|
||||||
UsedAudioModule->Enqueue(samples, count);
|
AudioUsedModule->Enqueue(samples, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1936,7 +1996,7 @@ void AudioEnqueue(const void *samples, int count)
|
|||||||
*/
|
*/
|
||||||
void AudioFlushBuffers(void)
|
void AudioFlushBuffers(void)
|
||||||
{
|
{
|
||||||
UsedAudioModule->FlushBuffers();
|
AudioUsedModule->FlushBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1944,7 +2004,7 @@ void AudioFlushBuffers(void)
|
|||||||
*/
|
*/
|
||||||
void AudioPoller(void)
|
void AudioPoller(void)
|
||||||
{
|
{
|
||||||
UsedAudioModule->Poller();
|
AudioUsedModule->Poller();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1952,7 +2012,7 @@ void AudioPoller(void)
|
|||||||
*/
|
*/
|
||||||
int AudioFreeBytes(void)
|
int AudioFreeBytes(void)
|
||||||
{
|
{
|
||||||
return UsedAudioModule->FreeBytes();
|
return AudioUsedModule->FreeBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1962,7 +2022,7 @@ int AudioFreeBytes(void)
|
|||||||
*/
|
*/
|
||||||
uint64_t AudioGetDelay(void)
|
uint64_t AudioGetDelay(void)
|
||||||
{
|
{
|
||||||
return UsedAudioModule->GetDelay();
|
return AudioUsedModule->GetDelay();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2020,6 +2080,7 @@ void AudioSetVolume(int volume)
|
|||||||
**
|
**
|
||||||
** @param freq sample frequency
|
** @param freq sample frequency
|
||||||
** @param channels number of channels
|
** @param channels number of channels
|
||||||
|
** @param use_ac3 use ac3/pass-through device
|
||||||
**
|
**
|
||||||
** @retval 0 everything ok
|
** @retval 0 everything ok
|
||||||
** @retval 1 didn't support frequency/channels combination
|
** @retval 1 didn't support frequency/channels combination
|
||||||
@@ -2027,9 +2088,10 @@ void AudioSetVolume(int volume)
|
|||||||
**
|
**
|
||||||
** @todo audio changes must be queued and done when the buffer is empty
|
** @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
|
// invalid parameter
|
||||||
if (!freq || !channels || !*freq || !*channels) {
|
if (!freq || !channels || !*freq || !*channels) {
|
||||||
@@ -2039,9 +2101,9 @@ int AudioSetup(int *freq, int *channels)
|
|||||||
}
|
}
|
||||||
#ifdef USE_AUDIORING
|
#ifdef USE_AUDIORING
|
||||||
// FIXME: need to store possible combination and report this
|
// FIXME: need to store possible combination and report this
|
||||||
return AudioRingAdd(*freq, *channels);
|
return AudioRingAdd(*freq, *channels, use_ac3);
|
||||||
#endif
|
#endif
|
||||||
return UsedAudioModule->Setup(freq, channels);
|
return AudioUsedModule->Setup(freq, channels, use_ac3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2053,15 +2115,37 @@ int AudioSetup(int *freq, int *channels)
|
|||||||
*/
|
*/
|
||||||
void AudioSetDevice(const char *device)
|
void AudioSetDevice(const char *device)
|
||||||
{
|
{
|
||||||
AudioModuleName = "alsa"; // detect alsa/OSS
|
if (!AudioModuleName) {
|
||||||
if (!device[0]) {
|
AudioModuleName = "alsa"; // detect alsa/OSS
|
||||||
AudioModuleName = "noop";
|
if (!device[0]) {
|
||||||
} else if (device[0] == '/') {
|
AudioModuleName = "noop";
|
||||||
AudioModuleName = "oss";
|
} else if (device[0] == '/') {
|
||||||
|
AudioModuleName = "oss";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AudioPCMDevice = device;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Initialize audio output module.
|
** Initialize audio output module.
|
||||||
**
|
**
|
||||||
@@ -2089,27 +2173,27 @@ void AudioInit(void)
|
|||||||
//
|
//
|
||||||
for (u = 0; u < sizeof(AudioModules) / sizeof(*AudioModules); ++u) {
|
for (u = 0; u < sizeof(AudioModules) / sizeof(*AudioModules); ++u) {
|
||||||
if (!strcasecmp(name, AudioModules[u]->Name)) {
|
if (!strcasecmp(name, AudioModules[u]->Name)) {
|
||||||
UsedAudioModule = AudioModules[u];
|
AudioUsedModule = AudioModules[u];
|
||||||
Info(_("audio: '%s' output module used\n"), UsedAudioModule->Name);
|
Info(_("audio: '%s' output module used\n"), AudioUsedModule->Name);
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Error(_("audio: '%s' output module isn't supported\n"), name);
|
Error(_("audio: '%s' output module isn't supported\n"), name);
|
||||||
UsedAudioModule = &NoopModule;
|
AudioUsedModule = &NoopModule;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
#ifdef USE_AUDIORING
|
#ifdef USE_AUDIORING
|
||||||
AudioRingInit();
|
AudioRingInit();
|
||||||
#endif
|
#endif
|
||||||
UsedAudioModule->Init();
|
AudioUsedModule->Init();
|
||||||
freq = 48000;
|
freq = 48000;
|
||||||
chan = 2;
|
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"));
|
Error(_("audio: can't do initial setup\n"));
|
||||||
}
|
}
|
||||||
#ifdef USE_AUDIO_THREAD
|
#ifdef USE_AUDIO_THREAD
|
||||||
if (UsedAudioModule->Thread) { // supports threads
|
if (AudioUsedModule->Thread) { // supports threads
|
||||||
AudioInitThread();
|
AudioInitThread();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -2125,10 +2209,12 @@ void AudioExit(void)
|
|||||||
#ifdef USE_AUDIO_THREAD
|
#ifdef USE_AUDIO_THREAD
|
||||||
AudioExitThread();
|
AudioExitThread();
|
||||||
#endif
|
#endif
|
||||||
UsedAudioModule->Exit();
|
AudioUsedModule->Exit();
|
||||||
|
AudioUsedModule = &NoopModule;
|
||||||
#ifdef USE_AUDIORING
|
#ifdef USE_AUDIORING
|
||||||
AudioRingExit();
|
AudioRingExit();
|
||||||
#endif
|
#endif
|
||||||
|
AudioRunning = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUDIO_TEST
|
#ifdef AUDIO_TEST
|
||||||
|
|||||||
3
audio.h
3
audio.h
@@ -37,12 +37,13 @@ extern uint64_t AudioGetDelay(void); ///< get current audio delay
|
|||||||
extern void AudioSetClock(int64_t); ///< set audio clock base
|
extern void AudioSetClock(int64_t); ///< set audio clock base
|
||||||
extern int64_t AudioGetClock(); ///< get current audio clock
|
extern int64_t AudioGetClock(); ///< get current audio clock
|
||||||
extern void AudioSetVolume(int); ///< set volume
|
extern 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 AudioPlay(void); ///< play audio
|
||||||
//extern void AudioPause(void); ///< pause audio
|
//extern void AudioPause(void); ///< pause audio
|
||||||
|
|
||||||
extern void AudioSetDevice(const char *); ///< set PCM audio device
|
extern void AudioSetDevice(const char *); ///< set PCM audio device
|
||||||
|
extern void AudioSetDeviceAC3(const char *); ///< set Passthrough device
|
||||||
extern void AudioInit(void); ///< setup audio module
|
extern void AudioInit(void); ///< setup audio module
|
||||||
extern void AudioExit(void); ///< cleanup and exit audio module
|
extern void AudioExit(void); ///< cleanup and exit audio module
|
||||||
|
|
||||||
|
|||||||
42
codec.c
42
codec.c
@@ -320,20 +320,30 @@ static void Codec_draw_horiz_band(AVCodecContext * video_ctx,
|
|||||||
**
|
**
|
||||||
** @param hw_decoder video hardware decoder
|
** @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 *CodecVideoNewDecoder(VideoHwDecoder * hw_decoder)
|
||||||
{
|
{
|
||||||
VideoDecoder *decoder;
|
VideoDecoder *decoder;
|
||||||
|
|
||||||
if (!(decoder = calloc(1, sizeof(*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;
|
decoder->HwDecoder = hw_decoder;
|
||||||
|
|
||||||
return decoder;
|
return decoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Deallocate a video decoder context.
|
||||||
|
**
|
||||||
|
** @param decoder private video decoder
|
||||||
|
*/
|
||||||
|
void CodecVideoDelDecoder(VideoDecoder * decoder)
|
||||||
|
{
|
||||||
|
free(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Open video 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);
|
Debug(3, "codec: using codec %s or ID %#04x\n", name, codec_id);
|
||||||
|
|
||||||
|
if (decoder->VideoCtx) {
|
||||||
|
Error(_("codec: missing close\n"));
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// ffmpeg compatibility hack
|
// ffmpeg compatibility hack
|
||||||
//
|
//
|
||||||
@@ -548,13 +561,13 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
|
|||||||
video_ctx->frame_number, used);
|
video_ctx->frame_number, used);
|
||||||
}
|
}
|
||||||
if (used != pkt->size) {
|
if (used != pkt->size) {
|
||||||
if (used >= 0) {
|
if (used >= 0 && used < pkt->size) {
|
||||||
// some tv channels, produce this
|
// some tv channels, produce this
|
||||||
Debug(4,
|
Debug(4,
|
||||||
"codec: ooops didn't use complete video packet used %d of %d\n",
|
"codec: ooops didn't use complete video packet used %d of %d\n",
|
||||||
used, pkt->size);
|
used, pkt->size);
|
||||||
pkt->data += used;
|
|
||||||
pkt->size -= used;
|
pkt->size -= used;
|
||||||
|
pkt->data += used;
|
||||||
goto next_part;
|
goto next_part;
|
||||||
}
|
}
|
||||||
Debug(3, "codec: bad frame %d\n", used);
|
Debug(3, "codec: bad frame %d\n", used);
|
||||||
@@ -613,21 +626,29 @@ static char CodecPassthroughAC3; ///< pass ac3 through
|
|||||||
/**
|
/**
|
||||||
** Allocate a new audio decoder context.
|
** Allocate a new audio decoder context.
|
||||||
**
|
**
|
||||||
** @param hw_decoder video hardware decoder
|
** @returns private decoder pointer for audio decoder.
|
||||||
**
|
|
||||||
** @returns private decoder pointer for audio/video decoder.
|
|
||||||
*/
|
*/
|
||||||
AudioDecoder *CodecAudioNewDecoder(void)
|
AudioDecoder *CodecAudioNewDecoder(void)
|
||||||
{
|
{
|
||||||
AudioDecoder *audio_decoder;
|
AudioDecoder *audio_decoder;
|
||||||
|
|
||||||
if (!(audio_decoder = calloc(1, sizeof(*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;
|
return audio_decoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Deallocate an audio decoder context.
|
||||||
|
**
|
||||||
|
** @param decoder private audio decoder
|
||||||
|
*/
|
||||||
|
void CodecAudioDelDecoder(AudioDecoder * decoder)
|
||||||
|
{
|
||||||
|
free(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Open audio decoder.
|
** Open audio decoder.
|
||||||
**
|
**
|
||||||
@@ -794,6 +815,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
|||||||
if (audio_decoder->SampleRate != audio_ctx->sample_rate
|
if (audio_decoder->SampleRate != audio_ctx->sample_rate
|
||||||
|| audio_decoder->Channels != audio_ctx->channels) {
|
|| audio_decoder->Channels != audio_ctx->channels) {
|
||||||
int err;
|
int err;
|
||||||
|
int isAC3;
|
||||||
|
|
||||||
if (audio_decoder->ReSample) {
|
if (audio_decoder->ReSample) {
|
||||||
audio_resample_close(audio_decoder->ReSample);
|
audio_resample_close(audio_decoder->ReSample);
|
||||||
@@ -807,16 +829,18 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
|||||||
// SPDIF/HDMI passthrough
|
// SPDIF/HDMI passthrough
|
||||||
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
|
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
|
||||||
audio_decoder->HwChannels = 2;
|
audio_decoder->HwChannels = 2;
|
||||||
|
isAC3 = 1;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
audio_decoder->HwChannels = audio_ctx->channels;
|
audio_decoder->HwChannels = audio_ctx->channels;
|
||||||
|
isAC3 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// channels not support?
|
// channels not support?
|
||||||
if ((err =
|
if ((err =
|
||||||
AudioSetup(&audio_decoder->HwSampleRate,
|
AudioSetup(&audio_decoder->HwSampleRate,
|
||||||
&audio_decoder->HwChannels))) {
|
&audio_decoder->HwChannels, isAC3))) {
|
||||||
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
|
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
|
||||||
audio_ctx->sample_rate, audio_ctx->channels,
|
audio_ctx->sample_rate, audio_ctx->channels,
|
||||||
audio_decoder->HwSampleRate,
|
audio_decoder->HwSampleRate,
|
||||||
|
|||||||
6
codec.h
6
codec.h
@@ -40,6 +40,9 @@ 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 *);
|
||||||
|
|
||||||
|
/// Deallocate a video decoder context.
|
||||||
|
extern void CodecVideoDelDecoder(VideoDecoder *);
|
||||||
|
|
||||||
/// Open video codec.
|
/// Open video codec.
|
||||||
extern void CodecVideoOpen(VideoDecoder *, const char *, int);
|
extern void CodecVideoOpen(VideoDecoder *, const char *, int);
|
||||||
|
|
||||||
@@ -55,6 +58,9 @@ extern void CodecVideoFlushBuffers(VideoDecoder *);
|
|||||||
/// Allocate a new audio decoder context.
|
/// Allocate a new audio decoder context.
|
||||||
extern AudioDecoder *CodecAudioNewDecoder(void);
|
extern AudioDecoder *CodecAudioNewDecoder(void);
|
||||||
|
|
||||||
|
/// Deallocate an audio decoder context.
|
||||||
|
extern void CodecAudioDelDecoder(AudioDecoder *);
|
||||||
|
|
||||||
/// Open audio codec.
|
/// Open audio codec.
|
||||||
extern void CodecAudioOpen(AudioDecoder *, const char *, int);
|
extern void CodecAudioOpen(AudioDecoder *, const char *, int);
|
||||||
|
|
||||||
|
|||||||
2
misc.h
2
misc.h
@@ -86,7 +86,7 @@ static inline void Syslog(const int level, const char *format, ...)
|
|||||||
/**
|
/**
|
||||||
** Show fatal error.
|
** Show fatal error.
|
||||||
*/
|
*/
|
||||||
#define Fatal(fmt...) do { Error(fmt); exit(-1); } while (0)
|
#define Fatal(fmt...) do { Error(fmt); abort(); } while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Show warning.
|
** Show warning.
|
||||||
|
|||||||
403
softhddev.c
403
softhddev.c
@@ -39,6 +39,9 @@
|
|||||||
#define __USE_GNU
|
#define __USE_GNU
|
||||||
#endif
|
#endif
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#ifdef USE_JPEG
|
||||||
|
#include <jpeglib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "softhddev.h"
|
#include "softhddev.h"
|
||||||
@@ -58,8 +61,8 @@ static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static char ConfigFullscreen; ///< fullscreen modus
|
static char ConfigFullscreen; ///< fullscreen modus
|
||||||
static char ConfigSuspendClose = 1; ///< suspend should close devices
|
static char ConfigStartSuspended; ///< flag to start in suspend mode
|
||||||
static char ConfigSuspendX11 = 1; ///< suspend should stop x11
|
static char ConfigStartX11Server; ///< flag start the x11 server
|
||||||
|
|
||||||
static pthread_mutex_t SuspendLockMutex; ///< suspend lock mutex
|
static pthread_mutex_t SuspendLockMutex; ///< suspend lock mutex
|
||||||
|
|
||||||
@@ -123,6 +126,8 @@ static const uint16_t SampleRateTable[4] = {
|
|||||||
** FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4
|
** FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4
|
||||||
** Layer II & III:
|
** Layer II & III:
|
||||||
** FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
|
** FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
|
||||||
|
**
|
||||||
|
** @todo sometimes detects wrong position
|
||||||
*/
|
*/
|
||||||
static int FindAudioSync(const AVPacket * avpkt)
|
static int FindAudioSync(const AVPacket * avpkt)
|
||||||
{
|
{
|
||||||
@@ -209,15 +214,15 @@ int PlayAudio(const uint8_t * data, int size,
|
|||||||
if (VideoFreezed) { // video freezed
|
if (VideoFreezed) { // video freezed
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (SkipAudio || !MyAudioDecoder) { // skip audio
|
||||||
|
return size;
|
||||||
|
}
|
||||||
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
|
||||||
|
|
||||||
@@ -260,27 +265,17 @@ int PlayAudio(const uint8_t * data, int size,
|
|||||||
|
|
||||||
// Syncword - 0x0B77
|
// Syncword - 0x0B77
|
||||||
if (data[0] == 0x0B && data[1] == 0x77) {
|
if (data[0] == 0x0B && data[1] == 0x77) {
|
||||||
if (!MyAudioDecoder) {
|
|
||||||
MyAudioDecoder = CodecAudioNewDecoder();
|
|
||||||
AudioCodecID = CODEC_ID_NONE;
|
|
||||||
}
|
|
||||||
if (AudioCodecID != CODEC_ID_AC3) {
|
if (AudioCodecID != CODEC_ID_AC3) {
|
||||||
Debug(3, "[softhddev]%s: AC-3 %d\n", __FUNCTION__, id);
|
Debug(3, "[softhddev]%s: AC-3 %d\n", __FUNCTION__, id);
|
||||||
CodecAudioClose(MyAudioDecoder);
|
CodecAudioClose(MyAudioDecoder);
|
||||||
|
|
||||||
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AC3);
|
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AC3);
|
||||||
AudioCodecID = CODEC_ID_AC3;
|
AudioCodecID = CODEC_ID_AC3;
|
||||||
}
|
}
|
||||||
// Syncword - 0xFFFC - 0xFFFF
|
// Syncword - 0xFFFC - 0xFFFF
|
||||||
} else if (data[0] == 0xFF && (data[1] & 0xFC) == 0xFC) {
|
} else if (data[0] == 0xFF && (data[1] & 0xFC) == 0xFC) {
|
||||||
if (!MyAudioDecoder) {
|
|
||||||
MyAudioDecoder = CodecAudioNewDecoder();
|
|
||||||
AudioCodecID = CODEC_ID_NONE;
|
|
||||||
}
|
|
||||||
if (AudioCodecID != CODEC_ID_MP2) {
|
if (AudioCodecID != CODEC_ID_MP2) {
|
||||||
Debug(3, "[softhddev]%s: MP2 %d\n", __FUNCTION__, id);
|
Debug(3, "[softhddev]%s: MP2 %d\n", __FUNCTION__, id);
|
||||||
CodecAudioClose(MyAudioDecoder);
|
CodecAudioClose(MyAudioDecoder);
|
||||||
|
|
||||||
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
|
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
|
||||||
AudioCodecID = CODEC_ID_MP2;
|
AudioCodecID = CODEC_ID_MP2;
|
||||||
}
|
}
|
||||||
@@ -297,20 +292,17 @@ int PlayAudio(const uint8_t * data, int size,
|
|||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
return osize;
|
return osize;
|
||||||
}
|
}
|
||||||
if (!MyAudioDecoder) {
|
|
||||||
MyAudioDecoder = CodecAudioNewDecoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
avpkt->pts = AV_NOPTS_VALUE;
|
||||||
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
|
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
|
||||||
AudioCodecID = CODEC_ID_MP2;
|
AudioCodecID = CODEC_ID_MP2;
|
||||||
data += n;
|
data += n;
|
||||||
size -= n;
|
size -= n;
|
||||||
}
|
}
|
||||||
}
|
// no decoder or codec known
|
||||||
|
if (AudioCodecID == CODEC_ID_NONE) {
|
||||||
// no decoder or codec known
|
return osize;
|
||||||
if (!MyAudioDecoder || AudioCodecID == CODEC_ID_NONE) {
|
}
|
||||||
return osize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
avpkt->data = (void *)data;
|
avpkt->data = (void *)data;
|
||||||
@@ -347,7 +339,8 @@ void SetVolumeDevice(int volume)
|
|||||||
#include <alsa/iatomic.h> // portable atomic_t
|
#include <alsa/iatomic.h> // portable atomic_t
|
||||||
|
|
||||||
uint32_t VideoSwitch; ///< debug video switch ticks
|
uint32_t VideoSwitch; ///< debug video switch ticks
|
||||||
static volatile char NewVideoStream; ///< new video stream
|
static volatile char NewVideoStream; ///< flag new video stream
|
||||||
|
static VideoHwDecoder *MyHwDecoder; ///< video hw decoder
|
||||||
static VideoDecoder *MyVideoDecoder; ///< video decoder
|
static VideoDecoder *MyVideoDecoder; ///< video decoder
|
||||||
static enum CodecID VideoCodecID; ///< current codec id
|
static enum CodecID VideoCodecID; ///< current codec id
|
||||||
|
|
||||||
@@ -361,7 +354,7 @@ static volatile char Usr1Signal; ///< true got usr1 signal
|
|||||||
static AVPacket VideoPacketRb[VIDEO_PACKET_MAX];
|
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
|
atomic_t VideoPacketsFilled; ///< how many of the buffer is used
|
||||||
static volatile char VideoClearBuffers; ///< clear video buffers
|
static volatile char VideoClearBuffers; ///< clear video buffers
|
||||||
static volatile char SkipVideo; ///< skip video
|
static volatile char SkipVideo; ///< skip video
|
||||||
|
|
||||||
@@ -388,6 +381,7 @@ static void VideoPacketInit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_set(&VideoPacketsFilled, 0);
|
atomic_set(&VideoPacketsFilled, 0);
|
||||||
|
VideoPacketRead = VideoPacketWrite = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -460,10 +454,10 @@ static void VideoNextPacket(int codec_id)
|
|||||||
|
|
||||||
avpkt = &VideoPacketRb[VideoPacketWrite];
|
avpkt = &VideoPacketRb[VideoPacketWrite];
|
||||||
if (!avpkt->stream_index) { // ignore empty packets
|
if (!avpkt->stream_index) { // ignore empty packets
|
||||||
if (codec_id == CODEC_ID_NONE) {
|
if (codec_id != CODEC_ID_NONE) {
|
||||||
Debug(3, "video: possible stream change loss\n");
|
return;
|
||||||
}
|
}
|
||||||
return;
|
Debug(3, "video: possible stream change loss\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||||
@@ -477,6 +471,7 @@ static void VideoNextPacket(int codec_id)
|
|||||||
}
|
}
|
||||||
// clear area for decoder, always enough space allocated
|
// clear area for decoder, always enough space allocated
|
||||||
memset(avpkt->data + avpkt->stream_index, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
memset(avpkt->data + avpkt->stream_index, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
|
||||||
avpkt->priv = (void *)(size_t) codec_id;
|
avpkt->priv = (void *)(size_t) codec_id;
|
||||||
|
|
||||||
// advance packet write
|
// advance packet write
|
||||||
@@ -492,6 +487,50 @@ static void VideoNextPacket(int codec_id)
|
|||||||
avpkt->dts = AV_NOPTS_VALUE;
|
avpkt->dts = AV_NOPTS_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Fix packet for FFMpeg.
|
||||||
|
**
|
||||||
|
** Some tv-stations sends mulitple pictures in a singe PES packet.
|
||||||
|
** Current ffmpeg 0.10 and libav-0.8 has problems with this.
|
||||||
|
** Split the packet into single picture packets.
|
||||||
|
*/
|
||||||
|
void FixPacketForFFMpeg(VideoDecoder * MyVideoDecoder, AVPacket * avpkt)
|
||||||
|
{
|
||||||
|
uint8_t *p;
|
||||||
|
int n;
|
||||||
|
AVPacket tmp[1];
|
||||||
|
int first;
|
||||||
|
|
||||||
|
p = avpkt->data;
|
||||||
|
n = avpkt->size;
|
||||||
|
*tmp = *avpkt;
|
||||||
|
|
||||||
|
first = 1;
|
||||||
|
while (n > 4) {
|
||||||
|
// scan for picture header 0x00000100
|
||||||
|
if (!p[0] && !p[1] && p[2] == 0x01 && !p[3]) {
|
||||||
|
if (first) {
|
||||||
|
first = 0;
|
||||||
|
n -= 4;
|
||||||
|
p += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// packet has already an picture header
|
||||||
|
tmp->size = p - tmp->data;
|
||||||
|
CodecVideoDecode(MyVideoDecoder, tmp);
|
||||||
|
// time-stamp only valid for first packet
|
||||||
|
tmp->pts = AV_NOPTS_VALUE;
|
||||||
|
tmp->dts = AV_NOPTS_VALUE;
|
||||||
|
tmp->data = p;
|
||||||
|
tmp->size = n;
|
||||||
|
}
|
||||||
|
--n;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
CodecVideoDecode(MyVideoDecoder, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Decode from PES packet ringbuffer.
|
** Decode from PES packet ringbuffer.
|
||||||
*/
|
*/
|
||||||
@@ -539,8 +578,8 @@ int VideoDecode(void)
|
|||||||
CodecVideoClose(MyVideoDecoder);
|
CodecVideoClose(MyVideoDecoder);
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
// size can be zero
|
||||||
goto skip;
|
goto skip;
|
||||||
break;
|
|
||||||
case CODEC_ID_MPEG2VIDEO:
|
case CODEC_ID_MPEG2VIDEO:
|
||||||
if (last_codec_id != CODEC_ID_MPEG2VIDEO) {
|
if (last_codec_id != CODEC_ID_MPEG2VIDEO) {
|
||||||
last_codec_id = CODEC_ID_MPEG2VIDEO;
|
last_codec_id = CODEC_ID_MPEG2VIDEO;
|
||||||
@@ -566,7 +605,33 @@ int VideoDecode(void)
|
|||||||
avpkt->size = avpkt->stream_index;
|
avpkt->size = avpkt->stream_index;
|
||||||
avpkt->stream_index = 0;
|
avpkt->stream_index = 0;
|
||||||
|
|
||||||
CodecVideoDecode(MyVideoDecoder, avpkt);
|
if (0) {
|
||||||
|
static int done;
|
||||||
|
|
||||||
|
if (done < 2) {
|
||||||
|
int fildes;
|
||||||
|
int who_designed_this_is____;
|
||||||
|
|
||||||
|
if (done == 0)
|
||||||
|
fildes =
|
||||||
|
open("frame0.pes", O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||||
|
else if (done == 1)
|
||||||
|
fildes =
|
||||||
|
open("frame1.pes", O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||||
|
else
|
||||||
|
fildes =
|
||||||
|
open("frame2.pes", O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||||
|
done++;
|
||||||
|
who_designed_this_is____ = write(fildes, avpkt->data, avpkt->size);
|
||||||
|
close(fildes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_codec_id == CODEC_ID_MPEG2VIDEO) {
|
||||||
|
FixPacketForFFMpeg(MyVideoDecoder, avpkt);
|
||||||
|
} else {
|
||||||
|
CodecVideoDecode(MyVideoDecoder, avpkt);
|
||||||
|
}
|
||||||
|
|
||||||
avpkt->size = saved_size;
|
avpkt->size = saved_size;
|
||||||
|
|
||||||
@@ -592,16 +657,36 @@ static void StartVideo(void)
|
|||||||
}
|
}
|
||||||
VideoOsdInit();
|
VideoOsdInit();
|
||||||
if (!MyVideoDecoder) {
|
if (!MyVideoDecoder) {
|
||||||
VideoHwDecoder *hw_decoder;
|
if ((MyHwDecoder = VideoNewHwDecoder())) {
|
||||||
|
MyVideoDecoder = CodecVideoNewDecoder(MyHwDecoder);
|
||||||
if ((hw_decoder = VideoNewHwDecoder())) {
|
|
||||||
MyVideoDecoder = CodecVideoNewDecoder(hw_decoder);
|
|
||||||
}
|
}
|
||||||
VideoCodecID = CODEC_ID_NONE;
|
VideoCodecID = CODEC_ID_NONE;
|
||||||
}
|
}
|
||||||
VideoPacketInit();
|
VideoPacketInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Stop video.
|
||||||
|
*/
|
||||||
|
static void StopVideo(void)
|
||||||
|
{
|
||||||
|
VideoOsdExit();
|
||||||
|
VideoExit();
|
||||||
|
if (MyVideoDecoder) {
|
||||||
|
// FIXME: this can crash, hw decoder released by video exit
|
||||||
|
CodecVideoClose(MyVideoDecoder);
|
||||||
|
CodecVideoDelDecoder(MyVideoDecoder);
|
||||||
|
MyVideoDecoder = NULL;
|
||||||
|
}
|
||||||
|
if (MyHwDecoder) {
|
||||||
|
// done by exit: VideoDelHwDecoder(MyHwDecoder);
|
||||||
|
MyHwDecoder = NULL;
|
||||||
|
}
|
||||||
|
VideoPacketExit();
|
||||||
|
|
||||||
|
NewVideoStream = 1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -732,13 +817,15 @@ int PlayVideo(const uint8_t * data, int size)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
// FIXME: no valid mpeg2/h264 detection yet
|
|
||||||
|
|
||||||
check = data + 9 + n;
|
check = data + 9 + n;
|
||||||
if (0) {
|
if (0) {
|
||||||
printf("%02x: %02x %02x %02x %02x %02x\n", data[6], check[0], check[1],
|
printf("%02x: %02x %02x %02x %02x %02x\n", data[6], check[0], check[1],
|
||||||
check[2], check[3], check[4]);
|
check[2], check[3], check[4]);
|
||||||
}
|
}
|
||||||
|
// FIXME: no valid mpeg2/h264 detection yet
|
||||||
|
// FIXME: better skip all zero's >3 && 0x01 0x09 h264, >2 && 0x01 -> mpeg2
|
||||||
|
|
||||||
// PES_VIDEO_STREAM 0xE0 or PES start code
|
// PES_VIDEO_STREAM 0xE0 or PES start code
|
||||||
//(data[6] & 0xC0) != 0x80 ||
|
//(data[6] & 0xC0) != 0x80 ||
|
||||||
if ((!check[0] && !check[1] && check[2] == 0x1)) {
|
if ((!check[0] && !check[1] && check[2] == 0x1)) {
|
||||||
@@ -778,10 +865,15 @@ int PlayVideo(const uint8_t * data, int size)
|
|||||||
Debug(3, "video: not detected\n");
|
Debug(3, "video: not detected\n");
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
|
// incomplete packets produce artefacts after channel switch
|
||||||
|
// packet < 65526 is the last split packet, detect it here for
|
||||||
|
// better latency
|
||||||
|
if (size < 65526 && VideoCodecID == CODEC_ID_MPEG2VIDEO) {
|
||||||
// mpeg codec supports incomplete packets
|
// mpeg codec supports incomplete packets
|
||||||
// waiting for a full complete packages, increases needed delays
|
// waiting for a full complete packages, increases needed delays
|
||||||
|
VideoEnqueue(pts, check, size - 9 - n);
|
||||||
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
|
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,6 +883,82 @@ int PlayVideo(const uint8_t * data, int size)
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_JPEG
|
||||||
|
|
||||||
|
uint8_t *CreateJpeg(uint8_t * image, int raw_size, int *size, int quality,
|
||||||
|
int width, int height)
|
||||||
|
{
|
||||||
|
struct jpeg_compress_struct cinfo;
|
||||||
|
struct jpeg_error_mgr jerr;
|
||||||
|
JSAMPROW row_ptr[1];
|
||||||
|
int row_stride;
|
||||||
|
uint8_t *outbuf;
|
||||||
|
long unsigned int outsize;
|
||||||
|
|
||||||
|
outbuf = NULL;
|
||||||
|
outsize = 0;
|
||||||
|
cinfo.err = jpeg_std_error(&jerr);
|
||||||
|
jpeg_create_compress(&cinfo);
|
||||||
|
jpeg_mem_dest(&cinfo, &outbuf, &outsize);
|
||||||
|
|
||||||
|
cinfo.image_width = width;
|
||||||
|
cinfo.image_height = height;
|
||||||
|
cinfo.input_components = raw_size / height / width;
|
||||||
|
cinfo.in_color_space = JCS_RGB;
|
||||||
|
|
||||||
|
jpeg_set_defaults(&cinfo);
|
||||||
|
jpeg_set_quality(&cinfo, quality, TRUE);
|
||||||
|
jpeg_start_compress(&cinfo, TRUE);
|
||||||
|
|
||||||
|
row_stride = width * 3;
|
||||||
|
while (cinfo.next_scanline < cinfo.image_height) {
|
||||||
|
row_ptr[0] = &image[cinfo.next_scanline * row_stride];
|
||||||
|
jpeg_write_scanlines(&cinfo, row_ptr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_finish_compress(&cinfo);
|
||||||
|
jpeg_destroy_compress(&cinfo);
|
||||||
|
*size = outsize;
|
||||||
|
|
||||||
|
return outbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Grabs the currently visible screen image.
|
||||||
|
**
|
||||||
|
** @param size size of the returned data
|
||||||
|
** @param jpeg flag true, create JPEG data
|
||||||
|
** @param quality JPEG quality
|
||||||
|
** @param width number of horizontal pixels in the frame
|
||||||
|
** @param height number of vertical pixels in the frame
|
||||||
|
*/
|
||||||
|
uint8_t *GrabImage(int *size, int jpeg, int quality, int width, int height)
|
||||||
|
{
|
||||||
|
if (jpeg) {
|
||||||
|
#ifdef USE_JPEG
|
||||||
|
int raw_size;
|
||||||
|
uint8_t *image;
|
||||||
|
uint8_t *jpg_image;
|
||||||
|
|
||||||
|
raw_size = 0;
|
||||||
|
image = VideoGrab(&raw_size, &width, &height, 0);
|
||||||
|
jpg_image = CreateJpeg(image, raw_size, size, quality, width, height);
|
||||||
|
free(image);
|
||||||
|
return jpg_image;
|
||||||
|
#else
|
||||||
|
(void)quality;
|
||||||
|
Error(_("softhddev: jpeg grabbing not supported\n"));
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (width != -1 && height != -1) {
|
||||||
|
Warning(_("softhddev: scaling unsupported\n"));
|
||||||
|
}
|
||||||
|
return VideoGrab(size, &width, &height, 1);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -798,6 +966,10 @@ int PlayVideo(const uint8_t * data, int size)
|
|||||||
*/
|
*/
|
||||||
void SetPlayMode(void)
|
void SetPlayMode(void)
|
||||||
{
|
{
|
||||||
|
if (ConfigStartSuspended) { // ignore first call, if start suspended
|
||||||
|
ConfigStartSuspended = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
Resume();
|
Resume();
|
||||||
if (MyVideoDecoder) {
|
if (MyVideoDecoder) {
|
||||||
if (VideoCodecID != CODEC_ID_NONE) {
|
if (VideoCodecID != CODEC_ID_NONE) {
|
||||||
@@ -858,18 +1030,50 @@ void Freeze(void)
|
|||||||
void StillPicture(const uint8_t * data, int size)
|
void StillPicture(const uint8_t * data, int size)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
static uint8_t seq_end_mpeg[] = { 0x00, 0x00, 0x01, 0xB7 };
|
||||||
|
static uint8_t seq_end_h264[] = { 0x00, 0x00, 0x00, 0x01, 0x10 };
|
||||||
|
|
||||||
// must be a PES start code
|
// must be a PES start code
|
||||||
if (size < 9 || !data || data[0] || data[1] || data[2] != 0x01) {
|
if (size < 9 || !data || data[0] || data[1] || data[2] != 0x01) {
|
||||||
Error(_("[softhddev] invalid PES video packet\n"));
|
Error(_("[softhddev] invalid still video packet\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Clear(); // flush video buffers
|
if (VideoCodecID == CODEC_ID_NONE) {
|
||||||
|
// FIXME: should detect codec, see PlayVideo
|
||||||
|
Error(_("[softhddev] no codec known for still picture\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//Clear(); // flush video buffers
|
||||||
|
|
||||||
// +1 future for deinterlace
|
// +1 future for deinterlace
|
||||||
for (i = -1; i < (VideoCodecID == CODEC_ID_MPEG2VIDEO ? 3 : 17); ++i) {
|
for (i = -1; i < (VideoCodecID == CODEC_ID_MPEG2VIDEO ? 3 : 17); ++i) {
|
||||||
PlayVideo(data, size); // reference frames
|
//if ( 1 ) {
|
||||||
|
const uint8_t *split;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
// split the I-frame into single pes packets
|
||||||
|
split = data;
|
||||||
|
n = size;
|
||||||
|
do {
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = (split[4] << 8) + split[5];
|
||||||
|
if (len > n) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PlayVideo(split, len + 6); // feed it
|
||||||
|
split += 6 + len;
|
||||||
|
n -= 6 + len;
|
||||||
|
} while (n > 6);
|
||||||
|
VideoNextPacket(VideoCodecID); // terminate last packet
|
||||||
|
|
||||||
|
if (VideoCodecID == CODEC_ID_H264) {
|
||||||
|
VideoEnqueue(AV_NOPTS_VALUE, seq_end_h264, sizeof(seq_end_h264));
|
||||||
|
} else {
|
||||||
|
VideoEnqueue(AV_NOPTS_VALUE, seq_end_mpeg, sizeof(seq_end_mpeg));
|
||||||
|
}
|
||||||
|
VideoNextPacket(VideoCodecID); // terminate last packet
|
||||||
}
|
}
|
||||||
VideoNextPacket(VideoCodecID); // terminate last packet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -946,24 +1150,22 @@ 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 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\taudio device (fe. alsa: hw:0,0 oss: /dev/dsp)\n"
|
return " -a device\taudio device (fe. alsa: hw:0,0 oss: /dev/dsp)\n"
|
||||||
|
" -p device\taudio device (alsa only) for pass-through (hw:0,1)\n"
|
||||||
" -d display\tdisplay of x11 server (fe. :0.0)\n"
|
" -d display\tdisplay of x11 server (fe. :0.0)\n"
|
||||||
" -f\t\tstart with fullscreen window (only with window manager)\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\t\tstart x11 server\n";
|
" -x\t\tstart x11 server\n" " -s\t\tstart in suspended mode\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -978,10 +1180,13 @@ int ProcessArgs(int argc, char *const argv[])
|
|||||||
// Parse arguments.
|
// Parse arguments.
|
||||||
//
|
//
|
||||||
for (;;) {
|
for (;;) {
|
||||||
switch (getopt(argc, argv, "-a:d:fg:x")) {
|
switch (getopt(argc, argv, "-a:p:d:fg:xs")) {
|
||||||
case 'a': // audio device
|
case 'a': // audio device
|
||||||
AudioSetDevice(optarg);
|
AudioSetDevice(optarg);
|
||||||
continue;
|
continue;
|
||||||
|
case 'p': // pass-through audio device
|
||||||
|
AudioSetDeviceAC3(optarg);
|
||||||
|
continue;
|
||||||
case 'd': // x11 display name
|
case 'd': // x11 display name
|
||||||
X11DisplayName = optarg;
|
X11DisplayName = optarg;
|
||||||
continue;
|
continue;
|
||||||
@@ -999,6 +1204,9 @@ int ProcessArgs(int argc, char *const argv[])
|
|||||||
case 'x': // x11 server
|
case 'x': // x11 server
|
||||||
ConfigStartX11Server = 1;
|
ConfigStartX11Server = 1;
|
||||||
continue;
|
continue;
|
||||||
|
case 's': // start in suspend mode
|
||||||
|
ConfigStartSuspended = 1;
|
||||||
|
continue;
|
||||||
case EOF:
|
case EOF:
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
@@ -1117,22 +1325,18 @@ static void StartXServer(void)
|
|||||||
*/
|
*/
|
||||||
void SoftHdDeviceExit(void)
|
void SoftHdDeviceExit(void)
|
||||||
{
|
{
|
||||||
// lets hope that vdr does a good thead cleanup
|
// lets hope that vdr does a good thread cleanup
|
||||||
// no it doesn't do a good thread cleanup
|
|
||||||
if (MyVideoDecoder) {
|
AudioExit();
|
||||||
CodecVideoClose(MyVideoDecoder);
|
|
||||||
// FIXME: CodecDelVideoDecoder(MyVideoDecoder);
|
|
||||||
MyVideoDecoder = NULL;
|
|
||||||
}
|
|
||||||
if (MyAudioDecoder) {
|
if (MyAudioDecoder) {
|
||||||
CodecAudioClose(MyAudioDecoder);
|
CodecAudioClose(MyAudioDecoder);
|
||||||
// FIXME: CodecDelAudioDecoder(MyAudioDecoder);
|
CodecAudioDelDecoder(MyAudioDecoder);
|
||||||
MyAudioDecoder = NULL;
|
MyAudioDecoder = NULL;
|
||||||
}
|
}
|
||||||
|
NewAudioStream = 0;
|
||||||
|
|
||||||
|
StopVideo();
|
||||||
|
|
||||||
VideoOsdExit();
|
|
||||||
VideoExit();
|
|
||||||
AudioExit();
|
|
||||||
CodecExit();
|
CodecExit();
|
||||||
VideoPacketExit();
|
VideoPacketExit();
|
||||||
|
|
||||||
@@ -1140,8 +1344,34 @@ void SoftHdDeviceExit(void)
|
|||||||
Debug(3, "x-setup: Stop x11 server\n");
|
Debug(3, "x-setup: Stop x11 server\n");
|
||||||
|
|
||||||
if (X11ServerPid) {
|
if (X11ServerPid) {
|
||||||
|
int waittime;
|
||||||
|
int timeout;
|
||||||
|
pid_t wpid;
|
||||||
|
int status;
|
||||||
|
|
||||||
kill(X11ServerPid, SIGTERM);
|
kill(X11ServerPid, SIGTERM);
|
||||||
// FIXME: wait for x11 finishing
|
waittime = 0;
|
||||||
|
timeout = 500; // 0.5s
|
||||||
|
// wait for x11 finishing, with timeout
|
||||||
|
do {
|
||||||
|
wpid = waitpid(X11ServerPid, &status, WNOHANG);
|
||||||
|
if (wpid) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (waittime++ < timeout) {
|
||||||
|
usleep(1 * 1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
kill(X11ServerPid, SIGKILL);
|
||||||
|
} while (waittime < timeout);
|
||||||
|
if (wpid && WIFEXITED(status)) {
|
||||||
|
Debug(3, "x-setup: x11 server exited (%d)\n",
|
||||||
|
WEXITSTATUS(status));
|
||||||
|
}
|
||||||
|
if (wpid && WIFSIGNALED(status)) {
|
||||||
|
Debug(3, "x-setup: x11 server killed (%d)\n",
|
||||||
|
WTERMSIG(status));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1157,12 +1387,20 @@ void Start(void)
|
|||||||
StartXServer();
|
StartXServer();
|
||||||
}
|
}
|
||||||
CodecInit();
|
CodecInit();
|
||||||
// FIXME: AudioInit for HDMI after X11 startup
|
|
||||||
AudioInit();
|
|
||||||
if (!ConfigStartX11Server) {
|
|
||||||
StartVideo();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!ConfigStartSuspended) {
|
||||||
|
// FIXME: AudioInit for HDMI after X11 startup
|
||||||
|
AudioInit();
|
||||||
|
MyAudioDecoder = CodecAudioNewDecoder();
|
||||||
|
AudioCodecID = CODEC_ID_NONE;
|
||||||
|
|
||||||
|
if (!ConfigStartX11Server) {
|
||||||
|
StartVideo();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SkipVideo = 1;
|
||||||
|
SkipAudio = 1;
|
||||||
|
}
|
||||||
pthread_mutex_init(&SuspendLockMutex, NULL);
|
pthread_mutex_init(&SuspendLockMutex, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1191,8 +1429,12 @@ void MainThreadHook(void)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
** Suspend plugin.
|
** Suspend plugin.
|
||||||
|
**
|
||||||
|
** @param video suspend closes video
|
||||||
|
** @param audio suspend closes audio
|
||||||
|
** @param dox11 suspend closes x11 server
|
||||||
*/
|
*/
|
||||||
void Suspend(void)
|
void Suspend(int video, int audio, int dox11)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&SuspendLockMutex);
|
pthread_mutex_lock(&SuspendLockMutex);
|
||||||
if (SkipVideo && SkipAudio) { // already suspended
|
if (SkipVideo && SkipAudio) { // already suspended
|
||||||
@@ -1206,13 +1448,25 @@ void Suspend(void)
|
|||||||
SkipAudio = 1;
|
SkipAudio = 1;
|
||||||
pthread_mutex_unlock(&SuspendLockMutex);
|
pthread_mutex_unlock(&SuspendLockMutex);
|
||||||
|
|
||||||
if (ConfigSuspendClose) {
|
if (audio || video) {
|
||||||
pthread_mutex_lock(&SuspendLockMutex);
|
pthread_mutex_lock(&SuspendLockMutex);
|
||||||
// FIXME: close audio
|
|
||||||
// FIXME: close video
|
if (audio) {
|
||||||
|
AudioExit();
|
||||||
|
if (MyAudioDecoder) {
|
||||||
|
CodecAudioClose(MyAudioDecoder);
|
||||||
|
CodecAudioDelDecoder(MyAudioDecoder);
|
||||||
|
MyAudioDecoder = NULL;
|
||||||
|
}
|
||||||
|
NewAudioStream = 0;
|
||||||
|
}
|
||||||
|
if (video) {
|
||||||
|
StopVideo();
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&SuspendLockMutex);
|
pthread_mutex_unlock(&SuspendLockMutex);
|
||||||
}
|
}
|
||||||
if (ConfigSuspendX11) {
|
if (dox11) {
|
||||||
// FIXME: stop x11, if started
|
// FIXME: stop x11, if started
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1228,13 +1482,20 @@ void Resume(void)
|
|||||||
|
|
||||||
Debug(3, "[softhddev]%s:\n", __FUNCTION__);
|
Debug(3, "[softhddev]%s:\n", __FUNCTION__);
|
||||||
|
|
||||||
if (ConfigSuspendX11) {
|
pthread_mutex_lock(&SuspendLockMutex);
|
||||||
|
// FIXME: start x11
|
||||||
|
|
||||||
|
if (!MyHwDecoder) { // video not running
|
||||||
|
StartVideo();
|
||||||
}
|
}
|
||||||
if (ConfigSuspendClose) {
|
if (!MyAudioDecoder) { // audio not running
|
||||||
pthread_mutex_lock(&SuspendLockMutex);
|
AudioInit();
|
||||||
pthread_mutex_unlock(&SuspendLockMutex);
|
MyAudioDecoder = CodecAudioNewDecoder();
|
||||||
|
AudioCodecID = CODEC_ID_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkipVideo = 0;
|
SkipVideo = 0;
|
||||||
SkipAudio = 0;
|
SkipAudio = 0;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&SuspendLockMutex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ extern "C"
|
|||||||
extern int PlayVideo(const uint8_t *, int);
|
extern int PlayVideo(const uint8_t *, int);
|
||||||
/// C plugin play TS video packet
|
/// C plugin play TS video packet
|
||||||
extern void PlayTsVideo(const uint8_t *, int);
|
extern void PlayTsVideo(const uint8_t *, int);
|
||||||
|
/// C plugin grab an image
|
||||||
|
extern uint8_t *GrabImage(int *, int, int, int, int);
|
||||||
|
|
||||||
/// C plugin set play mode
|
/// C plugin set play mode
|
||||||
extern void SetPlayMode(void);
|
extern void SetPlayMode(void);
|
||||||
@@ -77,7 +79,7 @@ extern "C"
|
|||||||
extern void MainThreadHook(void);
|
extern void MainThreadHook(void);
|
||||||
|
|
||||||
/// Suspend plugin
|
/// Suspend plugin
|
||||||
extern void Suspend(void);
|
extern void Suspend(int, int, int);
|
||||||
/// Resume plugin
|
/// Resume plugin
|
||||||
extern void Resume(void);
|
extern void Resume(void);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
301
softhddevice.cpp
301
softhddevice.cpp
@@ -42,7 +42,7 @@ extern "C"
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static const char *const VERSION = "0.3.5";
|
static const char *const VERSION = "0.4.6";
|
||||||
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");
|
||||||
|
|
||||||
@@ -61,6 +61,8 @@ static const char *const Resolution[RESOLUTIONS] = {
|
|||||||
static char ConfigMakePrimary; ///< config primary wanted
|
static char ConfigMakePrimary; ///< config primary wanted
|
||||||
static char ConfigHideMainMenuEntry; ///< config hide main menu entry
|
static char ConfigHideMainMenuEntry; ///< config hide main menu entry
|
||||||
|
|
||||||
|
static int ConfigVideoSkipLines; ///< config skip lines top/bottom
|
||||||
|
|
||||||
/// config deinterlace
|
/// config deinterlace
|
||||||
static int ConfigVideoDeinterlace[RESOLUTIONS];
|
static int ConfigVideoDeinterlace[RESOLUTIONS];
|
||||||
|
|
||||||
@@ -79,6 +81,13 @@ 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 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
|
static volatile char DoMakePrimary; ///< flag switch primary
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -123,7 +132,7 @@ extern "C" void FeedKeyPress(const char *keymap, const char *key, int repeat,
|
|||||||
csoft = new cSoftRemote(keymap);
|
csoft = new cSoftRemote(keymap);
|
||||||
}
|
}
|
||||||
|
|
||||||
dsyslog("[softhddev]%s %s, %s\n", __FUNCTION__, keymap, key);
|
//dsyslog("[softhddev]%s %s, %s\n", __FUNCTION__, keymap, key);
|
||||||
csoft->Put(key, repeat, release);
|
csoft->Put(key, repeat, release);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,12 +154,13 @@ class cSoftOsd:public cOsd
|
|||||||
cSoftOsd::cSoftOsd(int left, int top, uint level)
|
cSoftOsd::cSoftOsd(int left, int top, uint level)
|
||||||
:cOsd(left, top, level)
|
:cOsd(left, top, level)
|
||||||
{
|
{
|
||||||
// FIXME: OsdWidth/OsdHeight not correct!
|
/* FIXME: OsdWidth/OsdHeight not correct!
|
||||||
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;
|
this->Level = level;
|
||||||
//SetActive(true);
|
SetActive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
cSoftOsd::~cSoftOsd(void)
|
cSoftOsd::~cSoftOsd(void)
|
||||||
@@ -292,8 +302,8 @@ void cSoftOsd::Flush(void)
|
|||||||
h = pm->ViewPort().Height();
|
h = pm->ViewPort().Height();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dsyslog("[softhddev]%s: draw %dx%d+%d+%d %p\n", __FUNCTION__, w, h, x,
|
dsyslog("[softhddev]%s: draw %dx%d+%d+%d %p\n", __FUNCTION__, w, h,
|
||||||
y, pm->Data());
|
x, y, pm->Data());
|
||||||
*/
|
*/
|
||||||
|
|
||||||
OsdDrawARGB(x, y, w, h, pm->Data());
|
OsdDrawARGB(x, y, w, h, pm->Data());
|
||||||
@@ -355,6 +365,7 @@ class cMenuSetupSoft:public cMenuSetupPage
|
|||||||
protected:
|
protected:
|
||||||
int MakePrimary;
|
int MakePrimary;
|
||||||
int HideMainMenuEntry;
|
int HideMainMenuEntry;
|
||||||
|
int SkipLines;
|
||||||
int Scaling[RESOLUTIONS];
|
int Scaling[RESOLUTIONS];
|
||||||
int Deinterlace[RESOLUTIONS];
|
int Deinterlace[RESOLUTIONS];
|
||||||
int SkipChromaDeinterlace[RESOLUTIONS];
|
int SkipChromaDeinterlace[RESOLUTIONS];
|
||||||
@@ -362,6 +373,11 @@ class cMenuSetupSoft:public cMenuSetupPage
|
|||||||
int Sharpen[RESOLUTIONS];
|
int Sharpen[RESOLUTIONS];
|
||||||
int AudioDelay;
|
int AudioDelay;
|
||||||
int AudioPassthrough;
|
int AudioPassthrough;
|
||||||
|
int AutoCropInterval;
|
||||||
|
int AutoCropDelay;
|
||||||
|
int AutoCropTolerance;
|
||||||
|
int SuspendClose;
|
||||||
|
int SuspendX11;
|
||||||
protected:
|
protected:
|
||||||
virtual void Store(void);
|
virtual void Store(void);
|
||||||
public:
|
public:
|
||||||
@@ -370,6 +386,8 @@ class cMenuSetupSoft:public cMenuSetupPage
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
** Create a seperator item.
|
** Create a seperator item.
|
||||||
|
**
|
||||||
|
** @param label text inside separator
|
||||||
*/
|
*/
|
||||||
static inline cOsdItem *SeparatorItem(const char *label)
|
static inline cOsdItem *SeparatorItem(const char *label)
|
||||||
{
|
{
|
||||||
@@ -412,6 +430,11 @@ cMenuSetupSoft::cMenuSetupSoft(void)
|
|||||||
// video
|
// video
|
||||||
//
|
//
|
||||||
Add(SeparatorItem(tr("Video")));
|
Add(SeparatorItem(tr("Video")));
|
||||||
|
|
||||||
|
SkipLines = ConfigVideoSkipLines;
|
||||||
|
Add(new cMenuEditIntItem(tr("Skip lines top+bot (pixel)"), &SkipLines, 0,
|
||||||
|
64));
|
||||||
|
|
||||||
for (i = 0; i < RESOLUTIONS; ++i) {
|
for (i = 0; i < RESOLUTIONS; ++i) {
|
||||||
Add(SeparatorItem(resolution[i]));
|
Add(SeparatorItem(resolution[i]));
|
||||||
Scaling[i] = ConfigVideoScaling[i];
|
Scaling[i] = ConfigVideoScaling[i];
|
||||||
@@ -439,6 +462,29 @@ cMenuSetupSoft::cMenuSetupSoft(void)
|
|||||||
AudioPassthrough = ConfigAudioPassthrough;
|
AudioPassthrough = ConfigAudioPassthrough;
|
||||||
Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2,
|
Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2,
|
||||||
passthrough));
|
passthrough));
|
||||||
|
//
|
||||||
|
// auto-crop
|
||||||
|
//
|
||||||
|
Add(SeparatorItem(tr("Auto-crop")));
|
||||||
|
AutoCropInterval = ConfigAutoCropInterval;
|
||||||
|
Add(new cMenuEditIntItem(tr("autocrop interval (frames)"),
|
||||||
|
&AutoCropInterval, 0, 200));
|
||||||
|
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")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -452,6 +498,9 @@ void cMenuSetupSoft::Store(void)
|
|||||||
SetupStore("HideMainMenuEntry", ConfigHideMainMenuEntry =
|
SetupStore("HideMainMenuEntry", ConfigHideMainMenuEntry =
|
||||||
HideMainMenuEntry);
|
HideMainMenuEntry);
|
||||||
|
|
||||||
|
SetupStore("SkipLines", ConfigVideoSkipLines = SkipLines);
|
||||||
|
VideoSetSkipLines(ConfigVideoSkipLines);
|
||||||
|
|
||||||
for (i = 0; i < RESOLUTIONS; ++i) {
|
for (i = 0; i < RESOLUTIONS; ++i) {
|
||||||
char buf[128];
|
char buf[128];
|
||||||
|
|
||||||
@@ -478,6 +527,91 @@ void cMenuSetupSoft::Store(void)
|
|||||||
VideoSetAudioDelay(ConfigVideoAudioDelay);
|
VideoSetAudioDelay(ConfigVideoAudioDelay);
|
||||||
SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough);
|
SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough);
|
||||||
CodecSetAudioPassthrough(ConfigAudioPassthrough);
|
CodecSetAudioPassthrough(ConfigAudioPassthrough);
|
||||||
|
|
||||||
|
SetupStore("AutoCrop.Interval", ConfigAutoCropInterval = AutoCropInterval);
|
||||||
|
SetupStore("AutoCrop.Delay", ConfigAutoCropDelay = AutoCropDelay);
|
||||||
|
SetupStore("AutoCrop.Tolerance", ConfigAutoCropTolerance =
|
||||||
|
AutoCropTolerance);
|
||||||
|
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay,
|
||||||
|
ConfigAutoCropTolerance);
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
cSoftHdPlayer * Player;
|
||||||
|
public:
|
||||||
|
virtual void Hide(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual eOSState ProcessKey(eKeys);
|
||||||
|
|
||||||
|
cSoftHdControl(void);
|
||||||
|
|
||||||
|
virtual ~ cSoftHdControl();
|
||||||
|
};
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -488,7 +622,7 @@ class cSoftHdDevice:public cDevice
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cSoftHdDevice(void);
|
cSoftHdDevice(void);
|
||||||
virtual ~ cSoftHdDevice(void);
|
virtual ~ cSoftHdDevice(void);
|
||||||
|
|
||||||
virtual bool HasDecoder(void) const;
|
virtual bool HasDecoder(void) const;
|
||||||
virtual bool CanReplay(void) const;
|
virtual bool CanReplay(void) const;
|
||||||
@@ -503,6 +637,7 @@ 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 SetVideoDisplayFormat(eVideoDisplayFormat);
|
||||||
virtual void GetVideoSize(int &, int &, double &);
|
virtual void GetVideoSize(int &, int &, double &);
|
||||||
virtual void GetOsdSize(int &, int &, double &);
|
virtual void GetOsdSize(int &, int &, double &);
|
||||||
virtual int PlayVideo(const uchar *, int);
|
virtual int PlayVideo(const uchar *, int);
|
||||||
@@ -524,13 +659,13 @@ class cSoftHdDevice:public cDevice
|
|||||||
#if 0
|
#if 0
|
||||||
// SPU facilities
|
// SPU facilities
|
||||||
private:
|
private:
|
||||||
cDvbSpuDecoder * spuDecoder;
|
cDvbSpuDecoder * spuDecoder;
|
||||||
public:
|
public:
|
||||||
virtual cSpuDecoder * GetSpuDecoder(void);
|
virtual cSpuDecoder * GetSpuDecoder(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void MakePrimaryDevice(bool);
|
virtual void MakePrimaryDevice(bool);
|
||||||
};
|
};
|
||||||
|
|
||||||
cSoftHdDevice::cSoftHdDevice(void)
|
cSoftHdDevice::cSoftHdDevice(void)
|
||||||
@@ -581,16 +716,22 @@ bool cSoftHdDevice::HasDecoder(void) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Returns true if this device can currently start a replay session.
|
||||||
|
*/
|
||||||
bool cSoftHdDevice::CanReplay(void) const
|
bool cSoftHdDevice::CanReplay(void) const
|
||||||
{
|
{
|
||||||
return true;
|
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:
|
case pmAudioVideo:
|
||||||
break;
|
break;
|
||||||
case pmAudioOnly:
|
case pmAudioOnly:
|
||||||
@@ -601,18 +742,24 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
|
|||||||
case pmNone:
|
case pmNone:
|
||||||
return true;
|
return true;
|
||||||
case pmExtern_THIS_SHOULD_BE_AVOIDED:
|
case pmExtern_THIS_SHOULD_BE_AVOIDED:
|
||||||
break;
|
dsyslog("[softhddev] play mode external\n");
|
||||||
|
Suspend(1, 1, 0);
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
dsyslog("[softhddev]playmode not implemented... %d\n", PlayMode);
|
dsyslog("[softhddev]playmode not implemented... %d\n", play_mode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
::SetPlayMode();
|
::SetPlayMode();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Gets the current System Time Counter, which can be used to
|
||||||
|
** synchronize audio, video and subtitles.
|
||||||
|
*/
|
||||||
int64_t cSoftHdDevice::GetSTC(void)
|
int64_t cSoftHdDevice::GetSTC(void)
|
||||||
{
|
{
|
||||||
// dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||||
|
|
||||||
return::VideoGetClock();
|
return::VideoGetClock();
|
||||||
}
|
}
|
||||||
@@ -674,8 +821,8 @@ void cSoftHdDevice::SetVolumeDevice(int volume)
|
|||||||
*/
|
*/
|
||||||
void cSoftHdDevice::StillPicture(const uchar * data, int length)
|
void cSoftHdDevice::StillPicture(const uchar * data, int length)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s: %s\n", __FUNCTION__,
|
dsyslog("[softhddev]%s: %s %p %d\n", __FUNCTION__,
|
||||||
data[0] == 0x47 ? "ts" : "pes");
|
data[0] == 0x47 ? "ts" : "pes", data, length);
|
||||||
|
|
||||||
if (data[0] == 0x47) { // ts sync
|
if (data[0] == 0x47) { // ts sync
|
||||||
cDevice::StillPicture(data, length);
|
cDevice::StillPicture(data, length);
|
||||||
@@ -694,7 +841,7 @@ void cSoftHdDevice::StillPicture(const uchar * data, int length)
|
|||||||
bool cSoftHdDevice::Poll(
|
bool cSoftHdDevice::Poll(
|
||||||
__attribute__ ((unused)) cPoller & poller, int timeout_ms)
|
__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);
|
return::Poll(timeout_ms);
|
||||||
}
|
}
|
||||||
@@ -713,6 +860,28 @@ 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 FIXME: this function isn't called on the initial channel
|
||||||
|
*/
|
||||||
|
void cSoftHdDevice::
|
||||||
|
SetVideoDisplayFormat(eVideoDisplayFormat video_display_format)
|
||||||
|
{
|
||||||
|
static int last = -1;
|
||||||
|
|
||||||
|
cDevice::SetVideoDisplayFormat(video_display_format);
|
||||||
|
|
||||||
|
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Returns the width, height and video_aspect ratio of the currently
|
** Returns the width, height and video_aspect ratio of the currently
|
||||||
** displayed video material.
|
** displayed video material.
|
||||||
@@ -810,13 +979,22 @@ int cSoftHdDevice::PlayTsAudio(const uchar * data, int length)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int sizex,
|
/**
|
||||||
int sizey)
|
** Grabs the currently visible screen image.
|
||||||
|
**
|
||||||
|
** @param size size of the returned data
|
||||||
|
** @param jpeg flag true, create JPEG data
|
||||||
|
** @param quality JPEG quality
|
||||||
|
** @param width number of horizontal pixels in the frame
|
||||||
|
** @param height number of vertical pixels in the frame
|
||||||
|
*/
|
||||||
|
uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int width,
|
||||||
|
int height)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s: %d, %d, %d, %dx%d\n", __FUNCTION__, size, jpeg,
|
dsyslog("[softhddev]%s: %d, %d, %d, %dx%d\n", __FUNCTION__, size, jpeg,
|
||||||
quality, sizex, sizey);
|
quality, width, height);
|
||||||
|
|
||||||
return NULL;
|
return::GrabImage(&size, jpeg, quality, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -835,7 +1013,7 @@ class cPluginSoftHdDevice:public cPlugin
|
|||||||
virtual bool Initialize(void);
|
virtual bool Initialize(void);
|
||||||
virtual bool Start(void);
|
virtual bool Start(void);
|
||||||
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);
|
||||||
@@ -934,9 +1112,14 @@ void cPluginSoftHdDevice::Stop(void)
|
|||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Perform any cleanup or other regular tasks.
|
||||||
|
*/
|
||||||
void cPluginSoftHdDevice::Housekeeping(void)
|
void cPluginSoftHdDevice::Housekeeping(void)
|
||||||
{
|
{
|
||||||
// Perform any cleanup or other regular tasks.
|
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||||
|
|
||||||
|
// ::Housekeeping();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -956,11 +1139,14 @@ const char *cPluginSoftHdDevice::MainMenuEntry(void)
|
|||||||
*/
|
*/
|
||||||
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
|
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||||
|
|
||||||
cDevice::PrimaryDevice()->StopReplay();
|
//MyDevice->StopReplay();
|
||||||
Suspend();
|
cControl::Launch(new cSoftHdControl);
|
||||||
|
cControl::Attach();
|
||||||
|
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
|
||||||
if (ShutdownHandler.GetUserInactiveTime()) {
|
if (ShutdownHandler.GetUserInactiveTime()) {
|
||||||
|
dsyslog("[softhddev]%s: set user inactive\n", __FUNCTION__);
|
||||||
ShutdownHandler.SetUserInactive();
|
ShutdownHandler.SetUserInactive();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -983,7 +1169,7 @@ void cPluginSoftHdDevice::MainThreadHook(void)
|
|||||||
// check if user is inactive, automatic enter suspend mode
|
// check if user is inactive, automatic enter suspend mode
|
||||||
if (ShutdownHandler.IsUserInactive()) {
|
if (ShutdownHandler.IsUserInactive()) {
|
||||||
// this is regular called, but guarded against double calls
|
// this is regular called, but guarded against double calls
|
||||||
Suspend();
|
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
|
||||||
}
|
}
|
||||||
|
|
||||||
::MainThreadHook();
|
::MainThreadHook();
|
||||||
@@ -1001,11 +1187,15 @@ cMenuSetupPage *cPluginSoftHdDevice::SetupMenu(void)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
** Parse setup parameters
|
** Parse setup parameters
|
||||||
|
**
|
||||||
|
** @param name paramter name (case sensetive)
|
||||||
|
** @param value value as string
|
||||||
|
**
|
||||||
|
** @returns true if the parameter is supported.
|
||||||
*/
|
*/
|
||||||
bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char buf[128];
|
|
||||||
|
|
||||||
//dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
|
//dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
|
||||||
|
|
||||||
@@ -1017,7 +1207,13 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
|||||||
ConfigHideMainMenuEntry = atoi(value);
|
ConfigHideMainMenuEntry = atoi(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(name, "SkipLines")) {
|
||||||
|
VideoSetSkipLines(ConfigVideoSkipLines = atoi(value));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
for (i = 0; i < RESOLUTIONS; ++i) {
|
for (i = 0; i < RESOLUTIONS; ++i) {
|
||||||
|
char buf[128];
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
|
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
|
||||||
if (!strcmp(name, buf)) {
|
if (!strcmp(name, buf)) {
|
||||||
ConfigVideoScaling[i] = atoi(value);
|
ConfigVideoScaling[i] = atoi(value);
|
||||||
@@ -1050,6 +1246,7 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(name, "AudioDelay")) {
|
if (!strcmp(name, "AudioDelay")) {
|
||||||
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
|
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
|
||||||
return true;
|
return true;
|
||||||
@@ -1059,6 +1256,30 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(name, "AutoCrop.Interval")) {
|
||||||
|
VideoSetAutoCrop(ConfigAutoCropInterval =
|
||||||
|
atoi(value), ConfigAutoCropDelay, ConfigAutoCropTolerance);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!strcmp(name, "AutoCrop.Delay")) {
|
||||||
|
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay =
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1087,8 +1308,8 @@ const char **cPluginSoftHdDevice::SVDRPHelpPages(void)
|
|||||||
{
|
{
|
||||||
// FIXME: translation?
|
// FIXME: translation?
|
||||||
static const char *text[] = {
|
static const char *text[] = {
|
||||||
"SUSP\n",
|
"SUSP\n" " Suspend plugin.\n",
|
||||||
" Suspend plugin",
|
"RESU\n" " Resume plugin.\n",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1103,9 +1324,19 @@ cString cPluginSoftHdDevice::SVDRPCommand(const char *command,
|
|||||||
__attribute__ ((unused)) int &reply_code)
|
__attribute__ ((unused)) int &reply_code)
|
||||||
{
|
{
|
||||||
if (!strcasecmp(command, "SUSP")) {
|
if (!strcasecmp(command, "SUSP")) {
|
||||||
Suspend();
|
cControl::Launch(new cSoftHdControl);
|
||||||
|
cControl::Attach();
|
||||||
|
Suspend(ConfigSuspendClose, ConfigSuspendClose, ConfigSuspendX11);
|
||||||
return "SoftHdDevice is suspended";
|
return "SoftHdDevice is suspended";
|
||||||
}
|
}
|
||||||
|
if (!strcasecmp(command, "RESU")) {
|
||||||
|
if (ShutdownHandler.GetUserInactiveTime()) {
|
||||||
|
ShutdownHandler.SetUserInactiveTimeout();
|
||||||
|
}
|
||||||
|
Resume();
|
||||||
|
cControl::Shutdown(); // not need, if not suspended
|
||||||
|
return "SoftHdDevice is resumed";
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ SRC_URI=""
|
|||||||
LICENSE="AGPL-3"
|
LICENSE="AGPL-3"
|
||||||
SLOT="0"
|
SLOT="0"
|
||||||
KEYWORDS="~x86 ~amd64"
|
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.7
|
||||||
x11-libs/xcb-util
|
x11-libs/xcb-util
|
||||||
@@ -40,6 +40,7 @@ DEPEND=">=x11-libs/libxcb-1.7
|
|||||||
vaapi? ( x11-libs/libva )
|
vaapi? ( x11-libs/libva )
|
||||||
alsa? ( media-libs/alsa-lib )
|
alsa? ( media-libs/alsa-lib )
|
||||||
oss? ( sys-kernel/linux-headers )
|
oss? ( sys-kernel/linux-headers )
|
||||||
|
jpeg? ( virtual/jpeg )
|
||||||
"
|
"
|
||||||
|
|
||||||
src_prepare() {
|
src_prepare() {
|
||||||
@@ -49,11 +50,12 @@ src_prepare() {
|
|||||||
src_compile() {
|
src_compile() {
|
||||||
local myconf
|
local myconf
|
||||||
|
|
||||||
myconf=""
|
myconf="-DHAVE_PTHREAD_NAME"
|
||||||
use vdpau && myconf="${myconf} -DUSE_VDPAU"
|
use vdpau && myconf="${myconf} -DUSE_VDPAU"
|
||||||
use vaapi && myconf="${myconf} -DUSE_VAAPI"
|
use vaapi && myconf="${myconf} -DUSE_VAAPI"
|
||||||
use alsa && myconf="${myconf} -DUSE_ALSA"
|
use alsa && myconf="${myconf} -DUSE_ALSA"
|
||||||
use oss && myconf="${myconf} -DUSE_OSS"
|
use oss && myconf="${myconf} -DUSE_OSS"
|
||||||
|
use jpeg && myconf="${myconf} -DUSE_JPEG"
|
||||||
|
|
||||||
emake all CC="$(tc-getCC)" CFLAGS="${CFLAGS}" \
|
emake all CC="$(tc-getCC)" CFLAGS="${CFLAGS}" \
|
||||||
LDFLAGS="${LDFLAGS}" CONFIG="${myconf}" LIBDIR="." || die
|
LDFLAGS="${LDFLAGS}" CONFIG="${myconf}" LIBDIR="." || die
|
||||||
|
|||||||
25
video.h
25
video.h
@@ -47,16 +47,17 @@ extern unsigned VideoGetSurface(VideoHwDecoder *);
|
|||||||
extern void VideoReleaseSurface(VideoHwDecoder *, unsigned);
|
extern void VideoReleaseSurface(VideoHwDecoder *, unsigned);
|
||||||
|
|
||||||
#ifdef LIBAVCODEC_VERSION
|
#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.
|
/// Callback to negotiate the PixelFormat.
|
||||||
extern enum PixelFormat Video_get_format(VideoHwDecoder *, AVCodecContext *,
|
extern enum PixelFormat Video_get_format(VideoHwDecoder *, AVCodecContext *,
|
||||||
const enum PixelFormat *);
|
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
|
#ifdef AVCODEC_VDPAU_H
|
||||||
/// Draw vdpau render state.
|
/// Draw vdpau render state.
|
||||||
extern void VideoDrawRenderState(VideoHwDecoder *,
|
extern void VideoDrawRenderState(VideoHwDecoder *,
|
||||||
@@ -79,6 +80,9 @@ extern void VideoSetOutputPosition(int, int, int, int);
|
|||||||
/// Set video mode.
|
/// Set video mode.
|
||||||
extern void VideoSetVideoMode(int, int, int, int);
|
extern void VideoSetVideoMode(int, int, int, int);
|
||||||
|
|
||||||
|
/// Set display format.
|
||||||
|
extern void VideoSetDisplayFormat(int);
|
||||||
|
|
||||||
/// Set video fullscreen mode.
|
/// Set video fullscreen mode.
|
||||||
extern void VideoSetFullscreen(int);
|
extern void VideoSetFullscreen(int);
|
||||||
|
|
||||||
@@ -97,9 +101,15 @@ extern void VideoSetDenoise(int[]);
|
|||||||
/// Set sharpen.
|
/// Set sharpen.
|
||||||
extern void VideoSetSharpen(int[]);
|
extern void VideoSetSharpen(int[]);
|
||||||
|
|
||||||
|
/// Set skip lines.
|
||||||
|
extern void VideoSetSkipLines(int);
|
||||||
|
|
||||||
/// Set audio delay.
|
/// Set audio delay.
|
||||||
extern void VideoSetAudioDelay(int);
|
extern void VideoSetAudioDelay(int);
|
||||||
|
|
||||||
|
/// Set auto-crop parameters.
|
||||||
|
extern void VideoSetAutoCrop(int, int, int);
|
||||||
|
|
||||||
/// Clear OSD.
|
/// Clear OSD.
|
||||||
extern void VideoOsdClear(void);
|
extern void VideoOsdClear(void);
|
||||||
|
|
||||||
@@ -111,6 +121,9 @@ extern void VideoGetOsdSize(int *, int *);
|
|||||||
|
|
||||||
extern int64_t VideoGetClock(void); ///< Get video clock.
|
extern int64_t VideoGetClock(void); ///< Get video clock.
|
||||||
|
|
||||||
|
/// Grab screen.
|
||||||
|
extern uint8_t *VideoGrab(int *, int *, int *, int);
|
||||||
|
|
||||||
extern void VideoOsdInit(void); ///< Setup osd.
|
extern void VideoOsdInit(void); ///< Setup osd.
|
||||||
extern void VideoOsdExit(void); ///< Cleanup osd.
|
extern void VideoOsdExit(void); ///< Cleanup osd.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user