您的位置:首页 > 其它

如何生成mp4文件

2015-11-23 22:38 344 查看
生成mp4库的开源有很多 

1.gpac  https://gpac.wp.mines-telecom.fr

2.mpeg4ip http://mpeg4ip.sourceforge.net

3.mp4v2 从mpeg4ip提取 https://code.google.com/p/mp4v2/
 1.创建文件

 MP4Encoder m_objFileWriter;

 int r = m_objFileWriter.CreateMP4File((char*)m_file.c_str(),m_w,m_h,90000,m_fps);

2.写入视频数据

m_objFileWriter.WriteH264Data(data,iLen);

3.结束

m_objFileWriter.CloseMP4File();

======================源代码========================================

#pragma once

#include "mp4v2/mp4v2.h"

#include <string>

using namespace std;

// NALU单元

//#define NALU_TYPE_SLICE 1

//#define NALU_TYPE_DPA 2

//#define NALU_TYPE_DPB 3

//#define NALU_TYPE_DPC 4

//#define NALU_TYPE_IDR 5

//#define NALU_TYPE_SEI 6

//#define NALU_TYPE_SPS 7

//#define NALU_TYPE_PPS 8

//#define NALU_TYPE_AUD 9

//#define NALU_TYPE_EOSEQ 10

//#define NALU_TYPE_EOSTREAM 11

//#define NALU_TYPE_FILL 12

typedef struct _MP4ENC_NaluUnit

{

 int type;

 int size;

 unsigned char *data;

}MP4ENC_NaluUnit;

typedef struct _MP4ENC_Metadata

{

 // video, must be h264 type

 unsigned int nSpsLen;

 unsigned char Sps[1024];

 unsigned int nPpsLen;

 unsigned char Pps[1024];

} MP4ENC_Metadata,*LPMP4ENC_Metadata;

class MP4Encoder

{

public:

 MP4Encoder(void);

 ~MP4Encoder(void);

public:

 // open or creat a mp4 file.

    bool CreateMP4File(const char *fileName,int width,int height,int timeScale = 90000,int frameRate = 25);

 // wirte 264 metadata in mp4 file.

    bool Write264Metadata(LPMP4ENC_Metadata lpMetadata);

 // wirte 264 data, data can contain  multiple frame.

    int WriteH264Data(char* pData,int size,int videoWidth=0, int videoHeight=0);

    // close mp4 file.

    void CloseMP4File();

    // convert H264 file to mp4 file.

 // no need to call CreateMP4File and CloseMP4File,it will create/close mp4 file automaticly.

 bool WriteH264File(const char* pFile264,const char* pFileMp4);

    string getFileName() {

        return fileName;

    }

 // Prase H264 metamata from H264 data frame

    static bool PraseMetadata(char* pData,int size,MP4ENC_Metadata &metadata);

    static unsigned int test4byte(char* data, unsigned int offset) {

        return (data[offset] << 24) | (data[offset+1] << 16) | (data[offset+2] << 8) | (data[offset+3]);

    }

private:

 // read one nalu from H264 data buffer

    static int ReadOneNaluFromBuf(char *buffer,unsigned int nBufferSize,unsigned int offSet,MP4ENC_NaluUnit &nalu);

 void reset();

private:

 int m_nWidth;

 int m_nHeight;

 int m_nFrameRate;

 int m_nTimeScale;

 bool haveGetSPS;

 bool haveGetPPs;

    string fileName;

 MP4TrackId m_videoId;

    MP4FileHandle hMp4File;

};

#endif /* MP4ENCODER_H_ */

#include "MP4Encoder.h"

#include <string.h>

#define BUFFER_SIZE  (1024*1024)

MP4Encoder::MP4Encoder(void)

{

 reset();

}

MP4Encoder::~MP4Encoder(void)

{

}

bool MP4Encoder::CreateMP4File(const char *pFileName,int width,int height,int timeScale/* = 90000*/,int frameRate/* = 25*/)

{

 reset();

 if(pFileName == NULL)

 {

        return false;

 }

    fileName = pFileName;

 // create mp4 file

    hMp4File = MP4Create(pFileName);

    if (hMp4File == MP4_INVALID_FILE_HANDLE)

 {

        printf("ERROR:Open file fialed.\n");

        return false;

 }

 m_nWidth = width;

 m_nHeight = height;

 m_nTimeScale = timeScale;

 m_nFrameRate = frameRate;

    MP4SetTimeScale(hMp4File, m_nTimeScale);

    return true;

}

bool MP4Encoder::Write264Metadata(LPMP4ENC_Metadata lpMetadata)

{

    if(hMp4File == NULL) {

        return false;

    }

 m_videoId = MP4AddH264VideoTrack

  (hMp4File,

  m_nTimeScale,

  m_nTimeScale / m_nFrameRate,

  m_nWidth, // width

  m_nHeight,// height

  lpMetadata->Sps[1], // sps[1] AVCProfileIndication

  lpMetadata->Sps[2], // sps[2] profile_compat

  lpMetadata->Sps[3], // sps[3] AVCLevelIndication

  3);           // 4 bytes length before each NAL unit

 if (m_videoId == MP4_INVALID_TRACK_ID)

 {

        printf("add video track failed.\n");

  return false;

 }

 MP4SetVideoProfileLevel(hMp4File, 0x01); //  Simple Profile @ Level 3

 // write sps

    MP4AddH264SequenceParameterSet(hMp4File,m_videoId,lpMetadata->Sps,lpMetadata->nSpsLen);

 // write pps

 MP4AddH264PictureParameterSet(hMp4File,m_videoId,lpMetadata->Pps,lpMetadata->nPpsLen);

 return true;

}

int MP4Encoder::WriteH264Data(char* pData, int size, int videoWidth, int videoHeight)

{

 if(hMp4File == NULL)

 {

        printf("MP4Encoder::WriteH264Data hMp4File == NULL! create file first!.\n");

  return -1;

 }

    if(pData == NULL || size == 0)

 {

        printf("MP4Encoder::WriteH264Data pData == NULL or size == 0!.\n");

  return -1;

 }

   

    if(videoWidth>0&&videoHeight>0) {

        m_nWidth = m_nWidth== videoWidth?m_nWidth:videoWidth;

        m_nHeight = m_nHeight== videoHeight?m_nHeight:videoHeight;

    }

    if(test4byte(pData, 0) == 0x00000001

            && (pData[4]&0x1F) == 9) {//skip aud 00 00 00 01 09 10 or 00 00 00 01 09 30

        pData = pData + 6;

        size = size - 6;

    }

 MP4ENC_NaluUnit nalu;

 int pos = 0, len = 0;

 while (len = ReadOneNaluFromBuf(pData,size,pos,nalu))

 {

        if(nalu.type != 0x01

                && nalu.type != 0x05

                && nalu.type != 0x06

                && nalu.type != 0x07

                && nalu.type != 0x08

                && nalu.type != 0x09

                ){

            printf("recv invalidate frame! drop it\n");

            return 0;

        }

  if(nalu.type == 0x07) // sps

  {

   // 添加h264 track

   if(!haveGetSPS) {

    m_videoId = MP4AddH264VideoTrack

      (hMp4File,

        m_nTimeScale,

        m_nTimeScale / m_nFrameRate,

        m_nWidth,     // width

        m_nHeight,    // height

        nalu.data[1], // sps[1] AVCProfileIndication

        nalu.data[2], // sps[2] profile_compat

        nalu.data[3], // sps[3] AVCLevelIndication

        3);           // 4 bytes length before each NAL unit

    if (m_videoId == MP4_INVALID_TRACK_ID)

    {

                    printf("add video track failed.\n");

     return 0;

    }

                printf("find sps! add Track %d %d %d.\n", m_videoId, m_nWidth, m_nHeight);

    MP4SetVideoProfileLevel(hMp4File, 1); //  Simple Profile @ Level 3

    MP4AddH264SequenceParameterSet(hMp4File,m_videoId,nalu.data,nalu.size);

    haveGetSPS = true;

   }

  }

  else if(nalu.type == 0x08) // pps

  {

   if(!haveGetPPs) {

    MP4AddH264PictureParameterSet(hMp4File,m_videoId,nalu.data,nalu.size);

    haveGetPPs = true;

   }

  }

  else

  {

            if(!haveGetSPS

                    || !haveGetPPs) {

                printf("MP4Encoder watting first i frame\n");

                return 0;

            }

            if(nalu.type == 0x06) {//skip sei

                pos += len;

                continue;

            }

            int datalen = nalu.size+4;

   unsigned char *data = new unsigned char[datalen];

   // MP4 Nalu前四个字节表示Nalu长度

   data[0] = nalu.size>>24;

   data[1] = nalu.size>>16;

   data[2] = nalu.size>>8;

   data[3] = nalu.size&0xff;

   memcpy(data+4,nalu.data,nalu.size);

   if(!MP4WriteSample(hMp4File, m_videoId, data, datalen,MP4_INVALID_DURATION, 0, 1))

   {

                printf("MP4Encoder::MP4WriteSample error.\n");

    return 0;

   }

   delete[] data;

  }

  pos += len;

 }

    return pos;

}

int MP4Encoder::ReadOneNaluFromBuf(char *buffer,unsigned int nBufferSize,unsigned int offSet,MP4ENC_NaluUnit &nalu)

{

 int i = offSet;

 while(i<nBufferSize)

 {

  if(buffer[i++] == 0x00 &&

   buffer[i++] == 0x00 &&

   buffer[i++] == 0x00 &&

   buffer[i++] == 0x01

   )

  {

   int pos = i;

   while (pos<nBufferSize)

   {

    if(buffer[pos++] == 0x00 &&

     buffer[pos++] == 0x00 &&

     buffer[pos++] == 0x00 &&

     buffer[pos++] == 0x01

     )

    {

     break;

    }

   }

   if(pos == nBufferSize)

   {

    nalu.size = pos-i;

   }

   else

   {

    nalu.size = (pos-4)-i;

   }

   nalu.type = buffer[i]&0x1f;

   nalu.data =(unsigned char*)&buffer[i];

   return (nalu.size+i-offSet);

  }

 }

 return 0;

}

void MP4Encoder::reset() {

 m_videoId = -1;

 m_nWidth = 0;

 m_nHeight = 0;

 m_nTimeScale = 0;

 m_nFrameRate = 0;

 haveGetSPS = false;

 haveGetPPs = false;

    hMp4File = NULL;

}

void MP4Encoder::CloseMP4File()

{

    if(hMp4File)

 {

        MP4Duration fileDuration = MP4GetDuration(hMp4File);

        MP4Duration tmpDuration = MP4_INVALID_DURATION;

        uint64_t durationInMs = 0;

        if(m_videoId != MP4_INVALID_TRACK_ID) {

            tmpDuration = MP4GetTrackDuration(hMp4File,m_videoId);

            durationInMs =

                    double(MP4ConvertFromTrackDuration(hMp4File, m_videoId,

                                                       tmpDuration, MP4_MSECS_TIME_SCALE));

        }

//        if(fileDuration == 0

//                && tmpDuration != 0) {

        if(tmpDuration != 0) {

            fileDuration = tmpDuration;

          //  qDebug() << "MP4SetDuration before MP4Encoder::closeMP4File " << fileDuration;

          //  MP4SetDuration(hMp4File, fileDuration);

        }

     //  qDebug() << " MP4Encoder::CloseMP4File " << fileName

      //          << " fileDuration is " << fileDuration

       ////         << " " << tmpDuration

        //        << " durationInMs " << durationInMs;

        MP4Close(hMp4File);

  hMp4File = NULL;

 }

}

bool MP4Encoder::WriteH264File(const char* pFile264,const char* pFileMp4)

{

    if(pFile264 == NULL || pFileMp4 == NULL)

 {

  return false;

 }

    if(!CreateMP4File(pFileMp4,352,288)) {

        printf("ERROR:Create file failed!\n");

        return false;

    }

 FILE *fp = fopen(pFile264, "rb");

 if(!fp)

 {

        printf("ERROR:open file failed!\n");

  return false;

 }

 fseek(fp, 0, SEEK_SET);

    char *buffer  = new char[BUFFER_SIZE];

 int pos = 0;

 while(1)

 {

  int readlen = fread(buffer+pos, sizeof(unsigned char), BUFFER_SIZE-pos, fp);

  if(readlen<=0)

  {

   break;

  }

  readlen += pos;

  int writelen = 0;

  for(int i = readlen-1; i>=0; i--)

  {

    if(buffer[i--] == 0x01 &&

     buffer[i--] == 0x00 &&

     buffer[i--] == 0x00 &&

     buffer[i--] == 0x00

     )

    {

     writelen = i+5;

     break;

    }

  }

        writelen = WriteH264Data(buffer,writelen);

  if(writelen<=0)

  {

   break;

  }

  memcpy(buffer,buffer+writelen,readlen-writelen+1);

  pos = readlen-writelen+1;

 }

 fclose(fp);

 delete[] buffer;

    CloseMP4File();

 return true;

}

bool MP4Encoder:: PraseMetadata(char* pData,int size,MP4ENC_Metadata &metadata)

{

 if(pData == NULL || size<4)

 {

  return false;

 }

 MP4ENC_NaluUnit nalu;

 int pos = 0;

 bool bRet1 = false,bRet2 = false;

 while (int len = ReadOneNaluFromBuf(pData,size,pos,nalu))

 {

  if(nalu.type == 0x07)

  {

   memcpy(metadata.Sps,nalu.data,nalu.size);

   metadata.nSpsLen = nalu.size;

   bRet1 = true;

  }

  else if((nalu.type == 0x08))

  {

   memcpy(metadata.Pps,nalu.data,nalu.size);

   metadata.nPpsLen = nalu.size;

   bRet2 = true;

  }

  pos += len;

 }

 if(bRet1 && bRet2)

 {

  return true;

 }

 return false;

}



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