MP4v2调用接口及源码追踪

MP4格式:https://blog.csdn.net/qq_39048131/article/details/123133089?spm=1001.2014.3001.5501

1. MP4Create 

作用:创建mp4文件;

1. MP4FileHandle MP4Create (pFileName,  MP4_CREATE_64BIT_DATA);
if (hMp4file == MP4_INVALID_FILE_HANDLE){
    printf("ERROR:MP4Create  fialed.\n");
    return NULL;
}

/* 对应源码 src/mp4.cpp
    MP4FileHandle MP4Create (const char* fileName,
                             uint32_t  flags)
    {
        return MP4CreateEx(fileName, flags);//实际上调用了MP4CreateEx;
    }
*/

/*
参数1:将要创建的文件名绝对路径
参数2:flags;
    MP4_CREATE_64BIT_DATA // Bit: enable 64-bit data-atoms. 
    MP4_CREATE_64BIT_TIME // Bit: enable 64-bit time-atoms. 
参数3和4:是否添加添加ftyp和iods;默认1,添加;
参数5和6:主要标识字符串,次要版本号;默认均为0;
参数7和8:兼容标识和版本号;默认均为0;
返回值:失败返回MP4_INVALID_FILE_HANDLE
*/
2. MP4FileHandle hMp4file = MP4CreateEx(pFileName,  MP4_CREATE_64BIT_DATA, 1, 1, 0, 0, 0, 0);
if (hMp4file == MP4_INVALID_FILE_HANDLE){
    printf("ERROR:MP4CreateEx fialed.\n");
    return NULL;
}

/* 对应源码
    MP4FileHandle MP4CreateEx (const char* fileName,
                               uint32_t  flags,
                               int add_ftyp,
                               int add_iods,
                               char* majorBrand,
                               uint32_t minorVersion,
                               char** supportedBrands,
                               uint32_t supportedBrandsCount)
    {
        ...
        MP4File* pFile = ConstructMP4File();//new出MP4File
        if (!pFile)
            return MP4_INVALID_FILE_HANDLE;

        try {
            ASSERT(pFile);
            // LATER useExtensibleFormat, moov first, then mvex's
            //Create中根据传入的参数进行track的骨架生成;还包括"mdat","moov""iods"等;
            pFile->Create(fileName, flags, add_ftyp, add_iods,
                          majorBrand, minorVersion,
                          supportedBrands, supportedBrandsCount);
            return (MP4FileHandle)pFile;//创建成功返回句柄; 
        }
        // ... catch{}

        if (pFile)
            delete pFile;
        return MP4_INVALID_FILE_HANDLE;
    }

*/

2. MP4SetTimeScale

作用:设置时间尺度;文件媒体在1秒时间内的刻度值,可以理解为1秒长度的时间单元数;主要用于和duration配合计算文件时长等;

/*
参数1:句柄
参数2:时间刻度值;
返回值:设置成功返回true,失败返回false;
*/
MP4SetTimeScale(hMp4file,timeScale);
/* 源码 src/mp4info.cpp
    ((MP4File*)hFile)->SetTimeScale(value);
*/

3. MP4Close

作用:关闭mp4文件;和MP4Create 成对调用;

/*
参数1:句柄
参数2:flags;
    MP4_CLOSE_DO_NOT_COMPUTE_BITRATE // 不要在文件关闭时重新计算平均/最大比特率
*/
MP4Close(hMp4File, MP4_CLOSE_DO_NOT_COMPUTE_BITRATE);

/* 源码 src/mp4.cpp
    MP4File& f = *(MP4File*)hFile;
    f.Close(flags);
    delete &f;
*/

4. MP4AddH264VideoTrack

作用:添加video track,返回video track id值;

本函数在nalu类型为sps调用;
MP4TrackId videoID = MP4AddH264VideoTrack(hMp4File,             //句柄
                     timeScale,            //时间刻度
                     timeScale / frameRate,//时间刻度/视频帧率
                     width,                //宽
                     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
/* 源码 src/mp4.cpp
    MP4File *pFile = (MP4File *)hFile;
    return pFile->AddH264VideoTrack(timeScale,sampleDuration,width,height,
                                     AVCProfileIndication, profile_compat,
                                     AVCLevelIndication,sampleLenFieldSizeMinusOne);

    AddH264VideoTrack(...){
        添加了moov/track中的tkhd和media相关box信息;
        MP4TrackId trackId = AddVideoTrackDefault(timeScale,
                         sampleDuration,
                         width,
                         height,
                         "avc1");

        添加了mdia/minf/stbl/stsd/avc1相关box信息;
        SetTrackIntegerProperty(trackId,
                            "mdia.minf.stbl.stsd.avc1.width", width);
        SetTrackIntegerProperty(trackId,
                            "mdia.minf.stbl.stsd.avc1.height", height);

        SetTrackIntegerProperty(trackId,
                            "mdia.minf.stbl.stsd.avc1.avcC.AVCProfileIndication",
                            AVCProfileIndication);
        SetTrackIntegerProperty(trackId,
                            "mdia.minf.stbl.stsd.avc1.avcC.profile_compatibility",
                            profile_compat);
        SetTrackIntegerProperty(trackId,
                            "mdia.minf.stbl.stsd.avc1.avcC.AVCLevelIndication",
                            AVCLevelIndication);
        SetTrackIntegerProperty(trackId,
                            "mdia.minf.stbl.stsd.avc1.avcC.lengthSizeMinusOne",
                            sampleLenFieldSizeMinusOne);

    }
    
*/

5. MP4SetVideoProfileLevel

作用:设置video profile等级;

/*
    参数1:句柄
    参数2:设置的值
*/
MP4SetVideoProfileLevel(hMp4File, 0x7f);

/* 源码
 ((MP4File*)hFile)->SetVideoProfileLevel(value);
    -> 调用 SetIntegerProperty("moov.iods.visualProfileLevelId", value);
*/

6. MP4AddAudioTrack

作用: 添加音频 track

/*
    参数1:句柄
    参数2:时间刻度,建议设置成采样频率,以保证计时信息准确;  
    参数3:所有track采样的固定持续时间。    
    参数4:MP4_INVALID_AUDIO_TYPE~MP4_PCM16_BIG_ENDIAN_AUDIO_TYPE 位于general.h中;
*/
MP4TrackId audioID = MP4AddAudioTrack(hMp4File, nSampleRate,sampleDuration,
MP4_MPEG4_AUDIO_TYPE);

/* 源码
((MP4File*)hFile)->AddAudioTrack(timeScale, sampleDuration, audioType);

同样生成了tkhdh和mdia相关信息;
->执行了{
    MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale);

    AddTrackToOd(trackId);

    SetTrackFloatProperty(trackId, "tkhd.volume", 1.0);

    (void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0);

    (void)AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4a");

    AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.name");

    // stsd is a unique beast in that it has a count of the number
    // of child atoms that needs to be incremented after we add the mp4a atom
    MP4Integer32Property* pStsdCountProperty;
    FindIntegerProperty(
        MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
        (MP4Property**)&pStsdCountProperty);
    pStsdCountProperty->IncrementValue();

    SetTrackIntegerProperty(trackId,
                            "mdia.minf.stbl.stsd.mp4a.timeScale", timeScale << 16);

    SetTrackIntegerProperty(trackId,
                            "mdia.minf.stbl.stsd.mp4a.esds.ESID",
                            0
                           );

    SetTrackIntegerProperty(trackId,
                            "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId",
                            audioType);

    SetTrackIntegerProperty(trackId,
                            "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.streamType",
                            MP4AudioStreamType);

    m_pTracks[FindTrackIndex(trackId)]->
    SetFixedSampleDuration(sampleDuration);
}    
*/

7.MP4SetAudioProfileLevel

作用:设置audio profile等级

/*
    参数1:句柄
    参数2:设置等级值
*/
MP4SetAudioProfileLevel(hMp4File, 0x2);

/* 源码
    ((MP4File*)hFile)->SetAudioProfileLevel(value);
    -> 调用了 SetIntegerProperty("moov.iods.audioProfileLevelId", value);
*/

8. MP4SetTrackESConfiguration

作用:设置音频ES配置

char ucBuffer[] = {0x15 ,0x88};
//该参数可以直接写,也可以使用faac库的faacEncGetDecoderSpecificInfo获取;

/*
    参数1:句柄
    参数2:音频track ID值;
    参数3:配置值;
    参数4:配置写入长度
*/
MP4SetTrackESConfiguration(hMp4File, audioID, ucBuffer, 2);

/*源码
    ((MP4File*)hFile)->SetTrackESConfiguration(trackId, pConfig, configSize);
    -> 调用:{
    MP4DescriptorProperty* pConfigDescrProperty = NULL;
    if (FindProperty(MakeTrackName(trackId,
                                   "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo"),
                     (MP4Property**)&pConfigDescrProperty) == false ||
            pConfigDescrProperty == NULL) {
        // probably trackId refers to a hint track
        throw new Exception("no such property", __FILE__, __LINE__, __FUNCTION__);
    }

    // lookup the property to store the configuration
    MP4BytesProperty* pInfoProperty = NULL;
    (void)pConfigDescrProperty->FindProperty("decSpecificInfo[0].info",
            (MP4Property**)&pInfoProperty);

    // configuration being set for the first time
    if (pInfoProperty == NULL) {
        // need to create a new descriptor to hold it
        MP4Descriptor* pConfigDescr =
            pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag);
        pConfigDescr->Generate();

        (void)pConfigDescrProperty->FindProperty(
            "decSpecificInfo[0].info",
            (MP4Property**)&pInfoProperty);
        ASSERT(pInfoProperty);
    }

    // set the value
    pInfoProperty->SetValue(pConfig, configSize);
 }
*/

9. MP4AddH264SequenceParameterSet

作用:添加序列参数集(sps)设置

/*
    参数1:文件句柄
    参数2:视频track id
    参数3和4:(sps)nalu数据和长度
*/
MP4AddH264SequenceParameterSet(hMp4File,videoID,nalu.data,nalu.size);

/* 源码
主要填充mdia.minf.stbl.stsd.avc1.avcC下相关信息;

MP4File *pFile = (MP4File *)hFile;
pFile->AddH264SequenceParameterSet(trackId,pSequence,sequenceLen);
{
    format = GetTrackMediaDataName(trackId);

    if (!strcasecmp(format, "avc1"))
        avcCAtom = FindAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.avc1.avcC"));
    else if (!strcasecmp(format, "encv"))
        avcCAtom = FindAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.encv.avcC"));
    else
        // huh?  unknown track format
        return;


    MP4BitfieldProperty *pCount;
    MP4Integer16Property *pLength;
    MP4BytesProperty *pUnit;
    if ((avcCAtom->FindProperty("avcC.numOfSequenceParameterSets",
                                (MP4Property **)&pCount) == false) ||
            (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetLength",
                                    (MP4Property **)&pLength) == false) ||
            (avcCAtom->FindProperty("avcC.sequenceEntries.sequenceParameterSetNALUnit",
                                    (MP4Property **)&pUnit) == false)) {
        log.errorf("%s: \"%s\": Could not find avcC properties",
                   __FUNCTION__, GetFilename().c_str() );
        return;
    }

    ...

    pLength->AddValue(sequenceLen);
    pUnit->AddValue(pSequence, sequenceLen);
    pCount->IncrementValue();
}
*/

10. MP4AddH264PictureParameterSet

作用:(pps)添加图片参数序列设置;

 

MP4AddH264PictureParameterSet(hMp4File,videoID,nalu.data,nalu.size);
/*源码
同样是填充mdia.minf.stbl.stsd.avc1.avcC相关信息;
 pFile->AddH264PictureParameterSet(trackId,pPict,pictLen);
->调用{
     MP4Atom *avcCAtom =
        FindAtom(MakeTrackName(trackId,
                               "mdia.minf.stbl.stsd.avc1.avcC"));
    MP4Integer8Property *pCount;
    MP4Integer16Property *pLength;
    MP4BytesProperty *pUnit;
    if ((avcCAtom->FindProperty("avcC.numOfPictureParameterSets",
                                (MP4Property **)&pCount) == false) ||
            (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetLength",
                                    (MP4Property **)&pLength) == false) ||
            (avcCAtom->FindProperty("avcC.pictureEntries.pictureParameterSetNALUnit",
                                    (MP4Property **)&pUnit) == false)) {
        log.errorf("%s: \"%s\": Could not find avcC picture table properties",
                   __FUNCTION__, GetFilename().c_str());
        return;
    }

    ...

    pLength->AddValue(pictLen);
    pUnit->AddValue(pPict, pictLen);
    pCount->IncrementValue();
}
*/

11. MP4WriteSample

作用:若是视频:写I帧和P帧nalu数据;

        若是音频:写ACC数据;(不是ACC需要转成ACC格式);一般用faac开源库;

/*
参数1:句柄
参数2:音/视 track id值
参数3: 数据
参数4:数据长度
参数5:duration值,一般填MP4_INVALID_DURATION;
参数6:渲染偏移量;只有MPEG需要此特性;不需要填0即可;
参数7:此sample的同步/随机访问标志。
*/
视频:
MP4WriteSample(hMp4File, videoID, frameBuf, frameLen, MP4_INVALID_DURATION, 0, 1);

音频:
MP4WriteSample(hMp4File, audioID, frameBuf, frameLen, MP4_INVALID_DURATION, 0, 1);

/*源码
((MP4File*)hFile)->WriteSample( trackId,pBytes,numBytes,duration,renderingOffset,
                                isSyncSample );
又调用->{
    m_pTracks[FindTrackIndex(trackId)]->WriteSample(
        pBytes, numBytes, duration, renderingOffset, isSyncSample );
    又调用->{ //src/mp4track.cpp
       // append sample bytes to chunk buffer
        if( m_sizeOfDataInChunkBuffer + numBytes > m_chunkBufferSize ) {
        m_pChunkBuffer = (uint8_t*)MP4Realloc(m_pChunkBuffer, m_chunkBufferSize + numBytes);
        if (m_pChunkBuffer == NULL) 
            return;	
        
            m_chunkBufferSize += numBytes;
        }

        memcpy(&m_pChunkBuffer[m_sizeOfDataInChunkBuffer], pBytes, numBytes);
        m_sizeOfDataInChunkBuffer += numBytes;
        m_chunkSamples++;
        m_chunkDuration += duration;

        UpdateSampleSizes(m_writeSampleId, numBytes);

        UpdateSampleTimes(duration);

        UpdateRenderingOffsets(m_writeSampleId, renderingOffset);

        UpdateSyncSamples(m_writeSampleId, isSyncSample);

        if (IsChunkFull(m_writeSampleId)) {
            WriteChunkBuffer();
            m_curMode = curMode;
        }

        UpdateDurations(duration);

        UpdateModificationTimes();

        m_writeSampleId++;
    }

    m_pModificationProperty->SetValue( MP4GetAbsTimestamp() );
}
*/

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天未及海宽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值