MPEG2TSExtractor.cpp revision 5d7c3eef1985ff15a56920c548cc4e41d6c9627a
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#include "include/NuCachedSource2.h" 23 24#include <media/stagefright/foundation/ADebug.h> 25#include <media/stagefright/DataSource.h> 26#include <media/stagefright/MediaDefs.h> 27#include <media/stagefright/MediaErrors.h> 28#include <media/stagefright/MediaSource.h> 29#include <media/stagefright/MetaData.h> 30#include <utils/String8.h> 31 32#include "AnotherPacketSource.h" 33#include "ATSParser.h" 34 35namespace android { 36 37static const size_t kTSPacketSize = 188; 38 39struct MPEG2TSSource : public MediaSource { 40 MPEG2TSSource( 41 const sp<MPEG2TSExtractor> &extractor, 42 const sp<AnotherPacketSource> &impl, 43 bool seekable); 44 45 virtual status_t start(MetaData *params = NULL); 46 virtual status_t stop(); 47 virtual sp<MetaData> getFormat(); 48 49 virtual status_t read( 50 MediaBuffer **buffer, const ReadOptions *options = NULL); 51 52private: 53 sp<MPEG2TSExtractor> mExtractor; 54 sp<AnotherPacketSource> mImpl; 55 56 // If there are both audio and video streams, only the video stream 57 // will be seekable, otherwise the single stream will be seekable. 58 bool mSeekable; 59 60 DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource); 61}; 62 63MPEG2TSSource::MPEG2TSSource( 64 const sp<MPEG2TSExtractor> &extractor, 65 const sp<AnotherPacketSource> &impl, 66 bool seekable) 67 : mExtractor(extractor), 68 mImpl(impl), 69 mSeekable(seekable) { 70} 71 72status_t MPEG2TSSource::start(MetaData *params) { 73 return mImpl->start(params); 74} 75 76status_t MPEG2TSSource::stop() { 77 return mImpl->stop(); 78} 79 80sp<MetaData> MPEG2TSSource::getFormat() { 81 return mImpl->getFormat(); 82} 83 84status_t MPEG2TSSource::read( 85 MediaBuffer **out, const ReadOptions *options) { 86 *out = NULL; 87 88 status_t finalResult; 89 while (!mImpl->hasBufferAvailable(&finalResult)) { 90 if (finalResult != OK) { 91 return ERROR_END_OF_STREAM; 92 } 93 94 status_t err = mExtractor->feedMore(); 95 if (err != OK) { 96 mImpl->signalEOS(err); 97 } 98 } 99 100 int64_t seekTimeUs; 101 ReadOptions::SeekMode seekMode; 102 if (mSeekable && options && options->getSeekTo(&seekTimeUs, &seekMode)) { 103 // A seek was requested, but we don't actually support seeking and so can only "seek" to 104 // the current position 105 int64_t nextBufTimeUs; 106 if (mImpl->nextBufferTime(&nextBufTimeUs) != OK || seekTimeUs != nextBufTimeUs) { 107 return ERROR_UNSUPPORTED; 108 } 109 } 110 111 return mImpl->read(out, options); 112} 113 114//////////////////////////////////////////////////////////////////////////////// 115 116MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source) 117 : mDataSource(source), 118 mParser(new ATSParser), 119 mOffset(0) { 120 init(); 121} 122 123size_t MPEG2TSExtractor::countTracks() { 124 return mSourceImpls.size(); 125} 126 127sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) { 128 if (index >= mSourceImpls.size()) { 129 return NULL; 130 } 131 132 bool seekable = true; 133 if (mSourceImpls.size() > 1) { 134 CHECK_EQ(mSourceImpls.size(), 2u); 135 136 sp<MetaData> meta = mSourceImpls.editItemAt(index)->getFormat(); 137 const char *mime; 138 CHECK(meta->findCString(kKeyMIMEType, &mime)); 139 140 if (!strncasecmp("audio/", mime, 6)) { 141 seekable = false; 142 } 143 } 144 145 return new MPEG2TSSource(this, mSourceImpls.editItemAt(index), seekable); 146} 147 148sp<MetaData> MPEG2TSExtractor::getTrackMetaData( 149 size_t index, uint32_t /* flags */) { 150 return index < mSourceImpls.size() 151 ? mSourceImpls.editItemAt(index)->getFormat() : NULL; 152} 153 154sp<MetaData> MPEG2TSExtractor::getMetaData() { 155 sp<MetaData> meta = new MetaData; 156 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 157 158 return meta; 159} 160 161void MPEG2TSExtractor::init() { 162 bool haveAudio = false; 163 bool haveVideo = false; 164 int numPacketsParsed = 0; 165 166 while (feedMore() == OK) { 167 if (haveAudio && haveVideo) { 168 break; 169 } 170 if (!haveVideo) { 171 sp<AnotherPacketSource> impl = 172 (AnotherPacketSource *)mParser->getSource( 173 ATSParser::VIDEO).get(); 174 175 if (impl != NULL) { 176 haveVideo = true; 177 mSourceImpls.push(impl); 178 } 179 } 180 181 if (!haveAudio) { 182 sp<AnotherPacketSource> impl = 183 (AnotherPacketSource *)mParser->getSource( 184 ATSParser::AUDIO).get(); 185 186 if (impl != NULL) { 187 haveAudio = true; 188 mSourceImpls.push(impl); 189 } 190 } 191 192 if (++numPacketsParsed > 10000) { 193 break; 194 } 195 } 196 197 ALOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo); 198} 199 200status_t MPEG2TSExtractor::feedMore() { 201 Mutex::Autolock autoLock(mLock); 202 203 uint8_t packet[kTSPacketSize]; 204 ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize); 205 206 if (n < (ssize_t)kTSPacketSize) { 207 return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM; 208 } 209 210 mOffset += n; 211 return mParser->feedTSPacket(packet, kTSPacketSize); 212} 213 214uint32_t MPEG2TSExtractor::flags() const { 215 return CAN_PAUSE; 216} 217 218//////////////////////////////////////////////////////////////////////////////// 219 220bool SniffMPEG2TS( 221 const sp<DataSource> &source, String8 *mimeType, float *confidence, 222 sp<AMessage> *) { 223 for (int i = 0; i < 5; ++i) { 224 char header; 225 if (source->readAt(kTSPacketSize * i, &header, 1) != 1 226 || header != 0x47) { 227 return false; 228 } 229 } 230 231 *confidence = 0.1f; 232 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 233 234 return true; 235} 236 237} // namespace android 238