[FFmpeg-devel] [PATCH 06/20] avformat/matroskdec: Factor audio parsing out of matroska_parse_tracks()

Andreas Rheinhardt andreas.rheinhardt at outlook.com
Mon Sep 4 14:27:45 EEST 2023


More exactly, factor codec-specific audio parsing out of
matroska_parse_tracks(). This is intended to improve readability.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>
---
 libavformat/matroskadec.c | 424 ++++++++++++++++++++++----------------
 1 file changed, 243 insertions(+), 181 deletions(-)

diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index e1524a5943..8846e9358d 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -2501,9 +2501,241 @@ static int get_qt_codec(MatroskaTrack *track, uint32_t *fourcc, enum AVCodecID *
     return 0;
 }
 
+/* An enum with potential return values of the functions for parsing a track.
+ * Apart from that all these functions can also indicate ordinary errors via
+ * negative return values. */
+enum {
+    SKIP_TRACK = 1,
+};
+
 #define AAC_MAX_EXTRADATA_SIZE     5
 #define TTA_EXTRADATA_SIZE        22
 #define WAVPACK_EXTRADATA_SIZE     2
+/* Performs the codec-specific part of parsing an audio track. */
+static int mka_parse_audio_codec(MatroskaTrack *track, AVCodecParameters *par,
+                                 const MatroskaDemuxContext *matroska,
+                                 AVFormatContext *s, int *extradata_offset)
+{
+        uint8_t extradata[FFMAX3(AAC_MAX_EXTRADATA_SIZE,
+                                 TTA_EXTRADATA_SIZE,
+                                 WAVPACK_EXTRADATA_SIZE)];
+        int extradata_size = 0; // > 0 means that the extradata buffer is used
+        int ret;
+
+        if (!strcmp(track->codec_id, "A_MS/ACM") &&
+                   track->codec_priv.size >= 14         &&
+                   track->codec_priv.data) {
+        FFIOContext b;
+            int ret;
+            ffio_init_context(&b, track->codec_priv.data,
+                              track->codec_priv.size,
+                              0, NULL, NULL, NULL, NULL);
+            ret = ff_get_wav_header(s, &b.pub, par,
+                                    track->codec_priv.size, 0);
+            if (ret < 0)
+                return ret;
+            *extradata_offset = FFMIN(track->codec_priv.size, 18);
+            return 0;
+        } else if (!strcmp(track->codec_id, "A_QUICKTIME")
+                   /* Normally 36, but allow noncompliant private data */
+                   && (track->codec_priv.size >= 32)
+                   && (track->codec_priv.data)) {
+            enum AVCodecID codec_id;
+            uint32_t fourcc;
+            uint16_t sample_size;
+            int ret = get_qt_codec(track, &fourcc, &codec_id);
+            if (ret < 0)
+                return ret;
+            sample_size = AV_RB16(track->codec_priv.data + 26);
+            if (fourcc == 0) {
+                if (sample_size == 8) {
+                    fourcc = MKTAG('r','a','w',' ');
+                    codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc);
+                } else if (sample_size == 16) {
+                    fourcc = MKTAG('t','w','o','s');
+                    codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc);
+                }
+            }
+            if ((fourcc == MKTAG('t','w','o','s') ||
+                    fourcc == MKTAG('s','o','w','t')) &&
+                    sample_size == 8)
+                codec_id = AV_CODEC_ID_PCM_S8;
+            par->codec_id  = codec_id;
+            par->codec_tag = fourcc;
+            return 0;
+        }
+
+    switch (par->codec_id) {
+    case AV_CODEC_ID_PCM_S16BE:
+            switch (track->audio.bitdepth) {
+            case  8:
+                par->codec_id = AV_CODEC_ID_PCM_U8;
+                break;
+            case 24:
+                par->codec_id = AV_CODEC_ID_PCM_S24BE;
+                break;
+            case 32:
+                par->codec_id = AV_CODEC_ID_PCM_S32BE;
+                break;
+            }
+        break;
+    case AV_CODEC_ID_PCM_S16LE:
+            switch (track->audio.bitdepth) {
+            case  8:
+                par->codec_id = AV_CODEC_ID_PCM_U8;
+                break;
+            case 24:
+                par->codec_id = AV_CODEC_ID_PCM_S24LE;
+                break;
+            case 32:
+                par->codec_id = AV_CODEC_ID_PCM_S32LE;
+                break;
+            }
+        break;
+    case AV_CODEC_ID_PCM_F32LE:
+        if (track->audio.bitdepth == 64)
+            par->codec_id = AV_CODEC_ID_PCM_F64LE;
+        break;
+    case AV_CODEC_ID_AAC:
+        if (!track->codec_priv.size) {
+            int profile = matroska_aac_profile(track->codec_id);
+            int sri     = matroska_aac_sri(track->audio.samplerate);
+
+            extradata[0] = (profile << 3) | ((sri & 0x0E) >> 1);
+            extradata[1] = ((sri & 0x01) << 7) | (track->audio.channels << 3);
+            if (strstr(track->codec_id, "SBR")) {
+                sri            = matroska_aac_sri(track->audio.out_samplerate);
+                extradata[2]   = 0x56;
+                extradata[3]   = 0xE5;
+                extradata[4]   = 0x80 | (sri << 3);
+                extradata_size = 5;
+            } else
+                extradata_size = 2;
+        }
+        break;
+    case AV_CODEC_ID_ALAC:
+        if (track->codec_priv.size && track->codec_priv.size < INT_MAX - 12 - AV_INPUT_BUFFER_PADDING_SIZE) {
+            /* Only ALAC's magic cookie is stored in Matroska's track headers.
+             * Create the "atom size", "tag", and "tag version" fields the
+             * decoder expects manually. */
+            ret = ff_alloc_extradata(par, 12 + track->codec_priv.size);
+            if (ret < 0)
+                return ret;
+            AV_WB32(par->extradata, par->extradata_size);
+            AV_WB32(&par->extradata[4], MKBETAG('a', 'l', 'a', 'c'));
+            AV_WB32(&par->extradata[8], 0);
+            memcpy(&par->extradata[12], track->codec_priv.data,
+                   track->codec_priv.size);
+        }
+        break;
+    case AV_CODEC_ID_TTA:
+    {
+            uint8_t *ptr;
+            if (track->audio.channels > UINT16_MAX ||
+                track->audio.bitdepth > UINT16_MAX) {
+                av_log(matroska->ctx, AV_LOG_WARNING,
+                       "Too large audio channel number %"PRIu64
+                       " or bitdepth %"PRIu64". Skipping track.\n",
+                       track->audio.channels, track->audio.bitdepth);
+                if (matroska->ctx->error_recognition & AV_EF_EXPLODE)
+                    return AVERROR_INVALIDDATA;
+                else
+                    return SKIP_TRACK;
+            }
+            if (track->audio.out_samplerate < 0 || track->audio.out_samplerate > INT_MAX)
+                return AVERROR_INVALIDDATA;
+            extradata_size = TTA_EXTRADATA_SIZE;
+            ptr = extradata;
+            bytestream_put_be32(&ptr, AV_RB32("TTA1"));
+            bytestream_put_le16(&ptr, 1);
+            bytestream_put_le16(&ptr, track->audio.channels);
+            bytestream_put_le16(&ptr, track->audio.bitdepth);
+            bytestream_put_le32(&ptr, track->audio.out_samplerate);
+            bytestream_put_le32(&ptr, av_rescale(matroska->duration * matroska->time_scale,
+                                                 track->audio.out_samplerate,
+                                                 AV_TIME_BASE * 1000));
+        break;
+    }
+    case AV_CODEC_ID_RA_144:
+            track->audio.out_samplerate = 8000;
+            track->audio.channels       = 1;
+        break;
+    case AV_CODEC_ID_RA_288:
+    case AV_CODEC_ID_COOK:
+    case AV_CODEC_ID_ATRAC3:
+    case AV_CODEC_ID_SIPR:
+    {
+            const uint8_t *ptr = track->codec_priv.data;
+            int flavor;
+
+        if (!track->codec_priv.size)
+            break;
+
+            if (track->codec_priv.size < 46)
+                return AVERROR_INVALIDDATA;
+            ptr += 22;
+            flavor                       = bytestream_get_be16(&ptr);
+            track->audio.coded_framesize = bytestream_get_be32(&ptr);
+            ptr += 12;
+            track->audio.sub_packet_h    = bytestream_get_be16(&ptr);
+            track->audio.frame_size      = bytestream_get_be16(&ptr);
+            track->audio.sub_packet_size = bytestream_get_be16(&ptr);
+            if (track->audio.coded_framesize <= 0 ||
+                track->audio.sub_packet_h    <= 0 ||
+                track->audio.frame_size      <= 0)
+                return AVERROR_INVALIDDATA;
+
+            if (par->codec_id == AV_CODEC_ID_RA_288) {
+                if (track->audio.sub_packet_h & 1 || 2 * track->audio.frame_size
+                    != (int64_t)track->audio.sub_packet_h * track->audio.coded_framesize)
+                    return AVERROR_INVALIDDATA;
+                par->block_align = track->audio.coded_framesize;
+                track->codec_priv.size = 0;
+            } else {
+                if (par->codec_id == AV_CODEC_ID_SIPR) {
+                    static const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 };
+                    if (flavor > 3)
+                        return AVERROR_INVALIDDATA;
+                    track->audio.sub_packet_size = ff_sipr_subpk_size[flavor];
+                    par->bit_rate          = sipr_bit_rate[flavor];
+                } else if (track->audio.sub_packet_size <= 0 ||
+                           track->audio.frame_size % track->audio.sub_packet_size)
+                    return AVERROR_INVALIDDATA;
+                par->block_align = track->audio.sub_packet_size;
+                *extradata_offset = 78;
+            }
+            track->audio.buf = av_malloc_array(track->audio.sub_packet_h,
+                                               track->audio.frame_size);
+            if (!track->audio.buf)
+                return AVERROR(ENOMEM);
+        break;
+    }
+    case AV_CODEC_ID_FLAC:
+        if (track->codec_priv.size) {
+            ret = matroska_parse_flac(s, track, extradata_offset);
+            if (ret < 0)
+                return ret;
+        }
+        break;
+    case AV_CODEC_ID_WAVPACK:
+        if (track->codec_priv.size < 2) {
+            av_log(matroska->ctx, AV_LOG_INFO, "Assuming WavPack version 4.10 "
+                   "in absence of valid CodecPrivate.\n");
+            extradata_size = WAVPACK_EXTRADATA_SIZE;
+            AV_WL16(extradata, 0x410);
+        }
+        break;
+    }
+
+    if (extradata_size > 0) {
+        ret = ff_alloc_extradata(par, extradata_size);
+        if (ret < 0)
+            return ret;
+        memcpy(par->extradata, extradata, extradata_size);
+    }
+
+    return 0;
+}
 
 static int matroska_parse_tracks(AVFormatContext *s)
 {
@@ -2518,10 +2750,6 @@ static int matroska_parse_tracks(AVFormatContext *s)
         EbmlList *encodings_list = &track->encodings;
         MatroskaTrackEncoding *encodings = encodings_list->elem;
         AVCodecParameters *par;
-        uint8_t extradata[FFMAX3(AAC_MAX_EXTRADATA_SIZE,
-                                 TTA_EXTRADATA_SIZE,
-                                 WAVPACK_EXTRADATA_SIZE)];
-        int extradata_size = 0; // > 0 means that the extradata buffer is used
         int extradata_offset = 0;
         uint32_t fourcc = 0;
         FFIOContext b;
@@ -2702,6 +2930,14 @@ static int matroska_parse_tracks(AVFormatContext *s)
                                                       (AVRational){ 1, 1000000000 },
                                                       st->time_base);
 
+        if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
+            ret = mka_parse_audio_codec(track, par, matroska,
+                                        s, &extradata_offset);
+            if (ret < 0)
+                return ret;
+            if (ret == SKIP_TRACK)
+                continue;
+        } else
         if (!strcmp(track->codec_id, "V_MS/VFW/FOURCC") &&
              track->codec_priv.size >= 40               &&
             track->codec_priv.data) {
@@ -2714,43 +2950,6 @@ static int matroska_parse_tracks(AVFormatContext *s)
                 par->codec_id   = ff_codec_get_id(ff_codec_movvideo_tags,
                                                   par->codec_tag);
             extradata_offset    = 40;
-        } else if (!strcmp(track->codec_id, "A_MS/ACM") &&
-                   track->codec_priv.size >= 14         &&
-                   track->codec_priv.data) {
-            int ret;
-            ffio_init_context(&b, track->codec_priv.data,
-                              track->codec_priv.size,
-                              0, NULL, NULL, NULL, NULL);
-            ret = ff_get_wav_header(s, &b.pub, par,
-                                    track->codec_priv.size, 0);
-            if (ret < 0)
-                return ret;
-            extradata_offset = FFMIN(track->codec_priv.size, 18);
-        } else if (!strcmp(track->codec_id, "A_QUICKTIME")
-                   /* Normally 36, but allow noncompliant private data */
-                   && (track->codec_priv.size >= 32)
-                   && (track->codec_priv.data)) {
-            uint32_t fourcc;
-            uint16_t sample_size;
-            int ret = get_qt_codec(track, &fourcc, &codec_id);
-            if (ret < 0)
-                return ret;
-            sample_size = AV_RB16(track->codec_priv.data + 26);
-            if (fourcc == 0) {
-                if (sample_size == 8) {
-                    fourcc = MKTAG('r','a','w',' ');
-                    codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc);
-                } else if (sample_size == 16) {
-                    fourcc = MKTAG('t','w','o','s');
-                    codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc);
-                }
-            }
-            if ((fourcc == MKTAG('t','w','o','s') ||
-                    fourcc == MKTAG('s','o','w','t')) &&
-                    sample_size == 8)
-                codec_id = AV_CODEC_ID_PCM_S8;
-            par->codec_id  = codec_id;
-            par->codec_tag = fourcc;
         } else if (!strcmp(track->codec_id, "V_QUICKTIME") &&
                    (track->codec_priv.size >= 21)          &&
                    (track->codec_priv.data)) {
@@ -2778,146 +2977,11 @@ static int matroska_parse_tracks(AVFormatContext *s)
                 par->bits_per_coded_sample = bit_depth;
             }
             par->codec_tag = fourcc;
-        } else if (codec_id == AV_CODEC_ID_PCM_S16BE) {
-            switch (track->audio.bitdepth) {
-            case  8:
-                par->codec_id = AV_CODEC_ID_PCM_U8;
-                break;
-            case 24:
-                par->codec_id = AV_CODEC_ID_PCM_S24BE;
-                break;
-            case 32:
-                par->codec_id = AV_CODEC_ID_PCM_S32BE;
-                break;
-            }
-        } else if (codec_id == AV_CODEC_ID_PCM_S16LE) {
-            switch (track->audio.bitdepth) {
-            case  8:
-                par->codec_id = AV_CODEC_ID_PCM_U8;
-                break;
-            case 24:
-                par->codec_id = AV_CODEC_ID_PCM_S24LE;
-                break;
-            case 32:
-                par->codec_id = AV_CODEC_ID_PCM_S32LE;
-                break;
-            }
-        } else if (codec_id == AV_CODEC_ID_PCM_F32LE &&
-                   track->audio.bitdepth == 64) {
-            par->codec_id = AV_CODEC_ID_PCM_F64LE;
-        } else if (codec_id == AV_CODEC_ID_AAC && !track->codec_priv.size) {
-            int profile = matroska_aac_profile(track->codec_id);
-            int sri     = matroska_aac_sri(track->audio.samplerate);
-
-            extradata[0] = (profile << 3) | ((sri & 0x0E) >> 1);
-            extradata[1] = ((sri & 0x01) << 7) | (track->audio.channels << 3);
-            if (strstr(track->codec_id, "SBR")) {
-                sri            = matroska_aac_sri(track->audio.out_samplerate);
-                extradata[2]   = 0x56;
-                extradata[3]   = 0xE5;
-                extradata[4]   = 0x80 | (sri << 3);
-                extradata_size = 5;
-            } else
-                extradata_size = 2;
-        } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size && track->codec_priv.size < INT_MAX - 12 - AV_INPUT_BUFFER_PADDING_SIZE) {
-            /* Only ALAC's magic cookie is stored in Matroska's track headers.
-             * Create the "atom size", "tag", and "tag version" fields the
-             * decoder expects manually. */
-            ret = ff_alloc_extradata(par, 12 + track->codec_priv.size);
-            if (ret < 0)
-                return ret;
-            AV_WB32(par->extradata, par->extradata_size);
-            AV_WB32(&par->extradata[4], MKBETAG('a', 'l', 'a', 'c'));
-            AV_WB32(&par->extradata[8], 0);
-            memcpy(&par->extradata[12], track->codec_priv.data,
-                   track->codec_priv.size);
-        } else if (codec_id == AV_CODEC_ID_TTA) {
-            uint8_t *ptr;
-            if (track->audio.channels > UINT16_MAX ||
-                track->audio.bitdepth > UINT16_MAX) {
-                av_log(matroska->ctx, AV_LOG_WARNING,
-                       "Too large audio channel number %"PRIu64
-                       " or bitdepth %"PRIu64". Skipping track.\n",
-                       track->audio.channels, track->audio.bitdepth);
-                if (matroska->ctx->error_recognition & AV_EF_EXPLODE)
-                    return AVERROR_INVALIDDATA;
-                else
-                    continue;
-            }
-            if (track->audio.out_samplerate < 0 || track->audio.out_samplerate > INT_MAX)
-                return AVERROR_INVALIDDATA;
-            extradata_size = TTA_EXTRADATA_SIZE;
-            ptr = extradata;
-            bytestream_put_be32(&ptr, AV_RB32("TTA1"));
-            bytestream_put_le16(&ptr, 1);
-            bytestream_put_le16(&ptr, track->audio.channels);
-            bytestream_put_le16(&ptr, track->audio.bitdepth);
-            bytestream_put_le32(&ptr, track->audio.out_samplerate);
-            bytestream_put_le32(&ptr, av_rescale(matroska->duration * matroska->time_scale,
-                                                 track->audio.out_samplerate,
-                                                 AV_TIME_BASE * 1000));
         } else if (codec_id == AV_CODEC_ID_RV10 ||
                    codec_id == AV_CODEC_ID_RV20 ||
                    codec_id == AV_CODEC_ID_RV30 ||
                    codec_id == AV_CODEC_ID_RV40) {
             extradata_offset = 26;
-        } else if (codec_id == AV_CODEC_ID_RA_144) {
-            track->audio.out_samplerate = 8000;
-            track->audio.channels       = 1;
-        } else if ((codec_id == AV_CODEC_ID_RA_288 ||
-                    codec_id == AV_CODEC_ID_COOK   ||
-                    codec_id == AV_CODEC_ID_ATRAC3 ||
-                    codec_id == AV_CODEC_ID_SIPR)
-                      && track->codec_priv.data) {
-            const uint8_t *ptr = track->codec_priv.data;
-            int flavor;
-
-            if (track->codec_priv.size < 46)
-                return AVERROR_INVALIDDATA;
-            ptr += 22;
-            flavor                       = bytestream_get_be16(&ptr);
-            track->audio.coded_framesize = bytestream_get_be32(&ptr);
-            ptr += 12;
-            track->audio.sub_packet_h    = bytestream_get_be16(&ptr);
-            track->audio.frame_size      = bytestream_get_be16(&ptr);
-            track->audio.sub_packet_size = bytestream_get_be16(&ptr);
-            if (track->audio.coded_framesize <= 0 ||
-                track->audio.sub_packet_h    <= 0 ||
-                track->audio.frame_size      <= 0)
-                return AVERROR_INVALIDDATA;
-
-            if (codec_id == AV_CODEC_ID_RA_288) {
-                if (track->audio.sub_packet_h & 1 || 2 * track->audio.frame_size
-                    != (int64_t)track->audio.sub_packet_h * track->audio.coded_framesize)
-                    return AVERROR_INVALIDDATA;
-                par->block_align = track->audio.coded_framesize;
-                track->codec_priv.size = 0;
-            } else {
-                if (codec_id == AV_CODEC_ID_SIPR) {
-                    static const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 };
-                    if (flavor > 3)
-                        return AVERROR_INVALIDDATA;
-                    track->audio.sub_packet_size = ff_sipr_subpk_size[flavor];
-                    par->bit_rate          = sipr_bit_rate[flavor];
-                } else if (track->audio.sub_packet_size <= 0 ||
-                           track->audio.frame_size % track->audio.sub_packet_size)
-                    return AVERROR_INVALIDDATA;
-                par->block_align = track->audio.sub_packet_size;
-                extradata_offset       = 78;
-            }
-            track->audio.buf = av_malloc_array(track->audio.sub_packet_h,
-                                               track->audio.frame_size);
-            if (!track->audio.buf)
-                return AVERROR(ENOMEM);
-        } else if (codec_id == AV_CODEC_ID_FLAC && track->codec_priv.size) {
-            ret = matroska_parse_flac(s, track, &extradata_offset);
-            if (ret < 0)
-                return ret;
-        } else if (codec_id == AV_CODEC_ID_WAVPACK && track->codec_priv.size < 2) {
-            av_log(matroska->ctx, AV_LOG_INFO, "Assuming WavPack version 4.10 "
-                   "in absence of valid CodecPrivate.\n");
-            extradata_size = WAVPACK_EXTRADATA_SIZE;
-            AV_WL16(extradata, 0x410);
         } else if (codec_id == AV_CODEC_ID_PRORES && track->codec_priv.size == 4) {
             par->codec_tag = AV_RL32(track->codec_priv.data);
         } else if (codec_id == AV_CODEC_ID_VP9) {
@@ -2960,11 +3024,9 @@ static int matroska_parse_tracks(AVFormatContext *s)
             av_log(matroska->ctx, AV_LOG_INFO,
                    "Unknown/unsupported AVCodecID %s.\n", track->codec_id);
 
-        if (!par->extradata && (extradata_size > 0 || track->codec_priv.size > 0)) {
-            const uint8_t *src = extradata_size > 0 ? extradata :
-                                     track->codec_priv.data + extradata_offset;
-            unsigned extra_size = extradata_size > 0 ? extradata_size :
-                                                       track->codec_priv.size;
+        if (!par->extradata && track->codec_priv.size > 0) {
+            const uint8_t *src = track->codec_priv.data + extradata_offset;
+            unsigned extra_size = track->codec_priv.size;
             ret = ff_alloc_extradata(par, extra_size);
             if (ret < 0)
                 return ret;
-- 
2.34.1



More information about the ffmpeg-devel mailing list