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
1313
1414 #define MINIMP3_PREDECODE_FRAMES 2 /* frames to pre-decode and skip after seek (to fill internal structures) */
1515 /*#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 */
1719
18−#define MP3D_E_MEMORY -1
20+#define MP3D_E_MEMORY -1
21+#define MP3D_E_IOERROR -2
1922
2023 typedef struct
2124 {
@@ -42,13 +45,22 @@ typedef struct · 20 unmodified lines
4245 size_t num_frames, capacity;
4346 } mp3dec_index_t;
4447
45−typedef int (*MP3D_READ_CB)(void *buf, size_t size, void *user_data);
46−typedef int (*MP3D_SEEK_CB)(size_t position);
48+typedef size_t (*MP3D_READ_CB)(void *buf, size_t size, void *user_data);
49+typedef int (*MP3D_SEEK_CB)(uint64_t position, void *user_data);
50+
51+typedef struct
52+{
53+ MP3D_READ_CB read;
54+ void *read_data;
55+ MP3D_SEEK_CB seek;
56+ void *seek_data;
57+} mp3dec_io_t;
4758
4859 typedef struct
4960 {
5061 mp3dec_t mp3d;
5162 mp3dec_map_info_t file;
63+ mp3dec_io_t *io;
5264 mp3dec_index_t index;
5365 uint64_t offset, samples, detected_samples, cur_sample, start_offset, end_offset;
5466 mp3dec_frame_info_t info;
@@ -61,8 +73,8 @@ typedef struct · 6 unmodified lines
6173 int buffer_samples, buffer_consumed, to_skip, start_delay;
6274 } mp3dec_ex_t;
6375
64−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);
65−typedef int (*MP3D_PROGRESS_CB)(void *user_data, size_t file_size, size_t offset, mp3dec_frame_info_t *info);
76+typedef 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);
77+typedef int (*MP3D_PROGRESS_CB)(void *user_data, size_t file_size, uint64_t offset, mp3dec_frame_info_t *info);
6678
6779 #ifdef __cplusplus
6880 extern "C" {
@@ -70,19 +82,26 @@ extern "C" { · 1 unmodified line
7082
7183 /* decode whole buffer block */
7284 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);
85+int 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);
7386 /* iterate through frames */
7487 size_t mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data);
88+uint64_t mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data);
7589 /* streaming decoder with seeking capability */
7690 int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int seek_method);
77−int 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);
91+int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int seek_method);
7892 void mp3dec_ex_close(mp3dec_ex_t *dec);
7993 int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position);
8094 size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples);
8195 #ifndef MINIMP3_NO_STDIO
82−/* stdio versions with file pre-load */
96+/* stdio versions of file load, iterate and stream */
8397 int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);
84−int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data);
98+size_t mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data);
8599 int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int seek_method);
100+#ifdef _WIN32
101+int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);
102+int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data);
103+int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int seek_method);
104+#endif
86105 #endif
87106
88107 #ifdef __cplusplus
@@ -93,22 +112,9 @@ int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int seek_method); · 4 unmodified lines
93112 #ifdef MINIMP3_IMPLEMENTATION
94113 #include <limits.h>
95114
96−static void mp3dec_skip_id3(const uint8_t **pbuf, size_t *pbuf_size)
115+static void mp3dec_skip_id3v1(const uint8_t *buf, size_t *pbuf_size)
97116 {
98− char *buf = (char *)(*pbuf);
99117 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
112118 #ifndef MINIMP3_NOSKIP_ID3V1
113119 if (buf_size > 128 && !memcmp(buf + buf_size - 128, "TAG", 3))
114120 {
@@ -123,6 +129,36 @@ static void mp3dec_skip_id3(const uint8_t **pbuf, size_t *pbuf_size) · 8 unmodified lines
123129 buf_size -= 32;
124130 }
125131 #endif
132+ *pbuf_size = buf_size;
133+}
134+
135+static 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+
149+static 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);
126162 *pbuf = (const uint8_t *)buf;
127163 *pbuf_size = buf_size;
128164 }
@@ -135,7 +171,7 @@ static int mp3dec_check_vbrtag(const uint8_t *frame, int frame_size, uint32_t *f · 6 unmodified lines
135171 #define BYTES_FLAG 2
136172 #define TOC_FLAG 4
137173 #define VBR_SCALE_FLAG 8
138− /* Side info offsets afrer header:
174+ /* Side info offsets after header:
139175 / Mono Stereo
140176 / MPEG1 17 32
141177 / 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
322358 return frames;
323359 }
324360
325−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)
361+uint64_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+
424+static 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)
326425 {
327426 mp3dec_frame_t *idx_frame;
328427 mp3dec_ex_t *dec = (mp3dec_ex_t *)user_data;
@@ -435,8 +534,15 @@ seek_zero: · 106 unmodified lines
435534 { /* no index created yet (vbr tag used to calculate track length) */
436535 dec->samples = 0;
437536 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)
439− return MP3D_E_MEMORY;
537+ if (dec->io)
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+ }
440546 for (i = 0; i < dec->index.num_frames; i++)
441547 dec->index.frames[i].offset += dec->start_offset;
442548 dec->samples = dec->detected_samples;
@@ -467,9 +573,26 @@ seek_zero: · 24 unmodified lines
467573 { /* make sure bit-reservoir is filled when we start decoding */
468574 bs_t bs[1];
469575 L3_gr_info_t gr_info[4];
470− const uint8_t *hdr = dec->file.buffer + dec->index.frames[i - 1].offset;
471− int frame_bytes, frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr);
472− bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE);
576+ int frame_bytes, frame_size;
577+ const uint8_t *hdr;
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+ }
473596 if (HDR_IS_CRC(hdr))
474597 get_bits(bs, 16);
475598 i--;
@@ -489,6 +612,8 @@ seek_zero: · 13 unmodified lines
489612 i++;
490613 }
491614 do_exit:
615+ if (dec->io)
616+ dec->io->seek(dec->offset, dec->io->seek_data);
492617 dec->buffer_samples = 0;
493618 dec->buffer_consumed = 0;
494619 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
499624 {
500625 uint64_t end_offset = dec->end_offset ? dec->end_offset : dec->file.size;
501626 size_t samples_requested = samples;
627+ size_t filled = 0, consumed = 0;
628+ int eof = 0;
502629 mp3dec_frame_info_t frame_info;
503630 memset(&frame_info, 0, sizeof(frame_info));
504631 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
521648 {
522649 if (dec->detected_samples && dec->cur_sample >= dec->detected_samples)
523650 break;
524− const uint8_t *dec_buf = dec->file.buffer + dec->offset;
525− uint64_t buf_size = end_offset - dec->offset;
526− if (!buf_size)
527− break;
528− dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, MINIMP3_MIN(buf_size, (uint64_t)INT_MAX), dec->buffer, &frame_info);
651+ const uint8_t *dec_buf;
652+ if (dec->io)
653+ {
654+ if (!eof && (filled - consumed) < MINIMP3_BUF_SIZE)
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+ }
529679 dec->buffer_consumed = 0;
530680 if (dec->buffer_samples)
531681 {
@@ -611,12 +761,14 @@ retry_mmap: · 79 unmodified lines
611761 return 0;
612762 }
613763
764+#if MINIMP3_ENABLE_RING && defined(__linux__) && defined(_GNU_SOURCE)
765+#define MINIMP3_HAVE_RING
614766 static void mp3dec_close_ring(mp3dec_map_info_t *map_info)
615767 {
616768 #if defined(__linux__) && defined(_GNU_SOURCE)
617769 if (map_info->buffer && MAP_FAILED != map_info->buffer)
618770 munmap((void *)map_info->buffer, map_info->size*2);
619−#esle
771+#else
620772 if (map_info->buffer)
621773 {
622774 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
631783 {
632784 int memfd, page_size;
633785 #if defined(__linux__) && defined(_GNU_SOURCE)
786+ void *buffer;
634787 int res;
635788 #endif
636789 memset(map_info, 0, sizeof(*map_info));
637790
638791 #ifdef _SC_PAGESIZE
639− page_size = sysconf( _SC_PAGESIZE );
792+ page_size = sysconf(_SC_PAGESIZE);
640793 #else
641794 page_size = getpagesize();
642795 #endif
@@ -648,29 +801,29 @@ static int mp3dec_open_ring(mp3dec_map_info_t *map_info, size_t size) · 5 unmodified lines
648801 return -1;
649802
650803 retry_ftruncate:
651− res = ftruncate(memfd, size);
804+ res = ftruncate(memfd, map_info->size);
652805 if (res && (errno == EAGAIN || errno == EINTR))
653806 goto retry_ftruncate;
654807 if (res)
655808 goto error;
656809
657810 retry_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);
659812 if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR))
660813 goto retry_mmap;
661− if (MAP_FAILED == map_info->buffer)
814+ if (MAP_FAILED == map_info->buffer || !map_info->buffer)
662815 goto error;
663816 retry_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);
665818 if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR))
666819 goto retry_mmap2;
667− if (MAP_FAILED == map_info->buffer)
820+ if (MAP_FAILED == map_info->buffer || buffer != (void *)map_info->buffer)
668821 goto error;
669822 retry_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);
671824 if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR))
672825 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))
674827 goto error;
675828
676829 close(memfd);
@@ -702,6 +855,7 @@ error: · 25 unmodified lines
702855 return -1;
703856 #endif
704857 }
858+#endif /*MINIMP3_ENABLE_RING*/
705859 #elif defined(_WIN32)
706860 #include <windows.h>
707861
@@ -713,14 +867,11 @@ static void mp3dec_close_file(mp3dec_map_info_t *map_info) · 5 unmodified lines
713867 map_info->size = 0;
714868 }
715869
716−static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info)
870+static int mp3dec_open_file_h(HANDLE file, mp3dec_map_info_t *map_info)
717871 {
718872 memset(map_info, 0, sizeof(*map_info));
719873
720874 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;
724875 LARGE_INTEGER s;
725876 s.LowPart = GetFileSize(file, (DWORD*)&s.HighPart);
726877 if (s.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
@@ -743,6 +894,24 @@ error: · 16 unmodified lines
743894 return -1;
744895 }
745896
897+static 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+
905+static 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
746915 static void mp3dec_close_ring(mp3dec_map_info_t *map_info)
747916 {
748917 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
760929 HANDLE hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL);
761930 if (INVALID_HANDLE_VALUE == hMap)
762931 return -1;
932+ /* TODO: do not works with VirtualAlloc, but no guarantee enough free address space without it */
763933 map_info->buffer = (const uint8_t *)VirtualAlloc(0, size*2, MEM_RESERVE, PAGE_READWRITE);
764934 if (!map_info->buffer)
765935 goto error;
@@ -774,9 +944,9 @@ error: · 8 unmodified lines
774944 CloseHandle(hMap);
775945 return -1;
776946 }
947+#endif /*0*/
777948 #else
778949 #include <stdio.h>
779−#define MINIMP3_NO_RING
780950
781951 static void mp3dec_close_file(mp3dec_map_info_t *map_info)
782952 {
@@ -815,30 +985,90 @@ error: · 32 unmodified lines
815985 }
816986 #endif
817987
988+static 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+
995+static 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+
1002+static 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+
8181011 int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)
8191012 {
8201013 int ret;
8211014 mp3dec_map_info_t map_info;
8221015 if ((ret = mp3dec_open_file(file_name, &map_info)))
8231016 return ret;
824− mp3dec_load_buf(dec, map_info.buffer, map_info.size, info, progress_cb, user_data);
825− mp3dec_close_file(&map_info);
826− return info->samples ? 0 : -1;
1017+ return mp3dec_load_mapinfo(dec, &map_info,info, progress_cb, user_data);
8271018 }
8281019
829−int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data)
1020+size_t mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data)
8301021 {
8311022 int ret;
8321023 mp3dec_map_info_t map_info;
8331024 if ((ret = mp3dec_open_file(file_name, &map_info)))
8341025 return ret;
835− mp3dec_iterate_buf(map_info.buffer, map_info.size, callback, user_data);
836− mp3dec_close_file(&map_info);
1026+ return mp3dec_iterate_mapinfo(&map_info, callback, user_data);
1027+}
1028+
1029+int 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+
1037+int 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+ }
8371060 return 0;
8381061 }
8391062
8401063 void mp3dec_ex_close(mp3dec_ex_t *dec)
8411064 {
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
8421072 if (dec->is_file)
8431073 mp3dec_close_file(&dec->file);
8441074 if (dec->index.frames)
@@ -846,31 +1076,33 @@ void mp3dec_ex_close(mp3dec_ex_t *dec) · 1 unmodified line
8461076 memset(dec, 0, sizeof(*dec));
8471077 }
8481078
849−int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int seek_method)
1079+#ifdef _WIN32
1080+int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data)
8501081 {
8511082 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)))
8531085 return ret;
854− ret = mp3dec_ex_open_buf(dec, dec->file.buffer, dec->file.size, seek_method);
855− dec->is_file = 1;
856− return ret;
1086+ return mp3dec_load_mapinfo(dec, &map_info,info, progress_cb, user_data);
8571087 }
8581088
859−int 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)
1089+int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data)
8601090 {
861− memset(dec, 0, sizeof(*dec));
862−#ifndef MINIMP3_NO_RING
863− mp3dec_open_ring(&dec->file, MINIMP3_RING_SIZE);
864−#endif
865− dec->seek_method = seek_method;
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;
1091+ int ret;
1092+ mp3dec_map_info_t map_info;
1093+ if ((ret = mp3dec_open_file_w(file_name, &map_info)))
1094+ return ret;
1095+ return mp3dec_iterate_mapinfo(&map_info, callback, user_data);
8731096 }
1097+
1098+int 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
8741106 #else /* MINIMP3_NO_STDIO */
8751107 void mp3dec_ex_close(mp3dec_ex_t *dec)
8761108 {
minimp3_test.c+59−27
@@ -17,6 +17,7 @@ · 16 unmodified lines
1717 #define MODE_LOAD 0
1818 #define MODE_ITERATE 1
1919 #define MODE_STREAM 2
20+#define MODE_STREAM_CB 3
2021
2122 static int16_t read16le(const void *p)
2223 {
@@ -64,6 +65,16 @@ static unsigned char *preload(FILE *file, int *data_size) · 41 unmodified lines
6465 return data;
6566 }
6667
68+static size_t read_cb(void *buf, size_t size, void *user_data)
69+{
70+ return fread(buf, 1, size, (FILE*)user_data);
71+}
72+
73+static int seek_cb(uint64_t position, void *user_data)
74+{
75+ return fseek((FILE*)user_data, position, SEEK_SET);
76+}
77+
6778 typedef struct
6879 {
6980 mp3dec_t *mp3d;
@@ -71,7 +82,7 @@ typedef struct · 1 unmodified line
7182 size_t allocated;
7283 } frames_iterate_data;
7384
74−static 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)
85+static 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)
7586 {
7687 (void)buf_size;
7788 (void)offset;
@@ -113,20 +124,42 @@ static void decode_file(const char *input_file_name, const unsigned char *buf_re · 35 unmodified lines
113124 {
114125 frames_iterate_data d = { &mp3d, &info, 0 };
115126 mp3dec_init(&mp3d);
116− res = mp3dec_iterate(input_file_name, frames_iterate_cb, &d);
117− } else if (MODE_STREAM == mode)
127+ res = mp3dec_iterate(input_file_name, frames_iterate_cb, &d) > 0 ? 0 : -1;
128+ } else if (MODE_STREAM == mode || MODE_STREAM_CB == mode)
118129 {
119130 mp3dec_ex_t dec;
131+ mp3dec_io_t io;
120132 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+ }
122149 info.samples = dec.samples;
123− info.buffer = malloc(dec.samples*sizeof(int16_t));
150+ info.buffer = malloc(dec.samples*sizeof(mp3d_sample_t));
124151 info.hz = dec.info.hz;
125152 info.layer = dec.info.layer;
126153 info.channels = dec.info.channels;
127154 if (position < 0)
128155 {
156+#ifdef _WIN32
157+ LARGE_INTEGER t;
158+ QueryPerformanceCounter(&t);
159+ srand(t.QuadPart);
160+#else
129161 srand(time(0));
162+#endif
130163 position = info.samples > 150 ? (uint64_t)(info.samples - 150)*rand()/RAND_MAX : 0;
131164 printf("info: seek to %d/%d\n", position, (int)info.samples);
132165 }
@@ -151,6 +184,8 @@ static void decode_file(const char *input_file_name, const unsigned char *buf_re · 18 unmodified lines
151184 exit(1);
152185 }
153186 mp3dec_ex_close(&dec);
187+ if (MODE_STREAM_CB == mode)
188+ fclose((FILE*)io.read_data);
154189 } else
155190 {
156191 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
175210 if (wave_out && file_out)
176211 fwrite(wav_header(0, 0, 0, 0), 1, 44, file_out);
177212 #endif
178− if (info.samples)
213+ total_samples += info.samples;
214+ if (buf_ref)
179215 {
180− total_samples += info.samples;
181− if (buf_ref)
216+ size_t ref_samples = ref_size/2;
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++)
182227 {
183− size_t ref_samples = ref_size/2;
184− int len_match = ref_samples == info.samples;
185− int relaxed_len_match = len_match || (ref_samples + 1152) == info.samples || (ref_samples + 2304) == info.samples;
186− int seek_len_match = (ref_samples <= info.samples) || (ref_samples + 2304) >= info.samples;
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− }
228+ int MSEtemp = abs((int)buffer[i] - (int)(int16_t)read16le(&buf_ref[i*sizeof(int16_t)]));
229+ if (MSEtemp > maxdiff)
230+ maxdiff = MSEtemp;
231+ MSE += (float)MSEtemp*(float)MSEtemp;
200232 }
201− if (file_out)
202− fwrite(buffer, info.samples, sizeof(int16_t), file_out);
203233 }
234+ if (file_out)
235+ fwrite(buffer, info.samples, sizeof(int16_t), file_out);
204236 if (buffer)
205237 free(buffer);
206238
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
2121 scripts/test.sh
2222 scripts/test_mode.sh 1 0
2323 scripts/test_mode.sh 2 -1
24+scripts/test_mode.sh 3 -1
2425 set +e
2526 ./minimp3
2627 ./minimp3 do_not_exist
@@ -38,6 +39,9 @@ scripts/test.sh · 11 unmodified lines
3839 echo testing x64 with float output...
3940 gcc $CFLAGS -DMINIMP3_FLOAT_OUTPUT -o minimp3 minimp3_test.c -lm
4041 scripts/test.sh
42+scripts/test_mode.sh 1 0
43+scripts/test_mode.sh 2 -1
44+scripts/test_mode.sh 3 -1
4145
4246 echo testing arm w/o neon...
4347 arm-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