forked from FFmpeg/FFmpeg
avformat/flvdec: add enhanced audio codecs
This commit is contained in:
parent
70067c829b
commit
2f72dc33ff
2 changed files with 116 additions and 11 deletions
|
@ -132,6 +132,14 @@ enum {
|
||||||
enum {
|
enum {
|
||||||
AudioPacketTypeSequenceStart = 0,
|
AudioPacketTypeSequenceStart = 0,
|
||||||
AudioPacketTypeCodedFrames = 1,
|
AudioPacketTypeCodedFrames = 1,
|
||||||
|
AudioPacketTypeMultichannelConfig = 4,
|
||||||
|
AudioPacketTypeMultitrack = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AudioChannelOrderUnspecified = 0,
|
||||||
|
AudioChannelOrderNative = 1,
|
||||||
|
AudioChannelOrderCustom = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -224,12 +224,33 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type, int track_idx
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flv_same_audio_codec(AVCodecParameters *apar, int flags)
|
static int flv_same_audio_codec(AVCodecParameters *apar, int flags, uint32_t codec_fourcc)
|
||||||
{
|
{
|
||||||
int bits_per_coded_sample = (flags & FLV_AUDIO_SAMPLESIZE_MASK) ? 16 : 8;
|
int bits_per_coded_sample = (flags & FLV_AUDIO_SAMPLESIZE_MASK) ? 16 : 8;
|
||||||
int flv_codecid = flags & FLV_AUDIO_CODECID_MASK;
|
int flv_codecid = flags & FLV_AUDIO_CODECID_MASK;
|
||||||
int codec_id;
|
int codec_id;
|
||||||
|
|
||||||
|
switch (codec_fourcc) {
|
||||||
|
case MKBETAG('m', 'p', '4', 'a'):
|
||||||
|
return apar->codec_id == AV_CODEC_ID_AAC;
|
||||||
|
case MKBETAG('O', 'p', 'u', 's'):
|
||||||
|
return apar->codec_id == AV_CODEC_ID_OPUS;
|
||||||
|
case MKBETAG('.', 'm', 'p', '3'):
|
||||||
|
return apar->codec_id == AV_CODEC_ID_MP3;
|
||||||
|
case MKBETAG('f', 'L', 'a', 'C'):
|
||||||
|
return apar->codec_id == AV_CODEC_ID_FLAC;
|
||||||
|
case MKBETAG('a', 'c', '-', '3'):
|
||||||
|
return apar->codec_id == AV_CODEC_ID_AC3;
|
||||||
|
case MKBETAG('e', 'c', '-', '3'):
|
||||||
|
return apar->codec_id == AV_CODEC_ID_EAC3;
|
||||||
|
case 0:
|
||||||
|
// Not enhanced flv, continue as normal.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Unknown FOURCC
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!apar->codec_id && !apar->codec_tag)
|
if (!apar->codec_id && !apar->codec_tag)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -328,6 +349,24 @@ static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream,
|
||||||
apar->sample_rate = 8000;
|
apar->sample_rate = 8000;
|
||||||
apar->codec_id = AV_CODEC_ID_PCM_ALAW;
|
apar->codec_id = AV_CODEC_ID_PCM_ALAW;
|
||||||
break;
|
break;
|
||||||
|
case MKBETAG('m', 'p', '4', 'a'):
|
||||||
|
apar->codec_id = AV_CODEC_ID_AAC;
|
||||||
|
return;
|
||||||
|
case MKBETAG('O', 'p', 'u', 's'):
|
||||||
|
apar->codec_id = AV_CODEC_ID_OPUS;
|
||||||
|
return;
|
||||||
|
case MKBETAG('.', 'm', 'p', '3'):
|
||||||
|
apar->codec_id = AV_CODEC_ID_MP3;
|
||||||
|
return;
|
||||||
|
case MKBETAG('f', 'L', 'a', 'C'):
|
||||||
|
apar->codec_id = AV_CODEC_ID_FLAC;
|
||||||
|
return;
|
||||||
|
case MKBETAG('a', 'c', '-', '3'):
|
||||||
|
apar->codec_id = AV_CODEC_ID_AC3;
|
||||||
|
return;
|
||||||
|
case MKBETAG('e', 'c', '-', '3'):
|
||||||
|
apar->codec_id = AV_CODEC_ID_EAC3;
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
avpriv_request_sample(s, "Audio codec (%x)",
|
avpriv_request_sample(s, "Audio codec (%x)",
|
||||||
flv_codecid >> FLV_AUDIO_CODECID_OFFSET);
|
flv_codecid >> FLV_AUDIO_CODECID_OFFSET);
|
||||||
|
@ -1249,7 +1288,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||||
int multitrack = 0;
|
int multitrack = 0;
|
||||||
int pkt_type = 0;
|
int pkt_type = 0;
|
||||||
uint8_t track_idx = 0;
|
uint8_t track_idx = 0;
|
||||||
uint32_t video_codec_id = 0;
|
uint32_t codec_id = 0;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
/* pkt size is repeated at end. skip it */
|
/* pkt size is repeated at end. skip it */
|
||||||
|
@ -1293,16 +1332,31 @@ retry:
|
||||||
stream_type = FLV_STREAM_TYPE_AUDIO;
|
stream_type = FLV_STREAM_TYPE_AUDIO;
|
||||||
flags = avio_r8(s->pb);
|
flags = avio_r8(s->pb);
|
||||||
size--;
|
size--;
|
||||||
|
|
||||||
|
if ((flags & FLV_AUDIO_CODECID_MASK) == FLV_CODECID_EX_HEADER) {
|
||||||
|
enhanced_flv = 1;
|
||||||
|
pkt_type = flags & ~FLV_AUDIO_CODECID_MASK;
|
||||||
|
|
||||||
|
channels = 0;
|
||||||
|
|
||||||
|
if (pkt_type == AudioPacketTypeMultitrack) {
|
||||||
|
av_log(s, AV_LOG_ERROR, "Multitrack audio is unsupported!\n");
|
||||||
|
return AVERROR_PATCHWELCOME;
|
||||||
|
}
|
||||||
|
|
||||||
|
codec_id = avio_rb32(s->pb);
|
||||||
|
size -= 4;
|
||||||
|
}
|
||||||
} else if (type == FLV_TAG_TYPE_VIDEO) {
|
} else if (type == FLV_TAG_TYPE_VIDEO) {
|
||||||
stream_type = FLV_STREAM_TYPE_VIDEO;
|
stream_type = FLV_STREAM_TYPE_VIDEO;
|
||||||
flags = avio_r8(s->pb);
|
flags = avio_r8(s->pb);
|
||||||
video_codec_id = flags & FLV_VIDEO_CODECID_MASK;
|
codec_id = flags & FLV_VIDEO_CODECID_MASK;
|
||||||
/*
|
/*
|
||||||
* Reference Enhancing FLV 2023-03-v1.0.0-B.8
|
* Reference Enhancing FLV 2023-03-v1.0.0-B.8
|
||||||
* https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp-v1.pdf
|
* https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp-v1.pdf
|
||||||
* */
|
* */
|
||||||
enhanced_flv = (flags >> 7) & 1;
|
enhanced_flv = (flags >> 7) & 1;
|
||||||
pkt_type = enhanced_flv ? video_codec_id : 0;
|
pkt_type = enhanced_flv ? codec_id : 0;
|
||||||
size--;
|
size--;
|
||||||
|
|
||||||
if (pkt_type == PacketTypeMultitrack) {
|
if (pkt_type == PacketTypeMultitrack) {
|
||||||
|
@ -1320,7 +1374,7 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enhanced_flv) {
|
if (enhanced_flv) {
|
||||||
video_codec_id = avio_rb32(s->pb);
|
codec_id = avio_rb32(s->pb);
|
||||||
size -= 4;
|
size -= 4;
|
||||||
}
|
}
|
||||||
if (multitrack) {
|
if (multitrack) {
|
||||||
|
@ -1388,11 +1442,11 @@ skip:
|
||||||
st = s->streams[i];
|
st = s->streams[i];
|
||||||
if (stream_type == FLV_STREAM_TYPE_AUDIO) {
|
if (stream_type == FLV_STREAM_TYPE_AUDIO) {
|
||||||
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
|
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
|
||||||
(s->audio_codec_id || flv_same_audio_codec(st->codecpar, flags)))
|
(s->audio_codec_id || flv_same_audio_codec(st->codecpar, flags, codec_id)))
|
||||||
break;
|
break;
|
||||||
} else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
|
} else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
|
||||||
if (st->codecpar->codec_type == AVMEDIA_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, codec_id)) &&
|
||||||
st->id == track_idx)
|
st->id == track_idx)
|
||||||
break;
|
break;
|
||||||
} else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) {
|
} else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) {
|
||||||
|
@ -1461,7 +1515,7 @@ retry_duration:
|
||||||
flv->searched_for_end = 1;
|
flv->searched_for_end = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream_type == FLV_STREAM_TYPE_AUDIO) {
|
if (stream_type == FLV_STREAM_TYPE_AUDIO && !enhanced_flv) {
|
||||||
int bits_per_coded_sample;
|
int bits_per_coded_sample;
|
||||||
channels = (flags & FLV_AUDIO_CHANNEL_MASK) == FLV_STEREO ? 2 : 1;
|
channels = (flags & FLV_AUDIO_CHANNEL_MASK) == FLV_STEREO ? 2 : 1;
|
||||||
sample_rate = 44100 << ((flags & FLV_AUDIO_SAMPLERATE_MASK) >>
|
sample_rate = 44100 << ((flags & FLV_AUDIO_SAMPLERATE_MASK) >>
|
||||||
|
@ -1493,8 +1547,48 @@ retry_duration:
|
||||||
sample_rate = par->sample_rate;
|
sample_rate = par->sample_rate;
|
||||||
avcodec_parameters_free(&par);
|
avcodec_parameters_free(&par);
|
||||||
}
|
}
|
||||||
|
} else if (stream_type == FLV_STREAM_TYPE_AUDIO) {
|
||||||
|
if (!st->codecpar->codec_id) {
|
||||||
|
flv_set_audio_codec(s, st, st->codecpar,
|
||||||
|
codec_id ? codec_id : (flags & FLV_AUDIO_CODECID_MASK));
|
||||||
|
flv->last_sample_rate = 0;
|
||||||
|
flv->last_channels = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are not signalled in the flags anymore
|
||||||
|
channels = 0;
|
||||||
|
sample_rate = 0;
|
||||||
|
|
||||||
|
if (pkt_type == AudioPacketTypeMultichannelConfig) {
|
||||||
|
int channel_order = avio_r8(s->pb);
|
||||||
|
channels = avio_r8(s->pb);
|
||||||
|
size -= 2;
|
||||||
|
|
||||||
|
if (channel_order == AudioChannelOrderCustom) {
|
||||||
|
for (i = 0; i < channels; i++) {
|
||||||
|
avio_r8(s->pb); // audio channel mapping
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
} else if (channel_order == AudioChannelOrderNative) {
|
||||||
|
avio_rb32(s->pb); // audio channel flags
|
||||||
|
size -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!av_channel_layout_check(&st->codecpar->ch_layout)) {
|
||||||
|
///TODO: This can be much more sophisticated with above info.
|
||||||
|
av_channel_layout_default(&st->codecpar->ch_layout, channels);
|
||||||
|
flv->last_channels = channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channels != flv->last_channels) {
|
||||||
|
flv->last_channels = channels;
|
||||||
|
ff_add_param_change(pkt, channels, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
} else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
|
} else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
|
||||||
int ret = flv_set_video_codec(s, st, video_codec_id, 1);
|
int ret = flv_set_video_codec(s, st, codec_id, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
size -= ret;
|
size -= ret;
|
||||||
|
@ -1505,13 +1599,15 @@ retry_duration:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->codecpar->codec_id == AV_CODEC_ID_AAC ||
|
if (st->codecpar->codec_id == AV_CODEC_ID_AAC ||
|
||||||
|
st->codecpar->codec_id == AV_CODEC_ID_OPUS ||
|
||||||
|
st->codecpar->codec_id == AV_CODEC_ID_FLAC ||
|
||||||
st->codecpar->codec_id == AV_CODEC_ID_H264 ||
|
st->codecpar->codec_id == AV_CODEC_ID_H264 ||
|
||||||
st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
|
st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
|
||||||
st->codecpar->codec_id == AV_CODEC_ID_HEVC ||
|
st->codecpar->codec_id == AV_CODEC_ID_HEVC ||
|
||||||
st->codecpar->codec_id == AV_CODEC_ID_AV1 ||
|
st->codecpar->codec_id == AV_CODEC_ID_AV1 ||
|
||||||
st->codecpar->codec_id == AV_CODEC_ID_VP9) {
|
st->codecpar->codec_id == AV_CODEC_ID_VP9) {
|
||||||
int type = 0;
|
int type = 0;
|
||||||
if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO) {
|
if (enhanced_flv) {
|
||||||
type = pkt_type;
|
type = pkt_type;
|
||||||
} else {
|
} else {
|
||||||
type = avio_r8(s->pb);
|
type = avio_r8(s->pb);
|
||||||
|
@ -1547,6 +1643,7 @@ retry_duration:
|
||||||
size -= 3;
|
size -= 3;
|
||||||
}
|
}
|
||||||
if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
|
if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC ||
|
||||||
|
st->codecpar->codec_id == AV_CODEC_ID_OPUS || st->codecpar->codec_id == AV_CODEC_ID_FLAC ||
|
||||||
st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_HEVC ||
|
st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_HEVC ||
|
||||||
st->codecpar->codec_id == AV_CODEC_ID_AV1 || st->codecpar->codec_id == AV_CODEC_ID_VP9)) {
|
st->codecpar->codec_id == AV_CODEC_ID_AV1 || st->codecpar->codec_id == AV_CODEC_ID_VP9)) {
|
||||||
AVDictionaryEntry *t;
|
AVDictionaryEntry *t;
|
||||||
|
@ -1602,7 +1699,7 @@ retry_duration:
|
||||||
flv->mt_extradata_sz[track_idx] = 0;
|
flv->mt_extradata_sz[track_idx] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stream_type == FLV_STREAM_TYPE_AUDIO &&
|
if (stream_type == FLV_STREAM_TYPE_AUDIO && !enhanced_flv &&
|
||||||
(sample_rate != flv->last_sample_rate ||
|
(sample_rate != flv->last_sample_rate ||
|
||||||
channels != flv->last_channels)) {
|
channels != flv->last_channels)) {
|
||||||
flv->last_sample_rate = sample_rate;
|
flv->last_sample_rate = sample_rate;
|
||||||
|
|
Loading…
Add table
Reference in a new issue