shithub: mp3dec

Download patch

ref: 45a1de9792aa8402af620bd1dc2b2d7bb9a3c62a
parent: 4b51e005b755ccfa7d0dba68ed24702802169c03
author: lieff <lieff@users.noreply.github.com>
date: Fri Aug 3 19:14:41 EDT 2018

high-level API passes test

--- a/minimp3_ex.h
+++ b/minimp3_ex.h
@@ -11,7 +11,7 @@
 typedef struct
 {
     int16_t *buffer;
-    size_t samples;
+    size_t samples; /* channels included, byte size = samples*sizeof(int16_t) */
     int channels, hz, layer, avg_bitrate_kbps;
 } mp3dec_file_info_t;
 
@@ -220,10 +220,12 @@
     } while (frame_info.frame_bytes);
     if (!samples)
         return;
-    size_t samples_bytes = samples*frame_info.channels*2;
-    size_t allocated = (buf_size/frame_info.frame_bytes)*samples_bytes + MINIMP3_MAX_SAMPLES_PER_FRAME*2;
+    info->samples = samples*frame_info.channels;
+    size_t allocated = (buf_size/frame_info.frame_bytes)*info->samples*2 + MINIMP3_MAX_SAMPLES_PER_FRAME*2;
     info->buffer = malloc(allocated);
-    memcpy(info->buffer, pcm, samples_bytes);
+    memcpy(info->buffer, pcm, info->samples*2);
+    if (!info->buffer)
+        return;
     /* save info */
     info->channels = frame_info.channels;
     info->hz       = frame_info.hz;
@@ -233,24 +235,26 @@
     /* decode rest frames */
     do
     {
-        if ((allocated - samples_bytes) < MINIMP3_MAX_SAMPLES_PER_FRAME*2)
+        if ((allocated - info->samples*2) < MINIMP3_MAX_SAMPLES_PER_FRAME*2)
         {
             allocated *= 2;
             info->buffer = realloc(info->buffer, allocated);
         }
-        samples = mp3dec_decode_frame(dec, buf, buf_size, (int16_t*)((int8_t *)info->buffer + samples_bytes), &frame_info);
+        samples = mp3dec_decode_frame(dec, buf, buf_size, info->buffer + info->samples, &frame_info);
         if (samples)
         {
-            info->samples += samples;
+            if (info->hz != frame_info.hz || info->layer != frame_info.layer)
+                break;
+            info->samples += samples*frame_info.channels;
             avg_bitrate_kbps += frame_info.bitrate_kbps;
-            samples_bytes += samples*frame_info.channels*2;
+            frames++;
         }
         buf      += frame_info.frame_bytes;
         buf_size -= frame_info.frame_bytes;
     } while (frame_info.frame_bytes);
     /* reallocate to normal buffer size */
-    if (allocated != samples_bytes)
-        info->buffer = realloc(info->buffer, samples_bytes);
+    if (allocated != info->samples*2)
+        info->buffer = realloc(info->buffer, info->samples*2);
     info->avg_bitrate_kbps = avg_bitrate_kbps/frames;
 }
 
@@ -262,6 +266,7 @@
     size_t id3v2size = mp3dec_skip_id3v2(buf, buf_size);
     if (id3v2size > buf_size)
         return;
+    const uint8_t *orig_buf = buf;
     buf      += id3v2size;
     buf_size -= id3v2size;
     do
@@ -274,7 +279,14 @@
             continue;
         if (!frame_size)
             break;
-        callback(user_data, buf + i, frame_size, i, &frame_info);
+        const uint8_t *hdr = buf;
+        frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2;
+        frame_info.hz = hdr_sample_rate_hz(hdr);
+        frame_info.layer = 4 - HDR_GET_LAYER(hdr);
+        frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr);
+
+        if (callback(user_data, hdr, frame_size, hdr - orig_buf, &frame_info))
+            break;
         buf      += frame_size;
         buf_size -= frame_size;
     } while (1);
--- a/minimp3_test.c
+++ b/minimp3_test.c
@@ -2,7 +2,7 @@
 /*#define MINIMP3_ONLY_SIMD*/
 /*#define MINIMP3_NONSTANDARD_BUT_LOGICAL*/
 #define MINIMP3_IMPLEMENTATION
-#include "minimp3.h"
+#include "minimp3_ex.h"
 #include <stdio.h>
 #include <math.h>
 #include <string.h>
@@ -58,76 +58,81 @@
     return data;
 }
 
-static void decode_file(const unsigned char *buf_mp3, int mp3_size, const unsigned char *buf_ref, int ref_size, FILE *file_out, const int wave_out)
+#ifdef MP4_MODE
+typedef struct
 {
-    static mp3dec_t mp3d;
-    mp3dec_frame_info_t info;
-    int i, data_bytes, samples, total_samples = 0, maxdiff = 0;
-    double MSE = 0.0, psnr;
+    mp3dec_t *mp3d;
+    mp3dec_file_info_t *info;
+    size_t allocated;
+} frames_iterate_data;
 
-    if (mp3_size > 10 && !strncmp((char *)buf_mp3, "ID3", 3))
+static int frames_iterate_cb(void *user_data, const uint8_t *frame, int frame_size, size_t offset, mp3dec_frame_info_t *info)
+{
+    (void)offset;
+    frames_iterate_data *d = user_data;
+    d->info->channels = info->channels;
+    d->info->hz       = info->hz;
+    d->info->layer    = info->layer;
+    /*printf("%d %d %d\n", frame_size, (int)offset, info->channels);*/
+    if ((d->allocated - d->info->samples*2) < MINIMP3_MAX_SAMPLES_PER_FRAME*2)
     {
-        int id3v2size = (((buf_mp3[6] & 0x7f) << 21) | ((buf_mp3[7] & 0x7f) << 14) |
-            ((buf_mp3[8] & 0x7f) << 7) | (buf_mp3[9] & 0x7f)) + 10;
-        if (mp3_size >= id3v2size)
-        {
-            printf("info: skipping %d bytes of id3v2\n", id3v2size);
-            buf_mp3  += id3v2size;
-            mp3_size -= id3v2size;
-        }
+        if (!d->allocated)
+            d->allocated = 1024*1024;
+        else
+            d->allocated *= 2;
+        d->info->buffer = realloc(d->info->buffer, d->allocated);
     }
+    int samples = mp3dec_decode_frame(d->mp3d, frame, frame_size, d->info->buffer + d->info->samples, info);
+    if (samples)
+    {
+        d->info->samples += samples*info->channels;
+    }
+    return 0;
+}
+#endif
 
-    mp3dec_init(&mp3d);
+static void decode_file(const char *input_file_name, const unsigned char *buf_ref, int ref_size, FILE *file_out, const int wave_out)
+{
+    mp3dec_t mp3d;
+    int i, data_bytes, total_samples = 0, maxdiff = 0;
+    double MSE = 0.0, psnr;
+
+    mp3dec_file_info_t info;
     memset(&info, 0, sizeof(info));
+#ifdef MP4_MODE
+    frames_iterate_data d = { &mp3d, &info, 0 };
+    mp3dec_init(&mp3d);
+    if (mp3dec_iterate(input_file_name, frames_iterate_cb, &d))
+#else
+    if (mp3dec_load(&mp3d, input_file_name, &info))
+#endif
+    {
+        printf("error: file not found or read error");
+        exit(1);
+    }
 #ifndef MINIMP3_NO_WAV
     if (wave_out && file_out)
         fwrite(wav_header(0, 0, 0, 0), 1, 44, file_out);
 #endif
-    do
+    if (info.samples)
     {
-        short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
-#ifdef MP4_MODE
-        int free_format_bytes = 0, frame_size = 0;
-        i = mp3d_find_frame(buf_mp3, mp3_size, &free_format_bytes, &frame_size);
-        buf_mp3  += i;
-        mp3_size -= i;
-        if (i && !frame_size)
+        total_samples += info.samples;
+        if (buf_ref)
         {
-            printf("warning: skipping %d bytes, frame_size=%d\n", i, frame_size);
-            continue;
-        }
-        if (frame_size > mp3_size)
-        {
-            printf("error: demux mp3 frame failed: i=%d, frame_size=%d\n", i, frame_size);
-            exit(1);
-        }
-        if (!frame_size)
-            break;
-        samples = mp3dec_decode_frame(&mp3d, buf_mp3, frame_size, pcm, &info);
-#else
-        samples = mp3dec_decode_frame(&mp3d, buf_mp3, mp3_size, pcm, &info);
-#endif
-        if (samples)
-        {
-            total_samples += samples*info.channels;
-            if (buf_ref && ref_size >= samples*info.channels*2)
+            int max_samples = MINIMP3_MIN((size_t)ref_size/2, info.samples);
+            for (i = 0; i < max_samples; i++)
             {
-                for (i = 0; i < samples*info.channels; i++)
-                {
-                    int MSEtemp = abs((int)pcm[i] - (int)(short)read16le(&buf_ref[i*sizeof(short)]));
-                    if (MSEtemp > maxdiff)
-                        maxdiff = MSEtemp;
-                    MSE += (float)MSEtemp*(float)MSEtemp;
-                }
-                buf_ref  += samples*info.channels*2;
-                ref_size -= samples*info.channels*2;
+                int MSEtemp = abs((int)info.buffer[i] - (int)(short)read16le(&buf_ref[i*sizeof(short)]));
+                if (MSEtemp > maxdiff)
+                    maxdiff = MSEtemp;
+                MSE += (float)MSEtemp*(float)MSEtemp;
             }
-            if (file_out)
-                fwrite(pcm, samples, 2*info.channels, file_out);
         }
-        buf_mp3  += info.frame_bytes;
-        mp3_size -= info.frame_bytes;
-    } while (info.frame_bytes);
+        if (file_out)
+            fwrite(info.buffer, info.samples, sizeof(int16_t), file_out);
+        free(info.buffer);
+    }
+
 #ifndef LIBFUZZER
     MSE /= total_samples ? total_samples : 1;
     if (0 == MSE)
@@ -173,7 +178,7 @@
 int main(int argc, char *argv[])
 #endif
 {
-    int wave_out = 0, ref_size, mp3_size;
+    int wave_out = 0, ref_size;
     char *ref_file_name    = (argc > 2) ? argv[2] : NULL;
     char *output_file_name = (argc > 3) ? argv[3] : NULL;
     FILE *file_out = NULL;
@@ -200,17 +205,7 @@
         printf("error: no file names given\n");
         return 1;
     }
-    FILE *file_mp3 = fopen(input_file_name, "rb");
-    unsigned char *buf_mp3 = preload(file_mp3, &mp3_size);
-    if (file_mp3)
-        fclose(file_mp3);
-    if (!buf_mp3 || !mp3_size)
-    {
-        printf("error: no input data\n");
-        return 1;
-    }
-    decode_file(buf_mp3, mp3_size, buf_ref, ref_size, file_out, wave_out);
-    free(buf_mp3);
+    decode_file(input_file_name, buf_ref, ref_size, file_out, wave_out);
 #ifdef __AFL_HAVE_MANUAL_CONTROL
     }
 #endif
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -31,7 +31,7 @@
 
 echo testing arm w/o neon...
 arm-none-eabi-gcc -O2 -std=c89 -Wall -Wextra -Wmissing-prototypes -Werror -fno-asynchronous-unwind-tables -fno-stack-protector \
--mthumb -mcpu=cortex-m4 \
+-mthumb -mcpu=arm9e \
 -ffunction-sections -fdata-sections -Wl,--gc-sections -o minimp3_arm minimp3_test.c --specs=rdimon.specs -lm
 qemu-arm ./minimp3_arm