I want to be able to add chapter marks to all major audio file formats, which FFmpeg does (using the -map_chapters option) – but FFmpeg always mangles the other metadata. Any tags it doesn’t recognize, it strips/drops from the target file. How do I add chapter marks to an audio file via the command line without manipulating any other metadata?
- 201
1 Answers
The simple solutions
There are some simpler solutions that are specific to certain file formats: For ID3 (.mp3, etc.) there’s mp3chap, for VorbisComment (.ogg, .flac, .opus, etc.) there’s… well, vorbiscomment, and for ISOBMFF (.mp4, .m4a, .m4b, etc.) there’s… really nothing but FFmpeg, at the time of writing. (If you’re alright with a GUI program, there’s Kid3 with the MP4v2 plugin enabled in the settings.) If anyone wants advice for how to use these, ping me and I can help – but for now, I’d like to focus on…
The “one size fits all” solution
There is a way to add chapters reliably in the same way to all major audio metadata formats – ID3 (.mp3, etc.), ISOBMFF (.mp4, .m4a, .m4b, etc.), and VorbisComment (.ogg, .flac, .opus, etc.). It’s a bit complicated, however, and is best suited to inclusion in scripts, rather than manual usage.
It requires two tools:
- FFmpeg, to add the chapters (which will drop some tags)…
- …and Kid3, to write the original tags back. (Of course it’s KDE – the quiet savior of the software world!)
Given an audio file, audio.m4a (can be any format, not just .m4a) and an FFmpeg metadata file containing the chapters, ffmetadata.txt (you can construct this manually, or for example use this Python script to convert an Audacity labels export), perform the the following steps:
ffmpeg -i audio.m4a -i ffmetadata.txt -map 0:a -map_metadata 1 -map_chapters 1 -codec copy temp.m4a
kid3-cli -c "timeout off" -c "select 'audio.m4a'" -c "copy" -c "select 'temp.m4a'" -c "paste" -c "save"
Then replace the original file with the temporary file (mv -f temp.m4a audio.m4a on Linux; move -force temp.m4a audio.m4a on PowerShell).
Note: It gets a bit more complicated if the original file already has chapters that you wish to replace, as Kid3 will copy chapters for certain file formats and thus reset the ones you just overwrote. For that, I’ve created a QML script that you can download and run in kid3-cli – the steps then become:
ffmpeg -i audio.m4a -i ffmetadata.txt -map 0:a -map_metadata 1 -map_chapters 1 -codec copy temp.m4a
kid3-cli -c "timeout off" -c "select 'audio.m4a'" -c "execute @qml 'DeselectChapterTags.qml'" -c "copy" -c "select 'temp.m4a'" -c "paste" -c "save"
This solution should work perfectly for everything.
Some notes…
In my days of research for this, I came across some incidental information that might come in handy for somebody, someday:
- Some answers suggest using ExifTool in Kid3’s place. This is a poor idea, as it strips tags it doesn’t recognize (notably, the
descdescription tag in ISOBMFF/MP4 metadata), putting us in the same mangly position as FFmpeg. - You may want to add
-movflags disable_chplto your FFmpeg invocation. In ISOBMFF/MP4 files, by default, FFmpeg creates both QuickTime-style chapters (using theCHAPatom) and Nero metadata chapters (using theCHPLatom). In practice, however, the QuickTime-style chapters have more widespread support. - For some reason, FFmpeg considers chapter titles to be part of
-map_metadataand not-map_chaptersfor ISOBMFF/MP4 files. That’s why both-map_chapters 1and-map_metadata 1is needed. - Kid3’s commands that change state (e.g.
pasteandsave) appear to only work when you’ve selected a file while it’s within the current working directory. If you’re running the Kid3 commands from another directory, add-c "cd 'your-audio-directory/'"anytime before the finalselect.
- 201