• (转载)将h.264视频流封装成flv格式文件(二.开始动手)http://blog.csdn.net/yeyumin89/article/details/7932431


    前面写了flv文件的解析,有h264裸流的话就开始封装吧。网上大多数都是用ffmeg库来做这个工作的,哎,学习资料少学不会,还是自己动手吧。

    封装前要先了解下h.264格式,只需要知道一点点就可以了,我看了h.264官方文档,我靠,3百多页,还全是中文,什么,是中文?既然是中文的我就勉强看下吧,我靠,看起来还很复杂的,果断不看了,不需要,也没时间,我又不做解码,这东西具体步骤资料又少,基本都是那一两篇转来转去,这还要感谢我上一篇提到的那个连接的兄弟,记录下过程,不然以后就忘干净了。
     
    h264是一个个NALU单元组成的,每个单元以00 00 01 或者 00 00 00 01分隔开来,每2个00 00 00 01之间就是一个NALU单元。我们实际上就是将一个个NALU单元封装进FLV文件
     
    每个NALU单元开头第一个byte的低5bits表示着该单元的类型,即NAL nal_unit_type:
    #define NALU_TYPE_SLICE 1
    #define NALU_TYPE_DPA 2
    #define NALU_TYPE_DPB 3
    #define NALU_TYPE_DPC 4
    #define NALU_TYPE_IDR 5
    #define NALU_TYPE_SEI 6          
    #define NALU_TYPE_SPS 7
    #define NALU_TYPE_PPS 8
    #define NALU_TYPE_AUD 9
    #define NALU_TYPE_EOSEQ 10
    #define NALU_TYPE_EOSTREAM 11
    #define NALU_TYPE_FILL 12
     
    每个NALU第一个byte & 0x1f 就可以得出它的类型,比如上图第一个NALU:67 & 0x1f = 7,则此单元是SPS,第三个:68 & 0x1f = 8,则此单元是PPS。
     
    前一章说到如果数据是AAC或者AVC的话,则有一个音频和视频的配置信息需要写入前两个tag(metadata之后),AAC音频就不说了,在ISO-14496-3 Audio 中有描述,给一张图。
     
    说下AVC视频流的configuretion,ISO-14496-15 AVC file format 有详细描述,先给两张图,一张是说明,一张是实际截图。
     
    这个例子是对应我第一个截图来的,一般h264数据最开始的两个NALU就是PSP和PPS,但是我现在还没有明白为什么我的那个h264裸流在开始的时候会有两个SPS、PPS,而且之后数据还会不时的出现,但是我没有管这个,依然只各弄了一个进去,其他的忽略掉了,反正多余的我都忽略了,也没发现有什么错。反正首先把音视频的配置信息封进metadata之后的tag,然后就可以封数据了。再说下元数据,flv header之后就是它了,再之后就是音视频配置信息,再后面就是音视频数据,元数据前一章说了是amf格式的,安格式封就行了,测试其实没有元数据视频也可以正常播放,等会再简单说下amf吧。
     
     
     
    现在开始封装h264数据吧,前一章提到了flv关于AVC的格式,除开元数据,其他数据是:一个byte的video信息+一个byte的AVCPacket type+3个bytes的无用数据(composition time,当AVC时无用,全是0)+ 4个bytes的NALU单元长度 + N个bytes的NALU数据,所以包头数据长度信息是刚才提到的信息的总和长度。要强调下,当音视频配置信息tag的时候,是没有4个bytes的NALU单元长度的
    AVC的配置信息时,先上一个图,
    17 -- 高4bits:1,keyframe。 低4bits:7,代表AVC。 后面一个byte 0x00,AVCPacket type,代表AVC sequence header。后3个bytes无意义,之后就是decoder configuration record的内容了。 图中绿色后面 00 00 00 28就是前面tag的总长度
     
     
    当NALU第一个byte xx & 0x1f == 5的时候,说明该单元是一个I frame,关键帧
    17 -- 和上面的一样。 01 -- AVC NALU。蓝色框内的4个bytes记录后面NALU数据的长度。65 & 0x1f == 5.
     
     
    如果NALU第一个byte xx & 0x1f != 5的时候,就不是一个I frame
    27 -- 高4bits:2,inter frame ,P frame。 低4bits:7,AVC NALU。其他都一样。图中绿色后面 00 00 00 28就是前面tag的总长度。
     
     
    整个的flv文件其实是:FLV header + previous tag size0 + tag1 + previous tag size1 + tag2 + previous tag size2 + ... +tagN + previous tag sizeN。
    tag1是metadata,记录视频的一些信息;tag2是视频配置信息(AVC decoder configuration record),tag3是音频配置信息(如果没有音频则去掉此项),tag4以及之后的tag就是音视频数据了。
    每一个结构怎么封都说清楚了,安上面的步骤一个一个NALU封就行了。
     
     
     
     
     
    封包的时候要特别注意一下包头里面的时间戳,因为这个控制着播放的速度,如果不填,全是0的话,播放会相当快,一般按视频帧率来设置。我这个h264流是8帧的,所以我每个tag的时间间隔是125ms左右。
    注意了,flv里面的数据都是大端模式,放数据进去要转换一下,如果你是通常的小端的机器的话。
     
     
     
     
    到这里应该差不多了吧,我是一个NALU单元封装成一个tag,我也是刚接触,不知道上述还有哪些地方不合理,不过测试没有发现问题。我也才接触这东西,如果有知情人,望解释一下为什么有多个PPS SPS,谢谢可怜
     
    至于rtmp协议发送flv,之后再写吧。
  • 相关阅读:
    pycharm搭建Django项目
    记一次坑爹的Rocketmq排错
    vue关于编辑框的表单变化判断
    PostgreSQL创建空间数据库
    PostgreSQL查询集合结果用逗号分隔返回字符串
    sqoop 抽取 postgres 数据库的数据
    Hive插入parquet格式进行压缩
    python通过kylin的api调度cube
    python的while例子
    numpy和pandas 小计
  • 原文地址:https://www.cnblogs.com/GoAhead/p/2828066.html
Copyright © 2020-2023  润新知