人肉解析系列(一)————FLV-java你所关心的,我这里都有。附源码。非FFmpeg相关,纯java人肉解析。手写FLV。H264 AAC转FLV

3 篇文章 0 订阅
1 篇文章 0 订阅

    第一次写博客,不知道有没有什么潜规则。总之呢,是好是坏都已经在落笔的那一刻开始了。

    说起直播,各位都不陌生,毕竟国内这几年直播,短视频等视频行业大火,让所有程序员对直播都能如数家珍,随口便能讲出几种协议:RTMP,RTSP,RTP,HLS,flv等等等。rtsp到目前还依旧火爆比如ipCamera各种监控摄像头比如海康之类的都是rtsp。

    说起RTMP和RTSP,不得不有个头疼的问题:想要在网页端播放需要借助flash。众所周知,谷歌和微软都共同宣布了将在近期内停止flash的使用。尤其是谷歌浏览器想要弹出flash需要反复点击甚是恶心。而bilibili开源的flv.js也有几年了。所以也是该换换协议让网页端不在使用flash了。

   本篇文章适用于H264+AAC to flv相关的java工作者免除FFmpeg的痛苦。另外也适合行车记录仪相关工作者的使用,毕竟mp4录制的视频会在突然断电的一刻导致视频文件无法播放,而flv不会。

    本文所讲的FLV是缩减版FLV不是完全版的。是可以用来录像+直播使用。而不是完全讲解FLV。

    进入正题:H264+AAC to FLV 或 H264 to FLV 或 AAC to FLV!!!

 

 

   FLV是一个轻巧型视频格式,因为FLV的数据格式里没有过多地添加多余符号,几乎是接近于数据流裸流的格式,而且因为flv的数据格式在头上,所以中间即使突然断了丢失数据了也能播放,这是flv的优点。我们来看看FLV的大概格式样子:

                                                         FLV-Header(9字节)固定头 +FLV-Body

 

FLV-Header

  要注意1个bit,其他都可以是固定写法。这9字节里面的第5个字节的从右往左数第3bit和第1bit需要注意

  如果:0000 0101 则是有音频也有视频

             0000 0100 则是纯音频

             0000 0001 则是纯视频

  所以,头字节可以表示为

      0x46  0x4C  0x56 0x01 0x05 0x00 0x00 0x00 0x09 这是有视频也有音频的

      0x46  0x4C  0x56 0x01 0x04 0x00 0x00 0x00 0x09 这是只有音频的

      0x46  0x4C  0x56 0x01 0x01 0x00 0x00 0x00 0x09 这是只有视频的

FLV-Body

         flv-body里包含3种Tag,分别是:视频Tag、音频Tag、脚本Tag。都说脚本Tag信息重要,但是如果你是H264+AAC的话,是不需要脚本Tag。因为H264和aac 都有自己的格式头所以这里不需要脚本Tag(是文件、http流、socket流、webSocket流里都不需要脚本Tag)

           先说说FLV-Body大致格式:

                   Tag类型(1字节)+ 数据区长度(3字节) + 时间戳(3字节)+ 时间戳扩展(1字节)+ StreamsID(3字节)+ 数据区(数据区长度个字节) + 此Tag总长度(4字节)

                   其中Tag类型有:0x08:音频       0x09:视频       0x12脚本帧(这里不讲)

                          数据区长度:这个只是数据区长度 不包含后面的Tag总长度  和数据区之前的数据长度

                          时间戳和时间戳扩展:这个可以理解为 4字节byte[]中 byte[0] 为时间戳扩展  byte[1]+byte[2]+byte[3]为时间戳

                          StreamsID:3个字节万年为0x00 0x00 0x00

    

第一个videoTag:

                (此包需要包含H264的sps和pps,该包极其重要,如果没有则无法显示画面或花瓶)

                   0x09 + 数据区长度(3字节) + 0x00  0x00  0x00  0x00  0x00 0x00 0x00 + 数据区 +本videoTag总长度(4字节)

             数据区:

                      帧类别(1字节) + AVCPacketType(1字节)+  时间戳(3字节) + Version(固定为0x01) + ProfileCompact(3字节) + 固定2字节(0xFF  0xE1) + sps长度(2字节) + sps数据(长度取前面的sps长度) + 固定1字节(0x01) + pps长度(2字节) + pps数据

             其中:帧类别为0x17或者0x27   7代表x264编码 AVC(H264)  1和2代表关键帧和非关键帧 第一个videoTag一定是关键帧所以是0x17

                       AVCPacketType : 如果填写0x00 则代表是第一个videoTag 因为0x00是AVC sequence header 代表着该帧包含h264的sps和pps 后续videoTag帧全都填写0x01

                       ProfileCompact:其实就是sps字节数组里 从第一位到第四位:sps[1]+sps[2]+sps[3]

                       sps数据:sps数组从sps[0]-sps[sps.length]

              第一个videoTag例子(舍掉0x)

             09 00 00 21 00 00 00 00 00 00 00 17 00 00 00 00 01 42 80 16 FF E1 00 0D 67 42 80 16 E9 01 40 7B 40 36 85 09 A8 01 00 04 68 CE 06 E2 00 00 00 28

 

后续videoTag

           和第一帧videoTag大致是相同的这里需要注意的是时间戳不能往回减少,只能增加

            这里只说与第一帧不同之处

           帧类别:需要根据H264数据进行判断是否是关键帧,如果是关键帧还是输入0x17,如果是非关键帧填写0x27

          AVCPacketType:固定填写0x01

          H264数据中 00 00 00 01 替换成此帧长度(本帧长度里不计算这个00 00 00 01)

举个例子:

         09 00 00 21 00 00 00 00 17 01 00 00 00 +h264长度(四字节)+h264数据(去掉00 00 00 01)+本Tag总长度

audioTag

        (这里是AAC的头部,一般这个帧会非常短)

          0x08 + 数据区长度(3字节) + 0x00  0x00  0x00  0x00  0x00 0x00 0x00 + 数据区 +本audioTag总长度(4字节)

          数据区:固定1字节(AF) + 本音频帧类型(1字节) + AAC数据

                       本音频帧类型:如果是第一个音频帧需要写入AAC头数据 这里填写0x00 。如果不是第一帧这里填写0x01

                       AAC数据:我这边android编译出来的第一个头数据只有2个字节:0x12 0x10

          第一个audioTag例子(舍掉0x)

                 08 00 00 04 00 00 00 00 00 00 00 AF 00 12 10 00 00 00 0F

 

         后续audioTag帧和第一个只有音频帧类型不同 改为0x01即可

 

 

 

   说到这里,完整的FLV解析就分析完毕了。按照分析的样子转换成代码即可。该偏文章适合于android端不使用FFmpeg将MediaCode编码出来的H264+AAC转成flv格式视频。同时也适用于java后端人员使用该方法 将其他设备将RTP RTSP RTMP之类的流按照对应协议取出H264和aac 然后转化成flv利用webSocket推给前端flv.js播放实现去掉flash控件的目的。

 

 

说到这里,在介绍几个小技巧

   1、flv视频剪切,可以按照时间戳找到最近关键帧进行重新拼写(记得要加flv头)

   2、实现快放和慢放:其实是可以在写时间戳的时候 不按照正常时间戳填写 而是等比例缩短或者延长时间戳即可实现

 

 

源码里实现了  H264+AAC to FLV 或 H264 to FLV 或 AAC to FLV   和flv的剪切(其中剪切没有经过测试,不过应该是好用的。其他均已经在项目中使用了,很稳定)

如果本文内容有错误请在下方评论里指出,本人只是个普通程序员知识不多难免出错,如果有误导您的地方,还望海涵。

如果本文对你有帮助,请给博主一个大大的赞!! 另外博主比较懒,所以更新不会太频繁。如果有时间后续会依次推出用纯java代码截取rtp 和rtsp rtmp的h264和aac等相关信息

 

 

源码在这里:https://github.com/yuxitong/AndroidLivePusher

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值