版权声明:本文为博主原创文章,遵循 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

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐