History

WIP mp3dec_ex API callback input support.

lieff committed 6 years ago

Commit daef2f31 parent ac052113 files · +368 −100Browse files

Unified · Split

3 files
  1. minimp3_ex.h +305 −73
  2. minimp3_test.c +59 −27
  3. scripts/build.sh +4 −0
minimp3_ex.h+305−73
@@ -13,9 +13,12 @@ · 12 unmodified lines
13 13
14#define MINIMP3_PREDECODE_FRAMES 2 /* frames to pre-decode and skip after seek (to fill internal structures) */14#define MINIMP3_PREDECODE_FRAMES 2 /* frames to pre-decode and skip after seek (to fill internal structures) */
15/*#define MINIMP3_SEEK_IDX_LINEAR_SEARCH*/ /* define to use linear index search instead of binary search on seek */15/*#define MINIMP3_SEEK_IDX_LINEAR_SEARCH*/ /* define to use linear index search instead of binary search on seek */
16#define MINIMP3_RING_SIZE (128*1024)16#define MINIMP3_IO_SIZE (128*1024) /* io buffer size for streaming functions, must be greater than MINIMP3_BUF_SIZE */
17#define MINIMP3_BUF_SIZE (16*1024) /* buffer which can hold minimum 10 consecutive mp3 frames (~16KB) worst case */
18#define MINIMP3_ENABLE_RING 0 /* enable hardware magic ring buffer if available, to make less input buffer memmove(s) in callback IO mode */
17 19
18#define MP3D_E_MEMORY -120#define MP3D_E_MEMORY -1
21#define MP3D_E_IOERROR -2
19 22
20typedef struct23typedef struct
21{24{
@@ -42,13 +45,22 @@ typedef struct · 20 unmodified lines
42 size_t num_frames, capacity;45 size_t num_frames, capacity;
43} mp3dec_index_t;46} mp3dec_index_t;
44 47
45typedef int (*MP3D_READ_CB)(void *buf, size_t size, void *user_data);48typedef size_t (*MP3D_READ_CB)(void *buf, size_t size, void *user_data);
46typedef int (*MP3D_SEEK_CB)(size_t position);49typedef int (*MP3D_SEEK_CB)(uint64_t position, void *user_data);
50
51typedef struct
52{
53 MP3D_READ_CB read;
54 void *read_data;
55 MP3D_SEEK_CB seek;
56 void *seek_data;
57} mp3dec_io_t;
47 58
48typedef struct59typedef struct
49{60{
50 mp3dec_t mp3d;61 mp3dec_t mp3d;
51 mp3dec_map_info_t file;62 mp3dec_map_info_t file;
63 mp3dec_io_t *io;
52 mp3dec_index_t index;64 mp3dec_index_t index;
53 uint64_t offset, samples, detected_samples, cur_sample, start_offset, end_offset;65 uint64_t offset, samples, detected_samples, cur_sample, start_offset, end_offset;
54 mp3dec_frame_info_t info;66 mp3dec_frame_info_t info;
@@ -61,8 +73,8 @@ typedef struct · 6 unmodified lines
61 int buffer_samples, buffer_consumed, to_skip, start_delay;73 int buffer_samples, buffer_consumed, to_skip, start_delay;
62} mp3dec_ex_t;74} mp3dec_ex_t;
63 75
64typedef 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);76typedef int (*MP3D_ITERATE_CB)(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info);
65typedef int (*MP3D_PROGRESS_CB)(void *user_data, size_t file_size, size_t offset, mp3dec_frame_info_t *info);77typedef int (*MP3D_PROGRESS_CB)(void *user_data, size_t file_size, uint64_t offset, mp3dec_frame_info_t *info);
66 78
67#ifdef __cplusplus79#ifdef __cplusplus
68extern "C" {80extern "C" {
@@ -70,19 +82,26 @@ extern "C" { · 1 unmodified line
70 82
71/* decode whole buffer block */83/* decode whole buffer block */
72void 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);84void 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);
85int 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);
73/* iterate through frames */86/* iterate through frames */
74size_t mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data);87size_t mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data);
88uint64_t mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data);
75/* streaming decoder with seeking capability */89/* streaming decoder with seeking capability */
76int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int seek_method);90int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int seek_method);
77int mp3dec_ex_open_cb(mp3dec_ex_t *dec, MP3D_READ_CB read_cb, void *read_user_data, MP3D_SEEK_CB seek_cb, void *seek_user_data, int seek_method);91int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int seek_method);
78void mp3dec_ex_close(mp3dec_ex_t *dec);92void mp3dec_ex_close(mp3dec_ex_t *dec);
79int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position);93int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position);
80size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples);94size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples);
81#ifndef MINIMP3_NO_STDIO95#ifndef MINIMP3_NO_STDIO
82/* stdio versions with file pre-load */96/* stdio versions of file load, iterate and stream */
83int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);97int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);
84int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data);98size_t mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data);
85int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int seek_method);99int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int seek_method);
100#ifdef _WIN32
101int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);
102int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data);
103int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int seek_method);
104#endif
86#endif105#endif
87 106
88#ifdef __cplusplus107#ifdef __cplusplus
@@ -93,22 +112,9 @@ int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int seek_method); · 4 unmodified lines
93#ifdef MINIMP3_IMPLEMENTATION112#ifdef MINIMP3_IMPLEMENTATION
94#include <limits.h>113#include <limits.h>
95 114
96static void mp3dec_skip_id3(const uint8_t **pbuf, size_t *pbuf_size)115static void mp3dec_skip_id3v1(const uint8_t *buf, size_t *pbuf_size)
97{116{
98 char *buf = (char *)(*pbuf);
99 size_t buf_size = *pbuf_size;117 size_t buf_size = *pbuf_size;
100#ifndef MINIMP3_NOSKIP_ID3V2
101 if (buf_size > 10 && !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80)))
102 {
103 size_t id3v2size = (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10;
104 if ((buf[5] & 16))
105 id3v2size += 10; /* footer */
106 if (id3v2size >= buf_size)
107 id3v2size = buf_size;
108 buf += id3v2size;
109 buf_size -= id3v2size;
110 }
111#endif
112#ifndef MINIMP3_NOSKIP_ID3V1118#ifndef MINIMP3_NOSKIP_ID3V1
113 if (buf_size > 128 && !memcmp(buf + buf_size - 128, "TAG", 3))119 if (buf_size > 128 && !memcmp(buf + buf_size - 128, "TAG", 3))
114 {120 {
@@ -123,6 +129,36 @@ static void mp3dec_skip_id3(const uint8_t **pbuf, size_t *pbuf_size) · 8 unmodified lines
123 buf_size -= 32;129 buf_size -= 32;
124 }130 }
125#endif131#endif
132 *pbuf_size = buf_size;
133}
134
135static size_t mp3dec_skip_id3v2(const uint8_t *buf, size_t buf_size)
136{
137#ifndef MINIMP3_NOSKIP_ID3V2
138 if (buf_size >= 10 && !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80)))
139 {
140 size_t id3v2size = (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10;
141 if ((buf[5] & 16))
142 id3v2size += 10; /* footer */
143 return id3v2size;
144 }
145#endif
146 return 0;
147}
148
149static void mp3dec_skip_id3(const uint8_t **pbuf, size_t *pbuf_size)
150{
151 uint8_t *buf = (uint8_t *)(*pbuf);
152 size_t buf_size = *pbuf_size;
153 size_t id3v2size = mp3dec_skip_id3v2(buf, buf_size);
154 if (id3v2size)
155 {
156 if (id3v2size >= buf_size)
157 id3v2size = buf_size;
158 buf += id3v2size;
159 buf_size -= id3v2size;
160 }
161 mp3dec_skip_id3v1(buf, &buf_size);
126 *pbuf = (const uint8_t *)buf;162 *pbuf = (const uint8_t *)buf;
127 *pbuf_size = buf_size;163 *pbuf_size = buf_size;
128}164}
@@ -135,7 +171,7 @@ static int mp3dec_check_vbrtag(const uint8_t *frame, int frame_size, uint32_t *f · 6 unmodified lines
135#define BYTES_FLAG 2171#define BYTES_FLAG 2
136#define TOC_FLAG 4172#define TOC_FLAG 4
137#define VBR_SCALE_FLAG 8173#define VBR_SCALE_FLAG 8
138 /* Side info offsets afrer header:174 /* Side info offsets after header:
139 / Mono Stereo175 / Mono Stereo
140 / MPEG1 17 32176 / MPEG1 17 32
141 / MPEG2 & 2.5 9 17*/177 / MPEG2 & 2.5 9 17*/
@@ -322,7 +358,70 @@ size_t mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB c · 180 unmodified lines
322 return frames;358 return frames;
323}359}
324 360
325static 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)361uint64_t mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data)
362{
363 if (buf_size < MINIMP3_BUF_SIZE)
364 return 0;
365 io->seek(0, io->seek_data);
366 size_t filled = io->read(buf, 10, io->read_data), consumed = 0;
367 uint64_t readed = 0, frames = 0;
368 mp3dec_frame_info_t frame_info;
369 int eof = 0;
370 memset(&frame_info, 0, sizeof(frame_info));
371 size_t id3v2size = mp3dec_skip_id3v2(buf, filled);
372 if (id3v2size)
373 {
374 io->seek(id3v2size, io->seek_data);
375 filled = io->read(buf, buf_size, io->read_data);
376 readed += id3v2size;
377 } else
378 filled += io->read(buf + 10, buf_size - 10, io->read_data);
379 if (filled < MINIMP3_BUF_SIZE)
380 mp3dec_skip_id3v1(buf, &filled);
381 do
382 {
383 int free_format_bytes = 0, frame_size = 0;
384 int i = mp3d_find_frame(buf + consumed, filled - consumed, &free_format_bytes, &frame_size);
385 if (i && !frame_size)
386 {
387 consumed += i;
388 continue;
389 }
390 if (!frame_size)
391 break;
392 const uint8_t *hdr = buf + consumed + i;
393 frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2;
394 frame_info.hz = hdr_sample_rate_hz(hdr);
395 frame_info.layer = 4 - HDR_GET_LAYER(hdr);
396 frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr);
397 frame_info.frame_bytes = frame_size;
398
399 readed += i;
400 frames++;
401 if (callback)
402 {
403 if (callback(user_data, hdr, frame_size, free_format_bytes, filled - consumed, readed, &frame_info))
404 break;
405 }
406 readed += frame_size;
407 consumed += i + frame_size;
408 if (!eof && filled - consumed < MINIMP3_BUF_SIZE)
409 { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */
410 memmove(buf, buf + consumed, filled - consumed);
411 filled -= consumed;
412 consumed = 0;
413 size_t readed = io->read(buf + filled, buf_size - filled, io->read_data);
414 if (readed != (buf_size - filled))
415 eof = 1;
416 filled += readed;
417 if (eof)
418 mp3dec_skip_id3v1(buf, &filled);
419 }
420 } while (1);
421 return frames;
422}
423
424static int mp3dec_load_index(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info)
326{425{
327 mp3dec_frame_t *idx_frame;426 mp3dec_frame_t *idx_frame;
328 mp3dec_ex_t *dec = (mp3dec_ex_t *)user_data;427 mp3dec_ex_t *dec = (mp3dec_ex_t *)user_data;
@@ -435,8 +534,15 @@ seek_zero: · 106 unmodified lines
435 { /* no index created yet (vbr tag used to calculate track length) */534 { /* no index created yet (vbr tag used to calculate track length) */
436 dec->samples = 0;535 dec->samples = 0;
437 dec->buffer_samples = 0;536 dec->buffer_samples = 0;
438 if (mp3dec_iterate_buf(dec->file.buffer + dec->start_offset, dec->file.size - dec->start_offset, mp3dec_load_index, dec) > 0 && !dec->index.frames)537 if (dec->io)
439 return MP3D_E_MEMORY;538 {
539 if (mp3dec_iterate_cb(dec->io, (uint8_t *)dec->file.buffer, dec->file.size, mp3dec_load_index, dec) > 0 && !dec->index.frames)
540 return MP3D_E_MEMORY;
541 } else
542 {
543 if (mp3dec_iterate_buf(dec->file.buffer + dec->start_offset, dec->file.size - dec->start_offset, mp3dec_load_index, dec) > 0 && !dec->index.frames)
544 return MP3D_E_MEMORY;
545 }
440 for (i = 0; i < dec->index.num_frames; i++)546 for (i = 0; i < dec->index.num_frames; i++)
441 dec->index.frames[i].offset += dec->start_offset;547 dec->index.frames[i].offset += dec->start_offset;
442 dec->samples = dec->detected_samples;548 dec->samples = dec->detected_samples;
@@ -467,9 +573,26 @@ seek_zero: · 24 unmodified lines
467 { /* make sure bit-reservoir is filled when we start decoding */573 { /* make sure bit-reservoir is filled when we start decoding */
468 bs_t bs[1];574 bs_t bs[1];
469 L3_gr_info_t gr_info[4];575 L3_gr_info_t gr_info[4];
470 const uint8_t *hdr = dec->file.buffer + dec->index.frames[i - 1].offset;576 int frame_bytes, frame_size;
471 int frame_bytes, frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr);577 const uint8_t *hdr;
472 bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE);578 if (dec->io)
579 {
580 hdr = dec->file.buffer;
581 dec->io->seek(dec->index.frames[i - 1].offset, dec->io->seek_data);
582 size_t readed = dec->io->read((uint8_t *)hdr, HDR_SIZE, dec->io->read_data);
583 if (readed != HDR_SIZE)
584 return MP3D_E_IOERROR;
585 frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr);
586 readed = dec->io->read((uint8_t *)hdr + HDR_SIZE, frame_size - HDR_SIZE, dec->io->read_data);
587 if (readed != (size_t)(frame_size - HDR_SIZE))
588 return MP3D_E_IOERROR;
589 bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE);
590 } else
591 {
592 hdr = dec->file.buffer + dec->index.frames[i - 1].offset;
593 frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr);
594 bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE);
595 }
473 if (HDR_IS_CRC(hdr))596 if (HDR_IS_CRC(hdr))
474 get_bits(bs, 16);597 get_bits(bs, 16);
475 i--;598 i--;
@@ -489,6 +612,8 @@ seek_zero: · 13 unmodified lines
489 i++;612 i++;
490 }613 }
491do_exit:614do_exit:
615 if (dec->io)
616 dec->io->seek(dec->offset, dec->io->seek_data);
492 dec->buffer_samples = 0;617 dec->buffer_samples = 0;
493 dec->buffer_consumed = 0;618 dec->buffer_consumed = 0;
494 mp3dec_init(&dec->mp3d);619 mp3dec_init(&dec->mp3d);
@@ -499,6 +624,8 @@ size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples) · 4 unmodified lines
499{624{
500 uint64_t end_offset = dec->end_offset ? dec->end_offset : dec->file.size;625 uint64_t end_offset = dec->end_offset ? dec->end_offset : dec->file.size;
501 size_t samples_requested = samples;626 size_t samples_requested = samples;
627 size_t filled = 0, consumed = 0;
628 int eof = 0;
502 mp3dec_frame_info_t frame_info;629 mp3dec_frame_info_t frame_info;
503 memset(&frame_info, 0, sizeof(frame_info));630 memset(&frame_info, 0, sizeof(frame_info));
504 if (dec->detected_samples && dec->cur_sample >= dec->detected_samples)631 if (dec->detected_samples && dec->cur_sample >= dec->detected_samples)
@@ -521,11 +648,34 @@ size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples) · 16 unmodified lines
521 {648 {
522 if (dec->detected_samples && dec->cur_sample >= dec->detected_samples)649 if (dec->detected_samples && dec->cur_sample >= dec->detected_samples)
523 break;650 break;
524 const uint8_t *dec_buf = dec->file.buffer + dec->offset;651 const uint8_t *dec_buf;
525 uint64_t buf_size = end_offset - dec->offset;652 if (dec->io)
526 if (!buf_size)653 {
527 break;654 if (!eof && (filled - consumed) < MINIMP3_BUF_SIZE)
528 dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, MINIMP3_MIN(buf_size, (uint64_t)INT_MAX), dec->buffer, &frame_info);655 { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */
656 memmove((uint8_t*)dec->file.buffer, (uint8_t*)dec->file.buffer + consumed, filled - consumed);
657 filled -= consumed;
658 consumed = 0;
659 size_t readed = dec->io->read((uint8_t*)dec->file.buffer + filled, dec->file.size - filled, dec->io->read_data);
660 if (readed != (dec->file.size - filled))
661 eof = 1;
662 filled += readed;
663 if (eof)
664 mp3dec_skip_id3v1((uint8_t*)dec->file.buffer, &filled);
665 }
666 dec_buf = dec->file.buffer + consumed;
667 if (!(filled - consumed))
668 break;
669 dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, filled - consumed, dec->buffer, &frame_info);
670 consumed += frame_info.frame_bytes;
671 } else
672 {
673 dec_buf = dec->file.buffer + dec->offset;
674 uint64_t buf_size = end_offset - dec->offset;
675 if (!buf_size)
676 break;
677 dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, MINIMP3_MIN(buf_size, (uint64_t)INT_MAX), dec->buffer, &frame_info);
678 }
529 dec->buffer_consumed = 0;679 dec->buffer_consumed = 0;
530 if (dec->buffer_samples)680 if (dec->buffer_samples)
531 {681 {
@@ -611,12 +761,14 @@ retry_mmap: · 79 unmodified lines
611 return 0;761 return 0;
612}762}
613 763
764#if MINIMP3_ENABLE_RING && defined(__linux__) && defined(_GNU_SOURCE)
765#define MINIMP3_HAVE_RING
614static void mp3dec_close_ring(mp3dec_map_info_t *map_info)766static void mp3dec_close_ring(mp3dec_map_info_t *map_info)
615{767{
616#if defined(__linux__) && defined(_GNU_SOURCE)768#if defined(__linux__) && defined(_GNU_SOURCE)
617 if (map_info->buffer && MAP_FAILED != map_info->buffer)769 if (map_info->buffer && MAP_FAILED != map_info->buffer)
618 munmap((void *)map_info->buffer, map_info->size*2);770 munmap((void *)map_info->buffer, map_info->size*2);
619#esle771#else
620 if (map_info->buffer)772 if (map_info->buffer)
621 {773 {
622 shmdt(map_info->buffer);774 shmdt(map_info->buffer);
@@ -631,12 +783,13 @@ static int mp3dec_open_ring(mp3dec_map_info_t *map_info, size_t size) · 8 unmodified lines
631{783{
632 int memfd, page_size;784 int memfd, page_size;
633#if defined(__linux__) && defined(_GNU_SOURCE)785#if defined(__linux__) && defined(_GNU_SOURCE)
786 void *buffer;
634 int res;787 int res;
635#endif788#endif
636 memset(map_info, 0, sizeof(*map_info));789 memset(map_info, 0, sizeof(*map_info));
637 790
638#ifdef _SC_PAGESIZE791#ifdef _SC_PAGESIZE
639 page_size = sysconf( _SC_PAGESIZE );792 page_size = sysconf(_SC_PAGESIZE);
640#else793#else
641 page_size = getpagesize();794 page_size = getpagesize();
642#endif795#endif
@@ -648,29 +801,29 @@ static int mp3dec_open_ring(mp3dec_map_info_t *map_info, size_t size) · 5 unmodified lines
648 return -1;801 return -1;
649 802
650retry_ftruncate:803retry_ftruncate:
651 res = ftruncate(memfd, size);804 res = ftruncate(memfd, map_info->size);
652 if (res && (errno == EAGAIN || errno == EINTR))805 if (res && (errno == EAGAIN || errno == EINTR))
653 goto retry_ftruncate;806 goto retry_ftruncate;
654 if (res)807 if (res)
655 goto error;808 goto error;
656 809
657retry_mmap:810retry_mmap:
658 map_info->buffer = (const uint8_t *)mmap(NULL, map_info->size*2, PROT_NONE, MAP_PRIVATE, -1, 0);811 map_info->buffer = (const uint8_t *)mmap(NULL, map_info->size*2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
659 if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR))812 if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR))
660 goto retry_mmap;813 goto retry_mmap;
661 if (MAP_FAILED == map_info->buffer)814 if (MAP_FAILED == map_info->buffer || !map_info->buffer)
662 goto error;815 goto error;
663retry_mmap2:816retry_mmap2:
664 map_info->buffer = (const uint8_t *)mmap((void *)map_info->buffer, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0);817 buffer = mmap((void *)map_info->buffer, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0);
665 if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR))818 if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR))
666 goto retry_mmap2;819 goto retry_mmap2;
667 if (MAP_FAILED == map_info->buffer)820 if (MAP_FAILED == map_info->buffer || buffer != (void *)map_info->buffer)
668 goto error;821 goto error;
669retry_mmap3:822retry_mmap3:
670 map_info->buffer = (const uint8_t *)mmap((void *)map_info->buffer + map_info->size, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0);823 buffer = mmap((void *)map_info->buffer + map_info->size, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0);
671 if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR))824 if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR))
672 goto retry_mmap3;825 goto retry_mmap3;
673 if (MAP_FAILED == map_info->buffer)826 if (MAP_FAILED == map_info->buffer || buffer != (void *)(map_info->buffer + map_info->size))
674 goto error;827 goto error;
675 828
676 close(memfd);829 close(memfd);
@@ -702,6 +855,7 @@ error: · 25 unmodified lines
702 return -1;855 return -1;
703#endif856#endif
704}857}
858#endif /*MINIMP3_ENABLE_RING*/
705#elif defined(_WIN32)859#elif defined(_WIN32)
706#include <windows.h>860#include <windows.h>
707 861
@@ -713,14 +867,11 @@ static void mp3dec_close_file(mp3dec_map_info_t *map_info) · 5 unmodified lines
713 map_info->size = 0;867 map_info->size = 0;
714}868}
715 869
716static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info)870static int mp3dec_open_file_h(HANDLE file, mp3dec_map_info_t *map_info)
717{871{
718 memset(map_info, 0, sizeof(*map_info));872 memset(map_info, 0, sizeof(*map_info));
719 873
720 HANDLE mapping = NULL;874 HANDLE mapping = NULL;
721 HANDLE file = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
722 if (INVALID_HANDLE_VALUE == file)
723 return -1;
724 LARGE_INTEGER s;875 LARGE_INTEGER s;
725 s.LowPart = GetFileSize(file, (DWORD*)&s.HighPart);876 s.LowPart = GetFileSize(file, (DWORD*)&s.HighPart);
726 if (s.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)877 if (s.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
@@ -743,6 +894,24 @@ error: · 16 unmodified lines
743 return -1;894 return -1;
744}895}
745 896
897static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info)
898{
899 HANDLE file = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
900 if (INVALID_HANDLE_VALUE == file)
901 return -1;
902 return mp3dec_open_file_h(file, map_info);
903}
904
905static int mp3dec_open_file_w(const wchar_t *file_name, mp3dec_map_info_t *map_info)
906{
907 HANDLE file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
908 if (INVALID_HANDLE_VALUE == file)
909 return -1;
910 return mp3dec_open_file_h(file, map_info);
911}
912
913#if 0
914#define MINIMP3_HAVE_RING
746static void mp3dec_close_ring(mp3dec_map_info_t *map_info)915static void mp3dec_close_ring(mp3dec_map_info_t *map_info)
747{916{
748 if (map_info->buffer)917 if (map_info->buffer)
@@ -760,6 +929,7 @@ static int mp3dec_open_ring(mp3dec_map_info_t *map_info, size_t size) · 11 unmodified lines
760 HANDLE hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);929 HANDLE hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
761 if (INVALID_HANDLE_VALUE == hMap)930 if (INVALID_HANDLE_VALUE == hMap)
762 return -1;931 return -1;
932 /* TODO: do not works with VirtualAlloc, but no guarantee enough free address space without it */
763 map_info->buffer = (const uint8_t *)VirtualAlloc(0, size*2, MEM_RESERVE, PAGE_READWRITE);933 map_info->buffer = (const uint8_t *)VirtualAlloc(0, size*2, MEM_RESERVE, PAGE_READWRITE);
764 if (!map_info->buffer)934 if (!map_info->buffer)
765 goto error;935 goto error;
@@ -774,9 +944,9 @@ error: · 8 unmodified lines
774 CloseHandle(hMap);944 CloseHandle(hMap);
775 return -1;945 return -1;
776}946}
947#endif /*0*/
777#else948#else
778#include <stdio.h>949#include <stdio.h>
779#define MINIMP3_NO_RING
780 950
781static void mp3dec_close_file(mp3dec_map_info_t *map_info)951static void mp3dec_close_file(mp3dec_map_info_t *map_info)
782{952{
@@ -815,30 +985,90 @@ error: · 32 unmodified lines
815}985}
816#endif986#endif
817 987
988static 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)
989{
990 mp3dec_load_buf(dec, map_info->buffer, map_info->size, info, progress_cb, user_data);
991 mp3dec_close_file(map_info);
992 return info->samples ? 0 : -1;
993}
994
995static size_t mp3dec_iterate_mapinfo(mp3dec_map_info_t *map_info, MP3D_ITERATE_CB callback, void *user_data)
996{
997 size_t res = mp3dec_iterate_buf(map_info->buffer, map_info->size, callback, user_data);
998 mp3dec_close_file(map_info);
999 return res;
1000}
1001
1002static int mp3dec_ex_open_mapinfo(mp3dec_ex_t *dec, int seek_method)
1003{
1004 int ret = mp3dec_ex_open_buf(dec, dec->file.buffer, dec->file.size, seek_method);
1005 dec->is_file = 1;
1006 if (ret)
1007 mp3dec_ex_close(dec);
1008 return ret;
1009}
1010
818int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)1011int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)
819{1012{
820 int ret;1013 int ret;
821 mp3dec_map_info_t map_info;1014 mp3dec_map_info_t map_info;
822 if ((ret = mp3dec_open_file(file_name, &map_info)))1015 if ((ret = mp3dec_open_file(file_name, &map_info)))
823 return ret;1016 return ret;
824 mp3dec_load_buf(dec, map_info.buffer, map_info.size, info, progress_cb, user_data);1017 return mp3dec_load_mapinfo(dec, &map_info,info, progress_cb, user_data);
825 mp3dec_close_file(&map_info);
826 return info->samples ? 0 : -1;
827}1018}
828 1019
829int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data)1020size_t mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data)
830{1021{
831 int ret;1022 int ret;
832 mp3dec_map_info_t map_info;1023 mp3dec_map_info_t map_info;
833 if ((ret = mp3dec_open_file(file_name, &map_info)))1024 if ((ret = mp3dec_open_file(file_name, &map_info)))
834 return ret;1025 return ret;
835 mp3dec_iterate_buf(map_info.buffer, map_info.size, callback, user_data);1026 return mp3dec_iterate_mapinfo(&map_info, callback, user_data);
836 mp3dec_close_file(&map_info);1027}
1028
1029int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int seek_method)
1030{
1031 int ret;
1032 if ((ret = mp3dec_open_file(file_name, &dec->file)))
1033 return ret;
1034 return mp3dec_ex_open_mapinfo(dec, seek_method);
1035}
1036
1037int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int seek_method)
1038{
1039 memset(dec, 0, sizeof(*dec));
1040#ifdef MINIMP3_HAVE_RING
1041 if (mp3dec_open_ring(&dec->file, MINIMP3_IO_SIZE))
1042 return MP3D_E_MEMORY;
1043#else
1044 dec->file.size = MINIMP3_IO_SIZE;
1045 dec->file.buffer = malloc(dec->file.size);
1046 if (!dec->file.buffer)
1047 return MP3D_E_MEMORY;
1048#endif
1049 dec->seek_method = seek_method;
1050 dec->io = io;
1051 mp3dec_init(&dec->mp3d);
1052 if (MP3D_SEEK_TO_SAMPLE == dec->seek_method)
1053 {
1054 if (mp3dec_iterate_cb(io, (uint8_t *)dec->file.buffer, dec->file.size, mp3dec_load_index, dec) > 0 && !dec->index.frames && !dec->vbr_tag_found)
1055 return MP3D_E_MEMORY;
1056 dec->io->seek(dec->start_offset, dec->io->seek_data);
1057 mp3dec_init(&dec->mp3d);
1058 dec->buffer_samples = 0;
1059 }
837 return 0;1060 return 0;
838}1061}
839 1062
840void mp3dec_ex_close(mp3dec_ex_t *dec)1063void mp3dec_ex_close(mp3dec_ex_t *dec)
841{1064{
1065#ifdef MINIMP3_HAVE_RING
1066 if (dec->io)
1067 mp3dec_close_ring(&dec->file);
1068#else
1069 if (dec->io && dec->file.buffer)
1070 free((void*)dec->file.buffer);
1071#endif
842 if (dec->is_file)1072 if (dec->is_file)
843 mp3dec_close_file(&dec->file);1073 mp3dec_close_file(&dec->file);
844 if (dec->index.frames)1074 if (dec->index.frames)
@@ -846,31 +1076,33 @@ void mp3dec_ex_close(mp3dec_ex_t *dec) · 1 unmodified line
846 memset(dec, 0, sizeof(*dec));1076 memset(dec, 0, sizeof(*dec));
847}1077}
848 1078
849int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int seek_method)1079#ifdef _WIN32
1080int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)
850{1081{
851 int ret;1082 int ret;
852 if ((ret = mp3dec_open_file(file_name, &dec->file)))1083 mp3dec_map_info_t map_info;
1084 if ((ret = mp3dec_open_file_w(file_name, &map_info)))
853 return ret;1085 return ret;
854 ret = mp3dec_ex_open_buf(dec, dec->file.buffer, dec->file.size, seek_method);1086 return mp3dec_load_mapinfo(dec, &map_info,info, progress_cb, user_data);
855 dec->is_file = 1;
856 return ret;
857}1087}
858 1088
859int mp3dec_ex_open_cb(mp3dec_ex_t *dec, MP3D_READ_CB read_cb, void *read_user_data, MP3D_SEEK_CB seek_cb, void *seek_user_data, int seek_method)1089int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data)
860{1090{
861 memset(dec, 0, sizeof(*dec));1091 int ret;
862#ifndef MINIMP3_NO_RING1092 mp3dec_map_info_t map_info;
863 mp3dec_open_ring(&dec->file, MINIMP3_RING_SIZE);1093 if ((ret = mp3dec_open_file_w(file_name, &map_info)))
864#endif1094 return ret;
865 dec->seek_method = seek_method;1095 return mp3dec_iterate_mapinfo(&map_info, callback, user_data);
866 mp3dec_init(&dec->mp3d);
867 /* TODO */
868 (void)read_cb;
869 (void)read_user_data;
870 (void)seek_cb;
871 (void)seek_user_data;
872 return 0;
873}1096}
1097
1098int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int seek_method)
1099{
1100 int ret;
1101 if ((ret = mp3dec_open_file_w(file_name, &dec->file)))
1102 return ret;
1103 return mp3dec_ex_open_mapinfo(dec, seek_method);
1104}
1105#endif
874#else /* MINIMP3_NO_STDIO */1106#else /* MINIMP3_NO_STDIO */
875void mp3dec_ex_close(mp3dec_ex_t *dec)1107void mp3dec_ex_close(mp3dec_ex_t *dec)
876{1108{
minimp3_test.c+59−27
@@ -17,6 +17,7 @@ · 16 unmodified lines
17#define MODE_LOAD 017#define MODE_LOAD 0
18#define MODE_ITERATE 118#define MODE_ITERATE 1
19#define MODE_STREAM 219#define MODE_STREAM 2
20#define MODE_STREAM_CB 3
20 21
21static int16_t read16le(const void *p)22static int16_t read16le(const void *p)
22{23{
@@ -64,6 +65,16 @@ static unsigned char *preload(FILE *file, int *data_size) · 41 unmodified lines
64 return data;65 return data;
65}66}
66 67
68static size_t read_cb(void *buf, size_t size, void *user_data)
69{
70 return fread(buf, 1, size, (FILE*)user_data);
71}
72
73static int seek_cb(uint64_t position, void *user_data)
74{
75 return fseek((FILE*)user_data, position, SEEK_SET);
76}
77
67typedef struct78typedef struct
68{79{
69 mp3dec_t *mp3d;80 mp3dec_t *mp3d;
@@ -71,7 +82,7 @@ typedef struct · 1 unmodified line
71 size_t allocated;82 size_t allocated;
72} frames_iterate_data;83} frames_iterate_data;
73 84
74static int frames_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)85static int frames_iterate_cb(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info)
75{86{
76 (void)buf_size;87 (void)buf_size;
77 (void)offset;88 (void)offset;
@@ -113,20 +124,42 @@ static void decode_file(const char *input_file_name, const unsigned char *buf_re · 35 unmodified lines
113 {124 {
114 frames_iterate_data d = { &mp3d, &info, 0 };125 frames_iterate_data d = { &mp3d, &info, 0 };
115 mp3dec_init(&mp3d);126 mp3dec_init(&mp3d);
116 res = mp3dec_iterate(input_file_name, frames_iterate_cb, &d);127 res = mp3dec_iterate(input_file_name, frames_iterate_cb, &d) > 0 ? 0 : -1;
117 } else if (MODE_STREAM == mode)128 } else if (MODE_STREAM == mode || MODE_STREAM_CB == mode)
118 {129 {
119 mp3dec_ex_t dec;130 mp3dec_ex_t dec;
131 mp3dec_io_t io;
120 size_t readed;132 size_t readed;
121 res = mp3dec_ex_open(&dec, input_file_name, MP3D_SEEK_TO_SAMPLE);133 if (MODE_STREAM_CB == mode)
134 {
135 FILE *file = fopen(input_file_name, "rb");
136 io.read = read_cb;
137 io.seek = seek_cb;
138 io.read_data = io.seek_data = file;
139 res = file ? mp3dec_ex_open_cb(&dec, &io, MP3D_SEEK_TO_SAMPLE) : -1;
140 } else
141 {
142 res = mp3dec_ex_open(&dec, input_file_name, MP3D_SEEK_TO_SAMPLE);
143 }
144 if (res)
145 {
146 printf("error: mp3dec_ex_open() failed\n");
147 exit(1);
148 }
122 info.samples = dec.samples;149 info.samples = dec.samples;
123 info.buffer = malloc(dec.samples*sizeof(int16_t));150 info.buffer = malloc(dec.samples*sizeof(mp3d_sample_t));
124 info.hz = dec.info.hz;151 info.hz = dec.info.hz;
125 info.layer = dec.info.layer;152 info.layer = dec.info.layer;
126 info.channels = dec.info.channels;153 info.channels = dec.info.channels;
127 if (position < 0)154 if (position < 0)
128 {155 {
156#ifdef _WIN32
157 LARGE_INTEGER t;
158 QueryPerformanceCounter(&t);
159 srand(t.QuadPart);
160#else
129 srand(time(0));161 srand(time(0));
162#endif
130 position = info.samples > 150 ? (uint64_t)(info.samples - 150)*rand()/RAND_MAX : 0;163 position = info.samples > 150 ? (uint64_t)(info.samples - 150)*rand()/RAND_MAX : 0;
131 printf("info: seek to %d/%d\n", position, (int)info.samples);164 printf("info: seek to %d/%d\n", position, (int)info.samples);
132 }165 }
@@ -151,6 +184,8 @@ static void decode_file(const char *input_file_name, const unsigned char *buf_re · 18 unmodified lines
151 exit(1);184 exit(1);
152 }185 }
153 mp3dec_ex_close(&dec);186 mp3dec_ex_close(&dec);
187 if (MODE_STREAM_CB == mode)
188 fclose((FILE*)io.read_data);
154 } else189 } else
155 {190 {
156 printf("error: unknown mode\n");191 printf("error: unknown mode\n");
@@ -175,32 +210,29 @@ static void decode_file(const char *input_file_name, const unsigned char *buf_re · 18 unmodified lines
175 if (wave_out && file_out)210 if (wave_out && file_out)
176 fwrite(wav_header(0, 0, 0, 0), 1, 44, file_out);211 fwrite(wav_header(0, 0, 0, 0), 1, 44, file_out);
177#endif212#endif
178 if (info.samples)213 total_samples += info.samples;
214 if (buf_ref)
179 {215 {
180 total_samples += info.samples;216 size_t ref_samples = ref_size/2;
181 if (buf_ref)217 int len_match = ref_samples == info.samples;
218 int relaxed_len_match = len_match || (ref_samples + 1152) == info.samples || (ref_samples + 2304) == info.samples;
219 int seek_len_match = (ref_samples <= info.samples) || (ref_samples + 2304) >= info.samples;
220 if ((((!relaxed_len_match && 2 != mode && 3 != mode) || !seek_len_match) && 3 == info.layer && !no_std_vec) || (no_std_vec && !len_match))
221 { /* some standard vectors are for some reason a little shorter */
222 printf("error: reference and produced number of samples do not match (%d/%d)\n", (int)ref_samples, (int)info.samples);
223 exit(1);
224 }
225 int max_samples = MINIMP3_MIN(ref_samples, info.samples);
226 for (i = 0; i < max_samples; i++)
182 {227 {
183 size_t ref_samples = ref_size/2;228 int MSEtemp = abs((int)buffer[i] - (int)(int16_t)read16le(&buf_ref[i*sizeof(int16_t)]));
184 int len_match = ref_samples == info.samples;229 if (MSEtemp > maxdiff)
185 int relaxed_len_match = len_match || (ref_samples + 1152) == info.samples || (ref_samples + 2304) == info.samples;230 maxdiff = MSEtemp;
186 int seek_len_match = (ref_samples <= info.samples) || (ref_samples + 2304) >= info.samples;231 MSE += (float)MSEtemp*(float)MSEtemp;
187 if ((((!relaxed_len_match && 2 != mode) || !seek_len_match) && 3 == info.layer && !no_std_vec) || (no_std_vec && !len_match))
188 { /* some standard vectors are for some reason a little shorter */
189 printf("error: reference and produced number of samples do not match (%d/%d)\n", (int)ref_samples, (int)info.samples);
190 exit(1);
191 }
192 int max_samples = MINIMP3_MIN(ref_samples, info.samples);
193 for (i = 0; i < max_samples; i++)
194 {
195 int MSEtemp = abs((int)buffer[i] - (int)(int16_t)read16le(&buf_ref[i*sizeof(int16_t)]));
196 if (MSEtemp > maxdiff)
197 maxdiff = MSEtemp;
198 MSE += (float)MSEtemp*(float)MSEtemp;
199 }
200 }232 }
201 if (file_out)
202 fwrite(buffer, info.samples, sizeof(int16_t), file_out);
203 }233 }
234 if (file_out)
235 fwrite(buffer, info.samples, sizeof(int16_t), file_out);
204 if (buffer)236 if (buffer)
205 free(buffer);237 free(buffer);
206 238
scripts/build.sh+4−0
@@ -21,6 +21,7 @@ gcc -coverage -O0 -m32 -std=c89 -msse2 -DMINIMP3_TEST -DMINIMP3_NO_WAV -o minimp · 20 unmodified lines
21scripts/test.sh21scripts/test.sh
22scripts/test_mode.sh 1 022scripts/test_mode.sh 1 0
23scripts/test_mode.sh 2 -123scripts/test_mode.sh 2 -1
24scripts/test_mode.sh 3 -1
24set +e25set +e
25./minimp326./minimp3
26./minimp3 do_not_exist27./minimp3 do_not_exist
@@ -38,6 +39,9 @@ scripts/test.sh · 11 unmodified lines
38echo testing x64 with float output...39echo testing x64 with float output...
39gcc $CFLAGS -DMINIMP3_FLOAT_OUTPUT -o minimp3 minimp3_test.c -lm40gcc $CFLAGS -DMINIMP3_FLOAT_OUTPUT -o minimp3 minimp3_test.c -lm
40scripts/test.sh41scripts/test.sh
42scripts/test_mode.sh 1 0
43scripts/test_mode.sh 2 -1
44scripts/test_mode.sh 3 -1
41 45
42echo testing arm w/o neon...46echo testing arm w/o neon...
43arm-none-eabi-gcc $CFLAGS -mthumb -mcpu=arm9e -o minimp3_arm minimp3_test.c --specs=rdimon.specs -lm47arm-none-eabi-gcc $CFLAGS -mthumb -mcpu=arm9e -o minimp3_arm minimp3_test.c --specs=rdimon.specs -lm

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