Hi. I want to thank you for continuing this project, and to ask if I could pick your brains about how and where chapter information is stored using Mp4v2.
Here's the situation: I just started learning Swift less than a year ago. I don't know any of the C-related languages. With the help of my very generous mentor, I've got a version of MP4v2
as a Swift Package Manager package to import into my project, but the API is in raw C, and I'm struggling with it.
For example: I've created a structure that holds my chapters, and within it I have a property that converts them to an array of MP4Chapter_t
objects.
// convert chapters to mp4Chapter type
var mp4Chapters: [MP4Chapter_t] {
var mp4Chapters: [MP4Chapter_t] = []
var defaultChapterTitle: String = ""
// for each index in the chapters array...
for index in sortedChapters().indices {
defaultChapterTitle = "Chapter \(Int(index))"
// get the current chapter
let chapter = sortedChapters()[index]
// get the endTime for the current chapter from the startTime of the next chapter
let endTime: Int
// get the index of the next chapter
let nextIndex = sortedChapters().index(after: index)
if nextIndex < sortedChapters().endIndex {
let nextChapter = sortedChapters()[nextIndex]
// get the end time of the current chapter from the start time of the next chapter
endTime = nextChapter.startTime
} else {
// unless it's the last chapter, in which case the end time is the end of the file
endTime = self.fileDuration
}
// convert the duration to MP4Duration
let chapterDuration = endTime - chapter.startTime
let mp4Duration = MP4Duration(chapterDuration)
// use the duration and chapter title to initialize an MP4Chapter_t object
let title = chapter.chapter.chapterTitle
var mp4Chapter = MP4Chapter_t()
mp4Chapter.duration = mp4Duration
withUnsafeMutableBytes(of: &mp4Chapter.title) { buffer in
buffer.copyBytes(from: title?.utf8 ?? defaultChapterTitle.utf8)
}
mp4Chapters.append(mp4Chapter)
}
return mp4Chapters
}
But I sort of struggle to figure out what to do with it from there. I think maybe I use MP4SetChapters
, but I'm not sure. But even if I'm right, I can't figure out what it needs for the chapterList
parameter of MP4SetChapters
:
let mp4Chapters = toc.mp4Chapters
let chapterCountInt = mp4Chapters.count
let chapterCountUInt32 = chapterCountInt.truncatedUInt32
MP4SetChapters(fileHandle,
<#T##chapterList: UnsafeMutablePointer<MP4Chapter_t>!##UnsafeMutablePointer<MP4Chapter_t>!#>,
chapterCountUInt32,
MP4ChapterTypeAny)
I'm just not sure what <#T##chapterList: UnsafeMutablePointer<MP4Chapter_t>!##UnsafeMutablePointer<MP4Chapter_t>!#>
is supposed to be.
Failing that, since all I require is a very simple and straightforward library that manages metadata and chapters for mp4 files (specifically, the audio files, such as podcasts and audiobooks), I thought perhaps I could create it myself from scratch. I know how to read the atoms and identify the various atoms from the file data, but what I don't understand is where the chapter data actually lives.
Looking at the MP4v2
code, it seems like if the chapter is a Quicktime chapter, if is stored in the gmhd
atom:
(void)InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "gmhd", 0);
or if it's a Nero chapter, it creates a chpl
atom, but examining a file that was created using Mp4v2
) neither of those atoms are in the file. In the stbl
subAtoms I can see a lot of stuff that creates samples in the same number of chapters in the file I'm dissecting, so I'm pretty sure that's related, but as far as where the chapter title and duration data, etc, exist, I can't find it.
Do you have any insight into this you could share with me?