How to Convert wav to m4a with Tags Toyota Car Navigation Can Read
When playing an SD card in a Toyota factory-installed car navigation system, m4a files created with ffmpeg play fine but show (NO DATA) for track title, artist, and album. Rebuilding them with afconvert, which ships with macOS, makes the tags readable.
What works
afconvert -f m4af -d aac -b 256000 input.wav output.m4a
Write the tags with mutagen.
from mutagen.mp4 import MP4
f = MP4("output.m4a")
f["\xa9nam"] = ["Track Title"]
f["\xa9ART"] = ["Artist Name"]
f["aART"] = ["Artist Name"]
f["\xa9alb"] = ["Album Name"]
f["trkn"] = [(4, 25)]
f.save()
afconvert places the moov atom at the front of the file from the start and reserves a free block for tags, so there is no need for a post-processing pass equivalent to -movflags +faststart.
Do not run the file through ffmpeg after tagging. Even -c copy rebuilds the container in ffmpeg's own layout, and the tags stop being readable again.
Why ffmpeg output fails
The parser in the head unit assumes the hdlr atom is always exactly 34 bytes.
hdlr ends with a variable-length name field, so its size depends on who wrote it.
meta > hdlr |
mdia > hdlr |
|
|---|---|---|
| iTunes / afconvert | 34 (name is two zero bytes) | 34 (empty name) |
| ffmpeg | 33 (name is one zero byte) | 45 (name is "SoundHandler") |
A parser that hardcodes 34 bytes to compute where the next atom begins lands one byte off in an ffmpeg-produced file, reads garbage where ilst should start, and concludes there are no tags. Reading the audio track goes through a different code path, which is why playback still succeeds.
ffmpeg also adds an edts edit list under trak, plus sgpd and sbgp under stbl. Neither iTunes nor afconvert writes any of these.
What does not work
None of the following changed what the head unit displayed.
- Moving moov to the front of the file with
-movflags +faststart - Matching iTunes in
ftyp(settingminor_versionto 0 and includingmp42incompatible_brands) - Embedding album art (
covr) - Stripping extra tags (the
©cmtcomment and the©tooencoder name) - Resampling from 48 kHz down to 44.1 kHz — 48 kHz plays back fine to begin with
- Rewriting the tags of an ffmpeg file with mutagen, since mutagen leaves
hdlralone and ffmpeg's 33 bytes survive
Patching hdlr from 33 to 34 bytes at the byte level is not enough either: mdia > hdlr is still 45 bytes and the tags stay unreadable. Fixing ffmpeg's differences one at a time is not worth the effort.
Copy protection (CPRM / SD-Audio) has nothing to do with this. CPRM-protected music lives in an SD_AUDIO folder as encrypted files, with the key stored in the card's protected area. A file copied in Finder can never end up in that format, and if the card has no SD_AUDIO folder, the whole mechanism is out of the picture.
Checking a file you already have
Looking at the hdlr sizes tells you the answer before you walk out to the car.
import struct
import sys
d = open(sys.argv[1], "rb").read(400000)
i = d.find(b"mdirappl") # the meta hdlr sits just before mdir/appl
h = d.rfind(b"hdlr", 0, i)
print("meta hdlr:", struct.unpack(">I", d[h - 4:h])[0])
f = d.find(b"hdlr") # the first hdlr in the file belongs to mdia
print("mdia hdlr:", struct.unpack(">I", d[f - 4:f])[0])
Both 34 means the tags will be read. A 33 or a 45 means ffmpeg wrote it and the head unit will not read it as is.
Isolating the cause in the car
Because playback succeeds, staring at the files gets you nowhere. Build a test folder holding one file per hypothesis and try them all in a single drive.
Two things make this work.
Put the condition name in the title tag. If T2.m4a carries the title tag TAG2 OK, then seeing TAG2 OK on screen means the tag was read, and seeing T2 means the unit fell back to the filename. You can tell them apart from the driver's seat at a glance.
Drop in one MP3 with ID3v2 tags as a control, in the same folder. If that MP3 reads and the m4a files do not, the problem is confined to the m4a container layout. Anything that applies equally to every file in the folder — the state of the card, the behaviour of the head unit — is ruled out at the same time.
We look forward to discussing your development needs.