Windows直播软件开发——flv基本知识

602 阅读6分钟

  在获得编码结果后,我们就将它传输到服务器。在实际中具体传到哪里,用什么协议,这个得根据自己的实际需求。由于我是将画面传到斗鱼进行直播,因此我用rtmp协议来进行传输。处理rtmp协议可以使用librtmp这个库,使用起来并不是很难,难的是对编码数据进行封装,这一部分涉及到h.264结构与flv文件格式等知识。对于这一部分的内容,我会着重进行讲解。

rtmp协议

  关于这类知识,大家可以百度一些其它博客,里面已经讲的非常详细了。本文由于篇幅原因,不再赘述。这里贴出rtmp的官方文档的下载链接,大家可自行下载阅读:

rtmp文档下载链接: https://www.adobe.com/devnet/rtmp.html

flv格式讲解

  由于基于rtmp协议的网络播放器都是flash播放器,所以基本上其在rtmp协议上传输的音视频数据,都是基于flv格式的,虽然结构上可能与flv文件的格式会有些许差异,但在大体上是相同的,可以理解为网络版的flv。在讲解flv之前,先放出flv的官方文档下载链接,大家可自行下载:

flv/f4v文档下载链接:https://www.adobe.com/devnet/flv_generic.html#b

flv文件头

  在flv文件中,前九个字节属于flv文件头的部分。但对于网络传输中,我们不需要这个头,因此可以忽略。

flv文件主体

 &esnp;flv主体即是我们所关心的主要部分,其构成形式如下:

对于PreviousTagSize0来说,是一直为0的,而对于后面的 1,2,3,4等,则表示前一个的tag的大小。tag里面存放的也就是我们的音视频数据和控制数据。下面我们分别来介绍一下这几种tag。

tag结构

  tag结构是通用的结构,每种tag的结构都是这样,区分tag类型的,主要是TagType和Data字段。我们来看看它结构是怎样的。

  • TagType:Tag类型,8为音频Tag,9为视频Tag,18为脚本Tag
  • DataSize:Data数据类型的大小
  • TimeStamp:时间戳,单位为毫秒,第一个tag的时间戳为0
  • TimeStampExtended:扩展时间戳,解决原来时间戳长度不够的问题
  • StreamID:值一直为0
  • Data:Tag数据

音频tag

  音频tag的数据格式如下:

  • SoundFormat:音频格式,有PCM,AAC,MP3,Speex等,具体可以参考文档
  • SoundRate:采样率,0:5.5KHz,1:11KHz,2:22KHz,3:44KHz。对于AAC来说,只能为3
  • SoundSize:采样格式,0:8bit,1:16bit,不支持浮点型的32位。
  • SoundType:音频类型:0:sndMono,1:sndStereo。其中mono是单声道的,stereo为立体声。对于aac来说,只能为1
  • SoundData:音频数据
AAC音频数据

  如果SoundData表示的是音频数据,还不可以直接在里面填写AAC数据,在这里面,还得区分格式。格式如下:

  • AACPacketType:AAC数据包类型,0表示AAC的序列头信息,里面存放着可以给播放器进行解码的数据。1则表示AAC数据包
  • Data:如果AACPacketType为0的话,这里的数据就表示AudioSpecificConfig。对于AudioSpecificConfig的具体内容,我们在后面会进行介绍。

视频tag

  视频tag的数据格式如下:

  • FrameType:帧类型,对于H.264视频数据来说,值为1时则为IDR帧,值为2时则为其它帧
  • CodecID:编解码器类型,值为7则为H.264/AVC编解码器
  • VideoData:视频数据
AVC视频数据

  同音频一样,视频数据如果是AVC类型的话,也是不可以直接在里面填写视频数据的,还得区分格式。格式如下:

  • AVCPacketType:AVC数据包类型,0表示AVC序列头。1表示NALU,即H.264中的网络抽象层单元。2代表AVC序列的结尾。
  • CompositionTime:这一数据主要是用来计算pts的,显示时间戳,它是解码时间戳与显示时间戳的偏移值。在没有B帧的情况下,显示时间戳与解码时间戳是相等的。这里我们不会使用B帧,因为对于双向参考的B帧来说,解码它需要消耗更高得性能,CPU得消耗也会更高。因此这一部分我们不用管,到时直接给它清零即可。
  • Data:如果AVCPacketType为0的话,这里就是AVCDecoderConfigurationRecord得数据;如果AVCPacketType为1的话,这里就是NALU数据。如果AVCPacketType为2的话,这里就是空的。

数据tag

  数据tag类似于远程调用,我们传输过去的就是调用的方法和参数。其中最重要的就是onMetaData方法,这个在后面会讲到。 首先来看看他的格式:

  • objects:一些列的objects,类型为scriptdataobject类型
  • end:结束标识符,占二十四位,值恒为9

可以看到,数据tag无非就是一些列的objects加上一个结束标识符。接下来我们再来看看scriptdataobject类型,定义如下:

  • objectname:对象的名称,类型分别为scriptdatastring
  • objectdata:对象所包含的数据,类型分别为scriptdatavalue

到这里,由于篇幅原因,我就不继续往下了,因为往下还分有不同类型,比较繁琐,后面的内容请大家自行阅读文档即可。

OnMetaData:

  OnMetaData用于初始化flash播放器,配置相关的音视频信息。它的存在非常重要,但在librtmp中,它并没有帮我们发送这个方法。这个时候,需要我们自己构建去发送。如果缺少了这个方法,那大概率你的flash播放器都无法进行播放。(当然,我在测试中发现,缺少OnMetaData的情况下,vlc,火狐浏览器这些可以直接进行播放,它们应该是以rtmp流的方式去播放的)OnMetaData有关的参数设置如下:

  • duration:播放时长,由于我们是直播,这里直接设置成0
  • width:视频的宽度
  • height:视频的高度
  • videodatarate:视频比特率,单位为kbps
  • framerate:帧率
  • videocodecid:视频编解码器id,这里和我们上面所讲的视频tag中的编解码器id是一样的,照着填举行
  • audiosamplerate:音频采样率
  • audiosamplesize:一个音频样本的大小,有八位和十六位,不支持三十二位浮点型音频
  • stereo:是否立体声,true则为开启立体声
  • audiocodecid:音频编解码器id,与视频的情况一样,照着填写即可
  • filesize:flv文件大小,由于我们是直播,直接填0给它

除此之外,还需要注意一点,在发布流的时候,需要在OnMetaData前还需要发送@setDataFrame,它是Flash Media Server中的一个方法,用于添加一个具有metadata的关键帧,@setDataFrame中会触发OnMetaData事件,最终会对metadata进行设置。当然,与之对应的还有clearDataFrame,用于移除一个具有metadata的关键帧。

  内容就这么多,感谢观看。