winamp/Src/external_dependencies/libmp4v2/isma.cpp
2024-09-24 14:54:57 +02:00

943 lines
24 KiB
C++

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