自行实现ONVIF协议网络摄像机(IPC)开发(8):mp4v2封装h264裸流

一、mp4v2库文件的下载

1、可以网址下载 https://launchpad.net/ubuntu/artful/+source/mp4v2

2、也可以去CSDN下载可以文件 https://download.csdn.net/download/u012478275/10799430

二、linux下mp4v2库的交叉编译

1、使用tar -jxvf xxxx.tar.bz2解压,生成mp4v2-2.0.0文件夹;

2、mp4v2-2.0.0目录下执行 ./configure --host=arm-linux CXX=arm-hisiv300-linux-g++ CC=arm-hisiv300-linux-gcc --prefix=/opt/ --enable-shared --disable-option-checking --disable-debug --disable-fvisibility --disable-largefile --disable-util --disable-dependency-tracking --disable-libtool-lock --disable-optimize

注意:

(1)CXX=arm-hisiv300-linux-g++ CC=arm-hisiv300-linux-gcc为交叉编译工具,我这里使用的海思3520V300的交叉编译工具;

 (2)--prefix=/opt/  为交叉编译完成目标库文件生成的目录,包括库文件和头文件;

(3)其他参数根据需要添加;

3、make

4、make install

5、编译完成后在lib目录可以得到静态库目标libmp4v2.a和动态库目标libmp4v2.so.2.0.0,以及指向动态库的两个软链接文件。 
在include目录下可以得到mp4v2库的所有头文件,其中mp4v2.h是顶层include文件。使用mp4v2库时,只需包含mp4v2.h即可。

三、mp4v2 接口函数 

MP4FileHandle MP4Create (const char* fileName,uint32_t  flags)
功能:创建MP4文件句柄。
 返回:MP4文件句柄。
 参数:fileName 要录制的MP4文件名;flags 创建文件类型,如果要创建普通文件用默认值0就可以,如要录制大于4G的MP4文件此处要设置MP4_CREATE_64BIT_DATA。

bool MP4SetTimeScale( MP4FileHandle hFile, uint32_t value )
功能:设置时间标度。
返回:成功返回true,失败返回false。
参数:hFile MP4文件句柄,value 要设置的值(每秒的时钟ticks数,如90000)。

MP4TrackId MP4AddH264VideoTrack(MP4FileHandle hFile,
                                     uint32_t timeScale,
                                     MP4Duration sampleDuration,
                                     uint16_t width,
                                      uint16_t height,
                                     uint8_t AVCProfileIndication,
                                     uint8_t profile_compat,
                                     uint8_t AVCLevelIndication,
                                     uint8_t sampleLenFieldSizeMinusOne)
功能:添加h264视频track。
返回:返回track id号。
参数:hFile MP4文件句柄,timeScale 视频每秒的ticks数(如90000),sampleDuration 设置为 MP4_INVALID_DURATION(或者 90000/帧率),width height 视频的宽高,AVCProfileIndication profile (baseline profile, main profile, etc. see),profile_compat compatible profile,AVCLevelIndication levels,sampleLenFieldSizeMinusOne 设置为3.
注意: AVCProfileIndication,profile_compat, AVCLevelIndication,这三个参数值是在h264流中sps的前三位,例如sps数据是:67 4D 00 1F 9D A8 14 01 6E 40    这三个数据就取4D 00 1F ;

MP4TrackId MP4AddAudioTrack(
        MP4FileHandle hFile,
        uint32_t timeScale,
        MP4Duration sampleDuration,
        uint8_t audioType)
 功能:添加音频(aac)track。
 返回:返回track id号。
 参数:hFile MP4句柄,timeScale音频每秒的ticks数(如16000),下面两参数设置为MP4_INVALID_DURATION和MP4_MPEG4_AUDIO_TYPE。

bool MP4SetTrackESConfiguration(
       MP4FileHandle  hFile,
       MP4TrackId     trackId,
       const uint8_t* pConfig,
       uint32_t       configSize );

 功能:设置音频解码信息(如果设置错误会导致没有声音)。
 返回:成功返回true,失败返回false。
 参数:hFile 文件句柄,trackId 音频的track id,pConfig 记录解码信息的二进制流,configSize 解码串的长度。
 注意:mpeg4ip 使用faac进行aac音频编码的,在编码时可以调用相应的函数得到二进制串pConfig和长度configSize,但是如果aac不是用faac编码的,这是需要自己填充pConfig,可以参考faac的实现,下面是一个填充结构例子:

前五个字节为 AAC object types  LOW     2
接着4个字节为 码率index        16000      8
接着4个字节为 channels 个数                 1
应打印出的正确2进制形式为  00010 | 1000 | 0001 | 000
                                                            2          8        1

bool MP4WriteSample(
    MP4FileHandle  hFile,
    MP4TrackId     trackId,
    const uint8_t* pBytes,
    uint32_t       numBytes,
    MP4Duration    duration DEFAULT(MP4_INVALID_DURATION),
    MP4Duration    renderingOffset DEFAULT(0),
    bool           isSyncSample DEFAULT(true) );

功能:写一帧视频数据或写一段音频数据。
返回:成功返回true,失败返回false。
参数:hFile 文件句柄,trackId 音频或视频的track id,pBytes为要写的数据流指针,numBytes为数据字节长度,duration为前一视频帧与当前视频帧之间的ticks数,或这是前一段音频数据和当前音频数据之间的ticks。isSyncSample 对视频来说是否为关键帧。
注意:1,duration这个参数是用来实现音视频同步用的,如果设置错了会造成音视频不同步,甚至会出现crash现象(一般出现在调用MP4Close是crash)。 2,对于视频流MP4WriteSample函数每次调用是录制前一帧数据,用当前帧的时间戳和前一帧的时间戳计算duration值,然后把当前帧保存下来用做下次调用MP4WriteSample时用,写音频数据一样。

void MP4AddH264SequenceParameterSet(
    MP4FileHandle  hFile,
    MP4TrackId     trackId,
    const uint8_t* pSequence,
    uint16_t       sequenceLen );

void MP4AddH264PictureParameterSet(
    MP4FileHandle  hFile,
    MP4TrackId     trackId,
    const uint8_t* pPict,
    uint16_t       pictLen );

功能:添加序列参数集,添加图像参数集。
参数:hFile 文件句柄,trackId 视频track id,pSequence和pPict为要写入的序列图像参数集的数据指针,sequenceLen和pictLen为串长度。
注意:当检测到序列参数集或图像参数集更新时要调用MP4AddH264SequenceParameterSet或MP4AddH264PictureParameterSet进行更新。

MP4AddH264SequenceParameterSet的pSequence为H264流sps数据 67 4D 00 1F 9D A8 14 01 6E 40 ,sequenceLen =10;

MP4AddH264PictureParameterSet的pPict为H264流pps数据68 EE 3C 80 00 00 00 01 06 E5 01 9A 80 ,pictLen=13;

 

void MP4Close(
    MP4FileHandle hFile,
    uint32_t    flags DEFAULT(0) );
功能:关闭以打开的MP4文件。
参数:hFile 文件句柄,flags 是否允许在关闭MP4文件前做一些额外的优化处理。

注意:在录制较小的MP4文件时可以把flags设置为默认值,如果录制较大的文件最好把flags设置为MP4_CLOSE_DO_NOT_COMPUTE_BITRATE否则调用MP4Close函数会用掉很长的时间。

 

四、代码

1、初始化

    mp4_info->hMP4File = MP4Create(filename,0);
    if(mp4_info->hMP4File == MP4_INVALID_FILE_HANDLE)    
    {    
        errorPrintf(PRT_COMM,"open file fialed.\n");    
        return NULL;
    }

    if(!MP4SetTimeScale(mp4_info->hMP4File, 90000))
    {
        errorPrintf(PRT_COMM,"MP4SetTimeScale error...\n");    
        return NULL;
    }
   
    mp4_info->videoid =MP4AddH264VideoTrack(mp4_info>hMP4File,9000,9000/15,
    Width,Height,data[i+5],data[i+6],data[i+7], 0);
    if (mp4_info->videoid == MP4_INVALID_TRACK_ID)
    {
        errorPrintf(PRT_COMM,"add video track fialed.\n");
        return ret;
    }
    MP4SetVideoProfileLevel(mp4_info->hMP4File, 0x7F); 

2、添加序列参数集,添加图像参数集

   /* sps */
MP4AddH264SequenceParameterSet(mp4_info->hMP4File, mp4_info->mp4trackid,     
    &spsbuf[0], spslen);

  /* pps */
MP4AddH264PictureParameterSet(mp4_info->hMP4File, mp4_info->mp4trackid,
    &ppsbuf[0], ppslen);


3、写入H264帧(假设一帧数据缓存指针pbuf, 数据长度为len)

MP4WriteSample(mp4_info->hMP4File,mp4_info->videoid, pbuf, len,MP4_INVALID_DURATION, 0, 1);

4、关闭MP4文件

MP4Close(mp4_info->hMP4File,0);

四、代码例子下载

https://download.csdn.net/download/u012478275/10799433

 

 

你可能感兴趣的:(IPC开发)