14456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber/* 24456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * Copyright (C) 2010 The Android Open Source Project 34456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * 44456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 54456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * you may not use this file except in compliance with the License. 64456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * You may obtain a copy of the License at 74456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * 84456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 94456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * 104456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * Unless required by applicable law or agreed to in writing, software 114456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 124456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * See the License for the specific language governing permissions and 144456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber * limitations under the License. 154456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber */ 164456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 17b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen#define LOG_TAG "XINGSEEKER" 18b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen#include <utils/Log.h> 19b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen 2075226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen#include "XINGSeeker.h" 21d91dc5a0602f54fc0d4d2187f37b5b8169bb62c3Dongwon Kang#include <media/stagefright/foundation/avc_utils.h> 224456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 23607612858f3afad1ade51a098aafa2a41523b5f7Dongwon Kang#include <media/stagefright/foundation/ByteUtils.h> 242a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen#include <media/DataSourceBase.h> 254456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 264456da54bcd206ed1f518c69cc959ca65a179c83Andreas Hubernamespace android { 274456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 284456da54bcd206ed1f518c69cc959ca65a179c83Andreas HuberXINGSeeker::XINGSeeker() 294456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber : mDurationUs(-1), 30b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen mSizeBytes(0), 31b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen mEncoderDelay(0), 325fd7d3a23316ec0d2320fece85201859b52c2aefMarco Nelissen mEncoderPadding(0), 335fd7d3a23316ec0d2320fece85201859b52c2aefMarco Nelissen mTOCValid(false) { 344456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber} 354456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 364456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huberbool XINGSeeker::getDuration(int64_t *durationUs) { 374456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if (mDurationUs < 0) { 384456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber return false; 394456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 404456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 414456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber *durationUs = mDurationUs; 424456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 434456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber return true; 444456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber} 454456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 46c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongbool XINGSeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) { 475102400104ce1f0a6de7bf913381a91e4f18a22aMarco Nelissen if (mSizeBytes == 0 || !mTOCValid || mDurationUs < 0) { 484456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber return false; 494456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 504456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 514456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber float percent = (float)(*timeUs) * 100 / mDurationUs; 524456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber float fx; 534456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if( percent <= 0.0f ) { 544456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber fx = 0.0f; 554456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } else if( percent >= 100.0f ) { 564456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber fx = 256.0f; 574456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } else { 584456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber int a = (int)percent; 594456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber float fa, fb; 604456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if ( a == 0 ) { 614456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber fa = 0.0f; 624456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } else { 635102400104ce1f0a6de7bf913381a91e4f18a22aMarco Nelissen fa = (float)mTOC[a-1]; 644456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 654456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if ( a < 99 ) { 665102400104ce1f0a6de7bf913381a91e4f18a22aMarco Nelissen fb = (float)mTOC[a]; 674456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } else { 684456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber fb = 256.0f; 694456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 704456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber fx = fa + (fb-fa)*(percent-a); 714456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 724456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 734456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber *pos = (int)((1.0f/256.0f)*fx*mSizeBytes) + mFirstFramePos; 744456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 754456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber return true; 764456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber} 774456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 789e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen// static 793d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco NelissenXINGSeeker *XINGSeeker::CreateFromSource( 802a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen DataSourceBase *source, off64_t first_frame_pos) { 819e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen 824456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber uint8_t buffer[4]; 834456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber int offset = first_frame_pos; 844456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if (source->readAt(offset, &buffer, 4) < 4) { // get header 859e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen return NULL; 864456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 874456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber offset += 4; 884456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 899e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen int header = U32_AT(buffer);; 909e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen size_t xingframesize = 0; 919e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen int sampling_rate = 0; 929e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen int num_channels; 939e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen int samples_per_frame = 0; 949e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen if (!GetMPEGAudioFrameSize(header, &xingframesize, &sampling_rate, &num_channels, 959e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen NULL, &samples_per_frame)) { 969e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen return NULL; 974456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 989e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen uint8_t version = (buffer[1] >> 3) & 3; 999e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen 1004456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber // determine offset of XING header 1019e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen if(version & 1) { // mpeg1 1029e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen if (num_channels != 1) offset += 32; 1034456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber else offset += 17; 1049e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen } else { // mpeg 2 or 2.5 1059e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen if (num_channels != 1) offset += 17; 1064456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber else offset += 9; 1074456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1084456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 109b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen int xingbase = offset; 110b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen 1114456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID 1129e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen return NULL; 1134456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1144456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber offset += 4; 1154456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber // Check XING ID 1164456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if ((buffer[0] != 'X') || (buffer[1] != 'i') 1174456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber || (buffer[2] != 'n') || (buffer[3] != 'g')) { 1184456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if ((buffer[0] != 'I') || (buffer[1] != 'n') 1194456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber || (buffer[2] != 'f') || (buffer[3] != 'o')) { 1209e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen return NULL; 1214456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1224456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1234456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 1244456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if (source->readAt(offset, &buffer, 4) < 4) { // flags 1259e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen return NULL; 1264456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1274456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber offset += 4; 1284456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber uint32_t flags = U32_AT(buffer); 1294456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 1303d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen XINGSeeker *seeker = new XINGSeeker; 1313d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen seeker->mFirstFramePos = first_frame_pos + xingframesize; 1323d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen 1334456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if (flags & 0x0001) { // Frames field is present 1344456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if (source->readAt(offset, buffer, 4) < 4) { 1353d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen delete seeker; 1363d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen return NULL; 1374456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1389e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen int32_t frames = U32_AT(buffer); 1395fd7d3a23316ec0d2320fece85201859b52c2aefMarco Nelissen // only update mDurationUs if the calculated duration is valid (non zero) 1405fd7d3a23316ec0d2320fece85201859b52c2aefMarco Nelissen // otherwise, leave duration at -1 so that getDuration() and getOffsetForTime() 1415fd7d3a23316ec0d2320fece85201859b52c2aefMarco Nelissen // return false when called, to indicate that this xing tag does not have the 1425fd7d3a23316ec0d2320fece85201859b52c2aefMarco Nelissen // requested information 1435fd7d3a23316ec0d2320fece85201859b52c2aefMarco Nelissen if (frames) { 1445fd7d3a23316ec0d2320fece85201859b52c2aefMarco Nelissen seeker->mDurationUs = (int64_t)frames * samples_per_frame * 1000000LL / sampling_rate; 1455fd7d3a23316ec0d2320fece85201859b52c2aefMarco Nelissen } 1464456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber offset += 4; 1474456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1484456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if (flags & 0x0002) { // Bytes field is present 1499e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen if (source->readAt(offset, buffer, 4) < 4) { 1503d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen delete seeker; 1519e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen return NULL; 1524456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1539e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen seeker->mSizeBytes = U32_AT(buffer); 1544456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber offset += 4; 1554456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1564456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if (flags & 0x0004) { // TOC field is present 1579e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen if (source->readAt(offset + 1, seeker->mTOC, 99) < 99) { 1583d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen delete seeker; 1599e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen return NULL; 1604456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1619e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen seeker->mTOCValid = true; 1624456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber offset += 100; 1634456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1649e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen 1659e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen#if 0 1664456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber if (flags & 0x0008) { // Quality indicator field is present 1679e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen if (source->readAt(offset, buffer, 4) < 4) { 1683d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen delete seeker; 1699e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen return NULL; 1704456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 1719e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen // do something with the quality indicator 1729e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen offset += 4; 1734456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber } 174b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen 175b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen if (source->readAt(xingbase + 0xaf - 0x24, &buffer, 1) < 1) { // encoding flags 1763d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen delete seeker; 177b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen return false; 178b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen } 179b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen 180b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen ALOGV("nogap preceding: %s, nogap continued in next: %s", 181b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen (buffer[0] & 0x80) ? "true" : "false", 182b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen (buffer[0] & 0x40) ? "true" : "false"); 1839e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen#endif 1849e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen 185b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen if (source->readAt(xingbase + 0xb1 - 0x24, &buffer, 3) == 3) { 186b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen seeker->mEncoderDelay = (buffer[0] << 4) + (buffer[1] >> 4); 187b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen seeker->mEncoderPadding = ((buffer[1] & 0xf) << 8) + buffer[2]; 188b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen } 189b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen 1909e50385f34676d8fcb3b473ec4c9f5c388a4c887Marco Nelissen return seeker; 1914456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber} 1924456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 193b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissenint32_t XINGSeeker::getEncoderDelay() { 194b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen return mEncoderDelay; 195b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen} 196b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen 197b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissenint32_t XINGSeeker::getEncoderPadding() { 198b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen return mEncoderPadding; 199b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen} 200b636abde14f2612ea236257846b9ab15d87d4623Marco Nelissen 2014456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber} // namespace android 2024456da54bcd206ed1f518c69cc959ca65a179c83Andreas Huber 203