Could you provide guidance on how to add chapter marks to an M4A. I've been attempting bookmark. From what I've read, it requires the use of
AVMetadataKey.quickTimeUserDataKeyChapter
track.addTrackAssociation(to: ... type: .chapterList)
or both.
I've looked into AVTimedMetadataGroup but I havent found a way to get it added based on the documentation. I also havent found anyone who has used native Swift to add chapter marks. They've always given in and used ffmpeg or some other external solution.
inputURL is for the file that is being read in
outputURL is for the the final file
chapters is an array of dictionaries, where time is the start of each chapter and its name in the list
The target is macOS
import AVFoundation
class AudioChapterCreator {
// Function to create an audio file with chapters and a chapter list
func createAudioFileWithChapters(inputURL: URL, outputURL: URL, chapters: [(time: CMTime, title: String)]) {
let options = [AVURLAssetPreferPreciseDurationAndTimingKey: true]
let asset = AVURLAsset(url: inputURL, options: options)
let durationInSeconds = CMTimeGetSeconds(asset.duration)
print("asset durationInSeconds: \(durationInSeconds)")
guard let audioTrack = asset.tracks(withMediaType: .audio).first else {
print("Error: Unable to find audio track in the asset.")
return
}
// Create metadata items for chapters
let chapterMetadataItems = chapters.map { chapter -> AVMetadataItem in
let item = AVMutableMetadataItem()
// this duration is just for testing
let tempDur = CMTime(seconds: 100, preferredTimescale: 1)
item.keySpace = AVMetadataKeySpace.quickTimeUserData
item.key = AVMetadataKey.quickTimeUserDataKeyChapter as NSString
item.value = chapter.title as NSString
item.time = chapter.time
item.duration = tempDur
return item
}
// Create an AVAssetExportSession for writing the output file
guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
print("Error: Unable to create AVAssetExportSession.")
return
}
// Configure the AVAssetExportSession
exportSession.outputFileType = .m4a
exportSession.outputURL = outputURL
exportSession.metadata = asset.metadata + chapterMetadataItems
exportSession.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: asset.duration);
// Export the audio file
exportSession.exportAsynchronously {
switch exportSession.status {
case .completed:
print("Audio file with chapters and chapter list created successfully.")
case .failed:
print("Error: Failed to create the audio file.")
case .cancelled:
print("Export cancelled.")
default:
print("Export failed with unknown status.")
}
}
}
}