FLV specification
),
我们可以这么来理解 FLV 封装格式,除了 header 之外,它里面包含了一系列的 Tag,可能是 Video Tag,也可能是 Audio Tag, 这个是 FLV 文档来定义的。其中每个 Tag 里面包含了一些
描述性信息
,以及对应的编码后的 AAC 或者 H.264 数据。如果我们分为两层来看的话,一层是 FLV Tag,一层是编码后的音视频数据。
了解这个之后,我们再来试着理解上面提到的
read_frame_internal()
函数和
try_decode_frame()
在这里的作用。
read_frame_internal()
函数本质上就是从网络中读取音视频的 packet,对应到 FLV 格式的话,其实就是读取第一层,也就是 也就是 FLV Tag 信息,从 tag 里可以读取 tag 的一些
描述性信息
, 这些描述性信息包括(参考自 FLV Specification):
编码格式,是 AAC 还是 MP3,还是 Linear PCM?
Sample rate, 采样率,比如 48000
通道数,单声道还是双声道?(FLV 最多支持两个声道)
Bit depth
帧类型,关键帧还是中间帧?
编码格式,H.264 还是 H.263,还是 VP6 等其他格式?
那
read_frame_internal()
函数能拿到的就是上面的这些信息,这个信息是否够全呢?跟上面提到的
has_codec_parameters()
检测函数里的要求相比,确实还差了一些信息。比如音频的 sample format(比如
AV_SAMPLE_FMT_FLTP
),它需要打开音频解码器之后才能确定,sample rate 等信息也是解码后得到的更加准确。
视频的宽高、pixel format 信息是存放在 H.264 流信息里,所以也需要解码之后才能获取到,所以,这里才需要
try_decode_frame()
函数去做解码的工作才能拿到完整的信息。
也就是说
read_frame_internal()
函数负责从第一层 FLV Tag 里获得流信息,
try_decode_frame()
函数负责解码第二层的编码数据,来获取更多的流编码信息,最终汇总为完整的流信息,所以两处函数调用都是必要的。
OK,我们这里不展开
read_frame_internal()
函数 和
try_decode_frame()
函数内部的实现,有兴趣的小伙伴可以自己读读源码。