void MatroskaImport::AddChapterAtom(KaxChapterAtom *atom, Track chapterTrack)
{
	KaxChapterAtom *subChapter = FindChild<KaxChapterAtom>(*atom);
	bool addThisChapter = true;
	
	// since QuickTime only supports linear chapter tracks (no nesting), only add chapter leaves
	if (subChapter && subChapter->GetSize() > 0) {
		while (subChapter && subChapter->GetSize() > 0) {
			KaxChapterFlagHidden &hideChapter = GetChild<KaxChapterFlagHidden>(*subChapter);
			
			if (!uint8_t(hideChapter)) {
				AddChapterAtom(subChapter, chapterTrack);
				addThisChapter = false;
			}
			subChapter = &GetNextChild(*atom, *subChapter);
		}
	} 
	if (addThisChapter) {
		// add the chapter to the track if it has no children
		KaxChapterTimeStart & startTime = GetChild<KaxChapterTimeStart>(*atom);
		KaxChapterDisplay & chapDisplay = GetChild<KaxChapterDisplay>(*atom);
		KaxChapterString & chapString = GetChild<KaxChapterString>(chapDisplay);
		MediaHandler mh = GetMediaHandler(GetTrackMedia(chapterTrack));
		TimeValue start = UInt64(startTime) / timecodeScale;

		if (start > movieDuration) {
			Codecprintf(NULL, "MKV: Chapter time is beyond the end of the file\n");
			return;
		}
		
		Rect bounds = {0, 0, 0, 0};
		TimeValue inserted;
		OSErr err = TextMediaAddTextSample(mh, 
										   const_cast<Ptr>(UTFstring(chapString).GetUTF8().c_str()), 
										   UTFstring(chapString).GetUTF8().size(), 
										   0, 0, 0, NULL, NULL, 
										   teCenter, &bounds, dfClipToTextBox, 
										   0, 0, 0, NULL, 1, &inserted);
		if (err)
			Codecprintf(NULL, "MKV: Error adding text sample %d\n", err);
		else {
			InsertMediaIntoTrack(chapterTrack, start, inserted, 1, fixed1);
		}
	}
}
ComponentResult MatroskaImport::ReadChapters(KaxChapters &chapterEntries)
{
	KaxEditionEntry & edition = GetChild<KaxEditionEntry>(chapterEntries);
	UInt32 emptyDataRefExtension[2];
	
	if (seenChapters)
		return noErr;
	
	chapterTrack = NewMovieTrack(theMovie, 0, 0, kNoVolume);
	if (chapterTrack == NULL) {
		Codecprintf(NULL, "MKV: Error creating chapter track %d\n", GetMoviesError());
		return GetMoviesError();
	}
	
	// we use a handle data reference here because I don't see any way to add textual 
	// sample references (TextMediaAddTextSample() will behave the same as AddSample()
	// in that it modifies the original file if that's the data reference of the media)
	Handle dataRef = NewHandleClear(sizeof(Handle) + 1);

	emptyDataRefExtension[0] = EndianU32_NtoB(sizeof(UInt32)*2);
	emptyDataRefExtension[1] = EndianU32_NtoB(kDataRefExtensionInitializationData);
	
	PtrAndHand(&emptyDataRefExtension[0], dataRef, sizeof(emptyDataRefExtension));
	
	Media chapterMedia = NewTrackMedia(chapterTrack, TextMediaType, GetMovieTimeScale(theMovie), 
									   dataRef, HandleDataHandlerSubType);
	if (chapterMedia == NULL) {
		OSErr err = GetMoviesError();
		Codecprintf(NULL, "MKV: Error creating chapter media %d\n", err);
		DisposeMovieTrack(chapterTrack);
		return err;
	}
	
	// Name the chapter track "Chapters" for easy distinguishing
	QTMetaDataRef trackMetaData;
	OSErr err = QTCopyTrackMetaData(chapterTrack, &trackMetaData);
	if (err == noErr) {
		OSType key = kUserDataName;
		string chapterName("Chapters");
		QTMetaDataAddItem(trackMetaData, kQTMetaDataStorageFormatUserData,
						  kQTMetaDataKeyFormatUserData, (UInt8 *)&key, sizeof(key),
						  (UInt8 *)chapterName.c_str(), chapterName.size(),
						  kQTMetaDataTypeUTF8, NULL);
		QTMetaDataRelease(trackMetaData);
	}
	
	BeginMediaEdits(chapterMedia);
	
	// tell the text media handler the upcoming text samples are
	// encoded in Unicode with a byte order mark (BOM)
	MediaHandler mediaHandler = GetMediaHandler(chapterMedia);
	SInt32 dataPtr = kTextEncodingUnicodeDefault;
	TextMediaSetTextSampleData(mediaHandler, &dataPtr, kTXNTextEncodingAttribute);
	
	KaxChapterAtom *chapterAtom = FindChild<KaxChapterAtom>(edition);
	while (chapterAtom && chapterAtom->GetSize() > 0) {
		AddChapterAtom(chapterAtom, chapterTrack);
		chapterAtom = &GetNextChild<KaxChapterAtom>(edition, *chapterAtom);
	}
	
	EndMediaEdits(chapterMedia);
	SetTrackEnabled(chapterTrack, false);
	seenChapters = true;
	return noErr;
}