XINGSeeker.cpp revision b636abde14f2612ea236257846b9ab15d87d4623
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#define LOG_TAG "XINGSEEKER" 18#include <utils/Log.h> 19 20#include "include/XINGSeeker.h" 21#include "include/avc_utils.h" 22 23#include <media/stagefright/DataSource.h> 24#include <media/stagefright/Utils.h> 25 26namespace android { 27 28XINGSeeker::XINGSeeker() 29 : mDurationUs(-1), 30 mSizeBytes(0), 31 mEncoderDelay(0), 32 mEncoderPadding(0) { 33} 34 35bool XINGSeeker::getDuration(int64_t *durationUs) { 36 if (mDurationUs < 0) { 37 return false; 38 } 39 40 *durationUs = mDurationUs; 41 42 return true; 43} 44 45bool XINGSeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) { 46 if (mSizeBytes == 0 || !mTOCValid || mDurationUs < 0) { 47 return false; 48 } 49 50 float percent = (float)(*timeUs) * 100 / mDurationUs; 51 float fx; 52 if( percent <= 0.0f ) { 53 fx = 0.0f; 54 } else if( percent >= 100.0f ) { 55 fx = 256.0f; 56 } else { 57 int a = (int)percent; 58 float fa, fb; 59 if ( a == 0 ) { 60 fa = 0.0f; 61 } else { 62 fa = (float)mTOC[a-1]; 63 } 64 if ( a < 99 ) { 65 fb = (float)mTOC[a]; 66 } else { 67 fb = 256.0f; 68 } 69 fx = fa + (fb-fa)*(percent-a); 70 } 71 72 *pos = (int)((1.0f/256.0f)*fx*mSizeBytes) + mFirstFramePos; 73 74 return true; 75} 76 77// static 78sp<XINGSeeker> XINGSeeker::CreateFromSource( 79 const sp<DataSource> &source, off64_t first_frame_pos) { 80 sp<XINGSeeker> seeker = new XINGSeeker; 81 82 seeker->mFirstFramePos = first_frame_pos; 83 84 seeker->mSizeBytes = 0; 85 seeker->mTOCValid = false; 86 seeker->mDurationUs = 0; 87 88 uint8_t buffer[4]; 89 int offset = first_frame_pos; 90 if (source->readAt(offset, &buffer, 4) < 4) { // get header 91 return NULL; 92 } 93 offset += 4; 94 95 int header = U32_AT(buffer);; 96 size_t xingframesize = 0; 97 int sampling_rate = 0; 98 int num_channels; 99 int samples_per_frame = 0; 100 if (!GetMPEGAudioFrameSize(header, &xingframesize, &sampling_rate, &num_channels, 101 NULL, &samples_per_frame)) { 102 return NULL; 103 } 104 seeker->mFirstFramePos += xingframesize; 105 106 uint8_t version = (buffer[1] >> 3) & 3; 107 108 // determine offset of XING header 109 if(version & 1) { // mpeg1 110 if (num_channels != 1) offset += 32; 111 else offset += 17; 112 } else { // mpeg 2 or 2.5 113 if (num_channels != 1) offset += 17; 114 else offset += 9; 115 } 116 117 int xingbase = offset; 118 119 if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID 120 return NULL; 121 } 122 offset += 4; 123 // Check XING ID 124 if ((buffer[0] != 'X') || (buffer[1] != 'i') 125 || (buffer[2] != 'n') || (buffer[3] != 'g')) { 126 if ((buffer[0] != 'I') || (buffer[1] != 'n') 127 || (buffer[2] != 'f') || (buffer[3] != 'o')) { 128 return NULL; 129 } 130 } 131 132 if (source->readAt(offset, &buffer, 4) < 4) { // flags 133 return NULL; 134 } 135 offset += 4; 136 uint32_t flags = U32_AT(buffer); 137 138 if (flags & 0x0001) { // Frames field is present 139 if (source->readAt(offset, buffer, 4) < 4) { 140 return NULL; 141 } 142 int32_t frames = U32_AT(buffer); 143 seeker->mDurationUs = (int64_t)frames * samples_per_frame * 1000000LL / sampling_rate; 144 offset += 4; 145 } 146 if (flags & 0x0002) { // Bytes field is present 147 if (source->readAt(offset, buffer, 4) < 4) { 148 return NULL; 149 } 150 seeker->mSizeBytes = U32_AT(buffer); 151 offset += 4; 152 } 153 if (flags & 0x0004) { // TOC field is present 154 if (source->readAt(offset + 1, seeker->mTOC, 99) < 99) { 155 return NULL; 156 } 157 seeker->mTOCValid = true; 158 offset += 100; 159 } 160 161#if 0 162 if (flags & 0x0008) { // Quality indicator field is present 163 if (source->readAt(offset, buffer, 4) < 4) { 164 return NULL; 165 } 166 // do something with the quality indicator 167 offset += 4; 168 } 169 170 if (source->readAt(xingbase + 0xaf - 0x24, &buffer, 1) < 1) { // encoding flags 171 return false; 172 } 173 174 ALOGV("nogap preceding: %s, nogap continued in next: %s", 175 (buffer[0] & 0x80) ? "true" : "false", 176 (buffer[0] & 0x40) ? "true" : "false"); 177#endif 178 179 if (source->readAt(xingbase + 0xb1 - 0x24, &buffer, 3) == 3) { 180 seeker->mEncoderDelay = (buffer[0] << 4) + (buffer[1] >> 4); 181 seeker->mEncoderPadding = ((buffer[1] & 0xf) << 8) + buffer[2]; 182 } 183 184 return seeker; 185} 186 187int32_t XINGSeeker::getEncoderDelay() { 188 return mEncoderDelay; 189} 190 191int32_t XINGSeeker::getEncoderPadding() { 192 return mEncoderPadding; 193} 194 195} // namespace android 196 197