[FFmpeg-cvslog] avformat/flvdec: add support for demuxing multi-track FLV

Dennis Sädtler git at videolan.org
Fri Dec 27 21:25:37 EET 2024


ffmpeg | branch: master | Dennis Sädtler <dennis at obsproject.com> | Mon Apr  1 18:16:50 2024 +0200| [466a400b940dc1400794d52fcac2d60138b9b10a] | committer: Timo Rothenpieler

avformat/flvdec: add support for demuxing multi-track FLV

Based on enhanced-rtmp v2 spec published by Veovera:
https://veovera.github.io/enhanced-rtmp/docs/enhanced/enhanced-rtmp-v2

Signed-off-by: Dennis Sädtler <dennis at obsproject.com>
Signed-off-by: Timo Rothenpieler <timo at rothenpieler.org>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=466a400b940dc1400794d52fcac2d60138b9b10a
---

 libavformat/flv.h    |   6 +++
 libavformat/flvdec.c | 119 ++++++++++++++++++++++++++++++++--------
 libavformat/flvenc.c | 149 +++++++++++++++++++++++++++++++++++++--------------
 3 files changed, 211 insertions(+), 63 deletions(-)

diff --git a/libavformat/flv.h b/libavformat/flv.h
index 82eabf7749..1c0af2a519 100644
--- a/libavformat/flv.h
+++ b/libavformat/flv.h
@@ -103,6 +103,7 @@ enum {
     FLV_CODECID_NELLYMOSER           = 6 << FLV_AUDIO_CODECID_OFFSET,
     FLV_CODECID_PCM_ALAW             = 7 << FLV_AUDIO_CODECID_OFFSET,
     FLV_CODECID_PCM_MULAW            = 8 << FLV_AUDIO_CODECID_OFFSET,
+    FLV_CODECID_EX_HEADER            = 9 << FLV_AUDIO_CODECID_OFFSET,
     FLV_CODECID_AAC                  = 10<< FLV_AUDIO_CODECID_OFFSET,
     FLV_CODECID_SPEEX                = 11<< FLV_AUDIO_CODECID_OFFSET,
 };
@@ -128,6 +129,11 @@ enum {
     PacketTypeMultitrack            = 6,
 };
 
+enum {
+    AudioPacketTypeSequenceStart      = 0,
+    AudioPacketTypeCodedFrames        = 1,
+};
+
 enum {
     MultitrackTypeOneTrack             = 0x00,
     MultitrackTypeManyTracks           = 0x10,
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index 08482eb2db..35d70838e3 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -104,6 +104,10 @@ typedef struct FLVContext {
 
     FLVMetaVideoColor *metaVideoColor;
     int meta_color_info_flag;
+
+    uint8_t **mt_extradata;
+    int *mt_extradata_sz;
+    int mt_extradata_cnt;
 } FLVContext;
 
 /* AMF date type */
@@ -186,7 +190,7 @@ static void add_keyframes_index(AVFormatContext *s)
     }
 }
 
-static AVStream *create_stream(AVFormatContext *s, int codec_type)
+static AVStream *create_stream(AVFormatContext *s, int codec_type, int track_idx)
 {
     FFFormatContext *const si = ffformatcontext(s);
     FLVContext *flv   = s->priv_data;
@@ -194,6 +198,11 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type)
     if (!st)
         return NULL;
     st->codecpar->codec_type = codec_type;
+    st->id = track_idx;
+    avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
+    if (track_idx)
+        return st;
+
     if (s->nb_streams>=3 ||(   s->nb_streams==2
                            && s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE
                            && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE
@@ -210,8 +219,6 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type)
         st->avg_frame_rate = flv->framerate;
     }
 
-
-    avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
     flv->last_keyframe_stream_index = s->nb_streams - 1;
     add_keyframes_index(s);
     return st;
@@ -351,6 +358,7 @@ static int flv_same_video_codec(AVCodecParameters *vpar, uint32_t flv_codecid)
     case FLV_CODECID_VP6A:
         return vpar->codec_id == AV_CODEC_ID_VP6A;
     case FLV_CODECID_H264:
+    case MKBETAG('a', 'v', 'c', '1'):
         return vpar->codec_id == AV_CODEC_ID_H264;
     default:
         return vpar->codec_tag == flv_codecid;
@@ -407,6 +415,7 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
         ret = 1;     // 1 byte body size adjustment for flv_read_packet()
         break;
     case FLV_CODECID_H264:
+    case MKBETAG('a', 'v', 'c', '1'):
         par->codec_id = AV_CODEC_ID_H264;
         vstreami->need_parsing = AVSTREAM_PARSE_HEADERS;
         break;
@@ -676,7 +685,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
                     } else if (!strcmp(key, "height") && vpar) {
                         vpar->height = num_val;
                     } else if (!strcmp(key, "datastream")) {
-                        AVStream *st = create_stream(s, AVMEDIA_TYPE_SUBTITLE);
+                        AVStream *st = create_stream(s, AVMEDIA_TYPE_SUBTITLE, 0);
                         if (!st)
                             return AVERROR(ENOMEM);
                         st->codecpar->codec_id = AV_CODEC_ID_TEXT;
@@ -884,8 +893,11 @@ static int flv_read_close(AVFormatContext *s)
 {
     int i;
     FLVContext *flv = s->priv_data;
-    for (i=0; i<FLV_STREAM_TYPE_NB; i++)
+    for (i = 0; i < FLV_STREAM_TYPE_NB; i++)
         av_freep(&flv->new_extradata[i]);
+    for (i = 0; i < flv->mt_extradata_cnt; i++)
+        av_freep(&flv->mt_extradata[i]);
+    av_freep(&flv->mt_extradata_sz);
     av_freep(&flv->keyframe_times);
     av_freep(&flv->keyframe_filepositions);
     av_freep(&flv->metaVideoColor);
@@ -905,18 +917,47 @@ static int flv_get_extradata(AVFormatContext *s, AVStream *st, int size)
 }
 
 static int flv_queue_extradata(FLVContext *flv, AVIOContext *pb, int stream,
-                               int size)
+                               int size, int multitrack)
 {
     if (!size)
         return 0;
 
-    av_free(flv->new_extradata[stream]);
-    flv->new_extradata[stream] = av_mallocz(size +
-                                            AV_INPUT_BUFFER_PADDING_SIZE);
-    if (!flv->new_extradata[stream])
-        return AVERROR(ENOMEM);
-    flv->new_extradata_size[stream] = size;
-    avio_read(pb, flv->new_extradata[stream], size);
+    if (!multitrack) {
+        av_free(flv->new_extradata[stream]);
+        flv->new_extradata[stream] = av_mallocz(size +
+                                                AV_INPUT_BUFFER_PADDING_SIZE);
+        if (!flv->new_extradata[stream])
+            return AVERROR(ENOMEM);
+        flv->new_extradata_size[stream] = size;
+        avio_read(pb, flv->new_extradata[stream], size);
+    } else {
+        int new_count = stream + 1;
+
+        if (flv->mt_extradata_cnt < new_count) {
+            flv->mt_extradata = av_realloc(flv->mt_extradata,
+                                           sizeof(*flv->mt_extradata) *
+                                           new_count);
+            flv->mt_extradata_sz = av_realloc(flv->mt_extradata_sz,
+                                              sizeof(*flv->mt_extradata_sz) *
+                                              new_count);
+            if (!flv->mt_extradata || !flv->mt_extradata_sz)
+                return AVERROR(ENOMEM);
+            // Set newly allocated pointers/sizes to 0
+            for (int i = flv->mt_extradata_cnt; i < new_count; i++) {
+                    flv->mt_extradata[i] = NULL;
+                    flv->mt_extradata_sz[i] = 0;
+            }
+            flv->mt_extradata_cnt = new_count;
+        }
+
+        av_free(flv->mt_extradata[stream]);
+        flv->mt_extradata[stream] = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
+        if (!flv->mt_extradata[stream])
+            return AVERROR(ENOMEM);
+        flv->mt_extradata_sz[stream] = size;
+        avio_read(pb, flv->mt_extradata[stream], size);
+    }
+
     return 0;
 }
 
@@ -1032,7 +1073,7 @@ static int flv_data_packet(AVFormatContext *s, AVPacket *pkt,
     }
 
     if (i == s->nb_streams) {
-        st = create_stream(s, AVMEDIA_TYPE_SUBTITLE);
+        st = create_stream(s, AVMEDIA_TYPE_SUBTITLE, 0);
         if (!st)
             return AVERROR(ENOMEM);
         st->codecpar->codec_id = AV_CODEC_ID_TEXT;
@@ -1205,6 +1246,9 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
     int last = -1;
     int orig_size;
     int enhanced_flv = 0;
+    int multitrack = 0;
+    int pkt_type = 0;
+    uint8_t track_idx = 0;
     uint32_t video_codec_id = 0;
 
 retry:
@@ -1258,14 +1302,33 @@ retry:
          * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp-v1.pdf
          * */
         enhanced_flv = (flags >> 7) & 1;
+        pkt_type = enhanced_flv ? video_codec_id : 0;
         size--;
+
+        if (pkt_type == PacketTypeMultitrack) {
+            uint8_t types = avio_r8(s->pb);
+            int multitrack_type = types >> 4;
+            pkt_type = types & 0xF;
+
+            if (multitrack_type != MultitrackTypeOneTrack) {
+                av_log(s, AV_LOG_ERROR, "Multitrack types other than MultitrackTypeOneTrack are unsupported!\n");
+                return AVERROR_PATCHWELCOME;
+            }
+
+            multitrack = 1;
+            size--;
+        }
+
         if (enhanced_flv) {
             video_codec_id = avio_rb32(s->pb);
             size -= 4;
         }
+        if (multitrack) {
+            track_idx = avio_r8(s->pb);
+            size--;
+        }
 
-        if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
-            int pkt_type = flags & 0x0F;
+        if (enhanced_flv && (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
             if (pkt_type == PacketTypeMetadata) {
                 int ret = flv_parse_video_color_info(s, st, next);
                 av_log(s, AV_LOG_DEBUG, "enhanced flv parse metadata ret %d and skip\n", ret);
@@ -1329,7 +1392,8 @@ skip:
                 break;
         } else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
             if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
-                (s->video_codec_id || flv_same_video_codec(st->codecpar, video_codec_id)))
+                (s->video_codec_id || flv_same_video_codec(st->codecpar, video_codec_id)) &&
+                st->id == track_idx)
                 break;
         } else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) {
             if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
@@ -1341,7 +1405,7 @@ skip:
     }
     if (i == s->nb_streams) {
         static const enum AVMediaType stream_types[] = {AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_SUBTITLE, AVMEDIA_TYPE_DATA};
-        st = create_stream(s, stream_types[stream_type]);
+        st = create_stream(s, stream_types[stream_type], track_idx);
         if (!st)
             return AVERROR(ENOMEM);
     }
@@ -1448,7 +1512,7 @@ retry_duration:
         st->codecpar->codec_id == AV_CODEC_ID_VP9) {
         int type = 0;
         if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO) {
-            type = flags & 0x0F;
+            type = pkt_type;
         } else {
             type = avio_r8(s->pb);
             size--;
@@ -1464,7 +1528,8 @@ retry_duration:
             flv->meta_color_info_flag = 0;
         }
 
-        if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
+        if (st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
+            (st->codecpar->codec_id == AV_CODEC_ID_H264 && (!enhanced_flv || type == PacketTypeCodedFrames)) ||
             (st->codecpar->codec_id == AV_CODEC_ID_HEVC && type == PacketTypeCodedFrames)) {
             // sign extension
             int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000;
@@ -1487,7 +1552,7 @@ retry_duration:
             AVDictionaryEntry *t;
 
             if (st->codecpar->extradata) {
-                if ((ret = flv_queue_extradata(flv, s->pb, stream_type, size)) < 0)
+                if ((ret = flv_queue_extradata(flv, s->pb, multitrack ? track_idx : stream_type, size, multitrack)) < 0)
                     return ret;
                 ret = FFERROR_REDO;
                 goto leave;
@@ -1518,7 +1583,7 @@ retry_duration:
     pkt->pts          = pts == AV_NOPTS_VALUE ? dts : pts;
     pkt->stream_index = st->index;
     pkt->pos          = pos;
-    if (flv->new_extradata[stream_type]) {
+    if (!multitrack && flv->new_extradata[stream_type]) {
         int ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
                                           flv->new_extradata[stream_type],
                                           flv->new_extradata_size[stream_type]);
@@ -1526,6 +1591,16 @@ retry_duration:
             flv->new_extradata[stream_type]      = NULL;
             flv->new_extradata_size[stream_type] = 0;
         }
+    } else if (multitrack &&
+               flv->mt_extradata_cnt > track_idx &&
+               flv->mt_extradata[track_idx]) {
+        int ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
+                                          flv->mt_extradata[track_idx],
+                                          flv->mt_extradata_sz[track_idx]);
+        if (ret >= 0) {
+            flv->mt_extradata[track_idx]      = NULL;
+            flv->mt_extradata_sz[track_idx] = 0;
+        }
     }
     if (stream_type == FLV_STREAM_TYPE_AUDIO &&
                     (sample_rate != flv->last_sample_rate ||
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index b40770bb8a..1818b5482a 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -69,6 +69,10 @@ static const AVCodecTag flv_audio_codec_ids[] = {
     { AV_CODEC_ID_PCM_MULAW,  FLV_CODECID_PCM_MULAW  >> FLV_AUDIO_CODECID_OFFSET },
     { AV_CODEC_ID_PCM_ALAW,   FLV_CODECID_PCM_ALAW   >> FLV_AUDIO_CODECID_OFFSET },
     { AV_CODEC_ID_SPEEX,      FLV_CODECID_SPEEX      >> FLV_AUDIO_CODECID_OFFSET },
+    { AV_CODEC_ID_OPUS,       MKBETAG('O', 'p', 'u', 's') },
+    { AV_CODEC_ID_FLAC,       MKBETAG('f', 'L', 'a', 'C') },
+    { AV_CODEC_ID_AC3,        MKBETAG('a', 'c', '-', '3') },
+    { AV_CODEC_ID_EAC3,       MKBETAG('e', 'c', '-', '3') },
     { AV_CODEC_ID_NONE,       0 }
 };
 
@@ -139,6 +143,9 @@ static int get_audio_flags(AVFormatContext *s, AVCodecParameters *par)
     if (par->codec_id == AV_CODEC_ID_AAC) // specs force these parameters
         return FLV_CODECID_AAC | FLV_SAMPLERATE_44100HZ |
                FLV_SAMPLESSIZE_16BIT | FLV_STEREO;
+    if (par->codec_id == AV_CODEC_ID_OPUS || par->codec_id == AV_CODEC_ID_FLAC
+        || par->codec_id == AV_CODEC_ID_AC3 || par->codec_id == AV_CODEC_ID_EAC3)
+        return FLV_CODECID_EX_HEADER; // only needed for codec support check
     else if (par->codec_id == AV_CODEC_ID_SPEEX) {
         if (par->sample_rate != 16000) {
             av_log(s, AV_LOG_ERROR,
@@ -635,6 +642,42 @@ static int unsupported_codec(AVFormatContext *s,
     return AVERROR(ENOSYS);
 }
 
+static void flv_write_aac_header(AVFormatContext* s, AVCodecParameters* par)
+{
+    AVIOContext *pb = s->pb;
+    FLVContext *flv = s->priv_data;
+
+    if (!par->extradata_size && (flv->flags & FLV_AAC_SEQ_HEADER_DETECT)) {
+        PutBitContext pbc;
+        int samplerate_index;
+        int channels = par->ch_layout.nb_channels
+                - (par->ch_layout.nb_channels == 8 ? 1 : 0);
+        uint8_t data[2];
+
+        for (samplerate_index = 0; samplerate_index < 16;
+                samplerate_index++)
+            if (par->sample_rate
+                    == ff_mpeg4audio_sample_rates[samplerate_index])
+                break;
+
+        init_put_bits(&pbc, data, sizeof(data));
+        put_bits(&pbc, 5, par->profile + 1); //profile
+        put_bits(&pbc, 4, samplerate_index); //sample rate index
+        put_bits(&pbc, 4, channels);
+        put_bits(&pbc, 1, 0); //frame length - 1024 samples
+        put_bits(&pbc, 1, 0); //does not depend on core coder
+        put_bits(&pbc, 1, 0); //is not extension
+        flush_put_bits(&pbc);
+
+        avio_w8(pb, data[0]);
+        avio_w8(pb, data[1]);
+
+        av_log(s, AV_LOG_WARNING, "AAC sequence header: %02x %02x.\n",
+                data[0], data[1]);
+    }
+    avio_write(pb, par->extradata, par->extradata_size);
+}
+
 static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, int64_t ts, int stream_index) {
     int64_t data_size;
     AVIOContext *pb = s->pb;
@@ -642,7 +685,9 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
 
     if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
             || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC
-            || par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9) {
+            || par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9
+            || par->codec_id == AV_CODEC_ID_OPUS || par->codec_id == AV_CODEC_ID_FLAC
+            || par->codec_id == AV_CODEC_ID_AC3 || par->codec_id == AV_CODEC_ID_EAC3) {
         int64_t pos;
         avio_w8(pb,
                 par->codec_type == AVMEDIA_TYPE_VIDEO ?
@@ -651,39 +696,38 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, i
         put_timestamp(pb, ts);
         avio_wb24(pb, 0); // streamid
         pos = avio_tell(pb);
-        if (par->codec_id == AV_CODEC_ID_AAC) {
-            avio_w8(pb, get_audio_flags(s, par));
-            avio_w8(pb, 0); // AAC sequence header
-
-            if (!par->extradata_size && (flv->flags & FLV_AAC_SEQ_HEADER_DETECT)) {
-                PutBitContext pbc;
-                int samplerate_index;
-                int channels = par->ch_layout.nb_channels
-                        - (par->ch_layout.nb_channels == 8 ? 1 : 0);
-                uint8_t data[2];
-
-                for (samplerate_index = 0; samplerate_index < 16;
-                        samplerate_index++)
-                    if (par->sample_rate
-                            == ff_mpeg4audio_sample_rates[samplerate_index])
-                        break;
-
-                init_put_bits(&pbc, data, sizeof(data));
-                put_bits(&pbc, 5, par->profile + 1); //profile
-                put_bits(&pbc, 4, samplerate_index); //sample rate index
-                put_bits(&pbc, 4, channels);
-                put_bits(&pbc, 1, 0); //frame length - 1024 samples
-                put_bits(&pbc, 1, 0); //does not depend on core coder
-                put_bits(&pbc, 1, 0); //is not extension
-                flush_put_bits(&pbc);
-
-                avio_w8(pb, data[0]);
-                avio_w8(pb, data[1]);
-
-                av_log(s, AV_LOG_WARNING, "AAC sequence header: %02x %02x.\n",
-                        data[0], data[1]);
+        if (par->codec_type == AVMEDIA_TYPE_AUDIO) {
+            int extended_flv = par->codec_id == AV_CODEC_ID_OPUS
+                                    || par->codec_id == AV_CODEC_ID_FLAC
+                                    || par->codec_id == AV_CODEC_ID_AC3
+                                    || par->codec_id == AV_CODEC_ID_EAC3;
+
+            if (extended_flv) {
+                avio_w8(pb, FLV_CODECID_EX_HEADER | AudioPacketTypeSequenceStart);
+
+                if (par->codec_id == AV_CODEC_ID_AAC) {
+                    avio_write(pb, "mp4a", 4);
+                    flv_write_aac_header(s, par);
+                } else if (par->codec_id == AV_CODEC_ID_OPUS) {
+                    avio_write(pb, "Opus", 4);
+                    av_assert0(par->extradata_size);
+                    avio_write(pb, par->extradata, par->extradata_size);
+                } else if (par->codec_id == AV_CODEC_ID_FLAC) {
+                    avio_write(pb, "fLaC", 4);
+                    av_assert0(par->extradata_size);
+                    avio_write(pb, par->extradata, par->extradata_size);
+                } else if (par->codec_id == AV_CODEC_ID_MP3)
+                    avio_write(pb, ".mp3", 4);
+                else if (par->codec_id == AV_CODEC_ID_AC3)
+                    avio_write(pb, "ac-3", 4);
+                else if (par->codec_id == AV_CODEC_ID_EAC3)
+                    avio_write(pb, "ec-3", 4);
+            } else if (par->codec_id == AV_CODEC_ID_AAC) {
+                avio_w8(pb, get_audio_flags(s, par));
+                avio_w8(pb, 0); // AAC sequence header
+
+                flv_write_aac_header(s, par);
             }
-            avio_write(pb, par->extradata, par->extradata_size);
         } else {
             int track_idx = flv->video_track_idx_map[stream_index];
             // If video stream has track_idx > 0 we need to send H.264 as extended video packet
@@ -1021,13 +1065,20 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
     int64_t cur_offset = avio_tell(pb);
     int track_idx = flv->video_track_idx_map[pkt->stream_index];
 
+    int extended_audio = par->codec_id == AV_CODEC_ID_OPUS
+                            || par->codec_id == AV_CODEC_ID_FLAC
+                            || par->codec_id == AV_CODEC_ID_AC3
+                            || par->codec_id == AV_CODEC_ID_EAC3;
+
     if (par->codec_type == AVMEDIA_TYPE_AUDIO && !pkt->size) {
         av_log(s, AV_LOG_WARNING, "Empty audio Packet\n");
         return AVERROR(EINVAL);
     }
 
-    if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A ||
-        par->codec_id == AV_CODEC_ID_VP6  || par->codec_id == AV_CODEC_ID_AAC)
+    if (extended_audio)
+        flags_size = 5;
+    else if (par->codec_id == AV_CODEC_ID_VP6F || par->codec_id == AV_CODEC_ID_VP6A ||
+             par->codec_id == AV_CODEC_ID_VP6  || par->codec_id == AV_CODEC_ID_AAC)
         flags_size = 2;
     else if (par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4 ||
              par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
@@ -1046,7 +1097,8 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
 
     if (par->codec_id == AV_CODEC_ID_AAC || par->codec_id == AV_CODEC_ID_H264
             || par->codec_id == AV_CODEC_ID_MPEG4 || par->codec_id == AV_CODEC_ID_HEVC
-            || par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9) {
+            || par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9
+            || par->codec_id == AV_CODEC_ID_OPUS || par->codec_id == AV_CODEC_ID_FLAC) {
         size_t side_size;
         uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
         if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) {
@@ -1178,12 +1230,12 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
         avio_seek(pb, data_size + 10 - 3, SEEK_CUR);
         avio_wb32(pb, data_size + 11);
     } else {
-        int extended_flv = (par->codec_id == AV_CODEC_ID_H264 && track_idx) ||
-                            par->codec_id == AV_CODEC_ID_HEVC ||
-                            par->codec_id == AV_CODEC_ID_AV1 ||
-                            par->codec_id == AV_CODEC_ID_VP9;
+        int extended_video = (par->codec_id == AV_CODEC_ID_H264 && track_idx) ||
+                              par->codec_id == AV_CODEC_ID_HEVC ||
+                              par->codec_id == AV_CODEC_ID_AV1 ||
+                              par->codec_id == AV_CODEC_ID_VP9;
 
-        if (extended_flv) {
+        if (extended_video) {
             int h2645 = par->codec_id == AV_CODEC_ID_H264 ||
                         par->codec_id == AV_CODEC_ID_HEVC;
             int pkttype = PacketTypeCodedFrames;
@@ -1211,6 +1263,21 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
                 avio_w8(pb, track_idx);
             if (h2645 && pkttype == PacketTypeCodedFrames)
                 avio_wb24(pb, pkt->pts - pkt->dts);
+        } else if (extended_audio) {
+            avio_w8(pb, FLV_CODECID_EX_HEADER | AudioPacketTypeCodedFrames);
+
+            if (par->codec_id == AV_CODEC_ID_AAC)
+                avio_write(pb, "mp4a", 4);
+            else if (par->codec_id == AV_CODEC_ID_OPUS)
+                avio_write(pb, "Opus", 4);
+            else if (par->codec_id == AV_CODEC_ID_FLAC)
+                avio_write(pb, "fLaC", 4);
+            else if (par->codec_id == AV_CODEC_ID_MP3)
+                avio_write(pb, ".mp3", 4);
+            else if (par->codec_id == AV_CODEC_ID_AC3)
+                avio_write(pb, "ac-3", 4);
+            else if (par->codec_id == AV_CODEC_ID_EAC3)
+                avio_write(pb, "ec-3", 4);
         } else {
             av_assert1(flags >= 0);
             avio_w8(pb, flags);



More information about the ffmpeg-cvslog mailing list