您的位置:首页 > 移动开发 > Android开发

mpeg4ip的Mp4v2库移植到android系统上,实现h264封装到mp4的容器内

2013-07-09 10:00 411 查看
项目中用到保存视频流,找了篇不错的文章,mark一下。

第一步: 首选从官网上下载mpeg4ip源代码,只要其中的lib/mp4v2目录下cpp源文件和.h头文件,和include目录下的mpeg4ip.h和mpeg4ip_version.h头文件。(我下的版本是1.6)。我这里处理了下,把源文件放到src目录下,头文件放到include目录下。

     第二步,源文件做少量修改。

        1、mpeg4ip.h文件中注释掉  #include <mpeg4ip_config.h>

        2、mp4file.cpp文件中的GetNumberOfTracks函数中修改。

        修改前:

        u_int32_t MP4File::GetNumberOfTracks(const char* type, u_int8_t subType)

        {

              if (type == NULL) {

               return m_pTracks.Size();

              } 

              u_int32_t typeSeen = 0;

              const char* normType = MP4NormalizeTrackType(type, m_verbosity);

             for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {

                   if (!strcmp(normType, m_pTracks[i]->GetType())) {

                            if (subType) {

                                                          if (normType == MP4_AUDIO_TRACK_TYPE) {

                                                                   if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {

                                                                          continue;

                                                                      }

                                                          } else if (normType == MP4_VIDEO_TRACK_TYPE) {

                                                                    if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {

                                                                          continue;

                                                                     }

                                                           } 

                             // else unknown subtype, ignore it

                            }

                     typeSeen++;

                 }

            }

           return typeSeen;

       }

       修改后:

        u_int32_t MP4File::GetNumberOfTracks(const char* type, u_int8_t subType)

        {

              if (type == NULL) {

               return m_pTracks.Size();

              } 

              u_int32_t typeSeen = 0;

              const char* normType = MP4NormalizeTrackType(type, m_verbosity);

             for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {

                   if (!strcmp(normType, m_pTracks[i]->GetType())) {

                            if (subType) {

                                                          if ( !strcmp(normType, MP4_AUDIO_TRACK_TYPE)) {

                                                                   if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {

                                                                          continue;

                                                                      }

                                                          } else if ( !strcmp(normType, MP4_VIDEO_TRACK_TYPE) ) {

                                                                    if (subType != GetTrackEsdsObjectTypeId(m_pTracks[i]->GetId())) {

                                                                          continue;

                                                                     }

                                                           } 

                             // else unknown subtype, ignore it

                            }

                     typeSeen++;

                 }

            }

           return typeSeen;

       }

        MP4TrackId MP4File::FindTrackId(u_int16_t trackIndex, const char* type, u_int8_t subType)函数中字符串比较处做同样的修改。

    第三步:编写android.mk文件,这里要注意,因为android中默认的c++不支持异常处理,所以找到一个完整支持c++的标准c++静态库libstdc++.a,把libstdc++.a放到src目录下,且加上

LOCAL_SRC_FILES += libstdc++.a

LOCAL_LDFLAGS := $(LOCAL_PATH)/src/libstdc++.a 

还要加上

LOCAL_CPPFLAGS := -O2 -fexceptions -DHAVE_SOCKLEN_T -DHAVE_STRUCT_IOVEC

     第四步:源码状态下,mm编译。或者用ndk进行编译。

     第五步:调用库,进行封装。

  

   测试源代码(经过测试,封装的文件vlc能正常播放)

     

#include "mp4.h"

int main()

{

   unsigned char sps_pps[24] = {'\0'}; //存储sps和pps

   unsigned char buf[1024*100] = {'\0'};  //存储video数据

   int frameSize = 0;  //取过来的数据长度

   int ret;

   int sps_ppsLen = 0;  //sps和pps的总长度

   int id = start(); //打开数据流

   if(id <0 )

  {

    printf("open video fail %d\n",id);

    return -1;

   }

   ret = getsps(sps_pps,&sps_ppsLen);//取得sps和pps

   if(ret != 0)

   {

    printf("get sps and pps fail %d\n",ret);

    stop(id);

    return -1;

   }

   //创建mp4文件

   MP4FileHandle fileHandle = MP4CreateEx("/data/test.mp4",MP4_DETAILS_ALL,0,1,1,0,0,0,0);

   if(fileHandle == MP4_INVALID_FILE_HANDLE)

   {

    printf("creat mp4 file fail\n");

    stop(id);

    return -1;

   }

   //设置mp4文件的时间单位

    MP4SetTimeScale(fileHandle,90000);

  //创建视频track

   //根据ISO/IEC 14496-10 可知sps的第二个,第三个,第三个字节分别是 AVCProfileIndication,profile_compat,AVCLevelIndication

    MP4TrackId video = MP4AddH264VideoTrack(fileHandle,90000,90000/12,320,240,sps_pps[1],sps_pps[2],sps_pps[3],3);

   if(video == MP4_INVALID_TRACK_ID)

   {

    printf("creat video track fail\n");

    stop(id);

    MP4Close(fileHandle);

    return -1;

   }

  //设置sps和pps

   MP4AddH264SequenceParameterSet(fileHandle,video,sps_pps,sps_ppsLen-5);

   MP4AddH264PictureParameterSet(fileHandle,video,sps_pps+sps_ppsLen-5,5);

   int count = 0;

   int num = 0;

   while(count < 5000)

   {

       while(ret = thakral_getframe(id,buf+4,&frameSize,&num))

      {

        printf("get frame fail %d\n",ret);

       usleep(90*1000);

       }

     //由于传过来的数据没有0x00000001这样的头,都是纯数据,而mp4中的nal结构是 nal长度+nal数据

      int nalsize = frameSize;

      buf[0] = (nalsize&0xff000000)>>24;

      buf[1] = (nalsize&0x00ff0000)>>16;

      buf[2] = (nalsize&0x0000ff00)>>8;

      buf[3] = nalsize&0x000000ff;

      MP4WriteSample(fileHandle,video,buf,frameSize+4,MP4_INVALID_DURATION,0,true);

      count++;

     usleep(85*1000);

    }

    stop(id);

    MP4Close(fileHandle);

   return 0;

 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: