18 Commits
0.3.1 ... 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
12 changed files with 2076 additions and 719 deletions

View File

@@ -1,4 +1,31 @@
User johns 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 Date: Sun Jan 15 16:56:04 CET 2012
Release Version 0.3.1 Release Version 0.3.1

View File

@@ -14,6 +14,7 @@ PLUGIN = softhddevice
### The version number of this plugin (taken from the main source file): ### 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') 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) ### Configuration (edit this for your needs)
@@ -22,7 +23,7 @@ CONFIG := #-DDEBUG
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU") CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI") CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA") CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
#CONFIG += -DUSE_OSS CONFIG += -DUSE_OSS
### The C++ compiler and options: ### The C++ compiler and options:
@@ -59,7 +60,8 @@ PACKAGE = vdr-$(ARCHIVE)
INCLUDES += -I$(VDRDIR)/include INCLUDES += -I$(VDRDIR)/include
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' \
$(if $(GIT_REV), -DGIT_REV='"$(GIT_REV)"')
_CFLAGS = $(DEFINES) $(INCLUDES) \ _CFLAGS = $(DEFINES) $(INCLUDES) \
$(shell pkg-config --cflags libavcodec libavformat) \ $(shell pkg-config --cflags libavcodec libavformat) \

View File

@@ -24,17 +24,20 @@ A software and GPU emulated HD output device plugin for VDR.
o Video CPU/VA-API o Video CPU/VA-API
o Video VDPAU/VDPAU o Video VDPAU/VDPAU
o Video CPU/VDPAU o Video CPU/VDPAU
o Audio FFMpeg/Alsa/Analog
o Audio FFMpeg/Alsa/Digital
o Audio FFMpeg/OSS/Analog
o HDMI/SPDIF Passthrough
o VA-API bob software deinterlace
o Auto-crop
o planned: Video VA-API/Opengl o planned: Video VA-API/Opengl
o planned: Video VDPAU/Opengl o planned: Video VDPAU/Opengl
o planned: Video CPU/Xv o planned: Video CPU/Xv
o planned: Video CPU/Opengl o planned: Video CPU/Opengl
o planned: Software Deinterlacer o planned: Improved Software Deinterlacer (yadif or/and ffmpeg filters)
o planned: Video XvBA/XvBA o planned: Video XvBA/XvBA
o Audio FFMpeg/Alsa/Analog o planned: atmo light support
o Audio FFMpeg/Alsa/Digital
o Audio FFMpeg/OSS/Analog
o Alsa HDMI/SPDIF Passthrough
o planned: OSS HDMI/SPDIF Passthrough
To compile you must have the 'requires' installed. To compile you must have the 'requires' installed.
@@ -61,7 +64,7 @@ Install:
http://projects.vdr-developer.org/projects/plg-softhddevice/files http://projects.vdr-developer.org/projects/plg-softhddevice/files
tar vxf vdr-softhddevice-*.tar.bz2 tar vxf vdr-softhddevice-*.tar.bz2
cd vdr-softhddevice cd softhddevice-*
make VDRDIR=<path-to-your-vdr-files> LIBDIR=. make VDRDIR=<path-to-your-vdr-files> LIBDIR=.
You can edit Makefile to enable/disable VDPAU / VA-API / Alsa / OSS You can edit Makefile to enable/disable VDPAU / VA-API / Alsa / OSS
@@ -125,6 +128,14 @@ Setup: /etc/vdr/setup.conf
softhddevice.AudioPassthrough = 0 softhddevice.AudioPassthrough = 0
0 = none, 1 = AC-3 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 Setup: /etc/vdr/remote.conf
------ ------
@@ -146,6 +157,15 @@ Commandline:
Use vdr -h to see the command line arguments support by the plugin. Use vdr -h to see the command line arguments support by the plugin.
-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: Running:
-------- --------

55
Todo
View File

@@ -19,35 +19,41 @@ GNU Affero General Public License for more details.
$Id: $ $Id: $
missing: missing:
software deinterlace software deinterlace (yadif, ...)
auto crop software decoder with software deinterlace
zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?) zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)? ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
suspend output / energie saver: stop audio, stop video, configurable suspend output / energie saver: stop audio, stop video, configurable
Option deinterlace off / deinterlace force! Option deinterlace off / deinterlace force!
Make output drivers better moduluar. Make output drivers better modular (under construction).
video:
subtitle not cleared
subtitle could be asyncron
reduce warnings after channel switch
vdpau: vdpau:
1080i with temporal spatial and level 1 scaling too slow with my GT 520 VdpPreemptionCallback handling (under construction)
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
hard channel switch hard channel switch
suspendoutput didn't show logo or black picture. suspendoutput didn't show logo or black picture.
libva: libva:
hard channel switch hard channel switch
yaepghd (VaapiSetOutputPosition) support 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: libva-intel-driver:
intel still has hangups most with 1080i intel still has hangups most with 1080i
1080i does no v-sync (workaround written) 1080i does no v-sync (workaround written, fixed with vaapi-ext)
osd has sometimes wrong size (workaround written) OSD has sometimes wrong size (workaround written)
libva-vdpau-driver: libva-vdpau-driver:
G210 osd update too slow (needs hardware problem workaround) G210/GT520 OSD update too slow (needs hardware problem workaround)
OSD update is too slow
hangup on exit (VaapiDelDecoder -> VaapiCleanup hangup on exit (VaapiDelDecoder -> VaapiCleanup
-> vaDestroyContext -> pthread_rwlock_wrlock) -> vaDestroyContext -> pthread_rwlock_wrlock)
@@ -56,21 +62,18 @@ libva-xvba-driver:
x11: x11:
disable screensaver disable screensaver
audio/alsa: audio:
done? video/audio asyncron write TS -> PES parser, which feeds audio before the next start packet
random crashes in av_parser_parse2, when switching channels CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
sometimes alsa hangs Combine alsa+oss ringbuffer code.
fixed? snd_pcm_state: Assertion `pcm' failed. while switching channels Make alsa thread/polled and oss thread/polled output module runtime
(thread problem) selectable.
audio/alsa:
better downmix of >2 channels on 2 channel hardware better downmix of >2 channels on 2 channel hardware
remix support of unsupported sample rates remix support of unsupported sample rates
libav supports only resample of mono to 2 channels libav supports only resample of mono to 2 channels
ffmpeg didn't support resample of 5 to 2 channels ffmpeg didn't support resample of 5 to 2 channels
CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
audio:
write TS -> PES parser, which feeds audio before the next start packet
audio/oss: audio/oss:
alsa oss emulation mixer "pcm" not working alsa oss emulation mixer "pcm" not working
@@ -80,6 +83,7 @@ HDMI/SPDIF Passthrough:
only AC-3 written only AC-3 written
Channels are wrong setup, if changing setting during operation. Channels are wrong setup, if changing setting during operation.
split pcm and ac-3 out into two devices split pcm and ac-3 out into two devices
support oss pass-through
playback of recording playback of recording
pause is not reset, when replay exit pause is not reset, when replay exit
@@ -92,7 +96,10 @@ setup:
Setup 4:3 zoom type Setup 4:3 zoom type
Some setup parameters are not used until restart. Some setup parameters are not used until restart.
Can a notice be added to the setup menu? Can a notice be added to the setup menu?
576i, 720p, fake 1080i, 1080i
unsorted:
Menu -> Setup -> Plugins -> skingenigmang -> General
-> Try 8bpp single area: no, has missing parts.
future features (not planed for 1.0 - 1.5) future features (not planed for 1.0 - 1.5)
@@ -102,5 +109,7 @@ future features (not planed for 1.0 - 1.5)
software decoder for xv / opengl software decoder for xv / opengl
atmolight support atmolight support
multistream handling multistream handling
pip support
grab image with jpeg
upmix stereo to AC-3 upmix stereo to AC-3

595
audio.c
View File

@@ -35,21 +35,19 @@
/// ///
/// ///
/// @todo FIXME: there can be problems with little/big endian. /// @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_ALSA ///< enable alsa support
//#define USE_OSS ///< enable oss support //#define USE_OSS ///< enable OSS support
#define noSEARCH_HDMI_BUG #define USE_AUDIO_THREAD ///< use thread for audio playback
#define noSEARCH_HDMI_BUG2 #define noUSE_AUDIORING ///< new audio ring code (incomplete)
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h> #include <inttypes.h>
#include <string.h>
#include <libintl.h> #include <libintl.h>
#define _(str) gettext(str) ///< gettext shortcut #define _(str) gettext(str) ///< gettext shortcut
@@ -73,10 +71,10 @@
# error "No valid SNDCTL_DSP_HALT_OUTPUT found." # error "No valid SNDCTL_DSP_HALT_OUTPUT found."
# endif # endif
#endif #endif
#include <poll.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <string.h>
#endif #endif
#ifdef USE_AUDIO_THREAD #ifdef USE_AUDIO_THREAD
@@ -96,13 +94,42 @@
#include "misc.h" #include "misc.h"
#include "audio.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 // Variables
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
static const char *AudioPCMDevice; ///< alsa/oss PCM device name static const char *AudioModuleName; ///< which audio module to use
static const char *AudioMixerDevice; ///< alsa/oss mixer device name
static const char *AudioMixerChannel; ///< alsa/oss mixer channel name /// 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 volatile char AudioRunning; ///< thread running / stopped
static int AudioPaused; ///< audio paused static int AudioPaused; ///< audio paused
static unsigned AudioSampleRate; ///< audio sample rate in hz 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 static int64_t AudioPTS; ///< audio pts clock
#ifdef USE_AUDIO_THREAD #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 static pthread_cond_t AudioStartCond; ///< condition variable
#else
static const int AudioThread; ///< dummy audio thread
#endif #endif
#ifdef SEARCH_HDMI_BUG2 #ifdef USE_AUDIORING
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// ring buffer // 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 #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 RingBuffer *AlsaRingBuffer; ///< audio ring buffer
static unsigned AlsaStartThreshold; ///< start play, if filled static unsigned AlsaStartThreshold; ///< start play, if filled
#ifdef USE_AUDIO_THREAD
static volatile char AlsaFlushBuffer; ///< flag empty buffer static volatile char AlsaFlushBuffer; ///< flag empty buffer
#endif
static snd_mixer_t *AlsaMixer; ///< alsa mixer handle static snd_mixer_t *AlsaMixer; ///< alsa mixer handle
static snd_mixer_elem_t *AlsaMixerElem; ///< alsa pcm mixer element 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 (avail < 256) { // too much overhead
if (first) { if (first) {
// happens with broken alsa drivers // happens with broken alsa drivers
if (AudioThread) {
Error(_("audio/alsa: broken driver %d\n"), avail); Error(_("audio/alsa: broken driver %d\n"), avail);
usleep(5 * 1000); usleep(5 * 1000);
} }
}
Debug(4, "audio/alsa: break state %s\n", Debug(4, "audio/alsa: break state %s\n",
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle))); snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
break; 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); n = RingBufferGetReadPointer(AlsaRingBuffer, &p);
if (!n) { // ring buffer empty if (!n) { // ring buffer empty
if (first) { // only error on first loop if (first) { // only error on first loop
@@ -322,7 +345,6 @@ static int AlsaPlayRingbuffer(void)
} }
return 0; return 0;
} }
#endif
if (n < avail) { // not enough bytes in ring buffer if (n < avail) { // not enough bytes in ring buffer
avail = n; avail = n;
} }
@@ -376,9 +398,12 @@ static void AlsaFlushBuffers(void)
int err; int err;
snd_pcm_state_t state; snd_pcm_state_t state;
RingBufferReadAdvance(AlsaRingBuffer, RingBufferUsedBytes(AlsaRingBuffer)); if (AlsaRingBuffer && AlsaPCMHandle) {
RingBufferReadAdvance(AlsaRingBuffer,
RingBufferUsedBytes(AlsaRingBuffer));
state = snd_pcm_state(AlsaPCMHandle); state = snd_pcm_state(AlsaPCMHandle);
Debug(3, "audio/alsa: state %d - %s\n", state, snd_pcm_state_name(state)); Debug(3, "audio/alsa: state %d - %s\n", state,
snd_pcm_state_name(state));
if (state != SND_PCM_STATE_OPEN) { if (state != SND_PCM_STATE_OPEN) {
if ((err = snd_pcm_drop(AlsaPCMHandle)) < 0) { if ((err = snd_pcm_drop(AlsaPCMHandle)) < 0) {
Error(_("audio: snd_pcm_drop(): %s\n"), snd_strerror(err)); Error(_("audio: snd_pcm_drop(): %s\n"), snd_strerror(err));
@@ -388,9 +413,32 @@ static void AlsaFlushBuffers(void)
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err)); Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
} }
} }
}
AudioRunning = 0;
AudioPTS = INT64_C(0x8000000000000000); 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 #if 0
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -520,8 +568,6 @@ static void AlsaEnqueue(const void *samples, int count)
#endif #endif
#if 0
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// direct playback // direct playback
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -536,39 +582,11 @@ static void AlsaEnqueue(const void *samples, int count)
*/ */
static void AlsaEnqueue(const void *samples, int count) static void AlsaEnqueue(const void *samples, int count)
{ {
snd_pcm_state_t state; if (AlsaAddToRingbuffer(samples, count)) {
int avail; AudioRunning = 1;
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);
} }
// 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 #ifdef USE_AUDIO_THREAD
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -622,7 +640,7 @@ static void AlsaThread(void)
break; break;
} }
pthread_yield(); 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 samples sample buffer
** @param count number of bytes in 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) { if (!AlsaRingBuffer || !AlsaPCMHandle || !AudioSampleRate) {
printf("%p %p %d\n", AlsaRingBuffer, AlsaPCMHandle, AudioSampleRate);
Debug(3, "audio/alsa: enqueue not ready\n"); Debug(3, "audio/alsa: enqueue not ready\n");
return; 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 #endif
//----------------------------------------------------------------------------
/** /**
** Open alsa pcm device. ** Open alsa pcm device.
*/ */
@@ -1098,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 #endif // USE_ALSA
#ifdef USE_OSS #ifdef USE_OSS
@@ -1116,6 +1173,10 @@ static int OssMixerChannel; ///< mixer channel index
static RingBuffer *OssRingBuffer; ///< audio ring buffer static RingBuffer *OssRingBuffer; ///< audio ring buffer
static unsigned OssStartThreshold; ///< start play, if filled static unsigned OssStartThreshold; ///< start play, if filled
#ifdef USE_AUDIO_THREAD
static volatile char OssFlushBuffer; ///< flag empty buffer
#endif
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// OSS pcm // OSS pcm
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -1204,17 +1265,20 @@ static int OssPlayRingbuffer(void)
} }
/** /**
** Flush oss buffers. ** Flush OSS buffers.
*/ */
static void OssFlushBuffers(void) static void OssFlushBuffers(void)
{ {
RingBufferReadAdvance(OssRingBuffer, RingBufferUsedBytes(OssRingBuffer)); if (OssRingBuffer && OssPcmFildes != -1) {
RingBufferReadAdvance(OssRingBuffer,
RingBufferUsedBytes(OssRingBuffer));
// flush kernel buffers // flush kernel buffers
if (ioctl(OssPcmFildes, SNDCTL_DSP_HALT_OUTPUT, NULL) < 0) { if (ioctl(OssPcmFildes, SNDCTL_DSP_HALT_OUTPUT, NULL) < 0) {
Error(_("audio/oss: ioctl(SNDCTL_DSP_HALT_OUTPUT): %s\n"), Error(_("audio/oss: ioctl(SNDCTL_DSP_HALT_OUTPUT): %s\n"),
strerror(errno)); strerror(errno));
return;
} }
}
AudioRunning = 0;
AudioPTS = INT64_C(0x8000000000000000); AudioPTS = INT64_C(0x8000000000000000);
} }
@@ -1256,15 +1320,108 @@ static void OssPoller(void)
if (OssPcmFildes == -1) { // setup failure if (OssPcmFildes == -1) { // setup failure
return; return;
} }
if (AudioRunning) { if (!AudioThread && AudioRunning) {
OssPlayRingbuffer(); 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 ** @see AudioPCMDevice
*/ */
@@ -1292,7 +1449,7 @@ static void OssInitPCM(void)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
/** /**
** Set oss mixer volume (0-100) ** Set OSS mixer volume (0-100)
** **
** @param volume volume (0 .. 100) ** @param volume volume (0 .. 100)
*/ */
@@ -1317,7 +1474,7 @@ static const char *OssMixerChannelNames[SOUND_MIXER_NRDEVICES] =
SOUND_DEVICE_NAMES; SOUND_DEVICE_NAMES;
/** /**
** Initialize oss mixer. ** Initialize OSS mixer.
*/ */
static void OssInitMixer(void) static void OssInitMixer(void)
{ {
@@ -1371,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. ** @returns audio delay in time stamps.
*/ */
@@ -1411,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 freq sample frequency
** @param channels number of channels ** @param channels number of channels
@@ -1427,14 +1584,11 @@ static int OssSetup(int *freq, int *channels)
int ret; int ret;
int tmp; int tmp;
if (OssPcmFildes == -1) { // oss not ready if (OssPcmFildes == -1) { // OSS not ready
return -1; return -1;
} }
// flush any buffered data // flush any buffered data
{ AudioFlushBuffers();
AudioRunning = 0;
OssFlushBuffers();
}
ret = 0; ret = 0;
@@ -1519,7 +1673,7 @@ static int OssSetup(int *freq, int *channels)
} }
/** /**
** Initialize oss audio output module. ** Initialize OSS audio output module.
*/ */
static void OssInit(void) static void OssInit(void)
{ {
@@ -1530,7 +1684,7 @@ static void OssInit(void)
} }
/** /**
** Cleanup oss audio output module. ** Cleanup OSS audio output module.
*/ */
static void OssExit(void) static void OssExit(void)
{ {
@@ -1544,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 #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 // thread playback
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
#ifdef USE_AUDIO_THREAD #ifdef USE_AUDIO_THREAD
static pthread_t AudioThread; ///< audio play thread
static pthread_mutex_t AudioMutex; ///< audio condition mutex
/** /**
** Audio play thread. ** Audio play thread.
*/ */
@@ -1565,18 +1818,13 @@ static void *AudioPlayHandlerThread(void *dummy)
Debug(3, "audio: wait on start condition\n"); Debug(3, "audio: wait on start condition\n");
pthread_mutex_lock(&AudioMutex); pthread_mutex_lock(&AudioMutex);
AudioRunning = 0; AudioRunning = 0;
#ifndef SEARCH_HDMI_BUG
do { do {
pthread_cond_wait(&AudioStartCond, &AudioMutex); pthread_cond_wait(&AudioStartCond, &AudioMutex);
// cond_wait can return, without signal! // cond_wait can return, without signal!
} while (!AudioRunning); } while (!AudioRunning);
#else
usleep(1 * 1000);
AudioRunning = 1;
#endif
pthread_mutex_unlock(&AudioMutex); pthread_mutex_unlock(&AudioMutex);
#ifdef SEARCH_HDMI_BUG2 #ifdef USE_AUDIORING
if (atomic_read(&AudioRingFilled) > 1) { if (atomic_read(&AudioRingFilled) > 1) {
int sample_rate; int sample_rate;
int channels; int channels;
@@ -1619,9 +1867,7 @@ static void *AudioPlayHandlerThread(void *dummy)
#endif #endif
Debug(3, "audio: play start\n"); Debug(3, "audio: play start\n");
#ifdef USE_ALSA AudioUsedModule->Thread();
AlsaThread();
#endif
} }
return dummy; return dummy;
@@ -1636,15 +1882,9 @@ static void AudioInitThread(void)
pthread_cond_init(&AudioStartCond, NULL); pthread_cond_init(&AudioStartCond, NULL);
pthread_create(&AudioThread, NULL, AudioPlayHandlerThread, NULL); pthread_create(&AudioThread, NULL, AudioPlayHandlerThread, NULL);
pthread_setname_np(AudioThread, "softhddev audio"); 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(); pthread_yield();
} while (!AlsaPCMHandle); usleep(5 * 1000); // give thread some time to start
#endif
pthread_yield();
usleep(5 * 1000);
} }
/** /**
@@ -1671,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. ** Place samples in audio output queue.
** **
@@ -1679,14 +1932,7 @@ static void AudioExitThread(void)
*/ */
void AudioEnqueue(const void *samples, int count) void AudioEnqueue(const void *samples, int count)
{ {
#ifdef USE_ALSA AudioUsedModule->Enqueue(samples, count);
AlsaEnqueue(samples, count);
#endif
#ifdef USE_OSS
OssEnqueue(samples, count);
#endif
(void)samples;
(void)count;
} }
/** /**
@@ -1694,24 +1940,7 @@ void AudioEnqueue(const void *samples, int count)
*/ */
void AudioFlushBuffers(void) void AudioFlushBuffers(void)
{ {
#ifdef USE_ALSA AudioUsedModule->FlushBuffers();
#ifdef USE_AUDIO_THREAD
// signal thread to flush buffers
if (AudioThread) {
AlsaFlushBuffer = 1;
do {
AudioRunning = 1; // wakeup in case of sleeping
pthread_cond_signal(&AudioStartCond);
usleep(1 * 1000);
} while (AlsaFlushBuffer); // wait until flushed
}
#else
AlsaFlushBuffers();
#endif
#endif
#ifdef USE_OSS
OssFlushBuffers();
#endif
} }
/** /**
@@ -1719,14 +1948,7 @@ void AudioFlushBuffers(void)
*/ */
void AudioPoller(void) void AudioPoller(void)
{ {
#ifndef USE_AUDIO_THREAD AudioUsedModule->Poller();
#ifdef USE_ALSA
Error(_("audio/alsa: poller not implemented\n"));
#endif
#ifdef USE_OSS
OssPoller();
#endif
#endif
} }
/** /**
@@ -1734,13 +1956,17 @@ void AudioPoller(void)
*/ */
int AudioFreeBytes(void) int AudioFreeBytes(void)
{ {
#ifdef USE_ALSA return AudioUsedModule->FreeBytes();
return AlsaRingBuffer ? RingBufferFreeBytes(AlsaRingBuffer) : INT32_MAX; }
#endif
#ifdef USE_OSS /**
return OssRingBuffer ? RingBufferFreeBytes(OssRingBuffer) : INT32_MAX; ** Get audio delay in time stamps.
#endif **
return INT32_MAX; // no driver, much space ** @returns audio delay in time stamps.
*/
uint64_t AudioGetDelay(void)
{
return AudioUsedModule->GetDelay();
} }
/** /**
@@ -1760,22 +1986,6 @@ void AudioSetClock(int64_t pts)
AudioPTS = 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. ** Get current audio clock.
** **
@@ -1783,12 +1993,13 @@ uint64_t AudioGetDelay(void)
*/ */
int64_t AudioGetClock(void) int64_t AudioGetClock(void)
{ {
if ((uint64_t) AudioPTS != INT64_C(0x8000000000000000)) {
int64_t delay; int64_t delay;
delay = AudioGetDelay(); if ((delay = AudioGetDelay())) {
if (delay && (uint64_t) AudioPTS != INT64_C(0x8000000000000000)) {
return AudioPTS - delay; return AudioPTS - delay;
} }
}
return INT64_C(0x8000000000000000); return INT64_C(0x8000000000000000);
} }
@@ -1830,53 +2041,81 @@ int AudioSetup(int *freq, int *channels)
// FIXME: set flag invalid setup // FIXME: set flag invalid setup
return -1; return -1;
} }
#if defined(SEARCH_HDMI_BUG) || defined(SEARCH_HDMI_BUG2) #ifdef USE_AUDIORING
// FIXME: need to store possible combination and report this // FIXME: need to store possible combination and report this
return AudioRingAdd(*freq, *channels); return AudioRingAdd(*freq, *channels);
#endif #endif
#ifdef USE_ALSA return AudioUsedModule->Setup(freq, channels);
return AlsaSetup(freq, channels);
#endif
#ifdef USE_OSS
return OssSetup(freq, channels);
#endif
return -1;
} }
/** /**
** Set pcm audio device. ** Set pcm audio device.
** **
** @param device name of pcm device (fe. "hw:0,9" or "/dev/dsp") ** @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) void AudioSetDevice(const char *device)
{ {
AudioModuleName = "alsa"; // detect alsa/OSS
if (!device[0]) {
AudioModuleName = "noop";
} else if (device[0] == '/') {
AudioModuleName = "oss";
}
AudioPCMDevice = device; AudioPCMDevice = device;
} }
/** /**
** Initialize audio output module. ** Initialize audio output module.
**
** @todo FIXME: make audio output module selectable.
*/ */
void AudioInit(void) void AudioInit(void)
{ {
int freq; int freq;
int chan; int chan;
unsigned u;
const char *name;
#ifdef SEARCH_HDMI_BUG2 name = "noop";
AudioRingInit(); #ifdef USE_OSS
name = "oss";
#endif #endif
#ifdef USE_ALSA #ifdef USE_ALSA
AlsaInit(); name = "alsa";
#endif #endif
#ifdef USE_OSS if (AudioModuleName) {
OssInit(); 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 #endif
AudioUsedModule->Init();
freq = 48000; freq = 48000;
chan = 2; chan = 2;
if (AudioSetup(&freq, &chan)) { // set default parameters if (AudioSetup(&freq, &chan)) { // set default parameters
Error(_("audio: can't do initial setup\n")); Error(_("audio: can't do initial setup\n"));
} }
#ifdef USE_AUDIO_THREAD #ifdef USE_AUDIO_THREAD
if (AudioUsedModule->Thread) { // supports threads
AudioInitThread(); AudioInitThread();
}
#endif #endif
AudioPaused = 1; AudioPaused = 1;
@@ -1890,13 +2129,9 @@ void AudioExit(void)
#ifdef USE_AUDIO_THREAD #ifdef USE_AUDIO_THREAD
AudioExitThread(); AudioExitThread();
#endif #endif
#ifdef USE_ALSA AudioUsedModule->Exit();
AlsaExit(); AudioUsedModule = &NoopModule;
#endif #ifdef USE_AUDIORING
#ifdef USE_OSS
OssExit();
#endif
#ifdef SEARCH_HDMI_BUG2
AudioRingExit(); AudioRingExit();
#endif #endif
} }
@@ -1942,7 +2177,7 @@ static void PrintVersion(void)
#ifdef GIT_REV #ifdef GIT_REV
"(GIT-" GIT_REV ")" "(GIT-" GIT_REV ")"
#endif #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"); "\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 AudioEnqueue(const void *, int); ///< buffer audio samples
extern void AudioFlushBuffers(void); ///< flush audio buffers extern void AudioFlushBuffers(void); ///< flush audio buffers
extern void AudioPoller(void); ///< poll audio events/handling extern void AudioPoller(void); ///< poll audio events/handling
extern int AudioFreeBytes(void); ///< free bytes in audio output extern int AudioFreeBytes(void); ///< free bytes in audio output
//extern int AudioUsedBytes(void); ///< used bytes in audio output //extern int AudioUsedBytes(void); ///< used bytes in audio output
extern uint64_t AudioGetDelay(void); ///< get current audio delay
extern void AudioSetClock(int64_t); ///< set audio clock base extern void AudioSetClock(int64_t); ///< set audio clock base
extern int64_t AudioGetClock(); ///< get current audio clock extern int64_t AudioGetClock(); ///< get current audio clock
extern uint64_t AudioGetDelay(void); ///< get current audio delay extern void AudioSetVolume(int); ///< set volume
extern int AudioSetup(int *, int *); ///< setup audio output extern int AudioSetup(int *, int *); ///< setup audio output
//extern void AudioPlay(void); ///< play audio //extern void AudioPlay(void); ///< play audio
//extern void AudioPause(void); ///< pause audio //extern void AudioPause(void); ///< pause audio
extern void 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 AudioInit(void); ///< setup audio module
extern void AudioExit(void); ///< cleanup and exit audio module extern void AudioExit(void); ///< cleanup and exit audio module

View File

@@ -652,6 +652,9 @@ static int ValidateMpeg(const uint8_t * data, int size)
** supports complete packets. ** supports complete packets.
** We buffer here until we receive an complete PES Packet, which ** We buffer here until we receive an complete PES Packet, which
** is no problem, the audio is always far behind us. ** 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) int PlayVideo(const uint8_t * data, int size)
{ {
@@ -695,7 +698,7 @@ int PlayVideo(const uint8_t * data, int size)
Error(_("[softhddev] invalid video packet %d bytes\n"), size); Error(_("[softhddev] invalid video packet %d bytes\n"), size);
return size; return size;
} }
// FIXME: hack to test results // buffer full: needed for replay
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) { if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
return 0; return 0;
} }
@@ -788,6 +791,29 @@ int PlayVideo(const uint8_t * data, int size)
return 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);
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/** /**
@@ -913,22 +939,19 @@ int Flush(int timeout)
void GetOsdSize(int *width, int *height, double *aspect) void GetOsdSize(int *width, int *height, double *aspect)
{ {
#ifdef DEBUG #ifdef DEBUG
static char done; static int done_width;
static int done_height;
#endif #endif
// FIXME: should be configured! VideoGetOsdSize(width, height);
*width = 1920;
*height = 1080;
//*width = 768;
//*height = 576;
*aspect = 16.0 / 9.0 / (double)*width * (double)*height; *aspect = 16.0 / 9.0 / (double)*width * (double)*height;
#ifdef DEBUG #ifdef DEBUG
if (!done) { if (done_width != *width || done_height != *height) {
Debug(3, "[softhddev]%s: %dx%d %g\n", __FUNCTION__, *width, *height, Debug(3, "[softhddev]%s: %dx%d %g\n", __FUNCTION__, *width, *height,
*aspect); *aspect);
done = 1; done_width = *width;
done_height = *height;
} }
#endif #endif
} }
@@ -1117,8 +1140,12 @@ static void StartXServer(void)
*/ */
void SoftHdDeviceExit(void) void SoftHdDeviceExit(void)
{ {
// lets hope that vdr does a good thead cleanup // lets hope that vdr does a good thread cleanup
// no it doesn't do a good thread cleanup
VideoOsdExit();
VideoExit();
AudioExit();
if (MyVideoDecoder) { if (MyVideoDecoder) {
CodecVideoClose(MyVideoDecoder); CodecVideoClose(MyVideoDecoder);
// FIXME: CodecDelVideoDecoder(MyVideoDecoder); // FIXME: CodecDelVideoDecoder(MyVideoDecoder);
@@ -1130,9 +1157,6 @@ void SoftHdDeviceExit(void)
MyAudioDecoder = NULL; MyAudioDecoder = NULL;
} }
VideoOsdExit();
VideoExit();
AudioExit();
CodecExit(); CodecExit();
VideoPacketExit(); VideoPacketExit();

View File

@@ -46,6 +46,8 @@ extern "C"
extern int PlayVideo(const uint8_t *, int); extern int PlayVideo(const uint8_t *, int);
/// C plugin play TS video packet /// C plugin play TS video packet
extern void PlayTsVideo(const uint8_t *, int); extern void PlayTsVideo(const uint8_t *, int);
/// C plugin grab an image
extern uint8_t *GrabImage(int *, int, int, int, int);
/// C plugin set play mode /// C plugin set play mode
extern void SetPlayMode(void); extern void SetPlayMode(void);

View File

@@ -42,7 +42,7 @@ extern "C"
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
static const char *const VERSION = "0.3.1"; static const char *const VERSION = "0.4.0";
static const char *const DESCRIPTION = static const char *const DESCRIPTION =
trNOOP("A software and GPU emulated HD device"); trNOOP("A software and GPU emulated HD device");
@@ -53,6 +53,7 @@ static class cSoftHdDevice *MyDevice;
#define RESOLUTIONS 4 ///< number of resolutions #define RESOLUTIONS 4 ///< number of resolutions
/// resolutions names
static const char *const Resolution[RESOLUTIONS] = { static const char *const Resolution[RESOLUTIONS] = {
"576i", "720p", "1080i_fake", "1080i" "576i", "720p", "1080i_fake", "1080i"
}; };
@@ -78,6 +79,9 @@ static int ConfigVideoScaling[RESOLUTIONS];
static int ConfigVideoAudioDelay; ///< config audio delay static int ConfigVideoAudioDelay; ///< config audio delay
static int ConfigAudioPassthrough; ///< config audio pass-through static int ConfigAudioPassthrough; ///< config audio pass-through
static int ConfigAutoCropInterval; ///< auto crop detection interval
static int ConfigAutoCropDelay; ///< auto crop detection delay
static volatile char DoMakePrimary; ///< flag switch primary static volatile char DoMakePrimary; ///< flag switch primary
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -122,7 +126,7 @@ extern "C" void FeedKeyPress(const char *keymap, const char *key, int repeat,
csoft = new cSoftRemote(keymap); csoft = new cSoftRemote(keymap);
} }
dsyslog("[softhddev]%s %s, %s\n", __FUNCTION__, keymap, key); //dsyslog("[softhddev]%s %s, %s\n", __FUNCTION__, keymap, key);
csoft->Put(key, repeat, release); csoft->Put(key, repeat, release);
} }
@@ -144,12 +148,13 @@ class cSoftOsd:public cOsd
cSoftOsd::cSoftOsd(int left, int top, uint level) cSoftOsd::cSoftOsd(int left, int top, uint level)
:cOsd(left, top, level) :cOsd(left, top, level)
{ {
// FIXME: OsdWidth/OsdHeight not correct! /* FIXME: OsdWidth/OsdHeight not correct!
dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(), dsyslog("[softhddev]%s: %dx%d+%d+%d, %d\n", __FUNCTION__, OsdWidth(),
OsdHeight(), left, top, level); OsdHeight(), left, top, level);
*/
this->Level = level; this->Level = level;
//SetActive(true); SetActive(true);
} }
cSoftOsd::~cSoftOsd(void) cSoftOsd::~cSoftOsd(void)
@@ -158,8 +163,15 @@ cSoftOsd::~cSoftOsd(void)
SetActive(false); SetActive(false);
#ifdef USE_YAEPG #ifdef USE_YAEPG
if (vidWin.bpp) { // support yaepghd, video window
VideoSetOutputPosition(0, 0, 1920, 1080); 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 #endif
OsdClose(); OsdClose();
@@ -175,8 +187,8 @@ void cSoftOsd::Flush(void)
if (!Active()) { if (!Active()) {
return; return;
} }
// support yaepghd, video window
#ifdef USE_YAEPG #ifdef USE_YAEPG
// support yaepghd, video window
if (vidWin.bpp) { if (vidWin.bpp) {
dsyslog("[softhddev]%s: %dx%d+%d+%d\n", __FUNCTION__, vidWin.Width(), dsyslog("[softhddev]%s: %dx%d+%d+%d\n", __FUNCTION__, vidWin.Width(),
vidWin.Height(), vidWin.x1, vidWin.y2); vidWin.Height(), vidWin.x1, vidWin.y2);
@@ -213,6 +225,7 @@ void cSoftOsd::Flush(void)
if (!bitmap->Dirty(x1, y1, x2, y2)) { if (!bitmap->Dirty(x1, y1, x2, y2)) {
continue; // nothing dirty continue continue; // nothing dirty continue
} }
#if 0
// FIXME: need only to convert and upload dirty areas // FIXME: need only to convert and upload dirty areas
// DrawBitmap(bitmap); // DrawBitmap(bitmap);
@@ -225,7 +238,6 @@ void cSoftOsd::Flush(void)
((uint32_t *) argb)[x + y * w] = bitmap->GetColor(x, y); ((uint32_t *) argb)[x + y * w] = bitmap->GetColor(x, y);
} }
} }
// check if subtitles // check if subtitles
if (this->Level == OSD_LEVEL_SUBTITLES) { if (this->Level == OSD_LEVEL_SUBTITLES) {
int video_width; int video_width;
@@ -238,12 +250,32 @@ void cSoftOsd::Flush(void)
video_width = 1920; video_width = 1920;
video_height = 1080; video_height = 1080;
OsdDrawARGB((1920 - video_width) / 2 + Left() + bitmap->X0(), OsdDrawARGB((1920 - video_width) / 2 + Left() + bitmap->X0(),
1080 - video_height + Top() + bitmap->Y0(), 1080 - video_height + Top() + bitmap->Y0(), w, h, argb);
bitmap->Width(), bitmap->Height(), argb);
} else { } else {
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(), OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(), w, h,
bitmap->Width(), bitmap->Height(), argb); 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(); bitmap->Clean();
free(argb); free(argb);
@@ -264,8 +296,8 @@ void cSoftOsd::Flush(void)
h = pm->ViewPort().Height(); h = pm->ViewPort().Height();
/* /*
dsyslog("[softhddev]%s: draw %dx%d+%d+%d %p\n", __FUNCTION__, w, h, x, dsyslog("[softhddev]%s: draw %dx%d+%d+%d %p\n", __FUNCTION__, w, h,
y, pm->Data()); x, y, pm->Data());
*/ */
OsdDrawARGB(x, y, w, h, pm->Data()); OsdDrawARGB(x, y, w, h, pm->Data());
@@ -334,6 +366,8 @@ class cMenuSetupSoft:public cMenuSetupPage
int Sharpen[RESOLUTIONS]; int Sharpen[RESOLUTIONS];
int AudioDelay; int AudioDelay;
int AudioPassthrough; int AudioPassthrough;
int AutoCropInterval;
int AutoCropDelay;
protected: protected:
virtual void Store(void); virtual void Store(void);
public: public:
@@ -342,6 +376,8 @@ class cMenuSetupSoft:public cMenuSetupPage
/** /**
** Create a seperator item. ** Create a seperator item.
**
** @param label text inside separator
*/ */
static inline cOsdItem *SeparatorItem(const char *label) static inline cOsdItem *SeparatorItem(const char *label)
{ {
@@ -376,10 +412,10 @@ cMenuSetupSoft::cMenuSetupSoft(void)
// cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem // cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem
MakePrimary = ConfigMakePrimary; MakePrimary = ConfigMakePrimary;
Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary, Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary,
tr("no"), tr("yes"))); trVDR("no"), trVDR("yes")));
HideMainMenuEntry = ConfigHideMainMenuEntry; HideMainMenuEntry = ConfigHideMainMenuEntry;
Add(new cMenuEditBoolItem(tr("Hide main menu entry"), &HideMainMenuEntry, Add(new cMenuEditBoolItem(tr("Hide main menu entry"), &HideMainMenuEntry,
tr("no"), tr("yes"))); trVDR("no"), trVDR("yes")));
// //
// video // video
// //
@@ -393,7 +429,7 @@ cMenuSetupSoft::cMenuSetupSoft(void)
deinterlace)); deinterlace));
SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i]; SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i];
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"), Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),
&SkipChromaDeinterlace[i], tr("no"), tr("yes"))); &SkipChromaDeinterlace[i], trVDR("no"), trVDR("yes")));
Denoise[i] = ConfigVideoDenoise[i]; Denoise[i] = ConfigVideoDenoise[i];
Add(new cMenuEditIntItem(tr("Denoise (0..1000) (vdpau)"), &Denoise[i], Add(new cMenuEditIntItem(tr("Denoise (0..1000) (vdpau)"), &Denoise[i],
0, 1000)); 0, 1000));
@@ -411,6 +447,16 @@ cMenuSetupSoft::cMenuSetupSoft(void)
AudioPassthrough = ConfigAudioPassthrough; AudioPassthrough = ConfigAudioPassthrough;
Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2, Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2,
passthrough)); passthrough));
//
// auto-crop
//
Add(SeparatorItem(tr("Auto-crop")));
AutoCropInterval = ConfigAutoCropInterval;
Add(new cMenuEditIntItem(tr("autocrop interval (frames)"),
&AutoCropInterval, 0, 200));
AutoCropDelay = ConfigAutoCropDelay;
Add(new cMenuEditIntItem(tr("autocrop delay (n * interval)"),
&AutoCropDelay, 0, 200));
} }
/** /**
@@ -450,6 +496,11 @@ void cMenuSetupSoft::Store(void)
VideoSetAudioDelay(ConfigVideoAudioDelay); VideoSetAudioDelay(ConfigVideoAudioDelay);
SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough); SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough);
CodecSetAudioPassthrough(ConfigAudioPassthrough); CodecSetAudioPassthrough(ConfigAudioPassthrough);
SetupStore("AutoCrop.Interval", ConfigAutoCropInterval = AutoCropInterval);
SetupStore("AutoCrop.Delay", ConfigAutoCropDelay = AutoCropDelay);
VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -475,17 +526,12 @@ class cSoftHdDevice:public cDevice
virtual bool Poll(cPoller &, int = 0); virtual bool Poll(cPoller &, int = 0);
virtual bool Flush(int = 0); virtual bool Flush(int = 0);
virtual int64_t GetSTC(void); virtual int64_t GetSTC(void);
virtual void GetVideoSize(int &width, int &height, double &aspect) virtual void GetVideoSize(int &, int &, double &);
{
width = 1920;
height = 1080;
aspect = (double)width / height;
}
virtual void GetOsdSize(int &, int &, double &); virtual void GetOsdSize(int &, int &, double &);
virtual int PlayVideo(const uchar *, int); virtual int PlayVideo(const uchar *, int);
//virtual int PlayTsVideo(const uchar *, int); //virtual int PlayTsVideo(const uchar *, int);
#ifdef USE_OSS // FIXME: testing only oss #ifndef USE_AUDIO_THREAD // FIXME: testing none threaded
virtual int PlayTsAudio(const uchar *, int); virtual int PlayTsAudio(const uchar *, int);
#endif #endif
virtual void SetAudioChannelDevice(int); virtual void SetAudioChannelDevice(int);
@@ -498,8 +544,6 @@ class cSoftHdDevice:public cDevice
virtual uchar *GrabImage(int &, bool, int, int, int); virtual uchar *GrabImage(int &, bool, int, int, int);
virtual int ProvidesCa(const cChannel *) const;
#if 0 #if 0
// SPU facilities // SPU facilities
private: private:
@@ -526,6 +570,11 @@ cSoftHdDevice::~cSoftHdDevice(void)
//dsyslog("[softhddev]%s:\n", __FUNCTION__); //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) void cSoftHdDevice::MakePrimaryDevice(bool on)
{ {
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on); dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on);
@@ -536,18 +585,9 @@ 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 #if 0
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void) cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
{ {
dsyslog("[softhddev]%s:\n", __FUNCTION__); dsyslog("[softhddev]%s:\n", __FUNCTION__);
@@ -697,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)? ** FIXME: Called every second, for nothing (no OSD displayed)?
*/ */
@@ -757,33 +808,47 @@ int cSoftHdDevice::PlayVideo(const uchar * data, int length)
/// ///
/// Play a TS video packet. /// 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 // many code to repeat
} }
#endif #endif
#ifdef USE_OSS // FIXME: testing only oss #ifndef USE_AUDIO_THREAD // FIXME: testing none threaded
/// ///
/// Play a TS audio packet. /// Play a TS audio packet.
/// ///
/// misuse this function as audio poller /// misuse this function as audio poller
/// ///
/// @param data ts data buffer
/// @param length ts packet length
///
int cSoftHdDevice::PlayTsAudio(const uchar * data, int length) int cSoftHdDevice::PlayTsAudio(const uchar * data, int length)
{ {
AudioPoller(); AudioPoller();
return cDevice::PlayTsAudio(data, length); return cDevice::PlayTsAudio(data, length);
} }
#endif #endif
uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int sizex, /**
int sizey) ** Grabs the currently visible screen image.
**
** @param size size of the returned data
** @param jpeg flag true, create JPEG data
** @param quality JPEG quality
** @param width number of horizontal pixels in the frame
** @param height number of vertical pixels in the frame
*/
uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int width,
int height)
{ {
dsyslog("[softhddev]%s: %d, %d, %d, %dx%d\n", __FUNCTION__, size, jpeg, dsyslog("[softhddev]%s: %d, %d, %d, %dx%d\n", __FUNCTION__, size, jpeg,
quality, sizex, sizey); quality, width, height);
return NULL; return::GrabImage(&size, jpeg, quality, width, height);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -927,7 +992,9 @@ cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
cDevice::PrimaryDevice()->StopReplay(); cDevice::PrimaryDevice()->StopReplay();
Suspend(); Suspend();
if (ShutdownHandler.GetUserInactiveTime()) {
ShutdownHandler.SetUserInactive(); ShutdownHandler.SetUserInactive();
}
return NULL; return NULL;
} }
@@ -966,11 +1033,15 @@ cMenuSetupPage *cPluginSoftHdDevice::SetupMenu(void)
/** /**
** Parse setup parameters ** Parse setup parameters
**
** @param name paramter name (case sensetive)
** @param value value as string
**
** @returns true if the parameter is supported.
*/ */
bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value) bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
{ {
int i; int i;
char buf[128];
//dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value); //dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
@@ -983,6 +1054,8 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return true; return true;
} }
for (i = 0; i < RESOLUTIONS; ++i) { for (i = 0; i < RESOLUTIONS; ++i) {
char buf[128];
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling"); snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
if (!strcmp(name, buf)) { if (!strcmp(name, buf)) {
ConfigVideoScaling[i] = atoi(value); ConfigVideoScaling[i] = atoi(value);
@@ -1015,6 +1088,7 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return true; return true;
} }
} }
if (!strcmp(name, "AudioDelay")) { if (!strcmp(name, "AudioDelay")) {
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value)); VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
return true; return true;
@@ -1024,6 +1098,17 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return true; 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; return false;
} }

View File

@@ -21,15 +21,15 @@ SRC_URI=""
LICENSE="AGPL-3" LICENSE="AGPL-3"
SLOT="0" SLOT="0"
KEYWORDS="~x86 ~amd64" KEYWORDS="~x86 ~amd64"
IUSE="vaapi vdpau alsa oss yaepg" IUSE="vaapi vdpau alsa oss yaepg opengl"
DEPEND=">=x11-libs/libxcb-1.7 DEPEND=">=x11-libs/libxcb-1.7
x11-libs/xcb-util x11-libs/xcb-util
x11-libs/xcb-util-wm x11-libs/xcb-util-wm
x11-libs/xcb-util-wm
x11-libs/xcb-util-keysyms x11-libs/xcb-util-keysyms
x11-libs/xcb-util-renderutil x11-libs/xcb-util-renderutil
x11-libs/libX11 x11-libs/libX11
opengl? ( virtual/opengl )
>=media-video/ffmpeg-0.7 >=media-video/ffmpeg-0.7
sys-devel/gettext sys-devel/gettext
sys-devel/make sys-devel/make
@@ -39,6 +39,7 @@ DEPEND=">=x11-libs/libxcb-1.7
vdpau? ( x11-libs/libvdpau ) vdpau? ( x11-libs/libvdpau )
vaapi? ( x11-libs/libva ) vaapi? ( x11-libs/libva )
alsa? ( media-libs/alsa-lib ) alsa? ( media-libs/alsa-lib )
oss? ( sys-kernel/linux-headers )
" "
src_prepare() { src_prepare() {

1748
video.c

File diff suppressed because it is too large Load Diff

12
video.h
View File

@@ -37,6 +37,9 @@ typedef struct _video_hw_decoder_ VideoHwDecoder;
/// Allocate new video hardware decoder. /// Allocate new video hardware decoder.
extern VideoHwDecoder *VideoNewHwDecoder(void); extern VideoHwDecoder *VideoNewHwDecoder(void);
/// Deallocate video hardware decoder.
extern void VideoDelHwDecoder(VideoHwDecoder *);
/// Get and allocate a video hardware surface. /// Get and allocate a video hardware surface.
extern unsigned VideoGetSurface(VideoHwDecoder *); extern unsigned VideoGetSurface(VideoHwDecoder *);
@@ -97,14 +100,23 @@ extern void VideoSetSharpen(int[]);
/// Set audio delay. /// Set audio delay.
extern void VideoSetAudioDelay(int); extern void VideoSetAudioDelay(int);
/// Set auto-crop parameters.
extern void VideoSetAutoCrop(int, int);
/// Clear OSD. /// Clear OSD.
extern void VideoOsdClear(void); extern void VideoOsdClear(void);
/// Draw an OSD ARGB image. /// Draw an OSD ARGB image.
extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *); extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *);
/// Get OSD size.
extern void VideoGetOsdSize(int *, int *);
extern int64_t VideoGetClock(void); ///< Get video clock. extern int64_t VideoGetClock(void); ///< Get video clock.
/// Grab screen.
extern uint8_t *VideoGrab(int *, int *, int *);
extern void VideoOsdInit(void); ///< Setup osd. extern void VideoOsdInit(void); ///< Setup osd.
extern void VideoOsdExit(void); ///< Cleanup osd. extern void VideoOsdExit(void); ///< Cleanup osd.