需求:想用Mp4V2 库将H264流录成MP4文件
反复折腾了好一下子,才整出来,再次纪录下。
具体实现:
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
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