shithub: mp3dec

Download patch

ref: 32a3ae45de25edbee8c232a63b1c0528bc3dbd96
parent: 5904e0f2d75f9bc900224692f12793a9a00f78b5
author: lieff <lieff@users.noreply.github.com>
date: Tue Feb 4 21:09:46 EST 2020

mp3dec_ex: support delay and padding from vbr tag + test

diff: cannot open b/vectors/vbrtag//null: file does not exist: 'b/vectors/vbrtag//null'
--- a/minimp3_ex.h
+++ b/minimp3_ex.h
@@ -50,7 +50,7 @@
     mp3dec_t mp3d;
     mp3dec_map_info_t file;
     mp3dec_index_t index;
-    uint64_t offset, samples, start_offset, end_offset;
+    uint64_t offset, samples, detected_samples, start_offset, end_offset;
     mp3dec_frame_info_t info;
     mp3d_sample_t buffer[MINIMP3_MAX_SAMPLES_PER_FRAME];
 #ifndef MINIMP3_NO_STDIO
@@ -58,7 +58,7 @@
 #endif
     int free_format_bytes;
     int seek_method, vbr_tag_found;
-    int buffer_samples, buffer_consumed, to_skip;
+    int buffer_samples, buffer_consumed, to_skip, start_delay;
 } mp3dec_ex_t;
 
 typedef int (*MP3D_ITERATE_CB)(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, size_t offset, mp3dec_frame_info_t *info);
@@ -249,18 +249,50 @@
     {   /* detect VBR tag and try to avoid full scan */
         int i;
         dec->info = *info;
-        dec->start_offset = offset;
+        dec->start_offset = dec->offset = offset;
         dec->end_offset   = offset + buf_size;
         dec->free_format_bytes = free_format_bytes; /* should not change */
-        for (i = 5; i < frame_size - 12; i++)
+        /* TODO: skip side-info?
+        /  Side info offsets afrer header:
+        /                Mono  Stereo
+        /  MPEG1          17     32
+        /  MPEG2 & 2.5     9     17*/
+        for (i = 5; i < frame_size - 36; 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 */)
+#define FRAMES_FLAG     1
+#define BYTES_FLAG      2
+#define TOC_FLAG        4
+#define VBR_SCALE_FLAG  8
+                int flags = tag[7], delay, padding;
+                uint32_t frames;
+                if (!((flags & FRAMES_FLAG)))
                     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;
+                tag += 8;
+                frames = (uint32_t)(tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3];
+                tag += 4;
+                if (flags & BYTES_FLAG)
+                    tag += 4;
+                if (flags & TOC_FLAG)
+                    tag += 100;
+                if (flags & VBR_SCALE_FLAG)
+                    tag += 4;
+                tag += 21;
+                if (tag - frame + 2 >= frame_size)
+                    break;
+                delay   = (((tag[0] << 4) | (tag[1] >> 4)) + (528 + 1))*info->channels;
+                padding = ((((tag[1] & 0xF) << 8) | tag[2]) - (528 + 1))*info->channels;
+
+                dec->start_delay = dec->to_skip = delay;
+                dec->samples = hdr_frame_samples(frame)*info->channels*(uint64_t)frames;
+                if (dec->samples >= (uint64_t)dec->start_delay)
+                    dec->samples -= dec->start_delay;
+                if (padding > 0 && dec->samples >= (uint64_t)padding)
+                    dec->samples -= padding;
+                dec->detected_samples = dec->samples;
+                dec->start_offset = dec->offset = offset + frame_size;
                 dec->vbr_tag_found = 1;
                 return 1;
             }
@@ -296,10 +328,13 @@
     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 && !dec->vbr_tag_found)
-        return MP3D_E_MEMORY;
-    mp3dec_init(&dec->mp3d);
-    dec->buffer_samples = 0;
+    if (MP3D_SEEK_TO_SAMPLE == dec->seek_method)
+    {
+        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;
+        mp3dec_init(&dec->mp3d);
+        dec->buffer_samples = 0;
+    }
     return 0;
 }
 
@@ -335,6 +370,7 @@
         dec->offset = position;
         return 0;
     }
+    position += dec->start_delay;
     if (0 == position)
     {   /* optimize seek to zero, no index needed */
 seek_zero:
@@ -346,8 +382,11 @@
     {   /* no index created yet (vbr tag used to calculate track length) */
         dec->samples = 0;
         dec->buffer_samples = 0;
-        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->start_offset, dec->file.size - dec->start_offset, mp3dec_load_index, dec) > 0 && !dec->index.frames)
             return MP3D_E_MEMORY;
+        for (i = 0; i < dec->index.num_frames; i++)
+            dec->index.frames[i].offset += dec->start_offset;
+        dec->samples = dec->detected_samples;
     }
     if (!dec->index.frames)
         goto seek_zero; /* no frames in file - seek to zero */
--- a/scripts/test_mode.sh
+++ b/scripts/test_mode.sh
@@ -7,13 +7,17 @@
 APP=./minimp3
 MODE=$1
 POSITION=$2
-
-set +e
-for i in vectors/l3-compl.bit vectors/l3-he_32khz.bit vectors/l3-he_44khz.bit vectors/l3-he_48khz.bit \
+VECTORS="vectors/l3-compl.bit vectors/l3-he_32khz.bit vectors/l3-he_44khz.bit vectors/l3-he_48khz.bit \
 vectors/l3-hecommon.bit vectors/l3-he_mode.bit vectors/l3-si.bit vectors/l3-si_block.bit vectors/l3-si_huff.bit \
 vectors/l3-sin1k0db.bit vectors/l3-test45.bit vectors/l3-test46.bit vectors/M2L3_bitrate_16_all.bit \
 vectors/M2L3_bitrate_22_all.bit vectors/M2L3_bitrate_24_all.bit vectors/M2L3_compl24.bit vectors/M2L3_noise.bit \
-vectors/l3-nonstandard-id3v1.bit vectors/l3-nonstandard-id3v2.bit vectors/l1-fl1.bit vectors/l2-fl10.bit; do
+vectors/l3-nonstandard-id3v1.bit vectors/l3-nonstandard-id3v2.bit vectors/l1-fl1.bit vectors/l2-fl10.bit"
+if [ "$MODE" = "2" ]; then
+VECTORS+=" vectors/vbrtag/l3-nonstandard-sin1k0db_lame_tag.bit"
+fi
+
+set +e
+for i in $VECTORS; do
 $APP -m $MODE -s $POSITION $i ${i%.*}.pcm
 retval=$?
 echo -m $MODE -s $POSITION $i exited with code=$retval
binary files /dev/null b/vectors/vbrtag/l3-nonstandard-sin1k0db_lame_tag.bit differ
binary files /dev/null b/vectors/vbrtag/l3-nonstandard-sin1k0db_lame_tag.pcm differ