diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/libmp4v2/isma.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/external_dependencies/libmp4v2/isma.cpp')
-rw-r--r-- | Src/external_dependencies/libmp4v2/isma.cpp | 942 |
1 files changed, 942 insertions, 0 deletions
diff --git a/Src/external_dependencies/libmp4v2/isma.cpp b/Src/external_dependencies/libmp4v2/isma.cpp new file mode 100644 index 00000000..b366a408 --- /dev/null +++ b/Src/external_dependencies/libmp4v2/isma.cpp @@ -0,0 +1,942 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is MPEG4IP. + * + * The Initial Developer of the Original Code is Cisco Systems Inc. + * Portions created by Cisco Systems Inc. are + * Copyright (C) Cisco Systems Inc. 2001 - 2004. All Rights Reserved. + * + * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, + * and was contributed by Ximpo Group Ltd. + * + * Portions created by Ximpo Group Ltd. are + * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. + * + * Contributor(s): + * Dave Mackie dmackie@cisco.com + * Alix Marchandise-Franquet alix@cisco.com + * Ximpo Group Ltd. mp4v2@ximpo.com + */ + +#include "mp4common.h" + +static const u_int8_t BifsV2Config[3] = { + 0x00, 0x00, 0x60 // IsCommandStream = 1, PixelMetric = 1 +}; + +void MP4File::MakeIsmaCompliant(bool addIsmaComplianceSdp) +{ + ProtectWriteOperation("MP4MakeIsmaCompliant"); + + if (m_useIsma) { + // already done + return; + } + + // find first audio and/or video tracks + + MP4TrackId audioTrackId = MP4_INVALID_TRACK_ID; + try { + audioTrackId = FindTrackId(0, MP4_AUDIO_TRACK_TYPE); + } + catch (MP4Error* e) { + delete e; + } + + MP4TrackId videoTrackId = MP4_INVALID_TRACK_ID; + try { + videoTrackId = FindTrackId(0, MP4_VIDEO_TRACK_TYPE); + } + catch (MP4Error* e) { + delete e; + } + if (audioTrackId == MP4_INVALID_TRACK_ID && + videoTrackId == MP4_INVALID_TRACK_ID) return; + + const char *audio_media_data_name, *video_media_data_name; + uint8_t videoProfile = 0xff; + if (audioTrackId != MP4_INVALID_TRACK_ID) { + audio_media_data_name = MP4GetTrackMediaDataName(this, audioTrackId); + if (!(ATOMID(audio_media_data_name) == ATOMID("mp4a") || + ATOMID(audio_media_data_name) == ATOMID("enca"))) { + VERBOSE_ERROR(m_verbosity, + printf("MakeIsmaCompliant:can't make ISMA compliant when file contains an %s track\n", audio_media_data_name); + ); + return; + } + } + // + // Note - might have to check for avc1 here... + if (videoTrackId != MP4_INVALID_TRACK_ID) { + video_media_data_name = MP4GetTrackMediaDataName(this, videoTrackId); + if (!(ATOMID(video_media_data_name) == ATOMID("mp4v") || + ATOMID(video_media_data_name) == ATOMID("encv"))) { + VERBOSE_ERROR(m_verbosity, + printf("MakeIsmaCompliant:can't make ISMA compliant when file contains an %s track\n", video_media_data_name); + ); + return; + } + uint32_t verb = GetVerbosity(); + SetVerbosity(verb & ~MP4_DETAILS_ERROR); + videoProfile = MP4GetVideoProfileLevel(this, videoTrackId); + SetVerbosity(verb); + } + + m_useIsma = true; + + u_int64_t fileMsDuration = 0; + fileMsDuration = + ConvertFromMovieDuration(GetDuration(), MP4_MSECS_TIME_SCALE); + + // delete any existing OD track + if (m_odTrackId != MP4_INVALID_TRACK_ID) { + DeleteTrack(m_odTrackId); + } + + if (m_pRootAtom->FindAtomMP4("moov.iods") == NULL) { + (void)AddChildAtom("moov", "iods"); + } + (void)AddODTrack(); + SetODProfileLevel(0xFF); + + if (audioTrackId != MP4_INVALID_TRACK_ID) { + AddTrackToOd(audioTrackId); + MP4SetAudioProfileLevel(this, 0xf); + } + if (videoTrackId != MP4_INVALID_TRACK_ID) { + AddTrackToOd(videoTrackId); + MP4SetVideoProfileLevel(this, videoProfile); + } + + // delete any existing scene track + MP4TrackId sceneTrackId = MP4_INVALID_TRACK_ID; + try { + sceneTrackId = FindTrackId(0, MP4_SCENE_TRACK_TYPE); + } + catch (MP4Error *e) { + delete e; + } + if (sceneTrackId != MP4_INVALID_TRACK_ID) { + DeleteTrack(sceneTrackId); + } + + // add scene track + sceneTrackId = AddSceneTrack(); + SetSceneProfileLevel(0xFF); + SetGraphicsProfileLevel(0xFF); + SetTrackIntegerProperty(sceneTrackId, + "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId", + MP4SystemsV2ObjectType); + + SetTrackESConfiguration(sceneTrackId, + BifsV2Config, sizeof(BifsV2Config)); + + u_int8_t* pBytes = NULL; + u_int64_t numBytes = 0; + + // write OD Update Command + CreateIsmaODUpdateCommandFromFileForFile( + m_odTrackId, + audioTrackId, + videoTrackId, + &pBytes, + &numBytes); + + WriteSample(m_odTrackId, pBytes, numBytes, fileMsDuration); + + MP4Free(pBytes); + pBytes = NULL; + + // write BIFS Scene Replace Command + CreateIsmaSceneCommand( + MP4_IS_VALID_TRACK_ID(audioTrackId), + MP4_IS_VALID_TRACK_ID(videoTrackId), + &pBytes, + &numBytes); + + WriteSample(sceneTrackId, pBytes, numBytes, fileMsDuration); + + MP4Free(pBytes); + pBytes = NULL; + + // add session level sdp + CreateIsmaIodFromFile( + m_odTrackId, + sceneTrackId, + audioTrackId, + videoTrackId, + &pBytes, + &numBytes); + + char* iodBase64 = MP4ToBase64(pBytes, numBytes); + + uint sdpBufLen = (uint)strlen(iodBase64) + 256; + uint used; + char* sdpBuf = (char*)MP4Calloc(sdpBufLen); + + if (addIsmaComplianceSdp) { + strncpy(sdpBuf, "a=isma-compliance:1,1.0,1\015\012", sdpBufLen); + } + + used = (uint)strlen(sdpBuf); + sdpBufLen -= used; + snprintf(&sdpBuf[used], sdpBufLen, + "a=mpeg4-iod: \042data:application/mpeg4-iod;base64,%s\042\015\012", + iodBase64); + + SetSessionSdp(sdpBuf); + + VERBOSE_ISMA(GetVerbosity(), + printf("IOD SDP = %s\n", sdpBuf)); + + MP4Free(iodBase64); + iodBase64 = NULL; + MP4Free(pBytes); + pBytes = NULL; + MP4Free(sdpBuf); + sdpBuf = NULL; +} + +static void CloneIntegerProperty( + MP4Descriptor* pDest, + MP4DescriptorProperty* pSrc, + const char* name) +{ + MP4IntegerProperty* pGetProperty; + MP4IntegerProperty* pSetProperty; + + if (!pSrc->FindProperty(name, (MP4Property**)&pGetProperty)) return; + if (!pDest->FindProperty(name, (MP4Property**)&pSetProperty)) return; + pSetProperty->SetValue(pGetProperty->GetValue()); +} + +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 = FindAtomMP4File("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; + if (!pIod->FindProperty("esIds", (MP4Property**)&pEsProperty)) return; + pEsProperty->SetTags(MP4ESDescrTag); + + MP4IntegerProperty* pSetProperty; + MP4IntegerProperty* pSceneESID; + MP4IntegerProperty* pOdESID; + + // OD + MP4Descriptor* pOdEsd = + pEsProperty->AddDescriptor(MP4ESDescrTag); + pOdEsd->Generate(); + + if (!pOdEsd->FindProperty("ESID", (MP4Property**)&pOdESID)) return; + + // we set the OD ESID to a non-zero unique value + pOdESID->SetValue(m_odTrackId); + + if (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); + + uint urlBufLen = (uint)strlen(odCmdBase64) + 64; + char* urlBuf = (char*)MP4Malloc(urlBufLen); + + snprintf(urlBuf, urlBufLen, + "data:application/mpeg4-od-au;base64,%s", + odCmdBase64); + + MP4StringProperty* pUrlProperty; + if (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 + (void)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; + if (pOdEsd->FindProperty("decConfigDescr.bufferSizeDB", + (MP4Property**)&pBufferSizeProperty)) { + ASSERT(pBufferSizeProperty); + pBufferSizeProperty->SetValue(numBytes); + } + + // SL config needs to change from 2 (file) to 1 (null) + if (pOdEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pSetProperty)) + pSetProperty->SetValue(1); + + + // Scene + MP4Descriptor* pSceneEsd = + pEsProperty->AddDescriptor(MP4ESDescrTag); + pSceneEsd->Generate(); + + if (pSceneEsd->FindProperty("ESID", + (MP4Property**)&pSceneESID)) { + // we set the Scene ESID to a non-zero unique value + pSceneESID->SetValue(sceneTrackId); + } + + if (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); + snprintf(urlBuf, strlen(sceneCmdBase64) + 64, + "data:application/mpeg4-bifs-au;base64,%s", + sceneCmdBase64); + + if (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 + ASSERT(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; + if (pSceneEsd->FindProperty("decConfigDescr.bufferSizeDB", + (MP4Property**)&pBufferSizeProperty)) { + ASSERT(pBufferSizeProperty); + pBufferSizeProperty->SetValue(numBytes); + } + + // SL config needs to change from 2 (file) to 1 (null) + if (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)); +} + +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 + if (pIod->FindProperty("audioProfileLevelId", + (MP4Property**)&pInt)) + pInt->SetValue(audioProfile); + + if (pIod->FindProperty("visualProfileLevelId", + (MP4Property**)&pInt)) + pInt->SetValue(videoProfile); + + // Mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag + MP4DescriptorProperty* pEsProperty; + if (!pIod->FindProperty("esIds", (MP4Property**)&pEsProperty)) return; + 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); + snprintf(urlBuf, strlen(sceneCmdBase64) + 64, + "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(urlBuf); + urlBuf = NULL; + + MP4Free(sceneCmdBase64); + sceneCmdBase64 = 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 = "U64" bytes\n", numBytes); MP4HexDump(pBytes, numBytes)); + + char* odCmdBase64 = MP4ToBase64(pBytes, numBytes); + + urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64); + if (urlBuf != NULL) { + snprintf(urlBuf, strlen(odCmdBase64) + 64, + "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(urlBuf); + urlBuf = NULL; + } + MP4Free(odCmdBase64); + odCmdBase64 = NULL; + MP4Free(pBytes); + pBytes = 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::CreateESD( + MP4DescriptorProperty* pEsProperty, + u_int32_t esid, + u_int8_t objectType, + u_int8_t streamType, + u_int32_t bufferSize, + u_int32_t bitrate, + const 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(); + + if (pEsd->FindProperty("ESID", + (MP4Property**)&pInt)) + pInt->SetValue(esid); + + if (pEsd->FindProperty("decConfigDescr.objectTypeId", + (MP4Property**)&pInt)) + pInt->SetValue(objectType); + + if (pEsd->FindProperty("decConfigDescr.streamType", + (MP4Property**)&pInt)) + pInt->SetValue(streamType); + + if (pEsd->FindProperty("decConfigDescr.bufferSizeDB", + (MP4Property**)&pInt)) + pInt->SetValue(bufferSize); + + if (pEsd->FindProperty("decConfigDescr.maxBitrate", + (MP4Property**)&pInt)) + pInt->SetValue(bitrate); + + if (pEsd->FindProperty("decConfigDescr.avgBitrate", + (MP4Property**)&pInt)) + pInt->SetValue(bitrate); + + MP4DescriptorProperty* pConfigDescrProperty; + if (pEsd->FindProperty("decConfigDescr.decSpecificInfo", + (MP4Property**)&pConfigDescrProperty)) { + + MP4Descriptor* pConfigDescr = + pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag); + pConfigDescr->Generate(); + + if (pConfigDescrProperty->FindProperty("decSpecificInfo[0].info", + (MP4Property**)&pBytes)) + pBytes->SetValue(pConfig, configLength); + } + + if (pEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pInt)) + // changed 12/5/02 from plugfest to value 0 + pInt->SetValue(0); + + if (pEsd->FindProperty("slConfig.useAccessUnitEndFlag", + (MP4Property **)&pBits)) + pBits->SetValue(1); + + if (url) { + if (pEsd->FindProperty("URLFlag", + (MP4Property**)&pInt)) + pInt->SetValue(1); + + if (pEsd->FindProperty("URL", + (MP4Property**)&pString)) + pString->SetValue(url); + } + + //return pEsd; +} + +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; + if (pOd->FindProperty("objectDescriptorId", + (MP4Property**)&pOdIdProperty)) + pOdIdProperty->SetValue(odId); + + MP4DescriptorProperty* pEsIdsDescriptorProperty = NULL; + ASSERT(pOd->FindProperty("esIds", + (MP4Property**)&pEsIdsDescriptorProperty)); + ASSERT(pEsIdsDescriptorProperty); + + pEsIdsDescriptorProperty->SetTags(MP4ESIDRefDescrTag); + + MP4Descriptor *pRefDescriptor = + pEsIdsDescriptorProperty->AddDescriptor(MP4ESIDRefDescrTag); + pRefDescriptor->Generate(); + + MP4Integer16Property* pRefIndexProperty = NULL; + ASSERT(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; +} + +void MP4File::CreateIsmaODUpdateCommandFromFileForStream( + MP4TrackId audioTrackId, + MP4TrackId videoTrackId, + u_int8_t** ppBytes, + u_int64_t* pNumBytes) +{ + MP4DescriptorProperty* pAudioEsd = NULL; + MP4Integer8Property* pAudioSLConfigPredef = NULL; + MP4BitfieldProperty* pAudioAccessUnitEndFlag = NULL; + int oldAudioUnitEndFlagValue = 0; + MP4DescriptorProperty* pVideoEsd = NULL; + MP4Integer8Property* pVideoSLConfigPredef = NULL; + MP4BitfieldProperty* pVideoAccessUnitEndFlag = NULL; + int oldVideoUnitEndFlagValue = 0; + MP4IntegerProperty* pAudioEsdId = NULL; + MP4IntegerProperty* pVideoEsdId = NULL; + + if (audioTrackId != MP4_INVALID_TRACK_ID) { + // changed mp4a to * to handle enca case + MP4Atom* pEsdsAtom = + FindAtomMP4File(MakeTrackName(audioTrackId, + "mdia.minf.stbl.stsd.*.esds")); + ASSERT(pEsdsAtom); + + pAudioEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2)); + // ESID is 0 for file, stream needs to be non-ze + ASSERT(pAudioEsd->FindProperty("ESID", + (MP4Property**)&pAudioEsdId)); + + ASSERT(pAudioEsdId); + pAudioEsdId->SetValue(audioTrackId); + + // SL config needs to change from 2 (file) to 1 (null) + if (pAudioEsd->FindProperty("slConfigDescr.predefined", + (MP4Property**)&pAudioSLConfigPredef)) { + ASSERT(pAudioSLConfigPredef); + pAudioSLConfigPredef->SetValue(0); + } + + if (pAudioEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag", + (MP4Property **)&pAudioAccessUnitEndFlag)) { + oldAudioUnitEndFlagValue = + pAudioAccessUnitEndFlag->GetValue(); + pAudioAccessUnitEndFlag->SetValue(1); + } + } + + if (videoTrackId != MP4_INVALID_TRACK_ID) { + // changed mp4v to * to handle encv case + MP4Atom* pEsdsAtom = + FindAtomMP4File(MakeTrackName(videoTrackId, + "mdia.minf.stbl.stsd.*.esds")); + ASSERT(pEsdsAtom); + + pVideoEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2)); + ASSERT(pVideoEsd->FindProperty("ESID", + (MP4Property**)&pVideoEsdId)); + + ASSERT(pVideoEsdId); + pVideoEsdId->SetValue(videoTrackId); + + // SL config needs to change from 2 (file) to 1 (null) + ASSERT(pVideoEsd->FindProperty("slConfigDescr.predefined", + (MP4Property **)&pVideoSLConfigPredef)); + ASSERT(pVideoSLConfigPredef); + pVideoSLConfigPredef->SetValue(0); + + if (pVideoEsd->FindProperty("slConfigDescr.useAccessUnitEndFlag", + (MP4Property **)&pVideoAccessUnitEndFlag)) { + oldVideoUnitEndFlagValue = + pVideoAccessUnitEndFlag->GetValue(); + pVideoAccessUnitEndFlag->SetValue(1); + } + } + + CreateIsmaODUpdateCommandForStream( + pAudioEsd, pVideoEsd, ppBytes, pNumBytes); + VERBOSE_ISMA(GetVerbosity(), + printf("After CreateImsaODUpdateCommandForStream len "U64" =\n", *pNumBytes); MP4HexDump(*ppBytes, *pNumBytes)); + // return SL config values to 2 (file) + // return ESID values to 0 + if (pAudioSLConfigPredef) { + pAudioSLConfigPredef->SetValue(2); + } + if (pAudioEsdId) { + pAudioEsdId->SetValue(0); + } + if (pAudioAccessUnitEndFlag) { + pAudioAccessUnitEndFlag->SetValue(oldAudioUnitEndFlagValue ); + } + if (pVideoEsdId) { + pVideoEsdId->SetValue(0); + } + if (pVideoSLConfigPredef) { + pVideoSLConfigPredef->SetValue(2); + } + if (pVideoAccessUnitEndFlag) { + pVideoAccessUnitEndFlag->SetValue(oldVideoUnitEndFlagValue ); + } +} + +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; + if (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::CreateIsmaSceneCommand( + bool hasAudio, + bool hasVideo, + u_int8_t** ppBytes, + u_int64_t* pNumBytes) +{ + // from ISMA 1.0 Tech Spec Appendix E + static const u_int8_t bifsAudioOnly[] = { + 0xC0, 0x10, 0x12, + 0x81, 0x30, 0x2A, 0x05, 0x6D, 0xC0 + }; + static const u_int8_t bifsVideoOnly[] = { + 0xC0, 0x10, 0x12, + 0x61, 0x04, + 0x1F, 0xC0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, + 0x44, 0x28, 0x22, 0x82, 0x9F, 0x80 + }; + static const u_int8_t bifsAudioVideo[] = { + 0xC0, 0x10, 0x12, + 0x81, 0x30, 0x2A, 0x05, 0x6D, 0x26, + 0x10, 0x41, 0xFC, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, + 0x04, 0x42, 0x82, 0x28, 0x29, 0xF8 + }; + + if (hasAudio && hasVideo) { + *pNumBytes = sizeof(bifsAudioVideo); + *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); + memcpy(*ppBytes, bifsAudioVideo, sizeof(bifsAudioVideo)); + + } else if (hasAudio) { + *pNumBytes = sizeof(bifsAudioOnly); + *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); + memcpy(*ppBytes, bifsAudioOnly, sizeof(bifsAudioOnly)); + + } else if (hasVideo) { + *pNumBytes = sizeof(bifsVideoOnly); + *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); + memcpy(*ppBytes, bifsVideoOnly, sizeof(bifsVideoOnly)); + } else { + *pNumBytes = 0; + *ppBytes = NULL; + } +} + |