目录
1、视频文件
2、MP4
3、MP4学习方法
4、MP4文件格式解析
5、MP4Info工具使用
6、mp4v2移植和播放
6.1、下载mp4v2
6.2、配置并编译
6.3、部署
6.4、编译sample
6.5、准备TF卡
6.6、运行和测试
7、MP4打包源码解析
8.添加网络telnet调试
8.1、为什么添加telnet调试
8.2、telnet调试的原理-可以通过telnet协议远程登录一个运行了telnetd的程序
8.3、在HI3518E开发板上telnet远程登录调试
9、海思proc文件系统调试接口
9.1、proc文件系统的原理
9.2、参考 HiMPP IPC V2.0 媒体处理软件开发参考.pdf和HiISP FAQ V100版本.pdf
1、视频文件
(1)视频文件的本质:二进制文件,记录压缩后的视频帧(I帧、P帧等)并且能被播放器还原解码播放
H264码流:刷子
H264码流被播放器解码播放:刷子被人用来刷锅
mp4:将刷子拿给快递公司打包寄过去
(2)视频文件的关键:高效率记录信息(mp4)、兼容性(mp4有很多种格式)
(3)视频文件的信息:索引信息(记录有效信息是怎么被安排的)、有效信息(I帧、P帧这些)
2、MP4
(1)MP4由MP3升级而来,包含video(H.264)和audio(AAC)在内
(2)MP4是h.264的最主流打包格式
(3)MP4文件内部采用网络字节序(大端模式:高字节放在低地址)
3、MP4学习方法
(1)学习MP4的组织形式和box解析,box是mp4的最基本单元,box的种类有上百种(mp4有多种格式的原因)
(2)移植和使用mp4v2开源库来打包MP4
(3)研究MP4解包播放和mp4v2源码
(4)编程进行MP4的打包、解包、分割等。
4、MP4文件格式解析
mp4文件格式解析 - nigaopeng - 博客园 (cnblogs.com)
(1)MP4文件封装格式,对应的标准为ISO/IEC 14496-12,早期是基于QuickTime容器格式定义的
(2)MP4文件中的媒体描述与媒体数据是分开的,并且媒体数据的组织也很自由,不一定要按照时间先后顺序排列,甚至媒体数据可以直接引用外部其它视频文件,也就是内嵌其它视频
(3)MP4也支持流媒体,也就是在网上边下载边播放视频
(4)整个MP4文件由若干种不同类型的box组成,打包和解包时都是以box为单位的
(5)MP4中首先只有一个ftyp box,位于整个MP4的开头位置,ftyp box的作用是作为MP4格式的标志并包含关于一些文件信息
(6)ftyp box之后是Movie Box,MP4中也只有一个,它是container box,子box包含了媒体的metadata信息
(7)MP4文件的媒体数据被包含在mdat box(Midia Data Box)中,该box是container box,可以有多个子box,也可以没有(当媒体数据全部引用其他文件时),媒体数据的结构由metadata进行描述。
(8)box开头的4个字节(32位)为box size,该大小是整个box的大小,这样我们就可以在文件中定位各个box,如果size为1,则表示这个box的大小为large size,是一个很大的box,这里放不下他的box size值,真正的size值要在largesize域上得到。如果size为0,表示该box为文件的最后一个box,文件结尾即为该box结尾,所以mp4文件到这就结束了。
(9)size后面紧跟的32位为box type,一般是4个字符,如“ftyp”、“moov”等,这些box type都是已经预定义好的,分别表示固定的意义。如果是“uuid”,表示该box为用户扩展类型。如果box type是未定义的,应该将其忽略。
(10) free box是无关紧要的,可以被忽略。该box被删除后,不会对播放产生任何影响。
5、MP4Info工具使用
(1)每一个box包含header(头)和body(主体),在moov box中
mvhd是header,其余是主体
(2)Movie Box(moov):
该box包含了文件媒体的metadata信息,“moov”是一个container box,具体内容信息由子box诠释。同File Type Box一样,该box有且只有一个,且只被包含在文件层,不会被任何box包含。一般情况下,“moov”会紧随“ftyp”出现。
“moov”中会包含1个“mvhd”和若干个“trak”。其中“mvhd”为header box,一般作为“moov”的第一个子box出现(对于其他container box来说,header box都应作为首个子box出现)。“trak”包含了一个track的相关信息,是一个container box。
(3)Movie Header Box(mvhd):
字段 | 字节数 | 意义 |
box size | 4 | box大小, 这里是00 00 00 6C |
box type | 4 | box类型, 这里是6D 76 68 64 |
version | 1 | box版本,0或1,一般为0。(以下字节数均按version=0),这里是00 |
flags | 3 | 这里是00 00 00 |
creation time | 4 | 创建时间(相对于UTC时间1904-01-01零点的秒数), 这里是00 00 00 00,这是抖音下载的视频,不知道为啥是00 00 00 00,其它视频是正确的创建时间 |
modification time | 4 | 修改时间, 这里是00 00 00 00,同上 |
time scale | 4 | 文件媒体在1秒时间内的刻度值,可以理解为1秒长度的时间单元数, 这里是00 00 03 E8 |
duration | 4 | 该track的时间长度,用duration和time scale值可以计算track时长,比如audio track的time scale = 8000, duration = 560128,时长为70.016,video track的time scale = 600, duration = 42000,时长为70 |
rate | 4 | 推荐播放速率,高16位和低16位分别为小数点整数部分和小数部分,即[16.16] 格式,该值为1.0(0x00010000)表示正常前向播放 |
volume | 2 | 与rate类似,[8.8] 格式,1.0(0x0100)表示最大音量 |
reserved | 10 | 保留位 |
matrix | 36 | 视频变换矩阵 |
pre-defined | 24 | |
next track id | 4 | 下一个track使用的id号 |
(4)Track Box(trak):
“trak”也是一个container box,其子box包含了该track的媒体数据引用和描述(hint track除外)。一个MP4文件中的媒体可以至少包含有一个track,这些track之间彼此独立,有各自的时间和空间信息。“trak”必须包含一个“tkhd”和一个“mdia”,此外还有很多可选的box(略)。其中“tkhd”为track header box,“mdia”为media box,该box是一个包含一些track媒体数据信息box的container box。
(5)Track Header Box(tkhd)、Media Box(mdia)等详见博文
(6)Sample Table Box(stbl):该box是有效信息的索引
“stbl”几乎是普通的MP4文件中最复杂的一个box了,首先需要回忆一下sample的概念。sample是媒体数据存储的单位,存储在media的chunk中,chunk和sample的长度均可互不相同,如下图所示。
“stbl”包含了关于track中sample所有时间和位置的信息,以及sample的编解码等信息。利用这个表,可以解释sample的时序、类型、大小以及在各自存储容器中的位置。“stbl”是一个container box,其子box包括:sample description box(stsd)、time to sample box(stts)、sample size box(stsz或stz2)、sample to chunk box(stsc)、chunk offset box(stco或co64)、composition time to sample box(ctts)、sync sample box(stss)等。
“stsd”必不可少,且至少包含一个条目,该box包含了data reference box进行sample数据检索的信息。没有“stsd”就无法计算media sample的存储位置。“stsd”包含了编码的信息,其存储的信息随媒体类型不同而不同。
6、mp4v2移植和播放
6.1、下载mp4v2
(1)2.0.0~dfsg0-6 : mp4v2 package : Ubuntu
(2)解压,并在目录内创建_install目录作为安装目录
6.2、配置并编译
(1)sudo PATH=$PATH:/opt/hisi-linux/x86-arm/arm-hisiv300-linux/target/bin CC=arm-hisiv300-linux-gcc CXX=arm-hisiv300-linux-gcc ./configure --host=arm-hisiv300-linux --prefix=/home/aston/sambashare/mp4v2-2.0.0/_install --disable-option-checking --disable-debug --disable-optimize --disable-fvisibility --disable-gch --disable-largefile --disable-util --disable-dependency-tracking --disable-libtool-lock
(2)make
(3)make install
(4)检查各必要文件
6.3、部署
(1)生成的lib加到mpp lib里面
(2)include下文件夹添加到mpp/include中去
(3)lib/so加到开发板lib目录下
6.4、编译sample
(1)make
6.5、准备TF卡
(1)TF卡格式化为FAT32文件系统,若失败可试试低层格式化软件如SDFormat之类
(2)先检测下TF卡可用 ls /dev/mmcblk0p1
(3)开机后将TF卡进行挂载 mount -t vfat /dev/mmcblk0p1 /usr/mmc
6.6、运行和测试
(1)运行sample_venc,用rtsp测试确认有图像
(2)终止程序,取出TF卡用读卡器接电脑查看
7、MP4打包源码解析
HI_S32 SAMPLE_COMM_VENC_MP4(VENC_STREAM_S *stStream)
{
static int nRecordFlag = 0x00;
static int recording = 0x1;
static int spsflag = 0;
static int ppsflag = 0;
static MP4TrackId video = 0;
static MP4FileHandle hMP4File = NULL;//MP4文件的句柄
static char recordfish = 0x1;//这个变量表示我们录制有没有结束
//多次调用函数时,以上变量是累积的
int j = 0;
int len = 0;
char *pData = NULL;
char isSyncSample = 0;
if(recordfish == 0x00){//录制结束
return 0;
}
if(hMP4File == NULL){//创建MP4文件
hMP4File = MP4CreateEx("/usr/mmc/test.mp4",0, 1, 1, 0, 0, 0, 0); //文件存储路径
if (hMP4File == MP4_INVALID_FILE_HANDLE) {
printf("open file fialed.\n");
return -1;
}
MP4SetTimeScale(hMP4File, 90000);
}
if(recording && stStream->u32Seq > 30){ //丢弃前面不完整的一个序列,也可以不丢弃
//if(stStream->u32PackCount >= 3){ //从下一个序列的I帧开始编码,保证文件开始就能播放
nRecordFlag = 1;
//}
if(nRecordFlag){
for(j = 0;j < stStream->u32PackCount;j++){
len = stStream->pstPack[j].u32Len - stStream->pstPack[j].u32Offset;
pData = (stStream->pstPack[j].pu8Addr + stStream->pstPack[j].u32Offset);
if(stStream->pstPack[j].DataType.enH264EType == H264E_NALU_SPS){
if(spsflag == 0x00){
spsflag = 0x1;
//写sps
printf("Write sps =================\n");
//把一个视频的Track添加到文件中去
video = MP4AddH264VideoTrack(hMP4File, 90000, 90000 / 30, 1280, 720,
pData[4+1], //sps[1] AVCProfileIndication
pData[4+2], //sps[2] profile_compat
pData[4+3], //sps[3] AVCLevelIndication
3); // 4 bytes length before each NAL unit
MP4SetVideoProfileLevel(hMP4File, 0x7F);//视频质量的级别
MP4AddH264SequenceParameterSet(hMP4File, video, pData+4, len-4);
}
continue;
}
if(stStream->pstPack[j].DataType.enH264EType == H264E_NALU_PPS){
if(ppsflag == 0x00){
ppsflag = 0x1;
//写pps
printf("Write pps -------------------\n");
MP4AddH264PictureParameterSet(hMP4File, video, pData+4, len-4);
}
continue;
}
isSyncSample = (stStream->pstPack[j].DataType.enH264EType == H264E_NALU_ISLICE) ? (1) : (0);
pData[0] = (len - 4) >> 24;
pData[1] = (len - 4) >> 16;
pData[2] = (len - 4) >> 8;
pData[3] = len - 4;
printf("Write date type = %d isSyncSample = %d\n",stStream->pstPack[j].DataType.enH264EType,isSyncSample);
MP4WriteSample(hMP4File, video, pData, len , MP4_INVALID_DURATION, 0, isSyncSample);
}
}
}
if((recording && stStream->u32Seq > 900)){ //控制文件时长
recording = 0x00;
printf("Close mp4 file\n");
MP4Close(hMP4File, 0);
hMP4File = NULL;
video = 0;
recordfish = 0x00;
}
}
8.添加网络telnet调试
8.1、为什么添加telnet调试
(1)linux系统的用户界面就是commandline,本质上由busybox提供
(2)busybox的命令行只有1个,一旦前台被占用就无法做其他操作
(3)解决方案有2个:一个是建立多个commandline,一个是开放其他用户界面。
8.2、telnet调试的原理-可以通过telnet协议远程登录一个运行了telnetd的程序
(1)在开发板中提前运行telnetd(服务器)
(2)远程通过telnet的client连接server,构建一个用户界面
(3)这是非常传统典型的远程登录的方式···其实用过的
8.3、在HI3518E开发板上telnet远程登录调试
busybox本身已支持telnet远程登录
(1)命令行执行telnetd &后台运行,然后Windows打开CRT配置SSH至192.168.1.10开发板网口
(2)输入ssid:root,password:直接回车,进入
(3)问题:若遇到不断挂载和insmod驱动模块,可以将etc/profile 中的加载项移至/etc/init.d中的rcS文件中。这是因为因为开启telnet服务会多次加载profile
(4)可以将telnetd &加入rcS中开机默认加载
9、海思proc文件系统调试接口
9.1、proc文件系统的原理
proc文件系统是linux内核提供的一种调试机制,这种方式已经sys文件系统被替代,但原理是一样的
它是把内核一些关键变量以文件的方式呈现在用户层,我们因此可以知道内核的一些情况