XINGSeeker.cpp revision 5102400104ce1f0a6de7bf913381a91e4f18a22a
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 unsigned char *table_of_contents = NULL, bool *toc_is_valid = NULL, 28 int32_t *quality_indicator = NULL, 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->mTOC, &seeker->mTOCValid, 40 NULL, &seeker->mDurationUs)) { 41 return NULL; 42 } 43 44 return seeker; 45} 46 47XINGSeeker::XINGSeeker() 48 : mDurationUs(-1), 49 mSizeBytes(0) { 50} 51 52bool XINGSeeker::getDuration(int64_t *durationUs) { 53 if (mDurationUs < 0) { 54 return false; 55 } 56 57 *durationUs = mDurationUs; 58 59 return true; 60} 61 62bool XINGSeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) { 63 if (mSizeBytes == 0 || !mTOCValid || mDurationUs < 0) { 64 return false; 65 } 66 67 float percent = (float)(*timeUs) * 100 / mDurationUs; 68 float fx; 69 if( percent <= 0.0f ) { 70 fx = 0.0f; 71 } else if( percent >= 100.0f ) { 72 fx = 256.0f; 73 } else { 74 int a = (int)percent; 75 float fa, fb; 76 if ( a == 0 ) { 77 fa = 0.0f; 78 } else { 79 fa = (float)mTOC[a-1]; 80 } 81 if ( a < 99 ) { 82 fb = (float)mTOC[a]; 83 } else { 84 fb = 256.0f; 85 } 86 fx = fa + (fb-fa)*(percent-a); 87 } 88 89 *pos = (int)((1.0f/256.0f)*fx*mSizeBytes) + mFirstFramePos; 90 91 return true; 92} 93 94static bool parse_xing_header( 95 const sp<DataSource> &source, off64_t first_frame_pos, 96 int32_t *frame_number, int32_t *byte_number, 97 unsigned char *table_of_contents, bool *toc_valid, 98 int32_t *quality_indicator, 99 int64_t *duration) { 100 if (frame_number) { 101 *frame_number = 0; 102 } 103 if (byte_number) { 104 *byte_number = 0; 105 } 106 if (toc_valid) { 107 *toc_valid = false; 108 } 109 if (quality_indicator) { 110 *quality_indicator = 0; 111 } 112 if (duration) { 113 *duration = 0; 114 } 115 116 uint8_t buffer[4]; 117 int offset = first_frame_pos; 118 if (source->readAt(offset, &buffer, 4) < 4) { // get header 119 return false; 120 } 121 offset += 4; 122 123 uint8_t id, layer, sr_index, mode; 124 layer = (buffer[1] >> 1) & 3; 125 id = (buffer[1] >> 3) & 3; 126 sr_index = (buffer[2] >> 2) & 3; 127 mode = (buffer[3] >> 6) & 3; 128 if (layer == 0) { 129 return false; 130 } 131 if (id == 1) { 132 return false; 133 } 134 if (sr_index == 3) { 135 return false; 136 } 137 // determine offset of XING header 138 if(id&1) { // mpeg1 139 if (mode != 3) offset += 32; 140 else offset += 17; 141 } else { // mpeg2 142 if (mode != 3) offset += 17; 143 else offset += 9; 144 } 145 146 if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID 147 return false; 148 } 149 offset += 4; 150 // Check XING ID 151 if ((buffer[0] != 'X') || (buffer[1] != 'i') 152 || (buffer[2] != 'n') || (buffer[3] != 'g')) { 153 if ((buffer[0] != 'I') || (buffer[1] != 'n') 154 || (buffer[2] != 'f') || (buffer[3] != 'o')) { 155 return false; 156 } 157 } 158 159 if (source->readAt(offset, &buffer, 4) < 4) { // flags 160 return false; 161 } 162 offset += 4; 163 uint32_t flags = U32_AT(buffer); 164 165 if (flags & 0x0001) { // Frames field is present 166 if (source->readAt(offset, buffer, 4) < 4) { 167 return false; 168 } 169 if (frame_number) { 170 *frame_number = U32_AT(buffer); 171 } 172 int32_t frame = U32_AT(buffer); 173 // Samples per Frame: 1. index = MPEG Version ID, 2. index = Layer 174 const int samplesPerFrames[2][3] = 175 { 176 { 384, 1152, 576 }, // MPEG 2, 2.5: layer1, layer2, layer3 177 { 384, 1152, 1152 }, // MPEG 1: layer1, layer2, layer3 178 }; 179 // sampling rates in hertz: 1. index = MPEG Version ID, 2. index = sampling rate index 180 const int samplingRates[4][3] = 181 { 182 { 11025, 12000, 8000, }, // MPEG 2.5 183 { 0, 0, 0, }, // reserved 184 { 22050, 24000, 16000, }, // MPEG 2 185 { 44100, 48000, 32000, } // MPEG 1 186 }; 187 if (duration) { 188 *duration = (int64_t)frame * samplesPerFrames[id&1][3-layer] * 1000000LL 189 / samplingRates[id][sr_index]; 190 } 191 offset += 4; 192 } 193 if (flags & 0x0002) { // Bytes field is present 194 if (byte_number) { 195 if (source->readAt(offset, buffer, 4) < 4) { 196 return false; 197 } 198 *byte_number = U32_AT(buffer); 199 } 200 offset += 4; 201 } 202 if (flags & 0x0004) { // TOC field is present 203 if (table_of_contents) { 204 if (source->readAt(offset + 1, table_of_contents, 99) < 99) { 205 return false; 206 } 207 if (toc_valid) { 208 *toc_valid = true; 209 } 210 } 211 offset += 100; 212 } 213 if (flags & 0x0008) { // Quality indicator field is present 214 if (quality_indicator) { 215 if (source->readAt(offset, buffer, 4) < 4) { 216 return false; 217 } 218 *quality_indicator = U32_AT(buffer); 219 } 220 } 221 return true; 222} 223 224} // namespace android 225 226