Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header()
@ 2025-06-05 21:49 James Almer
  2025-06-05 21:49 ` [FFmpeg-devel] [PATCH 2/3] avformat/movenc: fix writing reserved bits in EC3SpecificBox James Almer
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: James Almer @ 2025-06-05 21:49 UTC (permalink / raw)
  To: ffmpeg-devel

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavcodec/ac3_parser.c          | 218 +++++++++++++++++++++++++++++++
 libavcodec/ac3_parser_internal.h |  19 +++
 libavcodec/ac3dec.c              |  88 +++----------
 libavcodec/ac3dec.h              |   4 +-
 libavcodec/ac3defs.h             |   2 +
 libavcodec/eac3dec.c             | 154 +++-------------------
 6 files changed, 279 insertions(+), 206 deletions(-)

diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c
index 69989690dd..1cba847eaa 100644
--- a/libavcodec/ac3_parser.c
+++ b/libavcodec/ac3_parser.c
@@ -73,6 +73,216 @@ int ff_ac3_find_syncword(const uint8_t *buf, int buf_size)
     return i;
 }
 
+/**
+ * Parse the 'sync info' and 'bit stream info' from the AC-3 bitstream.
+ * GetBitContext within AC3DecodeContext must point to
+ * the start of the synchronized AC-3 bitstream.
+ */
+static int ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
+{
+    /* read the rest of the bsi. read twice for dual mono mode. */
+    for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
+        hdr->dialog_normalization[i] = -get_bits(gbc, 5);
+        hdr->compression_exists[i] = get_bits1(gbc);
+        if (hdr->compression_exists[i])
+            hdr->heavy_dynamic_range[i] = get_bits(gbc, 8);
+        if (get_bits1(gbc))
+            skip_bits(gbc, 8); //skip language code
+        if (get_bits1(gbc))
+            skip_bits(gbc, 7); //skip audio production information
+    }
+
+    skip_bits(gbc, 2); //skip copyright bit and original bitstream bit
+
+    /* skip the timecodes or parse the Alternate Bit Stream Syntax */
+    if (hdr->bitstream_id != 6) {
+        if (get_bits1(gbc))
+            skip_bits(gbc, 14); //skip timecode1
+        if (get_bits1(gbc))
+            skip_bits(gbc, 14); //skip timecode2
+    } else {
+        if (get_bits1(gbc)) {
+            hdr->preferred_downmix       = get_bits(gbc, 2);
+            hdr->center_mix_level_ltrt   = get_bits(gbc, 3);
+            hdr->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7);
+            hdr->center_mix_level        = get_bits(gbc, 3);
+            hdr->surround_mix_level      = av_clip(get_bits(gbc, 3), 3, 7);
+        }
+        if (get_bits1(gbc)) {
+            hdr->dolby_surround_ex_mode = get_bits(gbc, 2);
+            hdr->dolby_headphone_mode   = get_bits(gbc, 2);
+            skip_bits(gbc, 10); // skip adconvtyp (1), xbsi2 (8), encinfo (1)
+        }
+    }
+
+    /* skip additional bitstream info */
+    if (get_bits1(gbc)) {
+        int i = get_bits(gbc, 6);
+        do {
+            skip_bits(gbc, 8);
+        } while (i--);
+    }
+
+    return 0;
+}
+
+static int eac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
+{
+    if (hdr->frame_type == EAC3_FRAME_TYPE_RESERVED)
+        return AC3_PARSE_ERROR_FRAME_TYPE;
+    if (hdr->substreamid)
+        return AC3_PARSE_ERROR_FRAME_TYPE;
+
+    skip_bits(gbc, 5); // skip bitstream id
+
+    /* volume control params */
+    for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
+        hdr->dialog_normalization[i] = -get_bits(gbc, 5);
+        hdr->compression_exists[i] = get_bits1(gbc);
+        if (hdr->compression_exists[i])
+            hdr->heavy_dynamic_range[i] = get_bits(gbc, 8);
+    }
+
+    /* dependent stream channel map */
+    if (hdr->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
+        if (get_bits1(gbc)) {
+            int64_t channel_layout = 0;
+            int channel_map = get_bits(gbc, 16);
+
+            for (int i = 0; i < 16; i++)
+                if (channel_map & (1 << (EAC3_MAX_CHANNELS - i - 1)))
+                    channel_layout |= ff_eac3_custom_channel_map_locations[i][1];
+
+            if (av_popcount64(channel_layout) > EAC3_MAX_CHANNELS) {
+                return AC3_PARSE_ERROR_CHANNEL_MAP;
+            }
+            hdr->channel_map = channel_map;
+        }
+    }
+
+    /* mixing metadata */
+    if (get_bits1(gbc)) {
+        /* center and surround mix levels */
+        if (hdr->channel_mode > AC3_CHMODE_STEREO) {
+            hdr->preferred_downmix = get_bits(gbc, 2);
+            if (hdr->channel_mode & 1) {
+                /* if three front channels exist */
+                hdr->center_mix_level_ltrt = get_bits(gbc, 3);
+                hdr->center_mix_level      = get_bits(gbc, 3);
+            }
+            if (hdr->channel_mode & 4) {
+                /* if a surround channel exists */
+                hdr->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7);
+                hdr->surround_mix_level      = av_clip(get_bits(gbc, 3), 3, 7);
+            }
+        }
+
+        /* lfe mix level */
+        if (hdr->lfe_on && (hdr->lfe_mix_level_exists = get_bits1(gbc))) {
+            hdr->lfe_mix_level = get_bits(gbc, 5);
+        }
+
+        /* info for mixing with other streams and substreams */
+        if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) {
+            for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
+                // TODO: apply program scale factor
+                if (get_bits1(gbc)) {
+                    skip_bits(gbc, 6);  // skip program scale factor
+                }
+            }
+            if (get_bits1(gbc)) {
+                skip_bits(gbc, 6);  // skip external program scale factor
+            }
+            /* skip mixing parameter data */
+            switch(get_bits(gbc, 2)) {
+                case 1: skip_bits(gbc, 5);  break;
+                case 2: skip_bits(gbc, 12); break;
+                case 3: {
+                    int mix_data_size = (get_bits(gbc, 5) + 2) << 3;
+                    skip_bits_long(gbc, mix_data_size);
+                    break;
+                }
+            }
+            /* skip pan information for mono or dual mono source */
+            if (hdr->channel_mode < AC3_CHMODE_STEREO) {
+                for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
+                    if (get_bits1(gbc)) {
+                        /* note: this is not in the ATSC A/52B specification
+                           reference: ETSI TS 102 366 V1.1.1
+                                      section: E.1.3.1.25 */
+                        skip_bits(gbc, 8);  // skip pan mean direction index
+                        skip_bits(gbc, 6);  // skip reserved paninfo bits
+                    }
+                }
+            }
+            /* skip mixing configuration information */
+            if (get_bits1(gbc)) {
+                for (int i = 0; i < hdr->num_blocks; i++) {
+                    if (hdr->num_blocks == 1 || get_bits1(gbc)) {
+                        skip_bits(gbc, 5);
+                    }
+                }
+            }
+        }
+    }
+
+    /* informational metadata */
+    if (get_bits1(gbc)) {
+        hdr->bitstream_mode = get_bits(gbc, 3);
+        skip_bits(gbc, 2); // skip copyright bit and original bitstream bit
+        if (hdr->channel_mode == AC3_CHMODE_STEREO) {
+            hdr->dolby_surround_mode  = get_bits(gbc, 2);
+            hdr->dolby_headphone_mode = get_bits(gbc, 2);
+        }
+        if (hdr->channel_mode >= AC3_CHMODE_2F2R) {
+            hdr->dolby_surround_ex_mode = get_bits(gbc, 2);
+        }
+        for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
+            if (get_bits1(gbc)) {
+                skip_bits(gbc, 8); // skip mix level, room type, and A/D converter type
+            }
+        }
+        if (hdr->sr_code != EAC3_SR_CODE_REDUCED) {
+            skip_bits1(gbc); // skip source sample rate code
+        }
+    }
+
+    /* converter synchronization flag
+       If frames are less than six blocks, this bit should be turned on
+       once every 6 blocks to indicate the start of a frame set.
+       reference: RFC 4598, Section 2.1.3  Frame Sets */
+    if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT && hdr->num_blocks != 6) {
+        skip_bits1(gbc); // skip converter synchronization flag
+    }
+
+    /* original frame size code if this stream was converted from AC-3 */
+    if (hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT &&
+            (hdr->num_blocks == 6 || get_bits1(gbc))) {
+        skip_bits(gbc, 6); // skip frame size code
+    }
+
+    /* additional bitstream info */
+    if (get_bits1(gbc)) {
+        int addbsil = get_bits(gbc, 6);
+        for (int i = 0; i < addbsil + 1; i++) {
+            if (i == 0) {
+                /* In this 8 bit chunk, the LSB is equal to flag_ec3_extension_type_a
+                   which can be used to detect Atmos presence */
+                skip_bits(gbc, 7);
+                hdr->eac3_extension_type_a = get_bits1(gbc);
+                if (hdr->eac3_extension_type_a) {
+                    hdr->complexity_index_type_a = get_bits(gbc, 8);
+                    i++;
+                }
+            } else {
+                skip_bits(gbc, 8); // skip additional bit stream info
+            }
+        }
+    }
+
+    return 0;
+}
+
 int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
 {
     int frame_size_code;
@@ -133,6 +343,10 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
         hdr->frame_size = ff_ac3_frame_size_tab[frame_size_code][hdr->sr_code] * 2;
         hdr->frame_type = EAC3_FRAME_TYPE_AC3_CONVERT; //EAC3_FRAME_TYPE_INDEPENDENT;
         hdr->substreamid = 0;
+
+        int ret = ac3_parse_header(gbc, hdr);
+        if (ret < 0)
+            return ret;
     } else {
         /* Enhanced AC-3 */
         hdr->crc1 = 0;
@@ -165,6 +379,10 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
         hdr->bit_rate = 8LL * hdr->frame_size * hdr->sample_rate /
                         (hdr->num_blocks * 256);
         hdr->channels = ff_ac3_channels_tab[hdr->channel_mode] + hdr->lfe_on;
+
+        int ret = eac3_parse_header(gbc, hdr);
+        if (ret < 0)
+            return ret;
     }
     hdr->channel_layout = ff_ac3_channel_layout_tab[hdr->channel_mode];
     if (hdr->lfe_on)
diff --git a/libavcodec/ac3_parser_internal.h b/libavcodec/ac3_parser_internal.h
index 46814bfb1f..ab5df34003 100644
--- a/libavcodec/ac3_parser_internal.h
+++ b/libavcodec/ac3_parser_internal.h
@@ -46,6 +46,7 @@ typedef struct AC3HeaderInfo {
     int substreamid;                        ///< substream identification
     int center_mix_level;                   ///< Center mix level index
     int surround_mix_level;                 ///< Surround mix level index
+    uint8_t channel_map_present;
     uint16_t channel_map;
     int num_blocks;                         ///< number of audio blocks
     int dolby_surround_mode;
@@ -62,6 +63,23 @@ typedef struct AC3HeaderInfo {
     uint64_t channel_layout;
     int8_t ac3_bit_rate_code;
     /** @} */
+
+    /** @name enhanced eac3 extension coded elements
+     * @{
+     */
+    int8_t dialog_normalization[2];
+    uint8_t compression_exists[2];
+    uint8_t heavy_dynamic_range[2];
+    uint8_t center_mix_level_ltrt;              ///< Center mix level index
+    uint8_t surround_mix_level_ltrt;            ///< Surround mix level index
+    uint8_t dolby_headphone_mode;
+    uint8_t dolby_surround_ex_mode;
+    uint8_t lfe_mix_level_exists;
+    uint8_t lfe_mix_level;
+    uint8_t preferred_downmix;
+    uint8_t eac3_extension_type_a;
+    uint8_t complexity_index_type_a;
+    /** @} */
 } AC3HeaderInfo;
 
 typedef enum {
@@ -71,6 +89,7 @@ typedef enum {
     AC3_PARSE_ERROR_FRAME_SIZE  = -0x4030c0a,
     AC3_PARSE_ERROR_FRAME_TYPE  = -0x5030c0a,
     AC3_PARSE_ERROR_CRC         = -0x6030c0a,
+    AC3_PARSE_ERROR_CHANNEL_MAP = -0x7030c0a,
 } AC3ParseError;
 
 /**
diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
index 5eacab4475..2f0e7f5344 100644
--- a/libavcodec/ac3dec.c
+++ b/libavcodec/ac3dec.c
@@ -156,72 +156,6 @@ static av_cold void ac3_decode_flush(AVCodecContext *avctx)
     av_lfg_init(&s->dith_state, 0);
 }
 
-/**
- * Parse the 'sync info' and 'bit stream info' from the AC-3 bitstream.
- * GetBitContext within AC3DecodeContext must point to
- * the start of the synchronized AC-3 bitstream.
- */
-static int ac3_parse_header(AC3DecodeContext *s)
-{
-    GetBitContext *gbc = &s->gbc;
-    int i;
-
-    /* read the rest of the bsi. read twice for dual mono mode. */
-    i = !s->channel_mode;
-    do {
-        s->dialog_normalization[(!s->channel_mode)-i] = -get_bits(gbc, 5);
-        if (s->dialog_normalization[(!s->channel_mode)-i] == 0) {
-            s->dialog_normalization[(!s->channel_mode)-i] = -31;
-        }
-        if (s->target_level != 0) {
-            s->level_gain[(!s->channel_mode)-i] = powf(2.0f,
-                (float)(s->target_level -
-                s->dialog_normalization[(!s->channel_mode)-i])/6.0f);
-        }
-        if (s->compression_exists[(!s->channel_mode)-i] = get_bits1(gbc)) {
-            s->heavy_dynamic_range[(!s->channel_mode)-i] =
-                AC3_HEAVY_RANGE(get_bits(gbc, 8));
-        }
-        if (get_bits1(gbc))
-            skip_bits(gbc, 8); //skip language code
-        if (get_bits1(gbc))
-            skip_bits(gbc, 7); //skip audio production information
-    } while (i--);
-
-    skip_bits(gbc, 2); //skip copyright bit and original bitstream bit
-
-    /* skip the timecodes or parse the Alternate Bit Stream Syntax */
-    if (s->bitstream_id != 6) {
-        if (get_bits1(gbc))
-            skip_bits(gbc, 14); //skip timecode1
-        if (get_bits1(gbc))
-            skip_bits(gbc, 14); //skip timecode2
-    } else {
-        if (get_bits1(gbc)) {
-            s->preferred_downmix       = get_bits(gbc, 2);
-            s->center_mix_level_ltrt   = get_bits(gbc, 3);
-            s->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7);
-            s->center_mix_level        = get_bits(gbc, 3);
-            s->surround_mix_level      = av_clip(get_bits(gbc, 3), 3, 7);
-        }
-        if (get_bits1(gbc)) {
-            s->dolby_surround_ex_mode = get_bits(gbc, 2);
-            s->dolby_headphone_mode   = get_bits(gbc, 2);
-            skip_bits(gbc, 10); // skip adconvtyp (1), xbsi2 (8), encinfo (1)
-        }
-    }
-
-    /* skip additional bitstream info */
-    if (get_bits1(gbc)) {
-        i = get_bits(gbc, 6);
-        do {
-            skip_bits(gbc, 8);
-        } while (i--);
-    }
-
-    return 0;
-}
-
 /**
  * Common function to parse AC-3 or E-AC-3 frame header
  */
@@ -281,10 +215,25 @@ static int parse_frame_header(AC3DecodeContext *s)
         s->dba_syntax            = 1;
         s->skip_syntax           = 1;
         memset(s->channel_uses_aht, 0, sizeof(s->channel_uses_aht));
-        return ac3_parse_header(s);
+        /* volume control params */
+        for (int i = 0; i < (s->channel_mode ? 1 : 2); i++) {
+            s->dialog_normalization[i] = hdr.dialog_normalization[i];
+            if (s->dialog_normalization[i] == 0) {
+                s->dialog_normalization[i] = -31;
+            }
+            if (s->target_level != 0) {
+                s->level_gain[i] = powf(2.0f,
+                    (float)(s->target_level - s->dialog_normalization[i])/6.0f);
+            }
+            s->compression_exists[i] = hdr.compression_exists[i];
+            if (s->compression_exists[i]) {
+                s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(hdr.heavy_dynamic_range[i]);
+            }
+        }
+        return 0;
     } else if (CONFIG_EAC3_DECODER) {
         s->eac3 = 1;
-        return ff_eac3_parse_header(s);
+        return ff_eac3_parse_header(s, &hdr);
     } else {
         av_log(s->avctx, AV_LOG_ERROR, "E-AC-3 support not compiled in\n");
         return AVERROR(ENOSYS);
@@ -1469,6 +1418,9 @@ dependent_frame:
                 av_log(avctx, AV_LOG_ERROR, "invalid frame type\n");
             }
             break;
+        case AC3_PARSE_ERROR_CHANNEL_MAP:
+            av_log(avctx, AV_LOG_ERROR, "invalid channel map\n");
+            return AVERROR_INVALIDDATA;
         case AC3_PARSE_ERROR_CRC:
             break;
         default: // Normal AVERROR do not try to recover.
diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
index 4042a99b80..a099264475 100644
--- a/libavcodec/ac3dec.h
+++ b/libavcodec/ac3dec.h
@@ -260,11 +260,13 @@ typedef struct AC3DecodeContext {
 ///@}
 } AC3DecodeContext;
 
+struct AC3HeaderInfo;
+
 /**
  * Parse the E-AC-3 frame header.
  * This parses both the bit stream info and audio frame header.
  */
-static int ff_eac3_parse_header(AC3DecodeContext *s);
+static int ff_eac3_parse_header(AC3DecodeContext *s, const struct AC3HeaderInfo *hdr);
 
 /**
  * Decode mantissas in a single channel for the entire frame.
diff --git a/libavcodec/ac3defs.h b/libavcodec/ac3defs.h
index f9b1be059f..8d6a58d21f 100644
--- a/libavcodec/ac3defs.h
+++ b/libavcodec/ac3defs.h
@@ -34,6 +34,8 @@
 #define AC3_CRITICAL_BANDS 50
 #define AC3_MAX_CPL_BANDS  18
 
+#define EAC3_SR_CODE_REDUCED 3
+
 /* pre-defined gain values */
 #define LEVEL_PLUS_3DB          M_SQRT2
 #define LEVEL_PLUS_1POINT5DB    1.1892071150027209
diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c
index 2b3bffda6e..c5095b1917 100644
--- a/libavcodec/eac3dec.c
+++ b/libavcodec/eac3dec.c
@@ -53,8 +53,6 @@ typedef enum {
     EAC3_GAQ_124
 } EAC3GaqMode;
 
-#define EAC3_SR_CODE_REDUCED  3
-
 static void ff_eac3_apply_spectral_extension(AC3DecodeContext *s)
 {
     int bin, bnd, ch, i;
@@ -287,7 +285,7 @@ static void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch)
     }
 }
 
-static int ff_eac3_parse_header(AC3DecodeContext *s)
+static int ff_eac3_parse_header(AC3DecodeContext *s, const AC3HeaderInfo *hdr)
 {
     int i, blk, ch;
     int ac3_exponent_strategy, parse_aht_info, parse_spx_atten_data;
@@ -323,11 +321,10 @@ static int ff_eac3_parse_header(AC3DecodeContext *s)
         avpriv_request_sample(s->avctx, "Reduced sampling rate");
         return AVERROR_PATCHWELCOME;
     }
-    skip_bits(gbc, 5); // skip bitstream id
 
     /* volume control params */
     for (i = 0; i < (s->channel_mode ? 1 : 2); i++) {
-        s->dialog_normalization[i] = -get_bits(gbc, 5);
+        s->dialog_normalization[i] = hdr->dialog_normalization[i];
         if (s->dialog_normalization[i] == 0) {
             s->dialog_normalization[i] = -31;
         }
@@ -335,147 +332,30 @@ static int ff_eac3_parse_header(AC3DecodeContext *s)
             s->level_gain[i] = powf(2.0f,
                 (float)(s->target_level - s->dialog_normalization[i])/6.0f);
         }
-        s->compression_exists[i] = get_bits1(gbc);
-        if (s->compression_exists[i]) {
-            s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(get_bits(gbc, 8));
+        if (hdr->compression_exists[i]) {
+            s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(hdr->heavy_dynamic_range[i]);
         }
     }
 
-    /* dependent stream channel map */
-    if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
-        if (get_bits1(gbc)) {
-            int64_t channel_layout = 0;
-            int channel_map = get_bits(gbc, 16);
-            av_log(s->avctx, AV_LOG_DEBUG, "channel_map: %0X\n", channel_map);
-
-            for (i = 0; i < 16; i++)
-                if (channel_map & (1 << (EAC3_MAX_CHANNELS - i - 1)))
-                    channel_layout |= ff_eac3_custom_channel_map_locations[i][1];
-
-            if (av_popcount64(channel_layout) > EAC3_MAX_CHANNELS) {
-                return AVERROR_INVALIDDATA;
-            }
-            s->channel_map = channel_map;
-        }
-    }
+    s->channel_map = hdr->channel_map;
 
     /* mixing metadata */
-    if (get_bits1(gbc)) {
-        /* center and surround mix levels */
-        if (s->channel_mode > AC3_CHMODE_STEREO) {
-            s->preferred_downmix = get_bits(gbc, 2);
-            if (s->channel_mode & 1) {
-                /* if three front channels exist */
-                s->center_mix_level_ltrt = get_bits(gbc, 3);
-                s->center_mix_level      = get_bits(gbc, 3);
-            }
-            if (s->channel_mode & 4) {
-                /* if a surround channel exists */
-                s->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7);
-                s->surround_mix_level      = av_clip(get_bits(gbc, 3), 3, 7);
-            }
-        }
-
-        /* lfe mix level */
-        if (s->lfe_on && (s->lfe_mix_level_exists = get_bits1(gbc))) {
-            s->lfe_mix_level = get_bits(gbc, 5);
-        }
-
-        /* info for mixing with other streams and substreams */
-        if (s->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) {
-            for (i = 0; i < (s->channel_mode ? 1 : 2); i++) {
-                // TODO: apply program scale factor
-                if (get_bits1(gbc)) {
-                    skip_bits(gbc, 6);  // skip program scale factor
-                }
-            }
-            if (get_bits1(gbc)) {
-                skip_bits(gbc, 6);  // skip external program scale factor
-            }
-            /* skip mixing parameter data */
-            switch(get_bits(gbc, 2)) {
-                case 1: skip_bits(gbc, 5);  break;
-                case 2: skip_bits(gbc, 12); break;
-                case 3: {
-                    int mix_data_size = (get_bits(gbc, 5) + 2) << 3;
-                    skip_bits_long(gbc, mix_data_size);
-                    break;
-                }
-            }
-            /* skip pan information for mono or dual mono source */
-            if (s->channel_mode < AC3_CHMODE_STEREO) {
-                for (i = 0; i < (s->channel_mode ? 1 : 2); i++) {
-                    if (get_bits1(gbc)) {
-                        /* note: this is not in the ATSC A/52B specification
-                           reference: ETSI TS 102 366 V1.1.1
-                                      section: E.1.3.1.25 */
-                        skip_bits(gbc, 8);  // skip pan mean direction index
-                        skip_bits(gbc, 6);  // skip reserved paninfo bits
-                    }
-                }
-            }
-            /* skip mixing configuration information */
-            if (get_bits1(gbc)) {
-                for (blk = 0; blk < s->num_blocks; blk++) {
-                    if (s->num_blocks == 1 || get_bits1(gbc)) {
-                        skip_bits(gbc, 5);
-                    }
-                }
-            }
-        }
-    }
+    s->preferred_downmix       = hdr->preferred_downmix;
+    s->center_mix_level_ltrt   = hdr->center_mix_level_ltrt;
+    s->center_mix_level        = hdr->center_mix_level;
+    s->surround_mix_level_ltrt = hdr->surround_mix_level_ltrt;
+    s->surround_mix_level      = hdr->surround_mix_level;
+    s->lfe_mix_level_exists    = hdr->lfe_mix_level_exists;
+    s->lfe_mix_level           = hdr->lfe_mix_level;
+    s->dolby_surround_mode     = hdr->dolby_surround_mode;
+    s->dolby_headphone_mode    = hdr->dolby_headphone_mode;
+    s->dolby_surround_ex_mode  = hdr->dolby_surround_ex_mode;
 
     /* informational metadata */
-    if (get_bits1(gbc)) {
-        s->bitstream_mode = get_bits(gbc, 3);
-        skip_bits(gbc, 2); // skip copyright bit and original bitstream bit
-        if (s->channel_mode == AC3_CHMODE_STEREO) {
-            s->dolby_surround_mode  = get_bits(gbc, 2);
-            s->dolby_headphone_mode = get_bits(gbc, 2);
-        }
-        if (s->channel_mode >= AC3_CHMODE_2F2R) {
-            s->dolby_surround_ex_mode = get_bits(gbc, 2);
-        }
-        for (i = 0; i < (s->channel_mode ? 1 : 2); i++) {
-            if (get_bits1(gbc)) {
-                skip_bits(gbc, 8); // skip mix level, room type, and A/D converter type
-            }
-        }
-        if (s->bit_alloc_params.sr_code != EAC3_SR_CODE_REDUCED) {
-            skip_bits1(gbc); // skip source sample rate code
-        }
-    }
-
-    /* converter synchronization flag
-       If frames are less than six blocks, this bit should be turned on
-       once every 6 blocks to indicate the start of a frame set.
-       reference: RFC 4598, Section 2.1.3  Frame Sets */
-    if (s->frame_type == EAC3_FRAME_TYPE_INDEPENDENT && s->num_blocks != 6) {
-        skip_bits1(gbc); // skip converter synchronization flag
-    }
-
-    /* original frame size code if this stream was converted from AC-3 */
-    if (s->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT &&
-            (s->num_blocks == 6 || get_bits1(gbc))) {
-        skip_bits(gbc, 6); // skip frame size code
-    }
+    s->bitstream_mode = hdr->bitstream_mode;
 
     /* additional bitstream info */
-    if (get_bits1(gbc)) {
-        int addbsil = get_bits(gbc, 6);
-        for (i = 0; i < addbsil + 1; i++) {
-            if (i == 0) {
-                /* In this 8 bit chunk, the LSB is equal to flag_ec3_extension_type_a
-                   which can be used to detect Atmos presence */
-                skip_bits(gbc, 7);
-                if (get_bits1(gbc)) {
-                    s->eac3_extension_type_a = 1;
-                }
-            } else {
-                skip_bits(gbc, 8); // skip additional bit stream info
-            }
-        }
-    }
+    s->eac3_extension_type_a = hdr->eac3_extension_type_a;
 
     /* audio frame syntax flags, strategy data, and per-frame data */
 
-- 
2.49.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] [PATCH 2/3] avformat/movenc: fix writing reserved bits in EC3SpecificBox
  2025-06-05 21:49 [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header() James Almer
@ 2025-06-05 21:49 ` James Almer
  2025-06-05 22:07   ` Baptiste Coudurier
  2025-06-05 21:49 ` [FFmpeg-devel] [PATCH 3/3] avformat/movenc: handle EAC-3 extension bits for Atmos James Almer
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: James Almer @ 2025-06-05 21:49 UTC (permalink / raw)
  To: ffmpeg-devel

As described in section F.6.1 from ETSI TS 102 366.

Found-by: nyanmisaka
Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavformat/movenc.c         | 2 +-
 tests/ref/fate/copy-trac3074 | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 402611e81e..25360b004d 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -631,7 +631,7 @@ static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
         put_bits(&pbc, 3, info->substream[i].bsmod);
         put_bits(&pbc, 3, info->substream[i].acmod);
         put_bits(&pbc, 1, info->substream[i].lfeon);
-        put_bits(&pbc, 5, 0); /* reserved */
+        put_bits(&pbc, 3, 0); /* reserved */
         put_bits(&pbc, 4, info->substream[i].num_dep_sub);
         if (!info->substream[i].num_dep_sub) {
             put_bits(&pbc, 1, 0); /* reserved */
diff --git a/tests/ref/fate/copy-trac3074 b/tests/ref/fate/copy-trac3074
index 53ba27e920..9ed42c8d8d 100644
--- a/tests/ref/fate/copy-trac3074
+++ b/tests/ref/fate/copy-trac3074
@@ -1,5 +1,5 @@
-36fcc0a62695bcf93068fcfe68283ee9 *tests/data/fate/copy-trac3074.mp4
-334016 tests/data/fate/copy-trac3074.mp4
+5b4a3ed9de3b2a92e5dcb127bca12e68 *tests/data/fate/copy-trac3074.mp4
+334015 tests/data/fate/copy-trac3074.mp4
 #tb 0: 1/48000
 #media_type 0: audio
 #codec_id 0: eac3
-- 
2.49.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [FFmpeg-devel] [PATCH 3/3] avformat/movenc: handle EAC-3 extension bits for Atmos
  2025-06-05 21:49 [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header() James Almer
  2025-06-05 21:49 ` [FFmpeg-devel] [PATCH 2/3] avformat/movenc: fix writing reserved bits in EC3SpecificBox James Almer
@ 2025-06-05 21:49 ` James Almer
  2025-06-05 22:09   ` Baptiste Coudurier
  2025-06-05 22:15 ` [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header() Baptiste Coudurier
  2025-06-05 23:07 ` Andreas Rheinhardt
  3 siblings, 1 reply; 7+ messages in thread
From: James Almer @ 2025-06-05 21:49 UTC (permalink / raw)
  To: ffmpeg-devel

From: nyanmisaka <nst799610810@gmail.com>

Fixes commit #9996.

Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavformat/movenc.c | 31 +++++++++++++++----------------
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 25360b004d..b546c8b545 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -393,6 +393,10 @@ struct eac3_info {
         uint16_t chan_loc;
         /* if there is no dependent substream, then one bit reserved instead */
     } substream[1]; /* TODO: support 8 independent substreams */
+    /* indicates the enhanced AC-3 extension, 1 bit */
+    uint8_t eac3_extension_type_a;
+    /* indicates the decoding complexity, 8 bits */
+    uint8_t complexity_index_type_a;
 };
 
 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
@@ -474,6 +478,9 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
     info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
     info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
                                     hdr->ac3_bit_rate_code);
+    info->eac3_extension_type_a   = hdr->eac3_extension_type_a;
+    info->complexity_index_type_a = hdr->complexity_index_type_a;
+
     num_blocks = hdr->num_blocks;
 
     if (!info->ec3_done) {
@@ -532,8 +539,6 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
             int parent = hdr->substreamid;
 
             while (cumul_size != pkt->size) {
-                GetBitContext gbc;
-                int i;
                 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
                 if (ret < 0)
                     goto end;
@@ -544,20 +549,9 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
                 info->substream[parent].num_dep_sub++;
                 ret /= 8;
 
-                /* header is parsed up to lfeon, but custom channel map may be needed */
-                init_get_bits8(&gbc, pkt->data + cumul_size + ret, pkt->size - cumul_size - ret);
-                /* skip bsid */
-                skip_bits(&gbc, 5);
-                /* skip volume control params */
-                for (i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
-                    skip_bits(&gbc, 5); // skip dialog normalization
-                    if (get_bits1(&gbc)) {
-                        skip_bits(&gbc, 8); // skip compression gain word
-                    }
-                }
                 /* get the dependent stream channel map, if exists */
-                if (get_bits1(&gbc))
-                    info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f;
+                if (hdr->channel_map_present)
+                    info->substream[parent].chan_loc |= (hdr->channel_map >> 5) & 0x1f;
                 else
                     info->substream[parent].chan_loc |= hdr->channel_mode;
                 cumul_size += hdr->frame_size;
@@ -614,7 +608,7 @@ static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
     }
 
     info = track->eac3_priv;
-    size = 2 + ((34 * (info->num_ind_sub + 1) + 7) >> 3);
+    size = 2 + ((32 * (info->num_ind_sub + 1) + 7 + 1 + 8) >> 3);
     buf = av_malloc(size);
     if (!buf) {
         return AVERROR(ENOMEM);
@@ -639,6 +633,11 @@ static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
             put_bits(&pbc, 9, info->substream[i].chan_loc);
         }
     }
+    if (info->eac3_extension_type_a == 1) {
+        put_bits(&pbc, 7, 0); /* reserved */
+        put_bits(&pbc, 1, info->eac3_extension_type_a);
+        put_bits(&pbc, 8, info->complexity_index_type_a);
+    }
     flush_put_bits(&pbc);
     size = put_bytes_output(&pbc);
 
-- 
2.49.0

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH 2/3] avformat/movenc: fix writing reserved bits in EC3SpecificBox
  2025-06-05 21:49 ` [FFmpeg-devel] [PATCH 2/3] avformat/movenc: fix writing reserved bits in EC3SpecificBox James Almer
@ 2025-06-05 22:07   ` Baptiste Coudurier
  0 siblings, 0 replies; 7+ messages in thread
From: Baptiste Coudurier @ 2025-06-05 22:07 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Hi James

> On Jun 5, 2025, at 2:49 PM, James Almer <jamrial@gmail.com> wrote:
> 
> As described in section F.6.1 from ETSI TS 102 366.
> 
> Found-by: nyanmisaka
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
> libavformat/movenc.c         | 2 +-
> tests/ref/fate/copy-trac3074 | 4 ++--
> 2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index 402611e81e..25360b004d 100644
> --- a/libavformat/movenc.c
> +++ b/libavformat/movenc.c
> @@ -631,7 +631,7 @@ static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
>         put_bits(&pbc, 3, info->substream[i].bsmod);
>         put_bits(&pbc, 3, info->substream[i].acmod);
>         put_bits(&pbc, 1, info->substream[i].lfeon);
> -        put_bits(&pbc, 5, 0); /* reserved */
> +        put_bits(&pbc, 3, 0); /* reserved */
>         put_bits(&pbc, 4, info->substream[i].num_dep_sub);
>         if (!info->substream[i].num_dep_sub) {
>             put_bits(&pbc, 1, 0); /* reserved */
> diff --git a/tests/ref/fate/copy-trac3074 b/tests/ref/fate/copy-trac3074
> index 53ba27e920..9ed42c8d8d 100644
> --- a/tests/ref/fate/copy-trac3074
> +++ b/tests/ref/fate/copy-trac3074
> @@ -1,5 +1,5 @@
> -36fcc0a62695bcf93068fcfe68283ee9 *tests/data/fate/copy-trac3074.mp4
> -334016 tests/data/fate/copy-trac3074.mp4
> +5b4a3ed9de3b2a92e5dcb127bca12e68 *tests/data/fate/copy-trac3074.mp4
> +334015 tests/data/fate/copy-trac3074.mp4
> #tb 0: 1/48000
> #media_type 0: audio
> #codec_id 0: eac3

Yes, I actually just noticed that :)

— 
Baptiste
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH 3/3] avformat/movenc: handle EAC-3 extension bits for Atmos
  2025-06-05 21:49 ` [FFmpeg-devel] [PATCH 3/3] avformat/movenc: handle EAC-3 extension bits for Atmos James Almer
@ 2025-06-05 22:09   ` Baptiste Coudurier
  0 siblings, 0 replies; 7+ messages in thread
From: Baptiste Coudurier @ 2025-06-05 22:09 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


> On Jun 5, 2025, at 2:49 PM, James Almer <jamrial@gmail.com> wrote:
> 
> From: nyanmisaka <nst799610810@gmail.com>
> 
> Fixes commit #9996.
> 
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
> libavformat/movenc.c | 31 +++++++++++++++----------------
> 1 file changed, 15 insertions(+), 16 deletions(-)
> 
> diff --git a/libavformat/movenc.c b/libavformat/movenc.c
> index 25360b004d..b546c8b545 100644
> --- a/libavformat/movenc.c
> +++ b/libavformat/movenc.c
> @@ -393,6 +393,10 @@ struct eac3_info {
>         uint16_t chan_loc;
>         /* if there is no dependent substream, then one bit reserved instead */
>     } substream[1]; /* TODO: support 8 independent substreams */
> +    /* indicates the enhanced AC-3 extension, 1 bit */
> +    uint8_t eac3_extension_type_a;
> +    /* indicates the decoding complexity, 8 bits */
> +    uint8_t complexity_index_type_a;
> };

I think we only need complexity_index_type_a, if it’s 0 it’s not necessary

> 
> static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
> @@ -474,6 +478,9 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
>     info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
>     info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
>                                     hdr->ac3_bit_rate_code);
> +    info->eac3_extension_type_a   = hdr->eac3_extension_type_a;
> +    info->complexity_index_type_a = hdr->complexity_index_type_a;
> +
>     num_blocks = hdr->num_blocks;
> 
>     if (!info->ec3_done) {
> @@ -532,8 +539,6 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
>             int parent = hdr->substreamid;
> 
>             while (cumul_size != pkt->size) {
> -                GetBitContext gbc;
> -                int i;
>                 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
>                 if (ret < 0)
>                     goto end;
> @@ -544,20 +549,9 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
>                 info->substream[parent].num_dep_sub++;
>                 ret /= 8;
> 
> -                /* header is parsed up to lfeon, but custom channel map may be needed */
> -                init_get_bits8(&gbc, pkt->data + cumul_size + ret, pkt->size - cumul_size - ret);
> -                /* skip bsid */
> -                skip_bits(&gbc, 5);
> -                /* skip volume control params */
> -                for (i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
> -                    skip_bits(&gbc, 5); // skip dialog normalization
> -                    if (get_bits1(&gbc)) {
> -                        skip_bits(&gbc, 8); // skip compression gain word
> -                    }
> -                }
>                 /* get the dependent stream channel map, if exists */
> -                if (get_bits1(&gbc))
> -                    info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f;
> +                if (hdr->channel_map_present)
> +                    info->substream[parent].chan_loc |= (hdr->channel_map >> 5) & 0x1f;

Beautiful cleanup

>                 else
>                     info->substream[parent].chan_loc |= hdr->channel_mode;
>                 cumul_size += hdr->frame_size;
> @@ -614,7 +608,7 @@ static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
>     }
> 
>     info = track->eac3_priv;
> -    size = 2 + ((34 * (info->num_ind_sub + 1) + 7) >> 3);
> +    size = 2 + ((32 * (info->num_ind_sub + 1) + 7 + 1 + 8) >> 3);

Let’s just make it optional on complexity_type_a

— 
Baptiste
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header()
  2025-06-05 21:49 [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header() James Almer
  2025-06-05 21:49 ` [FFmpeg-devel] [PATCH 2/3] avformat/movenc: fix writing reserved bits in EC3SpecificBox James Almer
  2025-06-05 21:49 ` [FFmpeg-devel] [PATCH 3/3] avformat/movenc: handle EAC-3 extension bits for Atmos James Almer
@ 2025-06-05 22:15 ` Baptiste Coudurier
  2025-06-05 23:07 ` Andreas Rheinhardt
  3 siblings, 0 replies; 7+ messages in thread
From: Baptiste Coudurier @ 2025-06-05 22:15 UTC (permalink / raw)
  To: FFmpeg development discussions and patches


> On Jun 5, 2025, at 2:49 PM, James Almer <jamrial@gmail.com> wrote:
> 
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
> 
> diff --git a/libavcodec/ac3_parser_internal.h b/libavcodec/ac3_parser_internal.h
> index 46814bfb1f..ab5df34003 100644
> --- a/libavcodec/ac3_parser_internal.h
> +++ b/libavcodec/ac3_parser_internal.h
> @@ -46,6 +46,7 @@ typedef struct AC3HeaderInfo {
>     int substreamid;                        ///< substream identification
>     int center_mix_level;                   ///< Center mix level index
>     int surround_mix_level;                 ///< Surround mix level index
> +    uint8_t channel_map_present;
>     uint16_t channel_map;
>     int num_blocks;                         ///< number of audio blocks
>     int dolby_surround_mode;

Am I missing something or this field is not set anywhere ?

Otherwise it looks great :)

— 
Baptiste
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header()
  2025-06-05 21:49 [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header() James Almer
                   ` (2 preceding siblings ...)
  2025-06-05 22:15 ` [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header() Baptiste Coudurier
@ 2025-06-05 23:07 ` Andreas Rheinhardt
  3 siblings, 0 replies; 7+ messages in thread
From: Andreas Rheinhardt @ 2025-06-05 23:07 UTC (permalink / raw)
  To: ffmpeg-devel

James Almer:
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
>  libavcodec/ac3_parser.c          | 218 +++++++++++++++++++++++++++++++
>  libavcodec/ac3_parser_internal.h |  19 +++
>  libavcodec/ac3dec.c              |  88 +++----------
>  libavcodec/ac3dec.h              |   4 +-
>  libavcodec/ac3defs.h             |   2 +
>  libavcodec/eac3dec.c             | 154 +++-------------------
>  6 files changed, 279 insertions(+), 206 deletions(-)
> 
> diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c
> index 69989690dd..1cba847eaa 100644
> --- a/libavcodec/ac3_parser.c
> +++ b/libavcodec/ac3_parser.c
> @@ -73,6 +73,216 @@ int ff_ac3_find_syncword(const uint8_t *buf, int buf_size)
>      return i;
>  }
>  
> +/**
> + * Parse the 'sync info' and 'bit stream info' from the AC-3 bitstream.
> + * GetBitContext within AC3DecodeContext must point to
> + * the start of the synchronized AC-3 bitstream.
> + */
> +static int ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
> +{
> +    /* read the rest of the bsi. read twice for dual mono mode. */
> +    for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
> +        hdr->dialog_normalization[i] = -get_bits(gbc, 5);
> +        hdr->compression_exists[i] = get_bits1(gbc);
> +        if (hdr->compression_exists[i])
> +            hdr->heavy_dynamic_range[i] = get_bits(gbc, 8);
> +        if (get_bits1(gbc))
> +            skip_bits(gbc, 8); //skip language code
> +        if (get_bits1(gbc))
> +            skip_bits(gbc, 7); //skip audio production information
> +    }
> +
> +    skip_bits(gbc, 2); //skip copyright bit and original bitstream bit
> +
> +    /* skip the timecodes or parse the Alternate Bit Stream Syntax */
> +    if (hdr->bitstream_id != 6) {
> +        if (get_bits1(gbc))
> +            skip_bits(gbc, 14); //skip timecode1
> +        if (get_bits1(gbc))
> +            skip_bits(gbc, 14); //skip timecode2
> +    } else {
> +        if (get_bits1(gbc)) {
> +            hdr->preferred_downmix       = get_bits(gbc, 2);
> +            hdr->center_mix_level_ltrt   = get_bits(gbc, 3);
> +            hdr->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7);
> +            hdr->center_mix_level        = get_bits(gbc, 3);
> +            hdr->surround_mix_level      = av_clip(get_bits(gbc, 3), 3, 7);
> +        }
> +        if (get_bits1(gbc)) {
> +            hdr->dolby_surround_ex_mode = get_bits(gbc, 2);
> +            hdr->dolby_headphone_mode   = get_bits(gbc, 2);
> +            skip_bits(gbc, 10); // skip adconvtyp (1), xbsi2 (8), encinfo (1)
> +        }
> +    }
> +
> +    /* skip additional bitstream info */
> +    if (get_bits1(gbc)) {
> +        int i = get_bits(gbc, 6);
> +        do {
> +            skip_bits(gbc, 8);
> +        } while (i--);
> +    }
> +
> +    return 0;
> +}
> +
> +static int eac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
> +{
> +    if (hdr->frame_type == EAC3_FRAME_TYPE_RESERVED)
> +        return AC3_PARSE_ERROR_FRAME_TYPE;
> +    if (hdr->substreamid)
> +        return AC3_PARSE_ERROR_FRAME_TYPE;
> +
> +    skip_bits(gbc, 5); // skip bitstream id
> +
> +    /* volume control params */
> +    for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
> +        hdr->dialog_normalization[i] = -get_bits(gbc, 5);
> +        hdr->compression_exists[i] = get_bits1(gbc);
> +        if (hdr->compression_exists[i])
> +            hdr->heavy_dynamic_range[i] = get_bits(gbc, 8);
> +    }
> +
> +    /* dependent stream channel map */
> +    if (hdr->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
> +        if (get_bits1(gbc)) {
> +            int64_t channel_layout = 0;
> +            int channel_map = get_bits(gbc, 16);
> +
> +            for (int i = 0; i < 16; i++)
> +                if (channel_map & (1 << (EAC3_MAX_CHANNELS - i - 1)))
> +                    channel_layout |= ff_eac3_custom_channel_map_locations[i][1];
> +
> +            if (av_popcount64(channel_layout) > EAC3_MAX_CHANNELS) {
> +                return AC3_PARSE_ERROR_CHANNEL_MAP;
> +            }
> +            hdr->channel_map = channel_map;
> +        }
> +    }
> +
> +    /* mixing metadata */
> +    if (get_bits1(gbc)) {
> +        /* center and surround mix levels */
> +        if (hdr->channel_mode > AC3_CHMODE_STEREO) {
> +            hdr->preferred_downmix = get_bits(gbc, 2);
> +            if (hdr->channel_mode & 1) {
> +                /* if three front channels exist */
> +                hdr->center_mix_level_ltrt = get_bits(gbc, 3);
> +                hdr->center_mix_level      = get_bits(gbc, 3);
> +            }
> +            if (hdr->channel_mode & 4) {
> +                /* if a surround channel exists */
> +                hdr->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7);
> +                hdr->surround_mix_level      = av_clip(get_bits(gbc, 3), 3, 7);
> +            }
> +        }
> +
> +        /* lfe mix level */
> +        if (hdr->lfe_on && (hdr->lfe_mix_level_exists = get_bits1(gbc))) {
> +            hdr->lfe_mix_level = get_bits(gbc, 5);
> +        }
> +
> +        /* info for mixing with other streams and substreams */
> +        if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) {
> +            for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
> +                // TODO: apply program scale factor
> +                if (get_bits1(gbc)) {
> +                    skip_bits(gbc, 6);  // skip program scale factor
> +                }
> +            }
> +            if (get_bits1(gbc)) {
> +                skip_bits(gbc, 6);  // skip external program scale factor
> +            }
> +            /* skip mixing parameter data */
> +            switch(get_bits(gbc, 2)) {
> +                case 1: skip_bits(gbc, 5);  break;
> +                case 2: skip_bits(gbc, 12); break;
> +                case 3: {
> +                    int mix_data_size = (get_bits(gbc, 5) + 2) << 3;
> +                    skip_bits_long(gbc, mix_data_size);
> +                    break;
> +                }
> +            }
> +            /* skip pan information for mono or dual mono source */
> +            if (hdr->channel_mode < AC3_CHMODE_STEREO) {
> +                for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
> +                    if (get_bits1(gbc)) {
> +                        /* note: this is not in the ATSC A/52B specification
> +                           reference: ETSI TS 102 366 V1.1.1
> +                                      section: E.1.3.1.25 */
> +                        skip_bits(gbc, 8);  // skip pan mean direction index
> +                        skip_bits(gbc, 6);  // skip reserved paninfo bits
> +                    }
> +                }
> +            }
> +            /* skip mixing configuration information */
> +            if (get_bits1(gbc)) {
> +                for (int i = 0; i < hdr->num_blocks; i++) {
> +                    if (hdr->num_blocks == 1 || get_bits1(gbc)) {
> +                        skip_bits(gbc, 5);
> +                    }
> +                }
> +            }
> +        }
> +    }
> +
> +    /* informational metadata */
> +    if (get_bits1(gbc)) {
> +        hdr->bitstream_mode = get_bits(gbc, 3);
> +        skip_bits(gbc, 2); // skip copyright bit and original bitstream bit
> +        if (hdr->channel_mode == AC3_CHMODE_STEREO) {
> +            hdr->dolby_surround_mode  = get_bits(gbc, 2);
> +            hdr->dolby_headphone_mode = get_bits(gbc, 2);
> +        }
> +        if (hdr->channel_mode >= AC3_CHMODE_2F2R) {
> +            hdr->dolby_surround_ex_mode = get_bits(gbc, 2);
> +        }
> +        for (int i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
> +            if (get_bits1(gbc)) {
> +                skip_bits(gbc, 8); // skip mix level, room type, and A/D converter type
> +            }
> +        }
> +        if (hdr->sr_code != EAC3_SR_CODE_REDUCED) {
> +            skip_bits1(gbc); // skip source sample rate code
> +        }
> +    }
> +
> +    /* converter synchronization flag
> +       If frames are less than six blocks, this bit should be turned on
> +       once every 6 blocks to indicate the start of a frame set.
> +       reference: RFC 4598, Section 2.1.3  Frame Sets */
> +    if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT && hdr->num_blocks != 6) {
> +        skip_bits1(gbc); // skip converter synchronization flag
> +    }
> +
> +    /* original frame size code if this stream was converted from AC-3 */
> +    if (hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT &&
> +            (hdr->num_blocks == 6 || get_bits1(gbc))) {
> +        skip_bits(gbc, 6); // skip frame size code
> +    }
> +
> +    /* additional bitstream info */
> +    if (get_bits1(gbc)) {
> +        int addbsil = get_bits(gbc, 6);
> +        for (int i = 0; i < addbsil + 1; i++) {
> +            if (i == 0) {
> +                /* In this 8 bit chunk, the LSB is equal to flag_ec3_extension_type_a
> +                   which can be used to detect Atmos presence */
> +                skip_bits(gbc, 7);
> +                hdr->eac3_extension_type_a = get_bits1(gbc);
> +                if (hdr->eac3_extension_type_a) {
> +                    hdr->complexity_index_type_a = get_bits(gbc, 8);
> +                    i++;
> +                }
> +            } else {
> +                skip_bits(gbc, 8); // skip additional bit stream info
> +            }
> +        }
> +    }
> +
> +    return 0;
> +}
> +
>  int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
>  {
>      int frame_size_code;
> @@ -133,6 +343,10 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
>          hdr->frame_size = ff_ac3_frame_size_tab[frame_size_code][hdr->sr_code] * 2;
>          hdr->frame_type = EAC3_FRAME_TYPE_AC3_CONVERT; //EAC3_FRAME_TYPE_INDEPENDENT;
>          hdr->substreamid = 0;
> +
> +        int ret = ac3_parse_header(gbc, hdr);
> +        if (ret < 0)
> +            return ret;
>      } else {
>          /* Enhanced AC-3 */
>          hdr->crc1 = 0;
> @@ -165,6 +379,10 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
>          hdr->bit_rate = 8LL * hdr->frame_size * hdr->sample_rate /
>                          (hdr->num_blocks * 256);
>          hdr->channels = ff_ac3_channels_tab[hdr->channel_mode] + hdr->lfe_on;
> +
> +        int ret = eac3_parse_header(gbc, hdr);
> +        if (ret < 0)
> +            return ret;
>      }
>      hdr->channel_layout = ff_ac3_channel_layout_tab[hdr->channel_mode];
>      if (hdr->lfe_on)
> diff --git a/libavcodec/ac3_parser_internal.h b/libavcodec/ac3_parser_internal.h
> index 46814bfb1f..ab5df34003 100644
> --- a/libavcodec/ac3_parser_internal.h
> +++ b/libavcodec/ac3_parser_internal.h
> @@ -46,6 +46,7 @@ typedef struct AC3HeaderInfo {
>      int substreamid;                        ///< substream identification
>      int center_mix_level;                   ///< Center mix level index
>      int surround_mix_level;                 ///< Surround mix level index
> +    uint8_t channel_map_present;
>      uint16_t channel_map;
>      int num_blocks;                         ///< number of audio blocks
>      int dolby_surround_mode;
> @@ -62,6 +63,23 @@ typedef struct AC3HeaderInfo {
>      uint64_t channel_layout;
>      int8_t ac3_bit_rate_code;
>      /** @} */
> +
> +    /** @name enhanced eac3 extension coded elements
> +     * @{
> +     */
> +    int8_t dialog_normalization[2];
> +    uint8_t compression_exists[2];
> +    uint8_t heavy_dynamic_range[2];
> +    uint8_t center_mix_level_ltrt;              ///< Center mix level index
> +    uint8_t surround_mix_level_ltrt;            ///< Surround mix level index
> +    uint8_t dolby_headphone_mode;
> +    uint8_t dolby_surround_ex_mode;
> +    uint8_t lfe_mix_level_exists;
> +    uint8_t lfe_mix_level;
> +    uint8_t preferred_downmix;
> +    uint8_t eac3_extension_type_a;
> +    uint8_t complexity_index_type_a;
> +    /** @} */
>  } AC3HeaderInfo;
>  
>  typedef enum {
> @@ -71,6 +89,7 @@ typedef enum {
>      AC3_PARSE_ERROR_FRAME_SIZE  = -0x4030c0a,
>      AC3_PARSE_ERROR_FRAME_TYPE  = -0x5030c0a,
>      AC3_PARSE_ERROR_CRC         = -0x6030c0a,
> +    AC3_PARSE_ERROR_CHANNEL_MAP = -0x7030c0a,
>  } AC3ParseError;
>  
>  /**
> diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
> index 5eacab4475..2f0e7f5344 100644
> --- a/libavcodec/ac3dec.c
> +++ b/libavcodec/ac3dec.c
> @@ -156,72 +156,6 @@ static av_cold void ac3_decode_flush(AVCodecContext *avctx)
>      av_lfg_init(&s->dith_state, 0);
>  }
>  
> -/**
> - * Parse the 'sync info' and 'bit stream info' from the AC-3 bitstream.
> - * GetBitContext within AC3DecodeContext must point to
> - * the start of the synchronized AC-3 bitstream.
> - */
> -static int ac3_parse_header(AC3DecodeContext *s)
> -{
> -    GetBitContext *gbc = &s->gbc;
> -    int i;
> -
> -    /* read the rest of the bsi. read twice for dual mono mode. */
> -    i = !s->channel_mode;
> -    do {
> -        s->dialog_normalization[(!s->channel_mode)-i] = -get_bits(gbc, 5);
> -        if (s->dialog_normalization[(!s->channel_mode)-i] == 0) {
> -            s->dialog_normalization[(!s->channel_mode)-i] = -31;
> -        }
> -        if (s->target_level != 0) {
> -            s->level_gain[(!s->channel_mode)-i] = powf(2.0f,
> -                (float)(s->target_level -
> -                s->dialog_normalization[(!s->channel_mode)-i])/6.0f);
> -        }
> -        if (s->compression_exists[(!s->channel_mode)-i] = get_bits1(gbc)) {
> -            s->heavy_dynamic_range[(!s->channel_mode)-i] =
> -                AC3_HEAVY_RANGE(get_bits(gbc, 8));
> -        }
> -        if (get_bits1(gbc))
> -            skip_bits(gbc, 8); //skip language code
> -        if (get_bits1(gbc))
> -            skip_bits(gbc, 7); //skip audio production information
> -    } while (i--);
> -
> -    skip_bits(gbc, 2); //skip copyright bit and original bitstream bit
> -
> -    /* skip the timecodes or parse the Alternate Bit Stream Syntax */
> -    if (s->bitstream_id != 6) {
> -        if (get_bits1(gbc))
> -            skip_bits(gbc, 14); //skip timecode1
> -        if (get_bits1(gbc))
> -            skip_bits(gbc, 14); //skip timecode2
> -    } else {
> -        if (get_bits1(gbc)) {
> -            s->preferred_downmix       = get_bits(gbc, 2);
> -            s->center_mix_level_ltrt   = get_bits(gbc, 3);
> -            s->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7);
> -            s->center_mix_level        = get_bits(gbc, 3);
> -            s->surround_mix_level      = av_clip(get_bits(gbc, 3), 3, 7);
> -        }
> -        if (get_bits1(gbc)) {
> -            s->dolby_surround_ex_mode = get_bits(gbc, 2);
> -            s->dolby_headphone_mode   = get_bits(gbc, 2);
> -            skip_bits(gbc, 10); // skip adconvtyp (1), xbsi2 (8), encinfo (1)
> -        }
> -    }
> -
> -    /* skip additional bitstream info */
> -    if (get_bits1(gbc)) {
> -        i = get_bits(gbc, 6);
> -        do {
> -            skip_bits(gbc, 8);
> -        } while (i--);
> -    }
> -
> -    return 0;
> -}
> -
>  /**
>   * Common function to parse AC-3 or E-AC-3 frame header
>   */
> @@ -281,10 +215,25 @@ static int parse_frame_header(AC3DecodeContext *s)
>          s->dba_syntax            = 1;
>          s->skip_syntax           = 1;
>          memset(s->channel_uses_aht, 0, sizeof(s->channel_uses_aht));
> -        return ac3_parse_header(s);
> +        /* volume control params */
> +        for (int i = 0; i < (s->channel_mode ? 1 : 2); i++) {
> +            s->dialog_normalization[i] = hdr.dialog_normalization[i];
> +            if (s->dialog_normalization[i] == 0) {
> +                s->dialog_normalization[i] = -31;
> +            }
> +            if (s->target_level != 0) {
> +                s->level_gain[i] = powf(2.0f,
> +                    (float)(s->target_level - s->dialog_normalization[i])/6.0f);
> +            }
> +            s->compression_exists[i] = hdr.compression_exists[i];
> +            if (s->compression_exists[i]) {
> +                s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(hdr.heavy_dynamic_range[i]);
> +            }
> +        }
> +        return 0;
>      } else if (CONFIG_EAC3_DECODER) {
>          s->eac3 = 1;
> -        return ff_eac3_parse_header(s);
> +        return ff_eac3_parse_header(s, &hdr);
>      } else {
>          av_log(s->avctx, AV_LOG_ERROR, "E-AC-3 support not compiled in\n");
>          return AVERROR(ENOSYS);
> @@ -1469,6 +1418,9 @@ dependent_frame:
>                  av_log(avctx, AV_LOG_ERROR, "invalid frame type\n");
>              }
>              break;
> +        case AC3_PARSE_ERROR_CHANNEL_MAP:
> +            av_log(avctx, AV_LOG_ERROR, "invalid channel map\n");
> +            return AVERROR_INVALIDDATA;
>          case AC3_PARSE_ERROR_CRC:
>              break;
>          default: // Normal AVERROR do not try to recover.
> diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
> index 4042a99b80..a099264475 100644
> --- a/libavcodec/ac3dec.h
> +++ b/libavcodec/ac3dec.h
> @@ -260,11 +260,13 @@ typedef struct AC3DecodeContext {
>  ///@}
>  } AC3DecodeContext;
>  
> +struct AC3HeaderInfo;
> +
>  /**
>   * Parse the E-AC-3 frame header.
>   * This parses both the bit stream info and audio frame header.
>   */
> -static int ff_eac3_parse_header(AC3DecodeContext *s);
> +static int ff_eac3_parse_header(AC3DecodeContext *s, const struct AC3HeaderInfo *hdr);
>  
>  /**
>   * Decode mantissas in a single channel for the entire frame.
> diff --git a/libavcodec/ac3defs.h b/libavcodec/ac3defs.h
> index f9b1be059f..8d6a58d21f 100644
> --- a/libavcodec/ac3defs.h
> +++ b/libavcodec/ac3defs.h
> @@ -34,6 +34,8 @@
>  #define AC3_CRITICAL_BANDS 50
>  #define AC3_MAX_CPL_BANDS  18
>  
> +#define EAC3_SR_CODE_REDUCED 3
> +
>  /* pre-defined gain values */
>  #define LEVEL_PLUS_3DB          M_SQRT2
>  #define LEVEL_PLUS_1POINT5DB    1.1892071150027209
> diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c
> index 2b3bffda6e..c5095b1917 100644
> --- a/libavcodec/eac3dec.c
> +++ b/libavcodec/eac3dec.c
> @@ -53,8 +53,6 @@ typedef enum {
>      EAC3_GAQ_124
>  } EAC3GaqMode;
>  
> -#define EAC3_SR_CODE_REDUCED  3
> -
>  static void ff_eac3_apply_spectral_extension(AC3DecodeContext *s)
>  {
>      int bin, bnd, ch, i;
> @@ -287,7 +285,7 @@ static void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch)
>      }
>  }
>  
> -static int ff_eac3_parse_header(AC3DecodeContext *s)
> +static int ff_eac3_parse_header(AC3DecodeContext *s, const AC3HeaderInfo *hdr)
>  {
>      int i, blk, ch;
>      int ac3_exponent_strategy, parse_aht_info, parse_spx_atten_data;
> @@ -323,11 +321,10 @@ static int ff_eac3_parse_header(AC3DecodeContext *s)
>          avpriv_request_sample(s->avctx, "Reduced sampling rate");
>          return AVERROR_PATCHWELCOME;
>      }
> -    skip_bits(gbc, 5); // skip bitstream id
>  
>      /* volume control params */
>      for (i = 0; i < (s->channel_mode ? 1 : 2); i++) {
> -        s->dialog_normalization[i] = -get_bits(gbc, 5);
> +        s->dialog_normalization[i] = hdr->dialog_normalization[i];
>          if (s->dialog_normalization[i] == 0) {
>              s->dialog_normalization[i] = -31;
>          }
> @@ -335,147 +332,30 @@ static int ff_eac3_parse_header(AC3DecodeContext *s)
>              s->level_gain[i] = powf(2.0f,
>                  (float)(s->target_level - s->dialog_normalization[i])/6.0f);
>          }
> -        s->compression_exists[i] = get_bits1(gbc);
> -        if (s->compression_exists[i]) {
> -            s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(get_bits(gbc, 8));
> +        if (hdr->compression_exists[i]) {
> +            s->heavy_dynamic_range[i] = AC3_HEAVY_RANGE(hdr->heavy_dynamic_range[i]);
>          }
>      }
>  
> -    /* dependent stream channel map */
> -    if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
> -        if (get_bits1(gbc)) {
> -            int64_t channel_layout = 0;
> -            int channel_map = get_bits(gbc, 16);
> -            av_log(s->avctx, AV_LOG_DEBUG, "channel_map: %0X\n", channel_map);
> -
> -            for (i = 0; i < 16; i++)
> -                if (channel_map & (1 << (EAC3_MAX_CHANNELS - i - 1)))
> -                    channel_layout |= ff_eac3_custom_channel_map_locations[i][1];
> -
> -            if (av_popcount64(channel_layout) > EAC3_MAX_CHANNELS) {
> -                return AVERROR_INVALIDDATA;
> -            }
> -            s->channel_map = channel_map;
> -        }
> -    }
> +    s->channel_map = hdr->channel_map;
>  
>      /* mixing metadata */
> -    if (get_bits1(gbc)) {
> -        /* center and surround mix levels */
> -        if (s->channel_mode > AC3_CHMODE_STEREO) {
> -            s->preferred_downmix = get_bits(gbc, 2);
> -            if (s->channel_mode & 1) {
> -                /* if three front channels exist */
> -                s->center_mix_level_ltrt = get_bits(gbc, 3);
> -                s->center_mix_level      = get_bits(gbc, 3);
> -            }
> -            if (s->channel_mode & 4) {
> -                /* if a surround channel exists */
> -                s->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7);
> -                s->surround_mix_level      = av_clip(get_bits(gbc, 3), 3, 7);
> -            }
> -        }
> -
> -        /* lfe mix level */
> -        if (s->lfe_on && (s->lfe_mix_level_exists = get_bits1(gbc))) {
> -            s->lfe_mix_level = get_bits(gbc, 5);
> -        }
> -
> -        /* info for mixing with other streams and substreams */
> -        if (s->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) {
> -            for (i = 0; i < (s->channel_mode ? 1 : 2); i++) {
> -                // TODO: apply program scale factor
> -                if (get_bits1(gbc)) {
> -                    skip_bits(gbc, 6);  // skip program scale factor
> -                }
> -            }
> -            if (get_bits1(gbc)) {
> -                skip_bits(gbc, 6);  // skip external program scale factor
> -            }
> -            /* skip mixing parameter data */
> -            switch(get_bits(gbc, 2)) {
> -                case 1: skip_bits(gbc, 5);  break;
> -                case 2: skip_bits(gbc, 12); break;
> -                case 3: {
> -                    int mix_data_size = (get_bits(gbc, 5) + 2) << 3;
> -                    skip_bits_long(gbc, mix_data_size);
> -                    break;
> -                }
> -            }
> -            /* skip pan information for mono or dual mono source */
> -            if (s->channel_mode < AC3_CHMODE_STEREO) {
> -                for (i = 0; i < (s->channel_mode ? 1 : 2); i++) {
> -                    if (get_bits1(gbc)) {
> -                        /* note: this is not in the ATSC A/52B specification
> -                           reference: ETSI TS 102 366 V1.1.1
> -                                      section: E.1.3.1.25 */
> -                        skip_bits(gbc, 8);  // skip pan mean direction index
> -                        skip_bits(gbc, 6);  // skip reserved paninfo bits
> -                    }
> -                }
> -            }
> -            /* skip mixing configuration information */
> -            if (get_bits1(gbc)) {
> -                for (blk = 0; blk < s->num_blocks; blk++) {
> -                    if (s->num_blocks == 1 || get_bits1(gbc)) {
> -                        skip_bits(gbc, 5);
> -                    }
> -                }
> -            }
> -        }
> -    }
> +    s->preferred_downmix       = hdr->preferred_downmix;
> +    s->center_mix_level_ltrt   = hdr->center_mix_level_ltrt;
> +    s->center_mix_level        = hdr->center_mix_level;
> +    s->surround_mix_level_ltrt = hdr->surround_mix_level_ltrt;
> +    s->surround_mix_level      = hdr->surround_mix_level;
> +    s->lfe_mix_level_exists    = hdr->lfe_mix_level_exists;
> +    s->lfe_mix_level           = hdr->lfe_mix_level;
> +    s->dolby_surround_mode     = hdr->dolby_surround_mode;
> +    s->dolby_headphone_mode    = hdr->dolby_headphone_mode;
> +    s->dolby_surround_ex_mode  = hdr->dolby_surround_ex_mode;
>  
>      /* informational metadata */
> -    if (get_bits1(gbc)) {
> -        s->bitstream_mode = get_bits(gbc, 3);
> -        skip_bits(gbc, 2); // skip copyright bit and original bitstream bit
> -        if (s->channel_mode == AC3_CHMODE_STEREO) {
> -            s->dolby_surround_mode  = get_bits(gbc, 2);
> -            s->dolby_headphone_mode = get_bits(gbc, 2);
> -        }
> -        if (s->channel_mode >= AC3_CHMODE_2F2R) {
> -            s->dolby_surround_ex_mode = get_bits(gbc, 2);
> -        }
> -        for (i = 0; i < (s->channel_mode ? 1 : 2); i++) {
> -            if (get_bits1(gbc)) {
> -                skip_bits(gbc, 8); // skip mix level, room type, and A/D converter type
> -            }
> -        }
> -        if (s->bit_alloc_params.sr_code != EAC3_SR_CODE_REDUCED) {
> -            skip_bits1(gbc); // skip source sample rate code
> -        }
> -    }
> -
> -    /* converter synchronization flag
> -       If frames are less than six blocks, this bit should be turned on
> -       once every 6 blocks to indicate the start of a frame set.
> -       reference: RFC 4598, Section 2.1.3  Frame Sets */
> -    if (s->frame_type == EAC3_FRAME_TYPE_INDEPENDENT && s->num_blocks != 6) {
> -        skip_bits1(gbc); // skip converter synchronization flag
> -    }
> -
> -    /* original frame size code if this stream was converted from AC-3 */
> -    if (s->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT &&
> -            (s->num_blocks == 6 || get_bits1(gbc))) {
> -        skip_bits(gbc, 6); // skip frame size code
> -    }
> +    s->bitstream_mode = hdr->bitstream_mode;
>  
>      /* additional bitstream info */
> -    if (get_bits1(gbc)) {
> -        int addbsil = get_bits(gbc, 6);
> -        for (i = 0; i < addbsil + 1; i++) {
> -            if (i == 0) {
> -                /* In this 8 bit chunk, the LSB is equal to flag_ec3_extension_type_a
> -                   which can be used to detect Atmos presence */
> -                skip_bits(gbc, 7);
> -                if (get_bits1(gbc)) {
> -                    s->eac3_extension_type_a = 1;
> -                }
> -            } else {
> -                skip_bits(gbc, 8); // skip additional bit stream info
> -            }
> -        }
> -    }
> +    s->eac3_extension_type_a = hdr->eac3_extension_type_a;
>  
>      /* audio frame syntax flags, strategy data, and per-frame data */
>  

Seems like av_ac3_parse_header() simply presumes the buffer to be padded
(like av_adts_header_parse() until 6c812a80ddfadb), although this is not
a documented requirement. Your patch will make it worse, because it
parses more.

- Andreas

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-06-05 23:07 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-06-05 21:49 [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header() James Almer
2025-06-05 21:49 ` [FFmpeg-devel] [PATCH 2/3] avformat/movenc: fix writing reserved bits in EC3SpecificBox James Almer
2025-06-05 22:07   ` Baptiste Coudurier
2025-06-05 21:49 ` [FFmpeg-devel] [PATCH 3/3] avformat/movenc: handle EAC-3 extension bits for Atmos James Almer
2025-06-05 22:09   ` Baptiste Coudurier
2025-06-05 22:15 ` [FFmpeg-devel] [PATCH 1/3] avcodec/ac3_parser: handle more header bits in ff_ac3_parse_header() Baptiste Coudurier
2025-06-05 23:07 ` Andreas Rheinhardt

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git