📄 mp4file.cpp
字号:
MP4TrackId MP4File::AddVideoTrack(
u_int32_t timeScale,
MP4Duration sampleDuration,
u_int16_t width,
u_int16_t height,
u_int8_t videoType)
{
MP4TrackId trackId = AddTrack(MP4_VIDEO_TRACK_TYPE, timeScale);
AddTrackToOd(trackId);
SetTrackFloatProperty(trackId, "tkhd.width", width);
SetTrackFloatProperty(trackId, "tkhd.height", height);
InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "vmhd", 0);
AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4v");
// 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 mp4v atom
MP4Integer32Property* pStsdCountProperty;
FindIntegerProperty(
MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
(MP4Property**)&pStsdCountProperty);
pStsdCountProperty->IncrementValue();
SetTrackIntegerProperty(trackId,
"mdia.minf.stbl.stsd.mp4v.width", width);
SetTrackIntegerProperty(trackId,
"mdia.minf.stbl.stsd.mp4v.height", height);
SetTrackIntegerProperty(trackId,
"mdia.minf.stbl.stsd.mp4v.esds.ESID", trackId);
SetTrackIntegerProperty(trackId,
"mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.objectTypeId",
videoType);
SetTrackIntegerProperty(trackId,
"mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.streamType",
MP4VisualStreamType);
SetTrackIntegerProperty(trackId,
"mdia.minf.stbl.stsz.sampleSize", sampleDuration);
m_pTracks[FindTrackIndex(trackId)]->
SetFixedSampleDuration(sampleDuration);
return trackId;
}
MP4TrackId MP4File::AddHintTrack(MP4TrackId refTrackId)
{
// validate reference track id
FindTrackIndex(refTrackId);
MP4TrackId trackId =
AddTrack(MP4_HINT_TRACK_TYPE, GetTrackTimeScale(refTrackId));
InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "hmhd", 0);
AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "rtp ");
// 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 rtp atom
MP4Integer32Property* pStsdCountProperty;
FindIntegerProperty(
MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
(MP4Property**)&pStsdCountProperty);
pStsdCountProperty->IncrementValue();
SetTrackIntegerProperty(trackId,
"mdia.minf.stbl.stsd.rtp .tims.timeScale",
GetTrackTimeScale(trackId));
AddDescendantAtoms(MakeTrackName(trackId, NULL), "tref.hint");
AddTrackReference(MakeTrackName(trackId, "tref.hint"), refTrackId);
AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hnti.sdp ");
AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hinf");
return trackId;
}
void MP4File::DeleteTrack(MP4TrackId trackId)
{
ProtectWriteOperation("MP4DeleteTrack");
u_int32_t trakIndex = FindTrakAtomIndex(trackId);
u_int16_t trackIndex = FindTrackIndex(trackId);
MP4Track* pTrack = m_pTracks[trackIndex];
MP4Atom* pTrakAtom = pTrack->GetTrakAtom();
ASSERT(pTrakAtom);
MP4Atom* pMoovAtom = FindAtom("moov");
ASSERT(pMoovAtom);
RemoveTrackFromIod(trackId);
RemoveTrackFromOd(trackId);
if (trackId == m_odTrackId) {
m_odTrackId = 0;
}
pMoovAtom->DeleteChildAtom(pTrakAtom);
m_trakIds.Delete(trakIndex);
m_pTracks.Delete(trackIndex);
delete pTrack;
delete pTrakAtom;
}
u_int32_t MP4File::GetNumberOfTracks(const char* type, u_int8_t subType)
{
if (type == NULL) {
return m_pTracks.Size();
}
u_int16_t typeSeen = 0;
const char* normType = MP4Track::NormalizeTrackType(type);
for (u_int16_t i = 0; i < m_pTracks.Size(); i++) {
if (!strcmp(normType, m_pTracks[i]->GetType())) {
if (subType) {
if (normType == MP4_AUDIO_TRACK_TYPE) {
if (subType != GetTrackAudioType(m_pTracks[i]->GetId())) {
continue;
}
} else if (normType == MP4_VIDEO_TRACK_TYPE) {
if (subType != GetTrackVideoType(m_pTracks[i]->GetId())) {
continue;
}
}
// else unknown subtype, ignore it
}
typeSeen++;
}
}
return typeSeen;
}
MP4TrackId MP4File::AllocTrackId()
{
MP4TrackId trackId =
GetIntegerProperty("moov.mvhd.nextTrackId");
if (trackId <= 0xFFFF) {
// check that nextTrackid is correct
try {
FindTrackIndex(trackId);
// ERROR, this trackId is in use
}
catch (MP4Error* e) {
// OK, this trackId is not in use, proceed
delete e;
SetIntegerProperty("moov.mvhd.nextTrackId", trackId + 1);
return trackId;
}
}
// we need to search for a track id
for (trackId = 1; trackId <= 0xFFFF; trackId++) {
try {
FindTrackIndex(trackId);
// KEEP LOOKING, this trackId is in use
}
catch (MP4Error* e) {
// OK, this trackId is not in use, proceed
delete e;
return trackId;
}
}
// extreme case where mp4 file has 2^16 tracks in it
throw new MP4Error("too many exising tracks", "AddTrack");
return MP4_INVALID_TRACK_ID; // to keep MSVC happy
}
MP4TrackId MP4File::FindTrackId(
u_int16_t trackIndex, const char* type, u_int8_t subType)
{
if (type == NULL) {
return m_pTracks[trackIndex]->GetId();
}
u_int16_t typeSeen = 0;
const char* normType = MP4Track::NormalizeTrackType(type);
for (u_int16_t i = 0; i < m_pTracks.Size(); i++) {
if (!strcmp(normType, m_pTracks[i]->GetType())) {
if (subType) {
if (normType == MP4_AUDIO_TRACK_TYPE) {
if (subType != GetTrackAudioType(m_pTracks[i]->GetId())) {
continue;
}
} else if (normType == MP4_VIDEO_TRACK_TYPE) {
if (subType != GetTrackVideoType(m_pTracks[i]->GetId())) {
continue;
}
}
// else unknown subtype, ignore it
}
if (trackIndex == typeSeen) {
return m_pTracks[i]->GetId();
}
typeSeen++;
}
}
throw new MP4Error("Track index doesn't exist - track %d type %s",
"FindTrackId",
trackIndex, type);
return MP4_INVALID_TRACK_ID; // satisfy MS compiler
}
u_int16_t MP4File::FindTrackIndex(MP4TrackId trackId)
{
for (u_int16_t i = 0; i < m_pTracks.Size(); i++) {
if (m_pTracks[i]->GetId() == trackId) {
return i;
}
}
throw new MP4Error("Track id %d doesn't exist", "FindTrackIndex", trackId);
return (u_int16_t)-1; // satisfy MS compiler
}
u_int16_t MP4File::FindTrakAtomIndex(MP4TrackId trackId)
{
if (trackId) {
for (u_int32_t i = 0; i < m_trakIds.Size(); i++) {
if (m_trakIds[i] == trackId) {
return i;
}
}
}
throw new MP4Error("Track id %d doesn't exist", "FindTrakAtomIndex",
trackId);
return (u_int16_t)-1; // satisfy MS compiler
}
u_int32_t MP4File::GetSampleSize(MP4TrackId trackId, MP4SampleId sampleId)
{
return m_pTracks[FindTrackIndex(trackId)]->GetSampleSize(sampleId);
}
u_int32_t MP4File::GetTrackMaxSampleSize(MP4TrackId trackId)
{
return m_pTracks[FindTrackIndex(trackId)]->GetMaxSampleSize();
}
MP4SampleId MP4File::GetSampleIdFromTime(MP4TrackId trackId,
MP4Timestamp when, bool wantSyncSample)
{
return m_pTracks[FindTrackIndex(trackId)]->
GetSampleIdFromTime(when, wantSyncSample);
}
MP4Timestamp MP4File::GetSampleTime(
MP4TrackId trackId, MP4SampleId sampleId)
{
MP4Timestamp timestamp;
m_pTracks[FindTrackIndex(trackId)]->
GetSampleTimes(sampleId, ×tamp, NULL);
return timestamp;
}
MP4Duration MP4File::GetSampleDuration(
MP4TrackId trackId, MP4SampleId sampleId)
{
MP4Duration duration;
m_pTracks[FindTrackIndex(trackId)]->
GetSampleTimes(sampleId, NULL, &duration);
return duration;
}
MP4Duration MP4File::GetSampleRenderingOffset(
MP4TrackId trackId, MP4SampleId sampleId)
{
return m_pTracks[FindTrackIndex(trackId)]->
GetSampleRenderingOffset(sampleId);
}
bool MP4File::GetSampleSync(MP4TrackId trackId, MP4SampleId sampleId)
{
return m_pTracks[FindTrackIndex(trackId)]->IsSyncSample(sampleId);
}
void MP4File::ReadSample(MP4TrackId trackId, MP4SampleId sampleId,
u_int8_t** ppBytes, u_int32_t* pNumBytes,
MP4Timestamp* pStartTime, MP4Duration* pDuration,
MP4Duration* pRenderingOffset, bool* pIsSyncSample)
{
m_pTracks[FindTrackIndex(trackId)]->
ReadSample(sampleId, ppBytes, pNumBytes,
pStartTime, pDuration, pRenderingOffset, pIsSyncSample);
}
void MP4File::WriteSample(MP4TrackId trackId,
u_int8_t* pBytes, u_int32_t numBytes,
MP4Duration duration, MP4Duration renderingOffset, bool isSyncSample)
{
ProtectWriteOperation("MP4WriteSample");
m_pTracks[FindTrackIndex(trackId)]->
WriteSample(pBytes, numBytes, duration, renderingOffset, isSyncSample);
m_pModificationProperty->SetValue(MP4GetAbsTimestamp());
}
void MP4File::SetSampleRenderingOffset(MP4TrackId trackId,
MP4SampleId sampleId, MP4Duration renderingOffset)
{
ProtectWriteOperation("MP4SetSampleRenderingOffset");
m_pTracks[FindTrackIndex(trackId)]->
SetSampleRenderingOffset(sampleId, renderingOffset);
m_pModificationProperty->SetValue(MP4GetAbsTimestamp());
}
char* MP4File::MakeTrackName(MP4TrackId trackId, const char* name)
{
u_int16_t trakIndex = FindTrakAtomIndex(trackId);
static char trakName[1024];
if (name == NULL || name[0] == '\0') {
snprintf(trakName, sizeof(trakName),
"moov.trak[%u]", trakIndex);
} else {
snprintf(trakName, sizeof(trakName),
"moov.trak[%u].%s", trakIndex, name);
}
return trakName;
}
u_int64_t MP4File::GetTrackIntegerProperty(MP4TrackId trackId, const char* name)
{
return GetIntegerProperty(MakeTrackName(trackId, name));
}
void MP4File::SetTrackIntegerProperty(MP4TrackId trackId, const char* name,
int64_t value)
{
SetIntegerProperty(MakeTrackName(trackId, name), value);
}
float MP4File::GetTrackFloatProperty(MP4TrackId trackId, const char* name)
{
return GetFloatProperty(MakeTrackName(trackId, name));
}
void MP4File::SetTrackFloatProperty(MP4TrackId trackId, const char* name,
float value)
{
SetFloatProperty(MakeTrackName(trackId, name), value);
}
const char* MP4File::GetTrackStringProperty(MP4TrackId trackId, const char* name)
{
return GetStringProperty(MakeTrackName(trackId, name));
}
void MP4File::SetTrackStringProperty(MP4TrackId trackId, const char* name,
const char* value)
{
SetStringProperty(MakeTrackName(trackId, name), value);
}
void MP4File::GetTrackBytesProperty(MP4TrackId trackId, const char* name,
u_int8_t** ppValue, u_int32_t* pValueSize)
{
GetBytesProperty(MakeTrackName(trackId, name), ppValue, pValueSize);
}
void MP4File::SetTrackBytesProperty(MP4TrackId trackId, const char* name,
const u_int8_t* pValue, u_int32_t valueSize)
{
SetBytesProperty(MakeTrackName(trackId, name), pValue, valueSize);
}
// file level convenience functions
MP4Duration MP4File::GetDuration()
{
return m_pDurationProperty->GetValue();
}
void MP4File::SetDuration(MP4Duration value)
{
m_pDurationProperty->SetValue(value);
}
u_int32_t MP4File::GetTimeScale()
{
return m_pTimeScaleProperty->GetValue();
}
void MP4File::SetTimeScale(u_int32_t value)
{
if (value == 0) {
throw new MP4Error("invalid value", "SetTimeScale");
}
m_pTimeScaleProperty->SetValue(value);
}
u_int8_t MP4File::GetODProfileLevel()
{
return GetIntegerProperty("moov.iods.ODProfileLevelId");
}
void MP4File::SetODProfileLevel(u_int8_t value)
{
SetIntegerProperty("moov.iods.ODProfileLevelId", value);
}
u_int8_t MP4File::GetSceneProfileLevel()
{
return GetIntegerProperty("moov.iods.sceneProfileLevelId");
}
void MP4File::SetSceneProfileLevel(u_int8_t value)
{
SetIntegerProperty("moov.iods.sceneProfileLevelId", value);
}
u_int8_t MP4File::GetVideoProfileLevel()
{
return GetIntegerProperty("moov.iods.visualProfileLevelId");
}
void MP4File::SetVideoProfileLevel(u_int8_t value)
{
SetIntegerProperty("moov.iods.visualProfileLevelId", value);
}
u_int8_t MP4File::GetAudioProfileLevel()
{
return GetIntegerProperty("moov.iods.audioProfileLevelId");
}
void MP4File::SetAudioProfileLevel(u_int8_t value)
{
SetIntegerProperty("moov.iods.audioProfileLevelId", value);
}
u_int8_t MP4File::GetGraphicsProfileLevel()
{
return GetIntegerProperty("moov.iods.graphicsProfileLevelId");
}
void MP4File::SetGraphicsProfileLevel(u_int8_t value)
{
SetIntegerProperty("moov.iods.graphicsProfileLevelId", value);
}
const char* MP4File::GetSessionSdp()
{
return GetStringProperty("moov.udta.hnti.rtp .sdpText");
}
void MP4File::SetSessionSdp(const char* sdpString)
{
AddDescendantAtoms("moov", "udta.hnti.rtp ");
SetStringProperty("moov.udta.hnti.rtp .sdpText", sdpString);
}
void MP4File::AppendSessionSdp(const char* sdpFragment)
{
const char* oldSdpString = NULL;
try {
oldSdpString = GetSessionSdp();
}
catch (MP4Error* e) {
delete e;
SetSessionSdp(sdpFragment);
return;
}
char* newSdpString =
(char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1);
strcpy(newSdpString, oldSdpString);
strcat(newSdpString, sdpFragment);
SetSessionSdp(newSdpString);
MP4Free(newSdpString);
}
// track level convenience functions
MP4SampleId MP4File::GetTrackNumberOfSamples(MP4TrackId trackId)
{
return m_pTracks[FindTrackIndex(trackId)]->GetNumberOfSamples();
}
const char* MP4File::GetTrackType(MP4TrackId trackId)
{
return m_pTracks[FindTrackIndex(trackId)]->GetType();
}
u_int32_t MP4File::GetTrackTimeScale(MP4TrackId trackId)
{
return m_pTracks[FindTrackIndex(trackId)]->GetTimeScale();
}
void MP4File::SetTrackTimeScale(MP4TrackId trackId, u_int32_t value)
{
if (value == 0) {
throw new MP4Error("invalid value", "SetTrackTimeScale");
}
SetTrackIntegerProperty(trackId, "mdia.mdhd.timeScale", value);
}
MP4Duration MP4File::GetTrackDuration(MP4TrackId trackId)
{
return GetTrackIntegerProperty(trackId, "mdia.mdhd.duration");
}
u_int8_t MP4File::GetTrackAudioType(MP4TrackId trackId)
{
return GetTrackIntegerProperty(trackId,
"mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId");
}
u_int8_t MP4File::GetTrackAudioMpeg4Type(MP4TrackId trackId)
{
// verify that track is an MPEG-4 audio track
if (GetTrackAudioType(trackId) != MP4_MPEG4_AUDIO_TYPE) {
return MP4_MPEG4_INVALID_AUDIO_TYPE;
}
u_int8_t* pEsConfig = NULL;
u_int32_t esConfigSize;
// The Mpeg4 audio type (AAC, CELP, HXVC, ...)
// is the first 5 bits of the ES configuration
GetTrackESConfiguration(trackId, &pEsConfig, &esConfigSize);
if (esConfigSize < 1) {
return MP4_MPEG4_INVALID_AUDIO_TYPE;
}
u_int8_t mpeg4Type = (pEsConfig[0] >> 3);
free(pEsConfig);
return mpeg4Type;
}
u_int8_t MP4File::GetTrackVideoType(MP4TrackId trackId)
{
return GetTrackIntegerProperty(trackId,
"mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.objectTypeId");
}
MP4Duration MP4File::GetTrackFixedSampleDuration(MP4TrackId trackId)
{
return m_pTracks[FindTrackIndex(trackId)]->GetFixedSampleDuration();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -