shithub: mp3dec

Download patch

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