使用mp4v2封装H.264成mp4最简单示例

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

发布了105 篇原创文章 · 获赞 191 · 访问量 7万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 数字20 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览