ref: ea70d0b775b2d589d1697d1e1dfbc744ecab814e
parent: 682006f91a95058ad3927b46c7d99df1d674d3e1
author: lieff <[email protected]>
date: Wed Feb 12 20:59:36 EST 2020
mp3dec_ex: implement mp3dec_load_cb, improve test
--- a/minimp3_ex.h
+++ b/minimp3_ex.h
@@ -81,7 +81,7 @@
#endif
/* decode whole buffer block */
-void mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);
+int mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);
int mp3dec_load_cb(mp3dec_t *dec, mp3dec_io_t *io, uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);
/* iterate through frames */
size_t mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data);
@@ -134,8 +134,9 @@
static size_t mp3dec_skip_id3v2(const uint8_t *buf, size_t buf_size)
{
+#define MINIMP3_ID3_DETECT_SIZE 10
#ifndef MINIMP3_NOSKIP_ID3V2
- if (buf_size >= 10 && !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80)))
+ if (buf_size >= MINIMP3_ID3_DETECT_SIZE && !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80)))
{
size_t id3v2size = (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10;
if ((buf[5] & 16))
@@ -210,8 +211,13 @@
return 1;
}
-void mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)
+int mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)
{
+ return mp3dec_load_cb(dec, 0, (uint8_t *)buf, buf_size, info, progress_cb, user_data);
+}
+
+int mp3dec_load_cb(mp3dec_t *dec, mp3dec_io_t *io, uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)
+{
uint64_t detected_samples = 0;
size_t orig_buf_size = buf_size;
int to_skip = 0;
@@ -218,10 +224,31 @@
mp3dec_frame_info_t frame_info;
memset(info, 0, sizeof(*info));
memset(&frame_info, 0, sizeof(frame_info));
+
/* skip id3 */
- mp3dec_skip_id3(&buf, &buf_size);
- if (!buf_size)
- return;
+ size_t filled, consumed;
+ int eof;
+ if (io)
+ {
+ io->seek(0, io->seek_data);
+ filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data), consumed = 0, eof = 0;
+ if (MINIMP3_ID3_DETECT_SIZE != filled)
+ return 0;
+ size_t id3v2size = mp3dec_skip_id3v2(buf, filled);
+ if (id3v2size)
+ {
+ io->seek(id3v2size, io->seek_data);
+ filled = io->read(buf, buf_size, io->read_data);
+ } else
+ filled += io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data);
+ if (filled < MINIMP3_BUF_SIZE)
+ mp3dec_skip_id3v1(buf, &filled);
+ } else
+ {
+ mp3dec_skip_id3((const uint8_t **)&buf, &buf_size);
+ if (!buf_size)
+ return 0;
+ }
/* try to make allocation size assumption by first frame or vbr tag */
mp3dec_init(dec);
int samples;
@@ -228,14 +255,33 @@
do
{
uint32_t frames;
- int delay, padding, free_format_bytes = 0, frame_size = 0;
- int i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size);
- buf += i;
- buf_size -= i;
+ int i, delay, padding, free_format_bytes = 0, frame_size = 0;
+ if (io)
+ {
+ if (!eof && filled - consumed < MINIMP3_BUF_SIZE)
+ { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */
+ memmove(buf, buf + consumed, filled - consumed);
+ filled -= consumed;
+ consumed = 0;
+ size_t readed = io->read(buf + filled, buf_size - filled, io->read_data);
+ if (readed != (buf_size - filled))
+ eof = 1;
+ filled += readed;
+ if (eof)
+ mp3dec_skip_id3v1(buf, &filled);
+ }
+ i = mp3d_find_frame(buf + consumed, filled - consumed, &free_format_bytes, &frame_size);
+ consumed += i;
+ } else
+ {
+ i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size);
+ buf += i;
+ buf_size -= i;
+ }
if (i && !frame_size)
continue;
if (!frame_size)
- return;
+ return 0;
const uint8_t *hdr = buf;
frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2;
frame_info.hz = hdr_sample_rate_hz(hdr);
@@ -253,9 +299,15 @@
if (padding > 0 && detected_samples >= (uint64_t)padding)
detected_samples -= padding;
if (!detected_samples)
- return;
- buf += frame_size;
- buf_size -= frame_size;
+ return 0;
+ if (io)
+ {
+ consumed += frame_size;
+ } else
+ {
+ buf += frame_size;
+ buf_size -= frame_size;
+ }
}
break;
} while(1);
@@ -266,7 +318,7 @@
allocated += (buf_size/frame_info.frame_bytes)*samples*sizeof(mp3d_sample_t);
info->buffer = (mp3d_sample_t*)malloc(allocated);
if (!info->buffer)
- return;
+ return MP3D_E_MEMORY;
/* save info */
info->channels = frame_info.channels;
info->hz = frame_info.hz;
@@ -273,7 +325,6 @@
info->layer = frame_info.layer;
/* decode all frames */
size_t avg_bitrate_kbps = 0, frames = 0;
- int frame_bytes;
do
{
if ((allocated - info->samples*sizeof(mp3d_sample_t)) < MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t))
@@ -281,10 +332,28 @@
allocated *= 2;
info->buffer = (mp3d_sample_t*)realloc(info->buffer, allocated);
}
- samples = mp3dec_decode_frame(dec, buf, MINIMP3_MIN(buf_size, (size_t)INT_MAX), info->buffer + info->samples, &frame_info);
- frame_bytes = frame_info.frame_bytes;
- buf += frame_bytes;
- buf_size -= frame_bytes;
+ if (io)
+ {
+ if (!eof && filled - consumed < MINIMP3_BUF_SIZE)
+ { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */
+ memmove(buf, buf + consumed, filled - consumed);
+ filled -= consumed;
+ consumed = 0;
+ size_t readed = io->read(buf + filled, buf_size - filled, io->read_data);
+ if (readed != (buf_size - filled))
+ eof = 1;
+ filled += readed;
+ if (eof)
+ mp3dec_skip_id3v1(buf, &filled);
+ }
+ samples = mp3dec_decode_frame(dec, buf + consumed, filled - consumed, info->buffer + info->samples, &frame_info);
+ consumed += frame_info.frame_bytes;
+ } else
+ {
+ samples = mp3dec_decode_frame(dec, buf, MINIMP3_MIN(buf_size, (size_t)INT_MAX), info->buffer + info->samples, &frame_info);
+ buf += frame_info.frame_bytes;
+ buf_size -= frame_info.frame_bytes;
+ }
if (samples)
{
if (info->hz != frame_info.hz || info->layer != frame_info.layer)
@@ -309,7 +378,7 @@
if (progress_cb)
progress_cb(user_data, orig_buf_size, orig_buf_size - buf_size, &frame_info);
}
- } while (frame_bytes);
+ } while (frame_info.frame_bytes);
if (detected_samples && info->samples > detected_samples)
info->samples = detected_samples; /* cut padding */
/* reallocate to normal buffer size */
@@ -317,6 +386,7 @@
info->buffer = (mp3d_sample_t*)realloc(info->buffer, info->samples*sizeof(mp3d_sample_t));
if (frames)
info->avg_bitrate_kbps = avg_bitrate_kbps/frames;
+ return 0;
}
size_t mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data)
@@ -363,11 +433,13 @@
if (buf_size < MINIMP3_BUF_SIZE)
return 0;
io->seek(0, io->seek_data);
- size_t filled = io->read(buf, 10, io->read_data), consumed = 0;
+ size_t filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data), consumed = 0;
uint64_t readed = 0, frames = 0;
mp3dec_frame_info_t frame_info;
int eof = 0;
memset(&frame_info, 0, sizeof(frame_info));
+ if (MINIMP3_ID3_DETECT_SIZE != filled)
+ return 0;
size_t id3v2size = mp3dec_skip_id3v2(buf, filled);
if (id3v2size)
{
@@ -375,7 +447,7 @@
filled = io->read(buf, buf_size, io->read_data);
readed += id3v2size;
} else
- filled += io->read(buf + 10, buf_size - 10, io->read_data);
+ filled += io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data);
if (filled < MINIMP3_BUF_SIZE)
mp3dec_skip_id3v1(buf, &filled);
do
--- a/minimp3_test.c
+++ b/minimp3_test.c
@@ -14,10 +14,15 @@
#include <strings.h>
#endif
-#define MODE_LOAD 0
-#define MODE_ITERATE 1
-#define MODE_STREAM 2
-#define MODE_STREAM_CB 3
+#define MODE_LOAD 0
+#define MODE_LOAD_BUF 1
+#define MODE_LOAD_CB 2
+#define MODE_ITERATE 3
+#define MODE_ITERATE_BUF 4
+#define MODE_ITERATE_CB 5
+#define MODE_STREAM 6
+#define MODE_STREAM_BUF 7
+#define MODE_STREAM_CB 8
static int16_t read16le(const void *p)
{
@@ -115,31 +120,75 @@
int no_std_vec = strstr(input_file_name, "nonstandard") || strstr(input_file_name, "ILL");
double MSE = 0.0, psnr;
+ mp3dec_io_t io;
mp3dec_file_info_t info;
memset(&info, 0, sizeof(info));
+ io.read = read_cb;
+ io.seek = seek_cb;
if (MODE_LOAD == mode)
{
res = mp3dec_load(&mp3d, input_file_name, &info, 0, 0);
+ } else if (MODE_LOAD_BUF == mode)
+ {
+ int size = 0;
+ FILE *file = fopen(input_file_name, "rb");
+ uint8_t *buf = preload(file, &size);
+ fclose(file);
+ res = buf ? mp3dec_load_buf(&mp3d, buf, size, &info, 0, 0) : -1;
+ free(buf);
+ } else if (MODE_LOAD_CB == mode)
+ {
+ uint8_t *io_buf = malloc(MINIMP3_IO_SIZE);
+ FILE *file = fopen(input_file_name, "rb");
+ io.read_data = io.seek_data = file;
+ res = file ? mp3dec_load_cb(&mp3d, &io, io_buf, MINIMP3_IO_SIZE, &info, 0, 0) : -1;
+ fclose((FILE*)io.read_data);
+ free(io_buf);
} else if (MODE_ITERATE == mode)
{
frames_iterate_data d = { &mp3d, &info, 0 };
mp3dec_init(&mp3d);
res = mp3dec_iterate(input_file_name, frames_iterate_cb, &d) > 0 ? 0 : -1;
- } else if (MODE_STREAM == mode || MODE_STREAM_CB == mode)
+ } else if (MODE_ITERATE_BUF == mode)
{
+ int size = 0;
+ FILE *file = fopen(input_file_name, "rb");
+ uint8_t *buf = preload(file, &size);
+ fclose(file);
+ frames_iterate_data d = { &mp3d, &info, 0 };
+ mp3dec_init(&mp3d);
+ res = mp3dec_iterate_buf(buf, size, frames_iterate_cb, &d) > 0 ? 0 : -1;
+ free(buf);
+ } else if (MODE_ITERATE_CB == mode)
+ {
+ uint8_t *io_buf = malloc(MINIMP3_IO_SIZE);
+ FILE *file = fopen(input_file_name, "rb");
+ io.read_data = io.seek_data = file;
+ frames_iterate_data d = { &mp3d, &info, 0 };
+ mp3dec_init(&mp3d);
+ res = mp3dec_iterate_cb(&io, io_buf, MINIMP3_IO_SIZE, frames_iterate_cb, &d) > 0 ? 0 : -1;
+ fclose((FILE*)io.read_data);
+ free(io_buf);
+ } else if (MODE_STREAM == mode || MODE_STREAM_BUF == mode || MODE_STREAM_CB == mode)
+ {
mp3dec_ex_t dec;
- mp3dec_io_t io;
size_t readed;
- if (MODE_STREAM_CB == mode)
+ uint8_t *buf;
+ if (MODE_STREAM == mode)
{
+ res = mp3dec_ex_open(&dec, input_file_name, MP3D_SEEK_TO_SAMPLE);
+ } else if (MODE_STREAM_BUF == mode)
+ {
+ int size = 0;
FILE *file = fopen(input_file_name, "rb");
- io.read = read_cb;
- io.seek = seek_cb;
+ buf = preload(file, &size);
+ fclose(file);
+ res = mp3dec_ex_open_buf(&dec, buf, size, MP3D_SEEK_TO_SAMPLE);
+ } else if (MODE_STREAM_CB == mode)
+ {
+ FILE *file = fopen(input_file_name, "rb");
io.read_data = io.seek_data = file;
res = file ? mp3dec_ex_open_cb(&dec, &io, MP3D_SEEK_TO_SAMPLE) : -1;
- } else
- {
- res = mp3dec_ex_open(&dec, input_file_name, MP3D_SEEK_TO_SAMPLE);
}
if (res)
{
@@ -184,6 +233,8 @@
exit(1);
}
mp3dec_ex_close(&dec);
+ if (MODE_STREAM_BUF == mode)
+ free(buf);
if (MODE_STREAM_CB == mode)
fclose((FILE*)io.read_data);
} else
@@ -217,7 +268,7 @@
int len_match = ref_samples == info.samples;
int relaxed_len_match = len_match || (ref_samples + 1152) == info.samples || (ref_samples + 2304) == info.samples;
int seek_len_match = (ref_samples <= info.samples) || (ref_samples + 2304) >= info.samples;
- if ((((!relaxed_len_match && 2 != mode && 3 != mode) || !seek_len_match) && 3 == info.layer && !no_std_vec) || (no_std_vec && !len_match))
+ if ((((!relaxed_len_match && MODE_STREAM != mode && MODE_STREAM_BUF != mode && MODE_STREAM_CB != mode) || !seek_len_match) && 3 == info.layer && !no_std_vec) || (no_std_vec && !len_match))
{ /* some standard vectors are for some reason a little shorter */
printf("error: reference and produced number of samples do not match (%d/%d)\n", (int)ref_samples, (int)info.samples);
exit(1);
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -11,17 +11,22 @@
echo testing mp4 mode...
gcc $CFLAGS -DMP4_MODE -o minimp3 minimp3_test.c -lm
-scripts/test_mode.sh 1 0
+scripts/test_mode.sh 3 0
echo testing stream mode...
-scripts/test_mode.sh 2 -1
+scripts/test_mode.sh 6 -1
echo testing coverage x86 w sse...
gcc -coverage -O0 -m32 -std=c89 -msse2 -DMINIMP3_TEST -DMINIMP3_NO_WAV -o minimp3 minimp3_test.c -lm
scripts/test.sh
scripts/test_mode.sh 1 0
-scripts/test_mode.sh 2 -1
-scripts/test_mode.sh 3 -1
+scripts/test_mode.sh 2 0
+scripts/test_mode.sh 3 0
+scripts/test_mode.sh 4 0
+scripts/test_mode.sh 5 0
+scripts/test_mode.sh 6 -1
+scripts/test_mode.sh 7 -1
+scripts/test_mode.sh 8 -1
set +e
./minimp3
./minimp3 do_not_exist
@@ -40,8 +45,13 @@
gcc $CFLAGS -DMINIMP3_FLOAT_OUTPUT -o minimp3 minimp3_test.c -lm
scripts/test.sh
scripts/test_mode.sh 1 0
-scripts/test_mode.sh 2 -1
-scripts/test_mode.sh 3 -1
+scripts/test_mode.sh 2 0
+scripts/test_mode.sh 3 0
+scripts/test_mode.sh 4 0
+scripts/test_mode.sh 5 0
+scripts/test_mode.sh 6 -1
+scripts/test_mode.sh 7 -1
+scripts/test_mode.sh 8 -1
echo testing arm w/o neon...
arm-none-eabi-gcc $CFLAGS -mthumb -mcpu=arm9e -o minimp3_arm minimp3_test.c --specs=rdimon.specs -lm