History

mp3dec_ex: support vbr tag for mp3dec_load_buf

lieff committed 6 years ago

Commit fa4c2ef1 parent 32a3ae44 files · +109 −64Browse files

Unified · Split

4 files
  1. minimp3_ex.h +110 −65
  2. scripts/test_mode.sh +1 −1
  3. vectors/l3-nonstandard-sin1k0db_lame_vbrtag.bit +0 −0
  4. vectors/l3-nonstandard-sin1k0db_lame_vbrtag.pcm +0 −0
minimp3_ex.h+110−65
@@ -127,10 +127,52 @@ static void mp3dec_skip_id3(const uint8_t **pbuf, size_t *pbuf_size) · 126 unmodified lines
127127 *pbuf_size = buf_size;
128128 }
129129
130+static int mp3dec_check_vbrtag(const uint8_t *frame, int frame_size, uint32_t *frames, int *delay, int *padding)
131+{
132+ int i;
133+ static const char g_xing_tag[4] = { 'X', 'i', 'n', 'g' };
134+ static const char g_info_tag[4] = { 'I', 'n', 'f', 'o' };
135+#define FRAMES_FLAG 1
136+#define BYTES_FLAG 2
137+#define TOC_FLAG 4
138+#define VBR_SCALE_FLAG 8
139+ /* TODO: skip side-info?
140+ / Side info offsets afrer header:
141+ / Mono Stereo
142+ / MPEG1 17 32
143+ / MPEG2 & 2.5 9 17*/
144+ for (i = 5; i < frame_size - 36; i++)
145+ {
146+ const uint8_t *tag = frame + i;
147+ if (memcmp(g_xing_tag, tag, 4) && memcmp(g_info_tag, tag, 4))
148+ continue;
149+ int flags = tag[7];
150+ if (!((flags & FRAMES_FLAG)))
151+ break;
152+ tag += 8;
153+ (*frames) = (uint32_t)(tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3];
154+ tag += 4;
155+ if (flags & BYTES_FLAG)
156+ tag += 4;
157+ if (flags & TOC_FLAG)
158+ tag += 100;
159+ if (flags & VBR_SCALE_FLAG)
160+ tag += 4;
161+ tag += 21;
162+ if (tag - frame + 2 >= frame_size)
163+ break;
164+ *delay = ((tag[0] << 4) | (tag[1] >> 4)) + (528 + 1);
165+ *padding = (((tag[1] & 0xF) << 8) | tag[2]) - (528 + 1);
166+ return 1;
167+ }
168+ return 0;
169+}
170+
130171 void 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)
131172 {
173+ uint64_t detected_samples = 0;
132174 size_t orig_buf_size = buf_size;
133− mp3d_sample_t pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
175+ int to_skip = 0;
134176 mp3dec_frame_info_t frame_info;
135177 memset(info, 0, sizeof(*info));
136178 memset(&frame_info, 0, sizeof(frame_info));
@@ -138,33 +180,57 @@ void mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_ · 1 unmodified line
138180 mp3dec_skip_id3(&buf, &buf_size);
139181 if (!buf_size)
140182 return;
141− /* try to make allocation size assumption by first frame */
183+ /* try to make allocation size assumption by first frame or vbr tag */
142184 mp3dec_init(dec);
143185 int samples;
144186 do
145187 {
146− samples = mp3dec_decode_frame(dec, buf, MINIMP3_MIN(buf_size, (size_t)INT_MAX), pcm, &frame_info);
147− buf += frame_info.frame_bytes;
148− buf_size -= frame_info.frame_bytes;
149− if (samples)
150− break;
151− } while (frame_info.frame_bytes);
152− if (!samples)
153− return;
154− samples *= frame_info.channels;
155− size_t allocated = (buf_size/frame_info.frame_bytes)*samples*sizeof(mp3d_sample_t) + MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t);
188+ uint32_t frames;
189+ int delay, padding, free_format_bytes = 0, frame_size = 0;
190+ int i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size);
191+ buf += i;
192+ buf_size -= i;
193+ if (i && !frame_size)
194+ continue;
195+ if (!frame_size)
196+ return;
197+ const uint8_t *hdr = buf;
198+ frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2;
199+ frame_info.hz = hdr_sample_rate_hz(hdr);
200+ frame_info.layer = 4 - HDR_GET_LAYER(hdr);
201+ frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr);
202+ frame_info.frame_bytes = frame_size;
203+ samples = hdr_frame_samples(hdr)*frame_info.channels;
204+ if (mp3dec_check_vbrtag(hdr, frame_size, &frames, &delay, &padding))
205+ {
206+ padding *= frame_info.channels;
207+ to_skip = delay*frame_info.channels;
208+ detected_samples = samples*(uint64_t)frames;
209+ if (detected_samples >= (uint64_t)to_skip)
210+ detected_samples -= to_skip;
211+ if (padding > 0 && detected_samples >= (uint64_t)padding)
212+ detected_samples -= padding;
213+ if (!detected_samples)
214+ return;
215+ buf += frame_size;
216+ buf_size -= frame_size;
217+ }
218+ break;
219+ } while(1);
220+ size_t allocated = MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t);
221+ if (detected_samples)
222+ allocated += detected_samples*sizeof(mp3d_sample_t);
223+ else
224+ allocated += (buf_size/frame_info.frame_bytes)*samples*sizeof(mp3d_sample_t);
156225 info->buffer = (mp3d_sample_t*)malloc(allocated);
157226 if (!info->buffer)
158227 return;
159− info->samples = samples;
160− memcpy(info->buffer, pcm, info->samples*sizeof(mp3d_sample_t));
161228 /* save info */
162229 info->channels = frame_info.channels;
163230 info->hz = frame_info.hz;
164231 info->layer = frame_info.layer;
165− size_t avg_bitrate_kbps = frame_info.bitrate_kbps;
166− size_t frames = 1;
167− /* decode rest frames */
232+ /* decode all frames */
233+ size_t avg_bitrate_kbps = 0, frames = 0;
168234 int frame_bytes;
169235 do
170236 {
@@ -187,17 +253,28 @@ void mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_ · 16 unmodified lines
187253 #else
188254 break;
189255 #endif
190− info->samples += samples*frame_info.channels;
256+ samples *= frame_info.channels;
257+ if (to_skip)
258+ {
259+ size_t skip = MINIMP3_MIN(samples, to_skip);
260+ to_skip -= skip;
261+ samples -= skip;
262+ memmove(info->buffer, info->buffer + skip, samples);
263+ }
264+ info->samples += samples;
191265 avg_bitrate_kbps += frame_info.bitrate_kbps;
192266 frames++;
193267 if (progress_cb)
194268 progress_cb(user_data, orig_buf_size, orig_buf_size - buf_size, &frame_info);
195269 }
196270 } while (frame_bytes);
271+ if (detected_samples)
272+ info->samples = detected_samples;
197273 /* reallocate to normal buffer size */
198274 if (allocated != info->samples*sizeof(mp3d_sample_t))
199275 info->buffer = (mp3d_sample_t*)realloc(info->buffer, info->samples*sizeof(mp3d_sample_t));
200− info->avg_bitrate_kbps = avg_bitrate_kbps/frames;
276+ if (frames)
277+ info->avg_bitrate_kbps = avg_bitrate_kbps/frames;
201278 }
202279
203280 size_t mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data)
@@ -241,61 +318,29 @@ size_t mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB c · 37 unmodified lines
241318
242319 static int mp3dec_load_index(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)
243320 {
244− static const char g_xing_tag[4] = { 'X', 'i', 'n', 'g' };
245− static const char g_info_tag[4] = { 'I', 'n', 'f', 'o' };
246321 mp3dec_frame_t *idx_frame;
247322 mp3dec_ex_t *dec = (mp3dec_ex_t *)user_data;
248323 if (!dec->index.frames && !dec->vbr_tag_found)
249324 { /* detect VBR tag and try to avoid full scan */
250− int i;
325+ uint32_t frames;
326+ int delay, padding;
251327 dec->info = *info;
252328 dec->start_offset = dec->offset = offset;
253329 dec->end_offset = offset + buf_size;
254330 dec->free_format_bytes = free_format_bytes; /* should not change */
255− /* TODO: skip side-info?
256− / Side info offsets afrer header:
257− / Mono Stereo
258− / MPEG1 17 32
259− / MPEG2 & 2.5 9 17*/
260− for (i = 5; i < frame_size - 36; i++)
331+ if (mp3dec_check_vbrtag(frame, frame_size, &frames, &delay, &padding))
261332 {
262− const uint8_t *tag = frame + i;
263− if (!memcmp(g_xing_tag, tag, 4) || !memcmp(g_info_tag, tag, 4))
264− {
265−#define FRAMES_FLAG 1
266−#define BYTES_FLAG 2
267−#define TOC_FLAG 4
268−#define VBR_SCALE_FLAG 8
269− int flags = tag[7], delay, padding;
270− uint32_t frames;
271− if (!((flags & FRAMES_FLAG)))
272− break;
273− tag += 8;
274− frames = (uint32_t)(tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3];
275− tag += 4;
276− if (flags & BYTES_FLAG)
277− tag += 4;
278− if (flags & TOC_FLAG)
279− tag += 100;
280− if (flags & VBR_SCALE_FLAG)
281− tag += 4;
282− tag += 21;
283− if (tag - frame + 2 >= frame_size)
284− break;
285− delay = (((tag[0] << 4) | (tag[1] >> 4)) + (528 + 1))*info->channels;
286− padding = ((((tag[1] & 0xF) << 8) | tag[2]) - (528 + 1))*info->channels;
287−
288− dec->start_delay = dec->to_skip = delay;
289− dec->samples = hdr_frame_samples(frame)*info->channels*(uint64_t)frames;
290− if (dec->samples >= (uint64_t)dec->start_delay)
291− dec->samples -= dec->start_delay;
292− if (padding > 0 && dec->samples >= (uint64_t)padding)
293− dec->samples -= padding;
294− dec->detected_samples = dec->samples;
295− dec->start_offset = dec->offset = offset + frame_size;
296− dec->vbr_tag_found = 1;
297− return 1;
298− }
333+ padding *= info->channels;
334+ dec->start_delay = dec->to_skip = delay*info->channels;
335+ dec->samples = hdr_frame_samples(frame)*info->channels*(uint64_t)frames;
336+ if (dec->samples >= (uint64_t)dec->start_delay)
337+ dec->samples -= dec->start_delay;
338+ if (padding > 0 && dec->samples >= (uint64_t)padding)
339+ dec->samples -= padding;
340+ dec->detected_samples = dec->samples;
341+ dec->start_offset = dec->offset = offset + frame_size;
342+ dec->vbr_tag_found = 1;
343+ return 1;
299344 }
300345 }
301346 if (dec->index.num_frames + 1 > dec->index.capacity)
scripts/test_mode.sh+1−1
@@ -13,7 +13,7 @@ vectors/l3-sin1k0db.bit vectors/l3-test45.bit vectors/l3-test46.bit vectors/M2L3 · 12 unmodified lines
1313 vectors/M2L3_bitrate_22_all.bit vectors/M2L3_bitrate_24_all.bit vectors/M2L3_compl24.bit vectors/M2L3_noise.bit \
1414 vectors/l3-nonstandard-id3v1.bit vectors/l3-nonstandard-id3v2.bit vectors/l1-fl1.bit vectors/l2-fl10.bit"
1515 if [ "$MODE" = "2" ]; then
16−VECTORS+=" vectors/vbrtag/l3-nonstandard-sin1k0db_lame_tag.bit"
16+VECTORS+=" vectors/l3-nonstandard-sin1k0db_lame_vbrtag.bit"
1717 fi
1818
1919 set +e
vectors/l3-nonstandard-sin1k0db_lame_vbrtag.bitrenamed from vectors/vbrtag/l3-nonstandard-sin1k0db_lame_tag.bit+0−0

File renamed without changes.

vectors/l3-nonstandard-sin1k0db_lame_vbrtag.pcmrenamed from vectors/vbrtag/l3-nonstandard-sin1k0db_lame_tag.pcm+0−0

File renamed without changes.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t