FLV 和 HTTP-FLV

FLV

简介

FLV(Flash Video)是 Adobe 公司推出的一种媒体文件格式,是一种非常常见的音视频封装格式,尤其是在流媒体场景中。在直播领域,通常采用 RTMP 推流,HTTP-FLV 播放的方案。

FLV 由 FLV Header,FLV Body 组成,FLV Body 由 FLV Tag 组成,FLV Tag 由 FLV Tag Header 和 FLV Tag Body 组成。FLV Tag 分为 Video Tag、Audio Tag 和 Script Tag,分别用来存放视频数据、音频数据和 MetaData 数据。

FLV总体格式

FLV Header

FLV Header 占用 9 个字节。

  • 3 个字节是文件的标识,固定是 FLV。
  • 1 个字节表示版本
  • 1 个字节中的第 6 位表示是否存在音频数据,第 8 位表示是否存在视频数据,其他位为 0 。
  • 4 个字节表示 FLV Header 的大小。

直播场景中的 HTTP-FLV 播放必须首先发送 FLV Header 。

FLV Tag

FLV Tag 分为Script Tag、Video Tag 和 Audio Tag,分别用来存放 MetaData 数据、视频数据和音频数据。

FLV Tag

FLV Tag Header

Reserved ~ StreamID 为 Tag Header 字段,共 11 字节。

FLV Script Tag

ScriptTagBody

Script Tag Body

示例
直播场景中的 HTTP-FLV 播放在发送 Video Tag 和 Audio Tag 之前,需要先发送 MetaData 即 Script Tag , 主要包括宽、高、时长、采样率等基础信息。

Script Data 使用 2 个 AMF(Action Message Forma) 包来存放信息。

第一个 AMF 包是 onMetaData 包。第 1 个字节表示的是 AMF 包的类型,第一个 AMF 包一般是字符串类型,字符串类型的值表示是 0x02,之后是 2 字节表示的长度,一般长度总是 10,值是 0x000A,之后就是 10 字节长度字符串,值是 onMetaData 。

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      type     |              length           |                              
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                                onMetaData 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |
   +-+-+-+-+-+-+-+-+

第二个 AMF 包是一个 Objcet 类型的 AMF 包,Object 类型的值表示是 0x03,Objcet 元素为元素名称和值组成的对,常见的元素如下:

常见 meta 元素

winshining/nginx-http-flv-module 的 meta :

    static ngx_rtmp_amf_elt_t       out_inf[] = {

        { NGX_RTMP_AMF_STRING,
          ngx_string("Server"),
          "NGINX HTTP-FLV (https://github.com/winshining/nginx-http-flv-module)", 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("width"),
          &v.width, 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("height"),
          &v.height, 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("displayWidth"),
          &v.width, 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("displayHeight"),
          &v.height, 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("duration"),
          &v.duration, 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("framerate"),
          &v.frame_rate, 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("fps"),
          &v.frame_rate, 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("videodatarate"),
          &v.video_data_rate, 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("videocodecid"),
          &v.video_codec_id, 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("audiodatarate"),
          &v.audio_data_rate, 0 },

        { NGX_RTMP_AMF_NUMBER,
          ngx_string("audiocodecid"),
          &v.audio_codec_id, 0 },

        { NGX_RTMP_AMF_STRING,
          ngx_string("profile"),
          &v.profile, sizeof(v.profile) },

        { NGX_RTMP_AMF_STRING,
          ngx_string("level"),
          &v.level, sizeof(v.level) },
    };

    static ngx_rtmp_amf_elt_t       out_elts[] = {

        { NGX_RTMP_AMF_STRING,
          ngx_null_string,
          "onMetaData", 0 },

        { NGX_RTMP_AMF_OBJECT,
          ngx_null_string,
          out_inf, sizeof(out_inf) },
    };

FLV Tag Audio Header

FLV Tag Audio Header

特别说明:

  1. SoundFormat = 3, Linear PCM little endian,存储原始 PCM 样本。如果数据为 8 位,则样本为无符号字节。如果数据是 16 位,则样本存储为小端、有符号数字。如果数据是立体声,则左右样本交错存储:左-右-左-右-等等。
  2. SoundFormat = 0 的 PCM 与 SoundFormat = 3 的 PCM 区别:SoundFormat = 0 的 PCM 按创建文件的平台的字节序顺序存储 16 位 PCM 样本。
  3. SoundFormat = 5 的 Nellymoser 8 kHz 和 SoundFormat = 6 的 Nellymoser 16 kHz 是特殊情况,因为 SoundRate 字段不能表示 8 kHz 和 16 kHz 采样率。当在 SoundFormat 中指定 Nellymoser 8 kHz 或 Nellymoser 16 kHz 时,Flash Player 将忽略 SoundRate 和 SoundType 字段。对于其他 Nellymoser 采样率,请指定正常的 Nellymoser SoundFormat 并照常使用 SoundRate 和 SoundType 字段。
  4. 如果 SoundFormat = 10 指示 AAC,SoundType 应为 1 (立体声),SoundRate 应为 3(44kHz)。但是,这并不意味着 FLV 中的 AAC 音频总是立体声、44kHz。相反,Flash Player会忽略 SoundType 和 SoundRate,而是根据 AAC Audio Data 中的 AAC sequence header 提取通道(单/双通道)和采样率。
  5. 如果 SoundFormat = 11 指示 Speex,则音频是以 16 kHz 采样的压缩单声道,SoundRate 应为 0,SoundSize 应为 1,SoundType 应为 0 。

FLV Tag Audio Data

AudioData 包含音频有效载荷:

  1. 如果加密,则为 EncrytedBody
  2. 如果非加密,则为 AudioTagBody

AudioTagBody :

  1. 如果 SoundFormat == 10 (AAC),则为 AACAudioData
  2. 否则,因 SoundFormat 而异,通常是对应格式的 Raw audio frame data

AACAudioData :

  1. 如果 AACPacketType == 0,表示 AAC Header
  2. 如果 AACPacketType == 1,表示 AAC Raw audio frame data

在直播场景中,若使用 AAC 格式的音频,则通常需要首先发送 AAC Header(包含通道(单/双通道)、采样率等信息 ),再发送 AAC Raw audio frame data 。

FLV Tag Video Header

Tag Video Header

FLV Tag Video Data

VideoData 包含音频有效载荷:

  1. 如果加密,则为 EncrytedBody
  2. 如果非加密,则为 VideoTagBody

VideoTagBody :

  1. 如果 FrameType == 5,则 VideoTagBody 为 Video frame payload 或 frame info
  2. 否则
    2.1 如果 CodecId == 2,则 VideoTagBody 为 H263 Video Packet
    2.2 如果 CodecId == 3,则 VideoTagBody 为 Screen Video Packet
    2.3 如果 CodecId == 4,则 VideoTagBody 为 VP6 FLV Video Packet
    2.4 如果 CodecId == 5,则 VideoTagBody 为 VP6 FLV Alpha Video Packet
    2.5 如果 CodecId == 6,则 VideoTagBody 为 Screen V2 Video Packet
    2.6 如果 CodecId == 7,则 VideoTagBody 为 AVC Video Packet

AVC Video Packet :

  1. 如果 AVCPacketType == 0,表示 AVC sequence Header
  2. 如果 AVCPacketType == 1,表示 One or more NALUs (more 是因为 AVC slice,在 AVC 中)

在直播场景中,若使用 AVC 格式的视频,则通常需要首先发送 AVC sequence Header (包含解码信息等 ),再发送 NALUs 。

AVCPacketType == 0 时,AVCPacket 为 AVC sequence header。 AVC sequence header 是 AVCDecoderConfigurationRecord 结构(包含SPS、PPS等编码参数集),该结构在标准文档 ISO-14496-15 AVC file format 中有详细说明。

AVCPacketType == 1 时 AVCPacket 包含 1个 或 多个 NALU。一个 AVCPacket 应该包含一个 frame,但是在 H.264 的 VCL (视频编码层)中可能会将 frame 分成 slice,每个 slice 作为 RBSP 被封装在单独的 NALU 中,因此一个 AVCPacket 包含一个 frame 时可能需要包含多个 NALU (即多个 slice)。

FLV 中包含的 NALU 通常采用 AVCC 格式封装,AVCC在每个NALU前都加上一个大端格式的前缀(1、2、4 字节,通常采用 4 字节)代表NALU长度。

HTTP-FLV

HTTP-FLV 是将音视频数据以 FLV 文件格式进行封装,再将 FLV 格式数据封装在 HTTP 协议中进行传输的一种流媒体传输方式。

HTTP-FLV 被广泛采用的原因:

  1. HTTP 优点:
    a. 一些防火墙会墙掉 RTMP 或者其他的一些协议,但是防火墙对 HTTP 非常友好,不会墙掉 HTTP,因此基于 HTTP 传输的成功率更高。
  2. FLV 优点:
    a. MP4、MKV 等封装格式将音视频数据和音视频元数据、索引、时间戳等分开存放,必须拿到完整的音视频文件才能播放,因为里面的单个音视频数据块不带有时间戳信息,播放器不能将这些没有时间戳信息的数据块连续起来,因此不能实时的解码播放。(当然 MP4 后来扩展了 FMP4 用于流媒体)
    b. FLV 格式的 FLV Tag Header 中携带时间戳,FLV 将每一帧音视频数据(Tag Body)封装成包含时间戳等音视频元数据(Tag Header)的数据包(Tag)。当播放器拿到 Tag 后,可根据时间戳等音视频元数据进行解码和播放。

HTTP-FLV 的实现原理: HTTP-FLV 利用 HTTP/1.1 分块传输机制发送 FLV 数据。虽然直播服务器无法知道直播流的长度,但是 HTTP/1.1 分块传输机制可以不填写 conten-length 字段而是携带 Transfer-Encoding: chunked 字段,这样客户端就会一直接受数据。

HTTP FLV

你可能感兴趣的:(FLV 和 HTTP-FLV)