From e27e9541fe7db0dcc6bb15861912a8bd813c8f90 Mon Sep 17 00:00:00 2001 From: Rodeo Date: Tue, 5 Feb 2013 18:03:07 +0000 Subject: Set AVCodecContext.request_channel_layout when decoding. Allows extracting a 5.1 or 2-channel downmix from a dedicated substream (TrueHD). Also works around a bug when decoding TrueHD Mono. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5242 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- libhb/decavcodec.c | 114 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 35 deletions(-) (limited to 'libhb/decavcodec.c') 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; } } -- cgit v1.2.3