Metadata when Remuxing MP3 Audiobooks into Apple-friendly MP4 with FFmpeg

699 views Asked by At

Since there is apparently no way to tell iTunes or iOS that MP3s contain an audiobook (or radioplay) by ID3 tag or file extension, I would like to remux them into MPEG-4 Part 14 containers with an .m4b file extension (without converting, i.e. transcoding or reencoding, the audio stream to AAC) and set the proper media type tag (stik = 2 Audiobook).

$ ffmpeg -hide_banner -y \
         -i "infile.mp3" -codec copy -map 0 \
         "outfile.m4b"

When auto-detecting the intended format from the output filename, FFmpeg (version 4.2.1 at the time of writing) toggles its -f ipod compatibility mode for .m4a and .m4b, which means it will apparently not accept MPEG 1/2 Layer 3 audio within an MP4 container:

[ipod @ 00000223bd927e40]
Could not find tag for codec mp3 in stream #0, codec not currently supported in container
Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument

I can override that (or change the file extension afterwards when using "outfile.mp4"):

$ ffmpeg -hide_banner -y \
         -i "infile.mp3" -codec copy -map 0 -f mp4 \
         "outfile.m4b"

The near-zero time required for the conversion and FFprobe assure me that the remuxing was successful:

Stream #0:0(und): Audio: mp3 (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 160 kb/s (default)

Custom ID3v2 tag fields and ones without a known MP4 cognate have been dropped, though. I would like to preserve them!

How do I do that with -map_metadata, if it is possible at all?

How can I use -metadata to add the necessary tag field (atom: stik) which would mark the file as an audiobook – phrased more generally:
how do I add a manually specified metadata tag field (e.g. MP4 atom or box) with FFmpeg?

$ ffmpeg -hide_banner -y \
         -i "infile.mp3" -codec copy -map 0 -f mp4 \
         -metadata:s:a:0 language=deu \
         -metadata stik=2
         "outfile.m4b"

FFmpeg documentation

  • -metadata[:metadata_specifier] key=value (output,per-metadata)
    Set a metadata key/value pair.
  • -map_metadata[:metadata_spec_out] infile[:metadata_spec_in] (output,per-metadata)
    Set metadata information of the next output file from infile. Note that those are file indices (zero-based), not filenames. Optional metadata_spec_in/out parameters specify, which metadata to copy. A metadata specifier can have the following forms:
    • g
      global metadata, i.e. metadata that applies to the whole file
    • s[:stream_spec]
      per-stream metadata. stream_spec is a stream specifier as described in the Stream specifiers chapter. In an input metadata specifier, the first matching stream is copied from. In an output metadata specifier, all matching streams are copied to.
    • c:chapter_index
      per-chapter metadata. chapter_index is the zero-based chapter index.
    • p:program_index
      per-program metadata. program_index is the zero-based program index.

If metadata specifier is omitted, it defaults to global.

By default, global metadata is copied from the first input file, per-stream and per-chapter metadata is copied along with streams/chapters. These default mappings are disabled by creating any mapping of the relevant type. A negative file index can be used to create a dummy mapping that just disables automatic copying.

PS

  • Apple does not seem to formally document stik. MPMediaType is slightly different. Pointers to the contrary would be greatly appreciated.
  • Ideally, I would like to automatically add all *.mp3 files within a subdirectory sorted alphabetically (which share the same encoder settings) as chapters within a single .mp4 container, but that probably deserves a separate question.
0

There are 0 answers