ref: accbb9767cd632250bfd8c30fe629410fe4dc474
parent: aedfc3e7ba86301b10c39cb131f5562fd4c99ce9
author: menno <menno>
date: Thu Jul 25 07:49:29 EDT 2002
Update to newest version of mp4v2 library (Somebody please check linux compilation)
--- /dev/null
+++ b/common/mp4v2/API_CHANGES
@@ -1,0 +1,85 @@
+Changes from 0.9.4 to 0.9.5
+---------------------------
+Added
+ MP4GetTrackAudioMpeg4Type()
+ Returns MPEG-4 Audio type (e.g. AAC, CELP, HXVC, MIDI, etc.)
+ MP4ReadSampleFromTime()
+ Variant of MP4ReadSample() that uses time instead of sample id
+ (basically MP4GetSampleIdFromTime() + MP4ReadSample())
+ MP4Info()
+ MP4FileInfo()
+ Returns summary info on tracks in file (from util/mp4info.cpp)
+
+ The following functions add support for mp4 authoring/editting:
+
+ MP4CloneTrack()
+ Make a copy of a specified track, without media samples
+ MP4CopyTrack()
+ Make a copy of a specified track, with or without media samples
+ MP4CopySample()
+ Make a copy of a specified media sample
+
+ MP4AddTrackEdit()
+ Add a track edit list element
+ MP4DeleteTrackEdit()
+ Delete a track edit list element
+ MP4GetTrackNumberOfEdits()
+ Return the number of track edit list elements
+ MP4GetTrackEditTotalDuration()
+ Return the total duration of the track edit list
+ MP4GetTrackEditStart()
+ Return the edit start time for the edit list element
+ MP4GetTrackEditMediaStart()
+ Return the media start time for the edit list element
+ MP4SetTrackEditMediaStart()
+ Set the media start time for the edit list element
+ MP4GetTrackEditDuration()
+ Return the edit list element duration
+ MP4SetTrackEditDuration()
+ Set the edit list element duration
+ MP4GetTrackEditDwell()
+ Return the edit list element dwell parameter, see man page
+ MP4SetTrackEditDwell()
+ Set the edit list element dwell parameter, see man page
+ MP4ReadSampleFromEditTime()
+ Apply the edit list timeline to reading a sample
+ MP4GetSampleIdFromEditTime()
+ Return the sample id for a specified time on the edit list timeline
+
+Modified
+ MP4GetSampleIdFromTime()
+ Semantic change - now returns sample id corresponding
+ to specified time, not the sample id with the smallest positive
+ start time difference from the specified time.
+
+
+Changes from 0.9.3 to 0.9.4
+---------------------------
+Added
+ MP4GetTrackVideoFrameRate()
+ Returns video frame rate (average rate if video is variable rate).
+
+ MP4GetTrackBitRate()
+ Returns track average bit rate in bits-per-second.
+
+Changes from 0.9.2 to 0.9.3
+---------------------------
+Modified
+ MP4Optimize()
+ Second argument, newFileName, can now be NULL in which case
+ a temporary file is created for the results of the optimization.
+ Upon success, the existing file specified with the first argument
+ is overwritten with the optimized file.
+
+ MP4GetNumberOfTracks()
+ MP4FindTrackId()
+ Both have a new optional argument, subType, with default value 0.
+ The subType can be specified for audio and video tracks to
+ match only a specific encoding type. See man page for more details.
+
+Added
+ MP4GetTrackVideoWidth()
+ Returns video width in pixels. See man page for caveat.
+
+ MP4GetTrackVideoHeight()
+ Returns video height in pixels. See man page for caveat.
--- a/common/mp4v2/Makefile.am
+++ b/common/mp4v2/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS = . test util
+
INCLUDES = -I$(top_srcdir)/include
AM_CXXFLAGS = -Wall
@@ -5,26 +7,6 @@
lib_LTLIBRARIES = libmp4v2.la
libmp4v2_la_SOURCES = \
- mp4.h \
- mp4.cpp \
- mp4array.h \
- mp4atom.h \
- mp4atom.cpp \
- mp4common.h \
- mp4container.h \
- mp4container.cpp \
- mp4descriptor.h \
- mp4descriptor.cpp \
- mp4file.h \
- mp4file.cpp \
- mp4file_io.cpp \
- mp4property.h \
- mp4property.cpp \
- mp4track.h \
- mp4track.cpp \
- mp4util.h \
- mp4util.cpp \
- atoms.h \
atom_co64.cpp \
atom_cprt.cpp \
atom_ctts.cpp \
@@ -64,6 +46,7 @@
atom_root.cpp \
atom_rtp.cpp \
atom_sdp.cpp \
+ atoms.h \
atom_smhd.cpp \
atom_snro.cpp \
atom_stbl.cpp \
@@ -93,15 +76,40 @@
atom_url.cpp \
atom_urn.cpp \
atom_vmhd.cpp \
- descriptors.h \
descriptors.cpp \
- ocidescriptors.h \
+ descriptors.h \
+ isma.cpp \
+ mp4array.h \
+ mp4atom.cpp \
+ mp4atom.h \
+ mp4common.h \
+ mp4container.cpp \
+ mp4container.h \
+ mp4.h \
+ mp4.cpp \
+ mp4descriptor.cpp \
+ mp4descriptor.h \
+ mp4file.cpp \
+ mp4file.h \
+ mp4file_io.cpp \
+ mp4info.cpp \
+ mp4property.cpp \
+ mp4property.h \
+ mp4track.cpp \
+ mp4track.h \
+ mp4util.cpp \
+ mp4util.h \
ocidescriptors.cpp \
- qosqualifiers.h \
- qosqualifiers.cpp \
- odcommands.h \
+ ocidescriptors.h \
odcommands.cpp \
- rtphint.h \
+ odcommands.h \
+ qosqualifiers.cpp \
+ qosqualifiers.h \
rtphint.cpp \
- isma.cpp
+ rtphint.h
+EXTRA_DIST = API_CHANGES \
+ INTERNALS \
+ libmp4v260.dsp \
+ libmp4v2_st60.dsp \
+ TODO
--- a/common/mp4v2/TODO
+++ b/common/mp4v2/TODO
@@ -1,10 +1,6 @@
-API and INTERNALS documentation
+Extended format (v2) support
-Extended format support
-
----
-
Means to dump all possible atoms/properties with types
Wrap printf's for verbosity - see example is player/lib/http/http_util.c
@@ -12,6 +8,4 @@
Distinguish cases of no ES Config and error parsing esds
Improve error recovery when length of atom/descriptor is larger than parent/file, resync on parent.
-
-Reshape things to use MPContainer as a base class?
--- a/common/mp4v2/atom_mvhd.cpp
+++ b/common/mp4v2/atom_mvhd.cpp
@@ -86,6 +86,8 @@
((MP4Integer32Property*)m_pProperties[3])->SetValue(now);
}
+ ((MP4Integer32Property*)m_pProperties[4])->SetValue(1000);
+
((MP4Float32Property*)m_pProperties[6])->SetValue(1.0);
((MP4Float32Property*)m_pProperties[7])->SetValue(1.0);
--- a/common/mp4v2/descriptors.cpp
+++ b/common/mp4v2/descriptors.cpp
@@ -94,7 +94,7 @@
new MP4StringProperty("URL", Counted));
AddProperty( /* 4 */
new MP4DescriptorProperty("esIds",
- MP4ESIDIncDescrTag, 0, Required, Many));
+ MP4ESIDRefDescrTag, 0, Required, Many));
AddProperty( /* 5 */
new MP4DescriptorProperty("ociDescr",
MP4OCIDescrTagsStart, MP4OCIDescrTagsEnd, Optional, Many));
--- a/common/mp4v2/descriptors.h
+++ b/common/mp4v2/descriptors.h
@@ -22,8 +22,8 @@
#ifndef __DESCRIPTORS_INCLUDED__
#define __DESCRIPTORS_INCLUDED__
-const u_int8_t MP4ODescrTag = 0x01;
-const u_int8_t MP4IODescrTag = 0x02;
+const u_int8_t MP4ODescrTag = 0x01;
+const u_int8_t MP4IODescrTag = 0x02;
const u_int8_t MP4ESDescrTag = 0x03;
const u_int8_t MP4DecConfigDescrTag = 0x04;
const u_int8_t MP4DecSpecificDescrTag = 0x05;
--- a/common/mp4v2/isma.cpp
+++ b/common/mp4v2/isma.cpp
@@ -21,6 +21,10 @@
#include "mp4common.h"
+static u_int8_t BifsV2Config[3] = {
+ 0x00, 0x00, 0x40 // IsCommandStream
+};
+
void MP4File::MakeIsmaCompliant(bool addIsmaComplianceSdp)
{
ProtectWriteOperation("MP4MakeIsmaCompliant");
@@ -49,6 +53,9 @@
delete e;
}
+ u_int64_t fileMsDuration =
+ ConvertFromMovieDuration(GetDuration(), MP4_MSECS_TIME_SCALE);
+
// delete any existing OD track
if (m_odTrackId != MP4_INVALID_TRACK_ID) {
DeleteTrack(m_odTrackId);
@@ -84,21 +91,22 @@
SetTrackIntegerProperty(sceneTrackId,
"mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId",
MP4SystemsV2ObjectType);
- static u_int8_t bifsv2Config[3] = {
- 0x00, 0x00, 0x40 // IsCommandStream
- };
+
SetTrackESConfiguration(sceneTrackId,
- bifsv2Config, sizeof(bifsv2Config));
+ BifsV2Config, sizeof(BifsV2Config));
u_int8_t* pBytes = NULL;
u_int64_t numBytes = 0;
// write OD Update Command
- CreateIsmaODUpdateCommand(
- m_odTrackId, audioTrackId, videoTrackId, true,
- &pBytes, &numBytes);
+ CreateIsmaODUpdateCommandFromFileForFile(
+ m_odTrackId,
+ audioTrackId,
+ videoTrackId,
+ &pBytes,
+ &numBytes);
- WriteSample(m_odTrackId, pBytes, numBytes, 1);
+ WriteSample(m_odTrackId, pBytes, numBytes, fileMsDuration);
MP4Free(pBytes);
pBytes = NULL;
@@ -105,21 +113,29 @@
// write BIFS Scene Replace Command
CreateIsmaSceneCommand(
- sceneTrackId, audioTrackId, videoTrackId,
- &pBytes, &numBytes);
+ MP4_IS_VALID_TRACK_ID(audioTrackId),
+ MP4_IS_VALID_TRACK_ID(videoTrackId),
+ &pBytes,
+ &numBytes);
- WriteSample(sceneTrackId, pBytes, numBytes, 1);
+ WriteSample(sceneTrackId, pBytes, numBytes, fileMsDuration);
MP4Free(pBytes);
pBytes = NULL;
// add session level sdp
- CreateIsmaIod(
- m_odTrackId, sceneTrackId, audioTrackId, videoTrackId,
- &pBytes, &numBytes);
+ CreateIsmaIodFromFile(
+ m_odTrackId,
+ sceneTrackId,
+ audioTrackId,
+ videoTrackId,
+ &pBytes,
+ &numBytes);
- char* sdpBuf = (char*)MP4Calloc(numBytes + 256);
+ char* iodBase64 = MP4ToBase64(pBytes, numBytes);
+ char* sdpBuf = (char*)MP4Calloc(strlen(iodBase64) + 256);
+
if (addIsmaComplianceSdp) {
strcpy(sdpBuf, "a=isma-compliance:1,1.0,1\015\012");
}
@@ -126,7 +142,7 @@
sprintf(&sdpBuf[strlen(sdpBuf)],
"a=mpeg4-iod: \042data:application/mpeg4-iod;base64,%s\042\015\012",
- MP4ToBase64(pBytes, numBytes));
+ iodBase64);
SetSessionSdp(sdpBuf);
@@ -133,6 +149,8 @@
VERBOSE_ISMA(GetVerbosity(),
printf("IOD SDP = %s\n", sdpBuf));
+ MP4Free(iodBase64);
+ iodBase64 = NULL;
MP4Free(pBytes);
pBytes = NULL;
MP4Free(sdpBuf);
@@ -153,7 +171,7 @@
pSetProperty->SetValue(pGetProperty->GetValue());
}
-void MP4File::CreateIsmaIod(
+void MP4File::CreateIsmaIodFromFile(
MP4TrackId odTrackId,
MP4TrackId sceneTrackId,
MP4TrackId audioTrackId,
@@ -200,22 +218,24 @@
u_int8_t* pBytes;
u_int64_t numBytes;
- CreateIsmaODUpdateCommand(
- m_odTrackId, audioTrackId, videoTrackId, false,
- &pBytes, &numBytes);
+ CreateIsmaODUpdateCommandFromFileForStream(
+ audioTrackId,
+ videoTrackId,
+ &pBytes,
+ &numBytes);
VERBOSE_ISMA(GetVerbosity(),
printf("OD data =\n"); MP4HexDump(pBytes, numBytes));
- MP4StringProperty* pUrlProperty;
- char* urlBuf = NULL;
+ char* odCmdBase64 = MP4ToBase64(pBytes, numBytes);
- urlBuf = (char*)MP4Malloc((numBytes * 4 / 3) + 64);
+ char* urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64);
sprintf(urlBuf,
"data:application/mpeg4-od-au;base64,%s",
- MP4ToBase64(pBytes, numBytes));
+ odCmdBase64);
+ MP4StringProperty* pUrlProperty;
pOdEsd->FindProperty("URL",
(MP4Property**)&pUrlProperty);
pUrlProperty->SetValue(urlBuf);
@@ -223,6 +243,8 @@
VERBOSE_ISMA(GetVerbosity(),
printf("OD data URL = \042%s\042\n", urlBuf));
+ MP4Free(odCmdBase64);
+ odCmdBase64 = NULL;
MP4Free(pBytes);
pBytes = NULL;
MP4Free(urlBuf);
@@ -266,16 +288,20 @@
pSetProperty->SetValue(1);
CreateIsmaSceneCommand(
- sceneTrackId, audioTrackId, videoTrackId,
- &pBytes, &numBytes);
+ MP4_IS_VALID_TRACK_ID(audioTrackId),
+ MP4_IS_VALID_TRACK_ID(videoTrackId),
+ &pBytes,
+ &numBytes);
VERBOSE_ISMA(GetVerbosity(),
printf("Scene data =\n"); MP4HexDump(pBytes, numBytes));
- urlBuf = (char*)MP4Malloc((numBytes * 4 / 3) + 64);
+ char *sceneCmdBase64 = MP4ToBase64(pBytes, numBytes);
+
+ urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64);
sprintf(urlBuf,
"data:application/mpeg4-bifs-au;base64,%s",
- MP4ToBase64(pBytes, numBytes));
+ sceneCmdBase64);
pSceneEsd->FindProperty("URL",
(MP4Property**)&pUrlProperty);
@@ -284,6 +310,8 @@
VERBOSE_ISMA(GetVerbosity(),
printf("Scene data URL = \042%s\042\n", urlBuf));
+ MP4Free(sceneCmdBase64);
+ sceneCmdBase64 = NULL;
MP4Free(urlBuf);
urlBuf = NULL;
MP4Free(pBytes);
@@ -325,11 +353,245 @@
printf("IOD data =\n"); MP4HexDump(*ppBytes, *pNumBytes));
}
-void MP4File::CreateIsmaODUpdateCommand(
+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;
+
+ // Video
+ MP4Descriptor* pVideoEsd =
+ CreateESD(
+ pEsProperty,
+ 20, // esid
+ MP4_MPEG4_VIDEO_TYPE,
+ MP4VisualStreamType,
+ videoBitrate / 8, // bufferSize
+ videoBitrate,
+ videoConfig,
+ videoConfigLength,
+ NULL);
+
+ // Audio
+ MP4Descriptor* pAudioEsd =
+ CreateESD(
+ pEsProperty,
+ 10, // esid
+ MP4_MPEG4_AUDIO_TYPE,
+ MP4AudioStreamType,
+ audioBitrate / 8, // bufferSize
+ audioBitrate,
+ audioConfig,
+ audioConfigLength,
+ NULL);
+
+ // OD
+
+ // Glop to make infrastructure happy
+ MP4DescriptorProperty* pAudioEsdProperty =
+ new MP4DescriptorProperty();
+ pAudioEsdProperty->AppendDescriptor(pAudioEsd);
+ MP4DescriptorProperty* pVideoEsdProperty =
+ new MP4DescriptorProperty();
+ pVideoEsdProperty->AppendDescriptor(pVideoEsd);
+
+ CreateIsmaODUpdateCommandForStream(
+ pAudioEsdProperty,
+ pVideoEsdProperty,
+ &pBytes,
+ &numBytes);
+
+ // TBD cleanup temporary descriptor properties
+
+ VERBOSE_ISMA(GetVerbosity(),
+ printf("OD data =\n"); 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));
+}
+
+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;
+
+ 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);
+ pInt->SetValue(1);
+
+ if (url) {
+ pEsd->FindProperty("URLFlag",
+ (MP4Property**)&pInt);
+ pInt->SetValue(1);
+
+ pEsd->FindProperty("URL",
+ (MP4Property**)&pString);
+ pString->SetValue(url);
+ }
+
+ return pEsd;
+}
+
+void MP4File::CreateIsmaODUpdateCommandFromFileForFile(
MP4TrackId odTrackId,
MP4TrackId audioTrackId,
MP4TrackId videoTrackId,
- bool mp4FileMode,
u_int8_t** ppBytes,
u_int64_t* pNumBytes)
{
@@ -336,13 +598,6 @@
MP4Descriptor* pCommand = CreateODCommand(MP4ODUpdateODCommandTag);
pCommand->Generate();
- MP4Descriptor* pAudioOd = NULL;
- MP4Descriptor* pVideoOd = NULL;
- MP4DescriptorProperty* pOrgAudioEsdProperty = NULL;
- MP4DescriptorProperty* pOrgVideoEsdProperty = NULL;
- MP4DescriptorProperty* pRealAudioEsdProperty = NULL;
- MP4DescriptorProperty* pRealVideoEsdProperty = NULL;
-
for (u_int8_t i = 0; i < 2; i++) {
MP4TrackId trackId;
u_int16_t odId;
@@ -359,33 +614,16 @@
continue;
}
- u_int32_t mpodIndex = FindTrackReference(
- MakeTrackName(odTrackId, "tref.mpod"), trackId);
- ASSERT(mpodIndex != 0);
-
- u_int8_t odTag;
- if (mp4FileMode) {
- odTag = MP4FileODescrTag;
- } else {
- odTag = MP4ODescrTag;
- }
-
MP4DescriptorProperty* pOdDescrProperty =
(MP4DescriptorProperty*)(pCommand->GetProperty(0));
- pOdDescrProperty->SetTags(odTag);
+ pOdDescrProperty->SetTags(MP4FileODescrTag);
MP4Descriptor* pOd =
- pOdDescrProperty->AddDescriptor(odTag);
+ pOdDescrProperty->AddDescriptor(MP4FileODescrTag);
pOd->Generate();
- if (i == 0) {
- pAudioOd = pOd;
- } else {
- pVideoOd = pOd;
- }
-
MP4BitfieldProperty* pOdIdProperty = NULL;
pOd->FindProperty("objectDescriptorId",
(MP4Property**)&pOdIdProperty);
@@ -396,87 +634,153 @@
(MP4Property**)&pEsIdsDescriptorProperty);
ASSERT(pEsIdsDescriptorProperty);
- if (mp4FileMode) {
- pEsIdsDescriptorProperty->SetTags(MP4ESIDRefDescrTag);
+ pEsIdsDescriptorProperty->SetTags(MP4ESIDRefDescrTag);
- MP4Descriptor *pRefDescriptor =
- pEsIdsDescriptorProperty->AddDescriptor(MP4ESIDRefDescrTag);
- pRefDescriptor->Generate();
+ MP4Descriptor *pRefDescriptor =
+ pEsIdsDescriptorProperty->AddDescriptor(MP4ESIDRefDescrTag);
+ pRefDescriptor->Generate();
- MP4Integer16Property* pRefIndexProperty = NULL;
- pRefDescriptor->FindProperty("refIndex",
- (MP4Property**)&pRefIndexProperty);
- ASSERT(pRefIndexProperty);
+ MP4Integer16Property* pRefIndexProperty = NULL;
+ pRefDescriptor->FindProperty("refIndex",
+ (MP4Property**)&pRefIndexProperty);
+ ASSERT(pRefIndexProperty);
- pRefIndexProperty->SetValue(mpodIndex);
+ u_int32_t mpodIndex = FindTrackReference(
+ MakeTrackName(odTrackId, "tref.mpod"), trackId);
+ ASSERT(mpodIndex != 0);
- } else { // stream mode
- pEsIdsDescriptorProperty->SetTags(MP4ESDescrTag);
+ pRefIndexProperty->SetValue(mpodIndex);
+ }
- MP4Atom* pEsdsAtom =
- FindAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd.*.esds"));
- ASSERT(pEsdsAtom);
+ pCommand->WriteToMemory(this, ppBytes, pNumBytes);
- MP4DescriptorProperty* pEsdProperty =
- (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2));
+ delete pCommand;
+}
- // HACK we temporarily point to the esds
- if (i == 0) {
- pOrgAudioEsdProperty = pEsIdsDescriptorProperty;
- pRealAudioEsdProperty = pEsdProperty;
- } else {
- pOrgVideoEsdProperty = pEsIdsDescriptorProperty;
- pRealVideoEsdProperty = pEsdProperty;
- }
- pOd->SetProperty(4, pEsdProperty);
+void MP4File::CreateIsmaODUpdateCommandFromFileForStream(
+ MP4TrackId audioTrackId,
+ MP4TrackId videoTrackId,
+ u_int8_t** ppBytes,
+ u_int64_t* pNumBytes)
+{
+ MP4DescriptorProperty* pAudioEsd = NULL;
+ MP4Integer8Property* pAudioSLConfig = NULL;
+ MP4DescriptorProperty* pVideoEsd = NULL;
+ MP4Integer8Property* pVideoSLConfig = NULL;
- // SL config needs to change from 2 (file) to 1 (null)
- MP4Integer8Property* pSLConfigProperty = NULL;
- pEsdProperty->FindProperty("slConfigDescr.predefined",
- (MP4Property**)&pSLConfigProperty);
- ASSERT(pSLConfigProperty);
- pSLConfigProperty->SetValue(1);
- }
+ if (audioTrackId != MP4_INVALID_TRACK_ID) {
+ MP4Atom* pEsdsAtom =
+ FindAtom(MakeTrackName(audioTrackId,
+ "mdia.minf.stbl.stsd.mp4a.esds"));
+ ASSERT(pEsdsAtom);
+
+ pAudioEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2));
+
+ // SL config needs to change from 2 (file) to 1 (null)
+ pAudioEsd->FindProperty("slConfigDescr.predefined",
+ (MP4Property**)&pAudioSLConfig);
+ ASSERT(pAudioSLConfig);
+ pAudioSLConfig->SetValue(1);
}
- pCommand->WriteToMemory(this, ppBytes, pNumBytes);
+ if (videoTrackId != MP4_INVALID_TRACK_ID) {
+ MP4Atom* pEsdsAtom =
+ FindAtom(MakeTrackName(videoTrackId,
+ "mdia.minf.stbl.stsd.mp4v.esds"));
+ ASSERT(pEsdsAtom);
- // carefully replace esd properties before destroying
- if (pAudioOd) {
- pAudioOd->SetProperty(4, pOrgAudioEsdProperty);
+ pVideoEsd = (MP4DescriptorProperty*)(pEsdsAtom->GetProperty(2));
- // SL config needs to go back to 2 (file)
- if (!mp4FileMode) {
- ASSERT(pRealAudioEsdProperty);
- MP4Integer8Property* pSLConfigProperty = NULL;
- pRealAudioEsdProperty->FindProperty("slConfigDescr.predefined",
- (MP4Property**)&pSLConfigProperty);
- ASSERT(pSLConfigProperty);
- pSLConfigProperty->SetValue(2);
- }
+ // SL config needs to change from 2 (file) to 1 (null)
+ pVideoEsd->FindProperty("slConfigDescr.predefined",
+ (MP4Property**)&pVideoSLConfig);
+ ASSERT(pVideoSLConfig);
+ pVideoSLConfig->SetValue(1);
}
- if (pVideoOd) {
- pVideoOd->SetProperty(4, pOrgVideoEsdProperty);
+ CreateIsmaODUpdateCommandForStream(
+ pAudioEsd, pVideoEsd, ppBytes, pNumBytes);
+
+ // return SL config values to 2 (file)
+ if (pAudioSLConfig) {
+ pAudioSLConfig->SetValue(2);
+ }
+ if (pVideoSLConfig) {
+ pVideoSLConfig->SetValue(2);
+ }
+}
- // SL config needs to go back to 2 (file)
- if (!mp4FileMode) {
- ASSERT(pRealVideoEsdProperty);
- MP4Integer8Property* pSLConfigProperty = NULL;
- pRealVideoEsdProperty->FindProperty("slConfigDescr.predefined",
- (MP4Property**)&pSLConfigProperty);
- ASSERT(pSLConfigProperty);
- pSLConfigProperty->SetValue(2);
+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::CreateIsmaSceneCommand(
- MP4TrackId sceneTrackId,
- MP4TrackId audioTrackId,
- MP4TrackId videoTrackId,
+ bool hasAudio,
+ bool hasVideo,
u_int8_t** ppBytes,
u_int64_t* pNumBytes)
{
@@ -495,18 +799,17 @@
0x61, 0x04, 0x88, 0x50, 0x45, 0x05, 0x3F, 0x00
};
- if (audioTrackId != MP4_INVALID_TRACK_ID
- && videoTrackId != MP4_INVALID_TRACK_ID) {
+ if (hasAudio && hasVideo) {
*pNumBytes = sizeof(bifsAudioVideo);
*ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes);
memcpy(*ppBytes, bifsAudioVideo, sizeof(bifsAudioVideo));
- } else if (audioTrackId != MP4_INVALID_TRACK_ID) {
+ } else if (hasAudio) {
*pNumBytes = sizeof(bifsAudioOnly);
*ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes);
memcpy(*ppBytes, bifsAudioOnly, sizeof(bifsAudioOnly));
- } else if (videoTrackId != MP4_INVALID_TRACK_ID) {
+ } else if (hasVideo) {
*pNumBytes = sizeof(bifsVideoOnly);
*ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes);
memcpy(*ppBytes, bifsVideoOnly, sizeof(bifsVideoOnly));
--- a/common/mp4v2/libmp4v2.dsp
+++ /dev/null
@@ -1,484 +1,0 @@
-# Microsoft Developer Studio Project File - Name="libmp4v2" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 5.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Static Library" 0x0104
-
-CFG=libmp4v2 - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "libmp4v2.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "libmp4v2.mak" CFG="libmp4v2 - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "libmp4v2 - Win32 Release" (based on "Win32 (x86) Static Library")
-!MESSAGE "libmp4v2 - Win32 Debug" (based on "Win32 (x86) Static Library")
-!MESSAGE
-
-# Begin Project
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-
-!IF "$(CFG)" == "libmp4v2 - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo
-
-!ELSEIF "$(CFG)" == "libmp4v2 - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo
-
-!ENDIF
-
-# Begin Target
-
-# Name "libmp4v2 - Win32 Release"
-# Name "libmp4v2 - Win32 Debug"
-# Begin Group "source"
-
-# PROP Default_Filter ".c, .cpp"
-# Begin Source File
-
-SOURCE=.\atom_co64.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_cprt.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_ctts.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dimm.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dinf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dmax.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dmed.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dref.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_drep.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_edts.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_elst.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_esds.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_free.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_ftyp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hdlr.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hinf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hmhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hnti.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_iods.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_maxr.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mdat.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mdhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mdia.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mfhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_minf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_moof.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_moov.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mp4a.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mp4s.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mp4v.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mvex.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mvhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_nmhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_nump.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_payt.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_pmax.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_root.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_rtp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_sdp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_smhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_snro.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stbl.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stco.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stdp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsc.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsh.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stss.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsz.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stts.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tfhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tims.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tkhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tmax.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tmin.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tpyl.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_traf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trak.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tref.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_treftype.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trex.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trpy.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trun.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tsro.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_udta.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_url.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_urn.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_vmhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\descriptors.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\isma.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4atom.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4container.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4descriptor.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4file.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4file_io.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4property.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4track.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4util.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ocidescriptors.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\odcommands.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\qosqualifiers.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\rtphint.cpp
-# End Source File
-# End Group
-# Begin Group "include"
-
-# PROP Default_Filter ".h"
-# Begin Source File
-
-SOURCE=.\atoms.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\descriptors.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4array.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4atom.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4common.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4container.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4descriptor.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4file.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4property.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4track.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4util.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\ocidescriptors.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\odcommands.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\qosqualifiers.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\rtphint.h
-# End Source File
-# End Group
-# End Target
-# End Project
--- a/common/mp4v2/libmp4v260.dsp
+++ b/common/mp4v2/libmp4v260.dsp
@@ -1,488 +1,493 @@
-# Microsoft Developer Studio Project File - Name="libmp4v2" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Static Library" 0x0104
-
-CFG=libmp4v2 - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "libmp4v260.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "libmp4v260.mak" CFG="libmp4v2 - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "libmp4v2 - Win32 Release" (based on "Win32 (x86) Static Library")
-!MESSAGE "libmp4v2 - Win32 Debug" (based on "Win32 (x86) Static Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "libmp4v2 - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD BASE RSC /l 0x409
-# ADD RSC /l 0x409
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo
-
-!ELSEIF "$(CFG)" == "libmp4v2 - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
-# ADD BASE RSC /l 0x409
-# ADD RSC /l 0x409
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo
-
-!ENDIF
-
-# Begin Target
-
-# Name "libmp4v2 - Win32 Release"
-# Name "libmp4v2 - Win32 Debug"
-# Begin Group "source"
-
-# PROP Default_Filter ".c, .cpp"
-# Begin Source File
-
-SOURCE=.\atom_co64.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_cprt.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_ctts.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dimm.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dinf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dmax.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dmed.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dref.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_drep.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_edts.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_elst.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_esds.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_free.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_ftyp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hdlr.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hinf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hmhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hnti.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_iods.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_maxr.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mdat.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mdhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mdia.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mfhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_minf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_moof.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_moov.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mp4a.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mp4s.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mp4v.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mvex.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mvhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_nmhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_nump.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_payt.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_pmax.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_root.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_rtp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_sdp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_smhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_snro.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stbl.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stco.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stdp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsc.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsh.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stss.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsz.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stts.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tfhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tims.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tkhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tmax.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tmin.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tpyl.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_traf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trak.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tref.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_treftype.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trex.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trpy.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trun.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tsro.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_udta.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_url.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_urn.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_vmhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\descriptors.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\isma.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4atom.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4container.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4descriptor.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4file.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4file_io.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4property.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4track.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4util.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ocidescriptors.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\odcommands.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\qosqualifiers.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\rtphint.cpp
-# End Source File
-# End Group
-# Begin Group "include"
-
-# PROP Default_Filter ".h"
-# Begin Source File
-
-SOURCE=.\atoms.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\descriptors.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4array.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4atom.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4common.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4container.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4descriptor.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4file.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4property.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4track.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4util.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\ocidescriptors.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\odcommands.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\qosqualifiers.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\rtphint.h
-# End Source File
-# End Group
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="libmp4v2" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=libmp4v2 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libmp4v260.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libmp4v260.mak" CFG="libmp4v2 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libmp4v2 - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "libmp4v2 - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libmp4v2 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "libmp4v2 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "libmp4v2 - Win32 Release"
+# Name "libmp4v2 - Win32 Debug"
+# Begin Group "source"
+
+# PROP Default_Filter ".c, .cpp"
+# Begin Source File
+
+SOURCE=.\atom_co64.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_cprt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_ctts.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_dimm.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_dinf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_dmax.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_dmed.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_dref.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_drep.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_edts.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_elst.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_esds.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_free.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_ftyp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_hdlr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_hinf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_hmhd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_hnti.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_iods.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_maxr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_mdat.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_mdhd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_mdia.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_mfhd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_minf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_moof.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_moov.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_mp4a.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_mp4s.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_mp4v.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_mvex.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_mvhd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_nmhd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_nump.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_payt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_pmax.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_root.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_rtp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_sdp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_smhd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_snro.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_stbl.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_stco.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_stdp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_stsc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_stsd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_stsh.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_stss.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_stsz.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_stts.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_tfhd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_tims.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_tkhd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_tmax.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_tmin.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_tpyl.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_traf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_trak.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_tref.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_treftype.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_trex.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_trpy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_trun.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_tsro.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_udta.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_url.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_urn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\atom_vmhd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\descriptors.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\isma.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4atom.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4container.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4descriptor.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4file.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4file_io.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4info.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4property.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4track.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4util.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ocidescriptors.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\odcommands.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\qosqualifiers.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\rtphint.cpp
+# End Source File
+# End Group
+# Begin Group "include"
+
+# PROP Default_Filter ".h"
+# Begin Source File
+
+SOURCE=.\atoms.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\descriptors.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4array.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4atom.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4common.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4container.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4descriptor.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4file.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4property.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4track.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4util.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ocidescriptors.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\odcommands.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\qosqualifiers.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\rtphint.h
+# End Source File
+# End Group
+# End Target
+# End Project
--- a/common/mp4v2/libmp4v2_st.dsp
+++ /dev/null
@@ -1,484 +1,0 @@
-# Microsoft Developer Studio Project File - Name="libmp4v2_st" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 5.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Static Library" 0x0104
-
-CFG=libmp4v2_st - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "libmp4v2_st.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "libmp4v2_st.mak" CFG="libmp4v2_st - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "libmp4v2_st - Win32 Release" (based on "Win32 (x86) Static Library")
-!MESSAGE "libmp4v2_st - Win32 Debug" (based on "Win32 (x86) Static Library")
-!MESSAGE
-
-# Begin Project
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-
-!IF "$(CFG)" == "libmp4v2_st - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "ST_Release"
-# PROP Intermediate_Dir "ST_Release"
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo
-
-!ELSEIF "$(CFG)" == "libmp4v2_st - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "ST_Debug"
-# PROP Intermediate_Dir "ST_Debug"
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /W3 /GX /Z7 /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo
-
-!ENDIF
-
-# Begin Target
-
-# Name "libmp4v2_st - Win32 Release"
-# Name "libmp4v2_st - Win32 Debug"
-# Begin Group "source"
-
-# PROP Default_Filter ".c, .cpp"
-# Begin Source File
-
-SOURCE=.\atom_co64.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_cprt.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_ctts.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dimm.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dinf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dmax.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dmed.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_dref.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_drep.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_edts.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_elst.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_esds.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_free.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_ftyp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hdlr.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hinf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hmhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_hnti.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_iods.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_maxr.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mdat.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mdhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mdia.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mfhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_minf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_moof.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_moov.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mp4a.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mp4s.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mp4v.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mvex.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_mvhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_nmhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_nump.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_payt.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_pmax.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_root.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_rtp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_sdp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_smhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_snro.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stbl.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stco.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stdp.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsc.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsh.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stss.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stsz.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_stts.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tfhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tims.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tkhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tmax.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tmin.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tpyl.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_traf.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trak.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tref.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_treftype.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trex.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trpy.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_trun.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_tsro.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_udta.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_url.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_urn.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\atom_vmhd.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\descriptors.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\isma.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4atom.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4container.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4descriptor.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4file.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4file_io.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4property.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4track.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4util.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ocidescriptors.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\odcommands.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\qosqualifiers.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\rtphint.cpp
-# End Source File
-# End Group
-# Begin Group "include"
-
-# PROP Default_Filter ".h"
-# Begin Source File
-
-SOURCE=.\atoms.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\descriptors.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4array.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4atom.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4common.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4container.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4descriptor.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4file.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4property.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4track.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\mp4util.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\ocidescriptors.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\odcommands.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\qosqualifiers.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\rtphint.h
-# End Source File
-# End Group
-# End Target
-# End Project
--- a/common/mp4v2/libmp4v2_st60.dsp
+++ b/common/mp4v2/libmp4v2_st60.dsp
@@ -41,7 +41,7 @@
# PROP Intermediate_Dir "ST_Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /I "..\..\include" /I ".\\" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I ".\\" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
@@ -64,7 +64,7 @@
# PROP Intermediate_Dir "ST_Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /W3 /GX /Z7 /Od /I "..\..\include" /I ".\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Z7 /Od /I ".\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
@@ -500,5 +500,9 @@
SOURCE=.\win32_ver.h
# End Source File
# End Group
+# Begin Source File
+
+SOURCE=.\mp4info.cpp
+# End Source File
# End Target
# End Project
--- a/common/mp4v2/mp4.cpp
+++ b/common/mp4v2/mp4.cpp
@@ -119,7 +119,10 @@
return false;
}
-extern "C" bool MP4Dump(MP4FileHandle hFile, FILE* pDumpFile, bool dumpImplicits)
+extern "C" bool MP4Dump(
+ MP4FileHandle hFile,
+ FILE* pDumpFile,
+ bool dumpImplicits)
{
if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
try {
@@ -545,8 +548,11 @@
return MP4_INVALID_TRACK_ID;
}
-extern "C" MP4TrackId MP4AddAudioTrack(MP4FileHandle hFile,
- u_int32_t timeScale, u_int32_t sampleDuration, u_int8_t audioType)
+extern "C" MP4TrackId MP4AddAudioTrack(
+ MP4FileHandle hFile,
+ u_int32_t timeScale,
+ MP4Duration sampleDuration,
+ u_int8_t audioType)
{
if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
try {
@@ -561,9 +567,13 @@
return MP4_INVALID_TRACK_ID;
}
-extern "C" MP4TrackId MP4AddVideoTrack(MP4FileHandle hFile,
- u_int32_t timeScale, u_int32_t sampleDuration,
- u_int16_t width, u_int16_t height, u_int8_t videoType)
+extern "C" MP4TrackId MP4AddVideoTrack(
+ MP4FileHandle hFile,
+ u_int32_t timeScale,
+ MP4Duration sampleDuration,
+ u_int16_t width,
+ u_int16_t height,
+ u_int8_t videoType)
{
if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
try {
@@ -593,8 +603,204 @@
return MP4_INVALID_TRACK_ID;
}
+extern "C" MP4TrackId MP4CloneTrack(
+ MP4FileHandle srcFile,
+ MP4TrackId srcTrackId,
+ MP4FileHandle dstFile)
+{
+ MP4TrackId dstTrackId = MP4_INVALID_TRACK_ID;
+
+ if (dstFile == NULL) {
+ dstFile = srcFile;
+ }
+
+ const char* trackType =
+ MP4GetTrackType(srcFile, srcTrackId);
+
+ if (!trackType) {
+ return dstTrackId;
+ }
+
+ if (MP4_IS_VIDEO_TRACK_TYPE(trackType)) {
+ dstTrackId = MP4AddVideoTrack(
+ dstFile,
+ MP4GetTrackTimeScale(srcFile, srcTrackId),
+ MP4GetTrackFixedSampleDuration(srcFile, srcTrackId),
+ MP4GetTrackVideoWidth(srcFile, srcTrackId),
+ MP4GetTrackVideoHeight(srcFile, srcTrackId),
+ MP4GetTrackVideoType(srcFile, srcTrackId));
+
+ } else if (MP4_IS_AUDIO_TRACK_TYPE(trackType)) {
+ dstTrackId = MP4AddAudioTrack(
+ dstFile,
+ MP4GetTrackTimeScale(srcFile, srcTrackId),
+ MP4GetTrackFixedSampleDuration(srcFile, srcTrackId),
+ MP4GetTrackAudioType(srcFile, srcTrackId));
+
+ } else if (MP4_IS_OD_TRACK_TYPE(trackType)) {
+ dstTrackId = MP4AddODTrack(dstFile);
+
+ } else if (MP4_IS_SCENE_TRACK_TYPE(trackType)) {
+ dstTrackId = MP4AddSceneTrack(dstFile);
+
+ } else if (MP4_IS_HINT_TRACK_TYPE(trackType)) {
+ dstTrackId = MP4AddHintTrack(
+ dstFile,
+ MP4GetHintTrackReferenceTrackId(srcFile, srcTrackId));
+
+ } else if (MP4_IS_SYSTEMS_TRACK_TYPE(trackType)) {
+ dstTrackId = MP4AddSystemsTrack(dstFile, trackType);
+
+ } else {
+ dstTrackId = MP4AddTrack(dstFile, trackType);
+ }
+
+ if (dstTrackId == MP4_INVALID_TRACK_ID) {
+ return dstTrackId;
+ }
+
+ MP4SetTrackTimeScale(
+ dstFile,
+ dstTrackId,
+ MP4GetTrackTimeScale(srcFile, srcTrackId));
+
+ // copy track ES configuration
+ u_int8_t* pConfig = NULL;
+ u_int32_t configSize = 0;
+
+ MP4GetTrackESConfiguration(
+ srcFile,
+ srcTrackId,
+ &pConfig,
+ &configSize);
+
+ MP4SetTrackESConfiguration(
+ dstFile,
+ dstTrackId,
+ pConfig,
+ configSize);
+
+ free(pConfig);
+
+ if (MP4_IS_HINT_TRACK_TYPE(trackType)) {
+ // probably not exactly what is wanted
+ // but caller can adjust later to fit their desires
+
+ char* payloadName = NULL;
+ u_int8_t payloadNumber;
+ u_int16_t maxPayloadSize;
+
+ MP4GetHintTrackRtpPayload(
+ srcFile,
+ srcTrackId,
+ &payloadName,
+ &payloadNumber,
+ &maxPayloadSize);
+
+ MP4SetHintTrackRtpPayload(
+ dstFile,
+ dstTrackId,
+ payloadName,
+ &payloadNumber,
+ maxPayloadSize);
+
+ MP4SetHintTrackSdp(
+ dstFile,
+ dstTrackId,
+ MP4GetHintTrackSdp(srcFile, srcTrackId));
+ }
+
+ return dstTrackId;
+}
+
+extern "C" MP4TrackId MP4CopyTrack(
+ MP4FileHandle srcFile,
+ MP4TrackId srcTrackId,
+ MP4FileHandle dstFile,
+ bool applyEdits)
+{
+ bool copySamples = true; // LATER allow false => reference samples
+
+ MP4TrackId dstTrackId =
+ MP4CloneTrack(srcFile, srcTrackId, dstFile);
+
+ if (dstTrackId == MP4_INVALID_TRACK_ID) {
+ return dstTrackId;
+ }
+
+ bool viaEdits =
+ applyEdits && MP4GetTrackNumberOfEdits(srcFile, srcTrackId);
+
+ MP4SampleId sampleId = 0;
+ MP4SampleId numSamples =
+ MP4GetTrackNumberOfSamples(srcFile, srcTrackId);
+
+ MP4Timestamp when = 0;
+ MP4Duration editsDuration =
+ MP4GetTrackEditTotalDuration(srcFile, srcTrackId);
+
+ while (true) {
+ MP4Duration sampleDuration = MP4_INVALID_DURATION;
+
+ if (viaEdits) {
+ sampleId = MP4GetSampleIdFromEditTime(
+ srcFile,
+ srcTrackId,
+ when,
+ NULL,
+ &sampleDuration);
+
+ // in theory, this shouldn't happen
+ if (sampleId == MP4_INVALID_SAMPLE_ID) {
+ MP4DeleteTrack(dstFile, dstTrackId);
+ return MP4_INVALID_TRACK_ID;
+ }
+
+ when += sampleDuration;
+
+ if (when >= editsDuration) {
+ break;
+ }
+ } else {
+ sampleId++;
+ if (sampleId > numSamples) {
+ break;
+ }
+ }
+
+ bool rc = false;
+
+ if (copySamples) {
+ rc = MP4CopySample(
+ srcFile,
+ srcTrackId,
+ sampleId,
+ dstFile,
+ dstTrackId,
+ sampleDuration);
+
+ } else {
+ rc = MP4ReferenceSample(
+ srcFile,
+ srcTrackId,
+ sampleId,
+ dstFile,
+ dstTrackId,
+ sampleDuration);
+ }
+
+ if (!rc) {
+ MP4DeleteTrack(dstFile, dstTrackId);
+ return MP4_INVALID_TRACK_ID;
+ }
+ }
+
+ return dstTrackId;
+}
+
extern "C" bool MP4DeleteTrack(
- MP4FileHandle hFile, MP4TrackId trackId)
+ MP4FileHandle hFile,
+ MP4TrackId trackId)
{
if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
try {
@@ -737,6 +943,22 @@
return MP4_INVALID_AUDIO_TYPE;
}
+extern "C" u_int8_t MP4GetTrackAudioMpeg4Type(
+ MP4FileHandle hFile, MP4TrackId trackId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetTrackAudioMpeg4Type(trackId);
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return MP4_MPEG4_INVALID_AUDIO_TYPE;
+}
+
+
extern "C" u_int8_t MP4GetTrackVideoType(
MP4FileHandle hFile, MP4TrackId trackId)
{
@@ -767,6 +989,22 @@
return MP4_INVALID_DURATION;
}
+extern "C" u_int32_t MP4GetTrackBitRate(
+ MP4FileHandle hFile, MP4TrackId trackId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetTrackIntegerProperty(trackId,
+ "mdia.minf.stbl.stsd.*.esds.decConfigDescr.avgBitrate");
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return 0;
+}
+
extern "C" void MP4GetTrackESConfiguration(
MP4FileHandle hFile, MP4TrackId trackId,
u_int8_t** ppConfig, u_int32_t* pConfigSize)
@@ -820,6 +1058,53 @@
return 0;
}
+extern "C" u_int16_t MP4GetTrackVideoWidth(
+ MP4FileHandle hFile, MP4TrackId trackId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetTrackIntegerProperty(trackId,
+ "mdia.minf.stbl.stsd.mp4v.width");
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return 0;
+}
+
+extern "C" u_int16_t MP4GetTrackVideoHeight(
+ MP4FileHandle hFile, MP4TrackId trackId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetTrackIntegerProperty(trackId,
+ "mdia.minf.stbl.stsd.mp4v.height");
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return 0;
+}
+
+extern "C" float MP4GetTrackVideoFrameRate(
+ MP4FileHandle hFile, MP4TrackId trackId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetTrackVideoFrameRate(trackId);
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return 0.0;
+}
+
/* generic track properties */
extern "C" u_int64_t MP4GetTrackIntegerProperty(
@@ -978,8 +1263,15 @@
{
if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
try {
- ((MP4File*)hFile)->ReadSample(trackId, sampleId, ppBytes, pNumBytes,
- pStartTime, pDuration, pRenderingOffset, pIsSyncSample);
+ ((MP4File*)hFile)->ReadSample(
+ trackId,
+ sampleId,
+ ppBytes,
+ pNumBytes,
+ pStartTime,
+ pDuration,
+ pRenderingOffset,
+ pIsSyncSample);
return true;
}
catch (MP4Error* e) {
@@ -991,6 +1283,46 @@
return false;
}
+extern "C" bool MP4ReadSampleFromTime(
+ /* input parameters */
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4Timestamp when,
+ /* output parameters */
+ u_int8_t** ppBytes,
+ u_int32_t* pNumBytes,
+ MP4Timestamp* pStartTime,
+ MP4Duration* pDuration,
+ MP4Duration* pRenderingOffset,
+ bool* pIsSyncSample)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ MP4SampleId sampleId =
+ ((MP4File*)hFile)->GetSampleIdFromTime(
+ trackId, when, false);
+
+ ((MP4File*)hFile)->ReadSample(
+ trackId,
+ sampleId,
+ ppBytes,
+ pNumBytes,
+ pStartTime,
+ pDuration,
+ pRenderingOffset,
+ pIsSyncSample);
+
+ return true;
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ *pNumBytes = 0;
+ return false;
+}
+
extern "C" bool MP4WriteSample(
MP4FileHandle hFile,
MP4TrackId trackId,
@@ -1002,8 +1334,13 @@
{
if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
try {
- ((MP4File*)hFile)->WriteSample(trackId, pBytes, numBytes,
- duration, renderingOffset, isSyncSample);
+ ((MP4File*)hFile)->WriteSample(
+ trackId,
+ pBytes,
+ numBytes,
+ duration,
+ renderingOffset,
+ isSyncSample);
return true;
}
catch (MP4Error* e) {
@@ -1014,6 +1351,77 @@
return false;
}
+extern "C" bool MP4CopySample(
+ MP4FileHandle srcFile,
+ MP4TrackId srcTrackId,
+ MP4SampleId srcSampleId,
+ MP4FileHandle dstFile,
+ MP4TrackId dstTrackId,
+ MP4Duration dstSampleDuration)
+{
+ bool rc;
+ u_int8_t* pBytes = NULL;
+ u_int32_t numBytes = 0;
+ MP4Duration sampleDuration;
+ MP4Duration renderingOffset;
+ bool isSyncSample;
+
+ // Note: we leave it up to the caller to ensure that the
+ // source and destination tracks are compatible.
+ // i.e. copying audio samples into a video track
+ // is unlikely to do anything useful
+
+ rc = MP4ReadSample(
+ srcFile,
+ srcTrackId,
+ srcSampleId,
+ &pBytes,
+ &numBytes,
+ NULL,
+ &sampleDuration,
+ &renderingOffset,
+ &isSyncSample);
+
+ if (!rc) {
+ return false;
+ }
+
+ if (dstFile == MP4_INVALID_FILE_HANDLE) {
+ dstFile = srcFile;
+ }
+ if (dstTrackId == MP4_INVALID_TRACK_ID) {
+ dstTrackId = srcTrackId;
+ }
+ if (dstSampleDuration != MP4_INVALID_DURATION) {
+ sampleDuration = dstSampleDuration;
+ }
+
+ rc = MP4WriteSample(
+ dstFile,
+ dstTrackId,
+ pBytes,
+ numBytes,
+ sampleDuration,
+ renderingOffset,
+ isSyncSample);
+
+ free(pBytes);
+
+ return rc;
+}
+
+extern "C" bool MP4ReferenceSample(
+ MP4FileHandle srcFile,
+ MP4TrackId srcTrackId,
+ MP4SampleId srcSampleId,
+ MP4FileHandle dstFile,
+ MP4TrackId dstTrackId,
+ MP4Duration dstSampleDuration)
+{
+ // LATER Not yet implemented
+ return false;
+}
+
extern "C" u_int32_t MP4GetSampleSize(
MP4FileHandle hFile,
MP4TrackId trackId,
@@ -1679,8 +2087,10 @@
u_int32_t verbosity,
bool addIsmaComplianceSdp)
{
+ MP4File* pFile = NULL;
+
try {
- MP4File* pFile = new MP4File(verbosity);
+ pFile = new MP4File(verbosity);
pFile->Modify(fileName);
pFile->MakeIsmaCompliant(addIsmaComplianceSdp);
pFile->Close();
@@ -1691,7 +2101,311 @@
VERBOSE_ERROR(verbosity, e->Print());
delete e;
}
+ delete pFile;
return false;
+}
+
+extern "C" char* MP4MakeIsmaSdpIod(
+ 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_int32_t verbosity)
+{
+ MP4File* pFile = NULL;
+
+ try {
+ pFile = new MP4File(verbosity);
+
+ u_int8_t* pBytes = NULL;
+ u_int64_t numBytes = 0;
+
+ pFile->CreateIsmaIodFromParams(
+ videoProfile,
+ videoBitrate,
+ videoConfig,
+ videoConfigLength,
+ audioProfile,
+ audioBitrate,
+ audioConfig,
+ audioConfigLength,
+ &pBytes,
+ &numBytes);
+
+ char* iodBase64 =
+ MP4ToBase64(pBytes, numBytes);
+ MP4Free(pBytes);
+
+ char* sdpIod =
+ (char*)MP4Malloc(strlen(iodBase64) + 64);
+ sprintf(sdpIod,
+ "a=mpeg4-iod: \042data:application/mpeg4-iod;base64,%s\042",
+ iodBase64);
+ MP4Free(iodBase64);
+
+ delete pFile;
+
+ return sdpIod;
+ }
+ catch (MP4Error* e) {
+ VERBOSE_ERROR(verbosity, e->Print());
+ delete e;
+ }
+ delete pFile;
+ return NULL;
+}
+
+/* Edit list */
+
+extern "C" MP4EditId MP4AddTrackEdit(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId,
+ MP4Timestamp startTime,
+ MP4Duration duration,
+ bool dwell)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ MP4EditId editId =
+ ((MP4File*)hFile)->AddTrackEdit(trackId, editId);
+
+ if (editId != MP4_INVALID_EDIT_ID) {
+ ((MP4File*)hFile)->SetTrackEditMediaStart(
+ trackId, editId, startTime);
+ ((MP4File*)hFile)->SetTrackEditDuration(
+ trackId, editId, duration);
+ ((MP4File*)hFile)->SetTrackEditDwell(
+ trackId, editId, dwell);
+ }
+
+ return editId;
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return MP4_INVALID_EDIT_ID;
+}
+
+extern "C" bool MP4DeleteTrackEdit(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ ((MP4File*)hFile)->DeleteTrackEdit(trackId, editId);
+ return true;
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return false;
+}
+
+extern "C" u_int32_t MP4GetTrackNumberOfEdits(
+ MP4FileHandle hFile,
+ MP4TrackId trackId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetTrackNumberOfEdits(trackId);
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return 0;
+}
+
+extern "C" MP4Timestamp MP4GetTrackEditMediaStart(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetTrackEditMediaStart(
+ trackId, editId);
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return MP4_INVALID_TIMESTAMP;
+}
+
+extern "C" MP4Duration MP4GetTrackEditTotalDuration(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetTrackEditTotalDuration(
+ trackId, editId);
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return MP4_INVALID_DURATION;
+}
+
+extern "C" bool MP4SetTrackEditMediaStart(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId,
+ MP4Timestamp startTime)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ ((MP4File*)hFile)->SetTrackEditMediaStart(
+ trackId, editId, startTime);
+ return true;
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return false;
+}
+
+extern "C" MP4Duration MP4GetTrackEditDuration(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetTrackEditDuration(trackId, editId);
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return MP4_INVALID_DURATION;
+}
+
+extern "C" bool MP4SetTrackEditDuration(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId,
+ MP4Duration duration)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ ((MP4File*)hFile)->SetTrackEditDuration(trackId, editId, duration);
+ return true;
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return false;
+}
+
+extern "C" int8_t MP4GetTrackEditDwell(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetTrackEditDwell(trackId, editId);
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return -1;
+}
+
+extern "C" bool MP4SetTrackEditDwell(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId,
+ bool dwell)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ ((MP4File*)hFile)->SetTrackEditDwell(trackId, editId, dwell);
+ return true;
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return false;
+}
+
+extern "C" bool MP4ReadSampleFromEditTime(
+ /* input parameters */
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4Timestamp when,
+ /* output parameters */
+ u_int8_t** ppBytes,
+ u_int32_t* pNumBytes,
+ MP4Timestamp* pStartTime,
+ MP4Duration* pDuration,
+ MP4Duration* pRenderingOffset,
+ bool* pIsSyncSample)
+{
+ MP4SampleId sampleId =
+ MP4GetSampleIdFromEditTime(
+ hFile,
+ trackId,
+ when,
+ pStartTime,
+ pDuration);
+
+ return MP4ReadSample(
+ hFile,
+ trackId,
+ sampleId,
+ ppBytes,
+ pNumBytes,
+ NULL,
+ NULL,
+ pRenderingOffset,
+ pIsSyncSample);
+}
+
+extern "C" MP4SampleId MP4GetSampleIdFromEditTime(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4Timestamp when,
+ MP4Timestamp* pStartTime,
+ MP4Duration* pDuration)
+{
+ if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+ try {
+ return ((MP4File*)hFile)->GetSampleIdFromEditTime(
+ trackId, when, pStartTime, pDuration);
+ }
+ catch (MP4Error* e) {
+ PRINT_ERROR(e);
+ delete e;
+ }
+ }
+ return MP4_INVALID_SAMPLE_ID;
}
/* Utlities */
--- a/common/mp4v2/mp4.h
+++ b/common/mp4v2/mp4.h
@@ -43,6 +43,7 @@
typedef u_int32_t MP4SampleId;
typedef u_int64_t MP4Timestamp;
typedef u_int64_t MP4Duration;
+typedef u_int32_t MP4EditId;
/* Invalid values for API types */
#define MP4_INVALID_FILE_HANDLE ((MP4FileHandle)NULL)
@@ -50,6 +51,7 @@
#define MP4_INVALID_SAMPLE_ID ((MP4SampleId)0)
#define MP4_INVALID_TIMESTAMP ((MP4Timestamp)-1)
#define MP4_INVALID_DURATION ((MP4Duration)-1)
+#define MP4_INVALID_EDIT_ID ((MP4EditId)0)
/* Macros to test for API type validity */
#define MP4_IS_VALID_FILE_HANDLE(x) ((x) != MP4_INVALID_FILE_HANDLE)
@@ -57,6 +59,7 @@
#define MP4_IS_VALID_SAMPLE_ID(x) ((x) != MP4_INVALID_SAMPLE_ID)
#define MP4_IS_VALID_TIMESTAMP(x) ((x) != MP4_INVALID_TIMESTAMP)
#define MP4_IS_VALID_DURATION(x) ((x) != MP4_INVALID_DURATION)
+#define MP4_IS_VALID_EDIT_ID(x) ((x) != MP4_INVALID_EDIT_ID)
/* MP4 verbosity levels - e.g. MP4SetVerbosity() */
#define MP4_DETAILS_ALL 0xFFFFFFFF
@@ -69,6 +72,7 @@
#define MP4_DETAILS_SAMPLE 0x00000040
#define MP4_DETAILS_HINT 0x00000080
#define MP4_DETAILS_ISMA 0x00000100
+#define MP4_DETAILS_EDIT 0x00000200
#define MP4_DETAILS_READ_ALL \
(MP4_DETAILS_READ | MP4_DETAILS_TABLE | MP4_DETAILS_SAMPLE)
@@ -96,6 +100,28 @@
#define MP4_IPMP_TRACK_TYPE "ipsm"
#define MP4_MPEGJ_TRACK_TYPE "mjsm"
+#define MP4_IS_VIDEO_TRACK_TYPE(type) \
+ (!strcasecmp(type, MP4_VIDEO_TRACK_TYPE))
+
+#define MP4_IS_AUDIO_TRACK_TYPE(type) \
+ (!strcasecmp(type, MP4_AUDIO_TRACK_TYPE))
+
+#define MP4_IS_OD_TRACK_TYPE(type) \
+ (!strcasecmp(type, MP4_OD_TRACK_TYPE))
+
+#define MP4_IS_SCENE_TRACK_TYPE(type) \
+ (!strcasecmp(type, MP4_SCENE_TRACK_TYPE))
+
+#define MP4_IS_HINT_TRACK_TYPE(type) \
+ (!strcasecmp(type, MP4_HINT_TRACK_TYPE))
+
+#define MP4_IS_SYSTEMS_TRACK_TYPE(type) \
+ (!strcasecmp(type, MP4_CLOCK_TRACK_TYPE) \
+ || !strcasecmp(type, MP4_MPEG7_TRACK_TYPE) \
+ || !strcasecmp(type, MP4_OCI_TRACK_TYPE) \
+ || !strcasecmp(type, MP4_IPMP_TRACK_TYPE) \
+ || !strcasecmp(type, MP4_MPEGJ_TRACK_TYPE))
+
/* MP4 Audio track types - see MP4AddAudioTrack()*/
#define MP4_INVALID_AUDIO_TYPE 0x00
#define MP4_MPEG1_AUDIO_TYPE 0x6B
@@ -107,8 +133,42 @@
#define MP4_MPEG2_AAC_AUDIO_TYPE MP4_MPEG2_AAC_MAIN_AUDIO_TYPE
#define MP4_MPEG4_AUDIO_TYPE 0x40
#define MP4_PRIVATE_AUDIO_TYPE 0xC0
-#define MP4_PCM16_AUDIO_TYPE 0xD0 /* a private definition */
+#define MP4_PCM16_AUDIO_TYPE 0xE0 /* a private definition */
+#define MP4_VORBIS_AUDIO_TYPE 0xE1 /* a private definition */
+#define MP4_AC3_AUDIO_TYPE 0xE2 /* a private definition */
+/* MP4 MPEG-4 Audio types from 14496-3 Table 1.5.1 */
+#define MP4_MPEG4_INVALID_AUDIO_TYPE 0
+#define MP4_MPEG4_AAC_MAIN_AUDIO_TYPE 1
+#define MP4_MPEG4_AAC_LC_AUDIO_TYPE 2
+#define MP4_MPEG4_AAC_SSR_AUDIO_TYPE 3
+#define MP4_MPEG4_AAC_LTP_AUDIO_TYPE 4
+#define MP4_MPEG4_AAC_SCALABLE_AUDIO_TYPE 6
+#define MP4_MPEG4_CELP_AUDIO_TYPE 8
+#define MP4_MPEG4_HVXC_AUDIO_TYPE 9
+#define MP4_MPEG4_TTSI_AUDIO_TYPE 12
+#define MP4_MPEG4_MAIN_SYNTHETIC_AUDIO_TYPE 13
+#define MP4_MPEG4_WAVETABLE_AUDIO_TYPE 14
+#define MP4_MPEG4_MIDI_AUDIO_TYPE 15
+#define MP4_MPEG4_ALGORITHMIC_FX_AUDIO_TYPE 16
+
+/* MP4 Audio type utilities following common usage */
+#define MP4_IS_MP3_AUDIO_TYPE(type) \
+ ((type) == MP4_MPEG1_AUDIO_TYPE || (type) == MP4_MPEG2_AUDIO_TYPE)
+
+#define MP4_IS_MPEG2_AAC_AUDIO_TYPE(type) \
+ (((type) >= MP4_MPEG2_AAC_MAIN_AUDIO_TYPE \
+ && (type) <= MP4_MPEG2_AAC_SSR_AUDIO_TYPE))
+
+#define MP4_IS_MPEG4_AAC_AUDIO_TYPE(mpeg4Type) \
+ (((mpeg4Type) >= MP4_MPEG4_AAC_MAIN_AUDIO_TYPE \
+ && (mpeg4Type) <= MP4_MPEG4_AAC_LTP_AUDIO_TYPE) \
+ || (mpeg4Type) == MP4_MPEG4_AAC_SCALABLE_AUDIO_TYPE)
+
+#define MP4_IS_AAC_AUDIO_TYPE(type) \
+ (MP4_IS_MPEG2_AAC_AUDIO_TYPE(type) \
+ || (type) == MP4_MPEG4_AUDIO_TYPE)
+
/* MP4 Video track types - see MP4AddVideoTrack() */
#define MP4_INVALID_VIDEO_TYPE 0x00
#define MP4_MPEG1_VIDEO_TYPE 0x6A
@@ -121,10 +181,24 @@
#define MP4_MPEG2_VIDEO_TYPE MP4_MPEG2_MAIN_VIDEO_TYPE
#define MP4_MPEG4_VIDEO_TYPE 0x20
#define MP4_JPEG_VIDEO_TYPE 0x6C
-#define MP4_PRIVATE_VIDEO_TYPE 0xC1
-#define MP4_YUV12_VIDEO_TYPE 0xD1 /* a private definition */
+#define MP4_PRIVATE_VIDEO_TYPE 0xD0
+#define MP4_YUV12_VIDEO_TYPE 0xF0 /* a private definition */
+#define MP4_H26L_VIDEO_TYPE 0xF1 /* a private definition */
+#define MP4_H263_VIDEO_TYPE 0xF2 /* a private definition */
+/* MP4 Video type utilities */
+#define MP4_IS_MPEG1_VIDEO_TYPE(type) \
+ ((type) == MP4_MPEG1_VIDEO_TYPE)
+#define MP4_IS_MPEG2_VIDEO_TYPE(type) \
+ (((type) >= MP4_MPEG2_SIMPLE_VIDEO_TYPE \
+ && (type) <= MP4_MPEG2_442_VIDEO_TYPE) \
+ || MP4_IS_MPEG1_VIDEO_TYPE(type))
+
+#define MP4_IS_MPEG4_VIDEO_TYPE(type) \
+ ((type) == MP4_MPEG4_VIDEO_TYPE)
+
+
/* MP4 API declarations */
#ifdef __cplusplus
@@ -133,28 +207,42 @@
/* file operations */
-MP4FileHandle MP4Create(const char* fileName,
+MP4FileHandle MP4Create(
+ const char* fileName,
u_int32_t verbosity DEFAULT(0),
bool use64bits DEFAULT(0),
bool useExtensibleFormat DEFAULT(0));
-MP4FileHandle MP4Modify(const char* fileName,
+MP4FileHandle MP4Modify(
+ const char* fileName,
u_int32_t verbosity DEFAULT(0),
bool useExtensibleFormat DEFAULT(0));
-MP4FileHandle MP4Read(const char* fileName,
+MP4FileHandle MP4Read(
+ const char* fileName,
u_int32_t verbosity DEFAULT(0));
-bool MP4Close(MP4FileHandle hFile);
+bool MP4Close(
+ MP4FileHandle hFile);
-bool MP4Optimize(const char* existingFileName,
+bool MP4Optimize(
+ const char* existingFileName,
const char* newFileName DEFAULT(NULL),
u_int32_t verbosity DEFAULT(0));
-bool MP4Dump(MP4FileHandle hFile,
+bool MP4Dump(
+ MP4FileHandle hFile,
FILE* pDumpFile DEFAULT(NULL),
bool dumpImplicits DEFAULT(0));
+char* MP4Info(
+ MP4FileHandle hFile,
+ MP4TrackId trackId DEFAULT(MP4_INVALID_TRACK_ID));
+
+char* MP4FileInfo(
+ const char* fileName,
+ MP4TrackId trackId DEFAULT(MP4_INVALID_TRACK_ID));
+
/* file properties */
/* specific file properties */
@@ -192,23 +280,32 @@
/* generic file properties */
u_int64_t MP4GetIntegerProperty(
- MP4FileHandle hFile, const char* propName);
+ MP4FileHandle hFile,
+ const char* propName);
float MP4GetFloatProperty(
- MP4FileHandle hFile, const char* propName);
+ MP4FileHandle hFile,
+ const char* propName);
const char* MP4GetStringProperty(
- MP4FileHandle hFile, const char* propName);
+ MP4FileHandle hFile,
+ const char* propName);
void MP4GetBytesProperty(
- MP4FileHandle hFile, const char* propName,
- u_int8_t** ppValue, u_int32_t* pValueSize);
+ MP4FileHandle hFile,
+ const char* propName,
+ u_int8_t** ppValue,
+ u_int32_t* pValueSize);
bool MP4SetIntegerProperty(
- MP4FileHandle hFile, const char* propName, int64_t value);
+ MP4FileHandle hFile,
+ const char* propName,
+ int64_t value);
bool MP4SetFloatProperty(
- MP4FileHandle hFile, const char* propName, float value);
+ MP4FileHandle hFile,
+ const char* propName,
+ float value);
bool MP4SetStringProperty(
MP4FileHandle hFile, const char* propName, const char* value);
@@ -220,10 +317,12 @@
/* track operations */
MP4TrackId MP4AddTrack(
- MP4FileHandle hFile, const char* type);
+ MP4FileHandle hFile,
+ const char* type);
MP4TrackId MP4AddSystemsTrack(
- MP4FileHandle hFile, const char* type);
+ MP4FileHandle hFile,
+ const char* type);
MP4TrackId MP4AddODTrack(
MP4FileHandle hFile);
@@ -232,19 +331,37 @@
MP4FileHandle hFile);
MP4TrackId MP4AddAudioTrack(
- MP4FileHandle hFile, u_int32_t timeScale, u_int32_t sampleDuration,
+ MP4FileHandle hFile,
+ u_int32_t timeScale,
+ MP4Duration sampleDuration,
u_int8_t audioType DEFAULT(MP4_MPEG4_AUDIO_TYPE));
MP4TrackId MP4AddVideoTrack(
- MP4FileHandle hFile, u_int32_t timeScale, u_int32_t sampleDuration,
- u_int16_t width, u_int16_t height,
+ MP4FileHandle hFile,
+ u_int32_t timeScale,
+ MP4Duration sampleDuration,
+ u_int16_t width,
+ u_int16_t height,
u_int8_t videoType DEFAULT(MP4_MPEG4_VIDEO_TYPE));
MP4TrackId MP4AddHintTrack(
- MP4FileHandle hFile, MP4TrackId refTrackId);
+ MP4FileHandle hFile,
+ MP4TrackId refTrackId);
+MP4TrackId MP4CloneTrack(
+ MP4FileHandle srcFile,
+ MP4TrackId srcTrackId,
+ MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE));
+
+MP4TrackId MP4CopyTrack(
+ MP4FileHandle srcFile,
+ MP4TrackId srcTrackId,
+ MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE),
+ bool applyEdits DEFAULT(false));
+
bool MP4DeleteTrack(
- MP4FileHandle hFile, MP4TrackId trackId);
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
u_int32_t MP4GetNumberOfTracks(
MP4FileHandle hFile,
@@ -266,71 +383,119 @@
/* specific track properties */
const char* MP4GetTrackType(
- MP4FileHandle hFile, MP4TrackId trackId);
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
MP4Duration MP4GetTrackDuration(
- MP4FileHandle hFile, MP4TrackId trackId);
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
u_int32_t MP4GetTrackTimeScale(
- MP4FileHandle hFile, MP4TrackId trackId);
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
bool MP4SetTrackTimeScale(
- MP4FileHandle hFile, MP4TrackId trackId, u_int32_t value);
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ u_int32_t value);
u_int8_t MP4GetTrackAudioType(
- MP4FileHandle hFile, MP4TrackId trackId);
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
+u_int8_t MP4GetTrackAudioMpeg4Type(
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
+
u_int8_t MP4GetTrackVideoType(
- MP4FileHandle hFile, MP4TrackId trackId);
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
/* returns MP4_INVALID_DURATION if track samples do not have a fixed duration */
MP4Duration MP4GetTrackFixedSampleDuration(
- MP4FileHandle hFile, MP4TrackId trackId);
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
+u_int32_t MP4GetTrackBitRate(
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
+
void MP4GetTrackESConfiguration(
- MP4FileHandle hFile, MP4TrackId trackId,
- u_int8_t** ppConfig, u_int32_t* pConfigSize);
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ u_int8_t** ppConfig,
+ u_int32_t* pConfigSize);
bool MP4SetTrackESConfiguration(
- MP4FileHandle hFile, MP4TrackId trackId,
- const u_int8_t* pConfig, u_int32_t configSize);
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ const u_int8_t* pConfig,
+ u_int32_t configSize);
MP4SampleId MP4GetTrackNumberOfSamples(
- MP4FileHandle hFile, MP4TrackId trackId);
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
+u_int16_t MP4GetTrackVideoWidth(
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
+
+u_int16_t MP4GetTrackVideoHeight(
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
+
+float MP4GetTrackVideoFrameRate(
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
+
/* generic track properties */
u_int64_t MP4GetTrackIntegerProperty(
- MP4FileHandle hFile, MP4TrackId trackId,
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
const char* propName);
float MP4GetTrackFloatProperty(
- MP4FileHandle hFile, MP4TrackId trackId,
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
const char* propName);
const char* MP4GetTrackStringProperty(
- MP4FileHandle hFile, MP4TrackId trackId,
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
const char* propName);
void MP4GetTrackBytesProperty(
- MP4FileHandle hFile, MP4TrackId trackId, const char* propName,
- u_int8_t** ppValue, u_int32_t* pValueSize);
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ const char* propName,
+ u_int8_t** ppValue,
+ u_int32_t* pValueSize);
bool MP4SetTrackIntegerProperty(
- MP4FileHandle hFile, MP4TrackId trackId,
- const char* propName, int64_t value);
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ const char* propName,
+ int64_t value);
bool MP4SetTrackFloatProperty(
- MP4FileHandle hFile, MP4TrackId trackId,
- const char* propName, float value);
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ const char* propName,
+ float value);
bool MP4SetTrackStringProperty(
- MP4FileHandle hFile, MP4TrackId trackId,
- const char* propName, const char* value);
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ const char* propName,
+ const char* value);
bool MP4SetTrackBytesProperty(
- MP4FileHandle hFile, MP4TrackId trackId,
- const char* propName, const u_int8_t* pValue, u_int32_t valueSize);
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ const char* propName,
+ const u_int8_t* pValue,
+ u_int32_t valueSize);
/* sample operations */
@@ -348,6 +513,21 @@
MP4Duration* pRenderingOffset DEFAULT(NULL),
bool* pIsSyncSample DEFAULT(NULL));
+/* uses (unedited) time to specify sample instead of sample id */
+bool MP4ReadSampleFromTime(
+ /* input parameters */
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4Timestamp when,
+ /* input/output parameters */
+ u_int8_t** ppBytes,
+ u_int32_t* pNumBytes,
+ /* output parameters */
+ MP4Timestamp* pStartTime DEFAULT(NULL),
+ MP4Duration* pDuration DEFAULT(NULL),
+ MP4Duration* pRenderingOffset DEFAULT(NULL),
+ bool* pIsSyncSample DEFAULT(NULL));
+
bool MP4WriteSample(
MP4FileHandle hFile,
MP4TrackId trackId,
@@ -357,6 +537,23 @@
MP4Duration renderingOffset DEFAULT(0),
bool isSyncSample DEFAULT(true));
+bool MP4CopySample(
+ MP4FileHandle srcFile,
+ MP4TrackId srcTrackId,
+ MP4SampleId srcSampleId,
+ MP4FileHandle dstFile DEFAULT(MP4_INVALID_FILE_HANDLE),
+ MP4TrackId dstTrackId DEFAULT(MP4_INVALID_TRACK_ID),
+ MP4Duration dstSampleDuration DEFAULT(MP4_INVALID_DURATION));
+
+/* Note this function is not yet implemented */
+bool MP4ReferenceSample(
+ MP4FileHandle srcFile,
+ MP4TrackId srcTrackId,
+ MP4SampleId srcSampleId,
+ MP4FileHandle dstFile,
+ MP4TrackId dstTrackId,
+ MP4Duration dstSampleDuration DEFAULT(MP4_INVALID_DURATION));
+
u_int32_t MP4GetSampleSize(
MP4FileHandle hFile,
MP4TrackId trackId,
@@ -521,11 +718,109 @@
MP4Duration duration,
bool isSyncSample DEFAULT(true));
-/* ISMA specific operations */
+/* ISMA specific utilities */
bool MP4MakeIsmaCompliant(const char* fileName,
u_int32_t verbosity DEFAULT(0),
bool addIsmaComplianceSdp DEFAULT(true));
+
+char* MP4MakeIsmaSdpIod(
+ 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_int32_t verbosity DEFAULT(0));
+
+/* edit list */
+
+/* NOTE this section of functionality
+ * has not yet been fully tested
+ */
+
+MP4EditId MP4AddTrackEdit(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId DEFAULT(MP4_INVALID_EDIT_ID),
+ MP4Timestamp startTime DEFAULT(0),
+ MP4Duration duration DEFAULT(0),
+ bool dwell DEFAULT(false));
+
+bool MP4DeleteTrackEdit(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+u_int32_t MP4GetTrackNumberOfEdits(
+ MP4FileHandle hFile,
+ MP4TrackId trackId);
+
+MP4Timestamp MP4GetTrackEditStart(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+MP4Duration MP4GetTrackEditTotalDuration(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId DEFAULT(MP4_INVALID_EDIT_ID));
+
+MP4Timestamp MP4GetTrackEditMediaStart(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+bool MP4SetTrackEditMediaStart(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId,
+ MP4Timestamp startTime);
+
+MP4Duration MP4GetTrackEditDuration(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+bool MP4SetTrackEditDuration(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId,
+ MP4Duration duration);
+
+int8_t MP4GetTrackEditDwell(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+bool MP4SetTrackEditDwell(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4EditId editId,
+ bool dwell);
+
+bool MP4ReadSampleFromEditTime(
+ /* input parameters */
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4Timestamp when,
+ /* input/output parameters */
+ u_int8_t** ppBytes,
+ u_int32_t* pNumBytes,
+ /* output parameters */
+ MP4Timestamp* pStartTime DEFAULT(NULL),
+ MP4Duration* pDuration DEFAULT(NULL),
+ MP4Duration* pRenderingOffset DEFAULT(NULL),
+ bool* pIsSyncSample DEFAULT(NULL));
+
+MP4SampleId MP4GetSampleIdFromEditTime(
+ MP4FileHandle hFile,
+ MP4TrackId trackId,
+ MP4Timestamp when,
+ MP4Timestamp* pStartTime DEFAULT(NULL),
+ MP4Duration* pDuration DEFAULT(NULL));
/* time conversion utilties */
--- a/common/mp4v2/mp4descriptor.cpp
+++ b/common/mp4v2/mp4descriptor.cpp
@@ -108,31 +108,35 @@
for (u_int32_t i = propStartIndex;
i < propStartIndex + numProperties; i++) {
+ MP4Property* pProperty = m_pProperties[i];
+
int32_t remaining = m_size - (pFile->GetPosition() - m_start);
- if (m_pProperties[i]->GetType() == DescriptorProperty
- && remaining >= 0) {
- // place a limit on how far this sub-descriptor looks
- ((MP4DescriptorProperty*)m_pProperties[i])->SetSizeLimit(remaining);
- m_pProperties[i]->Read(pFile);
+ if (pProperty->GetType() == DescriptorProperty) {
+ if (remaining > 0) {
+ // place a limit on how far this sub-descriptor looks
+ ((MP4DescriptorProperty*)pProperty)->SetSizeLimit(remaining);
+ pProperty->Read(pFile);
+ } // else do nothing, empty descriptor
+ } else {
+ // non-descriptor property
+ if (remaining >= 0) {
+ pProperty->Read(pFile);
- } else if (remaining >= 0) {
- m_pProperties[i]->Read(pFile);
-
- if (m_pProperties[i]->GetType() == TableProperty) {
- VERBOSE_READ_TABLE(pFile->GetVerbosity(),
- printf("Read: "); m_pProperties[i]->Dump(stdout, 0, true));
+ if (pProperty->GetType() == TableProperty) {
+ VERBOSE_READ_TABLE(pFile->GetVerbosity(),
+ printf("Read: "); pProperty->Dump(stdout, 0, true));
+ } else {
+ VERBOSE_READ(pFile->GetVerbosity(),
+ printf("Read: "); pProperty->Dump(stdout, 0, true));
+ }
} else {
- VERBOSE_READ(pFile->GetVerbosity(),
- printf("Read: "); m_pProperties[i]->Dump(stdout, 0, true));
- }
-
- } else {
- VERBOSE_ERROR(pFile->GetVerbosity(),
- printf("Overran descriptor, tag %u data size %u property %u\n",
+ VERBOSE_ERROR(pFile->GetVerbosity(),
+ printf("Overran descriptor, tag %u data size %u property %u\n",
m_tag, m_size, i));
- throw new MP4Error("overran descriptor",
- "MP4Descriptor::ReadProperties");
+ throw new MP4Error("overran descriptor",
+ "MP4Descriptor::ReadProperties");
+ }
}
}
}
--- a/common/mp4v2/mp4file.cpp
+++ b/common/mp4v2/mp4file.cpp
@@ -676,7 +676,7 @@
MP4Property** ppProperty, u_int32_t* pIndex)
{
if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property", "MP4File::FindIntegerProperty");
+ throw new MP4Error("no such property - %s", "MP4File::FindIntegerProperty", name);
}
switch ((*ppProperty)->GetType()) {
@@ -687,7 +687,7 @@
case Integer64Property:
break;
default:
- throw new MP4Error("type mismatch", "MP4File::FindIntegerProperty");
+ throw new MP4Error("type mismatch - property %s type %d", "MP4File::FindIntegerProperty", name, (*ppProperty)->GetType());
}
}
@@ -717,10 +717,13 @@
MP4Property** ppProperty, u_int32_t* pIndex)
{
if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property", "MP4File::FindFloatProperty");
+ throw new MP4Error("no such property - %s", "MP4File::FindFloatProperty", name);
}
if ((*ppProperty)->GetType() != Float32Property) {
- throw new MP4Error("type mismatch", "MP4File::FindFloatProperty");
+ throw new MP4Error("type mismatch - property %s type %d",
+ "MP4File::FindFloatProperty",
+ name,
+ (*ppProperty)->GetType());
}
}
@@ -750,10 +753,11 @@
MP4Property** ppProperty, u_int32_t* pIndex)
{
if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property", "MP4File::FindStringProperty");
+ throw new MP4Error("no such property - %s", "MP4File::FindStringProperty", name);
}
if ((*ppProperty)->GetType() != StringProperty) {
- throw new MP4Error("type mismatch", "MP4File::FindStringProperty");
+ throw new MP4Error("type mismatch - property %s type %d", "MP4File::FindStringProperty",
+ name, (*ppProperty)->GetType());
}
}
@@ -783,10 +787,10 @@
MP4Property** ppProperty, u_int32_t* pIndex)
{
if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property", "MP4File::FindBytesProperty");
+ throw new MP4Error("no such property %s", "MP4File::FindBytesProperty", name);
}
if ((*ppProperty)->GetType() != BytesProperty) {
- throw new MP4Error("type mismatch", "MP4File::FindBytesProperty");
+ throw new MP4Error("type mismatch - property %s - type %d", "MP4File::FindBytesProperty", name, (*ppProperty)->GetType());
}
}
@@ -857,7 +861,7 @@
pTrakAtom->FindProperty(
"trak.mdia.mdhd.timeScale", (MP4Property**)&pInteger32Property);
ASSERT(pInteger32Property);
- pInteger32Property->SetValue(timeScale ? timeScale : 1);
+ pInteger32Property->SetValue(timeScale ? timeScale : 1000);
// now have enough to create MP4Track object
MP4Track* pTrack = NULL;
@@ -1091,8 +1095,10 @@
return trackId;
}
-MP4TrackId MP4File::AddAudioTrack(u_int32_t timeScale,
- u_int32_t sampleDuration, u_int8_t audioType)
+MP4TrackId MP4File::AddAudioTrack(
+ u_int32_t timeScale,
+ MP4Duration sampleDuration,
+ u_int8_t audioType)
{
MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale);
@@ -1133,8 +1139,11 @@
}
MP4TrackId MP4File::AddVideoTrack(
- u_int32_t timeScale, u_int32_t sampleDuration,
- u_int16_t width, u_int16_t height, u_int8_t videoType)
+ 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);
@@ -1277,28 +1286,39 @@
MP4TrackId MP4File::AllocTrackId()
{
- MP4TrackId trackId = GetIntegerProperty("moov.mvhd.nextTrackId");
+ MP4TrackId trackId =
+ GetIntegerProperty("moov.mvhd.nextTrackId");
if (trackId <= 0xFFFF) {
- SetIntegerProperty("moov.mvhd.nextTrackId", trackId + 1);
- } else {
- // extremely rare case where we need to search for a track id
- for (u_int16_t i = 1; i <= 0xFFFF; i++) {
- try {
- FindTrackIndex(i);
- }
- catch (MP4Error* e) {
- trackId = i;
- delete e;
- }
+ // check that nextTrackid is correct
+ try {
+ FindTrackIndex(trackId);
+ // ERROR, this trackId is in use
}
- // even more extreme case where mp4 file has 2^16 tracks in it
- if (trackId > 0xFFFF) {
- throw new MP4Error("too many exising tracks", "AddTrack");
+ catch (MP4Error* e) {
+ // OK, this trackId is not in use, proceed
+ delete e;
+ SetIntegerProperty("moov.mvhd.nextTrackId", trackId + 1);
+ return trackId;
}
}
- 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(
@@ -1334,7 +1354,9 @@
}
}
- throw new MP4Error("Track index doesn't exist", "FindTrackId");
+ throw new MP4Error("Track index doesn't exist - track %d type %s",
+ "FindTrackId",
+ trackIndex, type);
return MP4_INVALID_TRACK_ID; // satisfy MS compiler
}
@@ -1346,7 +1368,7 @@
}
}
- throw new MP4Error("Track id doesn't exist", "FindTrackIndex");
+ throw new MP4Error("Track id %d doesn't exist", "FindTrackIndex", trackId);
return (u_int16_t)-1; // satisfy MS compiler
}
@@ -1360,7 +1382,8 @@
}
}
- throw new MP4Error("Track id doesn't exist", "FindTrakAtomIndex");
+ throw new MP4Error("Track id %d doesn't exist", "FindTrakAtomIndex",
+ trackId);
return (u_int16_t)-1; // satisfy MS compiler
}
@@ -1649,6 +1672,32 @@
"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,
@@ -1660,6 +1709,26 @@
return m_pTracks[FindTrackIndex(trackId)]->GetFixedSampleDuration();
}
+float MP4File::GetTrackVideoFrameRate(MP4TrackId trackId)
+{
+ MP4SampleId numSamples =
+ GetTrackNumberOfSamples(trackId);
+#ifdef _WIN32
+ int64_t
+#else
+ u_int64_t
+#endif
+ msDuration =
+ ConvertFromTrackDuration(trackId,
+ GetTrackDuration(trackId), MP4_MSECS_TIME_SCALE);
+
+ if (msDuration == 0) {
+ return 0.0;
+ }
+
+ return ((double)numSamples / (double)msDuration) * MP4_MSECS_TIME_SCALE;
+}
+
void MP4File::GetTrackESConfiguration(MP4TrackId trackId,
u_int8_t** ppConfig, u_int32_t* pConfigSize)
{
@@ -2088,5 +2157,121 @@
}
return streamType;
+}
+
+// edit list
+
+char* MP4File::MakeTrackEditName(
+ MP4TrackId trackId,
+ MP4EditId editId,
+ const char* name)
+{
+ char* trakName = MakeTrackName(trackId, NULL);
+
+ static char editName[1024];
+ snprintf(editName, sizeof(editName),
+ "%s.edts.elst.entries[%u].%s",
+ trakName, editId - 1, name);
+ return editName;
+}
+
+MP4EditId MP4File::AddTrackEdit(
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ ProtectWriteOperation("AddTrackEdit");
+ return m_pTracks[FindTrackIndex(trackId)]->AddEdit(editId);
+}
+
+void MP4File::DeleteTrackEdit(
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ ProtectWriteOperation("DeleteTrackEdit");
+ m_pTracks[FindTrackIndex(trackId)]->DeleteEdit(editId);
+}
+
+u_int32_t MP4File::GetTrackNumberOfEdits(
+ MP4TrackId trackId)
+{
+ return GetTrackIntegerProperty(trackId, "edts.elst.entryCount");
+}
+
+MP4Duration MP4File::GetTrackEditTotalDuration(
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ return m_pTracks[FindTrackIndex(trackId)]->GetEditTotalDuration(editId);
+}
+
+MP4Timestamp MP4File::GetTrackEditStart(
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ return m_pTracks[FindTrackIndex(trackId)]->GetEditStart(editId);
+}
+
+MP4Timestamp MP4File::GetTrackEditMediaStart(
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ return GetIntegerProperty(
+ MakeTrackEditName(trackId, editId, "mediaTime"));
+}
+
+void MP4File::SetTrackEditMediaStart(
+ MP4TrackId trackId,
+ MP4EditId editId,
+ MP4Timestamp startTime)
+{
+ SetIntegerProperty(
+ MakeTrackEditName(trackId, editId, "mediaTime"),
+ startTime);
+}
+
+MP4Duration MP4File::GetTrackEditDuration(
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ return GetIntegerProperty(
+ MakeTrackEditName(trackId, editId, "segmentDuration"));
+}
+
+void MP4File::SetTrackEditDuration(
+ MP4TrackId trackId,
+ MP4EditId editId,
+ MP4Duration duration)
+{
+ SetIntegerProperty(
+ MakeTrackEditName(trackId, editId, "segmentDuration"),
+ duration);
+}
+
+bool MP4File::GetTrackEditDwell(
+ MP4TrackId trackId,
+ MP4EditId editId)
+{
+ return (GetIntegerProperty(
+ MakeTrackEditName(trackId, editId, "mediaRate")) == 0);
+}
+
+void MP4File::SetTrackEditDwell(
+ MP4TrackId trackId,
+ MP4EditId editId,
+ bool dwell)
+{
+ SetIntegerProperty(
+ MakeTrackEditName(trackId, editId, "mediaRate"),
+ (dwell ? 0 : 1));
+}
+
+MP4SampleId MP4File::GetSampleIdFromEditTime(
+ MP4TrackId trackId,
+ MP4Timestamp when,
+ MP4Timestamp* pStartTime,
+ MP4Duration* pDuration)
+{
+ return m_pTracks[FindTrackIndex(trackId)]->GetSampleIdFromEditTime(
+ when, pStartTime, pDuration);
}
--- a/common/mp4v2/mp4file.h
+++ b/common/mp4v2/mp4file.h
@@ -29,6 +29,7 @@
class MP4StringProperty;
class MP4BytesProperty;
class MP4Descriptor;
+class MP4DescriptorProperty;
class MP4File {
public: /* equivalent to MP4 library API */
@@ -41,7 +42,6 @@
void Modify(const char* fileName);
void Optimize(const char* orgFileName,
const char* newFileName = NULL);
- void MakeIsmaCompliant(bool addIsmaComplianceSdp = true);
void Dump(FILE* pDumpFile = NULL, bool dumpImplicits = false);
void Close();
@@ -101,7 +101,7 @@
/* track operations */
- MP4TrackId AddTrack(const char* type, u_int32_t timeScale = 1);
+ MP4TrackId AddTrack(const char* type, u_int32_t timeScale = 1000);
void DeleteTrack(MP4TrackId trackId);
u_int32_t GetNumberOfTracks(const char* type = NULL, u_int8_t subType = 0);
@@ -188,11 +188,17 @@
MP4TrackId AddSceneTrack();
- MP4TrackId AddAudioTrack(u_int32_t timeScale, u_int32_t sampleDuration,
+ MP4TrackId AddAudioTrack(
+ u_int32_t timeScale,
+ MP4Duration sampleDuration,
u_int8_t audioType);
- MP4TrackId AddVideoTrack(u_int32_t timeScale, u_int32_t sampleDuration,
- u_int16_t width, u_int16_t height, u_int8_t videoType);
+ MP4TrackId AddVideoTrack(
+ u_int32_t timeScale,
+ MP4Duration sampleDuration,
+ u_int16_t width,
+ u_int16_t height,
+ u_int8_t videoType);
MP4TrackId AddHintTrack(MP4TrackId refTrackId);
@@ -206,10 +212,13 @@
void SetTrackTimeScale(MP4TrackId trackId, u_int32_t value);
u_int8_t GetTrackAudioType(MP4TrackId trackId);
+ u_int8_t GetTrackAudioMpeg4Type(MP4TrackId trackId);
u_int8_t GetTrackVideoType(MP4TrackId trackId);
MP4Duration GetTrackFixedSampleDuration(MP4TrackId trackId);
+ float GetTrackVideoFrameRate(MP4TrackId trackId);
+
void GetTrackESConfiguration(MP4TrackId trackId,
u_int8_t** ppConfig, u_int32_t* pConfigSize);
void SetTrackESConfiguration(MP4TrackId trackId,
@@ -219,6 +228,22 @@
void SetHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString);
void AppendHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString);
+ // ISMA specific functions
+
+ void MakeIsmaCompliant(bool addIsmaComplianceSdp = true);
+
+ void 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** ppBytes,
+ u_int64_t* pNumBytes);
+
// time convenience functions
u_int64_t ConvertFromMovieDuration(
@@ -325,6 +350,65 @@
u_int8_t AllocRtpPayloadNumber();
+ // edit list related
+
+ char* MakeTrackEditName(
+ MP4TrackId trackId,
+ MP4EditId editId,
+ const char* name);
+
+ MP4EditId AddTrackEdit(
+ MP4TrackId trackId,
+ MP4EditId editId = MP4_INVALID_EDIT_ID);
+
+ void DeleteTrackEdit(
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+ u_int32_t GetTrackNumberOfEdits(
+ MP4TrackId trackId);
+
+ MP4Timestamp GetTrackEditStart(
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+ MP4Duration GetTrackEditTotalDuration(
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+ MP4Timestamp GetTrackEditMediaStart(
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+ void SetTrackEditMediaStart(
+ MP4TrackId trackId,
+ MP4EditId editId,
+ MP4Timestamp startTime);
+
+ MP4Duration GetTrackEditDuration(
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+ void SetTrackEditDuration(
+ MP4TrackId trackId,
+ MP4EditId editId,
+ MP4Duration duration);
+
+ bool GetTrackEditDwell(
+ MP4TrackId trackId,
+ MP4EditId editId);
+
+ void SetTrackEditDwell(
+ MP4TrackId trackId,
+ MP4EditId editId,
+ bool dwell);
+
+ MP4SampleId GetSampleIdFromEditTime(
+ MP4TrackId trackId,
+ MP4Timestamp when,
+ MP4Timestamp* pStartTime = NULL,
+ MP4Duration* pDuration = NULL);
+
/* end of MP4 API */
/* "protected" interface to be used only by friends in library */
@@ -463,20 +547,49 @@
u_int8_t ConvertTrackTypeToStreamType(const char* trackType);
- void CreateIsmaIod(
- MP4TrackId odTrackId, MP4TrackId sceneTrackId,
- MP4TrackId audioTrackId, MP4TrackId videoTrackId,
- u_int8_t** ppBytes, u_int64_t* pNumBytes);
+ void CreateIsmaIodFromFile(
+ MP4TrackId odTrackId,
+ MP4TrackId sceneTrackId,
+ MP4TrackId audioTrackId,
+ MP4TrackId videoTrackId,
+ u_int8_t** ppBytes,
+ u_int64_t* pNumBytes);
- void CreateIsmaODUpdateCommand(
+ MP4Descriptor* 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);
+
+ void CreateIsmaODUpdateCommandFromFileForFile(
MP4TrackId odTrackId,
- MP4TrackId audioTrackId, MP4TrackId videoTrackId,
- bool mp4FileMode,
- u_int8_t** ppBytes, u_int64_t* pNumBytes);
+ MP4TrackId audioTrackId,
+ MP4TrackId videoTrackId,
+ u_int8_t** ppBytes,
+ u_int64_t* pNumBytes);
- void CreateIsmaSceneCommand(MP4TrackId sceneTrackId,
- MP4TrackId audioTrackId, MP4TrackId videoTrackId,
- u_int8_t** ppBytes, u_int64_t* pNumBytes);
+ void CreateIsmaODUpdateCommandFromFileForStream(
+ MP4TrackId audioTrackId,
+ MP4TrackId videoTrackId,
+ u_int8_t** ppBytes,
+ u_int64_t* pNumBytes);
+
+ void CreateIsmaODUpdateCommandForStream(
+ MP4DescriptorProperty* pAudioEsdProperty,
+ MP4DescriptorProperty* pVideoEsdProperty,
+ u_int8_t** ppBytes,
+ u_int64_t* pNumBytes);
+
+ void CreateIsmaSceneCommand(
+ bool hasAudio,
+ bool hasVideo,
+ u_int8_t** ppBytes,
+ u_int64_t* pNumBytes);
protected:
char* m_fileName;
--- a/common/mp4v2/mp4file_io.cpp
+++ b/common/mp4v2/mp4file_io.cpp
@@ -164,19 +164,18 @@
void MP4File::WriteBytes(u_int8_t* pBytes, u_int32_t numBytes, FILE* pFile)
{
- WARNING(pBytes == NULL);
- WARNING(numBytes == 0);
ASSERT(m_numWriteBits == 0 || m_numWriteBits >= 8);
if (pBytes == NULL || numBytes == 0) {
return;
}
- if (pFile == NULL) {
- ASSERT(m_pFile);
- pFile = m_pFile;
- }
if (m_memoryBuffer == NULL) {
+ if (pFile == NULL) {
+ ASSERT(m_pFile);
+ pFile = m_pFile;
+ }
+
u_int32_t rc = fwrite(pBytes, 1, numBytes, pFile);
if (rc != numBytes) {
throw new MP4Error(errno, "MP4WriteBytes");
@@ -442,11 +441,11 @@
u_int32_t charLength = byteLength / charSize;
if (allowExpandedCount) {
- do {
- u_int8_t b = MIN(charLength, 255);
- WriteUInt8(b);
- charLength -= b;
- } while (charLength);
+ while (charLength >= 0xFF) {
+ WriteUInt8(0xFF);
+ charLength -= 0xFF;
+ }
+ WriteUInt8(charLength);
} else {
if (charLength > 255) {
throw new MP4Error(ERANGE, "MP4WriteCountedString");
--- /dev/null
+++ b/common/mp4v2/mp4info.cpp
@@ -1,0 +1,334 @@
+/*
+ * 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-2002. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dave Mackie [email protected]
+ */
+
+#include "mp4common.h"
+
+static char* PrintAudioInfo(
+ MP4FileHandle mp4File,
+ MP4TrackId trackId)
+{
+ static const char* mpeg4AudioNames[] = {
+ "MPEG-4 Main @ L1",
+ "MPEG-4 Main @ L2",
+ "MPEG-4 Main @ L3",
+ "MPEG-4 Main @ L4",
+ "MPEG-4 Scalable @ L1",
+ "MPEG-4 Scalable @ L2",
+ "MPEG-4 Scalable @ L3",
+ "MPEG-4 Scalable @ L4",
+ "MPEG-4 Speech @ L1",
+ "MPEG-4 Speech @ L2",
+ "MPEG-4 Synthesis @ L1",
+ "MPEG-4 Synthesis @ L2",
+ "MPEG-4 Synthesis @ L3",
+ };
+ static u_int8_t numMpeg4AudioTypes =
+ sizeof(mpeg4AudioNames) / sizeof(char*);
+
+ static u_int8_t mpegAudioTypes[] = {
+ MP4_MPEG2_AAC_MAIN_AUDIO_TYPE, // 0x66
+ MP4_MPEG2_AAC_LC_AUDIO_TYPE, // 0x67
+ MP4_MPEG2_AAC_SSR_AUDIO_TYPE, // 0x68
+ MP4_MPEG2_AUDIO_TYPE, // 0x69
+ MP4_MPEG1_AUDIO_TYPE, // 0x6B
+ MP4_PCM16_AUDIO_TYPE,
+ MP4_VORBIS_AUDIO_TYPE,
+ };
+ static const char* mpegAudioNames[] = {
+ "MPEG-2 AAC Main",
+ "MPEG-2 AAC LC",
+ "MPEG-2 AAC SSR",
+ "MPEG-2 (MP3)",
+ "MPEG-1 (MP3)",
+ "PCM16",
+ "OGG VORBIS",
+ };
+ static u_int8_t numMpegAudioTypes =
+ sizeof(mpegAudioTypes) / sizeof(u_int8_t);
+
+ u_int8_t type =
+ MP4GetTrackAudioType(mp4File, trackId);
+ const char* typeName = "Unknown";
+
+ if (type == MP4_MPEG4_AUDIO_TYPE) {
+ type = MP4GetAudioProfileLevel(mp4File);
+ if (type > 0 && type <= numMpeg4AudioTypes) {
+ typeName = mpeg4AudioNames[type - 1];
+ } else {
+ typeName = "MPEG-4";
+ }
+ } else {
+ for (u_int8_t i = 0; i < numMpegAudioTypes; i++) {
+ if (type == mpegAudioTypes[i]) {
+ typeName = mpegAudioNames[i];
+ break;
+ }
+ }
+ }
+
+ u_int32_t timeScale =
+ MP4GetTrackTimeScale(mp4File, trackId);
+
+ MP4Duration trackDuration =
+ MP4GetTrackDuration(mp4File, trackId);
+
+ double msDuration =
+#ifdef _WIN32
+ (int64_t)
+#endif
+ MP4ConvertFromTrackDuration(mp4File, trackId,
+ trackDuration, MP4_MSECS_TIME_SCALE);
+
+ u_int32_t avgBitRate =
+ MP4GetTrackBitRate(mp4File, trackId);
+
+ char *sInfo = (char*)MP4Malloc(256);
+
+ // type duration avgBitrate samplingFrequency
+ sprintf(sInfo,
+ "%u\taudio\t%s, %.3f secs, %u kbps, %u Hz\n",
+ trackId,
+ typeName,
+ msDuration / 1000.0,
+ (avgBitRate + 500) / 1000,
+ timeScale);
+
+ return sInfo;
+}
+
+static char* PrintVideoInfo(
+ MP4FileHandle mp4File,
+ MP4TrackId trackId)
+{
+ static const char* mpeg4VideoNames[] = {
+ "MPEG-4 Simple @ L3",
+ "MPEG-4 Simple @ L2",
+ "MPEG-4 Simple @ L1",
+ "MPEG-4 Simple Scalable @ L2",
+ "MPEG-4 Simple Scalable @ L1",
+ "MPEG-4 Core @ L2",
+ "MPEG-4 Core @ L1",
+ "MPEG-4 Main @ L4",
+ "MPEG-4 Main @ L3",
+ "MPEG-4 Main @ L2",
+ "MPEG-4 Main @ L1",
+ "MPEG-4 N-Bit @ L2",
+ "MPEG-4 Hybrid @ L2",
+ "MPEG-4 Hybrid @ L1",
+ "MPEG-4 Hybrid @ L1",
+ };
+ static u_int8_t numMpeg4VideoTypes =
+ sizeof(mpeg4VideoNames) / sizeof(char*);
+
+ static u_int8_t mpegVideoTypes[] = {
+ MP4_MPEG2_SIMPLE_VIDEO_TYPE, // 0x60
+ MP4_MPEG2_MAIN_VIDEO_TYPE, // 0x61
+ MP4_MPEG2_SNR_VIDEO_TYPE, // 0x62
+ MP4_MPEG2_SPATIAL_VIDEO_TYPE, // 0x63
+ MP4_MPEG2_HIGH_VIDEO_TYPE, // 0x64
+ MP4_MPEG2_442_VIDEO_TYPE, // 0x65
+ MP4_MPEG1_VIDEO_TYPE, // 0x6A
+ MP4_JPEG_VIDEO_TYPE, // 0x6C
+ MP4_YUV12_VIDEO_TYPE,
+ MP4_H26L_VIDEO_TYPE
+ };
+ static const char* mpegVideoNames[] = {
+ "MPEG-2 Simple",
+ "MPEG-2 Main",
+ "MPEG-2 SNR",
+ "MPEG-2 Spatial",
+ "MPEG-2 High",
+ "MPEG-2 4:2:2",
+ "MPEG-1",
+ "JPEG",
+ "YUV12",
+ "H26L"
+ };
+ static u_int8_t numMpegVideoTypes =
+ sizeof(mpegVideoTypes) / sizeof(u_int8_t);
+
+ u_int8_t type =
+ MP4GetTrackVideoType(mp4File, trackId);
+ const char* typeName = "Unknown";
+
+ if (type == MP4_MPEG4_VIDEO_TYPE) {
+ type = MP4GetVideoProfileLevel(mp4File);
+ if (type > 0 && type <= numMpeg4VideoTypes) {
+ typeName = mpeg4VideoNames[type - 1];
+ } else {
+ typeName = "MPEG-4";
+ }
+ } else {
+ for (u_int8_t i = 0; i < numMpegVideoTypes; i++) {
+ if (type == mpegVideoTypes[i]) {
+ typeName = mpegVideoNames[i];
+ break;
+ }
+ }
+ }
+
+ MP4Duration trackDuration =
+ MP4GetTrackDuration(mp4File, trackId);
+
+ double msDuration =
+#ifdef _WIN32
+ (int64_t)
+#endif
+ MP4ConvertFromTrackDuration(mp4File, trackId,
+ trackDuration, MP4_MSECS_TIME_SCALE);
+
+ u_int32_t avgBitRate =
+ MP4GetTrackBitRate(mp4File, trackId);
+
+ // Note not all mp4 implementations set width and height correctly
+ // The real answer can be buried inside the ES configuration info
+ u_int16_t width = MP4GetTrackVideoWidth(mp4File, trackId);
+
+ u_int16_t height = MP4GetTrackVideoHeight(mp4File, trackId);
+
+ float fps = MP4GetTrackVideoFrameRate(mp4File, trackId);
+
+ char *sInfo = (char*)MP4Malloc(256);
+
+ // type duration avgBitrate frameSize frameRate
+ sprintf(sInfo,
+ "%u\tvideo\t%s, %.3f secs, %u kbps, %ux%u @ %.2f fps\n",
+ trackId,
+ typeName,
+ msDuration / 1000.0,
+ (avgBitRate + 500) / 1000,
+ width,
+ height,
+ fps
+ );
+
+ return sInfo;
+}
+
+static char* PrintHintInfo(
+ MP4FileHandle mp4File,
+ MP4TrackId trackId)
+{
+ MP4TrackId referenceTrackId =
+ MP4GetHintTrackReferenceTrackId(mp4File, trackId);
+
+ char* payloadName = NULL;
+ MP4GetHintTrackRtpPayload(mp4File, trackId, &payloadName);
+
+ char *sInfo = (char*)MP4Malloc(256);
+
+ sprintf(sInfo,
+ "%u\thint\tPayload %s for track %u\n",
+ trackId,
+ payloadName,
+ referenceTrackId);
+
+ free(payloadName);
+
+ return sInfo;
+}
+
+static char* PrintTrackInfo(
+ MP4FileHandle mp4File,
+ MP4TrackId trackId)
+{
+ char* trackInfo = NULL;
+
+ const char* trackType =
+ MP4GetTrackType(mp4File, trackId);
+
+ if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)) {
+ trackInfo = PrintAudioInfo(mp4File, trackId);
+ } else if (!strcmp(trackType, MP4_VIDEO_TRACK_TYPE)) {
+ trackInfo = PrintVideoInfo(mp4File, trackId);
+ } else if (!strcmp(trackType, MP4_HINT_TRACK_TYPE)) {
+ trackInfo = PrintHintInfo(mp4File, trackId);
+ } else {
+ trackInfo = (char*)MP4Malloc(256);
+ if (!strcmp(trackType, MP4_OD_TRACK_TYPE)) {
+ sprintf(trackInfo,
+ "%u\tod\tObject Descriptors\n",
+ trackId);
+ } else if (!strcmp(trackType, MP4_SCENE_TRACK_TYPE)) {
+ sprintf(trackInfo,
+ "%u\tscene\tBIFS\n",
+ trackId);
+ } else {
+ sprintf(trackInfo,
+ "%u\t%s\n",
+ trackId, trackType);
+ }
+ }
+
+ return trackInfo;
+}
+
+extern "C" char* MP4Info(
+ MP4FileHandle mp4File,
+ MP4TrackId trackId)
+{
+ char* info = NULL;
+
+ if (MP4_IS_VALID_FILE_HANDLE(mp4File)) {
+ try {
+ if (trackId == MP4_INVALID_TRACK_ID) {
+ info = (char*)MP4Calloc(4*1024);
+
+ sprintf(info, "Track\tType\tInfo\n");
+
+ u_int32_t numTracks = MP4GetNumberOfTracks(mp4File);
+
+ for (u_int32_t i = 0; i < numTracks; i++) {
+ trackId = MP4FindTrackId(mp4File, i);
+ char* trackInfo = PrintTrackInfo(mp4File, trackId);
+ strcat(info, trackInfo);
+ MP4Free(trackInfo);
+ }
+ } else {
+ info = PrintTrackInfo(mp4File, trackId);
+ }
+ }
+ catch (MP4Error* e) {
+ delete e;
+ }
+ }
+
+ return info;
+}
+
+extern "C" char* MP4FileInfo(
+ const char* fileName,
+ MP4TrackId trackId)
+{
+ MP4FileHandle mp4File =
+ MP4Read(fileName);
+
+ if (!mp4File) {
+ return NULL;
+ }
+
+ char* info = MP4Info(mp4File, trackId);
+
+ MP4Close(mp4File);
+
+ return info; // caller should free this
+}
+
--- a/common/mp4v2/mp4property.cpp
+++ b/common/mp4v2/mp4property.cpp
@@ -92,8 +92,54 @@
}
}
-void MP4IntegerProperty::IncrementValue(u_int32_t increment, u_int32_t index)
+void MP4IntegerProperty::InsertValue(u_int64_t value, u_int32_t index)
{
+ switch (this->GetType()) {
+ case Integer8Property:
+ ((MP4Integer8Property*)this)->InsertValue(value, index);
+ break;
+ case Integer16Property:
+ ((MP4Integer16Property*)this)->InsertValue(value, index);
+ break;
+ case Integer24Property:
+ ((MP4Integer24Property*)this)->InsertValue(value, index);
+ break;
+ case Integer32Property:
+ ((MP4Integer32Property*)this)->InsertValue(value, index);
+ break;
+ case Integer64Property:
+ ((MP4Integer64Property*)this)->InsertValue(value, index);
+ break;
+ default:
+ ASSERT(FALSE);
+ }
+}
+
+void MP4IntegerProperty::DeleteValue(u_int32_t index)
+{
+ switch (this->GetType()) {
+ case Integer8Property:
+ ((MP4Integer8Property*)this)->DeleteValue(index);
+ break;
+ case Integer16Property:
+ ((MP4Integer16Property*)this)->DeleteValue(index);
+ break;
+ case Integer24Property:
+ ((MP4Integer24Property*)this)->DeleteValue(index);
+ break;
+ case Integer32Property:
+ ((MP4Integer32Property*)this)->DeleteValue(index);
+ break;
+ case Integer64Property:
+ ((MP4Integer64Property*)this)->DeleteValue(index);
+ break;
+ default:
+ ASSERT(FALSE);
+ }
+}
+
+void MP4IntegerProperty::IncrementValue(int32_t increment, u_int32_t index)
+{
SetValue(GetValue() + increment);
}
@@ -189,7 +235,7 @@
}
fprintf(pFile,
#ifdef WIN32
- "%s = "LLU" (0x%0*I64) <%u bits>\n",
+ "%s = "LLU" (0x%0*I64x) <%u bits>\n",
#else
"%s = "LLU" (0x%0*llx) <%u bits>\n",
#endif
@@ -428,7 +474,6 @@
return;
}
MP4Free(m_values[index]);
- WARNING(m_valueSizes[index] == 0);
m_values[index] = (u_int8_t*)MP4Malloc(m_valueSizes[index]);
pFile->ReadBytes(m_values[index], m_valueSizes[index]);
}
@@ -438,8 +483,6 @@
if (m_implicit) {
return;
}
- WARNING(m_values[index] == NULL);
- WARNING(m_valueSizes[index] == 0);
pFile->WriteBytes(m_values[index], m_valueSizes[index]);
}
@@ -756,7 +799,8 @@
u_int64_t start = pFile->GetPosition();
while (true) {
- if (m_sizeLimit && pFile->GetPosition() > start + m_sizeLimit) {
+ // enforce size limitation
+ if (m_sizeLimit && pFile->GetPosition() >= start + m_sizeLimit) {
break;
}
--- a/common/mp4v2/mp4property.h
+++ b/common/mp4v2/mp4property.h
@@ -108,7 +108,11 @@
void SetValue(u_int64_t value, u_int32_t index = 0);
- void IncrementValue(u_int32_t increment = 1, u_int32_t index = 0);
+ void InsertValue(u_int64_t value, u_int32_t index = 0);
+
+ void DeleteValue(u_int32_t index = 0);
+
+ void IncrementValue(int32_t increment = 1, u_int32_t index = 0);
};
#define MP4INTEGER_PROPERTY_DECL2(isize, xsize) \
@@ -500,6 +504,10 @@
}
MP4Descriptor* AddDescriptor(u_int8_t tag);
+
+ void AppendDescriptor(MP4Descriptor* pDescriptor) {
+ m_pDescriptors.Add(pDescriptor);
+ }
void DeleteDescriptor(u_int32_t index);
--- a/common/mp4v2/mp4track.cpp
+++ b/common/mp4v2/mp4track.cpp
@@ -184,6 +184,9 @@
(MP4Property**)&m_pStssSampleProperty);
}
+ // edit list
+ InitEditListProperties();
+
// was everything found?
if (!success) {
throw new MP4Error("invalid track", "MP4Track::MP4Track");
@@ -342,14 +345,10 @@
printf("WriteSample: track %u id %u size %u (0x%x) ",
m_trackId, m_writeSampleId, numBytes, numBytes));
- if (pBytes == NULL) {
+ if (pBytes == NULL && numBytes > 0) {
throw new MP4Error("no sample data", "MP4WriteSample");
}
- if (numBytes == 0) {
- throw new MP4Error("sample size is zero", "MP4WriteSample");
- }
-
if (duration == MP4_INVALID_DURATION) {
duration = GetFixedSampleDuration();
}
@@ -522,7 +521,7 @@
u_int32_t fixedSampleSize =
m_pStszFixedSampleSizeProperty->GetValue();
- if (numBytes != fixedSampleSize) {
+ if (fixedSampleSize == 0 || numBytes != fixedSampleSize) {
// sample size is not fixed
if (fixedSampleSize) {
@@ -825,7 +824,8 @@
}
MP4SampleId MP4Track::GetSampleIdFromTime(
- MP4Timestamp when, bool wantSyncSample)
+ MP4Timestamp when,
+ bool wantSyncSample)
{
u_int32_t numStts = m_pSttsCountProperty->GetValue();
MP4SampleId sid = 1;
@@ -849,9 +849,6 @@
MP4SampleId sampleId = sid;
if (sampleDelta) {
sampleId += (d / sampleDelta);
- if (d % sampleDelta) {
- sampleId++;
- }
}
if (wantSyncSample) {
@@ -1361,5 +1358,260 @@
}
return type;
+}
+
+bool MP4Track::InitEditListProperties()
+{
+ m_pElstCountProperty = NULL;
+ m_pElstMediaTimeProperty = NULL;
+ m_pElstDurationProperty = NULL;
+ m_pElstRateProperty = NULL;
+ m_pElstReservedProperty = NULL;
+
+ MP4Atom* pElstAtom =
+ m_pTrakAtom->FindAtom("trak.edts.elst");
+
+ if (!pElstAtom) {
+ return false;
+ }
+
+ pElstAtom->FindProperty(
+ "elst.entryCount",
+ (MP4Property**)&m_pElstCountProperty);
+
+ pElstAtom->FindProperty(
+ "elst.entries.mediaTime",
+ (MP4Property**)&m_pElstMediaTimeProperty);
+
+ pElstAtom->FindProperty(
+ "elst.entries.segmentDuration",
+ (MP4Property**)&m_pElstDurationProperty);
+
+ pElstAtom->FindProperty(
+ "elst.entries.mediaRate",
+ (MP4Property**)&m_pElstRateProperty);
+
+ pElstAtom->FindProperty(
+ "elst.entries.reserved",
+ (MP4Property**)&m_pElstReservedProperty);
+
+ return m_pElstCountProperty
+ && m_pElstMediaTimeProperty
+ && m_pElstDurationProperty
+ && m_pElstRateProperty
+ && m_pElstReservedProperty;
+}
+
+MP4EditId MP4Track::AddEdit(MP4EditId editId)
+{
+ if (!m_pElstCountProperty) {
+ m_pFile->AddDescendantAtoms(m_pTrakAtom, "edts.elst");
+ InitEditListProperties();
+ }
+
+ if (editId == MP4_INVALID_EDIT_ID) {
+ editId = m_pElstCountProperty->GetValue() + 1;
+ }
+
+ m_pElstMediaTimeProperty->InsertValue(0, editId - 1);
+ m_pElstDurationProperty->InsertValue(0, editId - 1);
+ m_pElstRateProperty->InsertValue(1, editId - 1);
+ m_pElstReservedProperty->InsertValue(0, editId - 1);
+
+ m_pElstCountProperty->IncrementValue();
+
+ return editId;
+}
+
+void MP4Track::DeleteEdit(MP4EditId editId)
+{
+ if (editId == MP4_INVALID_EDIT_ID) {
+ throw new MP4Error("edit id can't be zero",
+ "MP4Track::DeleteEdit");
+ }
+
+ if (!m_pElstCountProperty
+ || m_pElstCountProperty->GetValue() == 0) {
+ throw new MP4Error("no edits exist",
+ "MP4Track::DeleteEdit");
+ }
+
+ m_pElstMediaTimeProperty->DeleteValue(editId - 1);
+ m_pElstDurationProperty->DeleteValue(editId - 1);
+ m_pElstRateProperty->DeleteValue(editId - 1);
+ m_pElstReservedProperty->DeleteValue(editId - 1);
+
+ m_pElstCountProperty->IncrementValue(-1);
+
+ // clean up if last edit is deleted
+ if (m_pElstCountProperty->GetValue() == 0) {
+ m_pElstCountProperty = NULL;
+ m_pElstMediaTimeProperty = NULL;
+ m_pElstDurationProperty = NULL;
+ m_pElstRateProperty = NULL;
+ m_pElstReservedProperty = NULL;
+
+ m_pTrakAtom->DeleteChildAtom(
+ m_pTrakAtom->FindAtom("trak.edts"));
+ }
+}
+
+MP4Timestamp MP4Track::GetEditStart(
+ MP4EditId editId)
+{
+ if (editId == MP4_INVALID_EDIT_ID) {
+ return MP4_INVALID_TIMESTAMP;
+ } else if (editId == 1) {
+ return 0;
+ }
+ return (MP4Timestamp)GetEditTotalDuration(editId - 1);
+}
+
+MP4Duration MP4Track::GetEditTotalDuration(
+ MP4EditId editId)
+{
+ u_int32_t numEdits = 0;
+
+ if (m_pElstCountProperty) {
+ numEdits = m_pElstCountProperty->GetValue();
+ }
+
+ if (editId == MP4_INVALID_EDIT_ID) {
+ editId = numEdits;
+ }
+
+ if (numEdits == 0 || editId > numEdits) {
+ return MP4_INVALID_DURATION;
+ }
+
+ MP4Duration totalDuration = 0;
+
+ for (MP4EditId eid = 1; eid <= editId; eid++) {
+ totalDuration +=
+ m_pElstDurationProperty->GetValue(eid - 1);
+ }
+
+ return totalDuration;
+}
+
+MP4SampleId MP4Track::GetSampleIdFromEditTime(
+ MP4Timestamp editWhen,
+ MP4Timestamp* pStartTime,
+ MP4Duration* pDuration)
+{
+ MP4SampleId sampleId = MP4_INVALID_SAMPLE_ID;
+ u_int32_t numEdits = 0;
+
+ if (m_pElstCountProperty) {
+ numEdits = m_pElstCountProperty->GetValue();
+ }
+
+ if (numEdits) {
+ MP4Duration editElapsedDuration = 0;
+
+ for (MP4EditId editId = 1; editId <= numEdits; editId++) {
+ // remember edit segment's start time (in edit timeline)
+ MP4Timestamp editStartTime =
+ (MP4Timestamp)editElapsedDuration;
+
+ // accumulate edit segment's duration
+ editElapsedDuration +=
+ m_pElstDurationProperty->GetValue(editId - 1);
+
+ // calculate difference between the specified edit time
+ // and the end of this edit segment
+ if (editElapsedDuration - editWhen <= 0) {
+ // the specified time has not yet been reached
+ continue;
+ }
+
+ // 'editWhen' is within this edit segment
+
+ // calculate the specified edit time
+ // relative to just this edit segment
+ MP4Duration editOffset =
+ editWhen - editStartTime;
+
+ // calculate the media (track) time that corresponds
+ // to the specified edit time based on the edit list
+ MP4Timestamp mediaWhen =
+ m_pElstMediaTimeProperty->GetValue(editId - 1)
+ + editOffset;
+
+ // lookup the sample id for the media time
+ sampleId = GetSampleIdFromTime(mediaWhen, false);
+
+ // lookup the sample's media start time and duration
+ MP4Timestamp sampleStartTime;
+ MP4Duration sampleDuration;
+
+ GetSampleTimes(sampleId, &sampleStartTime, &sampleDuration);
+
+ // calculate the difference if any between when the sample
+ // would naturally start and when it starts in the edit timeline
+ MP4Duration sampleStartOffset =
+ mediaWhen - sampleStartTime;
+
+ // calculate the start time for the sample in the edit time line
+ MP4Timestamp editSampleStartTime =
+ editWhen - MIN(editOffset, sampleStartOffset);
+
+ MP4Duration editSampleDuration = 0;
+
+ // calculate how long this sample lasts in the edit list timeline
+ if (m_pElstRateProperty->GetValue(editId - 1) == 0) {
+ // edit segment is a "dwell"
+ // so sample duration is that of the edit segment
+ editSampleDuration =
+ m_pElstDurationProperty->GetValue(editId - 1);
+
+ } else {
+ // begin with the natural sample duration
+ editSampleDuration = sampleDuration;
+
+ // now shorten that if the edit segment starts
+ // after the sample would naturally start
+ if (editOffset < sampleStartOffset) {
+ editSampleDuration -= sampleStartOffset - editOffset;
+ }
+
+ // now shorten that if the edit segment ends
+ // before the sample would naturally end
+ if (editElapsedDuration
+ < editSampleStartTime + sampleDuration) {
+ editSampleDuration -= (editSampleStartTime + sampleDuration)
+ - editElapsedDuration;
+ }
+ }
+
+ if (pStartTime) {
+ *pStartTime = editSampleStartTime;
+ }
+
+ if (pDuration) {
+ *pDuration = editSampleDuration;
+ }
+
+ VERBOSE_EDIT(m_pFile->GetVerbosity(),
+ printf("GetSampleIdFromEditTime: when %llu "
+ "sampleId %u start %llu duration %lld\n",
+ editWhen, sampleId,
+ editSampleStartTime, editSampleDuration));
+
+ return sampleId;
+ }
+
+ throw new MP4Error("time out of range",
+ "MP4Track::GetSampleIdFromEditTime");
+
+ } else { // no edit list
+ sampleId = GetSampleIdFromTime(editWhen, false);
+
+ if (pStartTime || pDuration) {
+ GetSampleTimes(sampleId, pStartTime, pDuration);
+ }
+ }
+
+ return sampleId;
}
--- a/common/mp4v2/mp4track.h
+++ b/common/mp4v2/mp4track.h
@@ -29,6 +29,7 @@
class MP4Atom;
class MP4Property;
class MP4IntegerProperty;
+class MP4Integer16Property;
class MP4Integer32Property;
class MP4Integer64Property;
class MP4StringProperty;
@@ -92,7 +93,8 @@
bool IsSyncSample(MP4SampleId sampleId);
- MP4SampleId GetSampleIdFromTime(MP4Timestamp when,
+ MP4SampleId GetSampleIdFromTime(
+ MP4Timestamp when,
bool wantSyncSample = false);
MP4Duration GetSampleRenderingOffset(MP4SampleId sampleId);
@@ -99,6 +101,23 @@
void SetSampleRenderingOffset(MP4SampleId sampleId,
MP4Duration renderingOffset);
+ MP4EditId AddEdit(
+ MP4EditId editId = MP4_INVALID_EDIT_ID);
+
+ void DeleteEdit(
+ MP4EditId editId);
+
+ MP4Timestamp GetEditStart(
+ MP4EditId editId);
+
+ MP4Timestamp GetEditTotalDuration(
+ MP4EditId editId);
+
+ MP4SampleId GetSampleIdFromEditTime(
+ MP4Timestamp editWhen,
+ MP4Timestamp* pStartTime = NULL,
+ MP4Duration* pDuration = NULL);
+
static const char* NormalizeTrackType(const char* type);
// special operation for use during hint track packet assembly
@@ -121,6 +140,8 @@
u_int8_t* pChunk, u_int32_t chunkSize);
protected:
+ bool InitEditListProperties();
+
FILE* GetSampleFile(MP4SampleId sampleId);
u_int64_t GetSampleFileOffset(MP4SampleId sampleId);
u_int32_t GetSampleStscIndex(MP4SampleId sampleId);
@@ -194,7 +215,7 @@
MP4Integer32Property* m_pStscFirstSampleProperty;
MP4Integer32Property* m_pChunkCountProperty;
- MP4IntegerProperty* m_pChunkOffsetProperty; // 32 or 64 bits
+ MP4IntegerProperty* m_pChunkOffsetProperty; // 32 or 64 bits
MP4Integer32Property* m_pSttsCountProperty;
MP4Integer32Property* m_pSttsSampleCountProperty;
@@ -206,6 +227,12 @@
MP4Integer32Property* m_pStssCountProperty;
MP4Integer32Property* m_pStssSampleProperty;
+
+ MP4Integer32Property* m_pElstCountProperty;
+ MP4IntegerProperty* m_pElstMediaTimeProperty; // 32 or 64 bits
+ MP4IntegerProperty* m_pElstDurationProperty; // 32 or 64 bits
+ MP4Integer16Property* m_pElstRateProperty;
+ MP4Integer16Property* m_pElstReservedProperty;
};
MP4ARRAY_DECL(MP4Track, MP4Track*);
--- a/common/mp4v2/mp4util.cpp
+++ b/common/mp4v2/mp4util.cpp
@@ -230,7 +230,7 @@
}
// final resort is to use floating point
- double d = (double)newTimeScale / (double)oldTimeScale;
+ double d = ((double)newTimeScale / (double)oldTimeScale) + 0.5;
#ifdef _WINDOWS
d *= (double)(int64_t)t;
#else
--- a/common/mp4v2/mp4util.h
+++ b/common/mp4v2/mp4util.h
@@ -21,16 +21,25 @@
#ifndef __MP4_UTIL_INCLUDED__
#define __MP4_UTIL_INCLUDED__
-
#include <assert.h>
+#ifndef ASSERT
#ifdef NDEBUG
#define ASSERT(expr)
+#else
+#define ASSERT(expr) \
+ if (!(expr)) { \
+ fflush(stdout); \
+ assert((expr)); \
+ }
+#endif
+#endif
+#ifdef NDEBUG
#define WARNING(expr)
#else
-#define ASSERT(expr) assert(expr)
#define WARNING(expr) \
if (expr) { \
+ fflush(stdout); \
fprintf(stderr, "Warning (%s) in %s at line %u\n", \
__STRING(expr), __FILE__, __LINE__); \
}
@@ -75,6 +84,9 @@
#define VERBOSE_ISMA(verbosity, expr) \
VERBOSE(MP4_DETAILS_ISMA, verbosity, expr)
+#define VERBOSE_EDIT(verbosity, expr) \
+ VERBOSE(MP4_DETAILS_EDIT, verbosity, expr)
+
inline void Indent(FILE* pFile, u_int8_t depth) {
fprintf(pFile, "%*c", depth, ' ');
}
@@ -93,25 +105,56 @@
m_errno = 0;
m_errstring = NULL;
m_where = NULL;
+ m_free = 0;
}
+ ~MP4Error() {
+ if (m_free != 0) {
+ free((void *)m_errstring);
+ }
+ }
MP4Error(int err, const char* where = NULL) {
m_errno = err;
m_errstring = NULL;
m_where = where;
+ m_free = 0;
}
- MP4Error(const char* errstring, const char* where = NULL) {
- m_errno = 0;
- m_errstring = errstring;
- m_where = where;
+ MP4Error(const char *format, const char *where, ...) {
+ char *string;
+ m_errno = 0;
+ string = (char *)malloc(512);
+ m_where = where;
+ if (string) {
+ va_list ap;
+ va_start(ap, where);
+ vsnprintf(string, 512, format, ap);
+ va_end(ap);
+ m_errstring = string;
+ m_free = 1;
+ } else {
+ m_errstring = format;
+ m_free = 0;
+ }
}
- MP4Error(int err, const char* errstring, const char* where) {
- m_errno = err;
- m_errstring = errstring;
- m_where = where;
+ MP4Error(int err, const char* format, const char* where, ...) {
+ char *string;
+ m_errno = err;
+ string = (char *)malloc(512);
+ m_where = where;
+ if (string) {
+ va_list ap;
+ va_start(ap, where);
+ vsnprintf(string, 512, format, ap);
+ va_end(ap);
+ m_errstring = string;
+ m_free = 1;
+ } else {
+ m_errstring = format;
+ m_free = 0;
+ }
}
void Print(FILE* pFile = stderr);
-
+ int m_free;
int m_errno;
const char* m_errstring;
const char* m_where;
--- a/common/mp4v2/rtphint.cpp
+++ b/common/mp4v2/rtphint.cpp
@@ -536,7 +536,7 @@
"MP4RtpAddESConfigurationPacket");
}
- AddPacket(true);
+ AddPacket(false);
MP4RtpPacket* pPacket = m_pWriteHint->GetCurrentPacket();
ASSERT(pPacket);
--- a/common/mp4v2/systems.h
+++ b/common/mp4v2/systems.h
@@ -23,7 +23,7 @@
#ifndef __SYSTEMS_H__
#define __SYSTEMS_H__
-#ifdef _WIN32
+#ifdef WIN32
#define HAVE_IN_PORT_T
#define HAVE_SOCKLEN_T
#include <win32_ver.h>
@@ -34,7 +34,7 @@
-#ifdef _WIN32
+#ifdef WIN32
#define _WIN32_WINNT 0x0400
#include <windows.h>
@@ -51,7 +51,7 @@
typedef unsigned __int64 u_int64_t;
typedef unsigned __int32 u_int32_t;
typedef unsigned __int16 u_int16_t;
-typedef unsigned char u_int8_t;
+typedef unsigned __int8 u_int8_t;
typedef __int64 int64_t;
typedef __int32 int32_t;
typedef __int16 int16_t;
@@ -72,6 +72,7 @@
#define close _close
#define open _open
#define access _access
+#define vsnprintf _vsnprintf
#define F_OK 0
#define OPEN_RDWR (_O_RDWR | _O_BINARY)
#define OPEN_CREAT (_O_CREAT | _O_BINARY)
@@ -170,7 +171,6 @@
#else
#define FPOS_TO_VAR(fpos, typed, var) (var) = (typed)(fpos)
#define VAR_TO_FPOS(fpos, var) (fpos) = (var)
-
#endif
#define FOPEN_READ_BINARY "r"
@@ -182,7 +182,10 @@
const char *lib,
const char *fmt,
va_list ap);
-
+typedef void (*lib_message_func_t)(int loglevel,
+ const char *lib,
+ const char *fmt,
+ ...);
#ifndef HAVE_IN_PORT_T
typedef uint16_t in_port_t;
#endif
@@ -222,4 +225,46 @@
#define INADDR_NONE (-1)
#endif
+#define MALLOC_STRUCTURE(a) ((a *)malloc(sizeof(a)))
+
+#ifndef HAVE_GLIB_H
+typedef char gchar;
+typedef unsigned char guchar;
+
+typedef int gint;
+typedef unsigned int guint;
+
+typedef long glong;
+typedef unsigned long gulong;
+
+typedef double gdouble;
+
+typedef int gboolean;
+
+typedef int16_t gint16;
+typedef uint16_t guint16;
+
+typedef int32_t gint32;
+typedef uint32_t guint32;
+
+typedef int64_t gint64;
+typedef uint64_t guint64;
+
+typedef uint8_t guint8;
+typedef int8_t gint8;
+
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
#endif /* __SYSTEMS_H__ */
+
+
+
+
--- a/common/mp4v2/win32_ver.h
+++ b/common/mp4v2/win32_ver.h
@@ -1,2 +1,2 @@
#define PACKAGE "mpeg4ip"
-#define VERSION "0.9.2.16"
+#define VERSION "0.9.5"