=================================================================
音视频入门基础:FLV专题系列文章:
音视频入门基础:FLV专题(1)——FLV官方文档下载
音视频入门基础:FLV专题(2)——使用FFmpeg命令生成flv文件
音视频入门基础:FLV专题(3)——FLV header简介
音视频入门基础:FLV专题(4)——使用flvAnalyser工具分析FLV文件
音视频入门基础:FLV专题(5)——FFmpeg源码中,判断某文件是否为FLV文件的实现
音视频入门基础:FLV专题(6)——FFmpeg源码中,解码FLV header的实现
音视频入门基础:FLV专题(7)——Tag header简介
音视频入门基础:FLV专题(8)——FFmpeg源码中,解码Tag header的实现
音视频入门基础:FLV专题(9)——Script Tag简介
音视频入门基础:FLV专题(10)——Script Tag实例分析
音视频入门基础:FLV专题(11)——FFmpeg源码中,解析SCRIPTDATASTRING类型的ScriptDataValue的实现
音视频入门基础:FLV专题(12)——FFmpeg源码中,解析DOUBLE类型的ScriptDataValue的实现
音视频入门基础:FLV专题(13)——FFmpeg源码中,解析任意Type值的SCRIPTDATAVALUE类型的实现
音视频入门基础:FLV专题(14)——FFmpeg源码中,解码Script Tag的实现
音视频入门基础:FLV专题(15)——Video Tag简介
音视频入门基础:FLV专题(16)——FFmpeg源码中,解码Video Tag的VideoTagHeader的实现
音视频入门基础:FLV专题(17)——FFmpeg源码中,提取Video Tag的VIDEODATA的实现
音视频入门基础:FLV专题(18)——Audio Tag简介
音视频入门基础:FLV专题(19)——FFmpeg源码中,解码Audio Tag的AudioTagHeader,并提取AUDIODATA的实现
音视频入门基础:FLV专题(20)——FFmpeg源码中,获取FLV文件major_brand、minor_version、compatible_brands、encoder、Duration的实现
音视频入门基础:FLV专题(21)——FFmpeg源码中,获取FLV文件音频信息的实现(上)
音视频入门基础:FLV专题(22)——FFmpeg源码中,获取FLV文件音频信息的实现(中)
音视频入门基础:FLV专题(23)——FFmpeg源码中,获取FLV文件音频信息的实现(下)
音视频入门基础:FLV专题(24)——FFmpeg源码中,获取FLV文件视频信息的实现
音视频入门基础:FLV专题(25)——通过FFprobe显示FLV文件每个packet的信息
=================================================================
本文接着《音视频入门基础:FLV专题(22)——FFmpeg源码中,获取FLV文件音频信息的实现(中)》,继续讲解FFmpeg获取FLV文件的音频信息到底是从哪个地方获取的。本文的一级标题从“七”开始。
七、Bit depth
FLV文件中每个Audio Tag的AudioTagHeader的SoundSize属性都包含Bit depth(又叫位深度、位元深度、采样深度、采样位数、采样格式)信息。但是如果FLV文件中的音频压缩编码格式为AAC,FFmpeg会强制把Bit depth设置为fltp。这是因为对于有损压缩编解码器(如MP3和AAC),Bit depth是在编码期间计算的,并且可以因采样而异,Bit depth只对PCM数字信号有意义。具体可以参考:《音视频入门基础:AAC专题(3)——AAC的ADTS格式简介》。
可以看到在aac_decode_init函数中(该函数定义在libavcodec/aacdec_template.c),强制把音频采样格式设置成了AV_SAMPLE_FMT_FLTP:
static av_cold int aac_decode_init(AVCodecContext *avctx)
{
//...
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
//...
}
所以如果FLV文件中的音频压缩编码格式为AAC,通过“ffmpeg -i video1.flv命令”获取到的音频采样格式固定为fltp,该值没有意义:
八、音频码率
FFmpeg获取音频码率是通过解析名称为“onMetadata”的Script Tag获取的。onMetadata中存在一个audiodatarate属性表示音频码率,单位为kilobits per second,即Kbps:
由《音视频入门基础:FLV专题(13)——FFmpeg源码中,解析任意Type值的SCRIPTDATAVALUE类型的实现》、《音视频入门基础:FLV专题(14)——FFmpeg源码中,解码Script Tag的实现》可以知道,FFmpeg源码通过amf_parse_object函数中的下面代码块将名称为“onMetadata”的Script Tag中audiodatarate属性解析出来,乘以1024,得到单位为bps的音频码率,存到flv->audio_bit_rate中,即存到(FLVContext *)(s->priv_data)->audio_bit_rate中:
static int amf_parse_object(AVFormatContext *s, AVStream *astream,
AVStream *vstream, const char *key,
int64_t max_pos, int depth)
{
//...
if (key) {
//...
if (depth == 1) {
if (amf_type == AMF_DATA_TYPE_NUMBER ||
amf_type == AMF_DATA_TYPE_BOOL) {
//...
else if (!strcmp(key, "audiodatarate") &&
0 <= (int)(num_val * 1024.0))
flv->audio_bit_rate = num_val * 1024.0;
//...
}
//...
}
}
}
然后通过libavformat/flvdec.c中的create_stream函数,将flv->audio_bit_rate赋值给AVCodecParameters的bit_rate。st->codecpar为指向一个AVCodecParameters类型变量的指针:
static AVStream *create_stream(AVFormatContext *s, int codec_type)
{
//...
if (codec_type == AVMEDIA_TYPE_AUDIO) {
st->codecpar->bit_rate = flv->audio_bit_rate;
flv->missing_streams &= ~FLV_HEADER_FLAG_HASAUDIO;
}
//...
}
通过avcodec_parameters_to_context函数将AVCodecParameters的bit_rate赋值给AVCodecContext的bit_rate:
int avcodec_parameters_to_context(AVCodecContext *codec,
const AVCodecParameters *par)
{
//...
codec->bit_rate = par->bit_rate;
//...
}
然后在dump_stream_format函数中,通过avcodec_string函数中的语句:bitrate = get_bit_rate(enc)拿到AVCodecContext的bit_rate,该bit_rate以bps为单位。最后再把它除以1000,得到以kb/s为单位的音频码率,打印出来:
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...
bitrate = get_bit_rate(enc);
if (bitrate != 0) {
av_bprintf(&bprint, ", %"PRId64" kb/s", bitrate / 1000);
//...
}
所以通过flvAnalyser工具查看到的音频码率跟使用FFmpeg命令查看到的音频码率不一样,这是因为FFmpeg源码中获取onMetadata中的audiodatarate属性是先把它乘以1024,但是打印的时候再除以1000的(正常情况下打印的时候应该除以1024才对)。比如实际的音频码率为133.6865kb/s,乘以1024就是136895b/s,再除以1000就变成了136kb/s。所以FFmpeg(截止FFmpeg7.0.1)打印音频码率这部分代码应该是有bug的,导致显示的音频码率不准确: