[FFmpeg-devel] [PATCH 03/13] avformat/flvenc: add enhanced audio codecs
Timo Rothenpieler
timo at rothenpieler.org
Tue May 21 12:02:12 EEST 2024
---
libavformat/flv.h | 6 ++
libavformat/flvenc.c | 143 +++++++++++++++++++++++++++++++------------
2 files changed, 111 insertions(+), 38 deletions(-)
diff --git a/libavformat/flv.h b/libavformat/flv.h
index 653c2bc82c..d030d576f3 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/flvenc.c b/libavformat/flvenc.c
index 7ddc59e369..4e79b06499 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -68,6 +68,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 }
};
@@ -138,6 +142,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,
@@ -634,6 +641,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;
@@ -641,7 +684,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 ?
@@ -650,39 +695,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
@@ -1018,13 +1062,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 ||
@@ -1043,7 +1094,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))) {
@@ -1175,12 +1227,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)
+ 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;
@@ -1208,6 +1260,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);
--
2.43.2
More information about the ffmpeg-devel
mailing list