Mp4V2库编译及使用
2015-04-09 12:07
274 查看
需求:想用Mp4V2 库将H264流录成MP4文件
反复折腾了好一下子,才整出来,再次纪录下。
具体实现:
1、下载Mp4v2源码
google code下载地址:http://code.google.com/p/mp4v2/downloads/list,若打不开链接,可以去github里搜索,本人也将其打包全部上传到github。
2、编译IOS上平台上合并库。
编译脚本如下(忘记出处了,不好意思):
3、使用:在写入文件时,需要先写入SPS帧和PPS帧,然后再写入I,B,P帧,不然录像文件播放不了。
附:有网友提出编译不过,报错。
原因:需要添加系统库libc++.dylib,添加即可。
参考网址:
http://blog.csdn.net/skdkjzz/article/details/40506473
https://github.com/Thinkerfans/lib-mp4v2
反复折腾了好一下子,才整出来,再次纪录下。
具体实现:
1、下载Mp4v2源码
google code下载地址:http://code.google.com/p/mp4v2/downloads/list,若打不开链接,可以去github里搜索,本人也将其打包全部上传到github。
2、编译IOS上平台上合并库。
编译脚本如下(忘记出处了,不好意思):
#!/bin/sh IOS_BASE_SDK=8.2 SOURCE="mp4v2-2.0.0" ROOT=`pwd` FAT="$ROOT/fat" THIN="$ROOT/thin" ARCHS="i386 x86_64 armv7 armv7s arm64 " #ARCHS="i386 x86_64" CONFIGURE_FLAGS="--disable-gch --disable-debug --disable-util \ --enable-shared=no" clean() { rm -rf $THIN rm -rf $FAT } clean for ARCH in $ARCHS do echo "building $ARCH .." if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ] then PLATFORM="iPhoneSimulator" CPU= if [ "$ARCH" = "x86_64" ] then SIMULATOR="-mios-simulator-version-min=7.0" HOST= else SIMULATOR="-mios-simulator-version-min=5.0" HOST="--host=i386-apple-darwin" fi else PLATFORM="iPhoneOS" if [ $ARCH = "armv7s" ] then CPU="--cpu=swift" else CPU= fi SIMULATOR= HOST="--host=arm-apple-darwin" fi DEVROOT=`xcode-select -p`/"Platforms/$PLATFORM.platform/Developer" SDKROOT=$DEVROOT/SDKs/$PLATFORM$IOS_BASE_SDK.sdk CFLAGS="-arch $ARCH $SIMULATOR -pipe -no-cpp-precomp -isysroot $SDKROOT -I$SDKROOT/usr/include/" export CFLAGS="$CFLAGS" export CXX="llvm-g++" export CC="llvm-gcc" if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ] then export LD=$DEVROOT/usr/bin/ld export LDFLAGS="-L$SDKROOT/usr/lib/" else export LD=$DEVROOT/usr/bin/ld export AR=$DEVROOT/usr/bin/ar export AS=$DEVROOT/usr/bin/as export NM=$DEVROOT/usr/bin/nm export RANLIB=$DEVROOT/usr/bin/ranlib export LDFLAGS="-L$SDKROOT/usr/lib/" export LIBTOOL=$DEVROOT/usr/bin/libtool export LIPO=$DEVROOT/usr/bin/lipo export OTOOL=$DEVROOT/usr/bin/otool export NMEDIT=$DEVROOT/usr/bin/nmedit export DSYMUTIL=$DEVROOT/usr/bin/dsymutil export STRIP=$DEVROOT/usr/bin/strip fi export CPPFLAGS=$CFLAGS export CXXFLAGS=$CFLAGS make distclean $ROOT/$SOURCE/configure $CONFIGURE_FLAGS $HOST --prefix="$THIN/$ARCH" make make install echo "build $ARCH done.." done echo "building fat .." mkdir -p "${FAT}/lib" set - $ARCHS CWD=`pwd` cd ${THIN}/$1/lib for LIB in `ls *.a` do echo $LIB cd $CWD xcrun -sdk iphoneos lipo -create `find $THIN -name $LIB` -output $FAT/lib/$LIB done cd $CWD cp -rf $THIN/$1/include $FAT echo "build fat done.."
3、使用:在写入文件时,需要先写入SPS帧和PPS帧,然后再写入I,B,P帧,不然录像文件播放不了。
#include "mp4record.h" #include <stdlib.h> typedef struct MP4V2_CONTEXT{ int m_vWidth,m_vHeight,m_vFrateR,m_vTimeScale; MP4FileHandle m_mp4FHandle; MP4TrackId m_vTrackId,m_aTrackId; double m_vFrameDur; } MP4V2_CONTEXT; struct MP4V2_CONTEXT * recordCtx = NULL; int initMp4Encoder(const char * filename,int width,int height){ int ret = -1; recordCtx = malloc(sizeof(struct MP4V2_CONTEXT)); if (!recordCtx) { printf("error : malloc context \n"); return ret; } recordCtx->m_vWidth = width; recordCtx->m_vHeight = height; recordCtx->m_vFrateR = 25; recordCtx->m_vTimeScale = 90000; recordCtx->m_vFrameDur = 300; recordCtx->m_vTrackId = 0; recordCtx->m_aTrackId = 0; recordCtx->m_mp4FHandle = MP4Create(filename,0); if (recordCtx->m_mp4FHandle == MP4_INVALID_FILE_HANDLE) { printf("error : MP4Create \n"); return ret; } MP4SetTimeScale(recordCtx->m_mp4FHandle, recordCtx->m_vTimeScale); //------------------------------------------------------------------------------------- audio track // recordCtx->m_aTrackId = MP4AddAudioTrack(recordCtx->m_mp4FHandle, 44100, 1024, MP4_MPEG4_AUDIO_TYPE); // if (recordCtx->m_aTrackId == MP4_INVALID_TRACK_ID){ // printf("error : MP4AddAudioTrack \n"); // return ret; // } // // MP4SetAudioProfileLevel(recordCtx->m_mp4FHandle, 0x2); // uint8_t aacConfig[2] = {18,16}; // MP4SetTrackESConfiguration(recordCtx->m_mp4FHandle,recordCtx->m_aTrackId,aacConfig,2); // printf("ok : initMp4Encoder file=%s \n",filename); return 0; } int mp4VEncode(uint8_t * _naluData ,int _naluSize){ int index = -1; if(_naluData[0]==0 && _naluData[1]==0 && _naluData[2]==0 && _naluData[3]==1 && _naluData[4]==0x67){ index = _NALU_SPS_; } if(index!=_NALU_SPS_ && recordCtx->m_vTrackId == MP4_INVALID_TRACK_ID){ return index; } if(_naluData[0]==0 && _naluData[1]==0 && _naluData[2]==0 && _naluData[3]==1 && _naluData[4]==0x68){ index = _NALU_PPS_; } if(_naluData[0]==0 && _naluData[1]==0 && _naluData[2]==0 && _naluData[3]==1 && _naluData[4]==0x65){ index = _NALU_I_; } if(_naluData[0]==0 && _naluData[1]==0 && _naluData[2]==0 && _naluData[3]==1 && _naluData[4]==0x41){ index = _NALU_P_; } // switch(index){ case _NALU_SPS_: if(recordCtx->m_vTrackId == MP4_INVALID_TRACK_ID){ recordCtx->m_vTrackId = MP4AddH264VideoTrack (recordCtx->m_mp4FHandle, recordCtx->m_vTimeScale, recordCtx->m_vTimeScale / recordCtx->m_vFrateR, recordCtx->m_vWidth, // width recordCtx->m_vHeight, // height _naluData[5], // sps[1] AVCProfileIndication _naluData[6], // sps[2] profile_compat _naluData[7], // sps[3] AVCLevelIndication 3); // 4 bytes length before each NAL unit if (recordCtx->m_vTrackId == MP4_INVALID_TRACK_ID) { return -1; } MP4SetVideoProfileLevel(recordCtx->m_mp4FHandle, 0x7F); // Simple Profile @ Level 3 } MP4AddH264SequenceParameterSet(recordCtx->m_mp4FHandle,recordCtx->m_vTrackId,_naluData+4,_naluSize-4); // break; case _NALU_PPS_: MP4AddH264PictureParameterSet(recordCtx->m_mp4FHandle,recordCtx->m_vTrackId,_naluData+4,_naluSize-4); break; case _NALU_I_: { uint8_t * IFrameData = malloc(_naluSize+1); // IFrameData[0] = (_naluSize-3) >>24; IFrameData[1] = (_naluSize-3) >>16; IFrameData[2] = (_naluSize-3) >>8; IFrameData[3] = (_naluSize-3) &0xff; memcpy(IFrameData+4,_naluData+3,_naluSize-3); // if(!MP4WriteSample(recordCtx->m_mp4FHandle, recordCtx->m_vTrackId, IFrameData, _naluSize+1, recordCtx->m_vFrameDur/44100*90000, 0, 1)){ // return -1; // } // recordCtx->m_vFrameDur = 0; if(!MP4WriteSample(recordCtx->m_mp4FHandle, recordCtx->m_vTrackId, IFrameData, _naluSize+1, MP4_INVALID_DURATION, 0, 1)){ return -1; } free(IFrameData); // break; } case _NALU_P_: { _naluData[0] = (_naluSize-4) >>24; _naluData[1] = (_naluSize-4) >>16; _naluData[2] = (_naluSize-4) >>8; _naluData[3] = (_naluSize-4) &0xff; // if(!MP4WriteSample(recordCtx->m_mp4FHandle, recordCtx->m_vTrackId, _naluData, _naluSize, recordCtx->m_vFrameDur/44100*90000, 0, 1)){ // return -1; // } // recordCtx->m_vFrameDur = 0; if(!MP4WriteSample(recordCtx->m_mp4FHandle, recordCtx->m_vTrackId, _naluData, _naluSize, MP4_INVALID_DURATION, 0, 1)){ return -1; } break; } } return 0; } int mp4AEncode(uint8_t * data ,int len){ if(recordCtx->m_vTrackId == MP4_INVALID_TRACK_ID){ return -1; } MP4WriteSample(recordCtx->m_mp4FHandle, recordCtx->m_aTrackId, data, len , MP4_INVALID_DURATION, 0, 1); recordCtx->m_vFrameDur += 1024; return 0; } void closeMp4Encoder(){ if(recordCtx){ if (recordCtx->m_mp4FHandle != MP4_INVALID_FILE_HANDLE) { MP4Close(recordCtx->m_mp4FHandle,0); recordCtx->m_mp4FHandle = NULL; } free(recordCtx); recordCtx = NULL; } printf("ok : closeMp4Encoder \n"); }
附:有网友提出编译不过,报错。
原因:需要添加系统库libc++.dylib,添加即可。
参考网址:
http://blog.csdn.net/skdkjzz/article/details/40506473
https://github.com/Thinkerfans/lib-mp4v2
相关文章推荐
- TAO使用指南 -- 编译ACE和TAO
- 关于Delphi中预编译指令的使用方法
- 使用ant编译、运行junit、以及检查编码
- jakarta-ant的使用(java编译工具)
- 在MS Windows下使用Visual C++编译Qt
- 使用J2WTK2.2编译和运行第一个J2ME的HelloWorld程序
- 使用Ant编译Java工程(转载)
- windows下编译和使用libpq
- 使用 Eclipse 插件来编辑、编译和调试应用程序
- 怎样使用 Visual C++ 编译出只有 1536 字节的窗口程序
- 使用预编译头文件加快C++语言编译速度
- 使用CODEDOM动态实现代码的生成,编译
- jakarta-ant的使用(java编译工具)
- 使用 Eclipse 插件来编辑、编译和调试应用程序(zz from chianitlab.com)
- 彻底解决RedHat8下的Kylix3安装使用的问题(安装、字体显示、bcb编译问题)
- 水晶报表使用经验谈1--建立水晶报表第一步及编译最易出现错误的解决方法及报表转换成pdf文档进行打印方法
- 在ASP.NET 1.1 中使用预编译功能!
- jakarta-ant的使用(java编译工具)
- 使用CSC编译组件
- fteescale编译环境使用初探