75 lines
2.2 KiB
C
75 lines
2.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <inttypes.h>
|
|
|
|
// Simplified frame length calculation (MPEG1 Layer3 only)
|
|
uint32_t calc_frame_len(uint32_t header) {
|
|
const int bitrates[] = {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320};
|
|
const int samplerates[] = {44100, 48000, 32000};
|
|
|
|
int br_idx = (header >> 12) & 0xF;
|
|
int sr_idx = (header >> 10) & 0x3;
|
|
int padding = (header >> 9) & 0x1;
|
|
|
|
int bitrate = bitrates[br_idx] * 1000;
|
|
int samplerate = samplerates[sr_idx];
|
|
|
|
return 144 * bitrate / samplerate + padding;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if(argc != 2) return fprintf(stderr, "Usage: %s <input_file>\n", argv[0]), 1;
|
|
|
|
FILE* fin = fopen(argv[1], "rb");
|
|
if(!fin) return perror("fopen"), 1;
|
|
|
|
FILE* fout = NULL;
|
|
long file_count = 0;
|
|
uint32_t pos = 0;
|
|
uint32_t header;
|
|
uint8_t buf[4];
|
|
|
|
while(fread(buf, 1, 4, fin) == 4) {
|
|
header = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
|
|
|
// Check for valid MP3 header: 0xFF 0xE? (sync + version)
|
|
if(buf[0] == 0xFF && (buf[1] & 0xE0) == 0xE0) {
|
|
uint32_t frame_len = calc_frame_len(header >> 8);
|
|
|
|
if(frame_len > 0 && frame_len < (10*1024*1024)) { // Sanity check
|
|
if(!fout) {
|
|
char fname[128];
|
|
snprintf(fname, sizeof(fname), "output_%ld.mp3", file_count++);
|
|
fout = fopen(fname, "wb");
|
|
if(!fout) { perror("fopen output"); break; }
|
|
printf("Extracting %s\n", fname);
|
|
}
|
|
|
|
// Save header
|
|
fwrite(buf, 1, 4, fout);
|
|
// Save frame data
|
|
for(uint32_t i = 4; i < frame_len; i++) {
|
|
int c = fgetc(fin);
|
|
if(c == EOF) break;
|
|
fputc(c, fout);
|
|
}
|
|
pos = ftell(fin);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if(fout) {
|
|
fclose(fout);
|
|
fout = NULL;
|
|
}
|
|
|
|
// Rewind 3 bytes to allow overlapping frames
|
|
fseek(fin, ++pos, SEEK_SET);
|
|
}
|
|
|
|
if(fout) fclose(fout);
|
|
fclose(fin);
|
|
return 0;
|
|
}
|