shithub: mp3dec

Download patch

ref: d6d18139bc0aff43d0aa73f9544994fdf902d65f
parent: ad04f4973d6291f392598ef5b328d2ea117df6e6
author: lieff <lieff@users.noreply.github.com>
date: Sat Jan 25 21:08:04 EST 2020

support VBR tags

--- a/minimp3_ex.h
+++ b/minimp3_ex.h
@@ -51,7 +51,7 @@
 #ifndef MINIMP3_NO_STDIO
     int is_file;
 #endif
-    int seek_method;
+    int seek_method, vbr_tag_found;
     int buffer_samples, buffer_consumed, to_skip;
 } mp3dec_ex_t;
 
@@ -70,7 +70,7 @@
 int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int seek_method);
 /*int mp3dec_ex_open_cb(mp3dec_ex_t *dec, MP3D_READ_CB cb, void *user_data, uint64_t file_size, int seek_method);*/
 void mp3dec_ex_close(mp3dec_ex_t *dec);
-void mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position);
+int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position);
 size_t mp3dec_ex_read(mp3dec_ex_t *dec, int16_t *buf, size_t samples);
 #ifndef MINIMP3_NO_STDIO
 /* stdio versions with file pre-load */
@@ -237,6 +237,25 @@
     (void)frame_size;
     mp3dec_frame_t *idx_frame;
     mp3dec_ex_t *dec = (mp3dec_ex_t *)user_data;
+    if (!dec->index.frames && !dec->vbr_tag_found)
+    {   /* detect VBR tag and try to avoid full scan */
+        dec->info = *info;
+        static const char g_xing_tag[4] = { 'X', 'i', 'n', 'g' };
+        static const char g_info_tag[4] = { 'I', 'n', 'f', 'o' };
+        for (int i = 5; i < frame_size - 12; i++)
+        {
+            const uint8_t *tag = frame + i;
+            if (!memcmp(g_xing_tag, tag, 4) || !memcmp(g_info_tag, tag, 4))
+            {
+                if (!((tag[7] & 1))/* frames field present */)
+                    break;
+                uint64_t frames = (uint32_t)(tag[8] << 24) | (tag[9] << 16) | (tag[10] << 8) | tag[11];
+                dec->samples += hdr_frame_samples(frame)*info->channels*frames;
+                dec->vbr_tag_found = 1;
+                return 1;
+            }
+        }
+    }
     if (dec->index.num_frames + 1 > dec->index.capacity)
     {
         if (!dec->index.capacity)
@@ -245,10 +264,8 @@
             dec->index.capacity *= 2;
         dec->index.frames = (mp3dec_frame_t *)realloc((void*)dec->index.frames, sizeof(mp3dec_frame_t)*dec->index.capacity);
         if (!dec->index.frames)
-            return -1;
+            return MP3D_E_MEMORY;
     }
-    if (!dec->samples)
-        dec->info = *info;
     idx_frame = &dec->index.frames[dec->index.num_frames++];
     idx_frame->offset = offset;
     idx_frame->sample = dec->samples;
@@ -263,19 +280,33 @@
     dec->file.size   = buf_size;
     dec->seek_method = seek_method;
     mp3dec_init(&dec->mp3d);
-    if (mp3dec_iterate_buf(dec->file.buffer, dec->file.size, mp3dec_load_index, dec) > 0 && !dec->index.frames)
+    if (mp3dec_iterate_buf(dec->file.buffer, dec->file.size, mp3dec_load_index, dec) > 0 && !dec->index.frames && !dec->vbr_tag_found)
         return MP3D_E_MEMORY;
     return 0;
 }
 
-void mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position)
+int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position)
 {
     size_t i;
     if (MP3D_SEEK_TO_BYTE == dec->seek_method)
     {
         dec->offset = position;
-        return;
+        return 0;
     }
+    if (0 == position)
+    {   /* optimize seek to zero, no index needed */
+seek_zero:
+        dec->offset  = 0;
+        dec->to_skip = 0;
+        goto do_exit;
+    }
+    if (!dec->index.frames && dec->vbr_tag_found)
+    {   /* no index created yet (vbr tag used to calculate track length) */
+        if (mp3dec_iterate_buf(dec->file.buffer, dec->file.size, mp3dec_load_index, dec) > 0 && !dec->index.frames)
+            return MP3D_E_MEMORY;
+    }
+    if (!dec->index.frames)
+        goto seek_zero; /* no frames in file - seek to zero */
     for (i = 0; i < dec->index.num_frames; i++)
     {
         if (dec->index.frames[i].sample > position)
@@ -285,9 +316,11 @@
         i--;
     dec->offset = dec->index.frames[i].offset;
     dec->to_skip = position - dec->index.frames[i].sample;
+do_exit:
     dec->buffer_samples  = 0;
     dec->buffer_consumed = 0;
     mp3dec_init(&dec->mp3d);
+    return 0;
 }
 
 size_t mp3dec_ex_read(mp3dec_ex_t *dec, int16_t *buf, size_t samples)