/*---------------------------------------------------------------------------- .MP3 file dumper Chris Giese http://SisAndHappy.com/ChrisGiese This code is public domain (no copyright). You can do whatever you want with it. 24 Aug 2018: first release ----------------------------------------------------------------------------*/ #include /****************************************************************************/ int main(int arg_c, char *arg_v[]) { static const char *mpeg_ver[2] = { "MPEG-2", "MPEG-1" }; static const unsigned freq_table[2][4] = { { 22050u, 24000u, 16000u, 0 /* MPEG-2 */ }, { 44100u, 48000u, 32000u, 0 /* MPEG-1 */ } }; static const unsigned short bitrate_table[2][4][16] = { {/* MPEG-2 */ {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0}, {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}, {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} },{/* MPEG-1 */ {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} } }; static const char *mode_table[4] = { "stereo", "joint stereo", "dual-channel", "mono" }; static char buf[4]; /**/ unsigned mpeg_id, layer, no_crc, bitrate_index, freq_index; unsigned has_padding, mode/*, mode_ext*/, bitrate, freq, bytes; unsigned long pos; FILE *in; int i; if(arg_c != 2) { printf("Dumps .MP3 files\n"); return 1; } if((in = fopen(arg_v[1], "rb")) == NULL) { printf("Error: can't open input file %s\n", arg_v[1]); return 2; } buf[0] = 0xFF; while(1) { /* eleven '1' bits = sync at start of an MP3 frame */ do { do { if((i = fgetc(in)) == EOF) goto DONE; } while(i != 0xFF); if((i = fgetc(in)) == EOF) goto DONE; } while((i & 0xE0) != 0xE0); /* it _still_ might not be an MP3 header -- validate below */ buf[1] = i; pos = ftell(in) - 2; /* read remaining two bytes of header */ if(fread(&buf[2], 1, 2, in) != 2) { printf("Error: unexpected end of input file %s\n", arg_v[1]); return 2; } /* ID: 1=MPEG-1, 0=MPEG-2 */ mpeg_id = (buf[1] >> 3) & 1; /* layer: 0=?, 1=layer III, 2=layer II, 3=layer I */ layer = (buf[1] >> 1) & 3; no_crc = (buf[1] & 1); bitrate_index = (buf[2] >> 4) & 15; freq_index = (buf[2] >> 2) & 3; has_padding = (buf[2] >> 1) & 1; mode = (buf[3] >> 6) & 3; // mode_ext = mode ? 0 : (buf[3] >> 4) & 3; /* validate */ if(layer == 0 || bitrate_index == 15 || freq_index == 3) { fseek(in, -3, SEEK_CUR); continue; } /* variable frame size ("free format") */ if(bitrate_index == 0) { fseek(in, -3, SEEK_CUR); continue; } bitrate = bitrate_table[mpeg_id][3 - layer] [bitrate_index]; freq = freq_table[mpeg_id][freq_index]; printf("%7lu ID=%u (%s), layer=%u, no_crc=%u, bitrate_" "index=%2u (bitrate=%3u), freq_index=%u (freq=%u), " "has_padding=%u, mode=%u (%s)\n", pos, mpeg_id, mpeg_ver[mpeg_id], 4 - layer, no_crc, bitrate_index, bitrate, freq_index, freq, has_padding, mode, mode_table[mode]); bytes = (unsigned)((mpeg_id ? 144000L : 72000L) * bitrate / freq); if(has_padding) bytes++; if(!no_crc) bytes += 2; fseek(in, pos + bytes, SEEK_SET); } DONE: fclose(in); return 0; }