37 Commits
0.3.0 ... 0.4.0

Author SHA1 Message Date
Johns
fa27a1c73a Release Version 0.4.0. 2012-01-21 15:56:45 +01:00
Johns
e32857a27a VDPAU: Add screenshot support. 2012-01-20 21:46:22 +01:00
Johns
5ba88bb822 Use common module prefix. 2012-01-20 19:56:06 +01:00
Johns
0422b6aa5a VDPAU: Add auto-crop support. 2012-01-20 15:33:37 +01:00
Johns
eb024558de VDPAU: Changed OSD alpha calculation. 2012-01-19 22:58:02 +01:00
Johns
1593d5dd83 Fix bug: Used VideoSharpen for denoise settings.
Instant update deinterlace/... configuration changes.
2012-01-19 21:28:38 +01:00
Johns
09f62307d4 Fix bug: AudioExit called without AudioInit crash. 2012-01-19 17:01:02 +01:00
Johns
87f7aa63cc Release Version 0.3.5. 2012-01-19 16:01:05 +01:00
Johns
b1ce88923e Small miscellaneous cleanups. 2012-01-19 00:16:15 +01:00
Johns
c6e66e0787 OSD improvements:
Use OSD size equal to video window.
Update only dirty area(s) of OSD.
Show/mix only used area of OSD.
Fix bug: vpdau use previous resolution for deint, ...
2012-01-18 15:15:37 +01:00
Johns
19d4eeed82 Little speed improved Intel VA-API deinterlace. 2012-01-17 18:53:53 +01:00
Johns
9f668c4750 Fix software deinterlace with VA-API. 2012-01-17 17:41:24 +01:00
Johns
e419742a40 OSS needs kernel headers. 2012-01-16 23:55:45 +01:00
Johns
2cacdc6c90 Debug, if vaapi putsurface is too slow. 2012-01-16 23:54:48 +01:00
Johns
6efe558f78 Fix bug: transposed digits 567 should be 576. 2012-01-16 20:20:01 +01:00
Johns
80100299f3 Disable VA-API if init fails. 2012-01-16 17:05:22 +01:00
Johns
5509d768ac Remove double x11-libs/xcb-util-wm. 2012-01-16 16:39:23 +01:00
Johns
c0d0a4ae7c Audio module cleanup (more to come).
Alsa + OSS can be included/build at the same time.
Alsa or OSS can be runtime selected with -a.
Add audio thread support to OSS module.
Add polled audio support to alsa module.
Removed some debug source code.
2012-01-16 15:42:17 +01:00
Johns
e619f5c836 Release Version 0.3.1. 2012-01-15 16:57:03 +01:00
Johns
973fcfe4dd Support BBC-HD (no clean solution). 2012-01-15 14:31:54 +01:00
Johns
eec30433b6 Fix bug: AudioFreeBytes fails if no audio ready. 2012-01-13 22:39:04 +01:00
Johns
baf577aba5 Fix bug: snd_pcm_state: Assertion `pcm' failed. 2012-01-13 19:33:59 +01:00
Johns
81d7ef9755 Support xcb_ewmh.h for xcb-util <0.3.8. 2012-01-13 17:20:43 +01:00
Johns
7f7de8678f Add support for fullscreen mode. 2012-01-13 16:31:29 +01:00
Johns
92bb00c410 Add vaapi color space conversion. 2012-01-13 12:28:56 +01:00
Johns
d3b98b90f4 Fix bug: devision by zero in ...UpdateOutput, 2012-01-13 10:04:26 +01:00
Johns
788636ee6b Destroy vdpau surface only, when initialized. 2012-01-13 00:58:30 +01:00
Johns
8e53cbd4a9 VAAPI: Instant use new deinterlace configuration. 2012-01-12 23:07:06 +01:00
Johns
54661f90ea Weave is deinterlace disabled. 2012-01-12 20:54:49 +01:00
Johns
30d8e8afe9 Fix subtitle position. 2012-01-12 18:55:07 +01:00
Johns
19a37bb0bf Add SVDRP support. 2012-01-12 15:20:01 +01:00
Johns
2087968d55 Rebuild objects, when Makefile changes. 2012-01-12 15:19:19 +01:00
Johns
d983f780b3 Suspend when user is inactive. 2012-01-11 18:01:18 +01:00
712b2e0de1 Patch collection from Christian Ruppert.
Move objects before $LIBS to avoid link failures with --as-needed.
Do not override CFLAGS for video test.
Rearrange *FLAGS incl. some minor fixes.
Don't override VDRDIR, LIBDIR and TMPDIR in makefile.
Don't abuse LDFLAGS in makefile.
Define CC in makefile.
Include GL/gl.h for the GL_COLOR_BUFFER_BIT definition.
VideoInit() needs an argument.
2012-01-10 22:48:42 +01:00
Johns
54f92e67fc Don't mute hardware while replaying. 2012-01-10 16:41:46 +01:00
Johns
960cd27ab5 Add support for close and resize x11 window. 2012-01-10 15:53:54 +01:00
Johns
3a97700981 Add main menu entry, which suspends the plugin. 2012-01-10 15:52:07 +01:00
12 changed files with 2755 additions and 935 deletions

View File

@@ -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

View File

@@ -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 $@

View File

@@ -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
View File

@@ -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
View File

@@ -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");
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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!

View File

@@ -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() {

2226
video.c

File diff suppressed because it is too large Load Diff

21
video.h
View File

@@ -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.