XINGSeeker.cpp revision c7fc37a3dab9bd1f96713649f351b5990e6316ff
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "include/XINGSeeker.h" 18 19#include <media/stagefright/DataSource.h> 20#include <media/stagefright/Utils.h> 21 22namespace android { 23 24static bool parse_xing_header( 25 const sp<DataSource> &source, off64_t first_frame_pos, 26 int32_t *frame_number = NULL, int32_t *byte_number = NULL, 27 char *table_of_contents = NULL, int32_t *quality_indicator = NULL, 28 int64_t *duration = NULL); 29 30// static 31sp<XINGSeeker> XINGSeeker::CreateFromSource( 32 const sp<DataSource> &source, off64_t first_frame_pos) { 33 sp<XINGSeeker> seeker = new XINGSeeker; 34 35 seeker->mFirstFramePos = first_frame_pos; 36 37 if (!parse_xing_header( 38 source, first_frame_pos, 39 NULL, &seeker->mSizeBytes, seeker->mTableOfContents, 40 NULL, &seeker->mDurationUs)) { 41 return NULL; 42 } 43 44 LOGI("Found XING header."); 45 46 return seeker; 47} 48 49XINGSeeker::XINGSeeker() 50 : mDurationUs(-1), 51 mSizeBytes(0) { 52} 53 54bool XINGSeeker::getDuration(int64_t *durationUs) { 55 if (mDurationUs < 0) { 56 return false; 57 } 58 59 *durationUs = mDurationUs; 60 61 return true; 62} 63 64bool XINGSeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) { 65 if (mSizeBytes == 0 || mTableOfContents[0] <= 0 || mDurationUs < 0) { 66 return false; 67 } 68 69 float percent = (float)(*timeUs) * 100 / mDurationUs; 70 float fx; 71 if( percent <= 0.0f ) { 72 fx = 0.0f; 73 } else if( percent >= 100.0f ) { 74 fx = 256.0f; 75 } else { 76 int a = (int)percent; 77 float fa, fb; 78 if ( a == 0 ) { 79 fa = 0.0f; 80 } else { 81 fa = (float)mTableOfContents[a-1]; 82 } 83 if ( a < 99 ) { 84 fb = (float)mTableOfContents[a]; 85 } else { 86 fb = 256.0f; 87 } 88 fx = fa + (fb-fa)*(percent-a); 89 } 90 91 *pos = (int)((1.0f/256.0f)*fx*mSizeBytes) + mFirstFramePos; 92 93 return true; 94} 95 96static bool parse_xing_header( 97 const sp<DataSource> &source, off64_t first_frame_pos, 98 int32_t *frame_number, int32_t *byte_number, 99 char *table_of_contents, int32_t *quality_indicator, 100 int64_t *duration) { 101 if (frame_number) { 102 *frame_number = 0; 103 } 104 if (byte_number) { 105 *byte_number = 0; 106 } 107 if (table_of_contents) { 108 table_of_contents[0] = 0; 109 } 110 if (quality_indicator) { 111 *quality_indicator = 0; 112 } 113 if (duration) { 114 *duration = 0; 115 } 116 117 uint8_t buffer[4]; 118 int offset = first_frame_pos; 119 if (source->readAt(offset, &buffer, 4) < 4) { // get header 120 return false; 121 } 122 offset += 4; 123 124 uint8_t id, layer, sr_index, mode; 125 layer = (buffer[1] >> 1) & 3; 126 id = (buffer[1] >> 3) & 3; 127 sr_index = (buffer[2] >> 2) & 3; 128 mode = (buffer[3] >> 6) & 3; 129 if (layer == 0) { 130 return false; 131 } 132 if (id == 1) { 133 return false; 134 } 135 if (sr_index == 3) { 136 return false; 137 } 138 // determine offset of XING header 139 if(id&1) { // mpeg1 140 if (mode != 3) offset += 32; 141 else offset += 17; 142 } else { // mpeg2 143 if (mode != 3) offset += 17; 144 else offset += 9; 145 } 146 147 if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID 148 return false; 149 } 150 offset += 4; 151 // Check XING ID 152 if ((buffer[0] != 'X') || (buffer[1] != 'i') 153 || (buffer[2] != 'n') || (buffer[3] != 'g')) { 154 if ((buffer[0] != 'I') || (buffer[1] != 'n') 155 || (buffer[2] != 'f') || (buffer[3] != 'o')) { 156 return false; 157 } 158 } 159 160 if (source->readAt(offset, &buffer, 4) < 4) { // flags 161 return false; 162 } 163 offset += 4; 164 uint32_t flags = U32_AT(buffer); 165 166 if (flags & 0x0001) { // Frames field is present 167 if (source->readAt(offset, buffer, 4) < 4) { 168 return false; 169 } 170 if (frame_number) { 171 *frame_number = U32_AT(buffer); 172 } 173 int32_t frame = U32_AT(buffer); 174 // Samples per Frame: 1. index = MPEG Version ID, 2. index = Layer 175 const int samplesPerFrames[2][3] = 176 { 177 { 384, 1152, 576 }, // MPEG 2, 2.5: layer1, layer2, layer3 178 { 384, 1152, 1152 }, // MPEG 1: layer1, layer2, layer3 179 }; 180 // sampling rates in hertz: 1. index = MPEG Version ID, 2. index = sampling rate index 181 const int samplingRates[4][3] = 182 { 183 { 11025, 12000, 8000, }, // MPEG 2.5 184 { 0, 0, 0, }, // reserved 185 { 22050, 24000, 16000, }, // MPEG 2 186 { 44100, 48000, 32000, } // MPEG 1 187 }; 188 if (duration) { 189 *duration = (int64_t)frame * samplesPerFrames[id&1][3-layer] * 1000000LL 190 / samplingRates[id][sr_index]; 191 } 192 offset += 4; 193 } 194 if (flags & 0x0002) { // Bytes field is present 195 if (byte_number) { 196 if (source->readAt(offset, buffer, 4) < 4) { 197 return false; 198 } 199 *byte_number = U32_AT(buffer); 200 } 201 offset += 4; 202 } 203 if (flags & 0x0004) { // TOC field is present 204 if (table_of_contents) { 205 if (source->readAt(offset + 1, table_of_contents, 99) < 99) { 206 return false; 207 } 208 } 209 offset += 100; 210 } 211 if (flags & 0x0008) { // Quality indicator field is present 212 if (quality_indicator) { 213 if (source->readAt(offset, buffer, 4) < 4) { 214 return false; 215 } 216 *quality_indicator = U32_AT(buffer); 217 } 218 } 219 return true; 220} 221 222} // namespace android 223 224