ref: fe9d954e72f315aa4caa4f490fe2b7a4fea1b416
parent: d6d18139bc0aff43d0aa73f9544994fdf902d65f
author: lieff <lieff@users.noreply.github.com>
date: Sun Jan 26 10:03:33 EST 2020
take into account bit-reservoir on seek
--- a/minimp3_ex.h
+++ b/minimp3_ex.h
@@ -11,6 +11,8 @@
#define MP3D_SEEK_TO_BYTE 0
#define MP3D_SEEK_TO_SAMPLE 1
+#define MINIMP3_PREDECODE_FRAMES 2 /* frames to pre-decode and skip after seek (to fill internal structures) */
+
#define MP3D_E_MEMORY -1
typedef struct
@@ -45,17 +47,18 @@
mp3dec_t mp3d;
mp3dec_map_info_t file;
mp3dec_index_t index;
- uint64_t offset, samples;
+ uint64_t offset, samples, start_offset;
mp3dec_frame_info_t info;
mp3d_sample_t buffer[MINIMP3_MAX_SAMPLES_PER_FRAME];
#ifndef MINIMP3_NO_STDIO
int is_file;
#endif
+ int free_format_bytes;
int seek_method, vbr_tag_found;
int buffer_samples, buffer_consumed, to_skip;
} mp3dec_ex_t;
-typedef int (*MP3D_ITERATE_CB)(void *user_data, const uint8_t *frame, int frame_size, size_t offset, mp3dec_frame_info_t *info);
+typedef int (*MP3D_ITERATE_CB)(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t offset, mp3dec_frame_info_t *info);
typedef int (*MP3D_PROGRESS_CB)(void *user_data, size_t file_size, size_t offset, mp3dec_frame_info_t *info);
#ifdef __cplusplus
@@ -223,7 +226,7 @@
frames++;
if (callback)
{
- if (callback(user_data, hdr, frame_size, hdr - orig_buf, &frame_info))
+ if (callback(user_data, hdr, frame_size, free_format_bytes, hdr - orig_buf, &frame_info))
break;
}
buf += frame_size;
@@ -232,17 +235,19 @@
return frames;
}
-static int mp3dec_load_index(void *user_data, const uint8_t *frame, int frame_size, size_t offset, mp3dec_frame_info_t *info)
+static int mp3dec_load_index(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t offset, mp3dec_frame_info_t *info)
{
- (void)frame_size;
+ static const char g_xing_tag[4] = { 'X', 'i', 'n', 'g' };
+ static const char g_info_tag[4] = { 'I', 'n', 'f', 'o' };
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 */
+ int i;
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++)
+ dec->start_offset = offset;
+ dec->free_format_bytes = free_format_bytes; /* should not change */
+ for (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))
@@ -296,12 +301,13 @@
if (0 == position)
{ /* optimize seek to zero, no index needed */
seek_zero:
- dec->offset = 0;
+ dec->offset = dec->start_offset;
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) */
+ dec->samples = 0;
if (mp3dec_iterate_buf(dec->file.buffer, dec->file.size, mp3dec_load_index, dec) > 0 && !dec->index.frames)
return MP3D_E_MEMORY;
}
@@ -309,11 +315,22 @@
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)
+ if (dec->index.frames[i].sample >= position)
break;
}
if (i)
- i--;
+ {
+ int to_fill_bytes = 511;
+ int skip_frames = MINIMP3_PREDECODE_FRAMES + ((dec->index.frames[i].sample == position) ? 0 : 1);
+ i -= MINIMP3_MIN(i, (size_t)skip_frames);
+ while (i && to_fill_bytes)
+ { /* make sure bit-reservoir is filled when we start decoding */
+ const uint8_t *hdr = dec->file.buffer + dec->index.frames[i - 1].offset;
+ int frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr);
+ to_fill_bytes -= MINIMP3_MIN(to_fill_bytes, frame_size);
+ i--;
+ }
+ }
dec->offset = dec->index.frames[i].offset;
dec->to_skip = position - dec->index.frames[i].sample;
do_exit:
--- a/minimp3_test.c
+++ b/minimp3_test.c
@@ -67,9 +67,10 @@
size_t allocated;
} frames_iterate_data;
-static int frames_iterate_cb(void *user_data, const uint8_t *frame, int frame_size, size_t offset, mp3dec_frame_info_t *info)
+static int frames_iterate_cb(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t offset, mp3dec_frame_info_t *info)
{
(void)offset;
+ (void)free_format_bytes;
frames_iterate_data *d = user_data;
d->info->channels = info->channels;
d->info->hz = info->hz;