summaryrefslogtreecommitdiff
path: root/codec.c
diff options
context:
space:
mode:
authorJohns <johns98@gmx.net>2012-02-21 20:55:28 +0100
committerJohns <johns98@gmx.net>2012-02-21 20:55:28 +0100
commit5d8dea1b6b9e15048f425f13b349e785a494cdb3 (patch)
treeac2fc34f5cff60e63b59fa8ed5bcd5d9f6a1d7fa /codec.c
parent1f232db5b499169e3c354b4af4bb59053009f210 (diff)
downloadvdr-plugin-softhddevice-5d8dea1b6b9e15048f425f13b349e785a494cdb3.tar.gz
vdr-plugin-softhddevice-5d8dea1b6b9e15048f425f13b349e785a494cdb3.tar.bz2
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).
Diffstat (limited to 'codec.c')
-rw-r--r--codec.c246
1 files changed, 204 insertions, 42 deletions
diff --git a/codec.c b/codec.c
index 1c65afb..8a23207 100644
--- a/codec.c
+++ b/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
- Error(_("codec: error audio data at %d\n"), index);
+ l = avcodec_decode_audio3(audio_ctx, buf, &buf_sz, (AVPacket *)avpkt);
+ if (l == AVERROR(EAGAIN)) {
+ Error(_("codec: latm\n"));
break;
}
-#ifdef DEBUG
- Debug(4, "codec/audio: -> %d\n", buf_sz);
- if ((unsigned)buf_sz > sizeof(buf)) {
- abort();
+ if (l < 0) { // no audio frame could be decompressed
+ Error(_("codec: error audio data at %d\n"), index);
+ break;
}
-#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;
+
+ 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;
+ }
- index += n;
- }
+ 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;
+ }
-#if 1
- // or av_free_packet, make no difference here
- av_destruct_packet(spkt);
-#endif
-}
+ // 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);
}