]> granicus.if.org Git - handbrake/commitdiff
Set AVCodecContext.request_channel_layout when decoding.
authorRodeo <tdskywalker@gmail.com>
Tue, 5 Feb 2013 18:03:07 +0000 (18:03 +0000)
committerRodeo <tdskywalker@gmail.com>
Tue, 5 Feb 2013 18:03:07 +0000 (18:03 +0000)
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

contrib/ffmpeg/A05-truehd-downmix.patch [new file with mode: 0644]
libhb/decavcodec.c

diff --git a/contrib/ffmpeg/A05-truehd-downmix.patch b/contrib/ffmpeg/A05-truehd-downmix.patch
new file mode 100644 (file)
index 0000000..3534461
--- /dev/null
@@ -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;
+ }
index fe59300feb8593ff07872dcc72fea2d786a278e3..8e376755248dee6e35b4c13f40dba598ec40dd49 100644 (file)
@@ -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;
                 }
             }