10 Commits
0.1.5 ... 0.2.0

Author SHA1 Message Date
Johns
cac1e5ce17 Release Version 0.2.0. 2012-01-07 13:21:27 +01:00
Johns
d6e2d04505 Fix compiler error with -DDEBUG. 2012-01-07 03:13:33 +01:00
Johns
45a34a3381 Add support for ac3 audio pass through. 2012-01-07 03:05:43 +01:00
Johns
92ffd978b0 Add workaround for alsa not playing hdmi sound.
Without open/close pcm, hdmi is quiet after second snd_pcm_set_params.
2012-01-07 02:35:49 +01:00
Johns
878813f206 Fix bug: broken device plugin stop and exit. 2012-01-06 15:39:32 +01:00
Johns
cb2314837c uwm window manager hide cursor workaround. 2012-01-06 15:37:21 +01:00
Johns
820c246148 Fix bug: old surface stay in video ringbuffer. 2012-01-05 22:55:57 +01:00
Johns
8dda2a0b8a Show transparent cursor to hide cursor. 2012-01-05 22:33:14 +01:00
Johns
761c06eac1 Add color standard support to vdpau. 2012-01-05 20:24:18 +01:00
Johns
0776bc5ee4 VDPAU improvements.
Add denoise, sharpness, skip chroma deinterlace support.
Show OSD only if something is to display, improves performance.
Add deinterlace mode with only 4 surfaces.
2012-01-05 17:20:44 +01:00
9 changed files with 1063 additions and 346 deletions

View File

@@ -1,5 +1,18 @@
User johns
Date:
Data: Sat Jan 7 13:20:07 CET 2012
Release Version 0.2.0
Add support for ac3 audio pass through.
Add workaround for alsa not playing hdmi sound.
Fix bug: broken device plugin stop and exit.
Show transparent cursor to hide cursor.
VDPAU: Add color standard support.
VDPAU: Add denoise and sharpness support.
VDPAU: Add skip chroma deinterlace support.
VDPAU: Show OSD only if something is to display, improves performance.
VDPAU: Add deinterlace with only 4 surfaces.
Date: Thu Jan 4 17:00:00 CET 2012
Release Version 0.1.5
Adds OSS mixer support.

View File

@@ -92,12 +92,22 @@ Setup: /etc/vdr/setup.conf
------
Following is supported:
softhddevice.MakePrimary = 1
0 = no change, 1 make softhddevice primary at start
softhddevice.Deinterlace = 0
0 = bob, 1 = weave, 2 = temporal, 3 = temporal_spatial, 4 = software
(only 0, 1 supported with vaapi)
softhddevice.MakePrimary = 1
0 = no change, 1 make softhddevice primary at start
softhddevice.SkipChromaDeinterlace = 0
0 = disabled, 1 = enabled (for slower cards, poor qualit<69>t)
softhddevice.Denoise = 0
0 .. 1000 noise reduction level (0 off, 1000 max)
softhddevice.Sharpness = 0
-1000 .. 1000 noise reduction level (0 off, -1000 max blur,
1000 max sharp)
softhddevice.Scaling = 0
0 = normal, 1 = fast, 2 = HQ, 3 = anamorphic
@@ -105,6 +115,10 @@ Setup: /etc/vdr/setup.conf
softhddevice.AudioDelay = 0
+n or -n ms
softhddevice.AudioPassthrough = 0
0 = none, 1 = AC-3
Commandline:
------------

16
Todo
View File

@@ -27,14 +27,20 @@ missing:
atmolight
zoom/fit-zoom 4:3
multistream handling
HDMI/SPDIF Passthrough
disable screensaver
disable window cursor
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
vdpau:
1080i with temporal spatial and level 1 scaling too slow with GT 520
1080i with temporal spatial too slow with GT 520 on some channels
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
hard channel switch
libva:
hard channel switch
libva-intel-driver:
intel still has hangups most with 1080i
@@ -71,8 +77,12 @@ audio/oss:
alsa oss emulation mixer "pcm" not working
ring buffer overflow with alsa oss emulation
HDMI/SPDIF Passthrough:
only AC-3 written
playback of recording
play back is too fast
pause is not reset, when replay exit
setup:
Setup of decoder type.

282
audio.c
View File

@@ -43,6 +43,8 @@
#endif
//#define USE_ALSA ///< enable alsa support
//#define USE_OSS ///< enable oss support
#define noSEARCH_HDMI_BUG
#define noSEARCH_HDMI_BUG2
#include <stdio.h>
#include <stdint.h>
@@ -88,6 +90,8 @@
#endif
#endif
#include <alsa/iatomic.h> // portable atomic_t
#include "ringbuffer.h"
#include "misc.h"
#include "audio.h"
@@ -110,6 +114,95 @@ static int64_t AudioPTS; ///< audio pts clock
static pthread_cond_t AudioStartCond; ///< condition variable
#endif
#ifdef SEARCH_HDMI_BUG2
//----------------------------------------------------------------------------
// ring buffer
//----------------------------------------------------------------------------
// FIXME: use this code, to combine alsa&oss ring buffers
#define AUDIO_RING_MAX 8 ///< number of audio ring buffers
/**
** Audio ring buffer.
*/
typedef struct _audio_ring_ring_
{
char FlushBuffers; ///< flag: flush buffers
unsigned SampleRate; ///< sample rate in hz
unsigned Channels; ///< number of channels
} AudioRingRing;
/// ring of audio ring buffers
static AudioRingRing AudioRing[AUDIO_RING_MAX];
static int AudioRingWrite; ///< audio ring write pointer
static int AudioRingRead; ///< audio ring read pointer
static atomic_t AudioRingFilled; ///< how many of the ring is used
/**
** Add sample rate, number of channel change to ring.
**
** @param freq sample frequency
** @param channels number of channels
*/
static int AudioRingAdd(int freq, int channels)
{
int filled;
filled = atomic_read(&AudioRingFilled);
if (filled == AUDIO_RING_MAX) { // no free slot
// FIXME: can wait for ring buffer empty
Error(_("audio: out of ring buffers\n"));
return -1;
}
AudioRing[AudioRingWrite].FlushBuffers = 1;
AudioRing[AudioRingWrite].SampleRate = freq;
AudioRing[AudioRingWrite].Channels = channels;
AudioRingWrite = (AudioRingWrite + 1) % AUDIO_RING_MAX;
atomic_inc(&AudioRingFilled);
#ifdef USE_AUDIO_THREAD
// tell thread, that something todo
AudioRunning = 1;
pthread_cond_signal(&AudioStartCond);
#endif
return 0;
}
/**
** Setup audio ring.
*/
static void AudioRingInit(void)
{
int i;
for (i = 0; i < AUDIO_RING_MAX; ++i) {
// FIXME:
//AlsaRingBuffer = RingBufferNew(48000 * 8 * 2); // ~1s 8ch 16bit
}
// one slot always reservered
AudioRingWrite = 1;
atomic_set(&AudioRingFilled, 1);
}
/**
** Cleanup audio ring.
*/
static void AudioRingExit(void)
{
int i;
for (i = 0; i < AUDIO_RING_MAX; ++i) {
// FIXME:
//RingBufferDel(AlsaRingBuffer);
}
}
#endif
#ifdef USE_ALSA
//============================================================================
@@ -152,6 +245,7 @@ static int AlsaAddToRingbuffer(const void *samples, int count)
if (n != count) {
Error(_("audio/alsa: can't place %d samples in ring buffer\n"), count);
// too many bytes are lost
// FIXME: should skip more, longer skip, but less often?
}
// Update audio clock
AudioPTS +=
@@ -207,7 +301,19 @@ static int AlsaPlayRingbuffer(void)
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
@@ -215,6 +321,7 @@ static int AlsaPlayRingbuffer(void)
}
return 0;
}
#endif
if (n < avail) { // not enough bytes in ring buffer
avail = n;
}
@@ -229,7 +336,7 @@ static int AlsaPlayRingbuffer(void)
} else {
err = snd_pcm_writei(AlsaPCMHandle, p, frames);
}
Debug(4, "audio/alsa: wrote %d/%d frames\n", err, frames);
//Debug(3, "audio/alsa: wrote %d/%d frames\n", err, frames);
if (err != frames) {
if (err < 0) {
if (err == -EAGAIN) {
@@ -255,6 +362,19 @@ static int AlsaPlayRingbuffer(void)
return 0;
}
/**
** Flush alsa buffers.
*/
static void AlsaFlushBuffers(void)
{
int err;
RingBufferReadAdvance(AlsaRingBuffer, RingBufferUsedBytes(AlsaRingBuffer));
if ((err = snd_pcm_drop(AlsaPCMHandle))) {
Error(_("audio: snd_pcm_drop(): %s\n"), snd_strerror(err));
}
}
#if 0
//----------------------------------------------------------------------------
@@ -462,16 +582,10 @@ static void AlsaThread(void)
if (AlsaFlushBuffer) {
// we can flush too many, but wo cares
Debug(3, "audio/alsa: flushing buffers\n");
RingBufferReadAdvance(AlsaRingBuffer,
RingBufferUsedBytes(AlsaRingBuffer));
#if 1
if ((err = snd_pcm_drop(AlsaPCMHandle))) {
Error(_("audio: snd_pcm_drop(): %s\n"), snd_strerror(err));
}
AlsaFlushBuffers();
if ((err = snd_pcm_prepare(AlsaPCMHandle))) {
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
}
#endif
AlsaFlushBuffer = 0;
break;
}
@@ -499,8 +613,9 @@ static void AlsaThread(void)
*/
static void AlsaEnqueue(const void *samples, int count)
{
if (!AlsaRingBuffer || !AlsaPCMHandle) {
Debug(3, "audio/alsa: not ready\n");
if (!AlsaRingBuffer || !AlsaPCMHandle || !AudioSampleRate) {
printf("%p %p %d\n", AlsaRingBuffer, AlsaPCMHandle, AudioSampleRate);
Debug(3, "audio/alsa: enqueue not ready\n");
return;
}
if (AlsaAddToRingbuffer(samples, count)) {
@@ -518,35 +633,48 @@ static void AlsaEnqueue(const void *samples, int count)
#endif
/**
** Initialize alsa pcm device.
**
** @see AudioPCMDevice
** Open alsa pcm device.
*/
static void AlsaInitPCM(void)
static snd_pcm_t *AlsaOpenPCM(void)
{
const char *device;
snd_pcm_t *handle;
snd_pcm_hw_params_t *hw_params;
int err;
snd_pcm_uframes_t buffer_size;
if (!(device = AudioPCMDevice)) {
if (!(device = getenv("ALSA_DEVICE"))) {
device = "default";
}
}
// FIXME: must set alsa error output to /dev/null
if ((err =
snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK)) < 0) {
Fatal(_("audio/alsa: playback open '%s' error: %s\n"), device,
Error(_("audio/alsa: playback open '%s' error: %s\n"), device,
snd_strerror(err));
// FIXME: no fatal error for plugins!
return NULL;
}
if ((err = snd_pcm_nonblock(handle, 0)) < 0) {
Error(_("audio/alsa: can't set block mode: %s\n"), snd_strerror(err));
}
return handle;
}
/**
** Initialize alsa pcm device.
**
** @see AudioPCMDevice
*/
static void AlsaInitPCM(void)
{
snd_pcm_t *handle;
snd_pcm_hw_params_t *hw_params;
int err;
snd_pcm_uframes_t buffer_size;
if (!(handle = AlsaOpenPCM())) {
return;
}
snd_pcm_hw_params_alloca(&hw_params);
// choose all parameters
@@ -556,8 +684,7 @@ static void AlsaInitPCM(void)
snd_strerror(err));
}
AlsaCanPause = snd_pcm_hw_params_can_pause(hw_params);
Info(_("audio/alsa: hw '%s' supports pause: %s\n"), device,
AlsaCanPause ? "yes" : "no");
Info(_("audio/alsa: supports pause: %s\n"), AlsaCanPause ? "yes" : "no");
snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size);
Info(_("audio/alsa: max buffer size %lu\n"), buffer_size);
@@ -656,7 +783,7 @@ static uint64_t AlsaGetDelay(void)
snd_pcm_sframes_t delay;
uint64_t pts;
if (!AlsaPCMHandle) {
if (!AlsaPCMHandle || !AudioSampleRate) {
return 0UL;
}
// FIXME: thread safe? __assert_fail_base in snd_pcm_delay
@@ -702,12 +829,14 @@ static int AlsaSetup(int *freq, int *channels)
snd_pcm_uframes_t period_size;
int err;
int ret;
snd_pcm_t *handle;
if (!AlsaPCMHandle) { // alsa not running yet
return -1;
}
#if 1
// flush any buffered data
#ifndef SEARCH_HDMI_BUG2
#ifdef USE_AUDIO_THREAD
if (AudioRunning) {
while (AudioRunning) {
@@ -718,11 +847,21 @@ static int AlsaSetup(int *freq, int *channels)
} else
#endif
{
RingBufferReadAdvance(AlsaRingBuffer,
RingBufferUsedBytes(AlsaRingBuffer));
AlsaFlushBuffers();
}
#endif
AudioPTS = INT64_C(0x8000000000000000);
if (1) { // close+open to fix hdmi no sound bugs
handle = AlsaPCMHandle;
AlsaPCMHandle = NULL;
snd_pcm_close(handle);
if (!(handle = AlsaOpenPCM())) {
return -1;
}
AlsaPCMHandle = handle;
}
ret = 0;
try_again:
AudioChannels = *channels;
@@ -844,6 +983,41 @@ static int AlsaSetup(int *freq, int *channels)
// FIXME: use hw_params for buffer_size period_size
#endif
#if 1
if (0) { // no underruns allowed, play silence
snd_pcm_sw_params_t *sw_params;
snd_pcm_uframes_t boundary;
snd_pcm_sw_params_alloca(&sw_params);
err = snd_pcm_sw_params_current(AlsaPCMHandle, sw_params);
if (err < 0) {
Error(_("audio: snd_pcm_sw_params_current failed: %s\n"),
snd_strerror(err));
}
if ((err = snd_pcm_sw_params_get_boundary(sw_params, &boundary)) < 0) {
Error(_("audio: snd_pcm_sw_params_get_boundary failed: %s\n"),
snd_strerror(err));
}
Debug(4, "audio/alsa: boundary %lu frames\n", boundary);
if ((err =
snd_pcm_sw_params_set_stop_threshold(AlsaPCMHandle, sw_params,
boundary)) < 0) {
Error(_("audio: snd_pcm_sw_params_set_silence_size failed: %s\n"),
snd_strerror(err));
}
if ((err =
snd_pcm_sw_params_set_silence_size(AlsaPCMHandle, sw_params,
boundary)) < 0) {
Error(_("audio: snd_pcm_sw_params_set_silence_size failed: %s\n"),
snd_strerror(err));
}
if ((err = snd_pcm_sw_params(AlsaPCMHandle, sw_params)) < 0) {
Error(_("audio: snd_pcm_sw_params failed: %s\n"),
snd_strerror(err));
}
}
#endif
// update buffer
snd_pcm_get_params(AlsaPCMHandle, &buffer_size, &period_size);
@@ -954,6 +1128,7 @@ static int OssAddToRingbuffer(const void *samples, int count)
if (n != count) {
Error(_("audio/oss: can't place %d samples in ring buffer\n"), count);
// too many bytes are lost
// FIXME: should skip more, longer skip, but less often?
}
// Update audio clock
AudioPTS +=
@@ -1375,12 +1550,59 @@ 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
if (atomic_read(&AudioRingFilled) > 1) {
int sample_rate;
int channels;
// skip all sample changes between
while (atomic_read(&AudioRingFilled) > 1) {
Debug(3, "audio: skip ring buffer\n");
AudioRingRead = (AudioRingRead + 1) % AUDIO_RING_MAX;
atomic_dec(&AudioRingFilled);
}
#ifdef USE_ALSA
// FIXME: flush only if there is something to flush
AlsaFlushBuffers();
sample_rate = AudioRing[AudioRingRead].SampleRate;
channels = AudioRing[AudioRingRead].Channels;
Debug(3, "audio: thread channels %d sample-rate %d hz\n", channels,
sample_rate);
if (AlsaSetup(&sample_rate, &channels)) {
Error(_("audio: can't set channels %d sample-rate %d hz\n"),
channels, sample_rate);
}
Debug(3, "audio: thread channels %d sample-rate %d hz\n",
AudioChannels, AudioSampleRate);
if (1) {
int16_t buf[6144 / 2];
buf[0] = htole16(0xF872); // iec 61937 sync word
buf[1] = htole16(0x4E1F);
buf[2] = htole16((7 << 5) << 8 | 0x00);
buf[3] = htole16(0x0000);
memset(buf + 4, 0, 6144 - 8);
AlsaEnqueue(buf, 6144);
}
#endif
}
#endif
Debug(3, "audio: play start\n");
#ifdef USE_ALSA
AlsaThread();
@@ -1406,6 +1628,8 @@ static void AudioInitThread(void)
pthread_yield();
} while (!AlsaPCMHandle);
#endif
pthread_yield();
usleep(5 * 1000);
}
/**
@@ -1550,6 +1774,10 @@ int AudioSetup(int *freq, int *channels)
// FIXME: set flag invalid setup
return -1;
}
#if defined(SEARCH_HDMI_BUG) || defined(SEARCH_HDMI_BUG2)
// FIXME: need to store possible combination and report this
return AudioRingAdd(*freq, *channels);
#endif
#ifdef USE_ALSA
return AlsaSetup(freq, channels);
#endif
@@ -1577,6 +1805,9 @@ void AudioInit(void)
int freq;
int chan;
#ifdef SEARCH_HDMI_BUG2
AudioRingInit();
#endif
#ifdef USE_ALSA
AlsaInit();
#endif
@@ -1609,6 +1840,9 @@ void AudioExit(void)
#ifdef USE_OSS
OssExit();
#endif
#ifdef SEARCH_HDMI_BUG2
AudioRingExit();
#endif
}
#ifdef AUDIO_TEST

196
codec.c
View File

@@ -35,8 +35,12 @@
*/
#define USE_AVPARSER
/// compile with passthrough support (experimental)
#define USE_PASSTHROUGH
#include <stdio.h>
#include <unistd.h>
#include <endian.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -585,8 +589,17 @@ struct _audio_decoder_
int HwChannels; ///< hw channels
ReSampleContext *ReSample; ///< audio resampling context
};
#ifdef USE_PASSTHROUGH
//static char CodecPassthroughPCM; ///< pass pcm through (unsupported)
static char CodecPassthroughAC3; ///< pass ac3 through
//static char CodecPassthroughDTS; ///< pass dts through (unsupported)
//static char CodecPassthroughMPA; ///< pass mpa through (unsupported)
#endif
/**
** Allocate a new audio decoder context.
**
@@ -683,6 +696,18 @@ void CodecAudioClose(AudioDecoder * audio_decoder)
}
}
/**
** Set audio pass-through.
*/
void CodecSetAudioPassthrough(int mask)
{
#ifdef USE_PASSTHROUGH
CodecPassthroughAC3 = mask & 1 ? 1 : 0;
#endif
// FIXME: must update audio decoder (nr. of channels wrong)
(void)mask;
}
#ifdef USE_AVPARSER
/**
@@ -730,6 +755,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
!index ? (uint64_t) spkt->pts : AV_NOPTS_VALUE,
!index ? (uint64_t) spkt->dts : AV_NOPTS_VALUE, -1);
// FIXME: make this a function for both #ifdef cases
if (dpkt->size) {
int buf_sz;
@@ -765,7 +791,15 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
audio_decoder->SampleRate = audio_ctx->sample_rate;
audio_decoder->HwSampleRate = audio_ctx->sample_rate;
audio_decoder->Channels = audio_ctx->channels;
audio_decoder->HwChannels = audio_ctx->channels;
#ifdef USE_PASSTHROUGH
// SPDIF/HDMI passthrough
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
audio_decoder->HwChannels = 2;
} else
#endif
{
audio_decoder->HwChannels = audio_ctx->channels;
}
// channels not support?
if ((err =
@@ -826,6 +860,81 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
AudioEnqueue(outbuf, outlen);
}
} else {
#ifdef USE_PASSTHROUGH
// SPDIF/HDMI passthrough
if (CodecPassthroughAC3
&& audio_ctx->codec_id == CODEC_ID_AC3) {
// build SPDIF header and append A52 audio to it
// dpkt is the original data
buf_sz = 6144;
if (buf_sz < dpkt->size + 8) {
Error(_
("codec/audio: decoded data smaller than encoded\n"));
break;
}
// copy original data for output
// FIXME: not 100% sure, if endian is correct
buf[0] = htole16(0xF872); // iec 61937 sync word
buf[1] = htole16(0x4E1F);
buf[2] = htole16(0x01 | (dpkt->data[5] & 0x07) << 8);
buf[3] = htole16(dpkt->size * 8);
swab(dpkt->data, buf + 4, dpkt->size);
memset(buf + 4 + dpkt->size / 2, 0,
buf_sz - 8 - dpkt->size);
}
#if 0
//
// old experimental code
//
if (1) {
// FIXME: need to detect dts
// copy original data for output
// FIXME: buf is sint
buf[0] = 0x72;
buf[1] = 0xF8;
buf[2] = 0x1F;
buf[3] = 0x4E;
buf[4] = 0x00;
switch (dpkt->size) {
case 512:
buf[5] = 0x0B;
break;
case 1024:
buf[5] = 0x0C;
break;
case 2048:
buf[5] = 0x0D;
break;
default:
Debug(3,
"codec/audio: dts sample burst not supported\n");
buf[5] = 0x00;
break;
}
buf[6] = (dpkt->size * 8);
buf[7] = (dpkt->size * 8) >> 8;
//buf[8] = 0x0B;
//buf[9] = 0x77;
//printf("%x %x\n", dpkt->data[0],dpkt->data[1]);
// swab?
memcpy(buf + 8, dpkt->data, dpkt->size);
memset(buf + 8 + dpkt->size, 0,
buf_sz - 8 - dpkt->size);
} else if (1) {
// FIXME: need to detect mp2
// FIXME: mp2 passthrough
// see softhddev.c version/layer
// 0x04 mpeg1 layer1
// 0x05 mpeg1 layer23
// 0x06 mpeg2 ext
// 0x07 mpeg2.5 layer 1
// 0x08 mpeg2.5 layer 2
// 0x09 mpeg2.5 layer 3
}
// DTS HD?
// True HD?
#endif
#endif
AudioEnqueue(buf, buf_sz);
}
}
@@ -904,90 +1013,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
avcodec_decode_audio4(audio_ctx, frame, &got_frame, dpkt);
#else
#endif
if (buf_sz > 0) { // something decoded
// Update audio clock
if ((uint64_t) spkt->pts != AV_NOPTS_VALUE) {
AudioSetClock(spkt->pts);
spkt->pts = AV_NOPTS_VALUE;
}
// FIXME: must first play remainings bytes, than change and play new.
if (audio_decoder->SampleRate != audio_ctx->sample_rate
|| audio_decoder->Channels != audio_ctx->channels) {
int err;
if (audio_decoder->ReSample) {
audio_resample_close(audio_decoder->ReSample);
audio_decoder->ReSample = NULL;
}
audio_decoder->SampleRate = audio_ctx->sample_rate;
audio_decoder->HwSampleRate = audio_ctx->sample_rate;
audio_decoder->Channels = audio_ctx->channels;
audio_decoder->HwChannels = audio_ctx->channels;
// channels not support?
if ((err =
AudioSetup(&audio_decoder->HwSampleRate,
&audio_decoder->HwChannels))) {
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
audio_ctx->sample_rate, audio_ctx->channels,
audio_decoder->HwSampleRate,
audio_decoder->HwChannels);
if (err == 1) {
audio_decoder->ReSample =
av_audio_resample_init(audio_decoder->HwChannels,
audio_ctx->channels, audio_decoder->HwSampleRate,
audio_ctx->sample_rate, audio_ctx->sample_fmt,
audio_ctx->sample_fmt, 16, 10, 0, 0.8);
// libav-0.8_pre didn't support 6 -> 2 channels
if (!audio_decoder->ReSample) {
Error(_("codec/audio: resample setup error\n"));
audio_decoder->HwChannels = 0;
audio_decoder->HwSampleRate = 0;
}
} else {
// FIXME: handle errors
Debug(3, "codec/audio: audio setup error\n");
audio_decoder->HwChannels = 0;
audio_decoder->HwSampleRate = 0;
break;
}
}
}
if (audio_decoder->HwSampleRate && audio_decoder->HwChannels) {
// need to resample audio
if (audio_decoder->ReSample) {
int16_t outbuf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 +
FF_INPUT_BUFFER_PADDING_SIZE]
__attribute__ ((aligned(16)));
int outlen;
// FIXME: libav-0.7.2 crash here
outlen =
audio_resample(audio_decoder->ReSample, outbuf, buf,
buf_sz);
#ifdef DEBUG
if (outlen != buf_sz) {
Debug(3, "codec/audio: possible fixed ffmpeg\n");
}
#endif
if (outlen) {
// outlen seems to be wrong in ffmpeg-0.9
outlen /= audio_ctx->channels *
av_get_bytes_per_sample(audio_ctx->sample_fmt);
outlen *=
audio_decoder->HwChannels *
av_get_bytes_per_sample(audio_ctx->sample_fmt);
Debug(4, "codec/audio: %d -> %d\n", buf_sz, outlen);
AudioEnqueue(outbuf, outlen);
}
} else {
AudioEnqueue(buf, buf_sz);
}
}
}
// FIXME: see above, old code removed
index += n;
}

View File

@@ -42,7 +42,9 @@
#include "video.h"
#include "codec.h"
static char BrokenThreadsAndPlugins; ///< broken vdr threads and plugins
//////////////////////////////////////////////////////////////////////////////
// Variables
//////////////////////////////////////////////////////////////////////////////
#ifdef USE_VDPAU
static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
@@ -50,6 +52,8 @@ static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
#define ConfigVdpauDecoder 0 ///< no vdpau decoder configured
#endif
static const char DeviceStopped = 1; ///< flag device stopped
//////////////////////////////////////////////////////////////////////////////
// Audio
//////////////////////////////////////////////////////////////////////////////
@@ -189,9 +193,6 @@ void PlayAudio(const uint8_t * data, int size,
int n;
AVPacket avpkt[1];
if (BrokenThreadsAndPlugins) {
return;
}
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
if (NewAudioStream) {
@@ -301,9 +302,6 @@ void PlayAudio(const uint8_t * data, int size,
*/
void Mute(void)
{
if (BrokenThreadsAndPlugins) {
return;
}
AudioSetVolume(0);
}
@@ -314,9 +312,6 @@ void Mute(void)
*/
void SetVolumeDevice(int volume)
{
if (BrokenThreadsAndPlugins) {
return;
}
AudioSetVolume((volume * 100) / 255);
}
@@ -439,6 +434,8 @@ static void VideoEnqueue(int64_t pts, const void *data, int size)
/**
** Finish current packet advance to next.
**
** @param codec_id codec id of packet (MPEG/H264)
*/
static void VideoNextPacket(int codec_id)
{
@@ -637,9 +634,6 @@ int PlayVideo(const uint8_t * data, int size)
int64_t pts;
int n;
if (BrokenThreadsAndPlugins) {
return size;
}
if (Usr1Signal) { // x11 server ready
Usr1Signal = 0;
StartVideo();
@@ -760,9 +754,6 @@ int PlayVideo(const uint8_t * data, int size)
*/
void SetPlayMode(void)
{
if (BrokenThreadsAndPlugins) {
return;
}
if (MyVideoDecoder) {
if (VideoCodecID != CODEC_ID_NONE) {
NewVideoStream = 1;
@@ -850,9 +841,6 @@ void GetOsdSize(int *width, int *height, double *aspect)
*/
void OsdClose(void)
{
if (BrokenThreadsAndPlugins) {
return;
}
VideoOsdClear();
}
@@ -861,9 +849,6 @@ void OsdClose(void)
*/
void OsdDrawARGB(int x, int y, int height, int width, const uint8_t * argb)
{
if (BrokenThreadsAndPlugins) {
return;
}
VideoOsdDrawARGB(x, y, height, width, argb);
}
@@ -1030,39 +1015,6 @@ static void StartXServer(void)
*/
void SoftHdDeviceExit(void)
{
}
/**
** Prepare plugin.
*/
void Start(void)
{
if (StartX11Server) {
StartXServer();
}
CodecInit();
// FIXME: AudioInit for HDMI after X11 startup
AudioInit();
if (!StartX11Server) {
StartVideo();
}
}
/**
** Stop plugin.
*/
void Stop(void)
{
#ifdef DEBUG
Debug(3, "video: max used PES packet size: %d\n", VideoMaxPacketSize);
#endif
// FIXME:
// don't let any thread enter our plugin, but can still crash, when
// a thread has called any function, while Stop is called.
BrokenThreadsAndPlugins = 1;
usleep(2 * 1000);
// lets hope that vdr does a good thead cleanup
// no it doesn't do a good thread cleanup
if (MyVideoDecoder) {
@@ -1091,10 +1043,40 @@ void Stop(void)
}
}
/**
** Prepare plugin.
*/
void Start(void)
{
if (StartX11Server) {
StartXServer();
}
CodecInit();
// FIXME: AudioInit for HDMI after X11 startup
AudioInit();
if (!StartX11Server) {
StartVideo();
}
}
/**
** Stop plugin.
**
** @note stop everything, but don't cleanup, module is still called.
*/
void Stop(void)
{
#ifdef DEBUG
Debug(3, "video: max used PES packet size: %d\n", VideoMaxPacketSize);
#endif
}
/**
** Main thread hook, periodic called from main thread.
*/
void MainThreadHook(void)
{
VideoDisplayHandler();
if (!DeviceStopped) {
VideoDisplayHandler();
}
}

View File

@@ -33,14 +33,16 @@
#include "softhddev.h"
#include "softhddevice.h"
extern "C" {
#include "video.h"
extern "C"
{
#include "video.h"
extern void AudioPoller(void);
extern void CodecSetAudioPassthrough(int);
}
//////////////////////////////////////////////////////////////////////////////
static const char *const VERSION = "0.1.5";
static const char *const VERSION = "0.2.0";
static const char *const DESCRIPTION =
trNOOP("A software and GPU emulated HD device");
@@ -49,11 +51,15 @@ static class cSoftHdDevice *MyDevice;
//////////////////////////////////////////////////////////////////////////////
static char ConfigMakePrimary; ///< config primary wanted
static char ConfigVideoDeinterlace; ///< config deinterlace
static char ConfigVideoScaling; ///< config scaling
static int ConfigVideoAudioDelay; ///< config audio delay
static char DoMakePrimary; ///< flag switch primary
static char ConfigMakePrimary; ///< config primary wanted
static char ConfigVideoDeinterlace; ///< config deinterlace
static char ConfigVideoSkipChromaDeinterlace; ///< config skip chroma
static int ConfigVideoDenoise; ///< config denoise
static int ConfigVideoSharpen; ///< config sharpen
static char ConfigVideoScaling; ///< config scaling
static int ConfigVideoAudioDelay; ///< config audio delay
static int ConfigAudioPassthrough; ///< config audio pass-through
static volatile char DoMakePrimary; ///< flag switch primary
//////////////////////////////////////////////////////////////////////////////
@@ -126,7 +132,7 @@ cSoftOsd::cSoftOsd(int left, int top, uint level)
cSoftOsd::~cSoftOsd(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
SetActive(false);
OsdClose();
@@ -203,8 +209,10 @@ void cSoftOsd::Flush(void)
w = pm->ViewPort().Width();
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());
@@ -226,14 +234,14 @@ class cSoftOsdProvider:public cOsdProvider
cSoftOsdProvider(void);
};
cOsd *cSoftOsdProvider::Osd; ///< single osd
cOsd *cSoftOsdProvider::Osd; ///< single osd
/**
** Create a new OSD.
*/
cOsd *cSoftOsdProvider::CreateOsd(int left, int top, uint level)
{
dsyslog("[softhddev]%s: %d, %d, %d\n", __FUNCTION__, left, top, level);
//dsyslog("[softhddev]%s: %d, %d, %d\n", __FUNCTION__, left, top, level);
Osd = new cSoftOsd(left, top, level);
return Osd;
@@ -250,7 +258,7 @@ bool cSoftOsdProvider::ProvidesTrueColor(void)
cSoftOsdProvider::cSoftOsdProvider(void)
: cOsdProvider()
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
}
//////////////////////////////////////////////////////////////////////////////
@@ -262,8 +270,12 @@ class cMenuSetupSoft:public cMenuSetupPage
protected:
int MakePrimary;
int Deinterlace;
int SkipChromaDeinterlace;
int Denoise;
int Sharpen;
int Scaling;
int AudioDelay;
int AudioPassthrough;
protected:
virtual void Store(void);
public:
@@ -275,10 +287,15 @@ class cMenuSetupSoft:public cMenuSetupPage
*/
cMenuSetupSoft::cMenuSetupSoft(void)
{
static const char * const deinterlace[] = {
"Bob", "Weave", "Temporal", "TemporalSpatial", "Software" };
static const char * const scaling[] = {
"Normal", "Fast", "HQ", "Anamorphic" };
static const char *const deinterlace[] = {
"Bob", "Weave", "Temporal", "TemporalSpatial", "Software"
};
static const char *const scaling[] = {
"Normal", "Fast", "HQ", "Anamorphic"
};
static const char *const passthrough[] = {
"None", "AC-3"
};
// cMenuEditBoolItem cMenuEditBitItem cMenuEditNumItem
// cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem
@@ -286,11 +303,25 @@ cMenuSetupSoft::cMenuSetupSoft(void)
Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary,
tr("no"), tr("yes")));
Deinterlace = ConfigVideoDeinterlace;
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace, 5, deinterlace));
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace, 5,
deinterlace));
SkipChromaDeinterlace = ConfigVideoSkipChromaDeinterlace;
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),
&SkipChromaDeinterlace, tr("no"), tr("yes")));
Denoise = ConfigVideoDenoise;
Add(new cMenuEditIntItem(tr("Denoise (vdpau 0..1000)"), &Denoise, 0,
1000));
Sharpen = ConfigVideoSharpen;
Add(new cMenuEditIntItem(tr("Sharpen (vdpau -1000..1000)"), &Sharpen,
-1000, 1000));
Scaling = ConfigVideoScaling;
Add(new cMenuEditStraItem(tr("Scaling"), &Scaling, 4, scaling));
AudioDelay = ConfigVideoAudioDelay;
Add(new cMenuEditIntItem(tr("Audio delay (ms)"), &AudioDelay, -1000, 1000));
Add(new cMenuEditIntItem(tr("Audio delay (ms)"), &AudioDelay, -1000,
1000));
AudioPassthrough = ConfigAudioPassthrough;
Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2,
passthrough));
}
/**
@@ -301,10 +332,19 @@ void cMenuSetupSoft::Store(void)
SetupStore("MakePrimary", ConfigMakePrimary = MakePrimary);
SetupStore("Deinterlace", ConfigVideoDeinterlace = Deinterlace);
VideoSetDeinterlace(ConfigVideoDeinterlace);
SetupStore("SkipChromaDeinterlace", ConfigVideoSkipChromaDeinterlace =
SkipChromaDeinterlace);
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
SetupStore("Denoise", ConfigVideoDenoise = Denoise);
VideoSetDenoise(ConfigVideoDenoise);
SetupStore("Sharpen", ConfigVideoSharpen = Sharpen);
VideoSetSharpen(ConfigVideoSharpen);
SetupStore("Scaling", ConfigVideoScaling = Scaling);
VideoSetScaling(ConfigVideoScaling);
SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay);
VideoSetAudioDelay(ConfigVideoAudioDelay);
SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough);
CodecSetAudioPassthrough(ConfigAudioPassthrough);
}
//////////////////////////////////////////////////////////////////////////////
@@ -333,7 +373,7 @@ class cSoftHdDevice:public cDevice
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
#ifdef USE_OSS // FIXME: testing only oss
virtual int PlayTsAudio(const uchar *, int);
#endif
virtual void SetAudioChannelDevice(int);
@@ -360,14 +400,14 @@ class cSoftHdDevice:public cDevice
cSoftHdDevice::cSoftHdDevice(void)
{
dsyslog("[softhddev]%s\n", __FUNCTION__);
//dsyslog("[softhddev]%s\n", __FUNCTION__);
spuDecoder = NULL;
}
cSoftHdDevice::~cSoftHdDevice(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
}
void cSoftHdDevice::MakePrimaryDevice(bool on)
@@ -383,7 +423,7 @@ void cSoftHdDevice::MakePrimaryDevice(bool on)
int cSoftHdDevice::ProvidesCa(
__attribute__ ((unused)) const cChannel * channel) const
{
dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
//dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
return 0;
}
@@ -436,7 +476,7 @@ int64_t cSoftHdDevice::GetSTC(void)
{
// dsyslog("[softhddev]%s:\n", __FUNCTION__);
return ::VideoGetClock();
return::VideoGetClock();
}
void cSoftHdDevice::TrickSpeed(int Speed)
@@ -479,7 +519,7 @@ void cSoftHdDevice::Mute(void)
void cSoftHdDevice::SetVolumeDevice(int volume)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
//dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
::SetVolumeDevice(volume);
}
@@ -496,7 +536,7 @@ bool cSoftHdDevice::Poll(
{
// dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms);
return ::Poll(timeout_ms);
return::Poll(timeout_ms);
}
bool cSoftHdDevice::Flush(int timeout_ms)
@@ -532,22 +572,23 @@ int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id)
void cSoftHdDevice::SetAudioTrackDevice(
__attribute__ ((unused)) eTrackType type)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
}
void cSoftHdDevice::SetDigitalAudioDevice(bool on)
void cSoftHdDevice::SetDigitalAudioDevice( __attribute__ ((unused)) bool on)
{
dsyslog("[softhddev]%s: %s\n", __FUNCTION__, on ? "true" : "false");
//dsyslog("[softhddev]%s: %s\n", __FUNCTION__, on ? "true" : "false");
}
void cSoftHdDevice::SetAudioChannelDevice(int audio_channel)
void cSoftHdDevice::SetAudioChannelDevice( __attribute__ ((unused))
int audio_channel)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, audio_channel);
//dsyslog("[softhddev]%s: %d\n", __FUNCTION__, audio_channel);
}
int cSoftHdDevice::GetAudioChannelDevice(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
return 0;
}
@@ -560,7 +601,7 @@ int cSoftHdDevice::PlayVideo(const uchar * data, int length)
{
//dsyslog("[softhddev]%s: %p %d\n", __FUNCTION__, data, length);
return ::PlayVideo(data, length);
return::PlayVideo(data, length);
}
#if 0
@@ -573,7 +614,7 @@ int cSoftHdDevice::PlayTsVideo(const uchar * Data, int Length)
}
#endif
#ifdef USE_OSS // FIXME: testing only oss
#ifdef USE_OSS // FIXME: testing only oss
///
/// Play a TS audio packet.
///
@@ -583,7 +624,7 @@ int cSoftHdDevice::PlayTsAudio(const uchar * data, int length)
{
AudioPoller();
return cDevice::PlayTsAudio(data,length);
return cDevice::PlayTsAudio(data, length);
}
#endif
@@ -626,13 +667,13 @@ cPluginSoftHdDevice::cPluginSoftHdDevice(void)
// Initialize any member variables here.
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
}
cPluginSoftHdDevice::~cPluginSoftHdDevice(void)
{
// Clean up after yourself!
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
::SoftHdDeviceExit();
}
@@ -660,7 +701,7 @@ const char *cPluginSoftHdDevice::CommandLineHelp(void)
*/
bool cPluginSoftHdDevice::ProcessArgs(int argc, char *argv[])
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
return::ProcessArgs(argc, argv);
}
@@ -668,7 +709,7 @@ bool cPluginSoftHdDevice::ProcessArgs(int argc, char *argv[])
bool cPluginSoftHdDevice::Initialize(void)
{
// Start any background activities the plugin shall perform.
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
MyDevice = new cSoftHdDevice();
@@ -680,7 +721,7 @@ bool cPluginSoftHdDevice::Start(void)
const cDevice *primary;
// Start any background activities the plugin shall perform.
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
primary = cDevice::PrimaryDevice();
if (MyDevice != primary) {
@@ -703,7 +744,7 @@ bool cPluginSoftHdDevice::Start(void)
void cPluginSoftHdDevice::Stop(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
::Stop();
}
@@ -717,7 +758,7 @@ void cPluginSoftHdDevice::Housekeeping(void)
const char *cPluginSoftHdDevice::MainMenuEntry(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
return tr(MAINMENUENTRY);
return NULL;
}
@@ -730,7 +771,7 @@ const char *cPluginSoftHdDevice::MainMenuEntry(void)
*/
void cPluginSoftHdDevice::MainThreadHook(void)
{
// dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
if (DoMakePrimary && MyDevice) {
dsyslog("[softhddev]%s: switching primary device\n", __FUNCTION__);
@@ -765,7 +806,7 @@ cOsdObject *cPluginSoftHdDevice::MainMenuAction(void)
*/
cMenuSetupPage *cPluginSoftHdDevice::SetupMenu(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
//dsyslog("[softhddev]%s:\n", __FUNCTION__);
return new cMenuSetupSoft;
}
@@ -775,7 +816,7 @@ cMenuSetupPage *cPluginSoftHdDevice::SetupMenu(void)
*/
bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
{
dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
//dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
// FIXME: handle the values
if (!strcmp(name, "MakePrimary")) {
@@ -786,6 +827,19 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
VideoSetDeinterlace(ConfigVideoDeinterlace = atoi(value));
return true;
}
if (!strcmp(name, "SkipChromaDeinterlace")) {
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace =
atoi(value));
return true;
}
if (!strcmp(name, "Denoise")) {
VideoSetDenoise(ConfigVideoDenoise = atoi(value));
return true;
}
if (!strcmp(name, "Sharpen")) {
VideoSetSharpen(ConfigVideoSharpen = atoi(value));
return true;
}
if (!strcmp(name, "Scaling")) {
VideoSetScaling(ConfigVideoScaling = atoi(value));
return true;
@@ -794,6 +848,10 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
return true;
}
if (!strcmp(name, "AudioPassthrough")) {
CodecSetAudioPassthrough(ConfigAudioPassthrough = atoi(value));
return true;
}
return false;
}

627
video.c

File diff suppressed because it is too large Load Diff

11
video.h
View File

@@ -1,7 +1,7 @@
///
/// @file video.h @brief Video module header file
///
/// Copyright (c) 2009 - 2011 by Johns. All Rights Reserved.
/// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
///
/// Contributor(s):
///
@@ -83,9 +83,18 @@ extern int VideoSetGeometry(const char *);
/// set deinterlace
extern void VideoSetDeinterlace(int);
/// set skip chroma deinterlace
extern void VideoSetSkipChromaDeinterlace(int);
/// set scaling
extern void VideoSetScaling(int);
/// set denoise
extern void VideoSetDenoise(int);
/// set sharpen
extern void VideoSetSharpen(int);
/// set audio delay
extern void VideoSetAudioDelay(int);