版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/weixin_42462202/article/details/90108485
使用mp4v2封裝h.264成mp4最簡單示例
幾個重要的API
MP4Create
/*
- 函數功能:創建一個mp4文件
- 參數:fileName - mp4文件名
- 參數:flags - 設置屬性(MP4_CREATE_64BIT_DATA、MP4_CREATE_64BIT_TIME)
- 返回值:mp4文件的句柄 */
MP4FileHandle MP4Create(
const char* fileName,
uint32_t flags DEFAULT(0) );
MP4Close
/*
- 函數功能:關閉mp4文件,在寫入mp4文件後必須調用此函數,不然mp4文件會損壞
- 參數:hFile - mp4文件的句柄
*/
void MP4Close(
MP4FileHandle hFile,
uint32_t flags DEFAULT(0) );
MP4AddH264VideoTrack
/*
- 函數功能:添加track,相當於添加一路流
- 參數:hFile - mp4文件的句柄
- 參數:width - 視頻寬度
- 參數:height - 視頻高度
- 參數:AVCProfileIndication - sps[1]
- 參數:profile_compat - sps[2]
- 參數:AVCLevelIndication - sps[3]
- 參數:sampleLenFieldSizeMinusOne - 設置爲3即可
- 返回值:添加track的id
*/
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 );
MP4AddH264SequenceParameterSet
/*
- 函數功能:添加sps到mp4文件
- 參數:hFile - mp4文件的句柄
- 參數:pSequence - 指向sps的指針
- 參數:sequenceLen - sps的長度
/
MP4V2_EXPORT
void MP4AddH264SequenceParameterSet(
MP4FileHandle hFile,
MP4TrackId trackId,
const uint8_t pSequence,
uint16_t sequenceLen );
MP4AddH264PictureParameterSet
/*
- 函數功能:添加sps到mp4文件
- 參數:hFile - mp4文件的句柄
- 參數:pPict - 指向pps的指針
- 參數:pictLen - pps的長度
/
void MP4AddH264PictureParameterSet(
MP4FileHandle hFile,
MP4TrackId trackId,
const uint8_t pPict,
uint16_t pictLen );
MP4WriteSample
/*
* 函數功能:寫入nalu
* 參數:hFile - mp4文件的句柄
* 注意:前四個字節表示該nalu的長度
*/
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) );
封裝流程
sps
pps
其他類型的nalu
MP4Create
MP4AddH264VideoTrack
MP4AddH264SequenceParameterSet
MP4AddH264PictureParameterSet
MP4WriteSample
源碼
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <mp4v2/mp4v2.h>
int getNalu(FILE *pFile, unsigned char *pNalu)
{
unsigned char c;
int pos = 0;
int len;
if(!pFile)
return -1;
if((len = fread(pNalu, 1, 4, pFile)) <= 0)
return -1;
if(pNalu[0] != 0 || pNalu[1] != 0 || pNalu[2] != 0 || pNalu[3] != 1)
return -1;
pos = 4;
while(1)
{
if(feof(pFile))
break;
pNalu[pos] = fgetc(pFile);
if(pNalu[pos-3] == 0 && pNalu[pos-2] == 0 && pNalu[pos-1] == 0 && pNalu[pos] == 1)
{
fseek(pFile, -4, SEEK_CUR);
pos -= 4;
break;
}
pos++;
}
len = pos+1;
return len;
}
int packet2Mp4(const char *inputFile, const char *outputFiles)
{
FILE *pIn = NULL;
unsigned char *pBuf = malloc(1024*1024);
unsigned char *pNalu = NULL;
unsigned char naluType;
int len;
int num = 0;
MP4FileHandle pHandle = NULL;
MP4TrackId videoId;
int width = 640;
int height = 480;
int frameRate = 15;
int timeScale = 90000;
int addStream = 1;
pIn = fopen(inputFile, "rb");
if(!pIn)
return -1;
pHandle = MP4Create(outputFiles, 0);
if(pHandle == MP4_INVALID_FILE_HANDLE)
{
printf("ERROR:Create mp4 handle fialed.\n");
return -1;
}
MP4SetTimeScale(pHandle, timeScale);
while(1)
{
len = getNalu(pIn, pBuf);
if (len <= 0)
break;
if (pBuf[0] != 0 || pBuf[1] != 0 || pBuf[2] != 0 || pBuf[3] != 1)
continue;
len -= 4;
pNalu = pBuf+4;
naluType = pNalu[0]&0x1F;
switch (naluType)
{
case 0x07: // SPS
printf("------------------------------------\n");
printf("sps(%d)\n", len);
if (addStream)
{
videoId = MP4AddH264VideoTrack
(pHandle,
timeScale, // 一秒鐘多少timescale
timeScale/frameRate, // 每個幀有多少個timescale
width, // width
height, // height
pNalu[1], // sps[1] AVCProfileIndication
pNalu[2], // sps[2] profile_compat
pNalu[3], // sps[3] AVCLevelIndication
3); // 4 bytes length before each NAL unit
if (videoId == MP4_INVALID_TRACK_ID)
{
printf("Error:Can't add track.\n");
return -1;
}
MP4SetVideoProfileLevel(pHandle, 0x7F);
addStream = 0;
}
MP4AddH264SequenceParameterSet(pHandle, videoId, pNalu, len);
break;
case 0x08: // PPS
printf("pps(%d)\n", len);
MP4AddH264PictureParameterSet(pHandle, videoId, pNalu, len);
break;
default:
printf("slice(%d)\n", len);
pBuf[0] = (len>>24)&0xFF;
pBuf[1] = (len>>16)&0xFF;
pBuf[2] = (len>>8)&0xFF;
pBuf[3] = (len>>0)&0xFF;
MP4WriteSample(pHandle, videoId, pBuf, len+4, MP4_INVALID_DURATION, 0, 1);
break;
}
}
free(pBuf);
fclose(pIn);
MP4Close(pHandle, 0);
return 0;
}
int main(int argc, char *argv[])
{
if (packet2Mp4("test.h264", "test.mp4"))
{
printf("Error:Packet to Mp4 fail.\n");
return -1;
}
return 0;
}
文章最後發佈於: 2019-05-11 13:17:26
————————————————
版權聲明:本文爲CSDN博主「JT」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_42462202/article/details/90108485