MPEG2TSExtractor.cpp revision 2a4d22d79e927f2245537921e10fc5fda1c47a29
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_NDEBUG 0 18#define LOG_TAG "MPEG2TSExtractor" 19#include <utils/Log.h> 20 21#include "include/MPEG2TSExtractor.h" 22 23#include <media/stagefright/DataSource.h> 24#include <media/stagefright/MediaDefs.h> 25#include <media/stagefright/MediaErrors.h> 26#include <media/stagefright/MediaSource.h> 27#include <media/stagefright/MetaData.h> 28#include <utils/String8.h> 29 30#include "AnotherPacketSource.h" 31#include "ATSParser.h" 32 33namespace android { 34 35static const size_t kTSPacketSize = 188; 36 37struct MPEG2TSSource : public MediaSource { 38 MPEG2TSSource( 39 const sp<MPEG2TSExtractor> &extractor, 40 const sp<AnotherPacketSource> &impl); 41 42 virtual status_t start(MetaData *params = NULL); 43 virtual status_t stop(); 44 virtual sp<MetaData> getFormat(); 45 46 virtual status_t read( 47 MediaBuffer **buffer, const ReadOptions *options = NULL); 48 49private: 50 sp<MPEG2TSExtractor> mExtractor; 51 sp<AnotherPacketSource> mImpl; 52 53 DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource); 54}; 55 56MPEG2TSSource::MPEG2TSSource( 57 const sp<MPEG2TSExtractor> &extractor, 58 const sp<AnotherPacketSource> &impl) 59 : mExtractor(extractor), 60 mImpl(impl) { 61} 62 63status_t MPEG2TSSource::start(MetaData *params) { 64 return mImpl->start(params); 65} 66 67status_t MPEG2TSSource::stop() { 68 return mImpl->stop(); 69} 70 71sp<MetaData> MPEG2TSSource::getFormat() { 72 return mImpl->getFormat(); 73} 74 75status_t MPEG2TSSource::read( 76 MediaBuffer **out, const ReadOptions *options) { 77 *out = NULL; 78 79 status_t finalResult; 80 while (!mImpl->hasBufferAvailable(&finalResult)) { 81 if (finalResult != OK) { 82 return ERROR_END_OF_STREAM; 83 } 84 85 status_t err = mExtractor->feedMore(); 86 if (err != OK) { 87 mImpl->signalEOS(err); 88 } 89 } 90 91 return mImpl->read(out, options); 92} 93 94//////////////////////////////////////////////////////////////////////////////// 95 96MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source) 97 : mDataSource(source), 98 mParser(new ATSParser), 99 mOffset(0) { 100 init(); 101} 102 103size_t MPEG2TSExtractor::countTracks() { 104 return mSourceImpls.size(); 105} 106 107sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) { 108 if (index >= mSourceImpls.size()) { 109 return NULL; 110 } 111 112 return new MPEG2TSSource(this, mSourceImpls.editItemAt(index)); 113} 114 115sp<MetaData> MPEG2TSExtractor::getTrackMetaData( 116 size_t index, uint32_t flags) { 117 return index < mSourceImpls.size() 118 ? mSourceImpls.editItemAt(index)->getFormat() : NULL; 119} 120 121sp<MetaData> MPEG2TSExtractor::getMetaData() { 122 sp<MetaData> meta = new MetaData; 123 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 124 125 return meta; 126} 127 128void MPEG2TSExtractor::init() { 129 bool haveAudio = false; 130 bool haveVideo = false; 131 int numPacketsParsed = 0; 132 133 while (feedMore() == OK) { 134 ATSParser::SourceType type; 135 if (haveAudio && haveVideo) { 136 break; 137 } 138 if (!haveVideo) { 139 sp<AnotherPacketSource> impl = 140 (AnotherPacketSource *)mParser->getSource( 141 ATSParser::AVC_VIDEO).get(); 142 143 if (impl != NULL) { 144 haveVideo = true; 145 mSourceImpls.push(impl); 146 } 147 } 148 149 if (!haveAudio) { 150 sp<AnotherPacketSource> impl = 151 (AnotherPacketSource *)mParser->getSource( 152 ATSParser::MPEG2ADTS_AUDIO).get(); 153 154 if (impl != NULL) { 155 haveAudio = true; 156 mSourceImpls.push(impl); 157 } 158 } 159 160 if (++numPacketsParsed > 2500) { 161 break; 162 } 163 } 164 165 LOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo); 166} 167 168static bool isDiscontinuity(const uint8_t *data, ssize_t size) { 169 return size == 188 && data[0] == 0x00; 170} 171 172status_t MPEG2TSExtractor::feedMore() { 173 Mutex::Autolock autoLock(mLock); 174 175 uint8_t packet[kTSPacketSize]; 176 ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize); 177 178 if (isDiscontinuity(packet, n)) { 179 LOGI("XXX discontinuity detected"); 180 mParser->signalDiscontinuity(); 181 } else if (n < (ssize_t)kTSPacketSize) { 182 return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM; 183 } else { 184 mParser->feedTSPacket(packet, kTSPacketSize); 185 } 186 187 mOffset += n; 188 189 return OK; 190} 191 192//////////////////////////////////////////////////////////////////////////////// 193 194bool SniffMPEG2TS( 195 const sp<DataSource> &source, String8 *mimeType, float *confidence, 196 sp<AMessage> *) { 197 for (int i = 0; i < 5; ++i) { 198 char header; 199 if (source->readAt(kTSPacketSize * i, &header, 1) != 1 200 || header != 0x47) { 201 return false; 202 } 203 } 204 205 *confidence = 0.1f; 206 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 207 208 return true; 209} 210 211} // namespace android 212