Mp4V2库编译及使用

需求:想用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




你可能感兴趣的:(ffmpeg多媒体问题集)