XINGSeeker.cpp revision 6fb40672ac0f0b2f479367fa0ba4e8944df06dad
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, 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->mTableOfContents, 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 || mTableOfContents[0] <= 0 || 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)mTableOfContents[a-1]; 80 } 81 if ( a < 99 ) { 82 fb = (float)mTableOfContents[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, int32_t *quality_indicator, 98 int64_t *duration) { 99 if (frame_number) { 100 *frame_number = 0; 101 } 102 if (byte_number) { 103 *byte_number = 0; 104 } 105 if (table_of_contents) { 106 table_of_contents[0] = 0; 107 } 108 if (quality_indicator) { 109 *quality_indicator = 0; 110 } 111 if (duration) { 112 *duration = 0; 113 } 114 115 uint8_t buffer[4]; 116 int offset = first_frame_pos; 117 if (source->readAt(offset, &buffer, 4) < 4) { // get header 118 return false; 119 } 120 offset += 4; 121 122 uint8_t id, layer, sr_index, mode; 123 layer = (buffer[1] >> 1) & 3; 124 id = (buffer[1] >> 3) & 3; 125 sr_index = (buffer[2] >> 2) & 3; 126 mode = (buffer[3] >> 6) & 3; 127 if (layer == 0) { 128 return false; 129 } 130 if (id == 1) { 131 return false; 132 } 133 if (sr_index == 3) { 134 return false; 135 } 136 // determine offset of XING header 137 if(id&1) { // mpeg1 138 if (mode != 3) offset += 32; 139 else offset += 17; 140 } else { // mpeg2 141 if (mode != 3) offset += 17; 142 else offset += 9; 143 } 144 145 if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID 146 return false; 147 } 148 offset += 4; 149 // Check XING ID 150 if ((buffer[0] != 'X') || (buffer[1] != 'i') 151 || (buffer[2] != 'n') || (buffer[3] != 'g')) { 152 if ((buffer[0] != 'I') || (buffer[1] != 'n') 153 || (buffer[2] != 'f') || (buffer[3] != 'o')) { 154 return false; 155 } 156 } 157 158 if (source->readAt(offset, &buffer, 4) < 4) { // flags 159 return false; 160 } 161 offset += 4; 162 uint32_t flags = U32_AT(buffer); 163 164 if (flags & 0x0001) { // Frames field is present 165 if (source->readAt(offset, buffer, 4) < 4) { 166 return false; 167 } 168 if (frame_number) { 169 *frame_number = U32_AT(buffer); 170 } 171 int32_t frame = U32_AT(buffer); 172 // Samples per Frame: 1. index = MPEG Version ID, 2. index = Layer 173 const int samplesPerFrames[2][3] = 174 { 175 { 384, 1152, 576 }, // MPEG 2, 2.5: layer1, layer2, layer3 176 { 384, 1152, 1152 }, // MPEG 1: layer1, layer2, layer3 177 }; 178 // sampling rates in hertz: 1. index = MPEG Version ID, 2. index = sampling rate index 179 const int samplingRates[4][3] = 180 { 181 { 11025, 12000, 8000, }, // MPEG 2.5 182 { 0, 0, 0, }, // reserved 183 { 22050, 24000, 16000, }, // MPEG 2 184 { 44100, 48000, 32000, } // MPEG 1 185 }; 186 if (duration) { 187 *duration = (int64_t)frame * samplesPerFrames[id&1][3-layer] * 1000000LL 188 / samplingRates[id][sr_index]; 189 } 190 offset += 4; 191 } 192 if (flags & 0x0002) { // Bytes field is present 193 if (byte_number) { 194 if (source->readAt(offset, buffer, 4) < 4) { 195 return false; 196 } 197 *byte_number = U32_AT(buffer); 198 } 199 offset += 4; 200 } 201 if (flags & 0x0004) { // TOC field is present 202 if (table_of_contents) { 203 if (source->readAt(offset + 1, table_of_contents, 99) < 99) { 204 return false; 205 } 206 } 207 offset += 100; 208 } 209 if (flags & 0x0008) { // Quality indicator field is present 210 if (quality_indicator) { 211 if (source->readAt(offset, buffer, 4) < 4) { 212 return false; 213 } 214 *quality_indicator = U32_AT(buffer); 215 } 216 } 217 return true; 218} 219 220} // namespace android 221 222