mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
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:
parent
1f232db5b4
commit
5d8dea1b6b
@ -1,6 +1,7 @@
|
||||
User johns
|
||||
Date:
|
||||
|
||||
New audio PES packet parser.
|
||||
Fix bug: Grabbing a JPG image fails while suspended.
|
||||
Add support for hot keys.
|
||||
Add support to use characters input in edit mode.
|
||||
|
9
Makefile
9
Makefile
@ -19,8 +19,9 @@ GIT_REV = $(shell git describe --always 2>/dev/null)
|
||||
### Configuration (edit this for your needs)
|
||||
|
||||
CONFIG := #-DDEBUG
|
||||
CONFIG += -DAV_INFO
|
||||
#CONFIG += -DHAVE_PTHREAD_NAME
|
||||
CONFIG += -DAV_INFO # debug a/v sync
|
||||
#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 libva && echo "-DUSE_VAAPI")
|
||||
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)"')
|
||||
|
||||
_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\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --cflags gl glu` \
|
||||
@ -82,7 +83,7 @@ override CXXFLAGS += $(_CFLAGS)
|
||||
override CFLAGS += $(_CFLAGS)
|
||||
|
||||
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\
|
||||
xcb-screensaver xcb-randr xcb-glx xcb-icccm xcb-keysyms`\
|
||||
`pkg-config --libs gl glu` \
|
||||
|
9
Todo
9
Todo
@ -26,6 +26,8 @@ missing:
|
||||
Option deinterlace off / deinterlace force!
|
||||
ColorSpace aren'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:
|
||||
AudioPlayHandlerThread -> pthread_cond_wait
|
||||
@ -99,8 +101,11 @@ HDMI/SPDIF Passthrough:
|
||||
only AC-3 written
|
||||
|
||||
playback of recording
|
||||
pause is not reset, when replay exit
|
||||
replay/pause need 100% cpu
|
||||
pause is not reset, when replay exit (fixed?)
|
||||
replay/pause need 100% cpu (fixed?)
|
||||
|
||||
plugins:
|
||||
mp3 plugin needs 100% cpu (OSD updates?)
|
||||
|
||||
setup:
|
||||
Setup of decoder type.
|
||||
|
101
audio.c
101
audio.c
@ -141,7 +141,7 @@ static unsigned AudioSampleRate; ///< audio sample rate in hz
|
||||
static unsigned AudioChannels; ///< number of audio channels
|
||||
static const int AudioBytesProSample = 2; ///< number of bytes per sample
|
||||
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
|
||||
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
|
||||
#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
|
||||
|
||||
@ -297,7 +298,17 @@ static int AlsaAddToRingbuffer(const void *samples, int count)
|
||||
}
|
||||
|
||||
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
|
||||
return 1;
|
||||
}
|
||||
@ -654,7 +665,8 @@ static void AlsaThread(void)
|
||||
}
|
||||
state = snd_pcm_state(AlsaPCMHandle);
|
||||
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;
|
||||
}
|
||||
pthread_yield();
|
||||
@ -720,12 +732,11 @@ static snd_pcm_t *AlsaOpenPCM(int use_ac3)
|
||||
|
||||
// &&|| hell
|
||||
if (!(use_ac3 && ((device = AudioAC3Device)
|
||||
|| (device = getenv("ALSA_AC3_DEVICE"))
|
||||
|| (device = getenv("ALSA_PASSTHROUGH_DEVICE"))))
|
||||
|| (device = getenv("ALSA_AC3_DEVICE"))))
|
||||
&& !(device = AudioPCMDevice) && !(device = getenv("ALSA_DEVICE"))) {
|
||||
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
|
||||
if ((err =
|
||||
@ -752,7 +763,8 @@ static void AlsaInitPCM(void)
|
||||
snd_pcm_t *handle;
|
||||
snd_pcm_hw_params_t *hw_params;
|
||||
int err;
|
||||
snd_pcm_uframes_t buffer_size;
|
||||
|
||||
//snd_pcm_uframes_t buffer_size;
|
||||
|
||||
if (!(handle = AlsaOpenPCM(0))) {
|
||||
return;
|
||||
@ -767,8 +779,9 @@ static void AlsaInitPCM(void)
|
||||
}
|
||||
AlsaCanPause = snd_pcm_hw_params_can_pause(hw_params);
|
||||
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);
|
||||
// needs audio setup
|
||||
//snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size);
|
||||
//Info(_("audio/alsa: max buffer size %lu\n"), buffer_size);
|
||||
|
||||
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,
|
||||
AlsaUseMmap ? SND_PCM_ACCESS_MMAP_INTERLEAVED :
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED, *channels, *freq, 1,
|
||||
125 * 1000))) {
|
||||
96 * 1000))) {
|
||||
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
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
if (0) { // no underruns allowed, play silence
|
||||
snd_pcm_sw_params_t *sw_params;
|
||||
snd_pcm_uframes_t boundary;
|
||||
@ -1091,16 +1104,21 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
|
||||
// update buffer
|
||||
|
||||
snd_pcm_get_params(AlsaPCMHandle, &buffer_size, &period_size);
|
||||
Info(_("audio/alsa: buffer size %lu, period size %lu\n"), buffer_size,
|
||||
period_size);
|
||||
Info(_("audio/alsa: buffer size %lu %lums, period size %lu %lums\n"),
|
||||
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",
|
||||
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
|
||||
|
||||
AlsaStartThreshold = snd_pcm_frames_to_bytes(AlsaPCMHandle, period_size);
|
||||
// buffer time/delay in ms
|
||||
delay = AudioBufferTime;
|
||||
if (VideoAudioDelay > -100) {
|
||||
delay += 100 + VideoAudioDelay / 90;
|
||||
if (VideoAudioDelay > 0) {
|
||||
delay += VideoAudioDelay / 90;
|
||||
}
|
||||
if (AlsaStartThreshold <
|
||||
(*freq * *channels * AudioBytesProSample * delay) / 1000U) {
|
||||
@ -1284,7 +1302,17 @@ static int OssAddToRingbuffer(const void *samples, int count)
|
||||
}
|
||||
|
||||
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
|
||||
return 1;
|
||||
}
|
||||
@ -1522,7 +1550,7 @@ static int OssOpenPCM(int use_ac3)
|
||||
&& !(device = AudioPCMDevice) && !(device = getenv("OSS_AUDIODEV"))) {
|
||||
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) {
|
||||
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;
|
||||
// buffer time/delay in ms
|
||||
delay = AudioBufferTime;
|
||||
if (VideoAudioDelay > -100) {
|
||||
delay += 100 + VideoAudioDelay / 90;
|
||||
if (VideoAudioDelay > 0) {
|
||||
delay += VideoAudioDelay / 90;
|
||||
}
|
||||
if (OssStartThreshold <
|
||||
(*freq * *channels * AudioBytesProSample * delay) / 1000U) {
|
||||
@ -1964,6 +1992,9 @@ static void *AudioPlayHandlerThread(void *dummy)
|
||||
pthread_cond_wait(&AudioStartCond, &AudioMutex);
|
||||
// cond_wait can return, without signal!
|
||||
} while (!AudioRunning);
|
||||
Debug(3, "audio/alsa: ----> %zd ms\n",
|
||||
(RingBufferUsedBytes(AlsaRingBuffer) * 1000)
|
||||
/ (AudioSampleRate * AudioChannels * AudioBytesProSample));
|
||||
pthread_mutex_unlock(&AudioMutex);
|
||||
|
||||
#ifdef USE_AUDIORING
|
||||
@ -2064,6 +2095,21 @@ static const AudioModule *AudioModules[] = {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2183,7 +2229,7 @@ int AudioSetup(int *freq, int *channels, int use_ac3)
|
||||
void AudioPlay(void)
|
||||
{
|
||||
if (!AudioPaused) {
|
||||
Warning("audio: not paused, check the code\n");
|
||||
Debug(3, "audio: not paused, check the code\n");
|
||||
return;
|
||||
}
|
||||
Debug(3, "audio: resumed\n");
|
||||
@ -2197,13 +2243,24 @@ void AudioPlay(void)
|
||||
void AudioPause(void)
|
||||
{
|
||||
if (AudioPaused) {
|
||||
Warning("audio: already paused, check the code\n");
|
||||
Debug(3, "audio: already paused, check the code\n");
|
||||
return;
|
||||
}
|
||||
Debug(3, "audio: paused\n");
|
||||
AudioPaused = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
** Set audio buffer time.
|
||||
*/
|
||||
void AudioSetBufferTime(int delay)
|
||||
{
|
||||
if (!delay) {
|
||||
delay = 216;
|
||||
}
|
||||
AudioBufferTime = delay;
|
||||
}
|
||||
|
||||
/**
|
||||
** Set pcm audio device.
|
||||
**
|
||||
|
2
audio.h
2
audio.h
@ -42,6 +42,8 @@ extern int AudioSetup(int *, int *, int); ///< setup audio output
|
||||
extern void AudioPlay(void); ///< play 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 AudioSetDeviceAC3(const char *); ///< set pass-through device
|
||||
extern void AudioSetChannel(const char *); ///< set mixer channel
|
||||
|
244
codec.c
244
codec.c
@ -33,7 +33,7 @@
|
||||
/**
|
||||
** use av_parser to support insane dvb audio streams.
|
||||
*/
|
||||
#define USE_AVPARSER
|
||||
#define noUSE_AVPARSER
|
||||
|
||||
/// compile with passthrough support (experimental)
|
||||
#define USE_PASSTHROUGH
|
||||
@ -603,8 +603,10 @@ struct _audio_decoder_
|
||||
AVCodec *AudioCodec; ///< audio codec
|
||||
AVCodecContext *AudioCtx; ///< audio codec context
|
||||
|
||||
#ifdef USE_AVPARSER
|
||||
/// audio parser to support insane dvb streaks
|
||||
AVCodecParserContext *AudioParser;
|
||||
#endif
|
||||
int PassthroughAC3; ///< current ac-3 pass-through
|
||||
int SampleRate; ///< current stream sample rate
|
||||
int Channels; ///< current stream channels
|
||||
@ -697,10 +699,12 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name,
|
||||
// we do not send complete frames
|
||||
audio_decoder->AudioCtx->flags |= CODEC_FLAG_TRUNCATED;
|
||||
}
|
||||
#ifdef USE_AVPARSER
|
||||
if (!(audio_decoder->AudioParser =
|
||||
av_parser_init(audio_decoder->AudioCtx->codec_id))) {
|
||||
Fatal(_("codec: can't init audio parser\n"));
|
||||
}
|
||||
#endif
|
||||
audio_decoder->SampleRate = 0;
|
||||
audio_decoder->Channels = 0;
|
||||
audio_decoder->HwSampleRate = 0;
|
||||
@ -719,10 +723,12 @@ void CodecAudioClose(AudioDecoder * audio_decoder)
|
||||
audio_resample_close(audio_decoder->ReSample);
|
||||
audio_decoder->ReSample = NULL;
|
||||
}
|
||||
#ifdef USE_AVPARSER
|
||||
if (audio_decoder->AudioParser) {
|
||||
av_parser_close(audio_decoder->AudioParser);
|
||||
audio_decoder->AudioParser = NULL;
|
||||
}
|
||||
#endif
|
||||
if (audio_decoder->AudioCtx) {
|
||||
pthread_mutex_lock(&CodecLockMutex);
|
||||
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 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 +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE] __attribute__ ((aligned(16)));
|
||||
@ -844,8 +850,8 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
av_init_packet(dpkt);
|
||||
n = av_parser_parse2(audio_decoder->AudioParser, audio_ctx,
|
||||
&dpkt->data, &dpkt->size, spkt->data + index, spkt->size - index,
|
||||
!index ? (uint64_t) spkt->pts : AV_NOPTS_VALUE,
|
||||
!index ? (uint64_t) spkt->dts : AV_NOPTS_VALUE, -1);
|
||||
!index ? spkt->pts : (int64_t) AV_NOPTS_VALUE,
|
||||
!index ? spkt->dts : (int64_t) AV_NOPTS_VALUE, -1);
|
||||
|
||||
// FIXME: make this a function for both #ifdef cases
|
||||
if (dpkt->size) {
|
||||
@ -871,7 +877,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
#else
|
||||
#endif
|
||||
// Update audio clock
|
||||
if ((uint64_t) dpkt->pts != AV_NOPTS_VALUE) {
|
||||
if (dpkt->pts != (int64_t) AV_NOPTS_VALUE) {
|
||||
AudioSetClock(dpkt->pts);
|
||||
}
|
||||
// FIXME: must first play remainings bytes, than change and play new.
|
||||
@ -1059,6 +1065,8 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
** Decode an audio packet.
|
||||
**
|
||||
@ -1074,61 +1082,205 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
AVCodecContext *audio_ctx;
|
||||
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;
|
||||
index = 0;
|
||||
while (spkt->size > index) {
|
||||
int n;
|
||||
while (avpkt->size > index) {
|
||||
int l;
|
||||
int buf_sz;
|
||||
AVPacket dpkt[1];
|
||||
|
||||
av_init_packet(dpkt);
|
||||
dpkt->data = spkt->data + index;
|
||||
dpkt->size = spkt->size - index;
|
||||
|
||||
buf_sz = sizeof(buf);
|
||||
n = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, dpkt);
|
||||
if (n < 0) { // no audio frame could be decompressed
|
||||
l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, (AVPacket *)avpkt);
|
||||
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);
|
||||
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
|
||||
// FIXME: ffmpeg git comeing
|
||||
int got_frame;
|
||||
|
||||
avcodec_decode_audio4(audio_ctx, frame, &got_frame, dpkt);
|
||||
avcodec_decode_audio4(audio_ctx, frame, &got_frame, avpkt);
|
||||
#else
|
||||
#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;
|
||||
}
|
||||
|
||||
#if 1
|
||||
// or av_free_packet, make no difference here
|
||||
av_destruct_packet(spkt);
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Flush the audio decoder.
|
||||
@ -1137,7 +1289,17 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
|
||||
*/
|
||||
void CodecAudioFlushBuffers(AudioDecoder * decoder)
|
||||
{
|
||||
#ifdef USE_AVPARSER
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
3
codec.h
3
codec.h
@ -67,6 +67,9 @@ extern void CodecAudioOpen(AudioDecoder *, const char *, int);
|
||||
/// Close audio codec.
|
||||
extern void CodecAudioClose(AudioDecoder *);
|
||||
|
||||
/// Decode an audio packet.
|
||||
extern void CodecAudioDecodeOld(AudioDecoder *, const AVPacket *);
|
||||
|
||||
/// Decode an audio packet.
|
||||
extern void CodecAudioDecode(AudioDecoder *, const AVPacket *);
|
||||
|
||||
|
1087
softhddev.c
1087
softhddev.c
File diff suppressed because it is too large
Load Diff
@ -37,6 +37,8 @@ extern "C"
|
||||
|
||||
/// C plugin play audio packet
|
||||
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
|
||||
extern void SetVolumeDevice(int);
|
||||
|
||||
|
@ -835,9 +835,11 @@ class cSoftHdDevice:public cDevice
|
||||
virtual void GetVideoSize(int &, int &, double &);
|
||||
virtual void GetOsdSize(int &, int &, double &);
|
||||
virtual int PlayVideo(const uchar *, int);
|
||||
|
||||
#ifndef xxUSE_TS_AUDIO
|
||||
virtual int PlayAudio(const uchar *, int, uchar);
|
||||
#endif
|
||||
//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);
|
||||
#endif
|
||||
virtual void SetAudioChannelDevice(int);
|
||||
@ -845,7 +847,6 @@ class cSoftHdDevice:public cDevice
|
||||
virtual void SetDigitalAudioDevice(bool);
|
||||
virtual void SetAudioTrackDevice(eTrackType);
|
||||
virtual void SetVolumeDevice(int);
|
||||
virtual int PlayAudio(const uchar *, int, uchar);
|
||||
|
||||
// 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
|
||||
** device has an MPEG decoder).
|
||||
*/
|
||||
void cSoftHdDevice::
|
||||
SetVideoDisplayFormat(eVideoDisplayFormat video_display_format)
|
||||
void cSoftHdDevice:: SetVideoDisplayFormat(eVideoDisplayFormat
|
||||
video_display_format)
|
||||
{
|
||||
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.
|
||||
**
|
||||
** @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)
|
||||
{
|
||||
@ -1134,6 +1141,8 @@ int cSoftHdDevice::PlayAudio(const uchar * data, int length, uchar id)
|
||||
return::PlayAudio(data, length, id);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void cSoftHdDevice::SetAudioTrackDevice(
|
||||
__attribute__ ((unused)) eTrackType type)
|
||||
{
|
||||
@ -1173,6 +1182,9 @@ void cSoftHdDevice::SetVolumeDevice(int volume)
|
||||
|
||||
/**
|
||||
** 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)
|
||||
{
|
||||
|
47
video.c
47
video.c
@ -329,7 +329,6 @@ static xcb_atom_t NetWmState; ///< wm-state message atom
|
||||
static xcb_atom_t NetWmStateFullscreen; ///< fullscreen wm-state message atom
|
||||
|
||||
extern uint32_t VideoSwitch; ///< ticks for channel switch
|
||||
extern atomic_t VideoPacketsFilled; ///< how many of the buffer is used
|
||||
|
||||
#ifdef USE_VIDEO_THREAD
|
||||
|
||||
@ -396,19 +395,19 @@ static void VideoSetPts(int64_t * pts_p, int interlaced, const AVFrame * frame)
|
||||
int64_t pts;
|
||||
|
||||
// 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 = frame->best_effort_timestamp;
|
||||
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
|
||||
pts = frame->pkt_dts;
|
||||
}
|
||||
// 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
|
||||
if ((uint64_t) * pts_p != AV_NOPTS_VALUE) {
|
||||
if (*pts_p != (int64_t) AV_NOPTS_VALUE) {
|
||||
int64_t delta;
|
||||
|
||||
delta = pts - *pts_p;
|
||||
@ -4224,7 +4223,7 @@ static void VaapiAdvanceFrame(void)
|
||||
Warning(_
|
||||
("video: display buffer empty, duping frame (%d/%d) %d\n"),
|
||||
decoder->FramesDuped, decoder->FrameCounter,
|
||||
atomic_read(&VideoPacketsFilled));
|
||||
VideoGetBuffers());
|
||||
}
|
||||
last_warned_frame = decoder->FrameCounter;
|
||||
if (!(decoder->FramesDisplayed % 300)) {
|
||||
@ -4358,10 +4357,10 @@ static void VaapiSyncDisplayFrame(VaapiDecoder * decoder)
|
||||
// FIXME: audio not known assume 333ms delay
|
||||
|
||||
if (decoder->DupNextFrame) {
|
||||
++decoder->FramesDuped;
|
||||
decoder->DupNextFrame--;
|
||||
} else if ((uint64_t) audio_clock != AV_NOPTS_VALUE
|
||||
&& (uint64_t) video_clock != AV_NOPTS_VALUE) {
|
||||
++decoder->FramesDuped;
|
||||
} else if (audio_clock != (int64_t) AV_NOPTS_VALUE
|
||||
&& video_clock != (int64_t) AV_NOPTS_VALUE) {
|
||||
// both clocks are known
|
||||
|
||||
if (abs(video_clock - audio_clock) > 5000 * 90) {
|
||||
@ -4377,6 +4376,12 @@ static void VaapiSyncDisplayFrame(VaapiDecoder * decoder)
|
||||
Debug(3, "video: speed up video\n");
|
||||
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)
|
||||
// debug audio/video sync
|
||||
@ -4386,8 +4391,7 @@ static void VaapiSyncDisplayFrame(VaapiDecoder * decoder)
|
||||
VideoTimeStampString(video_clock),
|
||||
abs((video_clock - audio_clock) / 90) <
|
||||
9999 ? ((video_clock - audio_clock) / 90) : 88888,
|
||||
AudioGetDelay() / 90, (int)VideoDeltaPTS / 90,
|
||||
atomic_read(&VideoPacketsFilled));
|
||||
AudioGetDelay() / 90, (int)VideoDeltaPTS / 90, VideoGetBuffers());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -4463,7 +4467,7 @@ static void VaapiSyncRenderFrame(VaapiDecoder * decoder,
|
||||
static int64_t VaapiGetClock(const VaapiDecoder * decoder)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
// subtract buffered decoded frames
|
||||
@ -7235,7 +7239,7 @@ static void VdpauAdvanceFrame(void)
|
||||
Warning(_
|
||||
("video: display buffer empty, duping frame (%d/%d) %d\n"),
|
||||
decoder->FramesDuped, decoder->FrameCounter,
|
||||
atomic_read(&VideoPacketsFilled));
|
||||
VideoGetBuffers());
|
||||
}
|
||||
last_warned_frame = decoder->FrameCounter;
|
||||
if (!(decoder->FramesDisplayed % 300)) {
|
||||
@ -7371,8 +7375,9 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
|
||||
|
||||
if (decoder->DupNextFrame) {
|
||||
decoder->DupNextFrame--;
|
||||
} else if ((uint64_t) audio_clock != AV_NOPTS_VALUE
|
||||
&& (uint64_t) video_clock != AV_NOPTS_VALUE) {
|
||||
++decoder->FramesDuped;
|
||||
} else if (audio_clock != (int64_t) AV_NOPTS_VALUE
|
||||
&& video_clock != (int64_t) AV_NOPTS_VALUE) {
|
||||
// both clocks are known
|
||||
|
||||
if (abs(video_clock - audio_clock) > 5000 * 90) {
|
||||
@ -7388,6 +7393,12 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
|
||||
Debug(3, "video: speed up video\n");
|
||||
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)
|
||||
// debug audio/video sync
|
||||
@ -7397,8 +7408,7 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
|
||||
VideoTimeStampString(video_clock),
|
||||
abs((video_clock - audio_clock) / 90) <
|
||||
9999 ? ((video_clock - audio_clock) / 90) : 88888,
|
||||
AudioGetDelay() / 90, (int)VideoDeltaPTS / 90,
|
||||
atomic_read(&VideoPacketsFilled));
|
||||
AudioGetDelay() / 90, (int)VideoDeltaPTS / 90, VideoGetBuffers());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -7480,7 +7490,7 @@ static void VdpauSyncRenderFrame(VdpauDecoder * decoder,
|
||||
static int64_t VdpauGetClock(const VdpauDecoder * decoder)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
// subtract buffered decoded frames
|
||||
@ -9324,6 +9334,7 @@ void VideoExit(void)
|
||||
if (VideoUsedModule) {
|
||||
VideoUsedModule->Exit();
|
||||
}
|
||||
VideoUsedModule = NULL; // FIXME: NoopModule;
|
||||
#ifdef USE_GLX
|
||||
if (GlxEnabled) {
|
||||
GlxExit();
|
||||
|
1
video.h
1
video.h
@ -144,5 +144,6 @@ extern void VideoExit(void); ///< Cleanup and exit video module.
|
||||
|
||||
extern void VideoFlushInput(void); ///< Flush video input buffers.
|
||||
extern int VideoDecode(void); ///< Decode video input buffers.
|
||||
extern int VideoGetBuffers(void); ///< Get number of input buffers.
|
||||
|
||||
/// @}
|
||||
|
Loading…
Reference in New Issue
Block a user