{"id":13732085,"url":"https://github.com/lieff/minimp3","last_synced_at":"2025-05-15T11:02:11.064Z","repository":{"id":40636930,"uuid":"116830129","full_name":"lieff/minimp3","owner":"lieff","description":"Minimalistic MP3 decoder single header library","archived":false,"fork":false,"pushed_at":"2024-08-15T17:51:55.000Z","size":18935,"stargazers_count":1700,"open_issues_count":37,"forks_count":221,"subscribers_count":52,"default_branch":"master","last_synced_at":"2025-04-14T16:57:56.281Z","etag":null,"topics":["audio","codec","decoder","mini","mini-mp3","minimal","mp3","mp3-decoder","music","single-header","single-header-lib","small","sound","tiny"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lieff.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-01-09T14:58:36.000Z","updated_at":"2025-04-13T12:00:57.000Z","dependencies_parsed_at":"2025-01-02T17:04:23.690Z","dependency_job_id":"04d35e36-8fcd-4c1b-aa56-eae7087aa9cc","html_url":"https://github.com/lieff/minimp3","commit_stats":{"total_commits":302,"total_committers":18,"mean_commits":16.77777777777778,"dds":"0.10596026490066224","last_synced_commit":"afb604c06bc8beb145fecd42c0ceb5bda8795144"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lieff%2Fminimp3","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lieff%2Fminimp3/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lieff%2Fminimp3/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lieff%2Fminimp3/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lieff","download_url":"https://codeload.github.com/lieff/minimp3/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254328385,"owners_count":22052632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio","codec","decoder","mini","mini-mp3","minimal","mp3","mp3-decoder","music","single-header","single-header-lib","small","sound","tiny"],"created_at":"2024-08-03T02:01:45.948Z","updated_at":"2025-05-15T11:02:10.973Z","avatar_url":"https://github.com/lieff.png","language":"C","readme":"minimp3\n==========\n\n[![Build Status](https://travis-ci.org/lieff/minimp3.svg)](https://travis-ci.org/lieff/minimp3)\n\u003ca href=\"https://scan.coverity.com/projects/lieff-minimp3\"\u003e\n  \u003cimg alt=\"Coverity Scan Build Status\"\n       src=\"https://scan.coverity.com/projects/14844/badge.svg\"/\u003e\n\u003c/a\u003e\n[![codecov](https://codecov.io/gh/lieff/minimp3/branch/master/graph/badge.svg)](https://codecov.io/gh/lieff/minimp3)\n\nMinimalistic, single-header library for decoding MP3. minimp3 is designed to be\nsmall, fast (with SSE and NEON support), and accurate (ISO conformant). You can\nfind a rough benchmark below, measured using ``perf`` on an i7-6700K, IO\nincluded, no CPU heat to address speedstep:\n\n| Vector      | Hz    | Samples| Sec    | Clockticks | Clockticks per second | PSNR | Max diff |\n| ----------- | ----- | ------ | ------ | --------- | ------ | ------ | - |\n|compl.bit    | 48000 | 248832 | 5.184  | 14306684  | 2.759M | 124.22 | 1 |\n|he_32khz.bit | 32000 | 172800 | 5.4    | 8426158   | 1.560M | 139.67 | 1 |\n|he_44khz.bit | 44100 | 472320 | 10.710 | 21296300  | 1.988M | 144.04 | 1 |\n|he_48khz.bit | 48000 | 172800 | 3.6    | 8453846   | 2.348M | 139.67 | 1 |\n|hecommon.bit | 44100 | 69120  | 1.567  | 3169715   | 2.022M | 133.93 | 1 |\n|he_free.bit  | 44100 | 156672 | 3.552  | 5798418   | 1.632M | 137.48 | 1 |\n|he_mode.bit  | 44100 | 262656 | 5.955  | 9882314   | 1.659M | 118.00 | 1 |\n|si.bit       | 44100 | 135936 | 3.082  | 7170520   | 2.326M | 120.30 | 1 |\n|si_block.bit | 44100 | 73728  | 1.671  | 4233136   | 2.533M | 125.18 | 1 |\n|si_huff.bit  | 44100 | 86400  | 1.959  | 4785322   | 2.442M | 107.98 | 1 |\n|sin1k0db.bit | 44100 | 725760 | 16.457 | 24842977  | 1.509M | 111.03 | 1 |\n\nConformance test passed on all vectors (PSNR \u003e 96db).\n\n## Comparison with keyj's [minimp3](https://keyj.emphy.de/minimp3/)\n\nComparison by features:\n\n| Keyj minimp3 | Current |\n| ------------ | ------- |\n| Fixed point  | Floating point |\n| source: 84kb | 70kb |\n| binary: 34kb (20kb compressed) | 30kb (20kb) |\n| no vector opts | SSE/NEON intrinsics |\n| no free format | free format support |\n\nBelow, you can find the benchmark and conformance test for keyj's minimp3:\n\n\n| Vector      | Hz    | Samples| Sec    | Clockticks | Clockticks per second | PSNR | Max diff |\n| ----------- | ----- | ------ | ------ | --------- | ------  | ----- | - |\n|compl.bit    | 48000 | 248832 | 5.184  | 31849373  | 6.143M  | 71.50 | 41 |\n|he_32khz.bit | 32000 | 172800 | 5.4    | 26302319  | 4.870M  | 71.63 | 24 |\n|he_44khz.bit | 44100 | 472320 | 10.710 | 41628861  | 3.886M  | 71.63 | 24 |\n|he_48khz.bit | 48000 | 172800 | 3.6    | 25899527  | 7.194M  | 71.63 | 24 |\n|hecommon.bit | 44100 | 69120  | 1.567  | 20437779  | 13.039M | 71.58 | 25 |\n|he_free.bit  | 44100 | 0 | 0  | -  | - | -  | - |\n|he_mode.bit  | 44100 | 262656 | 5.955  | 30988984  | 5.203M  | 71.78 | 27 |\n|si.bit       | 44100 | 135936 | 3.082  | 24096223  | 7.817M  | 72.35 | 36 |\n|si_block.bit | 44100 | 73728  | 1.671  | 20722017  | 12.394M | 71.84 | 26 |\n|si_huff.bit  | 44100 | 86400  | 1.959  | 21121376  | 10.780M | 27.80 | 65535 |\n|sin1k0db.bit | 44100 | 730368 | 16.561 | 55569636  | 3.355M  | 0.15  | 58814 |\n\nKeyj minimp3 conformance test fails on all vectors (PSNR \u003c 96db), and free\nformat is unsupported. This caused some problems when it was used\n[here](https://github.com/lieff/lvg), and was the main motivation for this work.\n\n## Usage\n\nFirst, we need to initialize the decoder structure:\n\n```c\n//#define MINIMP3_ONLY_MP3\n//#define MINIMP3_ONLY_SIMD\n//#define MINIMP3_NO_SIMD\n//#define MINIMP3_NONSTANDARD_BUT_LOGICAL\n//#define MINIMP3_FLOAT_OUTPUT\n#define MINIMP3_IMPLEMENTATION\n#include \"minimp3.h\"\n...\n    static mp3dec_t mp3d;\n    mp3dec_init(\u0026mp3d);\n```\n\nNote that you must define ``MINIMP3_IMPLEMENTATION`` in exactly one source file.\nYou can ``#include`` ``minimp3.h`` in as many files as you like.\nAlso you can use ``MINIMP3_ONLY_MP3`` define to strip MP1/MP2 decoding code.\nMINIMP3_ONLY_SIMD define controls generic (non SSE/NEON) code generation (always enabled on x64/arm64 targets).\nIn case you do not want any platform-specific SIMD optimizations, you can define ``MINIMP3_NO_SIMD``.\nMINIMP3_NONSTANDARD_BUT_LOGICAL define saves some code bytes, and enforces non-standard but logical behaviour of mono-stereo transition (rare case).\nMINIMP3_FLOAT_OUTPUT makes ``mp3dec_decode_frame()`` output to be float instead of short and additional function mp3dec_f32_to_s16 will be available for float-\u003eshort conversion if needed.\n\nThen. we decode the input stream frame-by-frame:\n\n```c\n    /*typedef struct\n    {\n        int frame_bytes;\n        int channels;\n        int hz;\n        int layer;\n        int bitrate_kbps;\n    } mp3dec_frame_info_t;*/\n    mp3dec_frame_info_t info;\n    short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];\n    /*unsigned char *input_buf; - input byte stream*/\n    samples = mp3dec_decode_frame(\u0026mp3d, input_buf, buf_size, pcm, \u0026info);\n```\n\nThe ``mp3dec_decode_frame()`` function decodes one full MP3 frame from the\ninput buffer, which must be large enough to hold one full frame.\n\nThe decoder will analyze the input buffer to properly sync with the MP3 stream,\nand will skip ID3 data, as well as any data which is not valid. Short buffers\nmay cause false sync and can produce 'squealing' artefacts. The bigger the size\nof the input buffer, the more reliable the sync procedure. We recommend having\nas many as 10 consecutive MP3 frames (~16KB) in the input buffer at a time.\n\nAt end of stream just pass rest of the buffer, sync procedure should work even\nwith just 1 frame in stream (except for free format and garbage at the end can\nmess things up, so id3v1 and ape tags must be removed first).\n\nFor free format there minimum 3 frames needed to do proper sync: 2 frames to\ndetect frame length and 1 next frame to check detect is good.\n\nThe size of the consumed MP3 data is returned in the ``mp3dec_frame_info_t``\nfield of the ``frame_bytes`` struct; you must remove the data corresponding to\nthe ``frame_bytes`` field  from the input buffer before the next decoder\ninvocation.\n\nThe decoding function returns the number of decoded samples. The following cases\nare possible:\n\n- **0:** No MP3 data was found in the input buffer\n- **384:**  Layer 1\n- **576:**  MPEG 2 Layer 3\n- **1152:** Otherwise\n\nThe following is a description of the possible combinations of the number of\nsamples and ``frame_bytes`` field values:\n\n- More than 0 samples and ``frame_bytes \u003e 0``:  Succesful decode\n- 0 samples and ``frame_bytes \u003e  0``: The decoder skipped ID3 or invalid data\n- 0 samples and ``frame_bytes == 0``: Insufficient data\n\nIf ``frame_bytes == 0``, the other fields may be uninitialized or unchanged; if\n``frame_bytes != 0``, the other fields are available. The application may call\n``mp3dec_init()`` when changing decode position, but this is not necessary.\n\nAs a special case, the decoder supports already split MP3 streams (for example,\nafter doing an MP4 demux). In this case, the input buffer must contain _exactly\none_ non-free-format frame.\n\n## Seeking\n\nYou can seek to any byte in the stream and call ``mp3dec_decode_frame``; this\nwill work in almost all cases, but is not completely guaranteed. Probablility of\nsync procedure failure lowers when MAX_FRAME_SYNC_MATCHES value grows. Default\nMAX_FRAME_SYNC_MATCHES=10 and probablility of sync failure should be very low.\nIf granule data is accidentally detected as a valid MP3 header, short audio artefacting is\npossible.\n\nHigh-level mp3dec_ex_seek function supports precise seek to sample (MP3D_SEEK_TO_SAMPLE)\nusing index and binary search.\n\n## Track length detect\n\nIf the file is known to be cbr, then all frames have equal size and\nlack ID3 tags, which allows us to decode the first frame and calculate all frame\npositions as ``frame_bytes * N``. However, because of padding, frames can differ\nin size even in this case.\n\nIn general case whole stream scan is needed to calculate it's length. Scan can be\nomitted if vbr tag is present (added by encoders like lame and ffmpeg), which contains\nlength info. High-level functions automatically use the vbr tag if present.\n\n## High-level API\n\nIf you need only decode file/buffer or use precise seek, you can use optional high-level API.\nJust ``#include`` ``minimp3_ex.h`` instead and use following additional functions:\n\n```c\n#define MP3D_SEEK_TO_BYTE   0\n#define MP3D_SEEK_TO_SAMPLE 1\n\n#define MINIMP3_PREDECODE_FRAMES 2 /* frames to pre-decode and skip after seek (to fill internal structures) */\n/*#define MINIMP3_SEEK_IDX_LINEAR_SEARCH*/ /* define to use linear index search instead of binary search on seek */\n#define MINIMP3_IO_SIZE (128*1024) /* io buffer size for streaming functions, must be greater than MINIMP3_BUF_SIZE */\n#define MINIMP3_BUF_SIZE (16*1024) /* buffer which can hold minimum 10 consecutive mp3 frames (~16KB) worst case */\n#define MINIMP3_ENABLE_RING 0      /* enable hardware magic ring buffer if available, to make less input buffer memmove(s) in callback IO mode */\n\n#define MP3D_E_MEMORY  -1\n#define MP3D_E_IOERROR -2\n\ntypedef struct\n{\n    mp3d_sample_t *buffer;\n    size_t samples; /* channels included, byte size = samples*sizeof(mp3d_sample_t) */\n    int channels, hz, layer, avg_bitrate_kbps;\n} mp3dec_file_info_t;\n\ntypedef size_t (*MP3D_READ_CB)(void *buf, size_t size, void *user_data);\ntypedef int (*MP3D_SEEK_CB)(uint64_t position, void *user_data);\n\ntypedef struct\n{\n    MP3D_READ_CB read;\n    void *read_data;\n    MP3D_SEEK_CB seek;\n    void *seek_data;\n} mp3dec_io_t;\n\ntypedef struct\n{\n    uint64_t samples;\n    mp3dec_frame_info_t info;\n    int last_error;\n    ...\n} mp3dec_ex_t;\n\ntypedef 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);\ntypedef int (*MP3D_PROGRESS_CB)(void *user_data, size_t file_size, uint64_t offset, mp3dec_frame_info_t *info);\n\n/* decode whole buffer block */\nint 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);\nint 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);\n/* iterate through frames */\nint mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data);\nint mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data);\n/* streaming decoder with seeking capability */\nint mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int seek_method);\nint mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int seek_method);\nvoid mp3dec_ex_close(mp3dec_ex_t *dec);\nint mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position);\nsize_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples);\n#ifndef MINIMP3_NO_STDIO\n/* stdio versions of file load, iterate and stream */\nint mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);\nint mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data);\nint mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int seek_method);\n#ifdef _WIN32\nint mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data);\nint mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data);\nint mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int seek_method);\n#endif\n#endif\n```\n\nUse MINIMP3_NO_STDIO define to exclude STDIO functions.\nMINIMP3_ALLOW_MONO_STEREO_TRANSITION allows mixing mono and stereo in same file.\nIn that case ``mp3dec_frame_info_t-\u003echannels = 0`` is reported on such files and correct channels number passed to progress_cb callback for each frame in mp3dec_frame_info_t structure.\nMP3D_PROGRESS_CB is optional and can be NULL, example of file decoding:\n\n```c\n    mp3dec_t mp3d;\n    mp3dec_file_info_t info;\n    if (mp3dec_load(\u0026mp3d, input_file_name, \u0026info, NULL, NULL))\n    {\n        /* error */\n    }\n    /* mp3dec_file_info_t contains decoded samples and info,\n       use free(info.buffer) to deallocate samples */\n```\n\nExample of file decoding with seek capability:\n\n```c\n    mp3dec_ex_t dec;\n    if (mp3dec_ex_open(\u0026dec, input_file_name, MP3D_SEEK_TO_SAMPLE))\n    {\n        /* error */\n    }\n    /* dec.samples, dec.info.hz, dec.info.layer, dec.info.channels should be filled */\n    if (mp3dec_ex_seek(\u0026dec, position))\n    {\n        /* error */\n    }\n    mp3d_sample_t *buffer = malloc(dec.samples*sizeof(mp3d_sample_t));\n    size_t readed = mp3dec_ex_read(\u0026dec, buffer, dec.samples);\n    if (readed != dec.samples) /* normal eof or error condition */\n    {\n        if (dec.last_error)\n        {\n            /* error */\n        }\n    }\n```\n\n## Bindings\n\n * https://github.com/tosone/minimp3 - go bindings\n * https://github.com/notviri/rmp3 - rust `no_std` bindings which don't allocate.\n * https://github.com/germangb/minimp3-rs - rust bindings\n * https://github.com/johangu/node-minimp3 - NodeJS bindings\n * https://github.com/pyminimp3/pyminimp3 - python bindings\n * https://github.com/bashi/minimp3-wasm - wasm bindings\n * https://github.com/DasZiesel/minimp3-delphi - delphi bindings\n * https://github.com/mgeier/minimp3_ex-sys - low-level rust bindings to `minimp3_ex`\n\n## Interesting links\n\n * https://keyj.emphy.de/minimp3/\n * https://github.com/technosaurus/PDMP3\n * https://github.com/technosaurus/PDMP2\n * https://github.com/packjpg/packMP3\n * https://sites.google.com/a/kmlager.com/www/projects\n * https://sourceforge.net/projects/mp3dec/\n * http://blog.bjrn.se/2008/10/lets-build-mp3-decoder.html\n * http://www.mp3-converter.com/mp3codec/\n * http://www.multiweb.cz/twoinches/mp3inside.htm\n * https://www.mp3-tech.org/\n * https://id3.org/mp3Frame\n * https://www.datavoyage.com/mpgscript/mpeghdr.htm\n","funding_links":[],"categories":["Audio","C","Multimedia","多媒体"],"sub_categories":["Advanced books","高级书籍"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flieff%2Fminimp3","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flieff%2Fminimp3","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flieff%2Fminimp3/lists"}