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

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,7 +23,7 @@ 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:
@@ -59,7 +60,8 @@ PACKAGE = vdr-$(ARCHIVE)
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) \

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 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
@@ -125,6 +128,14 @@ 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
------
@@ -146,6 +157,15 @@ 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:
--------

55
Todo
View File

@@ -19,35 +19,41 @@ GNU Affero General Public License for more details.
$Id: $
missing:
software deinterlace
auto crop
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 moduluar.
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)
@@ -56,21 +62,18 @@ libva-xvba-driver:
x11:
disable screensaver
audio/alsa:
done? video/audio asyncron
random crashes in av_parser_parse2, when switching channels
sometimes alsa hangs
fixed? snd_pcm_state: Assertion `pcm' failed. while switching channels
(thread problem)
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:
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:
write TS -> PES parser, which feeds audio before the next start packet
audio/oss:
alsa oss emulation mixer "pcm" not working
@@ -80,6 +83,7 @@ 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
@@ -92,7 +96,10 @@ setup:
Setup 4:3 zoom type
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)
@@ -102,5 +109,7 @@ future features (not planed for 1.0 - 1.5)
software decoder for xv / opengl
atmolight support
multistream handling
pip support
grab image with jpeg
upmix stereo to AC-3

629
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.
*/
@@ -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
#ifdef USE_OSS
@@ -1116,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
//----------------------------------------------------------------------------
@@ -1204,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);
}
@@ -1256,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
*/
@@ -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)
*/
@@ -1317,7 +1474,7 @@ static const char *OssMixerChannelNames[SOUND_MIXER_NRDEVICES] =
SOUND_DEVICE_NAMES;
/**
** Initialize oss mixer.
** Initialize OSS mixer.
*/
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.
*/
@@ -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 channels number of channels
@@ -1427,14 +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();
}
AudioFlushBuffers();
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)
{
@@ -1530,7 +1684,7 @@ static void OssInit(void)
}
/**
** Cleanup oss audio output module.
** Cleanup OSS audio output module.
*/
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
//============================================================================
// 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.
*/
@@ -1565,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;
@@ -1619,9 +1867,7 @@ static void *AudioPlayHandlerThread(void *dummy)
#endif
Debug(3, "audio: play start\n");
#ifdef USE_ALSA
AlsaThread();
#endif
AudioUsedModule->Thread();
}
return dummy;
@@ -1636,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
}
/**
@@ -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.
**
@@ -1679,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);
}
/**
@@ -1694,24 +1940,7 @@ void AudioEnqueue(const void *samples, int count)
*/
void AudioFlushBuffers(void)
{
#ifdef USE_ALSA
#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
AudioUsedModule->FlushBuffers();
}
/**
@@ -1719,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();
}
/**
@@ -1734,13 +1956,17 @@ void AudioPoller(void)
*/
int AudioFreeBytes(void)
{
#ifdef USE_ALSA
return AlsaRingBuffer ? RingBufferFreeBytes(AlsaRingBuffer) : INT32_MAX;
#endif
#ifdef USE_OSS
return OssRingBuffer ? RingBufferFreeBytes(OssRingBuffer) : INT32_MAX;
#endif
return INT32_MAX; // no driver, much space
return AudioUsedModule->FreeBytes();
}
/**
** Get audio delay in time stamps.
**
** @returns audio delay in time stamps.
*/
uint64_t AudioGetDelay(void)
{
return AudioUsedModule->GetDelay();
}
/**
@@ -1760,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.
**
@@ -1783,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);
}
@@ -1830,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;
@@ -1890,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
}
@@ -1942,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

@@ -652,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)
{
@@ -695,7 +698,7 @@ int PlayVideo(const uint8_t * data, int size)
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;
}
@@ -788,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);
}
//////////////////////////////////////////////////////////////////////////////
/**
@@ -913,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
}
@@ -1117,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);
@@ -1130,9 +1157,6 @@ void SoftHdDeviceExit(void)
MyAudioDecoder = NULL;
}
VideoOsdExit();
VideoExit();
AudioExit();
CodecExit();
VideoPacketExit();

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);

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 =
trNOOP("A software and GPU emulated HD device");
@@ -53,6 +53,7 @@ static class cSoftHdDevice *MyDevice;
#define RESOLUTIONS 4 ///< number of resolutions
/// resolutions names
static const char *const Resolution[RESOLUTIONS] = {
"576i", "720p", "1080i_fake", "1080i"
};
@@ -78,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
//////////////////////////////////////////////////////////////////////////////
@@ -122,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);
}
@@ -144,12 +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);
*/
this->Level = level;
//SetActive(true);
SetActive(true);
}
cSoftOsd::~cSoftOsd(void)
@@ -158,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();
@@ -175,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);
@@ -213,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);
@@ -225,7 +238,6 @@ 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;
@@ -238,12 +250,32 @@ void cSoftOsd::Flush(void)
video_width = 1920;
video_height = 1080;
OsdDrawARGB((1920 - video_width) / 2 + Left() + bitmap->X0(),
1080 - video_height + Top() + bitmap->Y0(),
bitmap->Width(), bitmap->Height(), argb);
1080 - video_height + Top() + bitmap->Y0(), w, h, argb);
} else {
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(),
bitmap->Width(), bitmap->Height(), argb);
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);
@@ -264,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());
@@ -334,6 +366,8 @@ class cMenuSetupSoft:public cMenuSetupPage
int Sharpen[RESOLUTIONS];
int AudioDelay;
int AudioPassthrough;
int AutoCropInterval;
int AutoCropDelay;
protected:
virtual void Store(void);
public:
@@ -342,6 +376,8 @@ class cMenuSetupSoft:public cMenuSetupPage
/**
** Create a seperator item.
**
** @param label text inside separator
*/
static inline cOsdItem *SeparatorItem(const char *label)
{
@@ -376,10 +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,
tr("no"), tr("yes")));
trVDR("no"), trVDR("yes")));
//
// video
//
@@ -393,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));
@@ -411,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));
}
/**
@@ -450,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);
}
//////////////////////////////////////////////////////////////////////////////
@@ -475,17 +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 &width, int &height, double &aspect)
{
width = 1920;
height = 1080;
aspect = (double)width / height;
}
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);
@@ -498,8 +544,6 @@ class cSoftHdDevice:public cDevice
virtual uchar *GrabImage(int &, bool, int, int, int);
virtual int ProvidesCa(const cChannel *) const;
#if 0
// SPU facilities
private:
@@ -526,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);
@@ -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
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
{
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)?
*/
@@ -757,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);
}
//////////////////////////////////////////////////////////////////////////////
@@ -927,7 +992,9 @@ cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
cDevice::PrimaryDevice()->StopReplay();
Suspend();
ShutdownHandler.SetUserInactive();
if (ShutdownHandler.GetUserInactiveTime()) {
ShutdownHandler.SetUserInactive();
}
return NULL;
}
@@ -966,11 +1033,15 @@ 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);
@@ -983,6 +1054,8 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *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);
@@ -1015,6 +1088,7 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return true;
}
}
if (!strcmp(name, "AudioDelay")) {
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
return true;
@@ -1024,6 +1098,17 @@ 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;
}

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

1784
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.
extern VideoHwDecoder *VideoNewHwDecoder(void);
/// Deallocate video hardware decoder.
extern void VideoDelHwDecoder(VideoHwDecoder *);
/// Get and allocate a video hardware surface.
extern unsigned VideoGetSurface(VideoHwDecoder *);
@@ -97,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.