New audio PES handling.

New easier and more flexible audio PES packet parser, which includes own
codec parser.
Removed av_parser use.
Reduced audio buffer time, faster channel switch.
New audio transport stream parser (not enabled as default).
This commit is contained in:
Johns 2012-02-21 20:55:28 +01:00
parent 1f232db5b4
commit 5d8dea1b6b
12 changed files with 1302 additions and 420 deletions

View File

@ -1,6 +1,7 @@
User johns User johns
Date: Date:
New audio PES packet parser.
Fix bug: Grabbing a JPG image fails while suspended. Fix bug: Grabbing a JPG image fails while suspended.
Add support for hot keys. Add support for hot keys.
Add support to use characters input in edit mode. Add support to use characters input in edit mode.

View File

@ -19,8 +19,9 @@ GIT_REV = $(shell git describe --always 2>/dev/null)
### Configuration (edit this for your needs) ### Configuration (edit this for your needs)
CONFIG := #-DDEBUG CONFIG := #-DDEBUG
CONFIG += -DAV_INFO CONFIG += -DAV_INFO # debug a/v sync
#CONFIG += -DHAVE_PTHREAD_NAME #CONFIG += -DHAVE_PTHREAD_NAME # supports new pthread_setname_np
#CONFIG += -DUSE_TS_AUDIO # build new ts audio parser
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU") CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI") CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA") CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
@ -66,7 +67,7 @@ DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' \
$(if $(GIT_REV), -DGIT_REV='"$(GIT_REV)"') $(if $(GIT_REV), -DGIT_REV='"$(GIT_REV)"')
_CFLAGS = $(DEFINES) $(INCLUDES) \ _CFLAGS = $(DEFINES) $(INCLUDES) \
$(shell pkg-config --cflags libavcodec libavformat) \ $(shell pkg-config --cflags libavcodec) \
`pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\ `pkg-config --cflags x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\ xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
`pkg-config --cflags gl glu` \ `pkg-config --cflags gl glu` \
@ -82,7 +83,7 @@ override CXXFLAGS += $(_CFLAGS)
override CFLAGS += $(_CFLAGS) override CFLAGS += $(_CFLAGS)
LIBS += -lrt \ LIBS += -lrt \
$(shell pkg-config --libs libavcodec libavformat) \ $(shell pkg-config --libs libavcodec) \
`pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\ `pkg-config --libs x11 x11-xcb xcb xcb-xv xcb-shm xcb-dpms xcb-atom\
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\ xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
`pkg-config --libs gl glu` \ `pkg-config --libs gl glu` \

9
Todo
View File

@ -26,6 +26,8 @@ missing:
Option deinterlace off / deinterlace force! Option deinterlace off / deinterlace force!
ColorSpace aren't configurable with the gui. ColorSpace aren't configurable with the gui.
Inverse telecine isn't configurable with the gui. Inverse telecine isn't configurable with the gui.
Replay of old vdr 1.6 recordings.
svdrp support for hot-keys.
crash: crash:
AudioPlayHandlerThread -> pthread_cond_wait AudioPlayHandlerThread -> pthread_cond_wait
@ -99,8 +101,11 @@ HDMI/SPDIF Passthrough:
only AC-3 written only AC-3 written
playback of recording playback of recording
pause is not reset, when replay exit pause is not reset, when replay exit (fixed?)
replay/pause need 100% cpu replay/pause need 100% cpu (fixed?)
plugins:
mp3 plugin needs 100% cpu (OSD updates?)
setup: setup:
Setup of decoder type. Setup of decoder type.

101
audio.c
View File

@ -141,7 +141,7 @@ static unsigned AudioSampleRate; ///< audio sample rate in hz
static unsigned AudioChannels; ///< number of audio channels static unsigned AudioChannels; ///< number of audio channels
static const int AudioBytesProSample = 2; ///< number of bytes per sample static const int AudioBytesProSample = 2; ///< number of bytes per sample
static int64_t AudioPTS; ///< audio pts clock static int64_t AudioPTS; ///< audio pts clock
static const int AudioBufferTime = 350; ///< audio buffer time in ms static int AudioBufferTime = 216; ///< audio buffer time in ms
#ifdef USE_AUDIO_THREAD #ifdef USE_AUDIO_THREAD
static pthread_t AudioThread; ///< audio play thread static pthread_t AudioThread; ///< audio play thread
@ -151,7 +151,8 @@ static pthread_cond_t AudioStartCond; ///< condition variable
static const int AudioThread; ///< dummy audio thread static const int AudioThread; ///< dummy audio thread
#endif #endif
extern int VideoAudioDelay; /// import audio/video delay extern int VideoAudioDelay; ///< import audio/video delay
extern int VideoGetBuffers(void); ///< Get number of input buffers.
#ifdef USE_AUDIORING #ifdef USE_AUDIORING
@ -297,7 +298,17 @@ static int AlsaAddToRingbuffer(const void *samples, int count)
} }
if (!AudioRunning) { if (!AudioRunning) {
if (AlsaStartThreshold < RingBufferUsedBytes(AlsaRingBuffer)) { Debug(3, "audio/alsa: start %zd ms %d\n",
(RingBufferUsedBytes(AlsaRingBuffer) * 1000)
/ (AudioSampleRate * AudioChannels * AudioBytesProSample),
VideoGetBuffers());
// forced start
if (AlsaStartThreshold * 2 < RingBufferUsedBytes(AlsaRingBuffer)) {
return 1;
}
// enough video + audio buffered
if (VideoGetBuffers() > 1
&& AlsaStartThreshold < RingBufferUsedBytes(AlsaRingBuffer)) {
// restart play-back // restart play-back
return 1; return 1;
} }
@ -654,7 +665,8 @@ static void AlsaThread(void)
} }
state = snd_pcm_state(AlsaPCMHandle); state = snd_pcm_state(AlsaPCMHandle);
if (state != SND_PCM_STATE_RUNNING) { if (state != SND_PCM_STATE_RUNNING) {
Debug(3, "audio/alsa: stopping play\n"); Debug(3, "audio/alsa: stopping play '%s'\n",
snd_pcm_state_name(state));
break; break;
} }
pthread_yield(); pthread_yield();
@ -720,12 +732,11 @@ static snd_pcm_t *AlsaOpenPCM(int use_ac3)
// &&|| hell // &&|| hell
if (!(use_ac3 && ((device = AudioAC3Device) if (!(use_ac3 && ((device = AudioAC3Device)
|| (device = getenv("ALSA_AC3_DEVICE")) || (device = getenv("ALSA_AC3_DEVICE"))))
|| (device = getenv("ALSA_PASSTHROUGH_DEVICE"))))
&& !(device = AudioPCMDevice) && !(device = getenv("ALSA_DEVICE"))) { && !(device = AudioPCMDevice) && !(device = getenv("ALSA_DEVICE"))) {
device = "default"; device = "default";
} }
Debug(3, "audio/alsa: &&|| hell '%s'\n", device); Info(_("audio/alsa: using device '%s'\n"), device);
// open none blocking; if device is already used, we don't want wait // open none blocking; if device is already used, we don't want wait
if ((err = if ((err =
@ -752,7 +763,8 @@ static void AlsaInitPCM(void)
snd_pcm_t *handle; snd_pcm_t *handle;
snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_t *hw_params;
int err; int err;
snd_pcm_uframes_t buffer_size;
//snd_pcm_uframes_t buffer_size;
if (!(handle = AlsaOpenPCM(0))) { if (!(handle = AlsaOpenPCM(0))) {
return; return;
@ -767,8 +779,9 @@ static void AlsaInitPCM(void)
} }
AlsaCanPause = snd_pcm_hw_params_can_pause(hw_params); AlsaCanPause = snd_pcm_hw_params_can_pause(hw_params);
Info(_("audio/alsa: supports pause: %s\n"), 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); // needs audio setup
Info(_("audio/alsa: max buffer size %lu\n"), buffer_size); //snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size);
//Info(_("audio/alsa: max buffer size %lu\n"), buffer_size);
AlsaPCMHandle = handle; AlsaPCMHandle = handle;
} }
@ -941,7 +954,7 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
snd_pcm_set_params(AlsaPCMHandle, SND_PCM_FORMAT_S16, snd_pcm_set_params(AlsaPCMHandle, SND_PCM_FORMAT_S16,
AlsaUseMmap ? SND_PCM_ACCESS_MMAP_INTERLEAVED : AlsaUseMmap ? SND_PCM_ACCESS_MMAP_INTERLEAVED :
SND_PCM_ACCESS_RW_INTERLEAVED, *channels, *freq, 1, SND_PCM_ACCESS_RW_INTERLEAVED, *channels, *freq, 1,
125 * 1000))) { 96 * 1000))) {
Error(_("audio/alsa: set params error: %s\n"), snd_strerror(err)); Error(_("audio/alsa: set params error: %s\n"), snd_strerror(err));
/* /*
@ -1053,7 +1066,7 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
// FIXME: use hw_params for buffer_size period_size // FIXME: use hw_params for buffer_size period_size
#endif #endif
#if 1 #if 0
if (0) { // no underruns allowed, play silence if (0) { // no underruns allowed, play silence
snd_pcm_sw_params_t *sw_params; snd_pcm_sw_params_t *sw_params;
snd_pcm_uframes_t boundary; snd_pcm_uframes_t boundary;
@ -1091,16 +1104,21 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
// update buffer // update buffer
snd_pcm_get_params(AlsaPCMHandle, &buffer_size, &period_size); snd_pcm_get_params(AlsaPCMHandle, &buffer_size, &period_size);
Info(_("audio/alsa: buffer size %lu, period size %lu\n"), buffer_size, Info(_("audio/alsa: buffer size %lu %lums, period size %lu %lums\n"),
period_size); buffer_size, snd_pcm_frames_to_bytes(AlsaPCMHandle,
buffer_size) * 1000 / (AudioSampleRate * AudioChannels *
AudioBytesProSample), period_size,
snd_pcm_frames_to_bytes(AlsaPCMHandle,
period_size) * 1000 / (AudioSampleRate * AudioChannels *
AudioBytesProSample));
Debug(3, "audio/alsa: state %s\n", Debug(3, "audio/alsa: state %s\n",
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle))); snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
AlsaStartThreshold = snd_pcm_frames_to_bytes(AlsaPCMHandle, period_size); AlsaStartThreshold = snd_pcm_frames_to_bytes(AlsaPCMHandle, period_size);
// buffer time/delay in ms // buffer time/delay in ms
delay = AudioBufferTime; delay = AudioBufferTime;
if (VideoAudioDelay > -100) { if (VideoAudioDelay > 0) {
delay += 100 + VideoAudioDelay / 90; delay += VideoAudioDelay / 90;
} }
if (AlsaStartThreshold < if (AlsaStartThreshold <
(*freq * *channels * AudioBytesProSample * delay) / 1000U) { (*freq * *channels * AudioBytesProSample * delay) / 1000U) {
@ -1284,7 +1302,17 @@ static int OssAddToRingbuffer(const void *samples, int count)
} }
if (!AudioRunning) { if (!AudioRunning) {
if (OssStartThreshold < RingBufferUsedBytes(OssRingBuffer)) { Debug(3, "audio/oss: start %zd ms %d\n",
(RingBufferUsedBytes(OssRingBuffer) * 1000)
/ (AudioSampleRate * AudioChannels * AudioBytesProSample),
VideoGetBuffers());
// forced start
if (OssStartThreshold * 2 < RingBufferUsedBytes(OssRingBuffer)) {
return 1;
}
// enough video + audio buffered
if (VideoGetBuffers() > 1
&& OssStartThreshold < RingBufferUsedBytes(OssRingBuffer)) {
// restart play-back // restart play-back
return 1; return 1;
} }
@ -1522,7 +1550,7 @@ static int OssOpenPCM(int use_ac3)
&& !(device = AudioPCMDevice) && !(device = getenv("OSS_AUDIODEV"))) { && !(device = AudioPCMDevice) && !(device = getenv("OSS_AUDIODEV"))) {
device = "/dev/dsp"; device = "/dev/dsp";
} }
Debug(3, "audio/oss: &&|| hell '%s'\n", device); Info(_("audio/oss: using device '%s'\n"), device);
if ((fildes = open(device, O_WRONLY)) < 0) { if ((fildes = open(device, O_WRONLY)) < 0) {
Error(_("audio/oss: can't open dsp device '%s': %s\n"), device, Error(_("audio/oss: can't open dsp device '%s': %s\n"), device,
@ -1774,8 +1802,8 @@ static int OssSetup(int *freq, int *channels, int use_ac3)
OssStartThreshold = bi.bytes + tmp; OssStartThreshold = bi.bytes + tmp;
// buffer time/delay in ms // buffer time/delay in ms
delay = AudioBufferTime; delay = AudioBufferTime;
if (VideoAudioDelay > -100) { if (VideoAudioDelay > 0) {
delay += 100 + VideoAudioDelay / 90; delay += VideoAudioDelay / 90;
} }
if (OssStartThreshold < if (OssStartThreshold <
(*freq * *channels * AudioBytesProSample * delay) / 1000U) { (*freq * *channels * AudioBytesProSample * delay) / 1000U) {
@ -1964,6 +1992,9 @@ static void *AudioPlayHandlerThread(void *dummy)
pthread_cond_wait(&AudioStartCond, &AudioMutex); pthread_cond_wait(&AudioStartCond, &AudioMutex);
// cond_wait can return, without signal! // cond_wait can return, without signal!
} while (!AudioRunning); } while (!AudioRunning);
Debug(3, "audio/alsa: ----> %zd ms\n",
(RingBufferUsedBytes(AlsaRingBuffer) * 1000)
/ (AudioSampleRate * AudioChannels * AudioBytesProSample));
pthread_mutex_unlock(&AudioMutex); pthread_mutex_unlock(&AudioMutex);
#ifdef USE_AUDIORING #ifdef USE_AUDIORING
@ -2064,6 +2095,21 @@ static const AudioModule *AudioModules[] = {
*/ */
void AudioEnqueue(const void *samples, int count) void AudioEnqueue(const void *samples, int count)
{ {
if (0) {
static uint32_t last;
static uint32_t tick;
static uint32_t max = 110;
uint64_t delay;
delay = AudioGetDelay();
tick = GetMsTicks();
if ((last && tick - last > max) || delay < 80 * 90) {
//max = tick - last;
Debug(3, "audio: packet delta %d %lu\n", tick - last, delay / 90);
}
last = tick;
}
AudioUsedModule->Enqueue(samples, count); AudioUsedModule->Enqueue(samples, count);
} }
@ -2183,7 +2229,7 @@ int AudioSetup(int *freq, int *channels, int use_ac3)
void AudioPlay(void) void AudioPlay(void)
{ {
if (!AudioPaused) { if (!AudioPaused) {
Warning("audio: not paused, check the code\n"); Debug(3, "audio: not paused, check the code\n");
return; return;
} }
Debug(3, "audio: resumed\n"); Debug(3, "audio: resumed\n");
@ -2197,13 +2243,24 @@ void AudioPlay(void)
void AudioPause(void) void AudioPause(void)
{ {
if (AudioPaused) { if (AudioPaused) {
Warning("audio: already paused, check the code\n"); Debug(3, "audio: already paused, check the code\n");
return; return;
} }
Debug(3, "audio: paused\n"); Debug(3, "audio: paused\n");
AudioPaused = 1; AudioPaused = 1;
} }
/**
** Set audio buffer time.
*/
void AudioSetBufferTime(int delay)
{
if (!delay) {
delay = 216;
}
AudioBufferTime = delay;
}
/** /**
** Set pcm audio device. ** Set pcm audio device.
** **

View File

@ -42,6 +42,8 @@ extern int AudioSetup(int *, int *, int); ///< setup audio output
extern void AudioPlay(void); ///< play audio extern void AudioPlay(void); ///< play audio
extern void AudioPause(void); ///< pause audio extern void AudioPause(void); ///< pause audio
extern void AudioSetBufferTime(int); ///< set audio buffer time
extern void AudioSetDevice(const char *); ///< set PCM audio device extern void AudioSetDevice(const char *); ///< set PCM audio device
extern void AudioSetDeviceAC3(const char *); ///< set pass-through device extern void AudioSetDeviceAC3(const char *); ///< set pass-through device
extern void AudioSetChannel(const char *); ///< set mixer channel extern void AudioSetChannel(const char *); ///< set mixer channel

248
codec.c
View File

@ -33,7 +33,7 @@
/** /**
** use av_parser to support insane dvb audio streams. ** use av_parser to support insane dvb audio streams.
*/ */
#define USE_AVPARSER #define noUSE_AVPARSER
/// compile with passthrough support (experimental) /// compile with passthrough support (experimental)
#define USE_PASSTHROUGH #define USE_PASSTHROUGH
@ -603,8 +603,10 @@ struct _audio_decoder_
AVCodec *AudioCodec; ///< audio codec AVCodec *AudioCodec; ///< audio codec
AVCodecContext *AudioCtx; ///< audio codec context AVCodecContext *AudioCtx; ///< audio codec context
#ifdef USE_AVPARSER
/// audio parser to support insane dvb streaks /// audio parser to support insane dvb streaks
AVCodecParserContext *AudioParser; AVCodecParserContext *AudioParser;
#endif
int PassthroughAC3; ///< current ac-3 pass-through int PassthroughAC3; ///< current ac-3 pass-through
int SampleRate; ///< current stream sample rate int SampleRate; ///< current stream sample rate
int Channels; ///< current stream channels int Channels; ///< current stream channels
@ -697,10 +699,12 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name,
// we do not send complete frames // we do not send complete frames
audio_decoder->AudioCtx->flags |= CODEC_FLAG_TRUNCATED; audio_decoder->AudioCtx->flags |= CODEC_FLAG_TRUNCATED;
} }
#ifdef USE_AVPARSER
if (!(audio_decoder->AudioParser = if (!(audio_decoder->AudioParser =
av_parser_init(audio_decoder->AudioCtx->codec_id))) { av_parser_init(audio_decoder->AudioCtx->codec_id))) {
Fatal(_("codec: can't init audio parser\n")); Fatal(_("codec: can't init audio parser\n"));
} }
#endif
audio_decoder->SampleRate = 0; audio_decoder->SampleRate = 0;
audio_decoder->Channels = 0; audio_decoder->Channels = 0;
audio_decoder->HwSampleRate = 0; audio_decoder->HwSampleRate = 0;
@ -719,10 +723,12 @@ void CodecAudioClose(AudioDecoder * audio_decoder)
audio_resample_close(audio_decoder->ReSample); audio_resample_close(audio_decoder->ReSample);
audio_decoder->ReSample = NULL; audio_decoder->ReSample = NULL;
} }
#ifdef USE_AVPARSER
if (audio_decoder->AudioParser) { if (audio_decoder->AudioParser) {
av_parser_close(audio_decoder->AudioParser); av_parser_close(audio_decoder->AudioParser);
audio_decoder->AudioParser = NULL; audio_decoder->AudioParser = NULL;
} }
#endif
if (audio_decoder->AudioCtx) { if (audio_decoder->AudioCtx) {
pthread_mutex_lock(&CodecLockMutex); pthread_mutex_lock(&CodecLockMutex);
avcodec_close(audio_decoder->AudioCtx); avcodec_close(audio_decoder->AudioCtx);
@ -808,7 +814,7 @@ static void CodecReorderAudioFrame(int16_t * buf, int size, int channels)
** @param audio_decoder audio decoder data ** @param audio_decoder audio decoder data
** @param avpkt audio packet ** @param avpkt audio packet
*/ */
void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt) void CodecAudioDecodeOld(AudioDecoder * audio_decoder, const AVPacket * avpkt)
{ {
int16_t buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 + int16_t buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 +
FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16))); FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16)));
@ -844,8 +850,8 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
av_init_packet(dpkt); av_init_packet(dpkt);
n = av_parser_parse2(audio_decoder->AudioParser, audio_ctx, n = av_parser_parse2(audio_decoder->AudioParser, audio_ctx,
&dpkt->data, &dpkt->size, spkt->data + index, spkt->size - index, &dpkt->data, &dpkt->size, spkt->data + index, spkt->size - index,
!index ? (uint64_t) spkt->pts : AV_NOPTS_VALUE, !index ? spkt->pts : (int64_t) AV_NOPTS_VALUE,
!index ? (uint64_t) spkt->dts : AV_NOPTS_VALUE, -1); !index ? spkt->dts : (int64_t) AV_NOPTS_VALUE, -1);
// FIXME: make this a function for both #ifdef cases // FIXME: make this a function for both #ifdef cases
if (dpkt->size) { if (dpkt->size) {
@ -871,7 +877,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
#else #else
#endif #endif
// Update audio clock // Update audio clock
if ((uint64_t) dpkt->pts != AV_NOPTS_VALUE) { if (dpkt->pts != (int64_t) AV_NOPTS_VALUE) {
AudioSetClock(dpkt->pts); AudioSetClock(dpkt->pts);
} }
// FIXME: must first play remainings bytes, than change and play new. // FIXME: must first play remainings bytes, than change and play new.
@ -1059,6 +1065,8 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
#else #else
#endif
/** /**
** Decode an audio packet. ** Decode an audio packet.
** **
@ -1074,62 +1082,206 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
AVCodecContext *audio_ctx; AVCodecContext *audio_ctx;
int index; int index;
//#define spkt avpkt
#if 1
AVPacket spkt[1];
// av_new_packet reserves FF_INPUT_BUFFER_PADDING_SIZE and clears it
if (av_new_packet(spkt, avpkt->size)) {
Error(_("codec: out of memory\n"));
return;
}
memcpy(spkt->data, avpkt->data, avpkt->size);
spkt->pts = avpkt->pts;
spkt->dts = avpkt->dts;
#endif
audio_ctx = audio_decoder->AudioCtx; audio_ctx = audio_decoder->AudioCtx;
index = 0; index = 0;
while (spkt->size > index) { while (avpkt->size > index) {
int n; int l;
int buf_sz; int buf_sz;
AVPacket dpkt[1];
av_init_packet(dpkt);
dpkt->data = spkt->data + index;
dpkt->size = spkt->size - index;
buf_sz = sizeof(buf); buf_sz = sizeof(buf);
n = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt); l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, (AVPacket *)avpkt);
if (n < 0) { // no audio frame could be decompressed if (l == AVERROR(EAGAIN)) {
Error(_("codec: latm\n"));
break;
}
if (l < 0) { // no audio frame could be decompressed
Error(_("codec: error audio data at %d\n"), index); Error(_("codec: error audio data at %d\n"), index);
break; break;
} }
#ifdef DEBUG
Debug(4, "codec/audio: -> %d\n", buf_sz);
if ((unsigned)buf_sz > sizeof(buf)) {
abort();
}
#endif
#ifdef notyetFF_API_OLD_DECODE_AUDIO #ifdef notyetFF_API_OLD_DECODE_AUDIO
// FIXME: ffmpeg git comeing // FIXME: ffmpeg git comeing
int got_frame; int got_frame;
avcodec_decode_audio4(audio_ctx, frame, &got_frame, dpkt); avcodec_decode_audio4(audio_ctx, frame, &got_frame, avpkt);
#else #else
#endif #endif
// FIXME: see above, old code removed // Update audio clock
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
AudioSetClock(avpkt->pts);
}
// FIXME: must first play remainings bytes, than change and play new.
if (audio_decoder->PassthroughAC3 != CodecPassthroughAC3
|| audio_decoder->SampleRate != audio_ctx->sample_rate
|| audio_decoder->Channels != audio_ctx->channels) {
int err;
int isAC3;
index += n; audio_decoder->PassthroughAC3 = CodecPassthroughAC3;
// FIXME: use swr_convert from swresample (only in ffmpeg!)
// FIXME: tell ac3 decoder to use downmix
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;
// SPDIF/HDMI passthrough
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
audio_decoder->HwChannels = 2;
isAC3 = 1;
} else {
audio_decoder->HwChannels = audio_ctx->channels;
isAC3 = 0;
}
// channels not support?
if ((err =
AudioSetup(&audio_decoder->HwSampleRate,
&audio_decoder->HwChannels, isAC3))) {
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 {
Debug(3, "codec/audio: audio setup error\n");
// FIXME: handle errors
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_decoder->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);
CodecReorderAudioFrame(outbuf, outlen,
audio_decoder->HwChannels);
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
// avpkt is the original data
buf_sz = 6144;
if (buf_sz < avpkt->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 | (avpkt->data[5] & 0x07) << 8);
buf[3] = htole16(avpkt->size * 8);
swab(avpkt->data, buf + 4, avpkt->size);
memset(buf + 4 + avpkt->size / 2, 0,
buf_sz - 8 - avpkt->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 (avpkt->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] = (avpkt->size * 8);
buf[7] = (avpkt->size * 8) >> 8;
//buf[8] = 0x0B;
//buf[9] = 0x77;
//printf("%x %x\n", avpkt->data[0],avpkt->data[1]);
// swab?
memcpy(buf + 8, avpkt->data, avpkt->size);
memset(buf + 8 + avpkt->size, 0, buf_sz - 8 - avpkt->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
CodecReorderAudioFrame(buf, buf_sz, audio_decoder->HwChannels);
AudioEnqueue(buf, buf_sz);
}
}
if (avpkt->size > l) {
Error(_("codec: error more than one frame data\n"));
}
index += l;
} }
#if 1
// or av_free_packet, make no difference here
av_destruct_packet(spkt);
#endif
} }
#endif
/** /**
** Flush the audio decoder. ** Flush the audio decoder.
** **
@ -1137,7 +1289,17 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
*/ */
void CodecAudioFlushBuffers(AudioDecoder * decoder) void CodecAudioFlushBuffers(AudioDecoder * decoder)
{ {
#ifdef USE_AVPARSER
// FIXME: reset audio parser // FIXME: reset audio parser
if (decoder->AudioParser) {
av_parser_close(decoder->AudioParser);
decoder->AudioParser = NULL;
if (!(decoder->AudioParser =
av_parser_init(decoder->AudioCtx->codec_id))) {
Fatal(_("codec: can't init audio parser\n"));
}
}
#endif
avcodec_flush_buffers(decoder->AudioCtx); avcodec_flush_buffers(decoder->AudioCtx);
} }

View File

@ -67,6 +67,9 @@ 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.
extern void CodecAudioDecodeOld(AudioDecoder *, const AVPacket *);
/// Decode an audio packet. /// Decode an audio packet.
extern void CodecAudioDecode(AudioDecoder *, const AVPacket *); extern void CodecAudioDecode(AudioDecoder *, const AVPacket *);

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,8 @@ extern "C"
/// C plugin play audio packet /// C plugin play audio packet
extern int PlayAudio(const uint8_t *, int, uint8_t); extern int PlayAudio(const uint8_t *, int, uint8_t);
/// C plugin play TS audio packet
extern int PlayTsAudio(const uint8_t *, int);
/// C plugin set audio volume /// C plugin set audio volume
extern void SetVolumeDevice(int); extern void SetVolumeDevice(int);

View File

@ -835,9 +835,11 @@ class cSoftHdDevice:public cDevice
virtual void GetVideoSize(int &, int &, double &); virtual void GetVideoSize(int &, int &, double &);
virtual void GetOsdSize(int &, int &, double &); virtual void GetOsdSize(int &, int &, double &);
virtual int PlayVideo(const uchar *, int); virtual int PlayVideo(const uchar *, int);
#ifndef xxUSE_TS_AUDIO
virtual int PlayAudio(const uchar *, int, uchar);
#endif
//virtual int PlayTsVideo(const uchar *, int); //virtual int PlayTsVideo(const uchar *, int);
#ifndef USE_AUDIO_THREAD // FIXME: testing none threaded #if !defined(USE_AUDIO_THREAD) || defined(USE_TS_AUDIO)
virtual int PlayTsAudio(const uchar *, int); virtual int PlayTsAudio(const uchar *, int);
#endif #endif
virtual void SetAudioChannelDevice(int); virtual void SetAudioChannelDevice(int);
@ -845,7 +847,6 @@ class cSoftHdDevice:public cDevice
virtual void SetDigitalAudioDevice(bool); virtual void SetDigitalAudioDevice(bool);
virtual void SetAudioTrackDevice(eTrackType); virtual void SetAudioTrackDevice(eTrackType);
virtual void SetVolumeDevice(int); virtual void SetVolumeDevice(int);
virtual int PlayAudio(const uchar *, int, uchar);
// Image Grab facilities // Image Grab facilities
@ -1066,8 +1067,8 @@ bool cSoftHdDevice::Flush(int timeout_ms)
** Sets the video display format to the given one (only useful if this ** Sets the video display format to the given one (only useful if this
** device has an MPEG decoder). ** device has an MPEG decoder).
*/ */
void cSoftHdDevice:: void cSoftHdDevice:: SetVideoDisplayFormat(eVideoDisplayFormat
SetVideoDisplayFormat(eVideoDisplayFormat video_display_format) video_display_format)
{ {
static int last = -1; static int last = -1;
@ -1124,8 +1125,14 @@ void cSoftHdDevice::GetOsdSize(int &width, int &height, double &pixel_aspect)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#ifndef xxUSE_TS_AUDIO
/** /**
** Play a audio packet. ** Play a audio packet.
**
** @param data exactly one complete PES packet (which is incomplete)
** @param length length of PES packet
** @param id type of audio data this packet holds
*/ */
int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id) int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id)
{ {
@ -1134,6 +1141,8 @@ int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id)
return::PlayAudio(data, length, id); return::PlayAudio(data, length, id);
} }
#endif
void cSoftHdDevice::SetAudioTrackDevice( void cSoftHdDevice::SetAudioTrackDevice(
__attribute__ ((unused)) eTrackType type) __attribute__ ((unused)) eTrackType type)
{ {
@ -1173,6 +1182,9 @@ void cSoftHdDevice::SetVolumeDevice(int volume)
/** /**
** Play a video packet. ** Play a video packet.
**
** @param data exactly one complete PES packet (which is incomplete)
** @param length length of PES packet
*/ */
int cSoftHdDevice::PlayVideo(const uchar * data, int length) int cSoftHdDevice::PlayVideo(const uchar * data, int length)
{ {

47
video.c
View File

@ -329,7 +329,6 @@ static xcb_atom_t NetWmState; ///< wm-state message atom
static xcb_atom_t NetWmStateFullscreen; ///< fullscreen wm-state message atom static xcb_atom_t NetWmStateFullscreen; ///< fullscreen wm-state message atom
extern uint32_t VideoSwitch; ///< ticks for channel switch extern uint32_t VideoSwitch; ///< ticks for channel switch
extern atomic_t VideoPacketsFilled; ///< how many of the buffer is used
#ifdef USE_VIDEO_THREAD #ifdef USE_VIDEO_THREAD
@ -396,19 +395,19 @@ static void VideoSetPts(int64_t * pts_p, int interlaced, const AVFrame * frame)
int64_t pts; int64_t pts;
// update video clock // update video clock
if ((uint64_t) * pts_p != AV_NOPTS_VALUE) { if (*pts_p != (int64_t) AV_NOPTS_VALUE) {
*pts_p += interlaced ? 40 * 90 : 20 * 90; *pts_p += interlaced ? 40 * 90 : 20 * 90;
} }
//pts = frame->best_effort_timestamp; //pts = frame->best_effort_timestamp;
pts = frame->pkt_pts; pts = frame->pkt_pts;
if ((uint64_t) pts == AV_NOPTS_VALUE || !pts) { if (pts == (int64_t) AV_NOPTS_VALUE || !pts) {
// libav: 0.8pre didn't set pts // libav: 0.8pre didn't set pts
pts = frame->pkt_dts; pts = frame->pkt_dts;
} }
// libav: sets only pkt_dts which can be 0 // libav: sets only pkt_dts which can be 0
if (pts && (uint64_t) pts != AV_NOPTS_VALUE) { if (pts && pts != (int64_t) AV_NOPTS_VALUE) {
// build a monotonic pts // build a monotonic pts
if ((uint64_t) * pts_p != AV_NOPTS_VALUE) { if (*pts_p != (int64_t) AV_NOPTS_VALUE) {
int64_t delta; int64_t delta;
delta = pts - *pts_p; delta = pts - *pts_p;
@ -4224,7 +4223,7 @@ static void VaapiAdvanceFrame(void)
Warning(_ Warning(_
("video: display buffer empty, duping frame (%d/%d) %d\n"), ("video: display buffer empty, duping frame (%d/%d) %d\n"),
decoder->FramesDuped, decoder->FrameCounter, decoder->FramesDuped, decoder->FrameCounter,
atomic_read(&VideoPacketsFilled)); VideoGetBuffers());
} }
last_warned_frame = decoder->FrameCounter; last_warned_frame = decoder->FrameCounter;
if (!(decoder->FramesDisplayed % 300)) { if (!(decoder->FramesDisplayed % 300)) {
@ -4358,10 +4357,10 @@ static void VaapiSyncDisplayFrame(VaapiDecoder * decoder)
// FIXME: audio not known assume 333ms delay // FIXME: audio not known assume 333ms delay
if (decoder->DupNextFrame) { if (decoder->DupNextFrame) {
++decoder->FramesDuped;
decoder->DupNextFrame--; decoder->DupNextFrame--;
} else if ((uint64_t) audio_clock != AV_NOPTS_VALUE ++decoder->FramesDuped;
&& (uint64_t) video_clock != AV_NOPTS_VALUE) { } else if (audio_clock != (int64_t) AV_NOPTS_VALUE
&& video_clock != (int64_t) AV_NOPTS_VALUE) {
// both clocks are known // both clocks are known
if (abs(video_clock - audio_clock) > 5000 * 90) { if (abs(video_clock - audio_clock) > 5000 * 90) {
@ -4377,6 +4376,12 @@ static void VaapiSyncDisplayFrame(VaapiDecoder * decoder)
Debug(3, "video: speed up video\n"); Debug(3, "video: speed up video\n");
decoder->DropNextFrame = 1; decoder->DropNextFrame = 1;
} }
} else if (audio_clock == (int64_t) AV_NOPTS_VALUE
&& video_clock != (int64_t) AV_NOPTS_VALUE) {
if (VideoGetBuffers() < 4) {
Debug(3, "video: initial slow down video\n");
decoder->DupNextFrame++;
}
} }
#if defined(DEBUG) || defined(AV_INFO) #if defined(DEBUG) || defined(AV_INFO)
// debug audio/video sync // debug audio/video sync
@ -4386,8 +4391,7 @@ static void VaapiSyncDisplayFrame(VaapiDecoder * decoder)
VideoTimeStampString(video_clock), VideoTimeStampString(video_clock),
abs((video_clock - audio_clock) / 90) < abs((video_clock - audio_clock) / 90) <
9999 ? ((video_clock - audio_clock) / 90) : 88888, 9999 ? ((video_clock - audio_clock) / 90) : 88888,
AudioGetDelay() / 90, (int)VideoDeltaPTS / 90, AudioGetDelay() / 90, (int)VideoDeltaPTS / 90, VideoGetBuffers());
atomic_read(&VideoPacketsFilled));
} }
#endif #endif
} }
@ -4463,7 +4467,7 @@ static void VaapiSyncRenderFrame(VaapiDecoder * decoder,
static int64_t VaapiGetClock(const VaapiDecoder * decoder) static int64_t VaapiGetClock(const VaapiDecoder * decoder)
{ {
// pts is the timestamp of the latest decoded frame // pts is the timestamp of the latest decoded frame
if (!decoder || (uint64_t) decoder->PTS == AV_NOPTS_VALUE) { if (!decoder || decoder->PTS == (int64_t) AV_NOPTS_VALUE) {
return AV_NOPTS_VALUE; return AV_NOPTS_VALUE;
} }
// subtract buffered decoded frames // subtract buffered decoded frames
@ -7235,7 +7239,7 @@ static void VdpauAdvanceFrame(void)
Warning(_ Warning(_
("video: display buffer empty, duping frame (%d/%d) %d\n"), ("video: display buffer empty, duping frame (%d/%d) %d\n"),
decoder->FramesDuped, decoder->FrameCounter, decoder->FramesDuped, decoder->FrameCounter,
atomic_read(&VideoPacketsFilled)); VideoGetBuffers());
} }
last_warned_frame = decoder->FrameCounter; last_warned_frame = decoder->FrameCounter;
if (!(decoder->FramesDisplayed % 300)) { if (!(decoder->FramesDisplayed % 300)) {
@ -7371,8 +7375,9 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
if (decoder->DupNextFrame) { if (decoder->DupNextFrame) {
decoder->DupNextFrame--; decoder->DupNextFrame--;
} else if ((uint64_t) audio_clock != AV_NOPTS_VALUE ++decoder->FramesDuped;
&& (uint64_t) video_clock != AV_NOPTS_VALUE) { } else if (audio_clock != (int64_t) AV_NOPTS_VALUE
&& video_clock != (int64_t) AV_NOPTS_VALUE) {
// both clocks are known // both clocks are known
if (abs(video_clock - audio_clock) > 5000 * 90) { if (abs(video_clock - audio_clock) > 5000 * 90) {
@ -7388,6 +7393,12 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
Debug(3, "video: speed up video\n"); Debug(3, "video: speed up video\n");
decoder->DropNextFrame = 1; decoder->DropNextFrame = 1;
} }
} else if (audio_clock == (int64_t) AV_NOPTS_VALUE
&& video_clock != (int64_t) AV_NOPTS_VALUE) {
if (VideoGetBuffers() < 4) {
Debug(3, "video: initial slow down video\n");
decoder->DupNextFrame++;
}
} }
#if defined(DEBUG) || defined(AV_INFO) #if defined(DEBUG) || defined(AV_INFO)
// debug audio/video sync // debug audio/video sync
@ -7397,8 +7408,7 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
VideoTimeStampString(video_clock), VideoTimeStampString(video_clock),
abs((video_clock - audio_clock) / 90) < abs((video_clock - audio_clock) / 90) <
9999 ? ((video_clock - audio_clock) / 90) : 88888, 9999 ? ((video_clock - audio_clock) / 90) : 88888,
AudioGetDelay() / 90, (int)VideoDeltaPTS / 90, AudioGetDelay() / 90, (int)VideoDeltaPTS / 90, VideoGetBuffers());
atomic_read(&VideoPacketsFilled));
} }
#endif #endif
} }
@ -7480,7 +7490,7 @@ static void VdpauSyncRenderFrame(VdpauDecoder * decoder,
static int64_t VdpauGetClock(const VdpauDecoder * decoder) static int64_t VdpauGetClock(const VdpauDecoder * decoder)
{ {
// pts is the timestamp of the latest decoded frame // pts is the timestamp of the latest decoded frame
if (!decoder || (uint64_t) decoder->PTS == AV_NOPTS_VALUE) { if (!decoder || decoder->PTS == (int64_t) AV_NOPTS_VALUE) {
return AV_NOPTS_VALUE; return AV_NOPTS_VALUE;
} }
// subtract buffered decoded frames // subtract buffered decoded frames
@ -9324,6 +9334,7 @@ void VideoExit(void)
if (VideoUsedModule) { if (VideoUsedModule) {
VideoUsedModule->Exit(); VideoUsedModule->Exit();
} }
VideoUsedModule = NULL; // FIXME: NoopModule;
#ifdef USE_GLX #ifdef USE_GLX
if (GlxEnabled) { if (GlxEnabled) {
GlxExit(); GlxExit();

View File

@ -144,5 +144,6 @@ extern void VideoExit(void); ///< Cleanup and exit video module.
extern void VideoFlushInput(void); ///< Flush video input buffers. extern void VideoFlushInput(void); ///< Flush video input buffers.
extern int VideoDecode(void); ///< Decode video input buffers. extern int VideoDecode(void); ///< Decode video input buffers.
extern int VideoGetBuffers(void); ///< Get number of input buffers.
/// @} /// @}