mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 17:16:51 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa27a1c73a | ||
|
|
e32857a27a | ||
|
|
5ba88bb822 | ||
|
|
0422b6aa5a | ||
|
|
eb024558de | ||
|
|
1593d5dd83 | ||
|
|
09f62307d4 | ||
|
|
87f7aa63cc | ||
|
|
b1ce88923e | ||
|
|
c6e66e0787 | ||
|
|
19d4eeed82 | ||
|
|
9f668c4750 | ||
|
|
e419742a40 | ||
|
|
2cacdc6c90 | ||
|
|
6efe558f78 | ||
|
|
80100299f3 | ||
|
|
5509d768ac | ||
|
|
c0d0a4ae7c | ||
|
|
e619f5c836 | ||
|
|
973fcfe4dd | ||
|
|
eec30433b6 | ||
|
|
baf577aba5 | ||
|
|
81d7ef9755 | ||
|
|
7f7de8678f | ||
|
|
92bb00c410 | ||
|
|
d3b98b90f4 | ||
|
|
788636ee6b | ||
|
|
8e53cbd4a9 | ||
|
|
54661f90ea | ||
|
|
30d8e8afe9 | ||
|
|
19a37bb0bf | ||
|
|
2087968d55 | ||
|
|
d983f780b3 | ||
| 712b2e0de1 | |||
|
|
54f92e67fc | ||
|
|
960cd27ab5 | ||
|
|
3a97700981 |
57
ChangeLog
57
ChangeLog
@@ -1,4 +1,61 @@
|
||||
User johns
|
||||
Date: Sat Jan 21 15:49:16 CET 2012
|
||||
|
||||
Release Version 0.4.0
|
||||
VDPAU: Add grab image support.
|
||||
VDPAU: Add auto-crop support.
|
||||
VDPAU: Changed OSD alpha calculation.
|
||||
Fix bug: Used VideoSharpen for denoise settings.
|
||||
Instant update deinterlace/... configuration changes.
|
||||
Fix bug: AudioExit called without AudioInit crash.
|
||||
|
||||
Date: Thu Jan 19 15:58:40 CET 2012
|
||||
|
||||
Release Version 0.3.5
|
||||
OSD improvements:
|
||||
Use OSD size equal to video window.
|
||||
Update only dirty area(s) of OSD.
|
||||
Show/mix only used area of OSD.
|
||||
Fix bug: vpdau use previous resolution for deint, ...
|
||||
Fix software deinterlace with VA-API.
|
||||
Fix bug: transposed digits 567 should be 576.
|
||||
Audio module cleanup:
|
||||
Alsa + OSS can be included/build at the same time.
|
||||
Alsa or OSS can be runtime selected with -a.
|
||||
Add audio thread support to OSS module.
|
||||
Add polled audio support to alsa module.
|
||||
Removed some debug source code.
|
||||
|
||||
Date: Sun Jan 15 16:56:04 CET 2012
|
||||
|
||||
Release Version 0.3.1
|
||||
Fix bug: AudioFreeBytes didn't check if audio running/compiled.
|
||||
Fix bug: snd_pcm_state: Assertion `pcm' failed.
|
||||
Add support for fullscreen and fullscreen toogle.
|
||||
Instant update deinterlace configuration changes.
|
||||
Fix subtitle position.
|
||||
Add SVDRP support.
|
||||
Suspend when user is inactive.
|
||||
|
||||
User Christian Rupper
|
||||
Date: Tue Jan 10 22:33:14 CET 2012
|
||||
|
||||
Move objects before $LIBS to avoid link failures with --as-needed.
|
||||
Do not override CFLAGS for video test.
|
||||
Rearrange *FLAGS incl. some minor fixes.
|
||||
Don't override VDRDIR, LIBDIR and TMPDIR in makefile.
|
||||
Don't abuse LDFLAGS in makefile.
|
||||
Define CC in makefile.
|
||||
Include GL/gl.h for the GL_COLOR_BUFFER_BIT definition.
|
||||
VideoInit() needs an argument.
|
||||
|
||||
User johns
|
||||
Date: Tue Jan 10 22:32:50 CET 2012
|
||||
|
||||
Add main menu entry, which suspends the plugin.
|
||||
Add support for resize window.
|
||||
Close window sends "close" as remote key press.
|
||||
|
||||
Date: Mon Jan 9 22:09:38 CET 2012
|
||||
|
||||
Release Version 0.3.0
|
||||
|
||||
79
Makefile
79
Makefile
@@ -14,6 +14,7 @@ PLUGIN = softhddevice
|
||||
### The version number of this plugin (taken from the main source file):
|
||||
|
||||
VERSION = $(shell grep 'static const char \*const VERSION *=' $(PLUGIN).cpp | awk '{ print $$7 }' | sed -e 's/[";]//g')
|
||||
GIT_REV = $(shell git describe --always 2>/dev/null)
|
||||
|
||||
### Configuration (edit this for your needs)
|
||||
|
||||
@@ -22,44 +23,21 @@ CONFIG := #-DDEBUG
|
||||
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
|
||||
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
||||
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
|
||||
#CONFIG += -DUSE_OSS
|
||||
CONFIG += -DUSE_OSS
|
||||
|
||||
### The C++ compiler and options:
|
||||
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
CXXFLAGS ?= -g -O2 -W -Wall -Wextra -Woverloaded-virtual -fPIC
|
||||
override CXXFLAGS += $(DEFINES) $(INCLUDES)
|
||||
CFLAGS ?= -g -O2 -W -Wall -Wextra -Winit-self \
|
||||
-Wdeclaration-after-statement -fPIC
|
||||
#CFLAGS += -Werror
|
||||
override CFLAGS += $(DEFINES) $(INCLUDES) \
|
||||
$(shell pkg-config --cflags libavcodec libavformat) \
|
||||
`pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --cflags gl glu` \
|
||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
||||
`pkg-config --cflags vdpau`) \
|
||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||
`pkg-config --cflags libva-x11 libva-glx libva`) \
|
||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||
`pkg-config --cflags alsa`)
|
||||
override LDFLAGS += -lrt \
|
||||
$(shell pkg-config --libs libavcodec libavformat) \
|
||||
`pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --libs gl glu` \
|
||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
||||
`pkg-config --libs vdpau`) \
|
||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||
`pkg-config --libs libva-x11 libva-glx libva`) \
|
||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||
`pkg-config --libs alsa`)
|
||||
-Wdeclaration-after-statement
|
||||
CXXFLAGS ?= -g -O2 -W -Wall -Wextra -Woverloaded-virtual
|
||||
|
||||
### The directory environment:
|
||||
|
||||
VDRDIR = ../../..
|
||||
LIBDIR = ../../lib
|
||||
TMPDIR = /tmp
|
||||
VDRDIR ?= ../../..
|
||||
LIBDIR ?= ../../lib
|
||||
TMPDIR ?= /tmp
|
||||
|
||||
### Make sure that necessary options are included:
|
||||
|
||||
@@ -78,11 +56,40 @@ APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDI
|
||||
ARCHIVE = $(PLUGIN)-$(VERSION)
|
||||
PACKAGE = vdr-$(ARCHIVE)
|
||||
|
||||
### Includes and Defines (add further entries here):
|
||||
### Includes, Defines and dependencies (add further entries here):
|
||||
|
||||
INCLUDES += -I$(VDRDIR)/include
|
||||
|
||||
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
|
||||
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' \
|
||||
$(if $(GIT_REV), -DGIT_REV='"$(GIT_REV)"')
|
||||
|
||||
_CFLAGS = $(DEFINES) $(INCLUDES) \
|
||||
$(shell pkg-config --cflags libavcodec libavformat) \
|
||||
`pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --cflags gl glu` \
|
||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
||||
`pkg-config --cflags vdpau`) \
|
||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||
`pkg-config --cflags libva-x11 libva-glx libva`) \
|
||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||
`pkg-config --cflags alsa`)
|
||||
|
||||
#override _CFLAGS += -Werror
|
||||
override CXXFLAGS += $(_CFLAGS)
|
||||
override CFLAGS += $(_CFLAGS)
|
||||
|
||||
LIBS += -lrt \
|
||||
$(shell pkg-config --libs libavcodec libavformat) \
|
||||
`pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --libs gl glu` \
|
||||
$(if $(findstring USE_VDPAU,$(CONFIG)), \
|
||||
`pkg-config --libs vdpau`) \
|
||||
$(if $(findstring USE_VAAPI,$(CONFIG)), \
|
||||
`pkg-config --libs libva-x11 libva-glx libva`) \
|
||||
$(if $(findstring USE_ALSA,$(CONFIG)), \
|
||||
`pkg-config --libs alsa`)
|
||||
|
||||
### The object files (add further files here):
|
||||
|
||||
@@ -105,6 +112,8 @@ DEPFILE = .dependencies
|
||||
$(DEPFILE): Makefile
|
||||
@$(MAKEDEP) $(DEFINES) $(INCLUDES) $(SRCS) >$@
|
||||
|
||||
$(OBJS): Makefile
|
||||
|
||||
-include $(DEPFILE)
|
||||
|
||||
### Internationalization (I18N):
|
||||
@@ -137,7 +146,7 @@ i18n: $(I18Nmsgs) $(I18Npot)
|
||||
### Targets:
|
||||
|
||||
libvdr-$(PLUGIN).so: $(OBJS) Makefile
|
||||
$(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@ $(LDFLAGS)
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -fPIC $(OBJS) -o $@ $(LIBS)
|
||||
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
|
||||
|
||||
dist: $(I18Npo) clean
|
||||
@@ -163,5 +172,5 @@ indent:
|
||||
done
|
||||
|
||||
video_test: video.c
|
||||
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $(LIBS) \
|
||||
-O0 -g -o $@ $<
|
||||
$(CC) -DVIDEO_TEST -DVERSION='"$(VERSION)"' $(CFLAGS) $(LDFLAGS) $< $(LIBS) \
|
||||
-o $@
|
||||
|
||||
58
README.txt
58
README.txt
@@ -24,17 +24,20 @@ A software and GPU emulated HD output device plugin for VDR.
|
||||
o Video CPU/VA-API
|
||||
o Video VDPAU/VDPAU
|
||||
o Video CPU/VDPAU
|
||||
o Audio FFMpeg/Alsa/Analog
|
||||
o Audio FFMpeg/Alsa/Digital
|
||||
o Audio FFMpeg/OSS/Analog
|
||||
o HDMI/SPDIF Passthrough
|
||||
o VA-API bob software deinterlace
|
||||
o Auto-crop
|
||||
|
||||
o planned: Video VA-API/Opengl
|
||||
o planned: Video VDPAU/Opengl
|
||||
o planned: Video CPU/Xv
|
||||
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 Audio FFMpeg/Alsa/Analog
|
||||
o Audio FFMpeg/Alsa/Digital
|
||||
o Audio FFMpeg/OSS/Analog
|
||||
o planned: Alsa HDMI/SPDIF Passthrough
|
||||
o planned: OSS HDMI/SPDIF Passthrough
|
||||
o planned: atmo light support
|
||||
|
||||
To compile you must have the 'requires' installed.
|
||||
|
||||
@@ -61,7 +64,7 @@ Install:
|
||||
http://projects.vdr-developer.org/projects/plg-softhddevice/files
|
||||
|
||||
tar vxf vdr-softhddevice-*.tar.bz2
|
||||
cd vdr-softhddevice
|
||||
cd softhddevice-*
|
||||
make VDRDIR=<path-to-your-vdr-files> LIBDIR=.
|
||||
|
||||
You can edit Makefile to enable/disable VDPAU / VA-API / Alsa / OSS
|
||||
@@ -95,6 +98,9 @@ Setup: /etc/vdr/setup.conf
|
||||
softhddevice.MakePrimary = 1
|
||||
0 = no change, 1 make softhddevice primary at start
|
||||
|
||||
softhddevice.HideMainMenuEntry = 0
|
||||
0 = show softhddevice main menu entry, 1 = hide entry
|
||||
|
||||
<res> of the next parameters is 567i, 720p, 1080i_fake or 1080i.
|
||||
1080i_fake is 1280x1080 or 1440x1080
|
||||
1080i is "real" 1920x1080
|
||||
@@ -122,12 +128,50 @@ Setup: /etc/vdr/setup.conf
|
||||
softhddevice.AudioPassthrough = 0
|
||||
0 = none, 1 = AC-3
|
||||
|
||||
softhddevice.AutoCrop.Interval = 0
|
||||
0 disables auto-crop
|
||||
n each 'n' frames auto-crop is checked.
|
||||
|
||||
softhddevice.AutoCrop.Delay = 0
|
||||
if auto-crop is over after 'n' intervals the same, the cropping is
|
||||
used.
|
||||
|
||||
Setup: /etc/vdr/remote.conf
|
||||
------
|
||||
|
||||
Add "XKeySym." definitions to /etc/vdr/remote.conf to control
|
||||
the vdr and plugin with the connected input device.
|
||||
|
||||
fe.
|
||||
XKeySym.Up Up
|
||||
XKeySym.Down Down
|
||||
...
|
||||
|
||||
Additional to the x11 input sends the window close button "Close".
|
||||
|
||||
fe.
|
||||
XKeySym.Power Close
|
||||
|
||||
Commandline:
|
||||
------------
|
||||
|
||||
Use vdr -h to see the command line arguments support by the plugin.
|
||||
|
||||
-a audio_device
|
||||
|
||||
Selects audio output module and device.
|
||||
"" to disable audio output
|
||||
/... to use oss audio module (if compiled with oss
|
||||
support)
|
||||
other to use alsa audio module (if compiled with alsa
|
||||
support)
|
||||
|
||||
Running:
|
||||
--------
|
||||
|
||||
Click into video window to toggle fullscreen/window mode, only if you
|
||||
have a window manager running.
|
||||
|
||||
Warning:
|
||||
--------
|
||||
libav is not supported, expect many bugs with it.
|
||||
|
||||
81
Todo
81
Todo
@@ -19,60 +19,61 @@ GNU Affero General Public License for more details.
|
||||
$Id: $
|
||||
|
||||
missing:
|
||||
video out with xv
|
||||
video out with opengl
|
||||
software decoder for xv / opengl
|
||||
software deinterlace
|
||||
auto crop
|
||||
atmolight
|
||||
zoom/fit-zoom 4:3
|
||||
multistream handling
|
||||
disable screensaver
|
||||
disable window cursor
|
||||
software deinterlace (yadif, ...)
|
||||
software decoder with software deinterlace
|
||||
zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
|
||||
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
|
||||
suspend output / energie saver: stop audio, stop video, configurable
|
||||
Option deinterlace off / deinterlace force!
|
||||
Make output drivers better modular (under construction).
|
||||
|
||||
video:
|
||||
subtitle not cleared
|
||||
subtitle could be asyncron
|
||||
reduce warnings after channel switch
|
||||
|
||||
vdpau:
|
||||
1080i with temporal spatial and level 1 scaling too slow with my GT 520
|
||||
1080i with temporal spatial too slow with my GT 520 on some channels
|
||||
SkipChromaDeinterlace improves performance
|
||||
Improve OSD handling, show only what is used. Big OSD costs performance
|
||||
VdpPreemptionCallback handling
|
||||
VdpPreemptionCallback handling (under construction)
|
||||
hard channel switch
|
||||
suspendoutput didn't show logo or black picture.
|
||||
|
||||
libva:
|
||||
hard channel switch
|
||||
yaepghd (VaapiSetOutputPosition) support
|
||||
can associate ony displayed part of osd
|
||||
auto crop for va-api
|
||||
grab image for va-api
|
||||
|
||||
libva: branch vaapi-ext
|
||||
add support for vaapi-ext
|
||||
|
||||
libva-intel-driver:
|
||||
intel still has hangups most with 1080i
|
||||
1080i does no v-sync (workaround written)
|
||||
osd has sometimes wrong size (workaround written)
|
||||
1080i does no v-sync (workaround written, fixed with vaapi-ext)
|
||||
OSD has sometimes wrong size (workaround written)
|
||||
|
||||
libva-vdpau-driver:
|
||||
G210 osd update too slow (needs hardware problem workaround)
|
||||
OSD update is too slow
|
||||
G210/GT520 OSD update too slow (needs hardware problem workaround)
|
||||
hangup on exit (VaapiDelDecoder -> VaapiCleanup
|
||||
-> vaDestroyContext -> pthread_rwlock_wrlock)
|
||||
|
||||
libva-xvba-driver:
|
||||
|
||||
x11:
|
||||
support resize of x11 window
|
||||
support fullscreen window
|
||||
support fullscreen / window toggle
|
||||
close window should send power button
|
||||
disable cursor
|
||||
disable screensaver
|
||||
|
||||
audio:
|
||||
write TS -> PES parser, which feeds audio before the next start packet
|
||||
CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
|
||||
Combine alsa+oss ringbuffer code.
|
||||
Make alsa thread/polled and oss thread/polled output module runtime
|
||||
selectable.
|
||||
|
||||
audio/alsa:
|
||||
done? video/audio asyncron
|
||||
random crashes in av_parser_parse2, when switching channels
|
||||
sometimes alsa hangs
|
||||
|
||||
better downmix of >2 channels on 2 channel hardware
|
||||
remix support of unsupported sample rates
|
||||
libav supports only resample of mono to 2 channels
|
||||
ffmpeg didn't support resample of 5 to 2 channels
|
||||
CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
|
||||
|
||||
audio/oss:
|
||||
alsa oss emulation mixer "pcm" not working
|
||||
@@ -81,6 +82,8 @@ audio/oss:
|
||||
HDMI/SPDIF Passthrough:
|
||||
only AC-3 written
|
||||
Channels are wrong setup, if changing setting during operation.
|
||||
split pcm and ac-3 out into two devices
|
||||
support oss pass-through
|
||||
|
||||
playback of recording
|
||||
pause is not reset, when replay exit
|
||||
@@ -91,6 +94,22 @@ setup:
|
||||
Setup of output type.
|
||||
Setup of display type.
|
||||
Setup 4:3 zoom type
|
||||
Setup parameters are not used until restart.
|
||||
Some setup parameters are not used until restart.
|
||||
Can a notice be added to the setup menu?
|
||||
576i, 720p, fake 1080i, 1080i
|
||||
|
||||
unsorted:
|
||||
Menu -> Setup -> Plugins -> skingenigmang -> General
|
||||
-> Try 8bpp single area: no, has missing parts.
|
||||
|
||||
future features (not planed for 1.0 - 1.5)
|
||||
|
||||
video out with xv
|
||||
video out with opengl
|
||||
video out with xvba
|
||||
software decoder for xv / opengl
|
||||
atmolight support
|
||||
multistream handling
|
||||
pip support
|
||||
grab image with jpeg
|
||||
|
||||
upmix stereo to AC-3
|
||||
|
||||
647
audio.c
647
audio.c
@@ -35,21 +35,19 @@
|
||||
///
|
||||
///
|
||||
/// @todo FIXME: there can be problems with little/big endian.
|
||||
/// @todo FIXME: can combine oss and alsa ring buffer
|
||||
/// @todo FIXME: can combine OSS and alsa ring buffer
|
||||
///
|
||||
|
||||
#ifdef USE_ALSA // only with alsa supported
|
||||
#define USE_AUDIO_THREAD ///< use thread for audio playback
|
||||
#endif
|
||||
//#define USE_ALSA ///< enable alsa support
|
||||
//#define USE_OSS ///< enable oss support
|
||||
#define noSEARCH_HDMI_BUG
|
||||
#define noSEARCH_HDMI_BUG2
|
||||
//#define USE_OSS ///< enable OSS support
|
||||
#define USE_AUDIO_THREAD ///< use thread for audio playback
|
||||
#define noUSE_AUDIORING ///< new audio ring code (incomplete)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libintl.h>
|
||||
#define _(str) gettext(str) ///< gettext shortcut
|
||||
@@ -73,10 +71,10 @@
|
||||
# error "No valid SNDCTL_DSP_HALT_OUTPUT found."
|
||||
# endif
|
||||
#endif
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
@@ -96,13 +94,42 @@
|
||||
#include "misc.h"
|
||||
#include "audio.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Declarations
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** Audio output module structure and typedef.
|
||||
*/
|
||||
typedef struct _audio_module_
|
||||
{
|
||||
const char *Name; ///< audio output module name
|
||||
|
||||
void (*Thread) (void); ///< module thread handler
|
||||
void (*Enqueue) (const void *, int); ///< enqueue samples for output
|
||||
void (*FlushBuffers) (void); ///< flush sample buffers
|
||||
void (*Poller) (void); ///< output poller
|
||||
int (*FreeBytes) (void); ///< number of bytes free in buffer
|
||||
uint64_t(*GetDelay) (void); ///< get current audio delay
|
||||
void (*SetVolume) (int); ///< set output volume
|
||||
int (*Setup) (int *, int *); ///< setup channels, samplerate
|
||||
void (*Init) (void); ///< initialize audio output module
|
||||
void (*Exit) (void); ///< cleanup audio output module
|
||||
} AudioModule;
|
||||
|
||||
static const AudioModule NoopModule; ///< forward definition of noop module
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Variables
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
static const char *AudioPCMDevice; ///< alsa/oss PCM device name
|
||||
static const char *AudioMixerDevice; ///< alsa/oss mixer device name
|
||||
static const char *AudioMixerChannel; ///< alsa/oss mixer channel name
|
||||
static const char *AudioModuleName; ///< which audio module to use
|
||||
|
||||
/// Selected audio module.
|
||||
static const AudioModule *AudioUsedModule = &NoopModule;
|
||||
static const char *AudioPCMDevice; ///< alsa/OSS PCM device name
|
||||
static const char *AudioMixerDevice; ///< alsa/OSS mixer device name
|
||||
static const char *AudioMixerChannel; ///< alsa/OSS mixer channel name
|
||||
static volatile char AudioRunning; ///< thread running / stopped
|
||||
static int AudioPaused; ///< audio paused
|
||||
static unsigned AudioSampleRate; ///< audio sample rate in hz
|
||||
@@ -111,16 +138,20 @@ static const int AudioBytesProSample = 2; ///< number of bytes per sample
|
||||
static int64_t AudioPTS; ///< audio pts clock
|
||||
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
static pthread_t AudioThread; ///< audio play thread
|
||||
static pthread_mutex_t AudioMutex; ///< audio condition mutex
|
||||
static pthread_cond_t AudioStartCond; ///< condition variable
|
||||
#else
|
||||
static const int AudioThread; ///< dummy audio thread
|
||||
#endif
|
||||
|
||||
#ifdef SEARCH_HDMI_BUG2
|
||||
#ifdef USE_AUDIORING
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ring buffer
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// FIXME: use this code, to combine alsa&oss ring buffers
|
||||
// FIXME: use this code, to combine alsa&OSS ring buffers
|
||||
|
||||
#define AUDIO_RING_MAX 8 ///< number of audio ring buffers
|
||||
|
||||
@@ -219,7 +250,10 @@ static int AlsaUseMmap; ///< use mmap
|
||||
|
||||
static RingBuffer *AlsaRingBuffer; ///< audio ring buffer
|
||||
static unsigned AlsaStartThreshold; ///< start play, if filled
|
||||
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
static volatile char AlsaFlushBuffer; ///< flag empty buffer
|
||||
#endif
|
||||
|
||||
static snd_mixer_t *AlsaMixer; ///< alsa mixer handle
|
||||
static snd_mixer_elem_t *AlsaMixerElem; ///< alsa pcm mixer element
|
||||
@@ -295,26 +329,15 @@ static int AlsaPlayRingbuffer(void)
|
||||
if (avail < 256) { // too much overhead
|
||||
if (first) {
|
||||
// happens with broken alsa drivers
|
||||
Error(_("audio/alsa: broken driver %d\n"), avail);
|
||||
usleep(5 * 1000);
|
||||
if (AudioThread) {
|
||||
Error(_("audio/alsa: broken driver %d\n"), avail);
|
||||
usleep(5 * 1000);
|
||||
}
|
||||
}
|
||||
Debug(4, "audio/alsa: break state %s\n",
|
||||
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
|
||||
break;
|
||||
}
|
||||
#ifdef SEARCH_HDMI_BUG
|
||||
{
|
||||
uint16_t buf[8192];
|
||||
unsigned u;
|
||||
|
||||
for (u = 0; u < sizeof(buf) / 2; u++) {
|
||||
buf[u] = random() & 0xffff;
|
||||
}
|
||||
|
||||
n = sizeof(buf);
|
||||
p = buf;
|
||||
}
|
||||
#else
|
||||
n = RingBufferGetReadPointer(AlsaRingBuffer, &p);
|
||||
if (!n) { // ring buffer empty
|
||||
if (first) { // only error on first loop
|
||||
@@ -322,7 +345,6 @@ static int AlsaPlayRingbuffer(void)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (n < avail) { // not enough bytes in ring buffer
|
||||
avail = n;
|
||||
}
|
||||
@@ -376,21 +398,47 @@ static void AlsaFlushBuffers(void)
|
||||
int err;
|
||||
snd_pcm_state_t state;
|
||||
|
||||
RingBufferReadAdvance(AlsaRingBuffer, RingBufferUsedBytes(AlsaRingBuffer));
|
||||
state = snd_pcm_state(AlsaPCMHandle);
|
||||
Debug(3, "audio/alsa: state %d - %s\n", state, snd_pcm_state_name(state));
|
||||
if (state != SND_PCM_STATE_OPEN) {
|
||||
if ((err = snd_pcm_drop(AlsaPCMHandle)) < 0) {
|
||||
Error(_("audio: snd_pcm_drop(): %s\n"), snd_strerror(err));
|
||||
}
|
||||
// ****ing alsa crash, when in open state here
|
||||
if ((err = snd_pcm_prepare(AlsaPCMHandle)) < 0) {
|
||||
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
|
||||
if (AlsaRingBuffer && AlsaPCMHandle) {
|
||||
RingBufferReadAdvance(AlsaRingBuffer,
|
||||
RingBufferUsedBytes(AlsaRingBuffer));
|
||||
state = snd_pcm_state(AlsaPCMHandle);
|
||||
Debug(3, "audio/alsa: state %d - %s\n", state,
|
||||
snd_pcm_state_name(state));
|
||||
if (state != SND_PCM_STATE_OPEN) {
|
||||
if ((err = snd_pcm_drop(AlsaPCMHandle)) < 0) {
|
||||
Error(_("audio: snd_pcm_drop(): %s\n"), snd_strerror(err));
|
||||
}
|
||||
// ****ing alsa crash, when in open state here
|
||||
if ((err = snd_pcm_prepare(AlsaPCMHandle)) < 0) {
|
||||
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
AudioRunning = 0;
|
||||
AudioPTS = INT64_C(0x8000000000000000);
|
||||
}
|
||||
|
||||
/**
|
||||
** Call back to play audio polled.
|
||||
*/
|
||||
static void AlsaPoller(void)
|
||||
{
|
||||
if (!AlsaPCMHandle) { // setup failure
|
||||
return;
|
||||
}
|
||||
if (!AudioThread && AudioRunning) {
|
||||
AlsaPlayRingbuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Get free bytes in audio output.
|
||||
*/
|
||||
static int AlsaFreeBytes(void)
|
||||
{
|
||||
return AlsaRingBuffer ? RingBufferFreeBytes(AlsaRingBuffer) : INT32_MAX;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -520,8 +568,6 @@ static void AlsaEnqueue(const void *samples, int count)
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// direct playback
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -536,39 +582,11 @@ static void AlsaEnqueue(const void *samples, int count)
|
||||
*/
|
||||
static void AlsaEnqueue(const void *samples, int count)
|
||||
{
|
||||
snd_pcm_state_t state;
|
||||
int avail;
|
||||
int n;
|
||||
int err;
|
||||
int frames;
|
||||
const void *p;
|
||||
|
||||
Debug(3, "audio/alsa: %6zd + %4d\n", RingBufferUsedBytes(AlsaRingBuffer),
|
||||
count);
|
||||
n = RingBufferWrite(AlsaRingBuffer, samples, count);
|
||||
if (n != count) {
|
||||
Error(_("audio/alsa: can't place %d samples in ring buffer\n"), count);
|
||||
if (AlsaAddToRingbuffer(samples, count)) {
|
||||
AudioRunning = 1;
|
||||
}
|
||||
// check if running, wait until enough buffered
|
||||
state = snd_pcm_state(AlsaPCMHandle);
|
||||
Debug(4, "audio/alsa: state %d - %s\n", state, snd_pcm_state_name(state));
|
||||
if (state == SND_PCM_STATE_PREPARED) {
|
||||
// FIXME: adjust start ratio
|
||||
if (RingBufferFreeBytes(AlsaRingBuffer)
|
||||
> RingBufferUsedBytes(AlsaRingBuffer)) {
|
||||
return;
|
||||
}
|
||||
Debug(3, "audio/alsa: state %d - %s start play\n", state,
|
||||
snd_pcm_state_name(state));
|
||||
}
|
||||
// Update audio clock
|
||||
AudioPTS +=
|
||||
(size * 90000) / (AudioSampleRate * AudioChannels *
|
||||
AudioBytesProSample);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -622,7 +640,7 @@ static void AlsaThread(void)
|
||||
break;
|
||||
}
|
||||
pthread_yield();
|
||||
usleep(20 * 1000); // let fill the buffers
|
||||
usleep(20 * 1000); // let fill/empty the buffers
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -633,10 +651,9 @@ static void AlsaThread(void)
|
||||
** @param samples sample buffer
|
||||
** @param count number of bytes in sample buffer
|
||||
*/
|
||||
static void AlsaEnqueue(const void *samples, int count)
|
||||
static void AlsaThreadEnqueue(const void *samples, int count)
|
||||
{
|
||||
if (!AlsaRingBuffer || !AlsaPCMHandle || !AudioSampleRate) {
|
||||
printf("%p %p %d\n", AlsaRingBuffer, AlsaPCMHandle, AudioSampleRate);
|
||||
Debug(3, "audio/alsa: enqueue not ready\n");
|
||||
return;
|
||||
}
|
||||
@@ -652,8 +669,26 @@ static void AlsaEnqueue(const void *samples, int count)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Flush alsa buffers with thread.
|
||||
*/
|
||||
static void AlsaThreadFlushBuffers(void)
|
||||
{
|
||||
// signal thread to flush buffers
|
||||
if (AudioThread) {
|
||||
AlsaFlushBuffer = 1;
|
||||
do {
|
||||
AudioRunning = 1; // wakeup in case of sleeping
|
||||
pthread_cond_signal(&AudioStartCond);
|
||||
usleep(1 * 1000);
|
||||
} while (AlsaFlushBuffer); // wait until flushed
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** Open alsa pcm device.
|
||||
*/
|
||||
@@ -856,23 +891,9 @@ static int AlsaSetup(int *freq, int *channels)
|
||||
if (!AlsaPCMHandle) { // alsa not running yet
|
||||
return -1;
|
||||
}
|
||||
#if 1
|
||||
#if 1 // easy alsa hw setup way
|
||||
// flush any buffered data
|
||||
#ifndef SEARCH_HDMI_BUG2
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
if (AudioRunning) {
|
||||
while (AudioRunning) {
|
||||
AlsaFlushBuffer = 1;
|
||||
usleep(1 * 1000);
|
||||
}
|
||||
AlsaFlushBuffer = 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
AlsaFlushBuffers();
|
||||
}
|
||||
#endif
|
||||
AudioPTS = INT64_C(0x8000000000000000);
|
||||
AudioFlushBuffers();
|
||||
|
||||
if (1) { // close+open to fix hdmi no sound bugs
|
||||
handle = AlsaPCMHandle;
|
||||
@@ -1112,6 +1133,28 @@ static void AlsaExit(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Alsa module.
|
||||
*/
|
||||
static const AudioModule AlsaModule = {
|
||||
.Name = "alsa",
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
.Thread = AlsaThread,
|
||||
.Enqueue = AlsaThreadEnqueue,
|
||||
.FlushBuffers = AlsaThreadFlushBuffers,
|
||||
#else
|
||||
.Enqueue = AlsaEnqueue,
|
||||
.FlushBuffers = AlsaFlushBuffers,
|
||||
#endif
|
||||
.Poller = AlsaPoller,
|
||||
.FreeBytes = AlsaFreeBytes,
|
||||
.GetDelay = AlsaGetDelay,
|
||||
.SetVolume = AlsaSetVolume,
|
||||
.Setup = AlsaSetup,
|
||||
.Init = AlsaInit,
|
||||
.Exit = AlsaExit,
|
||||
};
|
||||
|
||||
#endif // USE_ALSA
|
||||
|
||||
#ifdef USE_OSS
|
||||
@@ -1130,6 +1173,10 @@ static int OssMixerChannel; ///< mixer channel index
|
||||
static RingBuffer *OssRingBuffer; ///< audio ring buffer
|
||||
static unsigned OssStartThreshold; ///< start play, if filled
|
||||
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
static volatile char OssFlushBuffer; ///< flag empty buffer
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// OSS pcm
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -1218,17 +1265,20 @@ static int OssPlayRingbuffer(void)
|
||||
}
|
||||
|
||||
/**
|
||||
** Flush oss buffers.
|
||||
** Flush OSS buffers.
|
||||
*/
|
||||
static void OssFlushBuffers(void)
|
||||
{
|
||||
RingBufferReadAdvance(OssRingBuffer, RingBufferUsedBytes(OssRingBuffer));
|
||||
// flush kernel buffers
|
||||
if (ioctl(OssPcmFildes, SNDCTL_DSP_HALT_OUTPUT, NULL) < 0) {
|
||||
Error(_("audio/oss: ioctl(SNDCTL_DSP_HALT_OUTPUT): %s\n"),
|
||||
strerror(errno));
|
||||
return;
|
||||
if (OssRingBuffer && OssPcmFildes != -1) {
|
||||
RingBufferReadAdvance(OssRingBuffer,
|
||||
RingBufferUsedBytes(OssRingBuffer));
|
||||
// flush kernel buffers
|
||||
if (ioctl(OssPcmFildes, SNDCTL_DSP_HALT_OUTPUT, NULL) < 0) {
|
||||
Error(_("audio/oss: ioctl(SNDCTL_DSP_HALT_OUTPUT): %s\n"),
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
AudioRunning = 0;
|
||||
AudioPTS = INT64_C(0x8000000000000000);
|
||||
}
|
||||
|
||||
@@ -1270,15 +1320,108 @@ static void OssPoller(void)
|
||||
if (OssPcmFildes == -1) { // setup failure
|
||||
return;
|
||||
}
|
||||
if (AudioRunning) {
|
||||
if (!AudioThread && AudioRunning) {
|
||||
OssPlayRingbuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Get free bytes in audio output.
|
||||
*/
|
||||
static int OssFreeBytes(void)
|
||||
{
|
||||
return OssRingBuffer ? RingBufferFreeBytes(OssRingBuffer) : INT32_MAX;
|
||||
}
|
||||
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// thread playback
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** Initialize oss pcm device.
|
||||
** OSS thread
|
||||
*/
|
||||
static void OssThread(void)
|
||||
{
|
||||
for (;;) {
|
||||
struct pollfd fds[1];
|
||||
int err;
|
||||
|
||||
pthread_testcancel();
|
||||
if (OssFlushBuffer) {
|
||||
// we can flush too many, but wo cares
|
||||
Debug(3, "audio/oss: flushing buffers\n");
|
||||
OssFlushBuffers();
|
||||
OssFlushBuffer = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
fds[0].fd = OssPcmFildes;
|
||||
fds[0].events = POLLOUT | POLLERR;
|
||||
// wait for space in kernel buffers
|
||||
err = poll(fds, 1, 100);
|
||||
if (err < 0) {
|
||||
Error(_("audio/oss: error poll %s\n"), strerror(errno));
|
||||
usleep(100 * 1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (OssFlushBuffer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((err = OssPlayRingbuffer())) { // empty / error
|
||||
if (err < 0) { // underrun error
|
||||
break;
|
||||
}
|
||||
pthread_yield();
|
||||
usleep(20 * 1000); // let fill/empty the buffers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Place samples in audio output queue.
|
||||
**
|
||||
** @param samples sample buffer
|
||||
** @param count number of bytes in sample buffer
|
||||
*/
|
||||
static void OssThreadEnqueue(const void *samples, int count)
|
||||
{
|
||||
if (!OssRingBuffer || OssPcmFildes == -1 || !AudioSampleRate) {
|
||||
Debug(3, "audio/oss: enqueue not ready\n");
|
||||
return;
|
||||
}
|
||||
if (OssAddToRingbuffer(samples, count)) {
|
||||
// no lock needed, can wakeup next time
|
||||
AudioRunning = 1;
|
||||
pthread_cond_signal(&AudioStartCond);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Flush OSS buffers with thread.
|
||||
*/
|
||||
static void OssThreadFlushBuffers(void)
|
||||
{
|
||||
// signal thread to flush buffers
|
||||
if (AudioThread) {
|
||||
OssFlushBuffer = 1;
|
||||
do {
|
||||
AudioRunning = 1; // wakeup in case of sleeping
|
||||
pthread_cond_signal(&AudioStartCond);
|
||||
usleep(1 * 1000);
|
||||
} while (OssFlushBuffer); // wait until flushed
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** Initialize OSS pcm device.
|
||||
**
|
||||
** @see AudioPCMDevice
|
||||
*/
|
||||
@@ -1306,7 +1449,7 @@ static void OssInitPCM(void)
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** Set oss mixer volume (0-100)
|
||||
** Set OSS mixer volume (0-100)
|
||||
**
|
||||
** @param volume volume (0 .. 100)
|
||||
*/
|
||||
@@ -1331,7 +1474,7 @@ static const char *OssMixerChannelNames[SOUND_MIXER_NRDEVICES] =
|
||||
SOUND_DEVICE_NAMES;
|
||||
|
||||
/**
|
||||
** Initialize oss mixer.
|
||||
** Initialize OSS mixer.
|
||||
*/
|
||||
static void OssInitMixer(void)
|
||||
{
|
||||
@@ -1385,7 +1528,7 @@ static void OssInitMixer(void)
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** Get oss audio delay in time stamps.
|
||||
** Get OSS audio delay in time stamps.
|
||||
**
|
||||
** @returns audio delay in time stamps.
|
||||
*/
|
||||
@@ -1425,7 +1568,7 @@ static uint64_t OssGetDelay(void)
|
||||
}
|
||||
|
||||
/**
|
||||
** Setup oss audio for requested format.
|
||||
** Setup OSS audio for requested format.
|
||||
**
|
||||
** @param freq sample frequency
|
||||
** @param channels number of channels
|
||||
@@ -1441,15 +1584,11 @@ static int OssSetup(int *freq, int *channels)
|
||||
int ret;
|
||||
int tmp;
|
||||
|
||||
if (OssPcmFildes == -1) { // oss not ready
|
||||
if (OssPcmFildes == -1) { // OSS not ready
|
||||
return -1;
|
||||
}
|
||||
// flush any buffered data
|
||||
{
|
||||
AudioRunning = 0;
|
||||
OssFlushBuffers();
|
||||
}
|
||||
AudioPTS = INT64_C(0x8000000000000000);
|
||||
AudioFlushBuffers();
|
||||
|
||||
ret = 0;
|
||||
|
||||
@@ -1534,7 +1673,7 @@ static int OssSetup(int *freq, int *channels)
|
||||
}
|
||||
|
||||
/**
|
||||
** Initialize oss audio output module.
|
||||
** Initialize OSS audio output module.
|
||||
*/
|
||||
static void OssInit(void)
|
||||
{
|
||||
@@ -1545,7 +1684,7 @@ static void OssInit(void)
|
||||
}
|
||||
|
||||
/**
|
||||
** Cleanup oss audio output module.
|
||||
** Cleanup OSS audio output module.
|
||||
*/
|
||||
static void OssExit(void)
|
||||
{
|
||||
@@ -1559,17 +1698,116 @@ static void OssExit(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** OSS module.
|
||||
*/
|
||||
static const AudioModule OssModule = {
|
||||
.Name = "oss",
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
.Thread = OssThread,
|
||||
.Enqueue = OssThreadEnqueue,
|
||||
.FlushBuffers = OssThreadFlushBuffers,
|
||||
#else
|
||||
.Enqueue = OssEnqueue,
|
||||
.FlushBuffers = OssFlushBuffers,
|
||||
#endif
|
||||
.Poller = OssPoller,
|
||||
.FreeBytes = OssFreeBytes,
|
||||
.GetDelay = OssGetDelay,
|
||||
.SetVolume = OssSetVolume,
|
||||
.Setup = OssSetup,
|
||||
.Init = OssInit,
|
||||
.Exit = OssExit,
|
||||
};
|
||||
|
||||
#endif // USE_OSS
|
||||
|
||||
//============================================================================
|
||||
// Noop
|
||||
//============================================================================
|
||||
|
||||
/**
|
||||
** Noop enqueue samples.
|
||||
**
|
||||
** @param samples sample buffer
|
||||
** @param count number of bytes in sample buffer
|
||||
*/
|
||||
static void NoopEnqueue( __attribute__ ((unused))
|
||||
const void *samples, __attribute__ ((unused))
|
||||
int count)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
** Get free bytes in audio output.
|
||||
*/
|
||||
static int NoopFreeBytes(void)
|
||||
{
|
||||
return INT32_MAX; // no driver, much space
|
||||
}
|
||||
|
||||
/**
|
||||
** Get audio delay in time stamps.
|
||||
**
|
||||
** @returns audio delay in time stamps.
|
||||
*/
|
||||
static uint64_t NoopGetDelay(void)
|
||||
{
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
/**
|
||||
** Set mixer volume (0-100)
|
||||
**
|
||||
** @param volume volume (0 .. 100)
|
||||
*/
|
||||
static void NoopSetVolume( __attribute__ ((unused))
|
||||
int volume)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
** Noop setup.
|
||||
**
|
||||
** @param freq sample frequency
|
||||
** @param channels number of channels
|
||||
*/
|
||||
static int NoopSetup( __attribute__ ((unused))
|
||||
int *channels, __attribute__ ((unused))
|
||||
int *freq)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
** Noop void
|
||||
*/
|
||||
static void NoopVoid(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
** Noop module.
|
||||
*/
|
||||
static const AudioModule NoopModule = {
|
||||
.Name = "noop",
|
||||
.Enqueue = NoopEnqueue,
|
||||
.FlushBuffers = NoopVoid,
|
||||
.Poller = NoopVoid,
|
||||
.FreeBytes = NoopFreeBytes,
|
||||
.GetDelay = NoopGetDelay,
|
||||
.SetVolume = NoopSetVolume,
|
||||
.Setup = NoopSetup,
|
||||
.Init = NoopVoid,
|
||||
.Exit = NoopVoid,
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// thread playback
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
|
||||
static pthread_t AudioThread; ///< audio play thread
|
||||
static pthread_mutex_t AudioMutex; ///< audio condition mutex
|
||||
|
||||
/**
|
||||
** Audio play thread.
|
||||
*/
|
||||
@@ -1580,18 +1818,13 @@ static void *AudioPlayHandlerThread(void *dummy)
|
||||
Debug(3, "audio: wait on start condition\n");
|
||||
pthread_mutex_lock(&AudioMutex);
|
||||
AudioRunning = 0;
|
||||
#ifndef SEARCH_HDMI_BUG
|
||||
do {
|
||||
pthread_cond_wait(&AudioStartCond, &AudioMutex);
|
||||
// cond_wait can return, without signal!
|
||||
} while (!AudioRunning);
|
||||
#else
|
||||
usleep(1 * 1000);
|
||||
AudioRunning = 1;
|
||||
#endif
|
||||
pthread_mutex_unlock(&AudioMutex);
|
||||
|
||||
#ifdef SEARCH_HDMI_BUG2
|
||||
#ifdef USE_AUDIORING
|
||||
if (atomic_read(&AudioRingFilled) > 1) {
|
||||
int sample_rate;
|
||||
int channels;
|
||||
@@ -1634,9 +1867,7 @@ static void *AudioPlayHandlerThread(void *dummy)
|
||||
#endif
|
||||
|
||||
Debug(3, "audio: play start\n");
|
||||
#ifdef USE_ALSA
|
||||
AlsaThread();
|
||||
#endif
|
||||
AudioUsedModule->Thread();
|
||||
}
|
||||
|
||||
return dummy;
|
||||
@@ -1651,15 +1882,9 @@ static void AudioInitThread(void)
|
||||
pthread_cond_init(&AudioStartCond, NULL);
|
||||
pthread_create(&AudioThread, NULL, AudioPlayHandlerThread, NULL);
|
||||
pthread_setname_np(AudioThread, "softhddev audio");
|
||||
//pthread_detach(AudioThread);
|
||||
#ifdef very_old_unused_USE_ALSA
|
||||
// wait until thread has opened and is ready
|
||||
do {
|
||||
pthread_yield();
|
||||
} while (!AlsaPCMHandle);
|
||||
#endif
|
||||
|
||||
pthread_yield();
|
||||
usleep(5 * 1000);
|
||||
usleep(5 * 1000); // give thread some time to start
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1686,6 +1911,19 @@ static void AudioExitThread(void)
|
||||
//----------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** Table of all audio modules.
|
||||
*/
|
||||
static const AudioModule *AudioModules[] = {
|
||||
#ifdef USE_ALSA
|
||||
&AlsaModule,
|
||||
#endif
|
||||
#ifdef USE_OSS
|
||||
&OssModule,
|
||||
#endif
|
||||
&NoopModule,
|
||||
};
|
||||
|
||||
/**
|
||||
** Place samples in audio output queue.
|
||||
**
|
||||
@@ -1694,14 +1932,7 @@ static void AudioExitThread(void)
|
||||
*/
|
||||
void AudioEnqueue(const void *samples, int count)
|
||||
{
|
||||
#ifdef USE_ALSA
|
||||
AlsaEnqueue(samples, count);
|
||||
#endif
|
||||
#ifdef USE_OSS
|
||||
OssEnqueue(samples, count);
|
||||
#endif
|
||||
(void)samples;
|
||||
(void)count;
|
||||
AudioUsedModule->Enqueue(samples, count);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1709,23 +1940,7 @@ void AudioEnqueue(const void *samples, int count)
|
||||
*/
|
||||
void AudioFlushBuffers(void)
|
||||
{
|
||||
#ifdef USE_ALSA
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
if (AudioRunning) {
|
||||
while (AudioRunning) {
|
||||
AlsaFlushBuffer = 1;
|
||||
usleep(1 * 1000);
|
||||
}
|
||||
AlsaFlushBuffer = 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
AlsaFlushBuffers();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_OSS
|
||||
OssFlushBuffers();
|
||||
#endif
|
||||
AudioUsedModule->FlushBuffers();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1733,14 +1948,7 @@ void AudioFlushBuffers(void)
|
||||
*/
|
||||
void AudioPoller(void)
|
||||
{
|
||||
#ifndef USE_AUDIO_THREAD
|
||||
#ifdef USE_ALSA
|
||||
Error(_("audio/alsa: poller not implemented\n"));
|
||||
#endif
|
||||
#ifdef USE_OSS
|
||||
OssPoller();
|
||||
#endif
|
||||
#endif
|
||||
AudioUsedModule->Poller();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1748,13 +1956,17 @@ void AudioPoller(void)
|
||||
*/
|
||||
int AudioFreeBytes(void)
|
||||
{
|
||||
#ifdef USE_ALSA
|
||||
return RingBufferFreeBytes(AlsaRingBuffer);
|
||||
#endif
|
||||
#ifdef USE_OSS
|
||||
return RingBufferFreeBytes(OssRingBuffer);
|
||||
#endif
|
||||
return -1;
|
||||
return AudioUsedModule->FreeBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
** Get audio delay in time stamps.
|
||||
**
|
||||
** @returns audio delay in time stamps.
|
||||
*/
|
||||
uint64_t AudioGetDelay(void)
|
||||
{
|
||||
return AudioUsedModule->GetDelay();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1774,22 +1986,6 @@ void AudioSetClock(int64_t pts)
|
||||
AudioPTS = pts;
|
||||
}
|
||||
|
||||
/**
|
||||
** Get audio delay in time stamps.
|
||||
**
|
||||
** @returns audio delay in time stamps.
|
||||
*/
|
||||
uint64_t AudioGetDelay(void)
|
||||
{
|
||||
#ifdef USE_ALSA
|
||||
return AlsaGetDelay();
|
||||
#endif
|
||||
#ifdef USE_OSS
|
||||
return OssGetDelay();
|
||||
#endif
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
/**
|
||||
** Get current audio clock.
|
||||
**
|
||||
@@ -1797,11 +1993,12 @@ uint64_t AudioGetDelay(void)
|
||||
*/
|
||||
int64_t AudioGetClock(void)
|
||||
{
|
||||
int64_t delay;
|
||||
if ((uint64_t) AudioPTS != INT64_C(0x8000000000000000)) {
|
||||
int64_t delay;
|
||||
|
||||
delay = AudioGetDelay();
|
||||
if (delay && (uint64_t) AudioPTS != INT64_C(0x8000000000000000)) {
|
||||
return AudioPTS - delay;
|
||||
if ((delay = AudioGetDelay())) {
|
||||
return AudioPTS - delay;
|
||||
}
|
||||
}
|
||||
return INT64_C(0x8000000000000000);
|
||||
}
|
||||
@@ -1844,53 +2041,81 @@ int AudioSetup(int *freq, int *channels)
|
||||
// FIXME: set flag invalid setup
|
||||
return -1;
|
||||
}
|
||||
#if defined(SEARCH_HDMI_BUG) || defined(SEARCH_HDMI_BUG2)
|
||||
#ifdef USE_AUDIORING
|
||||
// FIXME: need to store possible combination and report this
|
||||
return AudioRingAdd(*freq, *channels);
|
||||
#endif
|
||||
#ifdef USE_ALSA
|
||||
return AlsaSetup(freq, channels);
|
||||
#endif
|
||||
#ifdef USE_OSS
|
||||
return OssSetup(freq, channels);
|
||||
#endif
|
||||
return -1;
|
||||
return AudioUsedModule->Setup(freq, channels);
|
||||
}
|
||||
|
||||
/**
|
||||
** Set pcm audio device.
|
||||
**
|
||||
** @param device name of pcm device (fe. "hw:0,9" or "/dev/dsp")
|
||||
**
|
||||
** @note this is currently used to select alsa/OSS output module.
|
||||
*/
|
||||
void AudioSetDevice(const char *device)
|
||||
{
|
||||
AudioModuleName = "alsa"; // detect alsa/OSS
|
||||
if (!device[0]) {
|
||||
AudioModuleName = "noop";
|
||||
} else if (device[0] == '/') {
|
||||
AudioModuleName = "oss";
|
||||
}
|
||||
AudioPCMDevice = device;
|
||||
}
|
||||
|
||||
/**
|
||||
** Initialize audio output module.
|
||||
**
|
||||
** @todo FIXME: make audio output module selectable.
|
||||
*/
|
||||
void AudioInit(void)
|
||||
{
|
||||
int freq;
|
||||
int chan;
|
||||
unsigned u;
|
||||
const char *name;
|
||||
|
||||
#ifdef SEARCH_HDMI_BUG2
|
||||
AudioRingInit();
|
||||
name = "noop";
|
||||
#ifdef USE_OSS
|
||||
name = "oss";
|
||||
#endif
|
||||
#ifdef USE_ALSA
|
||||
AlsaInit();
|
||||
name = "alsa";
|
||||
#endif
|
||||
#ifdef USE_OSS
|
||||
OssInit();
|
||||
if (AudioModuleName) {
|
||||
name = AudioModuleName;
|
||||
}
|
||||
//
|
||||
// search selected audio module.
|
||||
//
|
||||
for (u = 0; u < sizeof(AudioModules) / sizeof(*AudioModules); ++u) {
|
||||
if (!strcasecmp(name, AudioModules[u]->Name)) {
|
||||
AudioUsedModule = AudioModules[u];
|
||||
Info(_("audio: '%s' output module used\n"), AudioUsedModule->Name);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
Error(_("audio: '%s' output module isn't supported\n"), name);
|
||||
AudioUsedModule = &NoopModule;
|
||||
return;
|
||||
|
||||
found:
|
||||
#ifdef USE_AUDIORING
|
||||
AudioRingInit();
|
||||
#endif
|
||||
AudioUsedModule->Init();
|
||||
freq = 48000;
|
||||
chan = 2;
|
||||
if (AudioSetup(&freq, &chan)) { // set default parameters
|
||||
Error(_("audio: can't do initial setup\n"));
|
||||
}
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
AudioInitThread();
|
||||
if (AudioUsedModule->Thread) { // supports threads
|
||||
AudioInitThread();
|
||||
}
|
||||
#endif
|
||||
|
||||
AudioPaused = 1;
|
||||
@@ -1904,13 +2129,9 @@ void AudioExit(void)
|
||||
#ifdef USE_AUDIO_THREAD
|
||||
AudioExitThread();
|
||||
#endif
|
||||
#ifdef USE_ALSA
|
||||
AlsaExit();
|
||||
#endif
|
||||
#ifdef USE_OSS
|
||||
OssExit();
|
||||
#endif
|
||||
#ifdef SEARCH_HDMI_BUG2
|
||||
AudioUsedModule->Exit();
|
||||
AudioUsedModule = &NoopModule;
|
||||
#ifdef USE_AUDIORING
|
||||
AudioRingExit();
|
||||
#endif
|
||||
}
|
||||
@@ -1956,7 +2177,7 @@ static void PrintVersion(void)
|
||||
#ifdef GIT_REV
|
||||
"(GIT-" GIT_REV ")"
|
||||
#endif
|
||||
",\n\t(c) 2009 - 2011 by Johns\n"
|
||||
",\n\t(c) 2009 - 2012 by Johns\n"
|
||||
"\tLicense AGPLv3: GNU Affero General Public License version 3\n");
|
||||
}
|
||||
|
||||
|
||||
8
audio.h
8
audio.h
@@ -30,21 +30,19 @@
|
||||
extern void AudioEnqueue(const void *, int); ///< buffer audio samples
|
||||
extern void AudioFlushBuffers(void); ///< flush audio buffers
|
||||
extern void AudioPoller(void); ///< poll audio events/handling
|
||||
|
||||
extern int AudioFreeBytes(void); ///< free bytes in audio output
|
||||
|
||||
//extern int AudioUsedBytes(void); ///< used bytes in audio output
|
||||
extern uint64_t AudioGetDelay(void); ///< get current audio delay
|
||||
extern void AudioSetClock(int64_t); ///< set audio clock base
|
||||
extern int64_t AudioGetClock(); ///< get current audio clock
|
||||
extern uint64_t AudioGetDelay(void); ///< get current audio delay
|
||||
|
||||
extern void AudioSetVolume(int); ///< set volume
|
||||
extern int AudioSetup(int *, int *); ///< setup audio output
|
||||
|
||||
//extern void AudioPlay(void); ///< play audio
|
||||
//extern void AudioPause(void); ///< pause audio
|
||||
extern void AudioSetVolume(int); ///< set volume
|
||||
|
||||
extern void AudioSetDevice(const char *); ///< set alsa PCM audio device
|
||||
extern void AudioSetDevice(const char *); ///< set PCM audio device
|
||||
extern void AudioInit(void); ///< setup audio module
|
||||
extern void AudioExit(void); ///< cleanup and exit audio module
|
||||
|
||||
|
||||
180
softhddev.c
180
softhddev.c
@@ -35,6 +35,11 @@
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
#ifndef __USE_GNU
|
||||
#define __USE_GNU
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "softhddev.h"
|
||||
|
||||
@@ -52,7 +57,13 @@ static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
|
||||
#define ConfigVdpauDecoder 0 ///< no vdpau decoder configured
|
||||
#endif
|
||||
|
||||
static const char DeviceStopped = 1; ///< flag device stopped
|
||||
static char ConfigFullscreen; ///< fullscreen modus
|
||||
static char ConfigSuspendClose = 1; ///< suspend should close devices
|
||||
static char ConfigSuspendX11 = 1; ///< suspend should stop x11
|
||||
|
||||
static pthread_mutex_t SuspendLockMutex; ///< suspend lock mutex
|
||||
|
||||
static volatile char VideoFreezed; ///< video freezed
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Audio
|
||||
@@ -195,13 +206,16 @@ int PlayAudio(const uint8_t * data, int size,
|
||||
|
||||
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
|
||||
|
||||
if (VideoFreezed) { // video freezed
|
||||
return 0;
|
||||
}
|
||||
if (NewAudioStream) {
|
||||
// FIXME: does this clear the audio ringbuffer?
|
||||
CodecAudioClose(MyAudioDecoder);
|
||||
AudioCodecID = CODEC_ID_NONE;
|
||||
NewAudioStream = 0;
|
||||
}
|
||||
if (SkipAudio) {
|
||||
if (SkipAudio) { // skip audio
|
||||
return size;
|
||||
}
|
||||
// PES header 0x00 0x00 0x01 ID
|
||||
@@ -313,7 +327,7 @@ int PlayAudio(const uint8_t * data, int size,
|
||||
void Mute(void)
|
||||
{
|
||||
SkipAudio = 1;
|
||||
AudioSetVolume(0);
|
||||
//AudioSetVolume(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,8 +362,8 @@ static AVPacket VideoPacketRb[VIDEO_PACKET_MAX];
|
||||
static int VideoPacketWrite; ///< write pointer
|
||||
static int VideoPacketRead; ///< read pointer
|
||||
static atomic_t VideoPacketsFilled; ///< how many of the buffer is used
|
||||
static volatile char VideoFreezed; ///< video freezed
|
||||
static volatile char VideoClearBuffers; ///< clear video buffers
|
||||
static volatile char SkipVideo; ///< skip video
|
||||
|
||||
#ifdef DEBUG
|
||||
static int VideoMaxPacketSize; ///< biggest used packet buffer
|
||||
@@ -567,19 +581,23 @@ int VideoDecode(void)
|
||||
/**
|
||||
** Try video start.
|
||||
**
|
||||
** Could be called, when already started.
|
||||
** NOT TRUE: Could be called, when already started.
|
||||
*/
|
||||
static void StartVideo(void)
|
||||
{
|
||||
VideoInit(X11DisplayName);
|
||||
if (ConfigFullscreen) {
|
||||
// FIXME: not good looking, mapped and then resized.
|
||||
VideoSetFullscreen(1);
|
||||
}
|
||||
VideoOsdInit();
|
||||
if (!MyVideoDecoder) {
|
||||
VideoHwDecoder *hw_decoder;
|
||||
|
||||
if ((hw_decoder = VideoNewHwDecoder())) {
|
||||
MyVideoDecoder = CodecVideoNewDecoder(hw_decoder);
|
||||
VideoCodecID = CODEC_ID_NONE;
|
||||
}
|
||||
VideoCodecID = CODEC_ID_NONE;
|
||||
}
|
||||
VideoPacketInit();
|
||||
}
|
||||
@@ -634,6 +652,9 @@ static int ValidateMpeg(const uint8_t * data, int size)
|
||||
** supports complete packets.
|
||||
** We buffer here until we receive an complete PES Packet, which
|
||||
** is no problem, the audio is always far behind us.
|
||||
** cTsToPes::GetPes splits the packets.
|
||||
**
|
||||
** @todo FIXME: combine the 5 ifs at start of the function
|
||||
*/
|
||||
int PlayVideo(const uint8_t * data, int size)
|
||||
{
|
||||
@@ -648,6 +669,12 @@ int PlayVideo(const uint8_t * data, int size)
|
||||
if (!MyVideoDecoder) { // no x11 video started
|
||||
return size;
|
||||
}
|
||||
if (SkipVideo) { // skip video
|
||||
return size;
|
||||
}
|
||||
if (VideoFreezed) { // video freezed
|
||||
return 0;
|
||||
}
|
||||
if (NewVideoStream) { // channel switched
|
||||
Debug(3, "video: new stream %d\n", GetMsTicks() - VideoSwitch);
|
||||
// FIXME: hack to test results
|
||||
@@ -668,10 +695,10 @@ int PlayVideo(const uint8_t * data, int size)
|
||||
n = data[8]; // header size
|
||||
// wrong size
|
||||
if (size < 9 + n + 4) {
|
||||
Error(_("[softhddev] invalid video packet\n"));
|
||||
Error(_("[softhddev] invalid video packet %d bytes\n"), size);
|
||||
return size;
|
||||
}
|
||||
// FIXME: hack to test results
|
||||
// buffer full: needed for replay
|
||||
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||
return 0;
|
||||
}
|
||||
@@ -735,6 +762,16 @@ int PlayVideo(const uint8_t * data, int size)
|
||||
Debug(3, "video: h264 detected\n");
|
||||
VideoCodecID = CODEC_ID_H264;
|
||||
}
|
||||
// Access Unit Delimiter (BBC-HD)
|
||||
// FIXME: the 4 offset are try & error selected
|
||||
} else if ((data[6] & 0xC0) == 0x80 && !check[4 + 0] && !check[4 + 1]
|
||||
&& !check[4 + 2] && check[4 + 3] == 0x1 && check[4 + 4] == 0x09) {
|
||||
if (VideoCodecID == CODEC_ID_H264) {
|
||||
VideoNextPacket(CODEC_ID_H264);
|
||||
} else {
|
||||
Debug(3, "video: h264 detected\n");
|
||||
VideoCodecID = CODEC_ID_H264;
|
||||
}
|
||||
} else {
|
||||
// this happens when vdr sends incomplete packets
|
||||
if (VideoCodecID == CODEC_ID_NONE) {
|
||||
@@ -754,6 +791,29 @@ int PlayVideo(const uint8_t * data, int size)
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
** Grabs the currently visible screen image.
|
||||
**
|
||||
** @param size size of the returned data
|
||||
** @param jpeg flag true, create JPEG data
|
||||
** @param quality JPEG quality
|
||||
** @param width number of horizontal pixels in the frame
|
||||
** @param height number of vertical pixels in the frame
|
||||
*/
|
||||
uint8_t *GrabImage(int *size, int jpeg, int quality, int width, int height)
|
||||
{
|
||||
if (jpeg) {
|
||||
(void)quality;
|
||||
Error(_("softhddev: jpeg grabbing not supported\n"));
|
||||
return NULL;
|
||||
}
|
||||
if (width != -1 && height != -1) {
|
||||
Error(_("softhddev: scaling not supported\n"));
|
||||
return NULL;
|
||||
}
|
||||
return VideoGrab(size, &width, &height);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
@@ -761,6 +821,7 @@ int PlayVideo(const uint8_t * data, int size)
|
||||
*/
|
||||
void SetPlayMode(void)
|
||||
{
|
||||
Resume();
|
||||
if (MyVideoDecoder) {
|
||||
if (VideoCodecID != CODEC_ID_NONE) {
|
||||
NewVideoStream = 1;
|
||||
@@ -774,6 +835,7 @@ void SetPlayMode(void)
|
||||
}
|
||||
VideoFreezed = 0;
|
||||
SkipAudio = 0;
|
||||
SkipVideo = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -877,22 +939,19 @@ int Flush(int timeout)
|
||||
void GetOsdSize(int *width, int *height, double *aspect)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
static char done;
|
||||
static int done_width;
|
||||
static int done_height;
|
||||
#endif
|
||||
|
||||
// FIXME: should be configured!
|
||||
*width = 1920;
|
||||
*height = 1080;
|
||||
//*width = 768;
|
||||
//*height = 576;
|
||||
|
||||
VideoGetOsdSize(width, height);
|
||||
*aspect = 16.0 / 9.0 / (double)*width * (double)*height;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!done) {
|
||||
if (done_width != *width || done_height != *height) {
|
||||
Debug(3, "[softhddev]%s: %dx%d %g\n", __FUNCTION__, *width, *height,
|
||||
*aspect);
|
||||
done = 1;
|
||||
done_width = *width;
|
||||
done_height = *height;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -910,12 +969,13 @@ void OsdClose(void)
|
||||
*/
|
||||
void OsdDrawARGB(int x, int y, int height, int width, const uint8_t * argb)
|
||||
{
|
||||
Resume();
|
||||
VideoOsdDrawARGB(x, y, height, width, argb);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static char StartX11Server; ///< flag start the x11 server
|
||||
static char ConfigStartX11Server; ///< flag start the x11 server
|
||||
|
||||
/**
|
||||
** Return command line help string.
|
||||
@@ -924,6 +984,7 @@ const char *CommandLineHelp(void)
|
||||
{
|
||||
return " -a device\taudio device (fe. alsa: hw:0,0 oss: /dev/dsp)\n"
|
||||
" -d display\tdisplay of x11 server (fe. :0.0)\n"
|
||||
" -f\t\tstart with fullscreen window (only with window manager)\n"
|
||||
" -g geometry\tx11 window geometry wxh+x+y\n"
|
||||
" -x\t\tstart x11 server\n";
|
||||
}
|
||||
@@ -940,13 +1001,16 @@ int ProcessArgs(int argc, char *const argv[])
|
||||
// Parse arguments.
|
||||
//
|
||||
for (;;) {
|
||||
switch (getopt(argc, argv, "-a:d:g:x")) {
|
||||
switch (getopt(argc, argv, "-a:d:fg:x")) {
|
||||
case 'a': // audio device
|
||||
AudioSetDevice(optarg);
|
||||
continue;
|
||||
case 'd': // x11 display name
|
||||
X11DisplayName = optarg;
|
||||
continue;
|
||||
case 'f': // fullscreen mode
|
||||
ConfigFullscreen = 1;
|
||||
continue;
|
||||
case 'g': // geometry
|
||||
if (VideoSetGeometry(optarg) < 0) {
|
||||
fprintf(stderr,
|
||||
@@ -956,7 +1020,7 @@ int ProcessArgs(int argc, char *const argv[])
|
||||
}
|
||||
continue;
|
||||
case 'x': // x11 server
|
||||
StartX11Server = 1;
|
||||
ConfigStartX11Server = 1;
|
||||
continue;
|
||||
case EOF:
|
||||
break;
|
||||
@@ -1076,8 +1140,12 @@ static void StartXServer(void)
|
||||
*/
|
||||
void SoftHdDeviceExit(void)
|
||||
{
|
||||
// lets hope that vdr does a good thead cleanup
|
||||
// no it doesn't do a good thread cleanup
|
||||
// lets hope that vdr does a good thread cleanup
|
||||
|
||||
VideoOsdExit();
|
||||
VideoExit();
|
||||
AudioExit();
|
||||
|
||||
if (MyVideoDecoder) {
|
||||
CodecVideoClose(MyVideoDecoder);
|
||||
// FIXME: CodecDelVideoDecoder(MyVideoDecoder);
|
||||
@@ -1089,19 +1157,19 @@ void SoftHdDeviceExit(void)
|
||||
MyAudioDecoder = NULL;
|
||||
}
|
||||
|
||||
VideoOsdExit();
|
||||
VideoExit();
|
||||
AudioExit();
|
||||
CodecExit();
|
||||
VideoPacketExit();
|
||||
|
||||
if (StartX11Server) {
|
||||
if (ConfigStartX11Server) {
|
||||
Debug(3, "x-setup: Stop x11 server\n");
|
||||
|
||||
if (X11ServerPid) {
|
||||
kill(X11ServerPid, SIGTERM);
|
||||
// FIXME: wait for x11 finishing
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&SuspendLockMutex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1109,15 +1177,17 @@ void SoftHdDeviceExit(void)
|
||||
*/
|
||||
void Start(void)
|
||||
{
|
||||
if (StartX11Server) {
|
||||
if (ConfigStartX11Server) {
|
||||
StartXServer();
|
||||
}
|
||||
CodecInit();
|
||||
// FIXME: AudioInit for HDMI after X11 startup
|
||||
AudioInit();
|
||||
if (!StartX11Server) {
|
||||
if (!ConfigStartX11Server) {
|
||||
StartVideo();
|
||||
}
|
||||
|
||||
pthread_mutex_init(&SuspendLockMutex, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1138,3 +1208,57 @@ void Stop(void)
|
||||
void MainThreadHook(void)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Suspend/Resume
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
** Suspend plugin.
|
||||
*/
|
||||
void Suspend(void)
|
||||
{
|
||||
pthread_mutex_lock(&SuspendLockMutex);
|
||||
if (SkipVideo && SkipAudio) { // already suspended
|
||||
pthread_mutex_unlock(&SuspendLockMutex);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug(3, "[softhddev]%s:\n", __FUNCTION__);
|
||||
|
||||
SkipVideo = 1;
|
||||
SkipAudio = 1;
|
||||
pthread_mutex_unlock(&SuspendLockMutex);
|
||||
|
||||
if (ConfigSuspendClose) {
|
||||
pthread_mutex_lock(&SuspendLockMutex);
|
||||
// FIXME: close audio
|
||||
// FIXME: close video
|
||||
pthread_mutex_unlock(&SuspendLockMutex);
|
||||
}
|
||||
if (ConfigSuspendX11) {
|
||||
// FIXME: stop x11, if started
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Resume plugin.
|
||||
*/
|
||||
void Resume(void)
|
||||
{
|
||||
if (!SkipVideo && !SkipAudio) { // we are not suspended
|
||||
return;
|
||||
}
|
||||
|
||||
Debug(3, "[softhddev]%s:\n", __FUNCTION__);
|
||||
|
||||
if (ConfigSuspendX11) {
|
||||
}
|
||||
if (ConfigSuspendClose) {
|
||||
pthread_mutex_lock(&SuspendLockMutex);
|
||||
pthread_mutex_unlock(&SuspendLockMutex);
|
||||
}
|
||||
|
||||
SkipVideo = 0;
|
||||
SkipAudio = 0;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ extern "C"
|
||||
extern int PlayVideo(const uint8_t *, int);
|
||||
/// C plugin play TS video packet
|
||||
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
|
||||
extern void SetPlayMode(void);
|
||||
@@ -76,6 +78,10 @@ extern "C"
|
||||
/// C plugin main thread hook
|
||||
extern void MainThreadHook(void);
|
||||
|
||||
/// Suspend plugin
|
||||
extern void Suspend(void);
|
||||
/// Resume plugin
|
||||
extern void Resume(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
322
softhddevice.cpp
322
softhddevice.cpp
@@ -42,22 +42,24 @@ extern "C"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const char *const VERSION = "0.3.0";
|
||||
static const char *const VERSION = "0.4.0";
|
||||
static const char *const DESCRIPTION =
|
||||
trNOOP("A software and GPU emulated HD device");
|
||||
|
||||
//static const char *MAINMENUENTRY = trNOOP("Soft-HD-Device");
|
||||
static const char *MAINMENUENTRY = trNOOP("Suspend Soft-HD-Device");
|
||||
static class cSoftHdDevice *MyDevice;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define RESOLUTIONS 4 ///< number of resolutions
|
||||
|
||||
/// resolutions names
|
||||
static const char *const Resolution[RESOLUTIONS] = {
|
||||
"576i", "720p", "1080i_fake", "1080i"
|
||||
};
|
||||
|
||||
static char ConfigMakePrimary; ///< config primary wanted
|
||||
static char ConfigHideMainMenuEntry; ///< config hide main menu entry
|
||||
|
||||
/// config deinterlace
|
||||
static int ConfigVideoDeinterlace[RESOLUTIONS];
|
||||
@@ -77,6 +79,9 @@ static int ConfigVideoScaling[RESOLUTIONS];
|
||||
static int ConfigVideoAudioDelay; ///< config audio delay
|
||||
static int ConfigAudioPassthrough; ///< config audio pass-through
|
||||
|
||||
static int ConfigAutoCropInterval; ///< auto crop detection interval
|
||||
static int ConfigAutoCropDelay; ///< auto crop detection delay
|
||||
|
||||
static volatile char DoMakePrimary; ///< flag switch primary
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -121,7 +126,7 @@ extern "C" void FeedKeyPress(const char *keymap, const char *key, int repeat,
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -131,8 +136,10 @@ extern "C" void FeedKeyPress(const char *keymap, const char *key, int repeat,
|
||||
|
||||
class cSoftOsd:public cOsd
|
||||
{
|
||||
int Level; ///< level: subtitle
|
||||
|
||||
public:
|
||||
cSoftOsd(int, int, uint);
|
||||
cSoftOsd(int, int, uint);
|
||||
virtual ~ cSoftOsd(void);
|
||||
virtual void Flush(void);
|
||||
// virtual void SetActive(bool);
|
||||
@@ -141,11 +148,13 @@ class cSoftOsd:public cOsd
|
||||
cSoftOsd::cSoftOsd(int left, int top, uint level)
|
||||
:cOsd(left, top, level)
|
||||
{
|
||||
// FIXME: OsdWidth/OsdHeight not correct!
|
||||
dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(),
|
||||
OsdHeight(), left, top, level);
|
||||
/* FIXME: OsdWidth/OsdHeight not correct!
|
||||
dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(),
|
||||
OsdHeight(), left, top, level);
|
||||
*/
|
||||
|
||||
//SetActive(true);
|
||||
this->Level = level;
|
||||
SetActive(true);
|
||||
}
|
||||
|
||||
cSoftOsd::~cSoftOsd(void)
|
||||
@@ -154,8 +163,15 @@ cSoftOsd::~cSoftOsd(void)
|
||||
SetActive(false);
|
||||
|
||||
#ifdef USE_YAEPG
|
||||
if (vidWin.bpp) {
|
||||
VideoSetOutputPosition(0, 0, 1920, 1080);
|
||||
// support yaepghd, video window
|
||||
if (vidWin.bpp) { // restore fullsized video
|
||||
int width;
|
||||
int height;
|
||||
double video_aspect;
|
||||
|
||||
::GetOsdSize(&width, &height, &video_aspect);
|
||||
// works osd relative
|
||||
VideoSetOutputPosition(0, 0, width, height);
|
||||
}
|
||||
#endif
|
||||
OsdClose();
|
||||
@@ -171,8 +187,8 @@ void cSoftOsd::Flush(void)
|
||||
if (!Active()) {
|
||||
return;
|
||||
}
|
||||
// support yaepghd, video window
|
||||
#ifdef USE_YAEPG
|
||||
// support yaepghd, video window
|
||||
if (vidWin.bpp) {
|
||||
dsyslog("[softhddev]%s: %dx%d+%d+%d\n", __FUNCTION__, vidWin.Width(),
|
||||
vidWin.Height(), vidWin.x1, vidWin.y2);
|
||||
@@ -209,6 +225,7 @@ void cSoftOsd::Flush(void)
|
||||
if (!bitmap->Dirty(x1, y1, x2, y2)) {
|
||||
continue; // nothing dirty continue
|
||||
}
|
||||
#if 0
|
||||
// FIXME: need only to convert and upload dirty areas
|
||||
|
||||
// DrawBitmap(bitmap);
|
||||
@@ -221,9 +238,44 @@ void cSoftOsd::Flush(void)
|
||||
((uint32_t *) argb)[x + y * w] = bitmap->GetColor(x, y);
|
||||
}
|
||||
}
|
||||
// check if subtitles
|
||||
if (this->Level == OSD_LEVEL_SUBTITLES) {
|
||||
int video_width;
|
||||
int video_height;
|
||||
|
||||
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(),
|
||||
bitmap->Width(), bitmap->Height(), argb);
|
||||
if (0) {
|
||||
dsyslog("[softhddev]%s: subtitle %d, %d\n", __FUNCTION__,
|
||||
Left() + bitmap->X0(), Top() + bitmap->Y0());
|
||||
}
|
||||
video_width = 1920;
|
||||
video_height = 1080;
|
||||
OsdDrawARGB((1920 - video_width) / 2 + Left() + bitmap->X0(),
|
||||
1080 - video_height + Top() + bitmap->Y0(), w, h, argb);
|
||||
} else {
|
||||
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(), w, h,
|
||||
argb);
|
||||
}
|
||||
#else
|
||||
// convert and upload only dirty areas
|
||||
w = x2 - x1 + 1;
|
||||
h = y2 - y1 + 1;
|
||||
#ifdef DEBUG
|
||||
if (w > bitmap->Width() || h > bitmap->Height()) {
|
||||
esyslog(tr("softhdev: dirty area too big\n"));
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
argb = (uint8_t *) malloc(w * h * sizeof(uint32_t));
|
||||
for (y = y1; y <= y2; ++y) {
|
||||
for (x = x1; x <= x2; ++x) {
|
||||
((uint32_t *) argb)[x - x1 + (y - y1) * w] =
|
||||
bitmap->GetColor(x, y);
|
||||
}
|
||||
}
|
||||
// check if subtitles
|
||||
OsdDrawARGB(Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1,
|
||||
w, h, argb);
|
||||
#endif
|
||||
|
||||
bitmap->Clean();
|
||||
free(argb);
|
||||
@@ -244,8 +296,8 @@ void cSoftOsd::Flush(void)
|
||||
h = pm->ViewPort().Height();
|
||||
|
||||
/*
|
||||
dsyslog("[softhddev]%s: draw %dx%d+%d+%d %p\n", __FUNCTION__, w, h, x,
|
||||
y, pm->Data());
|
||||
dsyslog("[softhddev]%s: draw %dx%d+%d+%d %p\n", __FUNCTION__, w, h,
|
||||
x, y, pm->Data());
|
||||
*/
|
||||
|
||||
OsdDrawARGB(x, y, w, h, pm->Data());
|
||||
@@ -306,6 +358,7 @@ class cMenuSetupSoft:public cMenuSetupPage
|
||||
{
|
||||
protected:
|
||||
int MakePrimary;
|
||||
int HideMainMenuEntry;
|
||||
int Scaling[RESOLUTIONS];
|
||||
int Deinterlace[RESOLUTIONS];
|
||||
int SkipChromaDeinterlace[RESOLUTIONS];
|
||||
@@ -313,6 +366,8 @@ class cMenuSetupSoft:public cMenuSetupPage
|
||||
int Sharpen[RESOLUTIONS];
|
||||
int AudioDelay;
|
||||
int AudioPassthrough;
|
||||
int AutoCropInterval;
|
||||
int AutoCropDelay;
|
||||
protected:
|
||||
virtual void Store(void);
|
||||
public:
|
||||
@@ -321,6 +376,8 @@ class cMenuSetupSoft:public cMenuSetupPage
|
||||
|
||||
/**
|
||||
** Create a seperator item.
|
||||
**
|
||||
** @param label text inside separator
|
||||
*/
|
||||
static inline cOsdItem *SeparatorItem(const char *label)
|
||||
{
|
||||
@@ -338,7 +395,7 @@ static inline cOsdItem *SeparatorItem(const char *label)
|
||||
cMenuSetupSoft::cMenuSetupSoft(void)
|
||||
{
|
||||
static const char *const deinterlace[] = {
|
||||
"Bob", "Weave", "Temporal", "TemporalSpatial", "Software"
|
||||
"Bob", "Weave/None", "Temporal", "TemporalSpatial", "Software"
|
||||
};
|
||||
static const char *const scaling[] = {
|
||||
"Normal", "Fast", "HQ", "Anamorphic"
|
||||
@@ -355,7 +412,10 @@ cMenuSetupSoft::cMenuSetupSoft(void)
|
||||
// cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem
|
||||
MakePrimary = ConfigMakePrimary;
|
||||
Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary,
|
||||
tr("no"), tr("yes")));
|
||||
trVDR("no"), trVDR("yes")));
|
||||
HideMainMenuEntry = ConfigHideMainMenuEntry;
|
||||
Add(new cMenuEditBoolItem(tr("Hide main menu entry"), &HideMainMenuEntry,
|
||||
trVDR("no"), trVDR("yes")));
|
||||
//
|
||||
// video
|
||||
//
|
||||
@@ -369,7 +429,7 @@ cMenuSetupSoft::cMenuSetupSoft(void)
|
||||
deinterlace));
|
||||
SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i];
|
||||
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),
|
||||
&SkipChromaDeinterlace[i], tr("no"), tr("yes")));
|
||||
&SkipChromaDeinterlace[i], trVDR("no"), trVDR("yes")));
|
||||
Denoise[i] = ConfigVideoDenoise[i];
|
||||
Add(new cMenuEditIntItem(tr("Denoise (0..1000) (vdpau)"), &Denoise[i],
|
||||
0, 1000));
|
||||
@@ -387,6 +447,16 @@ cMenuSetupSoft::cMenuSetupSoft(void)
|
||||
AudioPassthrough = ConfigAudioPassthrough;
|
||||
Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2,
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,6 +467,8 @@ void cMenuSetupSoft::Store(void)
|
||||
int i;
|
||||
|
||||
SetupStore("MakePrimary", ConfigMakePrimary = MakePrimary);
|
||||
SetupStore("HideMainMenuEntry", ConfigHideMainMenuEntry =
|
||||
HideMainMenuEntry);
|
||||
|
||||
for (i = 0; i < RESOLUTIONS; ++i) {
|
||||
char buf[128];
|
||||
@@ -424,6 +496,11 @@ void cMenuSetupSoft::Store(void)
|
||||
VideoSetAudioDelay(ConfigVideoAudioDelay);
|
||||
SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough);
|
||||
CodecSetAudioPassthrough(ConfigAudioPassthrough);
|
||||
|
||||
SetupStore("AutoCrop.Interval", ConfigAutoCropInterval = AutoCropInterval);
|
||||
SetupStore("AutoCrop.Delay", ConfigAutoCropDelay = AutoCropDelay);
|
||||
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -449,10 +526,12 @@ class cSoftHdDevice:public cDevice
|
||||
virtual bool Poll(cPoller &, int = 0);
|
||||
virtual bool Flush(int = 0);
|
||||
virtual int64_t GetSTC(void);
|
||||
virtual void GetVideoSize(int &, int &, double &);
|
||||
virtual void GetOsdSize(int &, int &, double &);
|
||||
virtual int PlayVideo(const uchar *, int);
|
||||
|
||||
//virtual int PlayTsVideo(const uchar *, int);
|
||||
#ifdef USE_OSS // FIXME: testing only oss
|
||||
#ifndef USE_AUDIO_THREAD // FIXME: testing none threaded
|
||||
virtual int PlayTsAudio(const uchar *, int);
|
||||
#endif
|
||||
virtual void SetAudioChannelDevice(int);
|
||||
@@ -465,13 +544,13 @@ class cSoftHdDevice:public cDevice
|
||||
|
||||
virtual uchar *GrabImage(int &, bool, int, int, int);
|
||||
|
||||
virtual int ProvidesCa(const cChannel *) const;
|
||||
|
||||
#if 0
|
||||
// SPU facilities
|
||||
private:
|
||||
cDvbSpuDecoder * spuDecoder;
|
||||
public:
|
||||
virtual cSpuDecoder * GetSpuDecoder(void);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual void MakePrimaryDevice(bool);
|
||||
@@ -481,7 +560,9 @@ cSoftHdDevice::cSoftHdDevice(void)
|
||||
{
|
||||
//dsyslog("[softhddev]%s\n", __FUNCTION__);
|
||||
|
||||
#if 0
|
||||
spuDecoder = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
cSoftHdDevice::~cSoftHdDevice(void)
|
||||
@@ -489,6 +570,11 @@ cSoftHdDevice::~cSoftHdDevice(void)
|
||||
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
** Informs a device that it will be the primary device.
|
||||
**
|
||||
** @param on flag if becoming or loosing primary
|
||||
*/
|
||||
void cSoftHdDevice::MakePrimaryDevice(bool on)
|
||||
{
|
||||
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on);
|
||||
@@ -499,13 +585,7 @@ void cSoftHdDevice::MakePrimaryDevice(bool on)
|
||||
}
|
||||
}
|
||||
|
||||
int cSoftHdDevice::ProvidesCa(
|
||||
__attribute__ ((unused)) const cChannel * channel) const
|
||||
{
|
||||
//dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
|
||||
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
|
||||
{
|
||||
@@ -517,6 +597,8 @@ cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
|
||||
return spuDecoder;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool cSoftHdDevice::HasDecoder(void) const
|
||||
{
|
||||
return true;
|
||||
@@ -540,7 +622,7 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
|
||||
case pmVideoOnly:
|
||||
break;
|
||||
case pmNone:
|
||||
break;
|
||||
return true;
|
||||
case pmExtern_THIS_SHOULD_BE_AVOIDED:
|
||||
break;
|
||||
default:
|
||||
@@ -584,6 +666,9 @@ void cSoftHdDevice::Play(void)
|
||||
::Play();
|
||||
}
|
||||
|
||||
/**
|
||||
** Puts the device into "freeze frame" mode.
|
||||
*/
|
||||
void cSoftHdDevice::Freeze(void)
|
||||
{
|
||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
@@ -652,7 +737,18 @@ bool cSoftHdDevice::Flush(int timeout_ms)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** Returns the With, Height and PixelAspect ratio the OSD.
|
||||
** Returns the width, height and video_aspect ratio of the currently
|
||||
** displayed video material.
|
||||
**
|
||||
** @note the size is used to scale the subtitle.
|
||||
*/
|
||||
void cSoftHdDevice::GetVideoSize(int &width, int &height, double &video_aspect)
|
||||
{
|
||||
::GetOsdSize(&width, &height, &video_aspect);
|
||||
}
|
||||
|
||||
/**
|
||||
** Returns the width, height and pixel_aspect ratio the OSD.
|
||||
**
|
||||
** FIXME: Called every second, for nothing (no OSD displayed)?
|
||||
*/
|
||||
@@ -712,33 +808,47 @@ int cSoftHdDevice::PlayVideo(const uchar * data, int length)
|
||||
///
|
||||
/// Play a TS video packet.
|
||||
///
|
||||
int cSoftHdDevice::PlayTsVideo(const uchar * Data, int Length)
|
||||
int cSoftHdDevice::PlayTsVideo(const uchar * data, int length)
|
||||
{
|
||||
// many code to repeat
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_OSS // FIXME: testing only oss
|
||||
#ifndef USE_AUDIO_THREAD // FIXME: testing none threaded
|
||||
|
||||
///
|
||||
/// Play a TS audio packet.
|
||||
///
|
||||
/// misuse this function as audio poller
|
||||
///
|
||||
/// @param data ts data buffer
|
||||
/// @param length ts packet length
|
||||
///
|
||||
int cSoftHdDevice::PlayTsAudio(const uchar * data, int length)
|
||||
{
|
||||
AudioPoller();
|
||||
|
||||
return cDevice::PlayTsAudio(data, length);
|
||||
}
|
||||
|
||||
#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,
|
||||
quality, sizex, sizey);
|
||||
quality, width, height);
|
||||
|
||||
return NULL;
|
||||
return::GrabImage(&size, jpeg, quality, width, height);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -759,11 +869,13 @@ class cPluginSoftHdDevice:public cPlugin
|
||||
virtual void Stop(void);
|
||||
// virtual void Housekeeping(void);
|
||||
virtual void MainThreadHook(void);
|
||||
// virtual const char *MainMenuEntry(void);
|
||||
// virtual cOsdObject *MainMenuAction(void);
|
||||
virtual const char *MainMenuEntry(void);
|
||||
virtual cOsdObject *MainMenuAction(void);
|
||||
virtual cMenuSetupPage *SetupMenu(void);
|
||||
virtual bool SetupParse(const char *, const char *);
|
||||
// virtual bool Service(const char *Id, void *Data = NULL);
|
||||
// virtual bool Service(const char *, void * = NULL);
|
||||
virtual const char **SVDRPHelpPages(void);
|
||||
virtual cString SVDRPCommand(const char *, const char *, int &);
|
||||
};
|
||||
|
||||
cPluginSoftHdDevice::cPluginSoftHdDevice(void)
|
||||
@@ -820,15 +932,14 @@ bool cPluginSoftHdDevice::Initialize(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
** Start any background activities the plugin shall perform.
|
||||
*/
|
||||
bool cPluginSoftHdDevice::Start(void)
|
||||
{
|
||||
const cDevice *primary;
|
||||
|
||||
// Start any background activities the plugin shall perform.
|
||||
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
|
||||
primary = cDevice::PrimaryDevice();
|
||||
if (MyDevice != primary) {
|
||||
if (!MyDevice->IsPrimaryDevice()) {
|
||||
isyslog("[softhddev] softhddevice is not the primary device!");
|
||||
if (ConfigMakePrimary) {
|
||||
// Must be done in the main thread
|
||||
@@ -860,14 +971,33 @@ void cPluginSoftHdDevice::Housekeeping(void)
|
||||
// Perform any cleanup or other regular tasks.
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
** Create main menu entry.
|
||||
*/
|
||||
const char *cPluginSoftHdDevice::MainMenuEntry(void)
|
||||
{
|
||||
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
return tr(MAINMENUENTRY);
|
||||
return NULL;
|
||||
|
||||
return ConfigHideMainMenuEntry ? NULL : tr(MAINMENUENTRY);
|
||||
}
|
||||
|
||||
#endif
|
||||
/**
|
||||
** Perform the action when selected from the main VDR menu.
|
||||
*/
|
||||
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
|
||||
{
|
||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
|
||||
cDevice::PrimaryDevice()->StopReplay();
|
||||
Suspend();
|
||||
if (ShutdownHandler.GetUserInactiveTime()) {
|
||||
ShutdownHandler.SetUserInactive();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
** Called for every plugin once during every cycle of VDR's main program
|
||||
@@ -882,29 +1012,15 @@ void cPluginSoftHdDevice::MainThreadHook(void)
|
||||
cDevice::SetPrimaryDevice(MyDevice->DeviceNumber() + 1);
|
||||
DoMakePrimary = 0;
|
||||
}
|
||||
// check if user is inactive, automatic enter suspend mode
|
||||
if (ShutdownHandler.IsUserInactive()) {
|
||||
// this is regular called, but guarded against double calls
|
||||
Suspend();
|
||||
}
|
||||
|
||||
::MainThreadHook();
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
bool cPluginSoftHdDevice::Service(const char *Id, void *Data)
|
||||
{
|
||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
|
||||
{
|
||||
// Perform the action when selected from the main VDR menu.
|
||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
** Return our setup menu.
|
||||
*/
|
||||
@@ -917,20 +1033,29 @@ cMenuSetupPage *cPluginSoftHdDevice::SetupMenu(void)
|
||||
|
||||
/**
|
||||
** 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)
|
||||
{
|
||||
int i;
|
||||
char buf[128];
|
||||
|
||||
dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
|
||||
//dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
|
||||
|
||||
// FIXME: handle the values
|
||||
if (!strcmp(name, "MakePrimary")) {
|
||||
ConfigMakePrimary = atoi(value);
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(name, "HideMainMenuEntry")) {
|
||||
ConfigHideMainMenuEntry = atoi(value);
|
||||
return true;
|
||||
}
|
||||
for (i = 0; i < RESOLUTIONS; ++i) {
|
||||
char buf[128];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
|
||||
if (!strcmp(name, buf)) {
|
||||
ConfigVideoScaling[i] = atoi(value);
|
||||
@@ -963,6 +1088,7 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(name, "AudioDelay")) {
|
||||
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
|
||||
return true;
|
||||
@@ -972,7 +1098,65 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcmp(name, "AutoCrop.Interval")) {
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval =
|
||||
atoi(value), ConfigAutoCropDelay);
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(name, "AutoCrop.Delay")) {
|
||||
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay =
|
||||
atoi(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
bool cPluginSoftHdDevice::Service(const char *Id, void *Data)
|
||||
{
|
||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// cPlugin SVDRP
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
** Return SVDRP commands help pages.
|
||||
**
|
||||
** return a pointer to a list of help strings for all of the plugin's
|
||||
** SVDRP commands.
|
||||
*/
|
||||
const char **cPluginSoftHdDevice::SVDRPHelpPages(void)
|
||||
{
|
||||
// FIXME: translation?
|
||||
static const char *text[] = {
|
||||
"SUSP\n",
|
||||
" Suspend plugin",
|
||||
NULL
|
||||
};
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
** Handle SVDRP commands.
|
||||
*/
|
||||
cString cPluginSoftHdDevice::SVDRPCommand(const char *command,
|
||||
__attribute__ ((unused)) const char *option,
|
||||
__attribute__ ((unused)) int &reply_code)
|
||||
{
|
||||
if (!strcasecmp(command, "SUSP")) {
|
||||
Suspend();
|
||||
return "SoftHdDevice is suspended";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VDRPLUGINCREATOR(cPluginSoftHdDevice); // Don't touch this!
|
||||
|
||||
@@ -21,15 +21,15 @@ SRC_URI=""
|
||||
LICENSE="AGPL-3"
|
||||
SLOT="0"
|
||||
KEYWORDS="~x86 ~amd64"
|
||||
IUSE="vaapi vdpau alsa oss yaepg"
|
||||
IUSE="vaapi vdpau alsa oss yaepg opengl"
|
||||
|
||||
DEPEND=">=x11-libs/libxcb-1.7
|
||||
x11-libs/xcb-util
|
||||
x11-libs/xcb-util-wm
|
||||
x11-libs/xcb-util-wm
|
||||
x11-libs/xcb-util-keysyms
|
||||
x11-libs/xcb-util-renderutil
|
||||
x11-libs/libX11
|
||||
opengl? ( virtual/opengl )
|
||||
>=media-video/ffmpeg-0.7
|
||||
sys-devel/gettext
|
||||
sys-devel/make
|
||||
@@ -39,6 +39,7 @@ DEPEND=">=x11-libs/libxcb-1.7
|
||||
vdpau? ( x11-libs/libvdpau )
|
||||
vaapi? ( x11-libs/libva )
|
||||
alsa? ( media-libs/alsa-lib )
|
||||
oss? ( sys-kernel/linux-headers )
|
||||
"
|
||||
|
||||
src_prepare() {
|
||||
|
||||
21
video.h
21
video.h
@@ -37,6 +37,9 @@ typedef struct _video_hw_decoder_ VideoHwDecoder;
|
||||
/// Allocate new video hardware decoder.
|
||||
extern VideoHwDecoder *VideoNewHwDecoder(void);
|
||||
|
||||
/// Deallocate video hardware decoder.
|
||||
extern void VideoDelHwDecoder(VideoHwDecoder *);
|
||||
|
||||
/// Get and allocate a video hardware surface.
|
||||
extern unsigned VideoGetSurface(VideoHwDecoder *);
|
||||
|
||||
@@ -67,15 +70,18 @@ extern void VideoPollEvent(void);
|
||||
/// Wakeup display handler.
|
||||
extern void VideoDisplayWakeup(void);
|
||||
|
||||
/// Set video mode.
|
||||
//extern void VideoSetVideoMode(int, int, int, int);
|
||||
|
||||
/// Set video geometry.
|
||||
extern int VideoSetGeometry(const char *);
|
||||
|
||||
/// Set video output position.
|
||||
extern void VideoSetOutputPosition(int, int, int, int);
|
||||
|
||||
/// Set video mode.
|
||||
extern void VideoSetVideoMode(int, int, int, int);
|
||||
|
||||
/// Set video fullscreen mode.
|
||||
extern void VideoSetFullscreen(int);
|
||||
|
||||
/// Set deinterlace.
|
||||
extern void VideoSetDeinterlace(int[]);
|
||||
|
||||
@@ -94,14 +100,23 @@ extern void VideoSetSharpen(int[]);
|
||||
/// Set audio delay.
|
||||
extern void VideoSetAudioDelay(int);
|
||||
|
||||
/// Set auto-crop parameters.
|
||||
extern void VideoSetAutoCrop(int, int);
|
||||
|
||||
/// Clear OSD.
|
||||
extern void VideoOsdClear(void);
|
||||
|
||||
/// Draw an OSD ARGB image.
|
||||
extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *);
|
||||
|
||||
/// Get OSD size.
|
||||
extern void VideoGetOsdSize(int *, int *);
|
||||
|
||||
extern int64_t VideoGetClock(void); ///< Get video clock.
|
||||
|
||||
/// Grab screen.
|
||||
extern uint8_t *VideoGrab(int *, int *, int *);
|
||||
|
||||
extern void VideoOsdInit(void); ///< Setup osd.
|
||||
extern void VideoOsdExit(void); ///< Cleanup osd.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user