mirror of
https://github.com/ALLFATHER-BV/wadamesh.git
synced 2026-09-25 11:14:35 +00:00
Work
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void* testMp3Scratch();
|
||||
#define MINIMP3_ONLY_MP3
|
||||
#define MINIMP3_NO_SIMD
|
||||
#define MINIMP3_SCRATCH ((mp3dec_scratch_t*)testMp3Scratch())
|
||||
#define MINIMP3_IMPLEMENTATION
|
||||
#include "../lib/minimp3/minimp3.h"
|
||||
|
||||
static mp3dec_scratch_t g_scratch;
|
||||
static void* testMp3Scratch() { return &g_scratch; }
|
||||
|
||||
struct DecodeBuffer {
|
||||
uint8_t input[16 * 1024];
|
||||
mp3d_sample_t pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
|
||||
};
|
||||
|
||||
static uint32_t readLe32(const uint8_t* value) {
|
||||
return (uint32_t)value[0] | ((uint32_t)value[1] << 8) |
|
||||
((uint32_t)value[2] << 16) | ((uint32_t)value[3] << 24);
|
||||
}
|
||||
|
||||
static long mp3DataEnd(FILE* file) {
|
||||
assert(fseek(file, 0, SEEK_END) == 0);
|
||||
long end = ftell(file);
|
||||
assert(end >= 0);
|
||||
uint8_t footer[128];
|
||||
if (end >= 128 && fseek(file, end - 128, SEEK_SET) == 0 &&
|
||||
fread(footer, 1, 3, file) == 3 && !memcmp(footer, "TAG", 3)) {
|
||||
end -= 128;
|
||||
}
|
||||
if (end >= 32 && fseek(file, end - 32, SEEK_SET) == 0 &&
|
||||
fread(footer, 1, 32, file) == 32 && !memcmp(footer, "APETAGEX", 8)) {
|
||||
const uint32_t version = readLe32(footer + 8);
|
||||
const uint32_t tag_size = readLe32(footer + 12);
|
||||
const uint32_t flags = readLe32(footer + 20);
|
||||
const uint64_t total_size = (uint64_t)tag_size + ((flags & 0x80000000u) ? 32u : 0u);
|
||||
if ((version == 1000 || version == 2000) && tag_size >= 32 && total_size <= (uint64_t)end)
|
||||
end -= (long)total_size;
|
||||
}
|
||||
rewind(file);
|
||||
return end;
|
||||
}
|
||||
|
||||
static bool decodeFile(const char* path) {
|
||||
FILE* file = fopen(path, "rb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "%s: could not open\n", path);
|
||||
return false;
|
||||
}
|
||||
const long data_end = mp3DataEnd(file);
|
||||
if (data_end <= 0) { fclose(file); return false; }
|
||||
|
||||
DecodeBuffer buffer;
|
||||
mp3dec_t decoder;
|
||||
mp3dec_init(&decoder);
|
||||
size_t input_start = 0, input_count = 0;
|
||||
uint64_t samples_total = 0;
|
||||
int frames = 0, sample_rate = 0, channels = 0, bitrate_changes = 0;
|
||||
int last_bitrate = 0;
|
||||
bool eof = false, ok = true;
|
||||
|
||||
while (ok) {
|
||||
if (!eof && input_count < 4096) {
|
||||
if (input_start && input_start + input_count + 4096 > sizeof buffer.input) {
|
||||
memmove(buffer.input, buffer.input + input_start, input_count);
|
||||
input_start = 0;
|
||||
}
|
||||
size_t room = sizeof buffer.input - (input_start + input_count);
|
||||
const long position = ftell(file);
|
||||
const size_t remaining = position < data_end ? (size_t)(data_end - position) : 0;
|
||||
if (room > remaining) room = remaining;
|
||||
const size_t got = fread(buffer.input + input_start + input_count, 1, room, file);
|
||||
if (got > 0) {
|
||||
input_count += got;
|
||||
eof = ftell(file) >= data_end;
|
||||
}
|
||||
else if (ferror(file)) ok = false;
|
||||
else eof = true;
|
||||
}
|
||||
|
||||
if (!ok || !input_count) break;
|
||||
|
||||
mp3dec_frame_info_t info = {};
|
||||
const int samples = mp3dec_decode_frame(&decoder, buffer.input + input_start,
|
||||
(int)input_count, buffer.pcm, &info);
|
||||
if (info.frame_bytes < 0 || (size_t)info.frame_bytes > input_count) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if (info.frame_bytes > 0) {
|
||||
input_start += (size_t)info.frame_bytes;
|
||||
input_count -= (size_t)info.frame_bytes;
|
||||
if (!input_count) input_start = 0;
|
||||
} else if (eof) {
|
||||
break;
|
||||
} else if (input_start + input_count == sizeof buffer.input) {
|
||||
ok = false;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (samples <= 0) continue;
|
||||
if (info.layer != 3 || (info.channels != 1 && info.channels != 2) ||
|
||||
info.hz < 8000 || info.hz > 48000) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if (!sample_rate) {
|
||||
sample_rate = info.hz;
|
||||
channels = info.channels;
|
||||
} else if (sample_rate != info.hz) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if (last_bitrate && last_bitrate != info.bitrate_kbps) ++bitrate_changes;
|
||||
last_bitrate = info.bitrate_kbps;
|
||||
samples_total += (uint64_t)samples;
|
||||
++frames;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
if (!ok || frames == 0 || samples_total == 0) {
|
||||
fprintf(stderr, "%s: decode failed after %d frames\n", path, frames);
|
||||
return false;
|
||||
}
|
||||
printf("%s: %d frames, %llu samples/channel, %d Hz, %d channel(s), %d bitrate changes\n",
|
||||
path, frames, (unsigned long long)samples_total, sample_rate, channels,
|
||||
bitrate_changes);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %s file.mp3 [file.mp3 ...]\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
for (int i = 1; i < argc; ++i) assert(decodeFile(argv[i]));
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user