The recent need to encode H264 video into MP4 format. Research, one method is to use the FFmpeg library, you can first decode the H264 file, and then encode the generation of MP4 files, but this method is less efficient, 10M video may take a few seconds to complete. Another way is to encapsulate the H264 package directly into the MP4 format according to the MP4 file protocol, which is highly efficient because it is directly based on the MP4 package. H264 can be easily packaged into FLV files, but the MP4 format is relatively complex and can be cumbersome to package. Since there is no time to study the MP4 protocol, find an open source MP4 codec library mp4v2 (https://code.google.com/p/mp4v2/) on Google Code, mp4v2 can easily encode H264 format files. For ease of use, a Mp4encoder class is encapsulated based on the library, and the interface for the Mp4encoder package is as follows. Currently only supports encoding H264 files or data frames into a MP4 file.
Class Mp4encoder
{public
:
mp4encoder (void);
~mp4encoder (void);
Public:
//Open or creat a MP4 file.
Mp4filehandle createmp4file (const char *filename,int width,int height,int timescale = 90000,int frameRate =);
Wirte metadata in MP4 file.
BOOL Write264metadata (Mp4filehandle hmp4file,lpmp4enc_metadata lpmetadata);
Wirte data, data can contain multiple frame.
int Writeh264data (mp4filehandle hmp4file,const unsigned char* pdata,int size);
Close MP4 file.
void Closemp4file (Mp4filehandle hmp4file);
Convert H264 file to MP4 file.
No need to Createmp4file and Closemp4file,it would create/close mp4 file automaticly.
BOOL Writeh264file (const char* pfile264,const char* PFILEMP4);
Prase H264 metamata from H264 data frame
static bool Prasemetadata (const unsigned char* pdata,int Size,mp4enc_meta Data &metadata);
};
The client invokes the sample code:
#include <stdio.h>
#include "mp4encoder\mp4encoder.h"
int main (int argc, char** argv)
{
Mp4encoder Mp4encoder;
Convert H264 file to MP4 file
mp4encoder.writeh264file ("test.264", "Test.mp4");
}
Mp4encoder complete code is as follows:
/******************************************************************** filename:mp4encoder.h created:2013-04-16 au
Thor:firehood Purpose:mp4 Encoder, based on the Open Source Library MP4V2 implementation (HTTPS://CODE.GOOGLE.COM/P/MP4V2/). /#pragma once #include "mp4v2\mp4v2.h"//
Nalu Unit 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.
Mp4filehandle createmp4file (const char *filename,int width,int height,int timescale = 90000,int frameRate = 25);
Wirte metadata in MP4 file.
BOOL Write264metadata (Mp4filehandle hmp4file,lpmp4enc_metadata lpmetadata); Wirte data, data can contain multiPle frame.
int Writeh264data (mp4filehandle hmp4file,const unsigned char* pdata,int size);
Close MP4 file.
void Closemp4file (Mp4filehandle hmp4file);
Convert H264 file to MP4 file.
No need to Createmp4file and Closemp4file,it would create/close mp4 file automaticly.
BOOL Writeh264file (const char* pfile264,const char* PFILEMP4); Prase H264 metamata from H264 data frame static bool Prasemetadata (const unsigned char* pdata,int size,mp4enc_metadata
&metadata); Private://Read one NALU from H264 data buffer static int readonenalufrombuf (const unsigned char *buffer,unsigned int n
buffersize,unsigned int offset,mp4enc_naluunit &nalu);
Private:int M_nwidth;
int m_nheight;
int m_nframerate;
int M_ntimescale;
Mp4trackid m_videoid;
};
MP4Encoder.cpp
/******************************************************************** Filename:MP4Encoder.cpp created:2013-04-16
Author:firehood Purpose:mp4 Encoder, based on the Open Source Library MP4V2 implementation (HTTPS://CODE.GOOGLE.COM/P/MP4V2/). /#include "MP4Encoder.h" #include < String.h> #define BUFFER_SIZE (1024*1024) mp4encoder::mp4encoder (void): M_videoid (NULL), M_nwidth (0), m_nheight (0) , M_ntimescale (0), m_nframerate (0) {} mp4encoder::~mp4encoder (void) {} Mp4filehandle mp4encoder::createmp4file (const c Har *pfilename,int width,int height,int timescale/* = 90000*/,int framerate/* = 25*/) {if (Pfilename = = NULL) {return
False
}//Create mp4 file Mp4filehandle 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 = 90000;
M_nframerate = 25;
Mp4settimescale (Hmp4file, M_ntimescale); Return hMp4file; } bool Mp4encoder::write264metadata (Mp4filehandle hmp4file,lpmp4enc_metadata lpmetadata) {m_videoId = Mp4addh264videotrack (Hmp4file, M_ntimescale, M_ntimescale/m_nframerate, M_nwidth,//width m_nheight,//He ight lpmetadata->sps[1],//sps[1] avcprofileindication lpmetadata->sps[2],//sps[2] Profile_compat LpMetadat A->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 profiles @ Level 3//write SPS Mp4addh264sequenceparameterset (Hmp4file,m_videoid,lpmetadata->sps,lpmet
Adata->nspslen);
Write PPS Mp4addh264pictureparameterset (Hmp4file,m_videoid,lpmetadata->pps,lpmetadata->nppslen);
return true;
} int Mp4encoder::writeh264data (mp4filehandle hmp4file,const unsigned char* pdata,int size) {if (Hmp4file = = NULL) {
return-1;
}if (PData = = NULL) {return-1;
} mp4enc_naluunit Nalu;
int pos = 0, len = 0; while (len = Readonenalufrombuf (Pdata,size,pos,nalu)) {if (Nalu.type = = 0x07)//SPS {//Add H264 track M_vi Deoid = Mp4addh264videotrack (Hmp4file, M_ntimescale, M_ntimescale/m_nframerate, m_nwidth,//WID
Th 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; } mp4setvideoprofilelevel (Hmp4file, 1);
Simple profiles @ Level 3 Mp4addh264sequenceparameterset (hmp4file,m_videoid,nalu.data,nalu.size);
} else if (Nalu.type = = 0x08)//PPS {mp4addh264pictureparameterset (hmp4file,m_videoid,nalu.data,nalu.size);
} else {int datalen = nalu.size+4; unsigned char *data = newunsigned char[datalen];
MP4 Nalu The first four bytes represent Nalu length 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)) {return 0;
} delete[] data;
} pos + = Len;
} return POS; } int Mp4encoder::readonenalufrombuf (const unsigned 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 &A
mp;& 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::closemp4file (Mp4filehandle hmp4file) {if (hmp4file) {mp4close (hmp4file);
Hmp4file = NULL; }} bool Mp4encoder::writeh264file (const char* pfile264,const char* pFileMp4) {if (pFile264 = = NULL | | pFileMp4 = NU
LL) {return false;
} mp4filehandle hmp4file = Createmp4file (pfilemp4,352,288);
if (Hmp4file = = NULL) {printf ("Error:create file failed!");
return false;
} FILE *FP = fopen (pFile264, "RB");
if (!FP) {printf ("Error:open file failed!");
return false;
} fseek (FP, 0, Seek_set);
unsigned char *buffer = new unsigned 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 (Hmp4file,buffer,writelen);
if (writelen<=0) {break;
} memcpy (buffer,buffer+writelen,readlen-writelen+1);
pos = readlen-writelen+1;
} fclose (FP);
delete[] buffer;
Closemp4file (Hmp4file);
return true; } bool Mp4encoder:: prasemetadata (const unsigned 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;
}