Frame size is equal to (144 * bitrate / samplerate) + 1 (if padding is set)
However, if the protection bit is NOT set, a 16-bit CRC-checksum is added
between the frame header and the audio data. Is this checksum taken from the
audio-data bits? Or should the frame size be equal to (144 * bitrate /
samplerate) + 1 (padding byte) + 2 (checksum bytes)?
In an untagged MP3 file (or even a ID3v1 tagged one), I'd expected the first
frame to begin at byte 0. WinAmp indeed reports: 'Header found at: 0 bytes'.
When I read the file (I tried with both File Mapping and reading by
Random-Access), the file never starts with sync-bits. Instead, I find the
first frame at offset 622. I cleaned the file with both mp3Trim and VBRFix,
removing all possible tags. Is there any explanation for this? In VBR files,
the first frame my app finds is usually 4 bytes off compared to what WinAmp
reports.
With kind regards,
Matthias Claes
Hi Matthias,
I don't know how many MP3 format experts we have in the group if any. Most
of us that use MP3 format do so with the use of 3rd party filters that do
all the grunt work for us. You probably want to find a good MP3 format
discussion group or book that discusses the format in detail.
I went through the groupslist my ISP's newsserver offers, but nothing comes
close. Guess I'll have to keep plowing through the web.
Matthias Claes
Matthias Claes wrote:
--
/**
* Alessandro Angeli
*
* MVP::DigitalMedia
*
* a dot angeli at biosys dot net
*/
-----------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#define MPA_SYNC_CODE 0xFFE00000UL
struct {
int major;
int minor;
} versions[/* version */] = { {2,5}, {0,0}, {2,0}, {1,0}, };
int layers[/* layer */] = { 0, 3, 2, 1, };
char *booleans[/* boolean */] = { "no", "yes", };
int bitrates[4 /* version */][4 /* layer */][16 /* bitrate */] = {
{ /* V2.5 */
/* L0 */ { 0, },
/* L3 */ { 0, },
/* L2 */ { 0, },
/* L1 */ { 0, },
},
{ /* V0.0 */
/* L0 */ { 0, },
/* L3 */ { 0, },
/* L2 */ { 0, },
/* L1 */ { 0, },
},
{ /* V2.0 */
/* L0 */ { 0, },
/* L3 */ { 0, },
/* L2 */ { 0, },
/* L1 */ { 0, },
},
{ /* V1.0 */
/* L0 */ { 0, },
/* L3 */ { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256,
320, -1, },
/* L2 */ { 0, },
/* L1 */ { 0, },
},
};
int samplerates[4 /* version */][4 /* samplerate */] = {
/* V2.5 */ { 11025, 12000, 8000, -1, },
/* V0.0 */ { -1, -1, -1, -1, },
/* V2.0 */ { 22050, 24000, 16000, -1, },
/* V1.0 */ { 44100, 48000, 32000, -1, },
};
char *chanmodes[] = { "stereo", "joint stereo", "dual channel", "mono", };
struct {
int intensity;
int ms;
} extensions[] = { {0,0}, {1,0}, {0,1}, {1,1}, };
char *emphasises[] = { "none", "50/12 ms", "(reserved)", "CCITT J.17", };
int coeffs[4 /* version */][4 /* layer */] = {
/* V2.5 */ { 0, 0, 0, 0, },
/* V0.0 */ { 0, 0, 0, 0, },
/* V2.0 */ { 0, 72000, 72000, 24000, },
/* V1.0 */ { 0, 144000, 144000, 48000, },
};
int main(int argc, char *argv[])
{
int rc = 0;
FILE *hf = NULL;
unsigned long hdr = 0x00000000UL;
unsigned char b;
long offset;
int version;
int layer;
int protection;
int bitrate;
int samplerate;
int padding;
int private;
int chanmode;
int extension;
int copyright;
int original;
int emphasis;
int size;
printf("*** fopen(\"%s\")...\n",argv[1]);
if(NULL == (hf = fopen(argv[1],"rb"))) { rc = errno; goto exit; }
while(1) {
if(fread(&b,1,1,hf) < 1) { rc = errno; goto exit; }
hdr = (hdr << 8) | b;
if((hdr & MPA_SYNC_CODE) == MPA_SYNC_CODE) {
if((offset = ftell(hf)) < 0) { rc = errno; goto exit; }
offset -= 4;
printf("*** frame header found @ 0x%08lX (%ld):\n",offset,offset);
/// hdr = hdr & ~MPA_SYNC_CODE;
version = (hdr >> 19) & 0x03;
layer = (hdr >> 17) & 0x03;
protection = (hdr >> 16) & 0x01; protection = 1 - protection;
bitrate = (hdr >> 12) & 0x0F;
samplerate = (hdr >> 10) & 0x03;
padding = (hdr >> 9) & 0x01;
private = (hdr >> 8) & 0x01;
chanmode = (hdr >> 6) & 0x03;
extension = (hdr >> 4) & 0x03;
copyright = (hdr >> 3) & 0x01;
original = (hdr >> 2) & 0x01;
emphasis = (hdr >> 0) & 0x03;
printf(">>>\t version .. = (%d) MPEG
%d.%d\n",version,versions[version].major,versions[version].minor);
printf(">>>\t layer .... = (%d) Layer %d\n",layer,layers[layer]);
printf(">>>\t protection = (%d) %s\n",protection,booleans[protection]);
printf(">>>\t bitrate .. = (%d) %d
Kbps\n",bitrate,bitrates[version][layer][bitrate]);
printf(">>>\t samplerate = (%d) %d
Hz\n",samplerate,samplerates[version][samplerate]);
printf(">>>\t padding .. = (%d) %s\n",padding,booleans[padding]);
printf(">>>\t private .. = (%d) %s\n",private,booleans[private]);
printf(">>>\t chanmode . = (%d) %s\n",chanmode,chanmodes[chanmode]);
printf(">>>\t extension = (%d) Intensity stereo = %s, MS stereo =
%s\n",extension,booleans[extensions[extension].intensity],booleans[extension
s[extension].ms]);
printf(">>>\t copyright = (%d) %s\n",copyright,booleans[copyright]);
printf(">>>\t original . = (%d) %s\n",original,booleans[original]);
printf(">>>\t emphasis . = (%d) %s\n",emphasis,emphasises[emphasis]);
size = coeffs[version][layer]
* bitrates[version][layer][bitrate]
/ samplerates[version][samplerate]
+ padding - 4;
printf(">>>\t payload .. = %d bytes\n",size);
if(fseek(hf,size,SEEK_CUR)) { rc = errno; goto exit; }
}
}
exit:
printf(">>> rc = %d\n",rc);
if(hf) (void)fclose(hf);
return rc;
}
-----------------------------------------------------------------
--
Alessandro Angeli
MVP::DigitalMedia