博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
成功在MP4封装的H264视频中提取能播放的裸流
阅读量:5136 次
发布时间:2019-06-13

本文共 2558 字,大约阅读时间需要 8 分钟。

首先说明一下,本人只是从MP4(AVC)封装的h264视频流中成功把裸流提取出来并进行播放,而这一段MP4封装的流中是不含音频流的,因为项目并不需要实现这个,所以我也就偷懒了,需要从含有音频流的MP4当中提取h264的裸流,还请详细阅读ISO/IEC 14496系列文档,特别是12和15部分。

原理说明如下,.h264文件只需要写入sps,pps以及后面的视频裸流(nalu)就可以播放了,播放器可以选择VLC或者迅雷看看播放器,其它的没有测试过。
MP4文件是由一个一个box组成的文件,每个box的开头是box的length(4 byte),紧接着是4 byte的box type,如果length是0x01的话,那么在box type后面接着的就是8 byte的box length,再剩下的就都是box所包含的内容了,注意,box length包含box length本身的字节数。当然,如果length是0x00的话,我就不是非常了解了,因为没有测试过,具体还是看一下的标准吧。
以下是
ISO/IEC 14496-12 4.2
对于box的定义。
   aligned(8) class Box (unsigned int(32) boxtype, optional unsigned int(8)[16] extended_type) {  unsigned int(32) size;
 unsigned int(32) type = boxtype; 
 if (size==1) { unsigned int(64) largesize; 
 } else if (size==0) { 
 // box extends to end of file 
 } 
 if (boxtype==‘uuid’) {
 unsigned int(8)[16] usertype = extended_type;
 } 
   }
 
 
上面的图片当中,第一个box的长度是0x18,类型是ftyp,第二个box的长度是 0xa3c0,类型是mdat。注意,这里的话,我是认为滴吧mdat的box放置于moov的box前面,只是为了能更好地说明签名length的表示方式。在没有封装音频的MP4文件当中,mdat的box中内容就是slice了,每一个slice包含了nalu的长度(默认4 byte)以及nalu的数据。
第一步,我们先来提取视频的sps,以及pps,一开始,看别人关于一些转码的视频总是不明白,为什么每次总是要先录制一段大概0.1秒的视频,然后才开始正式录制视频。原来相同的手机在相同的录制设定下sps以及pps是相同的,而moov的box有时候是放在mdat的box之后的,我们需要提取的视频的裸流是从mdat中提取的,这就不难解释了。废话少说,以下是
ISO/IEC 14496-15 5.2.4.1.1关于avcC的数据的定义,这些数据是封装在avcC当中的。

 

aligned(8) class AVCDecoderConfigurationRecord { 
  unsigned int(8) configurationVersion = 1; 
  unsigned int(8) AVCProfileIndication; 
  unsigned int(8) profile_compatibility; 
  unsigned int(8) AVCLevelIndication;  
  bit(6) reserved = ‘111111’b;
  unsigned int(2) lengthSizeMinusOne;  
  bit(3) reserved = ‘111’b;
  unsigned int(5) numOfSequenceParameterSets; 
  for (i=0; i< numOfSequenceParameterSets;  i++) { 
    unsigned int(16) sequenceParameterSetLength ; 
  bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit; 
 } 
  unsigned int(8) numOfPictureParameterSets; 
  for (i=0; i< numOfPictureParameterSets;  i++) { 
  unsigned int(16) pictureParameterSetLength; 
  bit(8*pictureParameterSetLength) pictureParameterSetNALUnit; 
 } 
}
对照上面的定义,我们可以知道avcC的box长度是0x21。lengthSizeminusone是0xff & 0x03=3。这个参数加上1也就是4描述的是在slice里面对于nalu长度描述中的byte的个数(默认是4)。接下来的 0xE1 & 0x1f = 1描述的则是sps的个数,再接下来的两个byte 00 0A 描述的则是第一个sps的长度。所以,这里的sps就是 67 42 80 1E 95 A0 28 0F 5F 40。然后依次就是pps的个数 1 ,第一个pps的长度 00 04, pps就是 68 CE 3C 80。
至此,sps以及pps已经提取完毕。最后提取的就是h264的裸流了,这个裸流就是隐藏在slice当中的nalu了。slice就是mdat当中存放的内容。每个slice是这样定义的,首先是该slice的长度(注:长度的byte数有lengthSizeminusone那个参数决定,另外这里的长度并不包含slice本身所占的byte数目)。
当提取完毕以后,在sps,pps以及每个nalu前写入h264中的start code( 00 00 00 01),即可播放。以下是我所提取的视频,sps以及pps与上述的相同。
以上仅仅是本人在MP4学习中对MP4格式的一些理解,如果有什么错误,还望指出。
 

     

转载于:https://www.cnblogs.com/zhumai/archive/2012/08/21/2778375.html

你可能感兴趣的文章
第23月第24天 git命令 .git-credentials git rm --cached git stash clear
查看>>
java SE :标准输入/输出
查看>>
[ JAVA编程 ] double类型计算精度丢失问题及解决方法
查看>>
好玩的-记最近玩的几个经典ipad ios游戏
查看>>
Sql Server 中由数字转换为指定长度的字符串
查看>>
tmux的简单快捷键
查看>>
[Swift]LeetCode922.按奇偶排序数组 II | Sort Array By Parity II
查看>>
php match_model的简单使用
查看>>
Vue_(组件通讯)子组件向父组件传值
查看>>
STM32单片机使用注意事项
查看>>
移动开发平台-应用之星app制作教程
查看>>
springboot No Identifier specified for entity的解决办法
查看>>
浅谈 unix, linux, ios, android 区别和联系
查看>>
51nod 1428 活动安排问题 (贪心+优先队列)
查看>>
latex for wordpress(一)
查看>>
如何在maven工程中加载oracle驱动
查看>>
aboutMe
查看>>
【Debug】IAR在线调试时报错,Warning: Stack pointer is setup to incorrect alignmentStack,芯片使用STM32F103ZET6...
查看>>
一句话说清分布式锁,进程锁,线程锁
查看>>
FastDFS使用
查看>>