天天看點

h264->mp4(mp4v2-android)

2012-06-06 17:24

mpeg4ip的Mp4v2庫移植到android系統上,實作h264封裝到mp4的容器内

     第一步: 首選從​​官網​​上下載下傳mpeg4ip源代碼,隻要其中的lib/mp4v2目錄下cpp源檔案和.h頭檔案,和include目錄下的mpeg4ip.h和mpeg4ip_version.h頭檔案。(我下的版本是1.6)。我這裡處理了下,把源檔案放到src目錄下,頭檔案放到include目錄下。

     第二步,源檔案做少量修改。

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;
  }