ref: 0a2ff3be7ff27fe76439b257bdf0ddd8aea0aba0
parent: 728ff80391532687d22988dd48a5b166b2e66d0d
author: lieff <lieff@users.noreply.github.com>
date: Wed Mar 4 11:25:41 EST 2020
mp3dec_ex: add mp3dec_detect_* functions + test
--- a/minimp3_ex.h
+++ b/minimp3_ex.h
@@ -82,6 +82,9 @@
extern "C" {
#endif
+/* detect mp3/mpa format */
+int mp3dec_detect_buf(const uint8_t *buf, size_t buf_size);
+int mp3dec_detect_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size);
/* decode whole buffer block */
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);
@@ -95,11 +98,13 @@
int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position);
size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples);
#ifndef MINIMP3_NO_STDIO
-/* stdio versions of file load, iterate and stream */
+/* stdio versions of file detect, load, iterate and stream */
+int mp3dec_detect(const char *file_name);
int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);
int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data);
int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int seek_method);
#ifdef _WIN32
+int mp3dec_detect_w(const wchar_t *file_name);
int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);
int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data);
int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int seek_method);
@@ -217,6 +222,47 @@
return 1;
}
+int mp3dec_detect_buf(const uint8_t *buf, size_t buf_size)
+{
+ return mp3dec_detect_cb(0, (uint8_t *)buf, buf_size);
+}
+
+int mp3dec_detect_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size)
+{
+ if (!buf || (size_t)-1 == buf_size || (io && buf_size < MINIMP3_BUF_SIZE))
+ return MP3D_E_PARAM;
+ size_t filled = buf_size;
+ if (io)
+ {
+ if (io->seek(0, io->seek_data))
+ return MP3D_E_IOERROR;
+ filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data);
+ if (filled > MINIMP3_ID3_DETECT_SIZE)
+ return MP3D_E_IOERROR;
+ if (MINIMP3_ID3_DETECT_SIZE != filled)
+ return MP3D_E_USER;
+ }
+ if (mp3dec_skip_id3v2(buf, filled))
+ return 0; /* id3v2 tag is enough evidence */
+ if (io)
+ {
+ size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data);
+ if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE))
+ return MP3D_E_IOERROR;
+ filled += readed;
+ if (filled < MINIMP3_BUF_SIZE)
+ mp3dec_skip_id3v1(buf, &filled);
+ } else
+ {
+ mp3dec_skip_id3v1(buf, &filled);
+ }
+ int free_format_bytes, frame_size;
+ mp3d_find_frame(buf, MINIMP3_MIN(filled, (size_t)INT_MAX), &free_format_bytes, &frame_size);
+ if (frame_size)
+ return 0; /* MAX_FRAME_SYNC_MATCHES consecutive frames found */
+ return MP3D_E_USER;
+}
+
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);
@@ -1143,6 +1189,13 @@
}
#endif
+static int mp3dec_detect_mapinfo(mp3dec_map_info_t *map_info)
+{
+ int ret = mp3dec_detect_buf(map_info->buffer, map_info->size);
+ mp3dec_close_file(map_info);
+ return ret;
+}
+
static int mp3dec_load_mapinfo(mp3dec_t *dec, mp3dec_map_info_t *map_info, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)
{
int ret = mp3dec_load_buf(dec, map_info->buffer, map_info->size, info, progress_cb, user_data);
@@ -1166,6 +1219,15 @@
return ret;
}
+int mp3dec_detect(const char *file_name)
+{
+ int ret;
+ mp3dec_map_info_t map_info;
+ if ((ret = mp3dec_open_file(file_name, &map_info)))
+ return ret;
+ return mp3dec_detect_mapinfo(&map_info);
+}
+
int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)
{
int ret;
@@ -1241,6 +1303,15 @@
}
#ifdef _WIN32
+int mp3dec_detect_w(const wchar_t *file_name)
+{
+ int ret;
+ mp3dec_map_info_t map_info;
+ if ((ret = mp3dec_open_file_w(file_name, &map_info)))
+ return ret;
+ return mp3dec_detect_mapinfo(&map_info);
+}
+
int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)
{
int ret;
@@ -1247,7 +1318,7 @@
mp3dec_map_info_t map_info;
if ((ret = mp3dec_open_file_w(file_name, &map_info)))
return ret;
- return mp3dec_load_mapinfo(dec, &map_info,info, progress_cb, user_data);
+ return mp3dec_load_mapinfo(dec, &map_info, info, progress_cb, user_data);
}
int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data)
--- a/minimp3_test.c
+++ b/minimp3_test.c
@@ -57,6 +57,9 @@
#define MODE_STREAM 6
#define MODE_STREAM_BUF 7
#define MODE_STREAM_CB 8
+#define MODE_DETECT 9
+#define MODE_DETECT_BUF 10
+#define MODE_DETECT_CB 11
static int16_t read16le(const void *p)
{
@@ -178,6 +181,7 @@
mp3dec_t mp3d;
int i, res = -1, data_bytes, total_samples = 0, maxdiff = 0;
int no_std_vec = strstr(input_file_name, "nonstandard") || strstr(input_file_name, "ILL");
+ uint8_t *buf = 0;
double MSE = 0.0, psnr;
mp3dec_io_t io;
@@ -235,7 +239,6 @@
{
mp3dec_ex_t dec;
size_t readed;
- uint8_t *buf = 0;
if (MODE_STREAM == mode)
{
res = mp3dec_ex_open(&dec, input_file_name, seek_to_byte ? MP3D_SEEK_TO_BYTE : MP3D_SEEK_TO_SAMPLE);
@@ -330,6 +333,38 @@
free(buf);
if (MODE_STREAM_CB == mode)
fclose((FILE*)io.read_data);
+ } else if (MODE_DETECT == mode || MODE_DETECT_BUF == mode || MODE_DETECT_CB == mode)
+ {
+ if (MODE_DETECT == mode)
+ {
+ res = mp3dec_detect(input_file_name);
+ } else if (MODE_DETECT_BUF == mode)
+ {
+ int size = 0;
+ FILE *file = fopen(input_file_name, "rb");
+ buf = preload(file, &size);
+ fclose(file);
+ res = buf ? mp3dec_detect_buf(buf, size) : MP3D_E_IOERROR;
+ } else if (MODE_DETECT_CB == mode)
+ {
+ uint8_t *io_buf = malloc(MINIMP3_BUF_SIZE);
+ FAIL_MEM(io_buf);
+ FILE *file = fopen(input_file_name, "rb");
+ io.read_data = io.seek_data = file;
+ res = file ? mp3dec_detect_cb(&io, io_buf, MINIMP3_BUF_SIZE) : MP3D_E_IOERROR;
+ free(io_buf);
+ }
+ if (MP3D_E_USER == res)
+ {
+ printf("info: not an mp3/mpa file\n");
+ exit(1);
+ } else if (res)
+ {
+ printf("error: mp3dec_detect*()=%d failed\n", res);
+ exit(1);
+ }
+ printf("info: mp3/mpa file detected\n");
+ exit(0);
} else
{
printf("error: unknown mode\n");
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -30,6 +30,9 @@
scripts/test_mode.sh 6 -2 -1
scripts/test_mode.sh 7 -2 -1
scripts/test_mode.sh 8 -2 -1
+scripts/test_mode.sh 9 0 0
+scripts/test_mode.sh 10 0 0
+scripts/test_mode.sh 11 0 0
set +e
[[ "$(./minimp3)" != "error: no file names given" ]] && echo fail && exit 1 || echo pass
[[ "$(./minimp3 do_not_exist)" != "error: read function failed, code=-3" ]] && echo fail && exit 1 || echo pass