若该文为原创文章,转载请注明原文出处
使用MP4V2把H264和AAC文件封装成MP4文件。
1、硬件:T31X+SC5235
2、开发环境: ubuntu16.04-64bit
3、编译器:mips-gcc540-glibc222-32bit-r3.3.0.tar.gz
注:板子和和WIFI模块是某淘上淘的,使用的是RTL8188,使用的是USB接口,uboot和内核是自己裁剪移植的,内核默认自带WIFI驱动,所以不用移植可以直接使用。
mp4v2官网连接: https://launchpad.net/ubuntu/artful/+source/mp4v2
- 1、解压:
- tar xvf mp4v2_2.0.0_dfsg0.orig.tar.bz2
- 2、进入文件:
- cd mp4v2-2.0.0
- 3、创建install文件
- mkdir install
- 3、配置
- ./configure --host=mips-linux CC=ips-linux-gnu-gcc CXX=mips-linux-gnu-g++ --prefix=/home/yifeng/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 --enable-shared --enable-static
- 4、编译
- make
- 5、安装
- make install
-
编译完成后,会在install生成lib文件,扡生成的动态库拷贝到开发板的/usr/lib下。
至此:编译完成。
说明:把h264和aac文件封装成MP4文件,不是实时采集h264和aac。
完整代码:
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <mp4v2/mp4v2.h>
-
- struct AdtsHeader
- {
- unsigned int syncword; //12 bit 同步字 '1111 1111 1111',说明一个ADTS帧的开始
- unsigned int id; //1 bit MPEG 标示符, 0 for MPEG-4,1 for MPEG-2
- unsigned int layer; //2 bit 总是'00'
- unsigned int protectionAbsent; //1 bit 1表示没有crc,0表示有crc
- unsigned int profile; //1 bit 表示使用哪个级别的AAC
- unsigned int samplingFreqIndex; //4 bit 表示使用的采样频率
- unsigned int privateBit; //1 bit
- unsigned int channelCfg; //3 bit 表示声道数
- unsigned int originalCopy; //1 bit
- unsigned int home; //1 bit
-
- /*下面的为改变的参数即每一帧都不同*/
- unsigned int copyrightIdentificationBit; //1 bit
- unsigned int copyrightIdentificationStart; //1 bit
- unsigned int aacFrameLength; //13 bit 一个ADTS帧的长度包括ADTS头和AAC原始流
- unsigned int adtsBufferFullness; //11 bit 0x7FF 说明是码率可变的码流
-
- /* number_of_raw_data_blocks_in_frame
- * 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧
- * 所以说number_of_raw_data_blocks_in_frame == 0
- * 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
- */
- unsigned int numberOfRawDataBlockInFrame; //2 bit
- };
-
- static int parseAdtsHeader(uint8_t* in, struct AdtsHeader* res)
- {
- static int frame_number = 0;
- memset(res,0,sizeof(*res));
-
- if ((in[0] == 0xFF)&&((in[1] & 0xF0) == 0xF0))
- {
- res->id = ((unsigned int) in[1] & 0x08) >> 3;
- res->layer = ((unsigned int) in[1] & 0x06) >> 1;
- res->protectionAbsent = (unsigned int) in[1] & 0x01;
- res->profile = ((unsigned int) in[2] & 0xc0) >> 6;
- res->samplingFreqIndex = ((unsigned int) in[2] & 0x3c) >> 2;
- res->privateBit = ((unsigned int) in[2] & 0x02) >> 1;
- res->channelCfg = ((((unsigned int) in[2] & 0x01) << 2) | (((unsigned int) in[3] & 0xc0) >> 6));
- res->originalCopy = ((unsigned int) in[3] & 0x20) >> 5;
- res->home = ((unsigned int) in[3] & 0x10) >> 4;
- res->copyrightIdentificationBit = ((unsigned int) in[3] & 0x08) >> 3;
- res->copyrightIdentificationStart = (unsigned int) in[3] & 0x04 >> 2;
- res->aacFrameLength = (((((unsigned int) in[3]) & 0x03) << 11) |
- (((unsigned int)in[4] & 0xFF) << 3) |
- ((unsigned int)in[5] & 0xE0) >> 5) ;
- res->adtsBufferFullness = (((unsigned int) in[5] & 0x1f) << 6 |
- ((unsigned int) in[6] & 0xfc) >> 2);
- res->numberOfRawDataBlockInFrame = ((unsigned int) in[6] & 0x03);
-
- return 0;
- }
- else
- {
- printf("failed to parse adts header\n");
- return -1;
- }
- }
-
-
- int getNalu(FILE *pFile, unsigned char *pNalu)
- {
- unsigned char c;
- int pos = 0;
- int len;
-
- if(!pFile)
- return -1;
-
- if((len = fread(pNalu, 1, 4, pFile)) <= 0)
- return -1;
-
- if(pNalu[0] != 0 || pNalu[1] != 0 || pNalu[2] != 0 || pNalu[3] != 1)
- return -1;
-
- pos = 4;
-
- while(1)
- {
- if(feof(pFile))
- break;
-
- pNalu[pos] = fgetc(pFile);
-
- if(pNalu[pos-3] == 0 && pNalu[pos-2] == 0 && pNalu[pos-1] == 0 && pNalu[pos] == 1)
- {
- fseek(pFile, -4, SEEK_CUR);
- pos -= 4;
- break;
- }
-
- pos++;
- }
-
- len = pos+1;
-
- return len;
- }
-
-
-
- static int dump_frame(uint8_t* p_frame, uint32_t size)
- {
- printf("*********************************************************:%u\n", size);
- if(p_frame != NULL && size >0)
- {
- uint32_t i=0;
- for(; i<100; i++)
- {
- printf("%x ", p_frame[i]);
-
- if((i+1)%16 == 0)
- {
- printf("\n");
- }
- }
- }
- printf("\n");
- }
-
-
- int packet2Mp4(const char *inputh264File, const char *inputaacFile, const char *outputFiles)
- {
- FILE *pInh264 = NULL;
- FILE *pInAac = NULL;
- unsigned char *pBuf = malloc(1024*1024);
- unsigned char *frame = malloc(5000);
- unsigned char *pNalu = NULL;
- unsigned char naluType;
- int len;
- int num = 0;
- MP4FileHandle pHandle = NULL;
- MP4TrackId videoId;
- MP4TrackId audioId;
- int width = 480;
- int height = 288;
- int frameRate = 25;
- int timeScale = 90000;
- int addStream = 1;
- int ret = 0;
- struct AdtsHeader adtsHeader;
- int videoCnt = 0;
- int audioCnt = 0;
-
- pInh264 = fopen(inputh264File, "rb");
- if(!pInh264)
- return -1;
-
-
- pInAac = fopen(inputaacFile, "rb");
- if(!pInAac)
- return -1;
-
- pHandle = MP4Create(outputFiles, 0);
- if(pHandle == MP4_INVALID_FILE_HANDLE)
- {
- printf("ERROR:Create mp4 handle fialed.\n");
- return -1;
- }
-
- MP4SetTimeScale(pHandle, timeScale);
-
-
- // MP4_MPEG4_AAC_MAIN_AUDIO_TYPE
- audioId = MP4AddAudioTrack(pHandle, 48000, 1024, MP4_MPEG4_AUDIO_TYPE);
- if (audioId == MP4_INVALID_TRACK_ID)
- {
- printf("add audio track fialed.\n");
- return -1;
- }
- MP4SetAudioProfileLevel(pHandle, 0x2);
-
-
- while(1)
- {
- videoCnt++;
- audioCnt++;
-
- if(videoCnt >= 40)
- {
- videoCnt = 0;
- /* 视频处理 */
- len = getNalu(pInh264, pBuf);
- if (len <= 0)
- break;
-
- if (pBuf[0] != 0 || pBuf[1] != 0 || pBuf[2] != 0 || pBuf[3] != 1)
- continue;
-
-
- len -= 4;
- pNalu = pBuf+4;
- naluType = pNalu[0]&0x1F;
-
- switch (naluType)
- {
- case 0x07: // SPS
- printf("------------------------------------\n");
- printf("sps(%d)\n", len);
- if (addStream)
- {
- videoId = MP4AddH264VideoTrack
- (pHandle,
- timeScale, // 涓€绉掗挓澶氬皯timescale
- timeScale/frameRate, // 姣忎釜甯ф湁澶氬皯涓猼imescale
- width, // width
- height, // height
- pNalu[1], // sps[1] AVCProfileIndication
- pNalu[2], // sps[2] profile_compat
- pNalu[3], // sps[3] AVCLevelIndication
- 3); // 4 bytes length before each NAL unit
- if (videoId == MP4_INVALID_TRACK_ID)
- {
- printf("Error:Can't add track.\n");
- return -1;
- }
- printf("pNalu[1] = %x, pNalu[2] = %x, pNalu[3] = %x\n", pNalu[1], pNalu[2], pNalu[3]);
-
- MP4SetVideoProfileLevel(pHandle, 0x7F);
-
- addStream = 0;
- }
- dump_frame(pNalu, len);
- MP4AddH264SequenceParameterSet(pHandle, videoId, pNalu, len);
-
- break;
-
- case 0x08: // PPS
- printf("pps(%d)\n", len);
- dump_frame(pNalu, len);
- MP4AddH264PictureParameterSet(pHandle, videoId, pNalu, len);
- break;
-
- default:
- printf("slice(%d)\n", len);
- pBuf[0] = (len>>24)&0xFF;
- pBuf[1] = (len>>16)&0xFF;
- pBuf[2] = (len>>8)&0xFF;
- pBuf[3] = (len>>0)&0xFF;
- dump_frame(pBuf, len);
- MP4WriteSample(pHandle, videoId, pBuf, len+4, MP4_INVALID_DURATION, 0, 1);
-
- break;
- }
- }
-
- if(audioCnt >= 21)
- {
- audioCnt = 0;
- /* 音频处理 */
- ret = fread(frame, 1, 7, pInAac);
- if(ret <= 0)
- {
- break;
- }
- if(parseAdtsHeader(frame, &adtsHeader) < 0)
- {
- printf("parse err\n");
- break;
- }
- ret = fread(frame, 1, adtsHeader.aacFrameLength-7, pInAac);
- if(ret < 0)
- {
- printf("read err\n");
- break;
- }
- printf("audio frame:\n");
- dump_frame(frame, len);
- MP4WriteSample(pHandle, audioId, frame, adtsHeader.aacFrameLength-7 , MP4_INVALID_DURATION, 0, 1);
- }
- }
-
- free(pBuf);
- free(frame);
- fclose(pInh264);
- fclose(pInAac);
- MP4Close(pHandle, 0);
-
- return 0;
- }
-
- int main(int argc, char *argv[])
- {
- if (packet2Mp4("output.h264", "output.aac", "test.mp4"))
- {
- printf("Error:Packet to Mp4 fail.\n");
- return -1;
- }
-
- return 0;
- }
-
编译:
mips-linux-gnu-gcc h264_aac_to_mp4.c -o h264_aac_to_mp4 -lpmv4p2
把可执行文件和h264,aac文件拷贝到开发板下运行,生成的mp4可以在vlc上播放。
1、mpv2库交叉编译。
2、使用mpv2静态库,执行文件太大,建议使用动态库。
3、MP4格式学习。
如有侵权,请及时联系博主删除,VX:18750903063