void MP4DescriptorProperty::Generate() { // generate a default descriptor // if it is mandatory, and single if (m_mandatory && m_onlyOne) { MP4Descriptor* pDescriptor = AddDescriptor(m_tagsStart); pDescriptor->Generate(); } }
MP4Descriptor* MP4DescriptorProperty::AddDescriptor(u_int8_t tag) { // check that tag is in expected range ASSERT(tag >= m_tagsStart && tag <= m_tagsEnd); MP4Descriptor* pDescriptor = CreateDescriptor(tag); ASSERT(pDescriptor); m_pDescriptors.Add(pDescriptor); pDescriptor->SetParentAtom(m_pParentAtom); return pDescriptor; }
void MP4DescriptorProperty::Read(MP4File* pFile, u_int32_t index) { ASSERT(index == 0); if (m_implicit) { return; } u_int64_t start = pFile->GetPosition(); while (true) { // enforce size limitation if (m_sizeLimit && pFile->GetPosition() >= start + m_sizeLimit) { break; } u_int8_t tag; try { pFile->PeekBytes(&tag, 1); } catch (MP4Error* e) { if (pFile->GetPosition() >= pFile->GetSize()) { // EOF delete e; break; } throw e; } // check if tag is in desired range if (tag < m_tagsStart || tag > m_tagsEnd) { break; } MP4Descriptor* pDescriptor = AddDescriptor(tag); pDescriptor->Read(pFile); } // warnings if (m_mandatory && m_pDescriptors.Size() == 0) { VERBOSE_READ(pFile->GetVerbosity(), printf("Warning: Mandatory descriptor 0x%02x missing\n", m_tagsStart)); } else if (m_onlyOne && m_pDescriptors.Size() > 1) { VERBOSE_READ(pFile->GetVerbosity(), printf("Warning: Descriptor 0x%02x has more than one instance\n", m_tagsStart)); } }
MP4Descriptor* CreateOCIDescriptor(u_int8_t tag) { MP4Descriptor* pDescriptor = NULL; switch (tag) { case MP4ContentClassDescrTag: pDescriptor = new MP4ContentClassDescriptor(); break; case MP4KeywordDescrTag: pDescriptor = new MP4KeywordDescriptor(); break; case MP4RatingDescrTag: pDescriptor = new MP4RatingDescriptor(); break; case MP4LanguageDescrTag: pDescriptor = new MP4LanguageDescriptor(); break; case MP4ShortTextDescrTag: pDescriptor = new MP4ShortTextDescriptor(); break; case MP4ExpandedTextDescrTag: pDescriptor = new MP4ExpandedTextDescriptor(); break; case MP4ContentCreatorDescrTag: case MP4OCICreatorDescrTag: pDescriptor = new MP4CreatorDescriptor(tag); break; case MP4ContentCreationDescrTag: case MP4OCICreationDescrTag: pDescriptor = new MP4CreationDescriptor(tag); break; case MP4SmpteCameraDescrTag: pDescriptor = new MP4SmpteCameraDescriptor(); break; } if (pDescriptor == NULL) { if (tag >= MP4OCIDescrTagsStart && tag <= MP4OCIDescrTagsEnd) { pDescriptor = new MP4UnknownOCIDescriptor(); pDescriptor->SetTag(tag); } } return pDescriptor; }
MP4Descriptor* MP4QosQualifierProperty::CreateDescriptor(u_int8_t tag) { MP4Descriptor* pDescriptor = NULL; switch (tag) { #if 0 case MP4MaxDelayQosTag: pDescriptor = new MP4MaxDelayQosQualifier(); break; case MP4PrefMaxDelayQosTag: pDescriptor = new MP4PrefMaxDelayQosQualifier(); break; case MP4LossProbQosTag: pDescriptor = new MP4LossProbQosQualifier(); break; case MP4MaxGapLossQosTag: pDescriptor = new MP4MaxGapLossQosQualifier(); break; case MP4MaxAUSizeQosTag: pDescriptor = new MP4MaxAUSizeQosQualifier(); break; case MP4AvgAUSizeQosTag: pDescriptor = new MP4AvgAUSizeQosQualifier(); break; case MP4MaxAURateQosTag: pDescriptor = new MP4MaxAURateQosQualifier(); break; #else case MP4MaxDelayQosTag: case MP4PrefMaxDelayQosTag: case MP4LossProbQosTag: case MP4MaxGapLossQosTag: case MP4MaxAUSizeQosTag: case MP4AvgAUSizeQosTag: case MP4MaxAURateQosTag: pDescriptor = new MP4QosDescriptorBase(tag); break; #endif default: pDescriptor = new MP4UnknownQosQualifier(); pDescriptor->SetTag(tag); } return pDescriptor; }
MP4Descriptor* MP4QosQualifierProperty::CreateDescriptor(MP4Atom &parentAtom, uint8_t tag) { MP4Descriptor* pDescriptor = NULL; switch (tag) { case MP4MaxDelayQosTag: case MP4PrefMaxDelayQosTag: case MP4LossProbQosTag: case MP4MaxGapLossQosTag: case MP4MaxAUSizeQosTag: case MP4AvgAUSizeQosTag: case MP4MaxAURateQosTag: pDescriptor = new MP4QosDescriptorBase(parentAtom, tag); break; default: pDescriptor = new MP4UnknownQosQualifier(parentAtom); pDescriptor->SetTag(tag); } return pDescriptor; }
MP4Descriptor* MP4DescriptorProperty::CreateDescriptor(u_int8_t tag) { MP4Descriptor* pDescriptor = NULL; switch (tag) { case MP4ESDescrTag: pDescriptor = new MP4ESDescriptor(); break; case MP4DecConfigDescrTag: pDescriptor = new MP4DecConfigDescriptor(); break; case MP4DecSpecificDescrTag: pDescriptor = new MP4DecSpecificDescriptor(); break; case MP4SLConfigDescrTag: pDescriptor = new MP4SLConfigDescriptor(); break; case MP4ContentIdDescrTag: pDescriptor = new MP4ContentIdDescriptor(); break; case MP4SupplContentIdDescrTag: pDescriptor = new MP4SupplContentIdDescriptor(); break; case MP4IPIPtrDescrTag: pDescriptor = new MP4IPIPtrDescriptor(); break; case MP4IPMPPtrDescrTag: pDescriptor = new MP4IPMPPtrDescriptor(); break; case MP4IPMPDescrTag: pDescriptor = new MP4IPMPDescriptor(); break; case MP4QosDescrTag: pDescriptor = new MP4QosDescriptor(); break; case MP4RegistrationDescrTag: pDescriptor = new MP4RegistrationDescriptor(); break; case MP4ESIDIncDescrTag: pDescriptor = new MP4ESIDIncDescriptor(); break; case MP4ESIDRefDescrTag: pDescriptor = new MP4ESIDRefDescriptor(); break; case MP4IODescrTag: case MP4FileIODescrTag: pDescriptor = new MP4IODescriptor(); pDescriptor->SetTag(tag); break; case MP4ODescrTag: case MP4FileODescrTag: pDescriptor = new MP4ODescriptor(); pDescriptor->SetTag(tag); break; case MP4ExtProfileLevelDescrTag: pDescriptor = new MP4ExtProfileLevelDescriptor(); break; } if (pDescriptor == NULL) { if (tag >= MP4OCIDescrTagsStart && tag <= MP4OCIDescrTagsEnd) { pDescriptor = CreateOCIDescriptor(tag); } if (tag >= MP4ExtDescrTagsStart && tag <= MP4ExtDescrTagsEnd) { pDescriptor = new MP4ExtensionDescriptor(); pDescriptor->SetTag(tag); } } return pDescriptor; }
void MP4File::CreateIsmaODUpdateCommandForStream( MP4DescriptorProperty* pAudioEsdProperty, MP4DescriptorProperty* pVideoEsdProperty, u_int8_t** ppBytes, u_int64_t* pNumBytes) { MP4Descriptor* pAudioOd = NULL; MP4Descriptor* pVideoOd = NULL; MP4Descriptor* pCommand = CreateODCommand(MP4ODUpdateODCommandTag); pCommand->Generate(); for (u_int8_t i = 0; i < 2; i++) { u_int16_t odId; MP4DescriptorProperty* pEsdProperty = NULL; if (i == 0) { odId = 10; pEsdProperty = pAudioEsdProperty; } else { odId = 20; pEsdProperty = pVideoEsdProperty; } if (pEsdProperty == NULL) { continue; } MP4DescriptorProperty* pOdDescrProperty = (MP4DescriptorProperty*)(pCommand->GetProperty(0)); pOdDescrProperty->SetTags(MP4ODescrTag); MP4Descriptor* pOd = pOdDescrProperty->AddDescriptor(MP4ODescrTag); pOd->Generate(); if (i == 0) { pAudioOd = pOd; } else { pVideoOd = pOd; } MP4BitfieldProperty* pOdIdProperty = NULL; pOd->FindProperty("objectDescriptorId", (MP4Property**)&pOdIdProperty); pOdIdProperty->SetValue(odId); delete (MP4DescriptorProperty*)pOd->GetProperty(4); pOd->SetProperty(4, pEsdProperty); } // serialize OD command pCommand->WriteToMemory(this, ppBytes, pNumBytes); // detach from esd descriptor params if (pAudioOd) { pAudioOd->SetProperty(4, NULL); } if (pVideoOd) { pVideoOd->SetProperty(4, NULL); } // then destroy delete pCommand; }
void MP4File::CreateIsmaODUpdateCommandFromFileForFile( MP4TrackId odTrackId, MP4TrackId audioTrackId, MP4TrackId videoTrackId, u_int8_t** ppBytes, u_int64_t* pNumBytes) { MP4Descriptor* pCommand = CreateODCommand(MP4ODUpdateODCommandTag); pCommand->Generate(); for (u_int8_t i = 0; i < 2; i++) { MP4TrackId trackId; u_int16_t odId; if (i == 0) { trackId = audioTrackId; odId = 10; } else { trackId = videoTrackId; odId = 20; } if (trackId == MP4_INVALID_TRACK_ID) { continue; } MP4DescriptorProperty* pOdDescrProperty = (MP4DescriptorProperty*)(pCommand->GetProperty(0)); pOdDescrProperty->SetTags(MP4FileODescrTag); MP4Descriptor* pOd = pOdDescrProperty->AddDescriptor(MP4FileODescrTag); pOd->Generate(); MP4BitfieldProperty* pOdIdProperty = NULL; pOd->FindProperty("objectDescriptorId", (MP4Property**)&pOdIdProperty); pOdIdProperty->SetValue(odId); MP4DescriptorProperty* pEsIdsDescriptorProperty = NULL; pOd->FindProperty("esIds", (MP4Property**)&pEsIdsDescriptorProperty); ASSERT(pEsIdsDescriptorProperty); pEsIdsDescriptorProperty->SetTags(MP4ESIDRefDescrTag); MP4Descriptor *pRefDescriptor = pEsIdsDescriptorProperty->AddDescriptor(MP4ESIDRefDescrTag); pRefDescriptor->Generate(); MP4Integer16Property* pRefIndexProperty = NULL; pRefDescriptor->FindProperty("refIndex", (MP4Property**)&pRefIndexProperty); ASSERT(pRefIndexProperty); u_int32_t mpodIndex = FindTrackReference( MakeTrackName(odTrackId, "tref.mpod"), trackId); ASSERT(mpodIndex != 0); pRefIndexProperty->SetValue(mpodIndex); } pCommand->WriteToMemory(this, ppBytes, pNumBytes); delete pCommand; }
MP4Descriptor* MP4File::CreateESD( MP4DescriptorProperty* pEsProperty, u_int32_t esid, u_int8_t objectType, u_int8_t streamType, u_int32_t bufferSize, u_int32_t bitrate, u_int8_t* pConfig, u_int32_t configLength, char* url) { MP4IntegerProperty* pInt; MP4StringProperty* pString; MP4BytesProperty* pBytes; MP4BitfieldProperty* pBits; MP4Descriptor* pEsd = pEsProperty->AddDescriptor(MP4ESDescrTag); pEsd->Generate(); pEsd->FindProperty("ESID", (MP4Property**)&pInt); pInt->SetValue(esid); pEsd->FindProperty("decConfigDescr.objectTypeId", (MP4Property**)&pInt); pInt->SetValue(objectType); pEsd->FindProperty("decConfigDescr.streamType", (MP4Property**)&pInt); pInt->SetValue(streamType); pEsd->FindProperty("decConfigDescr.bufferSizeDB", (MP4Property**)&pInt); pInt->SetValue(bufferSize); pEsd->FindProperty("decConfigDescr.maxBitrate", (MP4Property**)&pInt); pInt->SetValue(bitrate); pEsd->FindProperty("decConfigDescr.avgBitrate", (MP4Property**)&pInt); pInt->SetValue(bitrate); MP4DescriptorProperty* pConfigDescrProperty; pEsd->FindProperty("decConfigDescr.decSpecificInfo", (MP4Property**)&pConfigDescrProperty); MP4Descriptor* pConfigDescr = pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag); pConfigDescr->Generate(); pConfigDescrProperty->FindProperty("decSpecificInfo[0].info", (MP4Property**)&pBytes); pBytes->SetValue(pConfig, configLength); pEsd->FindProperty("slConfigDescr.predefined", (MP4Property**)&pInt); // changed 12/5/02 from plugfest to value 0 pInt->SetValue(0); pEsd->FindProperty("slConfig.useAccessUnitEndFlag", (MP4Property **)&pBits); pBits->SetValue(1); if (url) { pEsd->FindProperty("URLFlag", (MP4Property**)&pInt); pInt->SetValue(1); pEsd->FindProperty("URL", (MP4Property**)&pString); pString->SetValue(url); } return pEsd; }
void MP4File::CreateIsmaIodFromParams( u_int8_t videoProfile, u_int32_t videoBitrate, u_int8_t* videoConfig, u_int32_t videoConfigLength, u_int8_t audioProfile, u_int32_t audioBitrate, u_int8_t* audioConfig, u_int32_t audioConfigLength, u_int8_t** ppIodBytes, u_int64_t* pIodNumBytes) { MP4IntegerProperty* pInt; u_int8_t* pBytes = NULL; u_int64_t numBytes; // Create the IOD MP4Descriptor* pIod = new MP4IODescriptor(); pIod->SetTag(MP4IODescrTag); pIod->Generate(); // Set audio and video profileLevels pIod->FindProperty("audioProfileLevelId", (MP4Property**)&pInt); pInt->SetValue(audioProfile); pIod->FindProperty("visualProfileLevelId", (MP4Property**)&pInt); pInt->SetValue(videoProfile); // Mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag MP4DescriptorProperty* pEsProperty; pIod->FindProperty("esIds", (MP4Property**)&pEsProperty); pEsProperty->SetTags(MP4ESDescrTag); // Add ES Descriptors // Scene CreateIsmaSceneCommand( (audioProfile != 0xFF), (videoProfile != 0xFF), &pBytes, &numBytes); VERBOSE_ISMA(GetVerbosity(), printf("Scene data =\n"); MP4HexDump(pBytes, numBytes)); char* sceneCmdBase64 = MP4ToBase64(pBytes, numBytes); char* urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64); sprintf(urlBuf, "data:application/mpeg4-bifs-au;base64,%s", sceneCmdBase64); VERBOSE_ISMA(GetVerbosity(), printf("Scene data URL = \042%s\042\n", urlBuf)); /* MP4Descriptor* pSceneEsd = */ CreateESD( pEsProperty, 201, // esid MP4SystemsV2ObjectType, MP4SceneDescriptionStreamType, numBytes, // bufferSize numBytes * 8, // bitrate BifsV2Config, sizeof(BifsV2Config), urlBuf); MP4Free(sceneCmdBase64); sceneCmdBase64 = NULL; MP4Free(urlBuf); urlBuf = NULL; MP4Free(pBytes); pBytes = NULL; // OD // Video MP4DescriptorProperty* pVideoEsdProperty = new MP4DescriptorProperty(); pVideoEsdProperty->SetTags(MP4ESDescrTag); /* MP4Descriptor* pVideoEsd = */ CreateESD( pVideoEsdProperty, 20, // esid MP4_MPEG4_VIDEO_TYPE, MP4VisualStreamType, videoBitrate / 8, // bufferSize videoBitrate, videoConfig, videoConfigLength, NULL); // Audio MP4DescriptorProperty* pAudioEsdProperty = new MP4DescriptorProperty(); pAudioEsdProperty->SetTags(MP4ESDescrTag); /* MP4Descriptor* pAudioEsd = */ CreateESD( pAudioEsdProperty, 10, // esid MP4_MPEG4_AUDIO_TYPE, MP4AudioStreamType, audioBitrate / 8, // bufferSize audioBitrate, audioConfig, audioConfigLength, NULL); CreateIsmaODUpdateCommandForStream( pAudioEsdProperty, pVideoEsdProperty, &pBytes, &numBytes); // cleanup temporary descriptor properties delete pAudioEsdProperty; delete pVideoEsdProperty; VERBOSE_ISMA(GetVerbosity(), printf("OD data = %llu bytes\n", numBytes); MP4HexDump(pBytes, numBytes)); char* odCmdBase64 = MP4ToBase64(pBytes, numBytes); urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64); sprintf(urlBuf, "data:application/mpeg4-od-au;base64,%s", odCmdBase64); VERBOSE_ISMA(GetVerbosity(), printf("OD data URL = \042%s\042\n", urlBuf)); /* MP4Descriptor* pOdEsd = */ CreateESD( pEsProperty, 101, MP4SystemsV1ObjectType, MP4ObjectDescriptionStreamType, numBytes, // bufferSize numBytes * 8, // bitrate NULL, // config 0, // configLength urlBuf); MP4Free(odCmdBase64); odCmdBase64 = NULL; MP4Free(pBytes); pBytes = NULL; MP4Free(urlBuf); urlBuf = NULL; // finally get the whole thing written to a memory pIod->WriteToMemory(this, ppIodBytes, pIodNumBytes); delete pIod; VERBOSE_ISMA(GetVerbosity(), printf("IOD data =\n"); MP4HexDump(*ppIodBytes, *pIodNumBytes)); }
void MP4File::CreateIsmaIodFromFile( MP4TrackId odTrackId, MP4TrackId sceneTrackId, MP4TrackId audioTrackId, MP4TrackId videoTrackId, u_int8_t** ppBytes, u_int64_t* pNumBytes) { MP4Descriptor* pIod = new MP4IODescriptor(); pIod->SetTag(MP4IODescrTag); pIod->Generate(); MP4Atom* pIodsAtom = FindAtom("moov.iods"); ASSERT(pIodsAtom); MP4DescriptorProperty* pSrcIod = (MP4DescriptorProperty*)pIodsAtom->GetProperty(2); CloneIntegerProperty(pIod, pSrcIod, "objectDescriptorId"); CloneIntegerProperty(pIod, pSrcIod, "ODProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "sceneProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "audioProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "visualProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "graphicsProfileLevelId"); // mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag MP4DescriptorProperty* pEsProperty; pIod->FindProperty("esIds", (MP4Property**)&pEsProperty); pEsProperty->SetTags(MP4ESDescrTag); MP4IntegerProperty* pSetProperty; MP4IntegerProperty* pSceneESID; MP4IntegerProperty* pOdESID; // OD MP4Descriptor* pOdEsd = pEsProperty->AddDescriptor(MP4ESDescrTag); pOdEsd->Generate(); pOdEsd->FindProperty("ESID", (MP4Property**)&pOdESID); // we set the OD ESID to a non-zero unique value pOdESID->SetValue(m_odTrackId); pOdEsd->FindProperty("URLFlag", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); u_int8_t* pBytes; u_int64_t numBytes; CreateIsmaODUpdateCommandFromFileForStream( audioTrackId, videoTrackId, &pBytes, &numBytes); VERBOSE_ISMA(GetVerbosity(), printf("OD data =\n"); MP4HexDump(pBytes, numBytes)); char* odCmdBase64 = MP4ToBase64(pBytes, numBytes); char* urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64); sprintf(urlBuf, "data:application/mpeg4-od-au;base64,%s", odCmdBase64); MP4StringProperty* pUrlProperty; pOdEsd->FindProperty("URL", (MP4Property**)&pUrlProperty); pUrlProperty->SetValue(urlBuf); VERBOSE_ISMA(GetVerbosity(), printf("OD data URL = \042%s\042\n", urlBuf)); MP4Free(odCmdBase64); odCmdBase64 = NULL; MP4Free(pBytes); pBytes = NULL; MP4Free(urlBuf); urlBuf = NULL; MP4DescriptorProperty* pSrcDcd = NULL; // HACK temporarily point to scene decoder config FindProperty(MakeTrackName(odTrackId, "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"), (MP4Property**)&pSrcDcd); ASSERT(pSrcDcd); MP4Property* pOrgOdEsdProperty = pOdEsd->GetProperty(8); pOdEsd->SetProperty(8, pSrcDcd); // bufferSizeDB needs to be set appropriately MP4BitfieldProperty* pBufferSizeProperty = NULL; pOdEsd->FindProperty("decConfigDescr.bufferSizeDB", (MP4Property**)&pBufferSizeProperty); ASSERT(pBufferSizeProperty); pBufferSizeProperty->SetValue(numBytes); // SL config needs to change from 2 (file) to 1 (null) pOdEsd->FindProperty("slConfigDescr.predefined", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); // Scene MP4Descriptor* pSceneEsd = pEsProperty->AddDescriptor(MP4ESDescrTag); pSceneEsd->Generate(); pSceneEsd->FindProperty("ESID", (MP4Property**)&pSceneESID); // we set the Scene ESID to a non-zero unique value pSceneESID->SetValue(sceneTrackId); pSceneEsd->FindProperty("URLFlag", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); CreateIsmaSceneCommand( MP4_IS_VALID_TRACK_ID(audioTrackId), MP4_IS_VALID_TRACK_ID(videoTrackId), &pBytes, &numBytes); VERBOSE_ISMA(GetVerbosity(), printf("Scene data =\n"); MP4HexDump(pBytes, numBytes)); char *sceneCmdBase64 = MP4ToBase64(pBytes, numBytes); urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64); sprintf(urlBuf, "data:application/mpeg4-bifs-au;base64,%s", sceneCmdBase64); pSceneEsd->FindProperty("URL", (MP4Property**)&pUrlProperty); pUrlProperty->SetValue(urlBuf); VERBOSE_ISMA(GetVerbosity(), printf("Scene data URL = \042%s\042\n", urlBuf)); MP4Free(sceneCmdBase64); sceneCmdBase64 = NULL; MP4Free(urlBuf); urlBuf = NULL; MP4Free(pBytes); pBytes = NULL; // HACK temporarily point to scene decoder config FindProperty(MakeTrackName(sceneTrackId, "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"), (MP4Property**)&pSrcDcd); ASSERT(pSrcDcd); MP4Property* pOrgSceneEsdProperty = pSceneEsd->GetProperty(8); pSceneEsd->SetProperty(8, pSrcDcd); // bufferSizeDB needs to be set pBufferSizeProperty = NULL; pSceneEsd->FindProperty("decConfigDescr.bufferSizeDB", (MP4Property**)&pBufferSizeProperty); ASSERT(pBufferSizeProperty); pBufferSizeProperty->SetValue(numBytes); // SL config needs to change from 2 (file) to 1 (null) pSceneEsd->FindProperty("slConfigDescr.predefined", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); // finally get the whole thing written to a memory pIod->WriteToMemory(this, ppBytes, pNumBytes); // now carefully replace esd properties before destroying pOdEsd->SetProperty(8, pOrgOdEsdProperty); pSceneEsd->SetProperty(8, pOrgSceneEsdProperty); pSceneESID->SetValue(0); // restore 0 value pOdESID->SetValue(0); delete pIod; VERBOSE_ISMA(GetVerbosity(), printf("IOD data =\n"); MP4HexDump(*ppBytes, *pNumBytes)); }