MP4转H264文件
本文最目标是基本的MP4v2接口的使用,并且实现一个简单的提取mp4文件里面264流的功能;
1.264文件基本知识
下看看H264文件的基本常识
NAL 头 0x00 0x00 0x00 0x01
sps :nal+0x67开头
pps :nal+0x68开头
I帧 0x65 开头
P帧…
具体的参考别人的解析
http://blog.csdn.net/jefry_xdz/article/details/8461343
2.mp4v2提取264文件的代码
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <sys/types.h> 5 #include <dirent.h> 6 #include <time.h> 7 #include <sys/time.h> 8 #include <mp4v2/mp4v2.h> 9 10 unsigned char sps[64],pps[64]; 11 int spslen = 0,ppslen = 0; 12 13 int get264stream(MP4FileHandle oMp4File,int VTrackId,int totalFrame) 14 { 15 if(!oMp4File) return -1; 16 char NAL[5] = {0x00,0x00,0x00,0x01}; 17 unsigned char *pData = NULL; 18 unsigned int nSize = 0; 19 MP4Timestamp pStartTime; 20 MP4Duration pDuration; 21 MP4Duration pRenderingOffset; 22 bool pIsSyncSample = 0; 23 24 int nReadIndex = 0; 25 FILE *pFile = NULL; 26 pFile = fopen("out.h264","wb"); 27 28 while(nReadIndex < totalFrame) 29 { 30 nReadIndex ++; 31 //printf("nReadIndex:%d\n",nReadIndex); 32 MP4ReadSample(oMp4File,VTrackId,nReadIndex,&pData,&nSize,&pStartTime,&pDuration,&pRenderingOffset,&pIsSyncSample); 33 34 //IDR֡ 帧,写入sps pps先 35 if(pIsSyncSample) 36 { 37 fwrite(NAL,4,1,pFile); 38 fwrite(sps,spslen,1,pFile); 39 40 fwrite(NAL,4,1,pFile); 41 fwrite(pps,ppslen,1,pFile); 42 43 } 44 //264frame 45 if(pData && nSize > 4) 46 { 47 //标准的264帧,前面几个字节就是frame的长度. 48 //需要替换为标准的264 nal 头. 49 pData[0] = 0x00; 50 pData[1] = 0x00; 51 pData[2] = 0x00; 52 pData[3] = 0x01; 53 fwrite(pData,nSize,1,pFile); 54 } 55 56 //如果传入MP4ReadSample的视频pData是null 57 // 它内部就会new 一个内存 58 //如果传入的是已知的内存区域, 59 //则需要保证空间bigger then max frames size. 60 free(pData); 61 pData = NULL; 62 } 63 fflush(pFile); 64 fclose(pFile); 65 66 return 0; 67 } 68 int openmp4file(char *sMp4file) 69 { 70 MP4FileHandle oMp4File; 71 int i; 72 73 //unsigned int oStreamDuration; 74 unsigned int oFrameCount; 75 76 oMp4File = MP4Read(sMp4file); 77 int videoindex = -1,audioindex = -1; 78 uint32_t numSamples; 79 //uint32_t timescale; 80 //uint64_t duration; 81 82 if (!oMp4File) 83 { 84 printf("Read error....%s\r\n",sMp4file); 85 return -1; 86 } 87 88 MP4TrackId trackId = MP4_INVALID_TRACK_ID; 89 uint32_t numTracks = MP4GetNumberOfTracks(oMp4File,NULL,0); 90 printf("numTracks:%d\n",numTracks); 91 92 for (i = 0; i < numTracks; i++) 93 { 94 trackId = MP4FindTrackId(oMp4File, i,NULL,0); 95 const char* trackType = MP4GetTrackType(oMp4File, trackId); 96 if (MP4_IS_VIDEO_TRACK_TYPE(trackType)) 97 { 98 //printf("[%s %d] trackId:%d\r\n",__FUNCTION__,__LINE__,trackId); 99 videoindex= trackId; 100 101 //duration = MP4GetTrackDuration(oMp4File, trackId ); 102 numSamples = MP4GetTrackNumberOfSamples(oMp4File, trackId); 103 //timescale = MP4GetTrackTimeScale(oMp4File, trackId); 104 //oStreamDuration = duration/(timescale/1000); 105 oFrameCount = numSamples; 106 107 // read sps/pps 108 uint8_t **seqheader; 109 uint8_t **pictheader; 110 uint32_t *pictheadersize; 111 uint32_t *seqheadersize; 112 uint32_t ix; 113 MP4GetTrackH264SeqPictHeaders(oMp4File, trackId, &seqheader, &seqheadersize, &pictheader, &pictheadersize); 114 115 for (ix = 0; seqheadersize[ix] != 0; ix++) 116 { 117 memcpy(sps, seqheader[ix], seqheadersize[ix]); 118 spslen = seqheadersize[ix]; 119 free(seqheader[ix]); 120 } 121 free(seqheader); 122 free(seqheadersize); 123 124 for (ix = 0; pictheadersize[ix] != 0; ix++) 125 { 126 memcpy(pps, pictheader[ix], pictheadersize[ix]); 127 ppslen = pictheadersize[ix]; 128 free(pictheader[ix]); 129 }
free(pictheader);
free(pictheadersize);
130 }
131 else if (MP4_IS_AUDIO_TRACK_TYPE(trackType)) 132 { 133 audioindex = trackId; 134 printf("audioindex:%d\n",audioindex); 135 } 136 } 137 138 //解析完了mp4,主要是为了获取sps pps 还有video的trackID 139 if(videoindex >= 0) 140 get264stream(oMp4File,videoindex,oFrameCount); 141 142 //需要mp4close 否则在嵌入式设备打开mp4上多了会内存泄露挂掉. 143 MP4Close(oMp4File,0); 144 return 0; 145 } 146 147 int main(void) 148 { 149 openmp4file("test.mp4"); 150 return 0; 151 }
3.测试文件ffproe的信息如下.
测试的mp4文件和生成的264文件信息如下,用播放器播放可以正常显示图像.