13508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat/*
23508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * Copyright (C) 2014 The Android Open Source Project
33508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * All rights reserved.
43508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat *
53508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * Redistribution and use in source and binary forms, with or without
63508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * modification, are permitted provided that the following conditions
73508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * are met:
83508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat *  * Redistributions of source code must retain the above copyright
93508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat *    notice, this list of conditions and the following disclaimer.
103508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat *  * Redistributions in binary form must reproduce the above copyright
113508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat *    notice, this list of conditions and the following disclaimer in
123508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat *    the documentation and/or other materials provided with the
133508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat *    distribution.
143508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat *
153508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
163508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
173508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
183508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
193508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
203508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
213508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
223508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
233508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
243508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
253508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat * SUCH DAMAGE.
273508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat */
283508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
293508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat#include <stdlib.h>
303508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat#include <stdio.h>
313508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat#include <assert.h>
323508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat#include <string.h>
333508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat#include <stdint.h>
343508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat#include "mp3reader.h"
353508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
363508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhatstatic uint32_t U32_AT(const uint8_t *ptr) {
373508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
383508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat}
393508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
403508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhatstatic bool parseHeader(
413508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        uint32_t header, size_t *frame_size,
423508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        uint32_t *out_sampling_rate = NULL, uint32_t *out_channels = NULL ,
433508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        uint32_t *out_bitrate = NULL, uint32_t *out_num_samples = NULL) {
443508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    *frame_size = 0;
453508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
463508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (out_sampling_rate) {
473508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        *out_sampling_rate = 0;
483508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
493508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
503508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (out_channels) {
513508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        *out_channels = 0;
523508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
533508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
543508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (out_bitrate) {
553508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        *out_bitrate = 0;
563508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
573508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
583508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (out_num_samples) {
593508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        *out_num_samples = 1152;
603508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
613508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
623508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if ((header & 0xffe00000) != 0xffe00000) {
633508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        return false;
643508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
653508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
663508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    unsigned version = (header >> 19) & 3;
673508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
683508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (version == 0x01) {
693508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        return false;
703508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
713508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
723508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    unsigned layer = (header >> 17) & 3;
733508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
743508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (layer == 0x00) {
753508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        return false;
763508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
773508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
783508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    unsigned bitrate_index = (header >> 12) & 0x0f;
793508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
803508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (bitrate_index == 0 || bitrate_index == 0x0f) {
813508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        // Disallow "free" bitrate.
823508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        return false;
833508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
843508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
853508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    unsigned sampling_rate_index = (header >> 10) & 3;
863508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
873508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (sampling_rate_index == 3) {
883508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        return false;
893508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
903508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
913508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
923508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    int sampling_rate = kSamplingRateV1[sampling_rate_index];
933508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (version == 2 /* V2 */) {
943508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        sampling_rate /= 2;
953508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    } else if (version == 0 /* V2.5 */) {
963508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        sampling_rate /= 4;
973508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
983508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
993508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    unsigned padding = (header >> 9) & 1;
1003508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1013508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (layer == 3) {
1023508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        // layer I
1033508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1043508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        static const int kBitrateV1[] = {
1053508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            32, 64, 96, 128, 160, 192, 224, 256,
1063508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            288, 320, 352, 384, 416, 448
1073508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        };
1083508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1093508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        static const int kBitrateV2[] = {
1103508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            32, 48, 56, 64, 80, 96, 112, 128,
1113508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            144, 160, 176, 192, 224, 256
1123508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        };
1133508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1143508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        int bitrate =
1153508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            (version == 3 /* V1 */)
1163508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                ? kBitrateV1[bitrate_index - 1]
1173508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                : kBitrateV2[bitrate_index - 1];
1183508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1193508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (out_bitrate) {
1203508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            *out_bitrate = bitrate;
1213508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
1223508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1233508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
1243508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1253508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (out_num_samples) {
1263508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            *out_num_samples = 384;
1273508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
1283508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    } else {
1293508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        // layer II or III
1303508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1313508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        static const int kBitrateV1L2[] = {
1323508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            32, 48, 56, 64, 80, 96, 112, 128,
1333508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            160, 192, 224, 256, 320, 384
1343508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        };
1353508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1363508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        static const int kBitrateV1L3[] = {
1373508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            32, 40, 48, 56, 64, 80, 96, 112,
1383508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            128, 160, 192, 224, 256, 320
1393508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        };
1403508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1413508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        static const int kBitrateV2[] = {
1423508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            8, 16, 24, 32, 40, 48, 56, 64,
1433508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            80, 96, 112, 128, 144, 160
1443508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        };
1453508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1463508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        int bitrate;
1473508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (version == 3 /* V1 */) {
1483508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            bitrate = (layer == 2 /* L2 */)
1493508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                ? kBitrateV1L2[bitrate_index - 1]
1503508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                : kBitrateV1L3[bitrate_index - 1];
1513508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1523508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            if (out_num_samples) {
1533508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                *out_num_samples = 1152;
1543508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            }
1553508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        } else {
1563508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            // V2 (or 2.5)
1573508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1583508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            bitrate = kBitrateV2[bitrate_index - 1];
1593508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            if (out_num_samples) {
1603508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                *out_num_samples = (layer == 1 /* L3 */) ? 576 : 1152;
1613508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            }
1623508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
1633508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1643508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (out_bitrate) {
1653508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            *out_bitrate = bitrate;
1663508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
1673508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1683508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (version == 3 /* V1 */) {
1693508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            *frame_size = 144000 * bitrate / sampling_rate + padding;
1703508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        } else {
1713508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            // V2 or V2.5
1723508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            size_t tmp = (layer == 1 /* L3 */) ? 72000 : 144000;
1733508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            *frame_size = tmp * bitrate / sampling_rate + padding;
1743508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
1753508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
1763508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1773508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (out_sampling_rate) {
1783508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        *out_sampling_rate = sampling_rate;
1793508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
1803508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1813508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (out_channels) {
1823508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        int channel_mode = (header >> 6) & 3;
1833508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1843508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        *out_channels = (channel_mode == 3) ? 1 : 2;
1853508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
1863508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1873508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    return true;
1883508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat}
1893508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1903508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat// Mask to extract the version, layer, sampling rate parts of the MP3 header,
1913508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat// which should be same for all MP3 frames.
1923508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhatstatic const uint32_t kMask = 0xfffe0c00;
1933508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
1943508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhatstatic ssize_t sourceReadAt(FILE *fp, off64_t offset, void *data, size_t size) {
1953508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    int retVal = fseek(fp, offset, SEEK_SET);
1963508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (retVal != EXIT_SUCCESS) {
1973508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        return 0;
1983508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    } else {
1993508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat       return fread(data, 1, size, fp);
2003508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
2013508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat}
2023508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2033508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat// Resync to next valid MP3 frame in the file.
2043508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhatstatic bool resync(
2053508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        FILE *fp, uint32_t match_header,
2063508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        off64_t *inout_pos, uint32_t *out_header) {
2073508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2083508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (*inout_pos == 0) {
2093508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        // Skip an optional ID3 header if syncing at the very beginning
2103508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        // of the datasource.
2113508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2123508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        for (;;) {
2133508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            uint8_t id3header[10];
2143508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            int retVal = sourceReadAt(fp, *inout_pos, id3header,
2153508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                                      sizeof(id3header));
2163508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            if (retVal < (ssize_t)sizeof(id3header)) {
2173508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                // If we can't even read these 10 bytes, we might as well bail
2183508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                // out, even if there _were_ 10 bytes of valid mp3 audio data...
2193508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                return false;
2203508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            }
2213508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2223508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            if (memcmp("ID3", id3header, 3)) {
2233508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                break;
2243508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            }
2253508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2263508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            // Skip the ID3v2 header.
2273508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2283508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            size_t len =
2293508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                ((id3header[6] & 0x7f) << 21)
2303508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                | ((id3header[7] & 0x7f) << 14)
2313508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                | ((id3header[8] & 0x7f) << 7)
2323508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                | (id3header[9] & 0x7f);
2333508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2343508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            len += 10;
2353508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2363508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            *inout_pos += len;
2373508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
2383508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2393508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
2403508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2413508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    off64_t pos = *inout_pos;
2423508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    bool valid = false;
2433508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2443508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    const int32_t kMaxReadBytes = 1024;
2453508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    const int32_t kMaxBytesChecked = 128 * 1024;
2463508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    uint8_t buf[kMaxReadBytes];
2473508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    ssize_t bytesToRead = kMaxReadBytes;
2483508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    ssize_t totalBytesRead = 0;
2493508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    ssize_t remainingBytes = 0;
2503508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    bool reachEOS = false;
2513508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    uint8_t *tmp = buf;
2523508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2533508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    do {
2543508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (pos >= *inout_pos + kMaxBytesChecked) {
2553508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            // Don't scan forever.
2563508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            break;
2573508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
2583508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2593508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (remainingBytes < 4) {
2603508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            if (reachEOS) {
2613508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                break;
2623508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            } else {
2633508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                memcpy(buf, tmp, remainingBytes);
2643508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                bytesToRead = kMaxReadBytes - remainingBytes;
2653508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2663508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                /*
2673508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                 * The next read position should start from the end of
2683508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                 * the last buffer, and thus should include the remaining
2693508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                 * bytes in the buffer.
2703508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                 */
2713508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                totalBytesRead = sourceReadAt(fp, pos + remainingBytes,
2723508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                                             buf + remainingBytes, bytesToRead);
2733508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2743508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                if (totalBytesRead <= 0) {
2753508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                    break;
2763508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                }
2773508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                reachEOS = (totalBytesRead != bytesToRead);
2783508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                remainingBytes += totalBytesRead;
2793508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                tmp = buf;
2803508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                continue;
2813508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            }
2823508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
2833508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2843508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        uint32_t header = U32_AT(tmp);
2853508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2863508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
2873508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            ++pos;
2883508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            ++tmp;
2893508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            --remainingBytes;
2903508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            continue;
2913508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
2923508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
2933508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        size_t frame_size;
2943508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        uint32_t sample_rate, num_channels, bitrate;
2953508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (!parseHeader(
2963508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                    header, &frame_size,
2973508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                    &sample_rate, &num_channels, &bitrate)) {
2983508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            ++pos;
2993508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            ++tmp;
3003508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            --remainingBytes;
3013508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            continue;
3023508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
3033508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3043508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        // We found what looks like a valid frame,
3053508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        // now find its successors.
3063508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3073508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        off64_t test_pos = pos + frame_size;
3083508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3093508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        valid = true;
3103508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        const int FRAME_MATCH_REQUIRED = 3;
3113508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        for (int j = 0; j < FRAME_MATCH_REQUIRED; ++j) {
3123508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            uint8_t tmp[4];
3133508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            ssize_t retval = sourceReadAt(fp, test_pos, tmp, sizeof(tmp));
3143508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            if (retval < (ssize_t)sizeof(tmp)) {
3153508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                valid = false;
3163508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                break;
3173508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            }
3183508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3193508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            uint32_t test_header = U32_AT(tmp);
3203508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3213508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            if ((test_header & kMask) != (header & kMask)) {
3223508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                valid = false;
3233508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                break;
3243508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            }
3253508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3263508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            size_t test_frame_size;
3273508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            if (!parseHeader(test_header, &test_frame_size)) {
3283508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                valid = false;
3293508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                break;
3303508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            }
3313508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3323508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            test_pos += test_frame_size;
3333508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
3343508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3353508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (valid) {
3363508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            *inout_pos = pos;
3373508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3383508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            if (out_header != NULL) {
3393508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                *out_header = header;
3403508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            }
3413508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
3423508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3433508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        ++pos;
3443508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        ++tmp;
3453508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        --remainingBytes;
3463508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    } while (!valid);
3473508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3483508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    return valid;
3493508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat}
3503508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3513508d77cf7b619d33d236533a45eea1a7321cc5aAshok BhatMp3Reader::Mp3Reader() : mFp(NULL) {
3523508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat}
3533508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3543508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat// Initialize the MP3 reader.
3553508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhatbool Mp3Reader::init(const char *file) {
3563508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3573508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    // Open the file.
3583508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    mFp = fopen(file, "rb");
3593508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (mFp == NULL) return false;
3603508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3613508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    // Sync to the first valid frame.
3623508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    off64_t pos = 0;
3633508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    uint32_t header;
3643508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    bool success = resync(mFp, 0 /*match_header*/, &pos, &header);
3653508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (success == false) return false;
3663508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3673508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    mCurrentPos  = pos;
3683508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    mFixedHeader = header;
3693508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3703508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    size_t frame_size;
3713508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    return parseHeader(header, &frame_size, &mSampleRate,
3723508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                       &mNumChannels, &mBitrate);
3733508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat}
3743508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3753508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat// Get the next valid MP3 frame.
3763508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhatbool Mp3Reader::getFrame(void *buffer, uint32_t *size) {
3773508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3783508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    size_t frame_size;
3793508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    uint32_t bitrate;
3803508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    uint32_t num_samples;
3813508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    uint32_t sample_rate;
3823508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    for (;;) {
3833508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        ssize_t n = sourceReadAt(mFp, mCurrentPos, buffer, 4);
3843508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (n < 4) {
3853508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            return false;
3863508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
3873508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3883508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        uint32_t header = U32_AT((const uint8_t *)buffer);
3893508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3903508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if ((header & kMask) == (mFixedHeader & kMask)
3913508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            && parseHeader(
3923508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                header, &frame_size, &sample_rate, NULL /*out_channels*/,
3933508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat                &bitrate, &num_samples)) {
3943508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            break;
3953508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
3963508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
3973508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        // Lost sync.
3983508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        off64_t pos = mCurrentPos;
3993508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        if (!resync(mFp, mFixedHeader, &pos, NULL /*out_header*/)) {
4003508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            // Unable to resync. Signalling end of stream.
4013508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat            return false;
4023508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        }
4033508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
4043508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        mCurrentPos = pos;
4053508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
4063508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        // Try again with the new position.
4073508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
4083508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    ssize_t n = sourceReadAt(mFp, mCurrentPos, buffer, frame_size);
4093508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    if (n < (ssize_t)frame_size) {
4103508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat        return false;
4113508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    }
4123508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
4133508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    *size = frame_size;
4143508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    mCurrentPos += frame_size;
4153508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    return true;
4163508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat}
4173508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
4183508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat// Close the MP3 reader.
4193508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhatvoid Mp3Reader::close() {
4203508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    assert(mFp != NULL);
4213508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat    fclose(mFp);
4223508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat}
4233508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat
4243508d77cf7b619d33d236533a45eea1a7321cc5aAshok BhatMp3Reader::~Mp3Reader() {
4253508d77cf7b619d33d236533a45eea1a7321cc5aAshok Bhat}
426