diff options
-rw-r--r-- | contrib/ffmpeg/A05-truehd-downmix.patch | 46 | ||||
-rw-r--r-- | libhb/decavcodec.c | 114 |
2 files changed, 125 insertions, 35 deletions
diff --git a/contrib/ffmpeg/A05-truehd-downmix.patch b/contrib/ffmpeg/A05-truehd-downmix.patch new file mode 100644 index 000000000..35344613f --- /dev/null +++ b/contrib/ffmpeg/A05-truehd-downmix.patch @@ -0,0 +1,46 @@ +diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c +index 3852f6e..86aecf7 100644 +--- a/libavcodec/mlpdec.c ++++ b/libavcodec/mlpdec.c +@@ -394,14 +394,24 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, + return AVERROR_INVALIDDATA; + } + +- if (m->avctx->request_channels > 0 +- && s->max_channel + 1 >= m->avctx->request_channels +- && substr < m->max_decoded_substream) { ++#if FF_API_REQUEST_CHANNELS ++ if (m->avctx->request_channels > 0 && ++ m->avctx->request_channels <= s->max_channel + 1 && ++ m->max_decoded_substream > substr) { + av_log(m->avctx, AV_LOG_DEBUG, +- "Extracting %d channel downmix from substream %d. " ++ "Extracting %d-channel downmix from substream %d. " + "Further substreams will be skipped.\n", + s->max_channel + 1, substr); + m->max_decoded_substream = substr; ++ } else ++#endif ++ if (m->avctx->request_channel_layout == s->ch_layout && ++ m->max_decoded_substream > substr) { ++ av_log(m->avctx, AV_LOG_DEBUG, ++ "Extracting %d-channel downmix (0x%"PRIx64") from substream %d. " ++ "Further substreams will be skipped.\n", ++ s->max_channel + 1, s->ch_layout, substr); ++ m->max_decoded_substream = substr; + } + + s->noise_shift = get_bits(gbp, 4); +@@ -463,8 +473,10 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, + cp->huff_lsbs = 24; + } + +- if (substr == m->max_decoded_substream) +- m->avctx->channels = s->max_matrix_channel + 1; ++ if (substr == m->max_decoded_substream) { ++ m->avctx->channels = s->max_matrix_channel + 1; ++ m->avctx->channel_layout = s->ch_layout; ++ } + + return 0; + } diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index fe59300fe..8e3767552 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -185,6 +185,19 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job ) pv->title = w->title; pv->list = hb_list_init(); + codec = avcodec_find_decoder(w->codec_param); + pv->context = avcodec_alloc_context3(codec); + if (pv->title->opaque_priv != NULL) + { + AVFormatContext *ic = (AVFormatContext*)pv->title->opaque_priv; + avcodec_copy_context(pv->context, ic->streams[w->audio->id]->codec); + } + else + { + pv->parser = av_parser_init(w->codec_param); + } + hb_ff_set_sample_fmt(pv->context, codec, AV_SAMPLE_FMT_FLT); + /* Downmixing & sample_fmt conversion */ if (!(w->audio->config.out.codec & HB_ACODEC_PASS_FLAG)) { @@ -197,26 +210,37 @@ static int decavcodecaInit( hb_work_object_t * w, hb_job_t * job ) hb_error("decavcodecaInit: hb_audio_resample_init() failed"); return 1; } + // some decoders can downmix using embedded coefficients, + // or dedicated audio substreams for a specific channel layout + switch (w->audio->config.out.mixdown) + { + case HB_AMIXDOWN_MONO: + if (w->codec_param == AV_CODEC_ID_TRUEHD) + { + // libavcodec can't decode TrueHD Mono (bug #356) + // work around it by requesting Stereo and downmixing + pv->context->request_channels = 2; + pv->context->request_channel_layout = AV_CH_LAYOUT_STEREO; + break; + } + pv->context->request_channel_layout = AV_CH_LAYOUT_MONO; + break; + // request 5.1 before downmixing to dpl1/dpl2 + case HB_AMIXDOWN_DOLBY: + case HB_AMIXDOWN_DOLBYPLII: + pv->context->request_channel_layout = AV_CH_LAYOUT_5POINT1; + break; + // request the layout corresponding to the selected mixdown + default: + pv->context->request_channel_layout = + hb_ff_mixdown_xlat(w->audio->config.out.mixdown, NULL); + break; + } } - codec = avcodec_find_decoder( w->codec_param ); - if ( pv->title->opaque_priv ) - { - AVFormatContext *ic = (AVFormatContext*)pv->title->opaque_priv; - pv->context = avcodec_alloc_context3(codec); - avcodec_copy_context( pv->context, ic->streams[w->audio->id]->codec); - hb_ff_set_sample_fmt( pv->context, codec, AV_SAMPLE_FMT_FLT ); - } - else - { - pv->parser = av_parser_init( w->codec_param ); - - pv->context = avcodec_alloc_context3(codec); - hb_ff_set_sample_fmt( pv->context, codec, AV_SAMPLE_FMT_FLT ); - } - if ( hb_avcodec_open( pv->context, codec, NULL, 0 ) ) + if (hb_avcodec_open(pv->context, codec, NULL, 0)) { - hb_log( "decavcodecaInit: avcodec_open failed" ); + hb_log("decavcodecaInit: avcodec_open failed"); return 1; } @@ -401,19 +425,32 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf, unsigned char *pbuffer; int pos, pbuffer_size; - while ( buf && !ret ) + while (buf != NULL && !ret) { pos = 0; - while ( pos < buf->size ) + while (pos < buf->size) { - int len; + int len, truehd_mono = 0; - if ( parser != NULL ) + if (parser != NULL) { - len = av_parser_parse2( parser, context, &pbuffer, - &pbuffer_size, buf->data + pos, - buf->size - pos, buf->s.start, - buf->s.start, 0 ); + len = av_parser_parse2(parser, context, &pbuffer, &pbuffer_size, + buf->data + pos, buf->size - pos, + buf->s.start, buf->s.start, 0); + if (context->codec_id == AV_CODEC_ID_TRUEHD && + context->channel_layout == AV_CH_LAYOUT_MONO) + { + // libavcodec can't decode TrueHD Mono (bug #356) + // work around it by requesting Stereo before decoding + truehd_mono = 1; + context->request_channels = 2; + context->request_channel_layout = AV_CH_LAYOUT_STEREO; + } + else + { + context->request_channels = 0; + context->request_channel_layout = 0; + } } else { @@ -421,7 +458,7 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf, len = pbuffer_size = buf->size; } pos += len; - if ( pbuffer_size > 0 ) + if (pbuffer_size > 0) { int got_frame; AVFrame frame = { { 0 } }; @@ -430,17 +467,24 @@ static int decavcodecaBSInfo( hb_work_object_t *w, const hb_buffer_t *buf, avp.data = pbuffer; avp.size = pbuffer_size; - len = avcodec_decode_audio4( context, &frame, &got_frame, &avp ); - if ( len > 0 && context->sample_rate > 0 ) + len = avcodec_decode_audio4(context, &frame, &got_frame, &avp); + if (len > 0 && context->sample_rate > 0) { - info->bitrate = context->bit_rate; - info->rate = context->sample_rate; - info->rate_base = 1; - info->channel_layout = - hb_ff_layout_xlat(context->channel_layout, - context->channels); + info->rate_base = 1; + info->rate = context->sample_rate; + info->bitrate = context->bit_rate; + info->samples_per_frame = frame.nb_samples; + if (truehd_mono) + { + info->channel_layout = AV_CH_LAYOUT_MONO; + } + else + { + info->channel_layout = + hb_ff_layout_xlat(context->channel_layout, + context->channels); + } ret = 1; - info->samples_per_frame = frame.nb_samples; break; } } |