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() );
}
*/