shithub: aacdec

Download patch

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"