AVIExtractor.cpp revision 63749954aa828b3f73b4738659eaea5eaeeca874
1cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber/* 2cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * Copyright (C) 2011 The Android Open Source Project 3cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * 4cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * you may not use this file except in compliance with the License. 6cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * You may obtain a copy of the License at 7cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * 8cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * 10cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * Unless required by applicable law or agreed to in writing, software 11cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * See the License for the specific language governing permissions and 14cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber * limitations under the License. 15cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber */ 16cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 17cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber//#define LOG_NDEBUG 0 18cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#define LOG_TAG "AVIExtractor" 19cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <utils/Log.h> 20cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 21cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include "include/AVIExtractor.h" 22cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 23cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <binder/ProcessState.h> 24cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <media/stagefright/foundation/hexdump.h> 25cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <media/stagefright/foundation/ABuffer.h> 26cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <media/stagefright/foundation/ADebug.h> 27cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <media/stagefright/DataSource.h> 28cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <media/stagefright/MediaBuffer.h> 29cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <media/stagefright/MediaBufferGroup.h> 30cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <media/stagefright/MediaDefs.h> 31cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <media/stagefright/MediaErrors.h> 32cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <media/stagefright/MetaData.h> 33cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber#include <media/stagefright/Utils.h> 34cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 35cabb7da7125a80c55233bd23959327424e9646ccAndreas Hubernamespace android { 36cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 37cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstruct AVIExtractor::AVISource : public MediaSource { 38cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber AVISource(const sp<AVIExtractor> &extractor, size_t trackIndex); 39cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 40cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber virtual status_t start(MetaData *params); 41cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber virtual status_t stop(); 42cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 43cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber virtual sp<MetaData> getFormat(); 44cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 45cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber virtual status_t read( 46cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber MediaBuffer **buffer, const ReadOptions *options); 47cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 48cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberprotected: 49cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber virtual ~AVISource(); 50cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 51cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberprivate: 52cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber sp<AVIExtractor> mExtractor; 53cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t mTrackIndex; 54cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const AVIExtractor::Track &mTrack; 55cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber MediaBufferGroup *mBufferGroup; 56cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t mSampleIndex; 57cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 58cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber DISALLOW_EVIL_CONSTRUCTORS(AVISource); 59cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber}; 60cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 61cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber//////////////////////////////////////////////////////////////////////////////// 62cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 63cabb7da7125a80c55233bd23959327424e9646ccAndreas HuberAVIExtractor::AVISource::AVISource( 64cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const sp<AVIExtractor> &extractor, size_t trackIndex) 65cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber : mExtractor(extractor), 66cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mTrackIndex(trackIndex), 67cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mTrack(mExtractor->mTracks.itemAt(trackIndex)), 68cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mBufferGroup(NULL) { 69cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 70cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 71cabb7da7125a80c55233bd23959327424e9646ccAndreas HuberAVIExtractor::AVISource::~AVISource() { 72cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (mBufferGroup) { 73cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber stop(); 74cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 75cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 76cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 77cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatus_t AVIExtractor::AVISource::start(MetaData *params) { 78cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber CHECK(!mBufferGroup); 79cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 80cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mBufferGroup = new MediaBufferGroup; 81cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 82cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize)); 83cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize)); 84cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mSampleIndex = 0; 85cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 86cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 87cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 88cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 89cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatus_t AVIExtractor::AVISource::stop() { 90cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber CHECK(mBufferGroup); 91cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 92cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber delete mBufferGroup; 93cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mBufferGroup = NULL; 94cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 95cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 96cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 97cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 98cabb7da7125a80c55233bd23959327424e9646ccAndreas Hubersp<MetaData> AVIExtractor::AVISource::getFormat() { 99cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return mTrack.mMeta; 100cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 101cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 102cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatus_t AVIExtractor::AVISource::read( 103cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber MediaBuffer **buffer, const ReadOptions *options) { 104cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber CHECK(mBufferGroup); 105cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 106cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *buffer = NULL; 107cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 108cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber int64_t seekTimeUs; 109cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ReadOptions::SeekMode seekMode; 110cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (options && options->getSeekTo(&seekTimeUs, &seekMode)) { 111cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber status_t err = 112cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mExtractor->getSampleIndexAtTime( 113cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mTrackIndex, seekTimeUs, seekMode, &mSampleIndex); 114cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 115cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (err != OK) { 116cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_END_OF_STREAM; 117cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 118cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 119cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 120cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber off64_t offset; 121cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t size; 122cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber bool isKey; 12363749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber int64_t timeUs; 124cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber status_t err = mExtractor->getSampleInfo( 12563749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs); 126cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 127cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ++mSampleIndex; 128cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 129cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (err != OK) { 130cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_END_OF_STREAM; 131cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 132cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 133cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber MediaBuffer *out; 134cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber CHECK_EQ(mBufferGroup->acquire_buffer(&out), (status_t)OK); 135cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 136cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t n = mExtractor->mDataSource->readAt(offset, out->data(), size); 137cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 138cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (n < (ssize_t)size) { 139cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED; 140cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 141cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 142cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber out->set_range(0, size); 143cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 144cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber out->meta_data()->setInt64(kKeyTime, timeUs); 145cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 146cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (isKey) { 147cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber out->meta_data()->setInt32(kKeyIsSyncFrame, 1); 148cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 149cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 150cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *buffer = out; 151cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 152cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 153cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 154cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 155cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber//////////////////////////////////////////////////////////////////////////////// 156cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 157cabb7da7125a80c55233bd23959327424e9646ccAndreas HuberAVIExtractor::AVIExtractor(const sp<DataSource> &dataSource) 158cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber : mDataSource(dataSource) { 159cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mInitCheck = parseHeaders(); 160cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 161cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (mInitCheck != OK) { 162cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mTracks.clear(); 163cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 164cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 165cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 166cabb7da7125a80c55233bd23959327424e9646ccAndreas HuberAVIExtractor::~AVIExtractor() { 167cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 168cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 169cabb7da7125a80c55233bd23959327424e9646ccAndreas Hubersize_t AVIExtractor::countTracks() { 170cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return mTracks.size(); 171cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 172cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 173cabb7da7125a80c55233bd23959327424e9646ccAndreas Hubersp<MediaSource> AVIExtractor::getTrack(size_t index) { 174cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return index < mTracks.size() ? new AVISource(this, index) : NULL; 175cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 176cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 177cabb7da7125a80c55233bd23959327424e9646ccAndreas Hubersp<MetaData> AVIExtractor::getTrackMetaData( 178cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t index, uint32_t flags) { 179cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return index < mTracks.size() ? mTracks.editItemAt(index).mMeta : NULL; 180cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 181cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 182cabb7da7125a80c55233bd23959327424e9646ccAndreas Hubersp<MetaData> AVIExtractor::getMetaData() { 183cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber sp<MetaData> meta = new MetaData; 184cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 185cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (mInitCheck == OK) { 186cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_AVI); 187cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 188cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 189cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return meta; 190cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 191cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 192cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatus_t AVIExtractor::parseHeaders() { 193cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mTracks.clear(); 194cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mMovieOffset = 0; 195cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mFoundIndex = false; 196cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mOffsetsAreAbsolute = false; 197cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 198cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t res = parseChunk(0ll, -1ll); 199cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 200cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (res < 0) { 201cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return (status_t)res; 202cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 203cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 204cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (mMovieOffset == 0ll || !mFoundIndex) { 205cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 206cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 207cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 208cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 209cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 210cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 211cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberssize_t AVIExtractor::parseChunk(off64_t offset, off64_t size, int depth) { 212cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (size >= 0 && size < 8) { 213cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 214cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 215cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 216cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint8_t tmp[12]; 217cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t n = mDataSource->readAt(offset, tmp, 8); 218cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 219cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (n < 8) { 220cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return (n < 0) ? n : (ssize_t)ERROR_MALFORMED; 221cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 222cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 223cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t fourcc = U32_AT(tmp); 224cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t chunkSize = U32LE_AT(&tmp[4]); 225cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 226cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (size >= 0 && chunkSize + 8 > size) { 227cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 228cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 229cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 230cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber static const char kPrefix[] = " "; 231cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const char *prefix = &kPrefix[strlen(kPrefix) - 2 * depth]; 232cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 233cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (fourcc == FOURCC('L', 'I', 'S', 'T') 234cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber || fourcc == FOURCC('R', 'I', 'F', 'F')) { 235cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // It's a list of chunks 236cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 237cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (size >= 0 && size < 12) { 238cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 239cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 240cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 241cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber n = mDataSource->readAt(offset + 8, &tmp[8], 4); 242cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 243cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (n < 4) { 244cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return (n < 0) ? n : (ssize_t)ERROR_MALFORMED; 245cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 246cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 247cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t subFourcc = U32_AT(&tmp[8]); 248cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 249cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber LOGV("%s offset 0x%08llx LIST of '%c%c%c%c', size %d", 250cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber prefix, 251cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber offset, 252cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber (char)(subFourcc >> 24), 253cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber (char)((subFourcc >> 16) & 0xff), 254cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber (char)((subFourcc >> 8) & 0xff), 255cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber (char)(subFourcc & 0xff), 256cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber chunkSize - 4); 257cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 258cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (subFourcc == FOURCC('m', 'o', 'v', 'i')) { 259cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // We're not going to parse this, but will take note of the 260cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // offset. 261cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 262cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mMovieOffset = offset; 263cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } else { 264cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber off64_t subOffset = offset + 12; 265cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber off64_t subOffsetLimit = subOffset + chunkSize - 4; 266cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber while (subOffset < subOffsetLimit) { 267cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t res = 268cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber parseChunk(subOffset, subOffsetLimit - subOffset, depth + 1); 269cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 270cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (res < 0) { 271cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return res; 272cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 273cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 274cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber subOffset += res; 275cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 276cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 277cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } else { 278cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber LOGV("%s offset 0x%08llx CHUNK '%c%c%c%c'", 279cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber prefix, 280cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber offset, 281cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber (char)(fourcc >> 24), 282cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber (char)((fourcc >> 16) & 0xff), 283cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber (char)((fourcc >> 8) & 0xff), 284cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber (char)(fourcc & 0xff)); 285cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 286cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber status_t err = OK; 287cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 288cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber switch (fourcc) { 289cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('s', 't', 'r', 'h'): 290cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber { 291cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber err = parseStreamHeader(offset + 8, chunkSize); 292cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 293cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 294cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 295cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('s', 't', 'r', 'f'): 296cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber { 297cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber err = parseStreamFormat(offset + 8, chunkSize); 298cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 299cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 300cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 301cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('i', 'd', 'x', '1'): 302cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber { 303cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber err = parseIndex(offset + 8, chunkSize); 304cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 305cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 306cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 307cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber default: 308cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 309cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 310cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 311cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (err != OK) { 312cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return err; 313cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 314cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 315cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 316cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (chunkSize & 1) { 317cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ++chunkSize; 318cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 319cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 320cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return chunkSize + 8; 321cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 322cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 323cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatic const char *GetMIMETypeForHandler(uint32_t handler) { 324cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber switch (handler) { 325cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // Wow... shamelessly copied from 326cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // http://wiki.multimedia.cx/index.php?title=ISO_MPEG-4 327cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 328cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('3', 'I', 'V', '2'): 329cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('3', 'i', 'v', '2'): 330cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('B', 'L', 'Z', '0'): 331cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('D', 'I', 'G', 'I'): 332cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('D', 'I', 'V', '1'): 333cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('d', 'i', 'v', '1'): 334cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('D', 'I', 'V', 'X'): 335cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('d', 'i', 'v', 'x'): 336cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('D', 'X', '5', '0'): 337cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('d', 'x', '5', '0'): 338cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('D', 'X', 'G', 'M'): 339cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('E', 'M', '4', 'A'): 340cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('E', 'P', 'H', 'V'): 341cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('F', 'M', 'P', '4'): 342cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('f', 'm', 'p', '4'): 343cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('F', 'V', 'F', 'W'): 344cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('H', 'D', 'X', '4'): 345cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('h', 'd', 'x', '4'): 346cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('M', '4', 'C', 'C'): 347cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('M', '4', 'S', '2'): 348cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('m', '4', 's', '2'): 349cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('M', 'P', '4', 'S'): 350cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('m', 'p', '4', 's'): 351cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('M', 'P', '4', 'V'): 352cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('m', 'p', '4', 'v'): 353cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('M', 'V', 'X', 'M'): 354cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('R', 'M', 'P', '4'): 355cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('S', 'E', 'D', 'G'): 356cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('S', 'M', 'P', '4'): 357cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('U', 'M', 'P', '4'): 358cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('W', 'V', '1', 'F'): 359cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('X', 'V', 'I', 'D'): 360cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('X', 'v', 'i', 'D'): 361cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('x', 'v', 'i', 'd'): 362cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case FOURCC('X', 'V', 'I', 'X'): 363cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return MEDIA_MIMETYPE_VIDEO_MPEG4; 364cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 365cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber default: 366cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return NULL; 367cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 368cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 369cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 370cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatus_t AVIExtractor::parseStreamHeader(off64_t offset, size_t size) { 371cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (size != 56) { 372cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 373cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 374cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 375cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (mTracks.size() > 99) { 376cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return -ERANGE; 377cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 378cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 379cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber sp<ABuffer> buffer = new ABuffer(size); 380cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); 381cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 382cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (n < (ssize_t)size) { 383cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return n < 0 ? (status_t)n : ERROR_MALFORMED; 384cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 385cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 386cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const uint8_t *data = buffer->data(); 387cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 388cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t type = U32_AT(data); 389cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t handler = U32_AT(&data[4]); 390cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t flags = U32LE_AT(&data[8]); 391cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 392cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber sp<MetaData> meta = new MetaData; 393cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 394cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t rate = U32LE_AT(&data[20]); 395cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t scale = U32LE_AT(&data[24]); 396cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 39763749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber uint32_t sampleSize = U32LE_AT(&data[44]); 39863749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber 399cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const char *mime = NULL; 400cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber Track::Kind kind = Track::OTHER; 401cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 402cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (type == FOURCC('v', 'i', 'd', 's')) { 403cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mime = GetMIMETypeForHandler(handler); 404cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 405cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (mime && strncasecmp(mime, "video/", 6)) { 406cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 407cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 408cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 409cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber kind = Track::VIDEO; 410cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } else if (type == FOURCC('a', 'u', 'd', 's')) { 411cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (mime && strncasecmp(mime, "audio/", 6)) { 412cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 413cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 414cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 415cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber kind = Track::AUDIO; 416cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 417cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 418cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (!mime) { 419cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mime = "application/octet-stream"; 420cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 421cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 422cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber meta->setCString(kKeyMIMEType, mime); 423cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 424cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mTracks.push(); 425cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber Track *track = &mTracks.editItemAt(mTracks.size() - 1); 426cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 427cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMeta = meta; 428cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mRate = rate; 429cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mScale = scale; 43063749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber track->mBytesPerSample = sampleSize; 431cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mKind = kind; 432cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mNumSyncSamples = 0; 433cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mThumbnailSampleSize = 0; 434cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mThumbnailSampleIndex = -1; 435cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMaxSampleSize = 0; 436cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 437cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 438cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 439cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 440cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatus_t AVIExtractor::parseStreamFormat(off64_t offset, size_t size) { 441cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (mTracks.isEmpty()) { 442cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 443cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 444cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 445cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber Track *track = &mTracks.editItemAt(mTracks.size() - 1); 446cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 447cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (track->mKind == Track::OTHER) { 448cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // We don't support this content, but that's not a parsing error. 449cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 450cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 451cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 452cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber bool isVideo = (track->mKind == Track::VIDEO); 453cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 454cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if ((isVideo && size < 40) || (!isVideo && size < 18)) { 455cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // Expected a BITMAPINFO or WAVEFORMATEX structure, respectively. 456cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 457cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 458cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 459cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber sp<ABuffer> buffer = new ABuffer(size); 460cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); 461cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 462cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (n < (ssize_t)size) { 463cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return n < 0 ? (status_t)n : ERROR_MALFORMED; 464cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 465cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 466cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const uint8_t *data = buffer->data(); 467cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 468cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (isVideo) { 469cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t width = U32LE_AT(&data[4]); 470cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t height = U32LE_AT(&data[8]); 471cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 472cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMeta->setInt32(kKeyWidth, width); 473cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMeta->setInt32(kKeyHeight, height); 474cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } else { 475cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t format = U16LE_AT(data); 476cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (format == 0x55) { 477cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); 478cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 479cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 480cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t numChannels = U16LE_AT(&data[2]); 481cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t sampleRate = U32LE_AT(&data[4]); 482cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 483cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMeta->setInt32(kKeyChannelCount, numChannels); 484cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMeta->setInt32(kKeySampleRate, sampleRate); 485cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 486cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 487cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 488cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 489cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 490cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber// static 491cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberbool AVIExtractor::IsCorrectChunkType( 492cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t trackIndex, Track::Kind kind, uint32_t chunkType) { 493cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t chunkBase = chunkType & 0xffff; 494cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 495cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber switch (kind) { 496cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case Track::VIDEO: 497cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber { 498cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (chunkBase != FOURCC(0, 0, 'd', 'c') 499cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber && chunkBase != FOURCC(0, 0, 'd', 'b')) { 500cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return false; 501cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 502cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 503cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 504cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 505cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case Track::AUDIO: 506cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber { 507cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (chunkBase != FOURCC(0, 0, 'w', 'b')) { 508cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return false; 509cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 510cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 511cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 512cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 513cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber default: 514cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 515cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 516cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 517cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (trackIndex < 0) { 518cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return true; 519cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 520cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 521cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint8_t hi = chunkType >> 24; 522cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint8_t lo = (chunkType >> 16) & 0xff; 523cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 524cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (hi < '0' || hi > '9' || lo < '0' || lo > '9') { 525cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return false; 526cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 527cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 528cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (trackIndex != (10 * (hi - '0') + (lo - '0'))) { 529cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return false; 530cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 531cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 532cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return true; 533cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 534cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 535cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatus_t AVIExtractor::parseIndex(off64_t offset, size_t size) { 536cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if ((size % 16) != 0) { 537cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 538cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 539cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 540cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber sp<ABuffer> buffer = new ABuffer(size); 541cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); 542cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 543cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (n < (ssize_t)size) { 544cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return n < 0 ? (status_t)n : ERROR_MALFORMED; 545cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 546cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 547cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const uint8_t *data = buffer->data(); 548cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 549cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber while (size > 0) { 550cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t chunkType = U32_AT(data); 551cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 552cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint8_t hi = chunkType >> 24; 553cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint8_t lo = (chunkType >> 16) & 0xff; 554cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 555cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (hi < '0' || hi > '9' || lo < '0' || lo > '9') { 556cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 557cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 558cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 559cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t trackIndex = 10 * (hi - '0') + (lo - '0'); 560cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 561cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (trackIndex >= mTracks.size()) { 562cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 563cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 564cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 565cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber Track *track = &mTracks.editItemAt(trackIndex); 566cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 567cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (!IsCorrectChunkType(-1, track->mKind, chunkType)) { 568cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 569cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 570cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 571cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (track->mKind == Track::OTHER) { 572cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber data += 16; 573cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size -= 16; 574cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber continue; 575cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 576cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 577cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t flags = U32LE_AT(&data[4]); 578cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t offset = U32LE_AT(&data[8]); 579cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t chunkSize = U32LE_AT(&data[12]); 580cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 581cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (chunkSize > track->mMaxSampleSize) { 582cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMaxSampleSize = chunkSize; 583cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 584cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 585cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mSamples.push(); 586cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 587cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber SampleInfo *info = 588cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber &track->mSamples.editItemAt(track->mSamples.size() - 1); 589cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 590cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber info->mOffset = offset; 591cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber info->mIsKey = (flags & 0x10) != 0; 592cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 593cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (info->mIsKey) { 594cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber static const size_t kMaxNumSyncSamplesToScan = 20; 595cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 596cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (track->mNumSyncSamples < kMaxNumSyncSamplesToScan) { 597cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (chunkSize > track->mThumbnailSampleSize) { 598cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mThumbnailSampleSize = chunkSize; 599cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 600cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mThumbnailSampleIndex = 601cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mSamples.size() - 1; 602cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 603cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 604cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 605cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ++track->mNumSyncSamples; 606cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 607cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 608cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber data += 16; 609cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size -= 16; 610cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 611cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 612cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (!mTracks.isEmpty()) { 613cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber off64_t offset; 614cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t size; 615cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber bool isKey; 61663749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber int64_t timeUs; 61763749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs); 618cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 619cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (err != OK) { 620cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mOffsetsAreAbsolute = !mOffsetsAreAbsolute; 62163749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs); 622cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 623cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (err != OK) { 624cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return err; 625cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 626cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 627cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 628cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber LOGV("Chunk offsets are %s", 629cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mOffsetsAreAbsolute ? "absolute" : "movie-chunk relative"); 630cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 631cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 632cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber for (size_t i = 0; i < mTracks.size(); ++i) { 633cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber Track *track = &mTracks.editItemAt(i); 634cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 63563749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber int64_t durationUs; 63663749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber CHECK_EQ((status_t)OK, 63763749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber getSampleTime(i, track->mSamples.size() - 1, &durationUs)); 638cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 639cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber LOGV("track %d duration = %.2f secs", i, durationUs / 1E6); 640cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 641cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMeta->setInt64(kKeyDuration, durationUs); 642cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMeta->setInt32(kKeyMaxInputSize, track->mMaxSampleSize); 643cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 644cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const char *tmp; 645cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber CHECK(track->mMeta->findCString(kKeyMIMEType, &tmp)); 646cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 647cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber AString mime = tmp; 648cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 649cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (!strncasecmp("video/", mime.c_str(), 6) 650cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber && track->mThumbnailSampleIndex >= 0) { 65163749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber int64_t thumbnailTimeUs; 65263749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber CHECK_EQ((status_t)OK, 65363749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber getSampleTime(i, track->mThumbnailSampleIndex, 65463749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber &thumbnailTimeUs)); 655cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 656cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs); 657cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 658cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) { 659cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber status_t err = addMPEG4CodecSpecificData(i); 660cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 661cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (err != OK) { 662cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return err; 663cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 664cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 665cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 66663749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber 66763749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber if (track->mBytesPerSample != 0) { 66863749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber // Assume all chunks are the same size for now. 66963749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber 67063749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber off64_t offset; 67163749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber size_t size; 67263749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber bool isKey; 67363749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber int64_t sampleTimeUs; 67463749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber CHECK_EQ((status_t)OK, 67563749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber getSampleInfo( 67663749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber i, 0, 67763749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber &offset, &size, &isKey, &sampleTimeUs)); 67863749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber 67963749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber track->mRate *= size / track->mBytesPerSample; 68063749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber } 681cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 682cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 683cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mFoundIndex = true; 684cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 685cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 686cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 687cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 688cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatic size_t GetSizeWidth(size_t x) { 689cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t n = 1; 690cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber while (x > 127) { 691cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ++n; 692cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber x >>= 7; 693cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 694cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return n; 695cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 696cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 697cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatic uint8_t *EncodeSize(uint8_t *dst, size_t x) { 698cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber while (x > 127) { 699cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *dst++ = (x & 0x7f) | 0x80; 700cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber x >>= 7; 701cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 702cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *dst++ = x; 703cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return dst; 704cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 705cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 706cabb7da7125a80c55233bd23959327424e9646ccAndreas Hubersp<ABuffer> MakeMPEG4VideoCodecSpecificData(const sp<ABuffer> &config) { 707cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t len1 = config->size() + GetSizeWidth(config->size()) + 1; 708cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13; 709cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3; 710cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 711cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber sp<ABuffer> csd = new ABuffer(len3); 712cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint8_t *dst = csd->data(); 713cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *dst++ = 0x03; 714cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber dst = EncodeSize(dst, len2 + 3); 715cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *dst++ = 0x00; // ES_ID 716cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *dst++ = 0x00; 717cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag 718cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 719cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *dst++ = 0x04; 720cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber dst = EncodeSize(dst, len1 + 13); 721cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile 722cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber for (size_t i = 0; i < 12; ++i) { 723cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *dst++ = 0x00; 724cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 725cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 726cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *dst++ = 0x05; 727cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber dst = EncodeSize(dst, config->size()); 728cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber memcpy(dst, config->data(), config->size()); 729cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber dst += config->size(); 730cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 731cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // hexdump(csd->data(), csd->size()); 732cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 733cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return csd; 734cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 735cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 736cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatus_t AVIExtractor::addMPEG4CodecSpecificData(size_t trackIndex) { 737cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber Track *track = &mTracks.editItemAt(trackIndex); 738cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 739cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber off64_t offset; 740cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t size; 741cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber bool isKey; 74263749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber int64_t timeUs; 74363749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber status_t err = 74463749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs); 745cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 746cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (err != OK) { 747cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return err; 748cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 749cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 750cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber sp<ABuffer> buffer = new ABuffer(size); 751cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size()); 752cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 753cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (n < (ssize_t)size) { 754cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return n < 0 ? (status_t)n : ERROR_MALFORMED; 755cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 756cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 757cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // Extract everything up to the first VOP start code from the first 758cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // frame's encoded data and use it to construct an ESDS with the 759cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber // codec specific data. 760cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 761cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t i = 0; 762cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber bool found = false; 763cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber while (i + 3 < buffer->size()) { 764cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (!memcmp("\x00\x00\x01\xb6", &buffer->data()[i], 4)) { 765cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber found = true; 766cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 767cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 768cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 769cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ++i; 770cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 771cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 772cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (!found) { 773cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 774cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 775cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 776cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber buffer->setRange(0, i); 777cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 778cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber sp<ABuffer> csd = MakeMPEG4VideoCodecSpecificData(buffer); 779cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track->mMeta->setData(kKeyESDS, kTypeESDS, csd->data(), csd->size()); 780cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 781cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 782cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 783cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 784cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatus_t AVIExtractor::getSampleInfo( 785cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t trackIndex, size_t sampleIndex, 78663749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber off64_t *offset, size_t *size, bool *isKey, 78763749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber int64_t *sampleTimeUs) { 788cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (trackIndex >= mTracks.size()) { 789cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return -ERANGE; 790cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 791cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 792cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const Track &track = mTracks.itemAt(trackIndex); 793cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 794cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (sampleIndex >= track.mSamples.size()) { 795cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return -ERANGE; 796cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 797cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 798cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const SampleInfo &info = track.mSamples.itemAt(sampleIndex); 799cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 800cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (!mOffsetsAreAbsolute) { 801cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *offset = info.mOffset + mMovieOffset + 8; 802cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } else { 803cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *offset = info.mOffset; 804cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 805cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 806cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *size = 0; 807cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 808cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint8_t tmp[8]; 809cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t n = mDataSource->readAt(*offset, tmp, 8); 810cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 811cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (n < 8) { 812cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED; 813cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 814cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 815cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber uint32_t chunkType = U32_AT(tmp); 816cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 817cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (!IsCorrectChunkType(trackIndex, track.mKind, chunkType)) { 818cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return ERROR_MALFORMED; 819cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 820cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 821cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *offset += 8; 822cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *size = U32LE_AT(&tmp[4]); 823cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 824cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *isKey = info.mIsKey; 825cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 82663749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale; 82763749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber 828cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 829cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 830cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 83163749954aa828b3f73b4738659eaea5eaeeca874Andreas Huberstatus_t AVIExtractor::getSampleTime( 83263749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) { 83363749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber off64_t offset; 83463749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber size_t size; 83563749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber bool isKey; 83663749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber return getSampleInfo( 83763749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs); 83863749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber} 83963749954aa828b3f73b4738659eaea5eaeeca874Andreas Huber 840cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberstatus_t AVIExtractor::getSampleIndexAtTime( 841cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t trackIndex, 842cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber int64_t timeUs, MediaSource::ReadOptions::SeekMode mode, 843cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t *sampleIndex) const { 844cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (trackIndex >= mTracks.size()) { 845cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return -ERANGE; 846cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 847cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 848cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const Track &track = mTracks.itemAt(trackIndex); 849cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 850cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t closestSampleIndex = 851cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber timeUs / track.mRate * track.mScale / 1000000ll; 852cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 853cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t numSamples = track.mSamples.size(); 854cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 855cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (closestSampleIndex < 0) { 856cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber closestSampleIndex = 0; 857cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } else if (closestSampleIndex >= numSamples) { 858cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber closestSampleIndex = numSamples - 1; 859cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 860cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 861cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (mode == MediaSource::ReadOptions::SEEK_CLOSEST) { 862cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *sampleIndex = closestSampleIndex; 863cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 864cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 865cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 866cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 867cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t prevSyncSampleIndex = closestSampleIndex; 868cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber while (prevSyncSampleIndex >= 0) { 869cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const SampleInfo &info = 870cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track.mSamples.itemAt(prevSyncSampleIndex); 871cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 872cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (info.mIsKey) { 873cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 874cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 875cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 876cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber --prevSyncSampleIndex; 877cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 878cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 879cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ssize_t nextSyncSampleIndex = closestSampleIndex; 880cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber while (nextSyncSampleIndex < numSamples) { 881cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const SampleInfo &info = 882cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber track.mSamples.itemAt(nextSyncSampleIndex); 883cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 884cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (info.mIsKey) { 885cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 886cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 887cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 888cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber ++nextSyncSampleIndex; 889cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 890cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 891cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber switch (mode) { 892cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC: 893cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber { 894cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *sampleIndex = prevSyncSampleIndex; 895cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 896cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return prevSyncSampleIndex >= 0 ? OK : UNKNOWN_ERROR; 897cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 898cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 899cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case MediaSource::ReadOptions::SEEK_NEXT_SYNC: 900cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber { 901cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *sampleIndex = nextSyncSampleIndex; 902cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 903cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return nextSyncSampleIndex < numSamples ? OK : UNKNOWN_ERROR; 904cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 905cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 906cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC: 907cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber { 908cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (prevSyncSampleIndex < 0 && nextSyncSampleIndex >= numSamples) { 909cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return UNKNOWN_ERROR; 910cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 911cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 912cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (prevSyncSampleIndex < 0) { 913cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *sampleIndex = nextSyncSampleIndex; 914cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 915cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 916cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 917cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (nextSyncSampleIndex >= numSamples) { 918cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *sampleIndex = prevSyncSampleIndex; 919cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 920cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 921cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 922cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t dist1 = closestSampleIndex - prevSyncSampleIndex; 923cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber size_t dist2 = nextSyncSampleIndex - closestSampleIndex; 924cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 925cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber *sampleIndex = 926cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber (dist1 < dist2) ? prevSyncSampleIndex : nextSyncSampleIndex; 927cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 928cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return OK; 929cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 930cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 931cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber default: 932cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber TRESPASS(); 933cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber break; 934cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 935cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 936cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 937cabb7da7125a80c55233bd23959327424e9646ccAndreas Huberbool SniffAVI( 938cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber const sp<DataSource> &source, String8 *mimeType, float *confidence, 939cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber sp<AMessage> *) { 940cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber char tmp[12]; 941cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (source->readAt(0, tmp, 12) < 12) { 942cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return false; 943cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 944cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 945cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) { 946cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI); 947f8c84b343488c29cc6ef224a7df751c94955e029Andreas Huber 948f8c84b343488c29cc6ef224a7df751c94955e029Andreas Huber // Just a tad over the mp3 extractor's confidence, since 949f8c84b343488c29cc6ef224a7df751c94955e029Andreas Huber // these .avi files may contain .mp3 content that otherwise would 950f8c84b343488c29cc6ef224a7df751c94955e029Andreas Huber // mistakenly lead to us identifying the entire file as a .mp3 file. 951f8c84b343488c29cc6ef224a7df751c94955e029Andreas Huber *confidence = 0.21; 952cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 953cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return true; 954cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber } 955cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 956cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber return false; 957cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} 958cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber 959cabb7da7125a80c55233bd23959327424e9646ccAndreas Huber} // namespace android 960