NOTE: This patch is taken from http://sourceforge.net/forum/forum.php?thread_id=1837284&forum_id=59136

diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/Makefile.am lib/mp4v2/Makefile.am
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/Makefile.am	2007-09-19 05:51:59 +0900
+++ lib/mp4v2/Makefile.am	2008-05-30 22:51:27 +0900
@@ -13,6 +13,7 @@
 	atom_amr.cpp \
 	atom_avc1.cpp \
 	atom_avcC.cpp \
+	atom_chpl.cpp \
 	atom_d263.cpp \
 	atom_damr.cpp \
 	atom_dref.cpp \
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/atom_chpl.cpp lib/mp4v2/atom_chpl.cpp
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/atom_chpl.cpp	1970-01-01 09:00:00 +0900
+++ lib/mp4v2/atom_chpl.cpp	2008-05-30 22:51:27 +0900
@@ -0,0 +1,59 @@
+/*
+ * 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 <a href="http://www.mozilla.org/MPL/" target="_blank">http://www.mozilla.org/MPL/</a>
+ *
+ * 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.  All Rights Reserved.
+ *
+ * Contributed to MPEG4IP 
+ * by Ullrich Pollaehne <pollaehne at users.sourceforge.net>
+ *
+ * Nero chapter atom
+ */
+
+#include "mp4common.h"
+
+// MP4ChplAtom is for Nero chapter list atom which is a child of udta
+MP4ChplAtom::MP4ChplAtom () : MP4Atom("chpl")
+{
+    // it is not completely clear if version, flags, reserved and chaptercount
+    // have the right sizes but 
+    // one thing is clear: chaptercount is not only 8-bit it is at least 16-bit
+
+    // add the version
+    AddVersionAndFlags();
+  
+    // add reserved bytes
+    AddReserved("reserved", 1);
+
+    // define the chaptercount
+    MP4Integer32Property * counter = new MP4Integer32Property("chaptercount");
+    AddProperty(counter);
+
+    // define the chapterlist
+    MP4TableProperty * list = new MP4TableProperty("chapters", counter);
+
+    // the start time as 100 nanoseconds units
+    list->AddProperty(new MP4Integer64Property("starttime"));
+
+    // the chapter name as UTF-8
+    list->AddProperty(new MP4StringProperty("name", true));
+
+    // add the chapterslist
+    AddProperty(list);
+}
+
+void MP4ChplAtom::Generate ()
+{
+    SetVersion(1);
+}
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/atom_udta.cpp lib/mp4v2/atom_udta.cpp
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/atom_udta.cpp	2006-02-23 09:28:57 +0900
+++ lib/mp4v2/atom_udta.cpp	2008-05-30 22:51:27 +0900
@@ -24,6 +24,7 @@
 MP4UdtaAtom::MP4UdtaAtom() 
 	: MP4Atom("udta") 
 {
+	ExpectChildAtom("chpl", Optional, OnlyOne);
 	ExpectChildAtom("cprt", Optional, Many);
 	ExpectChildAtom("hnti", Optional, OnlyOne);
 	ExpectChildAtom("meta", Optional, OnlyOne);
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/atoms.h lib/mp4v2/atoms.h
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/atoms.h	2007-09-19 05:51:59 +0900
+++ lib/mp4v2/atoms.h	2008-05-30 22:51:27 +0900
@@ -405,4 +405,10 @@
   void Generate(void);
 };
 
+class MP4ChplAtom : public MP4Atom {
+ public:
+  MP4ChplAtom();
+  void Generate(void);
+};
+
 #endif /* __MP4_ATOMS_INCLUDED__ */
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/libmp4v2.vcproj lib/mp4v2/libmp4v2.vcproj
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/libmp4v2.vcproj	2007-09-19 05:51:59 +0900
+++ lib/mp4v2/libmp4v2.vcproj	2008-05-30 22:51:27 +0900
@@ -163,6 +163,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\atom_chpl.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\atom_d263.cpp"
 				>
 			</File>
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/mp4.cpp lib/mp4v2/mp4.cpp
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/mp4.cpp	2007-09-29 05:45:11 +0900
+++ lib/mp4v2/mp4.cpp	2008-05-30 22:51:27 +0900
@@ -1116,11 +1116,13 @@
 }
 
 extern "C" MP4TrackId MP4AddChapterTextTrack(
-	MP4FileHandle hFile, MP4TrackId refTrackId)
+	MP4FileHandle hFile,
+	MP4TrackId refTrackId,
+	u_int32_t timescale)
 {
 	if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
 		try {
-			return ((MP4File*)hFile)->AddChapterTextTrack(refTrackId);
+			return ((MP4File*)hFile)->AddChapterTextTrack(refTrackId, timescale);
 		}
 		catch (MP4Error* e) {
 			PRINT_ERROR(e);
@@ -1131,6 +1133,93 @@
 }
 
 
+extern "C" void MP4AddQTChapter(
+	MP4FileHandle hFile, 
+	MP4TrackId chapterTrackId,
+        MP4Duration chapterDuration,
+        u_int32_t chapterNr,
+        const char * chapterTitle)
+{
+    if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+        try {
+            ((MP4File*)hFile)->AddChapter(chapterTrackId, chapterDuration, chapterNr, chapterTitle);
+        }
+        catch (MP4Error* e) {
+            PRINT_ERROR(e);
+            delete e;
+        }
+    }
+}
+
+
+extern "C" void MP4AddChapter(
+	MP4FileHandle hFile, 
+	MP4Timestamp chapterStart,
+        const char * chapterTitle)
+{
+    if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+        try {
+            ((MP4File*)hFile)->AddChapter(chapterStart, chapterTitle);
+        }
+        catch (MP4Error* e) {
+            PRINT_ERROR(e);
+            delete e;
+        }
+    }
+}
+
+
+extern "C" void MP4ConvertChapters(
+	MP4FileHandle hFile,
+	bool toQT)
+{
+    if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+        try {
+            ((MP4File*)hFile)->ConvertChapters(toQT);
+        }
+        catch (MP4Error* e) {
+            PRINT_ERROR(e);
+            delete e;
+        }
+    }
+}
+
+
+extern "C" void MP4DeleteChapters(
+	MP4FileHandle hFile,
+	MP4TrackId chapterTrackId,
+	bool deleteQT)
+{
+    if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+        try {
+            ((MP4File*)hFile)->DeleteChapters(chapterTrackId, deleteQT);
+        }
+        catch (MP4Error* e) {
+            PRINT_ERROR(e);
+            delete e;
+        }
+    }
+}
+
+
+extern "C" void MP4GetChaptersList(
+	MP4FileHandle hFile,
+	MP4Chapters_t ** chapterList,
+	u_int32_t * chapterCount,
+	bool getQT)
+{
+    if (MP4_IS_VALID_FILE_HANDLE(hFile)) {
+        try {
+            ((MP4File*)hFile)->GetChaptersList(chapterList, chapterCount, getQT);
+        }
+        catch (MP4Error* e) {
+            PRINT_ERROR(e);
+            delete e;
+        }
+    }
+}
+
+
 extern "C" MP4TrackId MP4CloneTrack (MP4FileHandle srcFile, 
 				     MP4TrackId srcTrackId,
 				     MP4FileHandle dstFile,
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/mp4.h lib/mp4v2/mp4.h
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/mp4.h	2007-09-29 05:45:11 +0900
+++ lib/mp4v2/mp4.h	2008-05-30 22:51:27 +0900
@@ -304,6 +304,15 @@
 #define MPEG4_FGSP_L4 (0xfc)
 #define MPEG4_FGSP_L5 (0xfd)
 
+/* chapter related definitions */
+#define CHAPTERTITLELEN 1023
+typedef struct MP4ChapterStruct {
+    MP4Duration duration;          /* duration of a chapter in milliseconds*/
+    char title[CHAPTERTITLELEN+1]; /* title of the chapter */
+} MP4Chapters_t;
+/* milliseconds to 100 nanoseconds */
+#define MILLI2HUNDREDNANO 10000
+
 /* MP4 API declarations */
 
 #ifdef __cplusplus
@@ -599,7 +608,35 @@
 
 MP4TrackId MP4AddChapterTextTrack(
 	MP4FileHandle hFile, 
-	MP4TrackId refTrackId);
+	MP4TrackId refTrackId,
+	u_int32_t timescale DEFAULT(0));
+
+void MP4AddQTChapter(
+	MP4FileHandle hFile,
+	MP4TrackId chapterTrackId,
+	MP4Duration chapterDuration,
+	u_int32_t chapterNr,
+	const char * chapterTitle DEFAULT(0));
+
+void MP4AddChapter(
+	MP4FileHandle hFile,
+	MP4Timestamp chapterStart,
+	const char * chapterTitle DEFAULT(0));
+
+void MP4ConvertChapters(
+	MP4FileHandle hFile,
+	bool toQT DEFAULT(true));
+
+void MP4DeleteChapters(
+	MP4FileHandle hFile, 
+	MP4TrackId chapterTrackId DEFAULT(MP4_INVALID_TRACK_ID),
+	bool deleteQT DEFAULT(true));
+
+void MP4GetChaptersList(
+	MP4FileHandle hFile,
+	MP4Chapters_t ** chapterList,
+	u_int32_t * chapterCount,
+	bool getQT DEFAULT(true));
 
 MP4TrackId MP4CloneTrack(
 	MP4FileHandle srcFile, 
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/mp4atom.cpp lib/mp4v2/mp4atom.cpp
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/mp4atom.cpp	2007-05-01 05:29:28 +0900
+++ lib/mp4v2/mp4atom.cpp	2008-05-30 22:51:27 +0900
@@ -93,6 +93,8 @@
     case 'c':
       if (ATOMID(type) == ATOMID("chap")) {
 	pAtom = new MP4TrefTypeAtom(type);
+      } else if (ATOMID(type) == ATOMID("chpl")) {
+          pAtom = new MP4ChplAtom();
 	  }
 	  break;
     case 'd':
@@ -269,11 +271,13 @@
       static const char cpy[5]={0251,'c', 'p', 'y', '\0'};
       static const char des[5]={0251,'d', 'e', 's','\0'};
       static const char prd[5]={0251, 'p', 'r', 'd', '\0'};
+      static const char lyr[5]={0251, 'l', 'y', 'r', '\0'};
       if (ATOMID(type) == ATOMID(name) ||
 	  ATOMID(type) == ATOMID(cmt) ||
 	  ATOMID(type) == ATOMID(cpy) ||
 	  ATOMID(type) == ATOMID(prd) ||
-	  ATOMID(type) == ATOMID(des)) {
+	  ATOMID(type) == ATOMID(des) ||
+	  ATOMID(type) == ATOMID(lyr)) {
 	pAtom = new MP4Meta2Atom(type);
       }
       break;
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/mp4file.cpp lib/mp4v2/mp4file.cpp
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/mp4file.cpp	2007-09-29 05:45:11 +0900
+++ lib/mp4v2/mp4file.cpp	2008-05-30 22:51:27 +0900
@@ -2124,13 +2124,16 @@
 	return trackId;
 }
 
-MP4TrackId MP4File::AddChapterTextTrack(MP4TrackId refTrackId)
+MP4TrackId MP4File::AddChapterTextTrack(MP4TrackId refTrackId, u_int32_t timescale)
 {
 	// validate reference track id
 	(void)FindTrackIndex(refTrackId);
 
-	MP4TrackId trackId = 
-		AddTrack(MP4_TEXT_TRACK_TYPE, GetTrackTimeScale(refTrackId));
+	if (0 == timescale) {
+	    timescale = GetTrackTimeScale(refTrackId);
+	}
+
+	MP4TrackId trackId = AddTrack(MP4_TEXT_TRACK_TYPE, timescale);
 
 	(void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "gmhd", 0);
 
@@ -2168,6 +2171,340 @@
 	return trackId;
 }
 
+void MP4File::AddChapter(MP4TrackId chapterTrackId, MP4Duration chapterDuration, u_int32_t chapterNr, const char * chapterTitle)
+{
+    if (0 == chapterTrackId) {
+        throw new MP4Error("No chapter track given","AddChapter"); 
+    }
+
+    uint32_t sampleLength = 0;
+    uint8_t  sample[1040] = {0};
+    int stringLen = 0;
+    char *string = (char *)&(sample[2]);
+
+    if( chapterTitle != NULL )
+    {
+        stringLen = strlen(chapterTitle);
+        strncpy( string, chapterTitle, MIN(stringLen, 1023) );
+    }
+
+    if( stringLen == 0 || stringLen >= 1024 )
+    {
+        snprintf( string, 1023, "Chapter %03i", chapterNr );
+        stringLen = strlen(string);
+    }
+
+    sampleLength = stringLen + 2 + 12; // Account for text length code and other marker
+
+    // 2-byte length marker
+    sample[0] = (stringLen >> 8) & 0xff;
+    sample[1] = stringLen & 0xff;
+
+    int x = 2 + stringLen;
+
+    // Modifier Length Marker
+    sample[x] = 0x00;
+    sample[x+1] = 0x00;
+    sample[x+2] = 0x00;
+    sample[x+3] = 0x0C;
+    
+    // Modifier Type Code
+    sample[x+4] = 'e';
+    sample[x+5] = 'n';
+    sample[x+6] = 'c';
+    sample[x+7] = 'd';
+    
+    // Modifier Value
+    sample[x+8] = 0x00;
+    sample[x+9] = 0x00;
+    sample[x+10] = (256 >> 8) & 0xff;
+    sample[x+11] = 256 & 0xff;
+
+    WriteSample(chapterTrackId, sample, sampleLength, chapterDuration);
+}
+
+void MP4File::AddChapter(MP4Timestamp chapterStart, const char * chapterTitle)
+{
+    MP4Atom * pChpl = FindAtom("moov.udta.chpl");
+    if (!pChpl) {
+	pChpl = AddDescendantAtoms("", "moov.udta.chpl");
+    }
+
+    char buffer[256];
+    int bufferLen = 0;
+
+    MP4Integer32Property * pCount = (MP4Integer32Property*)pChpl->GetProperty(3);
+    pCount->IncrementValue();
+    u_int32_t count = pCount->GetValue();
+
+    if (0 == chapterTitle) {
+	snprintf( buffer, 255, "Chapter %03i", count );
+    } else {
+	int len = MIN(255, strlen(chapterTitle));
+	strncpy( buffer, chapterTitle, len );
+	buffer[len] = 0;
+    }
+    bufferLen = strlen(buffer);
+
+    MP4TableProperty * pTable;
+    if (pChpl->FindProperty("chpl.chapters", (MP4Property **)&pTable)) {
+	MP4Integer64Property * pStartTime = (MP4Integer64Property *) pTable->GetProperty(0);
+	MP4StringProperty * pName = (MP4StringProperty *) pTable->GetProperty(1);
+	if (pStartTime && pTable) {
+	    pStartTime->AddValue(chapterStart);
+	    pName->AddValue(buffer);
+	}
+    }
+}
+
+void MP4File::ConvertChapters(bool toQT)
+{
+    if (toQT) {
+	MP4Chapters_t * chapters = 0;
+	u_int32_t chapterCount = 0;
+	const char * name = 0;
+	MP4Duration chapterDurationSum = 0;
+
+	GetChaptersList(&chapters, &chapterCount, false);
+	if (0 == chapterCount) {
+	    throw new MP4Error("Could not find chapter markers", "ConvertChapters");
+	}
+
+	// remove chapter track if there is an existing one
+	DeleteChapters();
+
+	// create the chapter track
+	MP4TrackId refTrack = FindTrackId(0, MP4_AUDIO_TRACK_TYPE);
+	MP4TrackId chapterTrack = AddChapterTextTrack(refTrack, MP4_MILLISECONDS_TIME_SCALE);
+
+	// calculate the duration of the chapter track
+	MP4Duration chapterTrackDuration = MP4ConvertTime(GetTrackDuration(refTrack),
+							  GetTrackTimeScale(refTrack),
+							  MP4_MILLISECONDS_TIME_SCALE);
+
+	for (u_int32_t chapterIndex = 0 ; chapterIndex < chapterCount; ++chapterIndex) {
+	    // calculate the duration
+	    MP4Duration duration = chapters[chapterIndex].duration;
+
+	    // sum up the chapter duration
+	    chapterDurationSum += duration;
+
+	    // create and write the chapter track sample for the previous chapter
+	    AddChapter( chapterTrack, duration, chapterIndex+1, chapters[chapterIndex].title );
+	}
+
+	MP4Free(chapters);
+    } else {
+	MP4Chapters_t * chapters = 0;
+	u_int32_t chapterCount = 0;
+
+	GetChaptersList(&chapters, &chapterCount);
+	if (0 == chapterCount) {
+	    throw new MP4Error("Could not find chapter markers", "ConvertChapters");
+	}
+
+	// remove existing chapters
+	DeleteChapters(0, false);
+
+	MP4Duration startTime = 0;
+	for (u_int32_t i = 0; i < chapterCount; ++i) {
+	    const char * title = chapters[i].title;
+	    MP4Duration duration = chapters[i].duration;
+
+	    AddChapter(startTime, title);
+	    startTime += duration * MILLI2HUNDREDNANO;
+	}
+
+	MP4Free(chapters);
+    }
+}
+
+void MP4File::DeleteChapters(MP4TrackId chapterTrackId, bool deleteQT)
+{
+    if (!deleteQT) {
+	MP4Atom * pChpl = FindAtom("moov.udta.chpl");
+	if (pChpl) {
+	    MP4Atom * pParent = pChpl->GetParentAtom();
+	    pParent->DeleteChildAtom(pChpl);
+	}
+	return;
+    }
+
+    char trackName[128] = {0};
+
+    // no text track given, find a suitable
+    if (0 == chapterTrackId) {
+	chapterTrackId = FindChapterTrack(trackName, 127);
+    } else {
+	FindChapterReferenceTrack(chapterTrackId, trackName, 127);
+    }
+
+    if (0 != chapterTrackId && 0 != trackName[0]) {
+	// remove the reference
+	RemoveTrackReference(trackName, chapterTrackId);
+
+	// remove the chapter track
+	DeleteTrack(chapterTrackId);
+    }
+}
+
+void MP4File::GetChaptersList(MP4Chapters_t ** chapterList,
+			      u_int32_t * chapterCount,
+			      bool getQT)
+{
+    *chapterList = 0;
+    *chapterCount = 0;
+
+    if (!getQT) {
+	MP4Atom * pChpl = FindAtom("moov.udta.chpl");
+	if (!pChpl) {
+	    throw new MP4Error("Atom moov.udta.chpl does not exist ", "GetChaptersList"); 
+	}
+
+	MP4Integer32Property * pCounter = 0;
+	MP4TableProperty * pTable = 0;
+	MP4Integer64Property * pStartTime = 0;
+	MP4StringProperty * pName = 0;
+	MP4Duration chapterDurationSum = 0;
+	const char * name = 0;
+
+	if (!pChpl->FindProperty("chpl.chaptercount", (MP4Property **)&pCounter)) {
+	    throw new MP4Error("Chapter count does not exist ", "GetChaptersList"); 
+	}
+
+	u_int32_t counter = pCounter->GetValue();
+	if (0 == counter) {
+	    return;
+	}
+
+	if (!pChpl->FindProperty("chpl.chapters", (MP4Property **)&pTable)) {
+	    throw new MP4Error("Chapter list does not exist ", "GetChaptersList"); 
+	}
+
+	if (0 == (pStartTime = (MP4Integer64Property *) pTable->GetProperty(0))) {
+	    throw new MP4Error("List of Chapter starttimes does not exist ", "GetChaptersList"); 
+	}
+	if (0 == (pName = (MP4StringProperty *) pTable->GetProperty(1))) {
+	    throw new MP4Error("List of Chapter titles does not exist ", "GetChaptersList"); 
+	}
+
+	MP4Chapters_t * chapters = (MP4Chapters_t*)MP4Malloc(sizeof(MP4Chapters_t) * counter);
+
+	// get the name of the first chapter
+	name = pName->GetValue();
+
+	// process remaining chapters
+	u_int32_t i, j;
+	for (i = 0, j = 1; i < counter; ++i, ++j) {
+	    // insert the chapter title
+	    u_int32_t len = MIN(strlen(name), CHAPTERTITLELEN);
+	    strncpy(chapters[i].title, name, len);
+	    chapters[i].title[len] = 0;
+
+	    // calculate the duration
+	    MP4Duration duration = 0;
+	    if (j < counter) {
+		duration = MP4ConvertTime(pStartTime->GetValue(j),
+					  (MP4_NANOSECONDS_TIME_SCALE / 100),
+					  MP4_MILLISECONDS_TIME_SCALE) - chapterDurationSum;
+
+		// now get the name of the chapter (to be written next)
+		name = pName->GetValue(j);
+	    } else {
+		// last chapter
+		duration = MP4ConvertTime(GetDuration(), GetTimeScale(), MP4_MILLISECONDS_TIME_SCALE) - chapterDurationSum;
+	    }
+
+	    // sum up the chapter duration
+	    chapterDurationSum += duration;
+
+	    // insert the chapter duration
+	    chapters[i].duration = duration;
+	}
+
+	*chapterList = chapters;
+	*chapterCount = counter;
+
+	// ok, we're done
+	return;
+    }
+
+
+    u_int8_t * sample = 0;
+    u_int32_t sampleSize = 0;
+    MP4Timestamp startTime = 0;
+    MP4Duration duration = 0;
+
+    // get the chapter track
+    MP4TrackId chapterTrackId = FindChapterTrack();
+    if (0 == chapterTrackId) {
+	throw new MP4Error("Could not find a chapter track", "GetChaptersList");
+    }
+
+    // get infos about the chapters
+    MP4Track * pChapterTrack = GetTrack(chapterTrackId);
+    u_int32_t counter = pChapterTrack->GetNumberOfSamples();
+    u_int32_t timescale = pChapterTrack->GetTimeScale();
+
+    MP4Chapters_t * chapters = (MP4Chapters_t*)MP4Malloc(sizeof(MP4Chapters_t) * counter);
+
+    // process all chapter sample
+    for (u_int32_t i = 0; i < counter; ++i) {
+	// get the sample corresponding to the starttime
+	MP4SampleId sampleId = pChapterTrack->GetSampleIdFromTime(startTime + duration, true);
+	pChapterTrack->ReadSample(sampleId, &sample, &sampleSize);
+
+	// get the starttime and duration
+	pChapterTrack->GetSampleTimes(sampleId, &startTime, &duration);
+
+	// we know that sample+2 contains the title
+	const char * title = (const char *)&(sample[2]);
+	int len = MIN(strlen(title), CHAPTERTITLELEN);
+	strncpy(chapters[i].title, title, len);
+	chapters[i].title[len] = 0;
+
+	// write the duration (in milliseconds)
+	chapters[i].duration = MP4ConvertTime(duration, timescale, MP4_MILLISECONDS_TIME_SCALE);
+
+	// we're done with this sample
+	MP4Free(sample);
+	sample = 0;
+    }
+
+    *chapterList = chapters;
+    *chapterCount = counter;
+}
+
+MP4TrackId MP4File::FindChapterTrack(char * trackName, int trackNameSize)
+{
+    for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
+	if (!strcmp(MP4_TEXT_TRACK_TYPE, m_pTracks[i]->GetType())) {
+	    MP4TrackId refTrackId = FindChapterReferenceTrack(m_pTracks[i]->GetId(), trackName, trackNameSize);
+	    if (0 != refTrackId) {
+		return m_pTracks[i]->GetId();
+	    }
+	}
+    }
+    return 0;
+}
+
+MP4TrackId MP4File::FindChapterReferenceTrack(MP4TrackId chapterTrackId, char * trackName, int trackNameSize)
+{
+    for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {
+	if (!strcmp(MP4_AUDIO_TRACK_TYPE, m_pTracks[i]->GetType())) {
+	    MP4TrackId refTrackId = m_pTracks[i]->GetId();
+	    char * name = MakeTrackName(refTrackId, "tref.chap");
+	    if (FindTrackReference(name, chapterTrackId)) {
+		if (0 != trackName) {
+		    strncpy(trackName, name, MIN(strlen(name),trackNameSize));
+		}
+		return m_pTracks[i]->GetId();
+	    }
+	}
+    }
+    return 0;
+}
+
 void MP4File::DeleteTrack(MP4TrackId trackId)
 {
 	ProtectWriteOperation("MP4DeleteTrack");
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/mp4file.h lib/mp4v2/mp4file.h
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/mp4file.h	2007-09-29 05:45:11 +0900
+++ lib/mp4v2/mp4file.h	2008-05-30 22:51:27 +0900
@@ -310,7 +310,20 @@
 	MP4TrackId AddHintTrack(MP4TrackId refTrackId);
 
 	MP4TrackId AddTextTrack(MP4TrackId refTrackId);
-	MP4TrackId AddChapterTextTrack(MP4TrackId refTrackId);
+	MP4TrackId AddChapterTextTrack(MP4TrackId refTrackId, u_int32_t timescale = 0);
+	void AddChapter(MP4TrackId chapterTrackId,
+			MP4Duration chapterDuration,
+			u_int32_t chapterNr,
+			const char * chapterTitle = 0);
+	void AddChapter(MP4Timestamp chapterStart,
+			const char * chapterTitle = 0);
+	void ConvertChapters(bool toQT = true);
+	void DeleteChapters(MP4TrackId chapterTrackId = 0, bool deleteQT = true);
+	void GetChaptersList(MP4Chapters_t ** chapterList,
+			      u_int32_t * chapterCount,
+			      bool getQT = true);
+	MP4TrackId FindChapterTrack(char * trackName = 0, int trackNameSize = 0);
+	MP4TrackId FindChapterReferenceTrack(MP4TrackId chapterTrackId, char * trackName = 0, int trackNameSize = 0);
 
 	MP4SampleId GetTrackNumberOfSamples(MP4TrackId trackId);
 
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/util/Makefile.am lib/mp4v2/util/Makefile.am
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/util/Makefile.am	2007-09-19 05:52:00 +0900
+++ lib/mp4v2/util/Makefile.am	2008-05-30 22:51:27 +0900
@@ -3,9 +3,13 @@
 
 AM_CXXFLAGS = @BILLS_CPPWARNINGS@
 
-bin_PROGRAMS = mp4dump mp4extract mp4info mp4trackdump mp4tags mp4art mp4videoinfo 
+bin_PROGRAMS = mp4dump mp4extract mp4info mp4trackdump mp4tags mp4chaps mp4art mp4videoinfo 
 check_PROGRAMS = mp4syncfiles
 
+mp4chaps_SOURCES = mp4chaps.cpp
+mp4chaps_LDADD = $(top_builddir)/lib/mp4v2/libmp4v2.la \
+	$(top_builddir)/lib/gnu/libmpeg4ip_gnu.la
+
 mp4dump_SOURCES = mp4dump.cpp
 mp4dump_LDADD = $(top_builddir)/lib/mp4v2/libmp4v2.la \
 	$(top_builddir)/lib/gnu/libmpeg4ip_gnu.la
@@ -40,4 +44,4 @@
 	$(top_builddir)/lib/gnu/libmpeg4ip_gnu.la
 
 EXTRA_DIST = mp4dump60.dsp  \
-	mp4info.dsp mp4tags.dsp mp4dump.vcproj mp4info.vcproj mp4tags.vcproj
+	mp4info.dsp mp4tags.dsp mp4dump.vcproj mp4info.vcproj mp4tags.vcproj mp4chaps.vcproj
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/util/mp4chaps.cpp lib/mp4v2/util/mp4chaps.cpp
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/util/mp4chaps.cpp	1970-01-01 09:00:00 +0900
+++ lib/mp4v2/util/mp4chaps.cpp	2008-05-30 22:51:27 +0900
@@ -0,0 +1,380 @@
+/* mp4chaps -- tool to set iTunes-compatible chapter markers from Nero chapter markers
+ * 
+ * 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 <a href="http://www.mozilla.org/MPL/" target="_blank">http://www.mozilla.org/MPL/</a>
+ * 
+ * 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.
+ * 
+ * Contributed to MPEG4IP 
+ * by Ullrich Pollaehne <pollaehne at users.sourceforge.net>
+ * with help from Handbrake <http://handbrake.m0k.org/>
+ */
+
+#include "mp4common.h"
+#include "mp4file.h"
+#include "mp4.h"
+#include "mpeg4ip_getopt.h"
+
+/* One-letter options -- if you want to rearrange these, change them
+   here, immediately below in OPT_STRING, and in the help text. */
+#define OPT_HELP     'h'
+#define OPT_VERSION  'v'
+#define OPT_REMOVE   'r'
+#define OPT_CONVERT  'c'
+#define OPT_OPTIMIZE 'o'
+#define OPT_QT       'Q'
+#define OPT_NERO     'N'
+#define OPT_EVERY    'e'
+#define OPT_LIST     'l'
+#define OPT_STRING   "hvrcoNQe:l"
+
+static const char* help_text =
+"OPTION... FILE...\n"
+"\nConvert/Manage Nero chapter markers or QT/iTunes/iPod\n"
+"  chapter markers in MP4 Audio files\n"
+"\n"
+"  -h, -help       Display this help text and exit\n"
+"  -v, -version    Display version information and exit\n"
+"  -r, -remove     Remove chapter markers\n"
+"  -c, -convert    Convert chapter markers\n"
+"  -o, -optimize   re-write file in optimized form\n"
+"  -N, -Nero       write/remove/convert to Nero chapter markers\n"
+"  -Q, -QuickTime  write/remove/convert to QuickTime chapter markers\n"
+"  -e, -every n    creates chapter markers every n seconds\n"
+"  -l, -list       list available chapter markers\n"
+"\n";
+
+
+// function prototypes
+void ListChapters(MP4FileHandle hFile, bool useQT = true);
+int CreateQTChaptersEvery(MP4FileHandle hFile, int milliSeconds, const char * filename);
+int CreateChaptersEvery(MP4FileHandle hFile, int milliSeconds, const char * filename);
+
+
+
+int main(int argc, char** argv)
+{
+    static struct option long_options[] = {
+	{ "help",      0, 0, OPT_HELP     },
+	{ "version",   0, 0, OPT_VERSION  },
+	{ "remove",    0, 0, OPT_REMOVE   },
+	{ "convert",   0, 0, OPT_CONVERT  },
+	{ "optimize",  0, 0, OPT_OPTIMIZE },
+	{ "Nero",      0, 0, OPT_NERO     },
+	{ "QuickTime", 0, 0, OPT_QT       },
+	{ "every",     1, 0, OPT_EVERY    },
+	{ "list",      0, 0, OPT_LIST     },
+	{ NULL,        0, 0, 0            }
+    };
+
+
+    bool optEvery = false;
+    bool optDelete = false;
+    bool optConvert = false;
+    bool optOptimize = false;
+    bool optQT = false;
+    bool optNero = false;
+    bool optList = false;
+    bool needsModification = false;
+    u_int32_t seconds = 0;
+
+    /* Option-processing loop. */
+    int c = getopt_long_only(argc, argv, OPT_STRING, long_options, NULL);
+    while (c != -1) {
+    switch(c) {
+      /* getopt() returns '?' if there was an error.  It already
+	 printed the error message, so just return. */
+    case '?':
+      return 1;
+
+      /* Help and version requests handled here. */
+    case OPT_HELP:
+      fprintf(stderr, "usage %s %s", argv[0], help_text);
+      return 0;
+    case OPT_VERSION:
+      fprintf(stderr, "%s - %s version %s\n", argv[0], MPEG4IP_PACKAGE, 
+	      MPEG4IP_VERSION);
+      return 0;
+
+    case OPT_NERO:
+      optNero = true;
+      break;
+
+    case OPT_QT:
+      optQT = true;
+      break;
+
+    case OPT_REMOVE:
+      optDelete = true;
+      needsModification = true;
+      break;
+
+    case OPT_CONVERT:
+      optConvert = true;
+      needsModification = true;
+      break;
+
+    case OPT_OPTIMIZE:
+      optOptimize = true;
+      needsModification = true;
+      break;
+
+    case OPT_LIST:
+      optList = true;
+      break;
+
+      /* Numeric arguments: convert them using sscanf(). */
+    case OPT_EVERY:
+      {
+          int r = sscanf(optarg, "%ul", &seconds);
+          if (r < 1) {
+            fprintf(stderr, "%s: option requires numeric argument -- %c\n",
+                    argv[0], c);
+            return 2;
+          }
+          optEvery = true;
+	  needsModification = true;
+      }
+      break;
+
+    default:
+      break;
+    } /* end switch */
+    
+    c = getopt_long_only(argc, argv, OPT_STRING, long_options, NULL);
+  } /* end while */
+
+    /* Check that we have at least one non-option argument */
+    if ((argc - optind) < 1) {
+	fprintf(stderr, 
+	"%s: You must specify at least one MP4 file.\n", 
+	argv[0]);
+	fprintf(stderr, "usage %s %s", argv[0], help_text);
+	return 3;
+    }
+
+    /* Loop through the non-option arguments, and do the requested chapter work */ 
+    int rc = 0;
+    bool needsOptimize = false;
+    while (optind < argc) {
+	char *filename = argv[optind++];
+
+	MP4FileHandle h = 0;
+	if (needsModification) {
+	    h = MP4Modify( filename, MP4_DETAILS_ERROR);
+	} else {
+	    h = MP4Read( filename, MP4_DETAILS_ERROR );
+	}
+
+	if (h == MP4_INVALID_FILE_HANDLE) {
+	  fprintf(stderr, "Could not open '%s'... aborting\n", filename);
+	  return 5;
+	}
+
+	if(optDelete) {
+	    if (optQT) {
+		MP4DeleteChapters(h);
+	    }
+	    if (optNero) {
+		MP4DeleteChapters(h, MP4_INVALID_TRACK_ID, false);
+	    }
+	    if (!optQT && ! optNero) {
+		MP4DeleteChapters(h);
+		MP4DeleteChapters(h, MP4_INVALID_TRACK_ID, false);
+	    }
+	}
+
+	if(optEvery) {
+	    if (optQT) {
+		rc = CreateQTChaptersEvery(h, seconds*MP4_MILLISECONDS_TIME_SCALE, filename);
+	    }
+	    if (optNero && 0 == rc) {
+		rc = CreateChaptersEvery(h, seconds*MP4_MILLISECONDS_TIME_SCALE, filename);
+	    }
+	    if (!optQT && !optNero)	{
+		rc = CreateChaptersEvery(h, seconds*MP4_MILLISECONDS_TIME_SCALE, filename);
+		if (0 == rc) {
+		    MP4ConvertChapters(h);
+		}
+	    }
+	    if (0 != rc) {
+		MP4Close(h);
+		continue;
+	    }
+	    needsOptimize = true;
+	}
+
+	if (optConvert) {
+	    if (optQT) {
+		MP4ConvertChapters(h, optQT);
+		needsOptimize = true;
+	    } else if (optNero) {
+		MP4ConvertChapters(h, false);
+		needsOptimize = true;
+	    }
+	}
+
+	if (optList) {
+	    ListChapters(h, optQT);
+	}
+
+	if (0 == rc) {
+	    MP4Close(h);
+
+	    if (optOptimize || needsOptimize) {
+		MP4Optimize(filename);
+	    }
+	}
+    } /* end while optind < argc */
+
+    return 0;
+}
+
+/*
+ * format a duration to a readable format ("stolen" from gpac MP4Box)
+ */
+static char *format_duration(u_int64_t dur, char *szDur)
+{
+    u_int32_t h, m, s, ms;
+
+    h = (u_int32_t) (dur / 3600000);
+    m = (u_int32_t) (dur/ 60000) - h*60;
+    s = (u_int32_t) (dur/1000) - h*3600 - m*60;
+    ms = (u_int32_t) (dur) - h*3600000 - m*60000 - s*1000;
+    if (h<=24) {
+	sprintf(szDur, "%02d:%02d:%02d.%03d", h, m, s, ms);
+    } else {
+	u_int32_t d = (u_int32_t) (dur / 3600000 / 24);
+	h = (u_int32_t) (dur/3600000)-24*d;
+	if (d<=365) {
+	    sprintf(szDur, "%d Days, %02d:%02d:%02d.%03d", d, h, m, s, ms);
+	} else {
+	    u_int32_t y=0;
+	    while (d>365) {
+		y++;
+		d-=365;
+		if (y%4) d--;
+	    }
+	    sprintf(szDur, "%d Years %d Days, %02d:%02d:%02d.%03d", y, d, h, m, s, ms);
+	}
+    }
+    return szDur;
+}
+
+/*
+ * List chapter start time and title
+ */
+void ListChapters(MP4FileHandle hFile, bool useQT)
+{
+    MP4Chapters_t * chapters = 0;
+    u_int32_t chapterCount = 0;
+    char szDur[20] = {0};
+    MP4Duration durationSum = 0;
+
+    // get the list of chapters
+    MP4GetChaptersList(hFile, &chapters, &chapterCount, useQT);
+    if (0 == chapterCount) {
+	return;
+    }
+
+    // start output (in mp4box format)
+    fprintf(stdout, "\nChapters:\n");
+
+    for(u_int32_t i = 0; i < chapterCount; ++i) {
+	// get the tile
+	const char * title = chapters[i].title;
+	// format the start time
+	const char * formattedDuration = format_duration(durationSum, szDur);
+
+	// print the infos
+	fprintf(stdout, "\tChapter #%u - %s - \"%s\"\n", i+1, formattedDuration, title);
+
+	// add the duration of this chapter to the sum (is the start time of the next chapter)
+	durationSum += chapters[i].duration;
+    }
+
+    // free up the memory
+    MP4Free(chapters);
+}
+
+/*
+ * Create QT/iTunes/iPod chapter markers with a duration of 'milliSeconds' milliseconds
+ */
+int CreateQTChaptersEvery(MP4FileHandle hFile, int milliSeconds, const char * filename)
+{
+    // delete previous chapter markers
+    MP4DeleteChapters(hFile);
+
+    // get the audio track that will reference the chapter track
+    MP4TrackId refTrackId = MP4FindTrackId(hFile, MP4_INVALID_TRACK_ID, MP4_AUDIO_TRACK_TYPE);
+    if (! MP4_IS_VALID_TRACK_ID(refTrackId)) {
+        MP4Close(hFile);
+        fprintf(stderr, "Could not find audio track in file '%s'... aborting\n", filename);
+        return 6;
+    }
+
+    // create the chapter track ...
+    MP4TrackId chapterTrack = MP4AddChapterTextTrack(hFile, refTrackId, MP4_MILLISECONDS_TIME_SCALE);
+
+    // get informations about the audio track
+    MP4Duration refTrackDuration = MP4GetTrackDuration(hFile, refTrackId);
+    uint32_t refTrackTimeScale = MP4GetTrackTimeScale(hFile, refTrackId);
+
+    MP4Duration chapterDuration = milliSeconds;
+    //MP4Duration chapterTrackDuration = (refTrackDuration * MP4_MILLISECONDS_TIME_SCALE) / refTrackTimeScale;
+    MP4Duration chapterTrackDuration = MP4ConvertTime(refTrackDuration, refTrackTimeScale, MP4_MILLISECONDS_TIME_SCALE);
+
+    // create chapters
+    MP4Duration chapterSum;
+    int i;
+    for (chapterSum = 0, i = 1; chapterTrackDuration > chapterSum; chapterSum += chapterDuration, ++i) {
+        if (chapterTrackDuration < (chapterSum + chapterDuration)) {
+	    chapterDuration = chapterTrackDuration - chapterSum;
+        }
+
+	// chapterDuration is expected as count of samples related to the timescale of chapterTrack
+        MP4AddQTChapter( hFile, chapterTrack, chapterDuration, i );
+    }
+
+    return 0;
+}
+
+
+/*
+ * Create Nero chapter markers with a duration of 'milliSeconds' milliseconds
+ */
+int CreateChaptersEvery(MP4FileHandle hFile, int milliSeconds, const char * filename)
+{
+    // delete previous chapter markers
+    MP4DeleteChapters(hFile, MP4_INVALID_TRACK_ID, false);
+
+    // get the audio track that will reference the chapter track
+    MP4TrackId refTrackId = MP4FindTrackId(hFile, MP4_INVALID_TRACK_ID, MP4_AUDIO_TRACK_TYPE);
+    if (! MP4_IS_VALID_TRACK_ID(refTrackId)) {
+        MP4Close(hFile);
+        fprintf(stderr, "Could not find audio track in file '%s'... aborting\n", filename);
+        return 6;
+    }
+
+    // get informations about the audio track
+    MP4Duration refTrackDuration = MP4GetTrackDuration(hFile, refTrackId);
+    uint32_t refTrackTimeScale = MP4GetTrackTimeScale(hFile, refTrackId);
+
+    // we need the duration in 100 nanosecond units
+    MP4Duration durationIn100Nanos = MP4ConvertTime( refTrackDuration, refTrackTimeScale, MP4_NANOSECONDS_TIME_SCALE / 100 );
+    //MP4Duration durationIn100Nanos = ((refTrackDuration * MP4_MILLISECONDS_TIME_SCALE) / refTrackTimeScale) * 10000;
+    MP4Duration chapterDuration = milliSeconds * 10000;
+
+    // create the chapters
+    for (MP4Duration startTime = 0; durationIn100Nanos > startTime; startTime += chapterDuration) {
+	// starttime is expected to be in 100-nanosecond units
+        MP4AddChapter( hFile, startTime );
+    }
+
+    return 0;
+}
diff -urN ../mpeg4ip-1.6.1-orig/lib/mp4v2/util/mp4chaps.vcproj lib/mp4v2/util/mp4chaps.vcproj
--- ../mpeg4ip-1.6.1-orig/lib/mp4v2/util/mp4chaps.vcproj	1970-01-01 09:00:00 +0900
+++ lib/mp4v2/util/mp4chaps.vcproj	2008-05-30 22:51:27 +0900
@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8,00"
+	Name="mp4chaps"
+	ProjectGUID="{990E370A-FEA4-461A-80FA-CF9B59A5350D}"
+	RootNamespace="mp4chaps"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=""$(SolutionDir)/include".."
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib"
+				LinkIncremental="2"
+				GenerateManifest="true"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="1"
+				FavorSizeOrSpeed="2"
+				AdditionalIncludeDirectories=""$(SolutionDir)/include".."
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="ws2_32.lib"
+				LinkIncremental="1"
+				GenerateManifest="false"
+				IgnoreAllDefaultLibraries="false"
+				IgnoreDefaultLibraryNames=""
+				GenerateDebugInformation="false"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				OptimizeForWindows98="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mp4chaps.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
--- ../mpeg4ip-1.6.1-orig/tools.sln	2007-09-29 05:45:08 +0900
+++ tools.sln	2008-05-30 22:52:53 +0900
@@ -2,6 +2,12 @@
 # Visual Studio 2005
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmp4v2", "lib\mp4v2\libmp4v2.vcproj", "{56EAC9DA-F67D-433B-AEBB-7C61CF2EF505}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mp4chaps", "lib\mp4v2\util\mp4chaps.vcproj", "{990E370A-FEA4-461A-80FA-CF9B59A5350D}"
+	ProjectSection(ProjectDependencies) = postProject
+		{9EF07C35-1D27-424D-970E-0E89D97DD111} = {9EF07C35-1D27-424D-970E-0E89D97DD111}
+		{56EAC9DA-F67D-433B-AEBB-7C61CF2EF505} = {56EAC9DA-F67D-433B-AEBB-7C61CF2EF505}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mp4info", "lib\mp4v2\util\mp4info.vcproj", "{22B77017-61F0-4D4A-A8F4-BE726F2E917C}"
 	ProjectSection(ProjectDependencies) = postProject
 		{56EAC9DA-F67D-433B-AEBB-7C61CF2EF505} = {56EAC9DA-F67D-433B-AEBB-7C61CF2EF505}
@@ -79,6 +85,10 @@
 		{56EAC9DA-F67D-433B-AEBB-7C61CF2EF505}.Debug|Win32.Build.0 = Debug|Win32
 		{56EAC9DA-F67D-433B-AEBB-7C61CF2EF505}.Release|Win32.ActiveCfg = Release|Win32
 		{56EAC9DA-F67D-433B-AEBB-7C61CF2EF505}.Release|Win32.Build.0 = Release|Win32
+		{990E370A-FEA4-461A-80FA-CF9B59A5350D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{990E370A-FEA4-461A-80FA-CF9B59A5350D}.Debug|Win32.Build.0 = Debug|Win32
+		{990E370A-FEA4-461A-80FA-CF9B59A5350D}.Release|Win32.ActiveCfg = Release|Win32
+		{990E370A-FEA4-461A-80FA-CF9B59A5350D}.Release|Win32.Build.0 = Release|Win32
 		{22B77017-61F0-4D4A-A8F4-BE726F2E917C}.Debug|Win32.ActiveCfg = Debug|Win32
 		{22B77017-61F0-4D4A-A8F4-BE726F2E917C}.Debug|Win32.Build.0 = Debug|Win32
 		{22B77017-61F0-4D4A-A8F4-BE726F2E917C}.Release|Win32.ActiveCfg = Release|Win32
