音视频入门基础:FLV专题(21)——FFmpeg源码中,获取FLV文件音频信息的实现(上)

由于本文篇幅较长,分为上、中、下三篇。

一、引言

通过FFmpeg命令可以获取到FLV文件的音频压缩编码格式、音频采样率、通道数、音频码率信息:

cpp 复制代码
./ffmpeg -i XXX.flv

而由《音视频入门基础:FLV专题(9)------Script Tag简介》和《音视频入门基础:FLV专题(18)------Audio Tag简介》可以知道:FLV文件中名称为"onMetadata"的Script Tag、每个Audio Tag的AudioTagHeader、AudioSpecificConfig都会包含音频信息。

名称为"onMetadata"的Script Tag:

每个Audio Tag的AudioTagHeader:

AudioSpecificConfig:

可以看到,FLV文件中的上述三个地方都会存在音频信息,有些信息比如:音频压缩编码格式、音频采样率、通道数甚至是重复的。所以FFmpeg到底获取的是哪个地方的音频信息呢,本文为大家揭开谜底。

二、音频压缩编码格式

FFmpeg获取FLV文件的音频压缩编码格式,获取的是Audio Tag的AudioTagHeader中的音频压缩编码格式。由《音视频入门基础:FLV专题(18)------Audio Tag简介》可以知道,AudioTagHeader存在一个占4位的SoundFormat属性,表示音频的压缩编码格式:

0:Linear PCM, platform endian

1:ADPCM

2:MP3

3:Linear PCM, little endian

4:Nellymoser 16 kHz mono

5:Nellymoser 8 kHz mono

6:Nellymoser

7:G.711 A-law logarithmic PCM

8:G.711 mu-law logarithmic PCM

9:reserved

10:AAC

11:Speex

14:MP3 8 kHz

15:Device-specific sound

由《音视频入门基础:FLV专题(19)------FFmpeg源码中,解码Audio Tag的AudioTagHeader,并提取AUDIODATA的实现》可以知道,FFmpeg源码中使用flv_read_packet函数来读取每个Tag的信息。如果判断出该Tag为Audio Tag,flv_read_packet函数中会通过下面代码块将AudioTagHeader的SoundFormat属性提取出来,转换得到音频压缩编码格式。将音频压缩编码格式赋值给st->codecpar->codec_id中。st->codecpar为指向一个AVCodecParameters类型变量的指针:

cpp 复制代码
        if (!st->codecpar->codec_id) {
            flv_set_audio_codec(s, st, st->codecpar,
                                flags & FLV_AUDIO_CODECID_MASK);
        //...
        }

然后在flv_read_packet函数外部,通过avcodec_parameters_to_context函数将AVCodecParameters的codec_id赋值给AVCodecContext的codec_id:

cpp 复制代码
int avcodec_parameters_to_context(AVCodecContext *codec,
                                  const AVCodecParameters *par)
{
//...
    codec->codec_id   = par->codec_id;
//...
}

然后在dump_stream_format函数中,通过avcodec_string函数中的语句:codec_name = avcodec_get_name(enc->codec_id) 拿到AVCodecContext的codec_id对应的音频压缩编码格式名称。最后再在dump_stream_format函数中将音频压缩编码格式打印出来:

cpp 复制代码
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...
    codec_name = avcodec_get_name(enc->codec_id);
//...
}

所以FFmpeg获取FLV文件的音频压缩编码格式,获取的是Audio Tag的AudioTagHeader中的音频压缩编码格式:

三、音频压缩编码格式的profile

音频压缩编码格式还有附带的profile(规格)。比如音频压缩编码格式为AAC,根据《ISO14496-3-2009.pdf》第124页,还有AAC Main、AAC LC、AAC SSR、AAC LTP这几种规格:

FFmpeg获取FLV文件的音频压缩编码格式的profile,获取的是AudioSpecificConfig中的audioObjectType。由《音视频入门基础:AAC专题(11)------AudioSpecificConfig简介》可以知道,FLV文件中的音频为AAC时,正常情况下它必定存在一个Audio Tag包含Audio Specific Config,而Audio Specific Config中存在一个占5位或11位的audioObjectType属性,表示音频对象类型:

0: Null

1: AAC Main

2: AAC LC (Low Complexity)

3: AAC SSR (Scalable Sample Rate)

4: AAC LTP (Long Term Prediction)

5: SBR (Spectral Band Replication)

6: AAC Scalable

7: TwinVQ

8: CELP (Code Excited Linear Prediction)

9: HXVC (Harmonic Vector eXcitation Coding)

10: Reserved

11: Reserved

12: TTSI (Text-To-Speech Interface)

13: Main Synthesis

14: Wavetable Synthesis

15: General MIDI

16: Algorithmic Synthesis and Audio Effects

17: ER (Error Resilient) AAC LC

18: Reserved

19: ER AAC LTP

20: ER AAC Scalable

21: ER TwinVQ

22: ER BSAC (Bit-Sliced Arithmetic Coding)

23: ER AAC LD (Low Delay)

24: ER CELP

25: ER HVXC

26: ER HILN (Harmonic and Individual Lines plus Noise)

27: ER Parametric

28: SSC (SinuSoidal Coding)

29: PS (Parametric Stereo)

30: MPEG Surround

31: (Escape value)

32: Layer-1

33: Layer-2

34: Layer-3

35: DST (Direct Stream Transfer)

36: ALS (Audio Lossless)

37: SLS (Scalable LosslesS)

38: SLS non-core

39: ER AAC ELD (Enhanced Low Delay)

40: SMR (Symbolic Music Representation) Simple

41: SMR Main

42: USAC (Unified Speech and Audio Coding) (no SBR)

43: SAOC (Spatial Audio Object Coding)

44: LD MPEG Surround

45: USAC

由《音视频入门基础:AAC专题(12)------FFmpeg源码中,解码AudioSpecificConfig的实现》可以知道,FFmpeg源码中使用decode_audio_specific_config_gb函数来读取AudioSpecificConfig的信息。decode_audio_specific_config_gb函数中会调用ff_mpeg4audio_get_config_gb函数,而ff_mpeg4audio_get_config_gb函数中,通过语句:c->object_type = get_object_type(gb) 获取AudioSpecificConfig的audioObjectType属性。执行decode_audio_specific_config_gb函数后,m4ac指向的变量会得到从AudioSpecificConfig中解码出来的属性:

cpp 复制代码
static inline int get_object_type(GetBitContext *gb)
{
    int object_type = get_bits(gb, 5);
    if (object_type == AOT_ESCAPE)
        object_type = 32 + get_bits(gb, 6);
    return object_type;
}

然后在decode_audio_specific_config_gb函数外部,通过aac_decode_frame_int函数将上一步得到的audioObjectType属性赋值给AVCodecContext的profile:

cpp 复制代码
static int aac_decode_frame_int(AVCodecContext *avctx, AVFrame *frame,
                                int *got_frame_ptr, GetBitContext *gb,
                                const AVPacket *avpkt)
{
//...
    // The AV_PROFILE_AAC_* defines are all object_type - 1
    // This may lead to an undefined profile being signaled
    ac->avctx->profile = ac->oc[1].m4ac.object_type - 1;
//...
}

然后在dump_stream_format函数中,通过avcodec_string函数中的语句:profile = avcodec_profile_name(enc->codec_id, enc->profile)拿到上一步中得到的AVCodecContext的profile。最后再在dump_stream_format函数中将profile打印出来:

cpp 复制代码
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
//...
    profile = avcodec_profile_name(enc->codec_id, enc->profile);
//...
}

所以FFmpeg获取FLV文件的音频压缩编码格式的profile,获取的是AudioSpecificConfig中的audioObjectType:

相关推荐
岁月小龙4 小时前
如何让ffmpeg运行时从当前目录加载库,而不是从/lib64
ffmpeg·origin·ffprobe·rpath
我喜欢就喜欢6 小时前
基于qt vs下的视频播放
开发语言·qt·音视频
安步当歌6 小时前
【WebRTC】视频采集模块中各个类的简单分析
音视频·webrtc·视频编解码·video-codec
EasyGBS7 小时前
国标GB28181公网直播EasyGBS国标GB28181软件管理解决方案
大数据·网络·音视频·媒体·视频监控·gb28181
Johnstons10 小时前
AnaTraf | 网络性能监控系统保障音视频质量的秘籍
网络·音视频·网络流量监控·网络流量分析·npmd
lrlianmengba10 小时前
推荐一款非常好用的视频编辑软件:Movavi Video Editor Plus
音视频
SZ17011023110 小时前
ffplay 实现视频流中音频的延迟
音视频·延迟
LNTON羚通12 小时前
CPU算法分析LiteAIServer视频智能分析平台视频智能分析:抖动、过亮与过暗检测技术
大数据·目标检测·音视频·视频监控
MediaTea13 小时前
Pr 视频过渡:沉浸式视频 - VR 光线
音视频·vr
几何心凉18 小时前
视频自动播放被浏览器阻止及其解决方案
音视频