mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Improved replay of recordings.
This commit is contained in:
parent
f1551cd321
commit
f6df79e8e6
2
Todo
2
Todo
@ -83,8 +83,8 @@ HDMI/SPDIF Passthrough:
|
|||||||
Channels are wrong setup, if changing setting during operation.
|
Channels are wrong setup, if changing setting during operation.
|
||||||
|
|
||||||
playback of recording
|
playback of recording
|
||||||
play back is too fast
|
|
||||||
pause is not reset, when replay exit
|
pause is not reset, when replay exit
|
||||||
|
replay/pause need 100% cpu
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
Setup of decoder type.
|
Setup of decoder type.
|
||||||
|
99
audio.c
99
audio.c
@ -342,6 +342,11 @@ static int AlsaPlayRingbuffer(void)
|
|||||||
if (err == -EAGAIN) {
|
if (err == -EAGAIN) {
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
if (err == -EBADFD) {
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
*/
|
||||||
Error(_("audio/alsa: underrun error?\n"));
|
Error(_("audio/alsa: underrun error?\n"));
|
||||||
err = snd_pcm_recover(AlsaPCMHandle, err, 0);
|
err = snd_pcm_recover(AlsaPCMHandle, err, 0);
|
||||||
if (err >= 0) {
|
if (err >= 0) {
|
||||||
@ -370,9 +375,13 @@ static void AlsaFlushBuffers(void)
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
RingBufferReadAdvance(AlsaRingBuffer, RingBufferUsedBytes(AlsaRingBuffer));
|
RingBufferReadAdvance(AlsaRingBuffer, RingBufferUsedBytes(AlsaRingBuffer));
|
||||||
if ((err = snd_pcm_drop(AlsaPCMHandle))) {
|
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));
|
||||||
}
|
}
|
||||||
|
if ((err = snd_pcm_prepare(AlsaPCMHandle)) < 0) {
|
||||||
|
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
|
||||||
|
}
|
||||||
|
AudioPTS = INT64_C(0x8000000000000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -567,8 +576,20 @@ static void AlsaThread(void)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
Debug(4, "audio: play loop\n");
|
|
||||||
pthread_testcancel();
|
pthread_testcancel();
|
||||||
|
if (AlsaFlushBuffer) {
|
||||||
|
// we can flush too many, but wo cares
|
||||||
|
Debug(3, "audio/alsa: flushing buffers\n");
|
||||||
|
AlsaFlushBuffers();
|
||||||
|
/*
|
||||||
|
if ((err = snd_pcm_prepare(AlsaPCMHandle))) {
|
||||||
|
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
AlsaFlushBuffer = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// wait for space in kernel buffers
|
||||||
if ((err = snd_pcm_wait(AlsaPCMHandle, 100)) < 0) {
|
if ((err = snd_pcm_wait(AlsaPCMHandle, 100)) < 0) {
|
||||||
Error(_("audio/alsa: wait underrun error?\n"));
|
Error(_("audio/alsa: wait underrun error?\n"));
|
||||||
err = snd_pcm_recover(AlsaPCMHandle, err, 0);
|
err = snd_pcm_recover(AlsaPCMHandle, err, 0);
|
||||||
@ -580,14 +601,7 @@ static void AlsaThread(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (AlsaFlushBuffer) {
|
if (AlsaFlushBuffer) {
|
||||||
// we can flush too many, but wo cares
|
continue;
|
||||||
Debug(3, "audio/alsa: flushing buffers\n");
|
|
||||||
AlsaFlushBuffers();
|
|
||||||
if ((err = snd_pcm_prepare(AlsaPCMHandle))) {
|
|
||||||
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
|
|
||||||
}
|
|
||||||
AlsaFlushBuffer = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if ((err = AlsaPlayRingbuffer())) { // empty / error
|
if ((err = AlsaPlayRingbuffer())) { // empty / error
|
||||||
snd_pcm_state_t state;
|
snd_pcm_state_t state;
|
||||||
@ -600,7 +614,8 @@ static void AlsaThread(void)
|
|||||||
Debug(3, "audio/alsa: stopping play\n");
|
Debug(3, "audio/alsa: stopping play\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
usleep(20 * 1000);
|
pthread_yield();
|
||||||
|
usleep(20 * 1000); // let fill the buffers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1195,6 +1210,21 @@ static int OssPlayRingbuffer(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** 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;
|
||||||
|
}
|
||||||
|
AudioPTS = INT64_C(0x8000000000000000);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// OSS pcm polled
|
// OSS pcm polled
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -1410,14 +1440,7 @@ static int OssSetup(int *freq, int *channels)
|
|||||||
// flush any buffered data
|
// flush any buffered data
|
||||||
{
|
{
|
||||||
AudioRunning = 0;
|
AudioRunning = 0;
|
||||||
RingBufferReadAdvance(OssRingBuffer,
|
OssFlushBuffers();
|
||||||
RingBufferUsedBytes(OssRingBuffer));
|
|
||||||
// flush kernel buffers
|
|
||||||
if (ioctl(OssPcmFildes, SNDCTL_DSP_HALT_OUTPUT, NULL) == -1) {
|
|
||||||
Error(_("audio/oss: ioctl(SNDCTL_DSP_HALT_OUTPUT): %s\n"),
|
|
||||||
strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
AudioPTS = INT64_C(0x8000000000000000);
|
AudioPTS = INT64_C(0x8000000000000000);
|
||||||
|
|
||||||
@ -1672,6 +1695,30 @@ void AudioEnqueue(const void *samples, int count)
|
|||||||
(void)count;
|
(void)count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Flush audio buffers.
|
||||||
|
*/
|
||||||
|
void AudioFlushBuffers(void)
|
||||||
|
{
|
||||||
|
#ifdef USE_ALSA
|
||||||
|
#ifdef USE_AUDIO_THREAD
|
||||||
|
if (AudioRunning) {
|
||||||
|
while (AudioRunning) {
|
||||||
|
AlsaFlushBuffer = 1;
|
||||||
|
usleep(1 * 1000);
|
||||||
|
}
|
||||||
|
AlsaFlushBuffer = 0;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
AlsaFlushBuffers();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_OSS
|
||||||
|
OssFlushBuffers();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Call back to play audio polled.
|
** Call back to play audio polled.
|
||||||
*/
|
*/
|
||||||
@ -1687,6 +1734,20 @@ void AudioPoller(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Get free bytes in audio output.
|
||||||
|
*/
|
||||||
|
int AudioFreeBytes(void)
|
||||||
|
{
|
||||||
|
#ifdef USE_ALSA
|
||||||
|
return RingBufferFreeBytes(AlsaRingBuffer);
|
||||||
|
#endif
|
||||||
|
#ifdef USE_OSS
|
||||||
|
return RingBufferFreeBytes(OssRingBuffer);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Set audio clock base.
|
** Set audio clock base.
|
||||||
**
|
**
|
||||||
|
8
audio.h
8
audio.h
@ -1,7 +1,7 @@
|
|||||||
///
|
///
|
||||||
/// @file audio.h @brief Audio module headerfile
|
/// @file audio.h @brief Audio module headerfile
|
||||||
///
|
///
|
||||||
/// Copyright (c) 2009 - 2011 by Johns. All Rights Reserved.
|
/// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
|
||||||
///
|
///
|
||||||
/// Contributor(s):
|
/// Contributor(s):
|
||||||
///
|
///
|
||||||
@ -28,12 +28,14 @@
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
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 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 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 uint64_t AudioGetDelay(void); ///< get current audio delay
|
||||||
|
|
||||||
extern int AudioSetup(int *, int *); ///< setup audio output
|
extern int AudioSetup(int *, int *); ///< setup audio output
|
||||||
|
23
codec.c
23
codec.c
@ -561,6 +561,16 @@ void CodecVideoDecode(VideoDecoder * decoder, const AVPacket * avpkt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Flush the video decoder.
|
||||||
|
**
|
||||||
|
** @param decoder video decoder data
|
||||||
|
*/
|
||||||
|
void CodecVideoFlushBuffers(VideoDecoder * decoder)
|
||||||
|
{
|
||||||
|
avcodec_flush_buffers(decoder->VideoCtx);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Audio
|
// Audio
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -738,9 +748,11 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
|||||||
spkt->pts = avpkt->pts;
|
spkt->pts = avpkt->pts;
|
||||||
spkt->dts = avpkt->dts;
|
spkt->dts = avpkt->dts;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef DEBUG
|
||||||
if (!audio_decoder->AudioParser) {
|
if (!audio_decoder->AudioParser) {
|
||||||
Fatal(_("codec: internal error parser freeded while running\n"));
|
Fatal(_("codec: internal error parser freeded while running\n"));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
audio_ctx = audio_decoder->AudioCtx;
|
audio_ctx = audio_decoder->AudioCtx;
|
||||||
index = 0;
|
index = 0;
|
||||||
@ -1026,6 +1038,17 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Flush the audio decoder.
|
||||||
|
**
|
||||||
|
** @param decoder audio decoder data
|
||||||
|
*/
|
||||||
|
void CodecAudioFlushBuffers(AudioDecoder * decoder)
|
||||||
|
{
|
||||||
|
// FIXME: reset audio parser
|
||||||
|
avcodec_flush_buffers(decoder->AudioCtx);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Codec
|
// Codec
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
24
codec.h
24
codec.h
@ -1,7 +1,7 @@
|
|||||||
///
|
///
|
||||||
/// @file codec.h @brief Codec module headerfile
|
/// @file codec.h @brief Codec module headerfile
|
||||||
///
|
///
|
||||||
/// Copyright (c) 2009 - 2011 by Johns. All Rights Reserved.
|
/// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
|
||||||
///
|
///
|
||||||
/// Contributor(s):
|
/// Contributor(s):
|
||||||
///
|
///
|
||||||
@ -40,26 +40,32 @@ typedef struct _audio_decoder_ AudioDecoder;
|
|||||||
/// Allocate a new video decoder context.
|
/// Allocate a new video decoder context.
|
||||||
extern VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder *);
|
extern VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder *);
|
||||||
|
|
||||||
/// Open video codec
|
/// Open video codec.
|
||||||
extern void CodecVideoOpen(VideoDecoder *, const char *, int);
|
extern void CodecVideoOpen(VideoDecoder *, const char *, int);
|
||||||
|
|
||||||
/// Close video codec
|
/// Close video codec.
|
||||||
extern void CodecVideoClose(VideoDecoder *);
|
extern void CodecVideoClose(VideoDecoder *);
|
||||||
|
|
||||||
/// Decode a video packet
|
/// Decode a video packet.
|
||||||
extern void CodecVideoDecode(VideoDecoder *, const AVPacket * pkt);
|
extern void CodecVideoDecode(VideoDecoder *, const AVPacket *);
|
||||||
|
|
||||||
|
/// Flush video buffers.
|
||||||
|
extern void CodecVideoFlushBuffers(VideoDecoder *);
|
||||||
|
|
||||||
/// Allocate a new audio decoder context.
|
/// Allocate a new audio decoder context.
|
||||||
extern AudioDecoder *CodecAudioNewDecoder(void);
|
extern AudioDecoder *CodecAudioNewDecoder(void);
|
||||||
|
|
||||||
/// Open audio codec
|
/// Open audio codec.
|
||||||
extern void CodecAudioOpen(AudioDecoder *, const char *, int);
|
extern void CodecAudioOpen(AudioDecoder *, const char *, int);
|
||||||
|
|
||||||
/// Close audio codec
|
/// Close audio codec.
|
||||||
extern void CodecAudioClose(AudioDecoder *);
|
extern void CodecAudioClose(AudioDecoder *);
|
||||||
|
|
||||||
/// Decode an audio packet
|
/// Decode an audio packet.
|
||||||
extern void CodecAudioDecode(AudioDecoder *, const AVPacket * pkt);
|
extern void CodecAudioDecode(AudioDecoder *, const AVPacket *);
|
||||||
|
|
||||||
|
/// Flush audio buffers.
|
||||||
|
extern void CodecAudioFlushBuffers(AudioDecoder *);
|
||||||
|
|
||||||
/// Setup and initialize codec module.
|
/// Setup and initialize codec module.
|
||||||
extern void CodecInit(void);
|
extern void CodecInit(void);
|
||||||
|
76
softhddev.c
76
softhddev.c
@ -59,6 +59,7 @@ static const char DeviceStopped = 1; ///< flag device stopped
|
|||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static volatile char NewAudioStream; ///< new audio stream
|
static volatile char NewAudioStream; ///< new audio stream
|
||||||
|
static volatile char SkipAudio; ///< skip audio stream
|
||||||
static AudioDecoder *MyAudioDecoder; ///< audio decoder
|
static AudioDecoder *MyAudioDecoder; ///< audio decoder
|
||||||
static enum CodecID AudioCodecID; ///< current codec id
|
static enum CodecID AudioCodecID; ///< current codec id
|
||||||
|
|
||||||
@ -185,10 +186,11 @@ static int FindAudioSync(const AVPacket * avpkt)
|
|||||||
** @param size size of PES packet
|
** @param size size of PES packet
|
||||||
** @param id PES packet type
|
** @param id PES packet type
|
||||||
*/
|
*/
|
||||||
void PlayAudio(const uint8_t * data, int size,
|
int PlayAudio(const uint8_t * data, int size,
|
||||||
__attribute__ ((unused)) uint8_t id)
|
__attribute__ ((unused)) uint8_t id)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
int osize;
|
||||||
AVPacket avpkt[1];
|
AVPacket avpkt[1];
|
||||||
|
|
||||||
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
|
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
|
||||||
@ -199,12 +201,19 @@ void PlayAudio(const uint8_t * data, int size,
|
|||||||
AudioCodecID = CODEC_ID_NONE;
|
AudioCodecID = CODEC_ID_NONE;
|
||||||
NewAudioStream = 0;
|
NewAudioStream = 0;
|
||||||
}
|
}
|
||||||
|
if (SkipAudio) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
// PES header 0x00 0x00 0x01 ID
|
// PES header 0x00 0x00 0x01 ID
|
||||||
// ID 0xBD 0xC0-0xCF
|
// ID 0xBD 0xC0-0xCF
|
||||||
|
|
||||||
if (size < 9) {
|
if (size < 9) {
|
||||||
Error(_("[softhddev] invalid audio packet\n"));
|
Error(_("[softhddev] invalid audio packet\n"));
|
||||||
return;
|
return size;
|
||||||
|
}
|
||||||
|
// Don't overrun audio buffers on replay
|
||||||
|
if (AudioFreeBytes() < 3072 * 8 * 8) { // 8 channels 8 packets
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = data[8]; // header size
|
n = data[8]; // header size
|
||||||
@ -225,11 +234,12 @@ void PlayAudio(const uint8_t * data, int size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osize = size;
|
||||||
data += 9 + n;
|
data += 9 + n;
|
||||||
size -= 9 + n; // skip pes header
|
size -= 9 + n; // skip pes header
|
||||||
if (size <= 0) {
|
if (size <= 0) {
|
||||||
Error(_("[softhddev] invalid audio packet\n"));
|
Error(_("[softhddev] invalid audio packet\n"));
|
||||||
return;
|
return osize;
|
||||||
}
|
}
|
||||||
// Detect audio code
|
// Detect audio code
|
||||||
// MPEG-PS mp2 MPEG1, MPEG2, AC3
|
// MPEG-PS mp2 MPEG1, MPEG2, AC3
|
||||||
@ -271,7 +281,7 @@ void PlayAudio(const uint8_t * data, int size,
|
|||||||
avpkt->size = size;
|
avpkt->size = size;
|
||||||
n = FindAudioSync(avpkt);
|
n = FindAudioSync(avpkt);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
return;
|
return osize;
|
||||||
}
|
}
|
||||||
if (!MyAudioDecoder) {
|
if (!MyAudioDecoder) {
|
||||||
MyAudioDecoder = CodecAudioNewDecoder();
|
MyAudioDecoder = CodecAudioNewDecoder();
|
||||||
@ -286,13 +296,15 @@ void PlayAudio(const uint8_t * data, int size,
|
|||||||
|
|
||||||
// no decoder or codec known
|
// no decoder or codec known
|
||||||
if (!MyAudioDecoder || AudioCodecID == CODEC_ID_NONE) {
|
if (!MyAudioDecoder || AudioCodecID == CODEC_ID_NONE) {
|
||||||
return;
|
return osize;
|
||||||
}
|
}
|
||||||
|
|
||||||
avpkt->data = (void *)data;
|
avpkt->data = (void *)data;
|
||||||
avpkt->size = size;
|
avpkt->size = size;
|
||||||
//memset(avpkt->data + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
//memset(avpkt->data + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
CodecAudioDecode(MyAudioDecoder, avpkt);
|
CodecAudioDecode(MyAudioDecoder, avpkt);
|
||||||
|
|
||||||
|
return osize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -300,6 +312,7 @@ void PlayAudio(const uint8_t * data, int size,
|
|||||||
*/
|
*/
|
||||||
void Mute(void)
|
void Mute(void)
|
||||||
{
|
{
|
||||||
|
SkipAudio = 1;
|
||||||
AudioSetVolume(0);
|
AudioSetVolume(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,6 +493,10 @@ int VideoDecode(void)
|
|||||||
}
|
}
|
||||||
if (VideoClearBuffers) {
|
if (VideoClearBuffers) {
|
||||||
atomic_set(&VideoPacketsFilled, 0);
|
atomic_set(&VideoPacketsFilled, 0);
|
||||||
|
VideoPacketRead = VideoPacketWrite;
|
||||||
|
if (MyVideoDecoder) {
|
||||||
|
CodecVideoFlushBuffers(MyVideoDecoder);
|
||||||
|
}
|
||||||
VideoClearBuffers = 0;
|
VideoClearBuffers = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -751,8 +768,12 @@ void SetPlayMode(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (MyAudioDecoder) {
|
if (MyAudioDecoder) {
|
||||||
|
if (AudioCodecID != CODEC_ID_NONE) {
|
||||||
NewAudioStream = 1;
|
NewAudioStream = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
VideoFreezed = 0;
|
||||||
|
SkipAudio = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -760,9 +781,16 @@ void SetPlayMode(void)
|
|||||||
*/
|
*/
|
||||||
void Clear(void)
|
void Clear(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VideoNextPacket(VideoCodecID); // terminate work
|
||||||
VideoClearBuffers = 1;
|
VideoClearBuffers = 1;
|
||||||
// FIXME: avcodec_flush_buffers
|
// FIXME: avcodec_flush_buffers
|
||||||
// FIXME: flush audio buffers
|
AudioFlushBuffers();
|
||||||
|
|
||||||
|
for (i = 0; VideoClearBuffers && i < 20; ++i) {
|
||||||
|
usleep(1 * 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -771,6 +799,7 @@ void Clear(void)
|
|||||||
void Play(void)
|
void Play(void)
|
||||||
{
|
{
|
||||||
VideoFreezed = 0;
|
VideoFreezed = 0;
|
||||||
|
SkipAudio = 0;
|
||||||
// FIXME: restart audio
|
// FIXME: restart audio
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -781,16 +810,33 @@ void Freeze(void)
|
|||||||
{
|
{
|
||||||
VideoFreezed = 1;
|
VideoFreezed = 1;
|
||||||
// FIXME: freeze audio
|
// FIXME: freeze audio
|
||||||
|
AudioFlushBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Display the given I-frame as a still picture.
|
||||||
|
*/
|
||||||
|
void StillPicture(const uint8_t * data, int size)
|
||||||
|
{
|
||||||
|
// must be a PES start code
|
||||||
|
if (size < 9 || !data || data[0] || data[1] || data[2] != 0x01) {
|
||||||
|
Error(_("[softhddev] invalid PES video packet\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PlayVideo(data, size);
|
||||||
|
PlayVideo(data, size);
|
||||||
|
VideoNextPacket(VideoCodecID); // terminate work
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Poll if device is ready. Called by replay.
|
** Poll if device is ready. Called by replay.
|
||||||
|
**
|
||||||
|
** @param timeout timeout to become ready in ms
|
||||||
*/
|
*/
|
||||||
int Poll(int timeout)
|
int Poll(int timeout)
|
||||||
{
|
{
|
||||||
// buffers are too full
|
// buffers are too full
|
||||||
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) {
|
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) {
|
||||||
Debug(3, "replay: poll %d\n", timeout);
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
// let display thread work
|
// let display thread work
|
||||||
usleep(timeout * 1000);
|
usleep(timeout * 1000);
|
||||||
@ -800,6 +846,22 @@ int Poll(int timeout)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Flush the device output buffers.
|
||||||
|
**
|
||||||
|
** @param timeout timeout to flush in ms
|
||||||
|
*/
|
||||||
|
int Flush(int timeout)
|
||||||
|
{
|
||||||
|
if (atomic_read(&VideoPacketsFilled)) {
|
||||||
|
if (timeout) { // let display thread work
|
||||||
|
usleep(timeout * 1000);
|
||||||
|
}
|
||||||
|
return !atomic_read(&VideoPacketsFilled);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// OSD
|
// OSD
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
///
|
///
|
||||||
/// @file softhddev.h @brief software HD device plugin header file.
|
/// @file softhddev.h @brief software HD device plugin header file.
|
||||||
///
|
///
|
||||||
/// Copyright (c) 2011 by Johns. All Rights Reserved.
|
/// Copyright (c) 2011 - 2012 by Johns. All Rights Reserved.
|
||||||
///
|
///
|
||||||
/// Contributor(s):
|
/// Contributor(s):
|
||||||
///
|
///
|
||||||
@ -36,7 +36,7 @@ extern "C"
|
|||||||
extern void OsdDrawARGB(int, int, int, int, const uint8_t *);
|
extern void OsdDrawARGB(int, int, int, int, const uint8_t *);
|
||||||
|
|
||||||
/// C plugin play audio packet
|
/// C plugin play audio packet
|
||||||
extern void PlayAudio(const uint8_t *, int, uint8_t);
|
extern int PlayAudio(const uint8_t *, int, uint8_t);
|
||||||
/// C plugin mute audio
|
/// C plugin mute audio
|
||||||
extern void Mute(void);
|
extern void Mute(void);
|
||||||
/// C plugin set audio volume
|
/// C plugin set audio volume
|
||||||
@ -55,8 +55,12 @@ extern "C"
|
|||||||
extern void Play(void);
|
extern void Play(void);
|
||||||
/// C plugin sets the device into "freeze frame" mode
|
/// C plugin sets the device into "freeze frame" mode
|
||||||
extern void Freeze(void);
|
extern void Freeze(void);
|
||||||
|
/// C plugin display I-frame as a still picture.
|
||||||
|
extern void StillPicture(const uint8_t *, int);
|
||||||
/// C plugin poll if ready
|
/// C plugin poll if ready
|
||||||
extern int Poll(int);
|
extern int Poll(int);
|
||||||
|
/// C plugin flush output buffers
|
||||||
|
extern int Flush(int);
|
||||||
|
|
||||||
/// C plugin command line help
|
/// C plugin command line help
|
||||||
extern const char *CommandLineHelp(void);
|
extern const char *CommandLineHelp(void);
|
||||||
|
@ -499,9 +499,14 @@ int64_t cSoftHdDevice::GetSTC(void)
|
|||||||
return::VideoGetClock();
|
return::VideoGetClock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSoftHdDevice::TrickSpeed(int Speed)
|
/**
|
||||||
|
** Set trick play speed.
|
||||||
|
**
|
||||||
|
** @param speed trick speed
|
||||||
|
*/
|
||||||
|
void cSoftHdDevice::TrickSpeed(int speed)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, Speed);
|
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSoftHdDevice::Clear(void)
|
void cSoftHdDevice::Clear(void)
|
||||||
@ -533,24 +538,37 @@ void cSoftHdDevice::Mute(void)
|
|||||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||||
|
|
||||||
cDevice::Mute();
|
cDevice::Mute();
|
||||||
|
|
||||||
::Mute();
|
::Mute();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSoftHdDevice::SetVolumeDevice(int volume)
|
void cSoftHdDevice::SetVolumeDevice(int volume)
|
||||||
{
|
{
|
||||||
//dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
|
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
|
||||||
|
|
||||||
::SetVolumeDevice(volume);
|
::SetVolumeDevice(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSoftHdDevice::StillPicture(
|
/**
|
||||||
__attribute__ ((unused)) const uchar * data, __attribute__ ((unused))
|
** Display the given I-frame as a still picture.
|
||||||
int length)
|
*/
|
||||||
|
void cSoftHdDevice::StillPicture(const uchar * data, int length)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||||
|
|
||||||
|
if ( data[0] == 0x47 ) { // ts sync
|
||||||
|
cDevice::StillPicture(data, length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
::StillPicture(data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Check if the device is ready for further action.
|
||||||
|
**
|
||||||
|
** @param poller file handles (unused)
|
||||||
|
** @param timeout_ms timeout in ms to become ready
|
||||||
|
*/
|
||||||
bool cSoftHdDevice::Poll(
|
bool cSoftHdDevice::Poll(
|
||||||
__attribute__ ((unused)) cPoller & poller, int timeout_ms)
|
__attribute__ ((unused)) cPoller & poller, int timeout_ms)
|
||||||
{
|
{
|
||||||
@ -559,11 +577,16 @@ bool cSoftHdDevice::Poll(
|
|||||||
return::Poll(timeout_ms);
|
return::Poll(timeout_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Flush the device output buffers.
|
||||||
|
**
|
||||||
|
** @param timeout_ms timeout in ms to become ready
|
||||||
|
*/
|
||||||
bool cSoftHdDevice::Flush(int timeout_ms)
|
bool cSoftHdDevice::Flush(int timeout_ms)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s: %d ms\n", __FUNCTION__, timeout_ms);
|
dsyslog("[softhddev]%s: %d ms\n", __FUNCTION__, timeout_ms);
|
||||||
|
|
||||||
return true;
|
return::Flush(timeout_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -580,13 +603,14 @@ void cSoftHdDevice::GetOsdSize(int &width, int &height, double &pixel_aspect)
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Play a audio packet.
|
||||||
|
*/
|
||||||
int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id)
|
int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id)
|
||||||
{
|
{
|
||||||
//dsyslog("[softhddev]%s: %p %p %d %d\n", __FUNCTION__, this, data, length, id);
|
//dsyslog("[softhddev]%s: %p %p %d %d\n", __FUNCTION__, this, data, length, id);
|
||||||
|
|
||||||
::PlayAudio(data, length, id);
|
return::PlayAudio(data, length, id);
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSoftHdDevice::SetAudioTrackDevice(
|
void cSoftHdDevice::SetAudioTrackDevice(
|
||||||
|
15
video.c
15
video.c
@ -6245,6 +6245,7 @@ enum PixelFormat Video_get_format(VideoHwDecoder * decoder,
|
|||||||
static void VideoSetPts(int64_t * pts_p, int interlaced, const AVFrame * frame)
|
static void VideoSetPts(int64_t * pts_p, int interlaced, const AVFrame * frame)
|
||||||
{
|
{
|
||||||
int64_t pts;
|
int64_t pts;
|
||||||
|
int64_t delta;
|
||||||
|
|
||||||
// update video clock
|
// update video clock
|
||||||
if ((uint64_t) * pts_p != AV_NOPTS_VALUE) {
|
if ((uint64_t) * pts_p != AV_NOPTS_VALUE) {
|
||||||
@ -6259,14 +6260,16 @@ static void VideoSetPts(int64_t * pts_p, int interlaced, const AVFrame * frame)
|
|||||||
if (!pts) {
|
if (!pts) {
|
||||||
pts = AV_NOPTS_VALUE;
|
pts = AV_NOPTS_VALUE;
|
||||||
}
|
}
|
||||||
// build a monotonic pts
|
|
||||||
if ((uint64_t) * pts_p != AV_NOPTS_VALUE) {
|
|
||||||
if (pts - *pts_p < -10 * 90) {
|
|
||||||
pts = AV_NOPTS_VALUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// libav: sets only pkt_dts which can be 0
|
// libav: sets only pkt_dts which can be 0
|
||||||
if ((uint64_t) pts != AV_NOPTS_VALUE) {
|
if ((uint64_t) pts != AV_NOPTS_VALUE) {
|
||||||
|
// build a monotonic pts
|
||||||
|
if ((uint64_t) * pts_p != AV_NOPTS_VALUE) {
|
||||||
|
delta = pts - *pts_p;
|
||||||
|
// ignore negative jumps
|
||||||
|
if (delta > -300 * 90 && delta < -15 * 90) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (*pts_p != pts) {
|
if (*pts_p != pts) {
|
||||||
Debug(3,
|
Debug(3,
|
||||||
"video: %#012" PRIx64 "->%#012" PRIx64 " %4" PRId64 " pts\n",
|
"video: %#012" PRIx64 "->%#012" PRIx64 " %4" PRId64 " pts\n",
|
||||||
|
Loading…
Reference in New Issue
Block a user