移植mp4v2开源库,h264+g711a/g711u编码mp4

59 篇文章 0 订阅
13 篇文章 1 订阅

1、mp4v2移植

    step1、下载:https://launchpad.net/ubuntu/+source/mp4v2

    step2、编译

                简单配置参数:

                 ./configure --host=arm-linux CXX=arm-hisiv100nptl-linux-g++ CC=arm-hisiv100nptl-linux-gcc --prefix=/home/mp4v2-2.0.0/Demo --enable-shared

                减少库大小配置参数:

                ./configure --host=arm-linux CXX=arm-hisiv100nptl-linux-g++ CC=arm-hisiv100nptl-linux-gcc --prefix=/home/mp4v2-2.0.0/Demo --enable-shared --disable-option-checking --disable-debug --disable-fvisibility --disable-largefile --disable-util --disable-dependency-tracking --disable-libtool-lock

               如果编译出来的库在调用 MP4AddH264VideoTrack 函数时发生崩溃现象,加上以下选项可以解决,具体原因我也不清楚。

               --disable-optimize

              make

              make install

2、mp4v2 API简介

 

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数)。

 

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,width height 视频的宽高,AVCProfileIndication profile (baseline profile, main profile, etc. see),profile_compat compatible profile,AVCLevelIndication levels,sampleLenFieldSizeMinusOne 设置为3.
注意: AVCProfileIndication,profile_compat, AVCLevelIndication,这三个参数值是在h264流中得到的。

 

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。

sampleDuration[翻译:样例持续时长]:音频这中这个参数是指每一帧音频的专多少个采样点

MP4TrackId MP4AddALawAudioTrack(
    MP4FileHandle hFile,
    uint32_t timeScale)

这个接口是初始化添加音频为APCM(G711_A)的接口,接口的问题是其中默认一帧的持续时间是20ms,见下面的源码。我们可以根据自己的实际情况来更改这个值。

MP4TrackId MP4File::AddALawAudioTrack(    uint32_t timeScale )
{
    uint32_t fixedSampleDuration = (timeScale * 20)/1000; // 20mSec/Sample
    MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale);
    m_pTracks[FindTrackIndex(trackId)]->SetFixedSampleDuration(fixedSampleDuration);
    return trackId;
}

所以建议修改库源码为以下接口:

MP4TrackId MP4AddALawAudioTrack(
    MP4FileHandle hFile,
    uint32_t timeScale, uint32_t pointPerFrame)

视频或者音画同步的主要参数是:SampleDuration。

G711_U的方式和G711_A做同样修改。


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进行更新。

 

void MP4Close(
    MP4FileHandle hFile,
    uint32_t    flags DEFAULT(0) );
功能:关闭以打开的MP4文件。
参数:hFile 文件句柄,flags 是否允许在关闭MP4文件前做一些额外的优化处理。
注意:在录制较小的MP4文件时可以把flags设置为默认值,如果录制较大的文件最好把flags设置为MP4_CLOSE_DO_NOT_COMPUTE_BITRATE否则调用MP4Close函数会用掉很长的时间。

3、h264编码mp4文件伪代码

 

  1.      rtp_s* p_rtp = (rtp_s*) arg; 
  2.      if (p_rtp == NULL) 
  3.      { 
  4.          printf("ERROR!\n"); 
  5.          return; 
  6.      } 
  7.   
  8.      MP4FileHandle file = MP4Create("test.mp4", 0);
  9.      if (file == MP4_INVALID_FILE_HANDLE) 
  10.      { 
  11.          printf("open file fialed.\n"); 
  12.          return; 
  13.      } 
  14.   
  15.      MP4SetTimeScale(file, 90000); 
  16.   
  17.      //添加h264 track     
  18.      MP4TrackId video = MP4AddH264VideoTrack(file, 90000, 90000 / video rate(25), width, height, 
  19. sps[1], //sps[1] AVCProfileIndication 
  20. sps[1], //sps[2] profile_compat 
  21. sps[3]f, //sps[3] AVCLevelIndication 
  22. 3); // 4 bytes length before each NAL unit 
  23.      if (video == MP4_INVALID_TRACK_ID) 
  24.      { 
  25.          printf("add video track failed.\n"); 
  26.          return; 
  27.      } 
  28.      MP4SetVideoProfileLevel(file, 0x7F); 
  29.   
  30.      //添加aac音频 
  31.      MP4TrackId audio = MP4AddAudioTrack(file, 48000, 1024, MP4_MPEG4_AUDIO_TYPE); 
  32.      if (video == MP4_INVALID_TRACK_ID) 
  33.      { 
  34.          printf("add audio track failed.\n"); 
  35.          return; 
  36.      } 
  37.      MP4SetAudioProfileLevel(file, 0x2); 
  38.     
  39.     //添加g711-u
  40.     m_audioId = MP4AddULawAudioTrack(hMp4File, 8000, 320);   //8K采用率
  41.     if(m_audioId == MP4_INVALID_TRACK_ID)
  42.     {
  43.         return 0;
  44.     }
  45.     bool  a = MP4SetTrackIntegerProperty( hMp4File,  m_audioId,"mdia.minf.stbl.stsd.ulaw.channels", 1);  //单通道
  46.     MP4SetAudioProfileLevel(hMp4File, 0x02);
  47.     
  48.    //添加g711-a
  49.     m_audioId = MP4AddALawAudioTrack(hMp4File, 8000, 320);   //8K采用率
  50.     if(m_audioId == MP4_INVALID_TRACK_ID)
  51.     {
  52.         return 0;
  53.     }
  54.     bool  a = MP4SetTrackIntegerProperty( hMp4File,  m_audioId,"mdia.minf.stbl.stsd.alaw.channels", 1); //单通道
  55.     MP4SetAudioProfileLevel(hMp4File, 0x02);
  56.  
  57.      int ncount = 0; 
  58.      while (1) 
  59.      { 
  60.          frame_t* pf = NULL; //frame 
  61.          pthread_mutex_lock(&p_rtp->mutex); 
  62.          pf = p_rtp->p_frame_header; 
  63.          if (pf != NULL) 
  64.          { 
  65.              if (pf->i_type == 1)//video 
  66.              { 
  67. MP4WriteSample(file, video, pf->p_frame, pf->i_frame_size, MP4_INVALID_DURATION, 0, 1); 
  68.               } 
  69.              else if (pf->i_type == 2)//audio 
  70.              { 
  71. MP4WriteSample(file, audio, pf->p_frame, pf->i_frame_size , MP4_INVALID_DURATION, 0, 1); 
  72.              } 
  73.   
  74.              ncount++; 
  75.   
  76.              //clear frame. 
  77.              p_rtp->i_buf_num--; 
  78.              p_rtp->p_frame_header = pf->p_next; 
  79.              if (p_rtp->i_buf_num <= 0) 
  80.              { 
  81.                  p_rtp->p_frame_buf = p_rtp->p_frame_header; 
  82.              } 
  83.              free_frame(&pf); 
  84.              pf = NULL; 
  85.   
  86.              if (ncount >= 1000) 
  87.              { 
  88.                  break; 
  89.              } 
  90.          } 
  91.          else 
  92.          { 
  93. //printf("BUFF EMPTY, p_rtp->i_buf_num:%d\n", p_rtp->i_buf_num); 
  94.          } 
  95.          pthread_mutex_unlock(&p_rtp->mutex); 
  96.          usleep(10000); 
  97.      } 
  98.   
  99.      MP4Close(file); 
  100.  }

 

 

 

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值