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