[FFmpeg-devel] [DEMO][PATCH] avcodec/eac3: add support for dependent stream

Paul B Mahol onemda at gmail.com
Mon Mar 26 23:18:08 EEST 2018


Signed-off-by: Paul B Mahol <onemda at gmail.com>
---

Need proper channel mapping support.

 libavcodec/aac_ac3_parser.c |  7 ++--
 libavcodec/aac_ac3_parser.h |  2 ++
 libavcodec/ac3_parser.c     | 29 +++++++++++++--
 libavcodec/ac3dec.c         | 88 ++++++++++++++++++++++++++++++---------------
 libavcodec/ac3dec.h         |  8 +++--
 libavcodec/eac3dec.c        | 10 ++----
 6 files changed, 101 insertions(+), 43 deletions(-)

diff --git a/libavcodec/aac_ac3_parser.c b/libavcodec/aac_ac3_parser.c
index 4e834b4424..6f8d4b3b78 100644
--- a/libavcodec/aac_ac3_parser.c
+++ b/libavcodec/aac_ac3_parser.c
@@ -24,6 +24,7 @@
 #include "libavutil/common.h"
 #include "parser.h"
 #include "aac_ac3_parser.h"
+#include "ac3.h"
 
 int ff_aac_ac3_parse(AVCodecParserContext *s1,
                      AVCodecContext *avctx,
@@ -86,8 +87,10 @@ get_next:
            the frame). */
         if (avctx->codec_id != AV_CODEC_ID_AAC) {
             avctx->sample_rate = s->sample_rate;
-            avctx->channels = s->channels;
-            avctx->channel_layout = s->channel_layout;
+            if (avctx->codec_id != AV_CODEC_ID_EAC3 || s->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
+                avctx->channels = s->channels;
+                avctx->channel_layout = s->channel_layout;
+            }
             s1->duration = s->samples;
             avctx->audio_service_type = s->service_type;
         }
diff --git a/libavcodec/aac_ac3_parser.h b/libavcodec/aac_ac3_parser.h
index c2506a5bfd..445ce0b9b2 100644
--- a/libavcodec/aac_ac3_parser.h
+++ b/libavcodec/aac_ac3_parser.h
@@ -44,6 +44,7 @@ typedef struct AACAC3ParseContext {
     int (*sync)(uint64_t state, struct AACAC3ParseContext *hdr_info,
             int *need_next_header, int *new_frame_start);
 
+    int frame_type;
     int channels;
     int sample_rate;
     int bit_rate;
@@ -54,6 +55,7 @@ typedef struct AACAC3ParseContext {
     int remaining_size;
     uint64_t state;
 
+    int queued_headers;
     int need_next_header;
     enum AVCodecID codec_id;
 } AACAC3ParseContext;
diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c
index 1015245a90..694b38c3b1 100644
--- a/libavcodec/ac3_parser.c
+++ b/libavcodec/ac3_parser.c
@@ -53,10 +53,12 @@ static const uint8_t surround_levels[4] = { 4, 6, 7, 6 };
 
 int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
 {
-    int frame_size_code;
+    int frame_size_code, i;
 
     memset(hdr, 0, sizeof(*hdr));
 
+    hdr->channel_map = -1;
+
     hdr->sync_word = get_bits(gbc, 16);
     if(hdr->sync_word != 0x0B77)
         return AAC_AC3_PARSE_ERROR_SYNC;
@@ -109,6 +111,8 @@ int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
         hdr->frame_type = EAC3_FRAME_TYPE_AC3_CONVERT; //EAC3_FRAME_TYPE_INDEPENDENT;
         hdr->substreamid = 0;
     } else {
+        int skipped_bits = 0;
+
         /* Enhanced AC-3 */
         hdr->crc1 = 0;
         hdr->frame_type = get_bits(gbc, 2);
@@ -140,6 +144,27 @@ 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;
+
+        skip_bits(gbc, 5);
+        skipped_bits += 5;
+        for (i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
+            skip_bits(gbc, 5);
+            skipped_bits += 6;
+            if (get_bits1(gbc)) {
+                skip_bits(gbc, 8);
+                skipped_bits += 8;
+            }
+        }
+
+        if (hdr->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
+            skipped_bits += 1;
+            if (get_bits1(gbc)) {
+                hdr->channel_map = get_bits(gbc, 16);
+                skipped_bits += 16;
+            }
+        }
+
+        skip_bits_long(gbc, -skipped_bits);
     }
     hdr->channel_layout = avpriv_ac3_channel_layout_tab[hdr->channel_mode];
     if (hdr->lfe_on)
@@ -218,8 +243,8 @@ static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info,
     else if (hdr_info->codec_id == AV_CODEC_ID_NONE)
         hdr_info->codec_id = AV_CODEC_ID_AC3;
 
-    *need_next_header = (hdr.frame_type != EAC3_FRAME_TYPE_AC3_CONVERT);
     *new_frame_start  = (hdr.frame_type != EAC3_FRAME_TYPE_DEPENDENT);
+    *need_next_header = *new_frame_start || (hdr.frame_type != EAC3_FRAME_TYPE_AC3_CONVERT);
     return hdr.frame_size;
 }
 
diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
index 244a18323f..58db1c5045 100644
--- a/libavcodec/ac3dec.c
+++ b/libavcodec/ac3dec.c
@@ -309,6 +309,7 @@ static int parse_frame_header(AC3DecodeContext *s)
     s->bitstream_id                 = hdr.bitstream_id;
     s->bitstream_mode               = hdr.bitstream_mode;
     s->channel_mode                 = hdr.channel_mode;
+    s->channel_map                  = hdr.channel_map;
     s->lfe_on                       = hdr.lfe_on;
     s->bit_alloc_params.sr_shift    = hdr.sr_shift;
     s->sample_rate                  = hdr.sample_rate;
@@ -317,6 +318,7 @@ static int parse_frame_header(AC3DecodeContext *s)
     s->fbw_channels                 = s->channels - s->lfe_on;
     s->lfe_ch                       = s->fbw_channels + 1;
     s->frame_size                   = hdr.frame_size;
+    s->superframe_size             += hdr.frame_size;
     s->preferred_downmix            = AC3_DMIXMOD_NOTINDICATED;
     s->center_mix_level             = hdr.center_mix_level;
     s->center_mix_level_ltrt        = 4; // -3.0dB
@@ -683,7 +685,7 @@ static void do_rematrixing(AC3DecodeContext *s)
  * Convert frequency domain coefficients to time-domain audio samples.
  * reference: Section 7.9.4 Transformation Equations
  */
-static inline void do_imdct(AC3DecodeContext *s, int channels)
+static inline void do_imdct(AC3DecodeContext *s, int channels, int offset)
 {
     int ch;
 
@@ -695,25 +697,25 @@ static inline void do_imdct(AC3DecodeContext *s, int channels)
                 x[i] = s->transform_coeffs[ch][2 * i];
             s->imdct_256.imdct_half(&s->imdct_256, s->tmp_output, x);
 #if USE_FIXED
-            s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1],
+            s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1 + offset],
                                        s->tmp_output, s->window, 128, 8);
 #else
-            s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1],
+            s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1 + offset],
                                        s->tmp_output, s->window, 128);
 #endif
             for (i = 0; i < 128; i++)
                 x[i] = s->transform_coeffs[ch][2 * i + 1];
-            s->imdct_256.imdct_half(&s->imdct_256, s->delay[ch - 1], x);
+            s->imdct_256.imdct_half(&s->imdct_256, s->delay[ch - 1 + offset], x);
         } else {
             s->imdct_512.imdct_half(&s->imdct_512, s->tmp_output, s->transform_coeffs[ch]);
 #if USE_FIXED
-            s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1],
+            s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1 + offset],
                                        s->tmp_output, s->window, 128, 8);
 #else
-            s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1],
+            s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1 + offset],
                                        s->tmp_output, s->window, 128);
 #endif
-            memcpy(s->delay[ch - 1], s->tmp_output + 128, 128 * sizeof(FFTSample));
+            memcpy(s->delay[ch - 1 + offset], s->tmp_output + 128, 128 * sizeof(FFTSample));
         }
     }
 }
@@ -1063,7 +1065,7 @@ static inline int coupling_coordinates(AC3DecodeContext *s, int blk)
 /**
  * Decode a single audio block from the AC-3 bitstream.
  */
-static int decode_audio_block(AC3DecodeContext *s, int blk)
+static int decode_audio_block(AC3DecodeContext *s, int blk, int offset)
 {
     int fbw_channels = s->fbw_channels;
     int channel_mode = s->channel_mode;
@@ -1426,7 +1428,7 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
             ac3_upmix_delay(s);
         }
 
-        do_imdct(s, s->channels);
+        do_imdct(s, s->channels, offset);
 
         if (downmix_output) {
 #if USE_FIXED
@@ -1449,7 +1451,7 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
                                           s->out_channels, s->fbw_channels, 128);
         }
 
-        do_imdct(s, s->out_channels);
+        do_imdct(s, s->out_channels, offset);
     }
 
     return 0;
@@ -1463,14 +1465,15 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
 {
     AVFrame *frame     = data;
     const uint8_t *buf = avpkt->data;
-    int buf_size = avpkt->size;
+    int buf_size, full_buf_size = avpkt->size;
     AC3DecodeContext *s = avctx->priv_data;
-    int blk, ch, err, ret;
+    int blk, ch, err, offset, ret;
     const uint8_t *channel_map;
     const SHORTFLOAT *output[AC3_MAX_CHANNELS];
     enum AVMatrixEncoding matrix_encoding;
     AVDownmixInfo *downmix_info;
 
+    buf_size = full_buf_size;
     /* copy input buffer to decoder context to avoid reading past the end
        of the buffer, which can be caused by a damaged input stream. */
     if (buf_size >= 2 && AV_RB16(buf) == 0x770B) {
@@ -1488,6 +1491,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
         av_lfg_init_from_data(&s->dith_state, s->input_buffer, FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE));
 
     buf = s->input_buffer;
+second_time:
     /* initialize the GetBitContext with the start of valid AC-3 Frame */
     if ((ret = init_get_bits8(&s->gbc, buf, buf_size)) < 0)
         return ret;
@@ -1511,7 +1515,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
             break;
         case AAC_AC3_PARSE_ERROR_FRAME_TYPE:
             /* skip frame if CRC is ok. otherwise use error concealment. */
-            /* TODO: add support for substreams and dependent frames */
+            /* TODO: add support for substreams */
             if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT || s->substreamid) {
                 av_log(avctx, AV_LOG_DEBUG,
                        "unsupported frame type %d: skipping frame\n",
@@ -1532,7 +1536,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
     } else {
         /* check that reported frame size fits in input buffer */
         if (s->frame_size > buf_size) {
-            av_log(avctx, AV_LOG_ERROR, "incomplete frame\n");
+            av_log(avctx, AV_LOG_ERROR, "incomplete frame %d %d\n", s->frame_size, buf_size);
             err = AAC_AC3_PARSE_ERROR_FRAME_SIZE;
         } else if (avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_CAREFUL)) {
             /* check for crc mismatch */
@@ -1594,29 +1598,25 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
     if (s->bitstream_mode == 0x7 && s->channels > 1)
         avctx->audio_service_type = AV_AUDIO_SERVICE_TYPE_KARAOKE;
 
-    /* get output buffer */
-    frame->nb_samples = s->num_blocks * AC3_BLOCK_SIZE;
-    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
-        return ret;
-
     /* decode the audio blocks */
     channel_map = ff_ac3_dec_channel_map[s->output_mode & ~AC3_OUTPUT_LFEON][s->lfe_on];
+    offset = s->frame_type == EAC3_FRAME_TYPE_DEPENDENT ? AC3_MAX_CHANNELS : 0;
     for (ch = 0; ch < AC3_MAX_CHANNELS; ch++) {
-        output[ch] = s->output[ch];
-        s->outptr[ch] = s->output[ch];
+        output[ch] = s->output[ch + offset];
+        s->outptr[ch] = s->output[ch + offset];
     }
     for (ch = 0; ch < s->channels; ch++) {
         if (ch < s->out_channels)
-            s->outptr[channel_map[ch]] = (SHORTFLOAT *)frame->data[ch];
+            s->outptr[channel_map[ch]] = s->output_buffer[ch + offset];
     }
     for (blk = 0; blk < s->num_blocks; blk++) {
-        if (!err && decode_audio_block(s, blk)) {
+        if (!err && decode_audio_block(s, blk, offset)) {
             av_log(avctx, AV_LOG_ERROR, "error decoding the audio block\n");
             err = 1;
         }
         if (err)
             for (ch = 0; ch < s->out_channels; ch++)
-                memcpy(((SHORTFLOAT*)frame->data[ch]) + AC3_BLOCK_SIZE*blk, output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT));
+                memcpy(s->output_buffer[ch + offset] + AC3_BLOCK_SIZE*blk, output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT));
         for (ch = 0; ch < s->out_channels; ch++)
             output[ch] = s->outptr[channel_map[ch]];
         for (ch = 0; ch < s->out_channels; ch++) {
@@ -1625,11 +1625,43 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
         }
     }
 
-    frame->decode_error_flags = err ? FF_DECODE_ERROR_INVALID_BITSTREAM : 0;
-
     /* keep last block for error concealment in next frame */
     for (ch = 0; ch < s->out_channels; ch++)
-        memcpy(s->output[ch], output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT));
+        memcpy(s->output[ch + offset], output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT));
+
+    /* check if there is dependent frame */
+    if (buf_size > s->frame_size) {
+        AC3HeaderInfo hdr;
+        int err;
+
+        if ((ret = init_get_bits8(&s->gbc, buf + s->frame_size, buf_size - s->frame_size)) < 0)
+            return ret;
+
+        err = ff_ac3_parse_header(&s->gbc, &hdr);
+        if (err)
+            return err;
+
+        if (hdr.frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
+            buf += s->frame_size;
+            buf_size -= s->frame_size;
+            goto second_time;
+        }
+    }
+
+    frame->decode_error_flags = err ? FF_DECODE_ERROR_INVALID_BITSTREAM : 0;
+
+    if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
+        avctx->channels = 8;
+        avctx->channel_layout = AV_CH_LAYOUT_7POINT1;
+    }
+
+    /* get output buffer */
+    frame->nb_samples = s->num_blocks * AC3_BLOCK_SIZE;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        return ret;
+
+    for (ch = 0; ch < avctx->channels; ch++)
+        memcpy((SHORTFLOAT *)frame->data[ch], s->output_buffer[ch], s->num_blocks * AC3_BLOCK_SIZE * sizeof(SHORTFLOAT));
 
     /*
      * AVMatrixEncoding
@@ -1689,7 +1721,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
 
     *got_frame_ptr = 1;
 
-    return FFMIN(buf_size, s->frame_size);
+    return FFMIN(full_buf_size, s->superframe_size);
 }
 
 /**
diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
index aa4cf04f8a..feeee780ac 100644
--- a/libavcodec/ac3dec.h
+++ b/libavcodec/ac3dec.h
@@ -76,6 +76,7 @@ typedef struct AC3DecodeContext {
 ///@{
     int frame_type;                         ///< frame type                             (strmtyp)
     int substreamid;                        ///< substream identification
+    int superframe_size;                    ///< current superframe size, in bytes
     int frame_size;                         ///< current frame size, in bytes
     int bit_rate;                           ///< stream bit rate, in bits-per-second
     int sample_rate;                        ///< sample frequency, in Hz
@@ -87,7 +88,7 @@ typedef struct AC3DecodeContext {
     int dialog_normalization[2];            ///< dialog level in dBFS                   (dialnorm)
     int compression_exists[2];              ///< compression field is valid for frame   (compre)
     int compression_gain[2];                ///< gain to apply for heavy compression    (compr)
-    int channel_map;                        ///< custom channel map
+    int channel_map;                        ///< custom channel map                     (chanmap)
     int preferred_downmix;                  ///< Preferred 2-channel downmix mode       (dmixmod)
     int center_mix_level;                   ///< Center mix level index
     int center_mix_level_ltrt;              ///< Center mix level index for Lt/Rt       (ltrtcmixlev)
@@ -239,11 +240,12 @@ typedef struct AC3DecodeContext {
 ///@name Aligned arrays
     DECLARE_ALIGNED(16, int,   fixed_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS];       ///< fixed-point transform coefficients
     DECLARE_ALIGNED(32, INTFLOAT, transform_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS];   ///< transform coefficients
-    DECLARE_ALIGNED(32, INTFLOAT, delay)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE];             ///< delay - added to the next block
+    DECLARE_ALIGNED(32, INTFLOAT, delay)[2 * AC3_MAX_CHANNELS][AC3_BLOCK_SIZE];         ///< delay - added to the next block
     DECLARE_ALIGNED(32, INTFLOAT, window)[AC3_BLOCK_SIZE];                              ///< window coefficients
     DECLARE_ALIGNED(32, INTFLOAT, tmp_output)[AC3_BLOCK_SIZE];                          ///< temporary storage for output before windowing
-    DECLARE_ALIGNED(32, SHORTFLOAT, output)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE];            ///< output after imdct transform and windowing
+    DECLARE_ALIGNED(32, SHORTFLOAT, output)[2 * AC3_MAX_CHANNELS][AC3_BLOCK_SIZE];            ///< output after imdct transform and windowing
     DECLARE_ALIGNED(32, uint8_t, input_buffer)[AC3_FRAME_BUFFER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; ///< temp buffer to prevent overread
+    DECLARE_ALIGNED(32, SHORTFLOAT, output_buffer)[2 * AC3_MAX_CHANNELS][AC3_BLOCK_SIZE * 6];  ///< final output buffer
 ///@}
 } AC3DecodeContext;
 
diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c
index 6f6309f179..9921ec849f 100644
--- a/libavcodec/eac3dec.c
+++ b/libavcodec/eac3dec.c
@@ -303,13 +303,7 @@ static int ff_eac3_parse_header(AC3DecodeContext *s)
     /* An E-AC-3 stream can have multiple independent streams which the
        application can select from. each independent stream can also contain
        dependent streams which are used to add or replace channels. */
-    if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
-        if (!s->eac3_frame_dependent_found) {
-            s->eac3_frame_dependent_found = 1;
-            avpriv_request_sample(s->avctx, "Dependent substream decoding");
-        }
-        return AAC_AC3_PARSE_ERROR_FRAME_TYPE;
-    } else if (s->frame_type == EAC3_FRAME_TYPE_RESERVED) {
+    if (s->frame_type == EAC3_FRAME_TYPE_RESERVED) {
         av_log(s->avctx, AV_LOG_ERROR, "Reserved frame type\n");
         return AAC_AC3_PARSE_ERROR_FRAME_TYPE;
     }
@@ -355,7 +349,7 @@ static int ff_eac3_parse_header(AC3DecodeContext *s)
     /* dependent stream channel map */
     if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) {
         if (get_bits1(gbc)) {
-            skip_bits(gbc, 16); // skip custom channel map
+            s->channel_map = get_bits(gbc, 16);
         }
     }
 
-- 
2.11.0



More information about the ffmpeg-devel mailing list