[ID3 Dev] Reading the MCDI frame
Troy Watson
drtwox at gmail.com
Mon Jul 14 01:27:04 PDT 2008
Hello everyone. I'm asking for some help reading (or more precisely,
skipping over) the MCDI frame in id3v2.3 and id3v2.4 tagged mp3 files.
I'm just starting out learning C, and as a learning exercise I've
written a small metadata reader for various audio formats. However,
there is one frame in some mp3s I can't, no matter how much I bang my
head, work out how to skip over.
My program reads the id3 header and finds the offset for the first
frame in the file. From there the frame header is read into a struct
like this:
typedef struct {
char name[4];
unsigned int size;
char flags[2];
} ID3_FRAME;
ID3_FRAME id3_frame;
I do a strcmp against id3_frame->name to see if this is a frame I'm
interested in reading. If it is I read and process it, and it it
isn't, fseek forward the value from id3_frame->size. Repeat until the
end of the id3 tag.
This works perfectly for the few thousand mp3 files I have *except*
any file with the MCDI frame. From what I can work out, the size I'm
reading for the MCDI frame is way off, and any fseek moves too far
into the tag, causing the next fread to get the wrong data. However,
the same code works for every other file if there is no MCDI frame.
Here's a hex dump of one tag as an example.
0000000: 49 44 33 04 00 00 00 00 15 0d 54 49 54 32 00 00 ID3.......TIT2..
0000010: 00 13 00 00 03 4d 61 64 20 4d 61 78 20 28 42 61 .....Mad Max (Ba
0000020: 64 20 4c 69 66 65 29 54 52 43 4b 00 00 00 02 00 d Life)TRCK.....
0000030: 00 03 32 54 43 4f 4e 00 00 00 03 00 00 03 32 30 ..2TCON.......20
0000040: 54 41 4c 42 00 00 00 10 00 00 03 43 6f 6d 6d 65 TALB.......Comme
0000050: 72 63 69 61 6c 20 5a 6f 6e 65 4d 43 44 49 00 00 rcial ZoneMCDI..
0000060: 01 38 00 00 46 00 2b 00 39 00 36 00 2b 00 34 00 .8..F.+.9.6.+.4.
0000070: 44 00 45 00 45 00 2b 00 39 00 36 00 30 00 30 00 D.E.E.+.9.6.0.0.
0000080: 2b 00 44 00 42 00 32 00 34 00 2b 00 31 00 31 00 +.D.B.2.4.+.1.1.
0000090: 42 00 30 00 32 00 2b 00 31 00 35 00 38 00 38 00 B.0.2.+.1.5.8.8.
00000a0: 38 00 2b 00 31 00 39 00 43 00 38 00 30 00 2b 00 8.+.1.9.C.8.0.+.
00000b0: 31 00 43 00 44 00 42 00 38 00 2b 00 32 00 30 00 1.C.D.B.8.+.2.0.
00000c0: 41 00 41 00 38 00 2b 00 32 00 33 00 37 00 43 00 A.A.8.+.2.3.7.C.
00000d0: 36 00 2b 00 32 00 37 00 31 00 43 00 38 00 2b 00 6.+.2.7.1.C.8.+.
00000e0: 32 00 42 00 45 00 38 00 41 00 2b 00 32 00 46 00 2.B.E.8.A.+.2.F.
00000f0: 41 00 34 00 45 00 2b 00 33 00 34 00 34 00 32 00 A.4.E.+.3.4.4.2.
0000100: 32 00 2b 00 33 00 41 00 43 00 36 00 45 00 2b 00 2.+.3.A.C.6.E.+.
0000110: 33 00 45 00 34 00 41 00 45 00 00 00 50 52 49 56 3.E.4.A.E...PRIV
0000120: 00 00 00 0e 00 00 50 65 61 6b 56 61 6c 75 65 00 ......PeakValue.
0000130: 27 69 00 00 50 52 49 56 00 00 00 11 00 00 41 76 'i..PRIV......Av
0000140: 65 72 61 67 65 4c 65 76 65 6c 00 ac 09 00 00 50 erageLevel.....P
0000150: 52 49 56 00 00 00 27 00 00 57 4d 2f 4d 65 64 69 RIV...'..WM/Medi
0000160: 61 43 6c 61 73 73 50 72 69 6d 61 72 79 49 44 00 aClassPrimaryID.
0000170: bc 7d 60 d1 23 e3 e2 4b 86 a1 48 a4 2a 28 44 1e .}`.#..K..H.*(D.
0000180: 50 52 49 56 00 00 00 29 00 00 57 4d 2f 4d 65 64 PRIV...)..WM/Med
0000190: 69 61 43 6c 61 73 73 53 65 63 6f 6e 64 61 72 79 iaClassSecondary
00001a0: 49 44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ID..............
00001b0: 00 00 00 50 52 49 56 00 00 00 1c 00 00 57 4d 2f ...PRIV......WM/
00001c0: 55 6e 69 71 75 65 46 69 6c 65 49 64 65 6e 74 69 UniqueFileIdenti
00001d0: 66 69 65 72 00 3b 00 00 00 54 50 45 32 00 00 00 fier.;...TPE2...
00001e0: 12 00 00 03 50 75 62 6c 69 63 20 49 6d 61 67 65 ....Public Image
00001f0: 20 4c 54 44 2e 54 50 45 31 00 00 00 15 00 00 03 LTD.TPE1.......
0000200: 50 75 62 6c 69 63 20 49 6d 61 67 65 20 4c 69 6d Public Image Lim
0000210: 69 74 65 64 54 4c 45 4e 00 00 00 07 00 00 03 32 itedTLEN.......2
0000220: 34 36 30 30 30 00 00 00 00 00 00 00 00 00 00 00 46000...........
0000230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0000240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Here's the output when run against this file:
Detected MP3, id3v2.4
frame_id: TIT2, size: 19
frame_id: TRCK, size: 2
frame_id: TCON, size: 3
frame_id: TALB, size: 16
frame_id: MCDI, size: 312
frame_id: dary, size: 1229193216
The MCDI frame size is read as 312, which is plainly NOT where the
MCDI frame ends, and as such the next fread into the struct is reading
from the wrong place. I've tried to find a spec for the TOC
information that the MCDI frame holds, but that hasn't turned up
anything useful either. The spec on id3.org has this to say:
"The frame consists of a binary dump of the Table Of Contents, TOC,
from the CD, which is a header of 4 bytes and then 8 bytes/track on
the CD plus 8 bytes for the 'lead out',".
Unless I'm reading it wrong, this file doesn't say how many tracks are
on the CD, so I can't calculate the MCDI frame size this way either.
Other software (Amarok for example) can read these files just fine, so
the file(s) can't be corrupt. I *could* retag them all and save the
headache, but I really want to know what I'm doing wrong. Please
help!
Note: If I've overlooked something totally obvious, or have made a
bad assumption, feel free to headbut me ;)
---------------------------------------------------------------------
To unsubscribe, e-mail: id3v2-unsubscribe at id3.org
For additional commands, e-mail: id3v2-help at id3.org
More information about the ID3v2
mailing list