[FFmpeg-devel] [PATCH] avcodec/ac3dec: fix downmix logic for eac3

James Almer jamrial at gmail.com
Sun Nov 24 19:07:03 EET 2024


Ensure downmixed is only set once during init, as it used to be.

Fixes a regression since acbb2777e28c.
Fixes ticket #11321.

Signed-off-by: James Almer <jamrial at gmail.com>
---
 libavcodec/ac3dec.c | 121 ++++++++++++++++++++++----------------------
 1 file changed, 61 insertions(+), 60 deletions(-)

diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
index 0a4d3375ee..11374bcb7d 100644
--- a/libavcodec/ac3dec.c
+++ b/libavcodec/ac3dec.c
@@ -199,7 +199,6 @@ static void ac3_downmix(AVCodecContext *avctx)
         av_channel_layout_uninit(&avctx->ch_layout);
         avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
     }
-    s->downmixed = 1;
 }
 
 /**
@@ -241,6 +240,7 @@ static av_cold int ac3_decode_init(AVCodecContext *avctx)
         avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
 
     ac3_downmix(avctx);
+    s->downmixed = 1;
 
     for (i = 0; i < AC3_MAX_CHANNELS; i++) {
         s->xcfptr[i] = s->transform_coeffs[i];
@@ -1647,6 +1647,66 @@ dependent_frame:
         if (ch < s->out_channels)
             s->outptr[channel_map[ch]] = s->output_buffer[ch + offset];
     }
+
+    for (ch = 0; ch < EAC3_MAX_CHANNELS; ch++)
+        extended_channel_map[ch] = ch;
+
+    if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
+        uint64_t ich_layout = ff_ac3_channel_layout_tab[s->prev_output_mode & ~AC3_OUTPUT_LFEON];
+        int channel_map_size = ff_ac3_channels_tab[s->output_mode & ~AC3_OUTPUT_LFEON] + s->lfe_on;
+        uint64_t channel_layout;
+        int extend = 0;
+
+        if (s->prev_output_mode & AC3_OUTPUT_LFEON)
+            ich_layout |= AV_CH_LOW_FREQUENCY;
+
+        channel_layout = ich_layout;
+        for (ch = 0; ch < 16; ch++) {
+            if (s->channel_map & (1 << (EAC3_MAX_CHANNELS - ch - 1))) {
+                channel_layout |= ff_eac3_custom_channel_map_locations[ch][1];
+            }
+        }
+        if (av_popcount64(channel_layout) > EAC3_MAX_CHANNELS) {
+            av_log(avctx, AV_LOG_ERROR, "Too many channels (%d) coded\n",
+                   av_popcount64(channel_layout));
+            return AVERROR_INVALIDDATA;
+        }
+
+        av_channel_layout_uninit(&avctx->ch_layout);
+        av_channel_layout_from_mask(&avctx->ch_layout, channel_layout);
+
+        for (ch = 0; ch < EAC3_MAX_CHANNELS; ch++) {
+            if (s->channel_map & (1 << (EAC3_MAX_CHANNELS - ch - 1))) {
+                if (ff_eac3_custom_channel_map_locations[ch][0]) {
+                    int index = av_channel_layout_index_from_channel(&avctx->ch_layout,
+                                                                     ff_ctzll(ff_eac3_custom_channel_map_locations[ch][1]));
+                    if (index < 0)
+                        return AVERROR_INVALIDDATA;
+                    if (extend >= channel_map_size)
+                        break;
+
+                    extended_channel_map[index] = offset + channel_map[extend++];
+                } else {
+                    int i;
+
+                    for (i = 0; i < 64; i++) {
+                        if ((1ULL << i) & ff_eac3_custom_channel_map_locations[ch][1]) {
+                            int index = av_channel_layout_index_from_channel(&avctx->ch_layout, i);
+                            if (index < 0)
+                                return AVERROR_INVALIDDATA;
+                            if (extend >= channel_map_size)
+                                break;
+
+                            extended_channel_map[index] = offset + channel_map[extend++];
+                        }
+                    }
+                }
+            }
+        }
+
+        ac3_downmix(avctx);
+    }
+
     for (blk = 0; blk < s->num_blocks; blk++) {
         if (!err && decode_audio_block(s, blk, offset)) {
             av_log(avctx, AV_LOG_ERROR, "error decoding the audio block\n");
@@ -1713,65 +1773,6 @@ skip:
         return AVERROR_INVALIDDATA;
     }
 
-    for (ch = 0; ch < EAC3_MAX_CHANNELS; ch++)
-        extended_channel_map[ch] = ch;
-
-    if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
-        uint64_t ich_layout = ff_ac3_channel_layout_tab[s->prev_output_mode & ~AC3_OUTPUT_LFEON];
-        int channel_map_size = ff_ac3_channels_tab[s->output_mode & ~AC3_OUTPUT_LFEON] + s->lfe_on;
-        uint64_t channel_layout;
-        int extend = 0;
-
-        if (s->prev_output_mode & AC3_OUTPUT_LFEON)
-            ich_layout |= AV_CH_LOW_FREQUENCY;
-
-        channel_layout = ich_layout;
-        for (ch = 0; ch < 16; ch++) {
-            if (s->channel_map & (1 << (EAC3_MAX_CHANNELS - ch - 1))) {
-                channel_layout |= ff_eac3_custom_channel_map_locations[ch][1];
-            }
-        }
-        if (av_popcount64(channel_layout) > EAC3_MAX_CHANNELS) {
-            av_log(avctx, AV_LOG_ERROR, "Too many channels (%d) coded\n",
-                   av_popcount64(channel_layout));
-            return AVERROR_INVALIDDATA;
-        }
-
-        av_channel_layout_uninit(&avctx->ch_layout);
-        av_channel_layout_from_mask(&avctx->ch_layout, channel_layout);
-
-        for (ch = 0; ch < EAC3_MAX_CHANNELS; ch++) {
-            if (s->channel_map & (1 << (EAC3_MAX_CHANNELS - ch - 1))) {
-                if (ff_eac3_custom_channel_map_locations[ch][0]) {
-                    int index = av_channel_layout_index_from_channel(&avctx->ch_layout,
-                                                                     ff_ctzll(ff_eac3_custom_channel_map_locations[ch][1]));
-                    if (index < 0)
-                        return AVERROR_INVALIDDATA;
-                    if (extend >= channel_map_size)
-                        break;
-
-                    extended_channel_map[index] = offset + channel_map[extend++];
-                } else {
-                    int i;
-
-                    for (i = 0; i < 64; i++) {
-                        if ((1ULL << i) & ff_eac3_custom_channel_map_locations[ch][1]) {
-                            int index = av_channel_layout_index_from_channel(&avctx->ch_layout, i);
-                            if (index < 0)
-                                return AVERROR_INVALIDDATA;
-                            if (extend >= channel_map_size)
-                                break;
-
-                            extended_channel_map[index] = offset + channel_map[extend++];
-                        }
-                    }
-                }
-            }
-        }
-
-        ac3_downmix(avctx);
-    }
-
     /* get output buffer */
     frame->nb_samples = s->num_blocks * AC3_BLOCK_SIZE;
     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
-- 
2.47.0



More information about the ffmpeg-devel mailing list