使用mp4v2封裝H.264成mp4最簡單示例

版權聲明:本文爲博主原創文章,遵循 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章