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/LiveSource.h" 23 #include "include/NuCachedSource2.h" 24 25 #include <media/stagefright/DataSource.h> 26 #include <media/stagefright/MediaDebug.h> 27 #include <media/stagefright/MediaDefs.h> 28 #include <media/stagefright/MediaErrors.h> 29 #include <media/stagefright/MediaSource.h> 30 #include <media/stagefright/MetaData.h> 31 #include <utils/String8.h> 32 33 #include "AnotherPacketSource.h" 34 #include "ATSParser.h" 35 36 namespace android { 37 38 static const size_t kTSPacketSize = 188; 39 40 struct MPEG2TSSource : public MediaSource { 41 MPEG2TSSource( 42 const sp<MPEG2TSExtractor> &extractor, 43 const sp<AnotherPacketSource> &impl, 44 bool seekable); 45 46 virtual status_t start(MetaData *params = NULL); 47 virtual status_t stop(); 48 virtual sp<MetaData> getFormat(); 49 50 virtual status_t read( 51 MediaBuffer **buffer, const ReadOptions *options = NULL); 52 53 private: 54 sp<MPEG2TSExtractor> mExtractor; 55 sp<AnotherPacketSource> mImpl; 56 57 // If there are both audio and video streams, only the video stream 58 // will be seekable, otherwise the single stream will be seekable. 59 bool mSeekable; 60 61 DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource); 62 }; 63 64 MPEG2TSSource::MPEG2TSSource( 65 const sp<MPEG2TSExtractor> &extractor, 66 const sp<AnotherPacketSource> &impl, 67 bool seekable) 68 : mExtractor(extractor), 69 mImpl(impl), 70 mSeekable(seekable) { 71 } 72 73 status_t MPEG2TSSource::start(MetaData *params) { 74 return mImpl->start(params); 75 } 76 77 status_t MPEG2TSSource::stop() { 78 return mImpl->stop(); 79 } 80 81 sp<MetaData> MPEG2TSSource::getFormat() { 82 sp<MetaData> meta = mImpl->getFormat(); 83 84 int64_t durationUs; 85 if (mExtractor->mLiveSource != NULL 86 && mExtractor->mLiveSource->getDuration(&durationUs)) { 87 meta->setInt64(kKeyDuration, durationUs); 88 } 89 90 return meta; 91 } 92 93 status_t MPEG2TSSource::read( 94 MediaBuffer **out, const ReadOptions *options) { 95 *out = NULL; 96 97 int64_t seekTimeUs; 98 ReadOptions::SeekMode seekMode; 99 if (mSeekable && options && options->getSeekTo(&seekTimeUs, &seekMode)) { 100 mExtractor->seekTo(seekTimeUs); 101 } 102 103 status_t finalResult; 104 while (!mImpl->hasBufferAvailable(&finalResult)) { 105 if (finalResult != OK) { 106 return ERROR_END_OF_STREAM; 107 } 108 109 status_t err = mExtractor->feedMore(); 110 if (err != OK) { 111 mImpl->signalEOS(err); 112 } 113 } 114 115 return mImpl->read(out, options); 116 } 117 118 //////////////////////////////////////////////////////////////////////////////// 119 120 MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source) 121 : mDataSource(source), 122 mParser(new ATSParser), 123 mOffset(0) { 124 init(); 125 } 126 127 size_t MPEG2TSExtractor::countTracks() { 128 return mSourceImpls.size(); 129 } 130 131 sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) { 132 if (index >= mSourceImpls.size()) { 133 return NULL; 134 } 135 136 bool seekable = true; 137 if (mSourceImpls.size() > 1) { 138 CHECK_EQ(mSourceImpls.size(), 2u); 139 140 sp<MetaData> meta = mSourceImpls.editItemAt(index)->getFormat(); 141 const char *mime; 142 CHECK(meta->findCString(kKeyMIMEType, &mime)); 143 144 if (!strncasecmp("audio/", mime, 6)) { 145 seekable = false; 146 } 147 } 148 149 return new MPEG2TSSource(this, mSourceImpls.editItemAt(index), seekable); 150 } 151 152 sp<MetaData> MPEG2TSExtractor::getTrackMetaData( 153 size_t index, uint32_t flags) { 154 return index < mSourceImpls.size() 155 ? mSourceImpls.editItemAt(index)->getFormat() : NULL; 156 } 157 158 sp<MetaData> MPEG2TSExtractor::getMetaData() { 159 sp<MetaData> meta = new MetaData; 160 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 161 162 return meta; 163 } 164 165 void MPEG2TSExtractor::init() { 166 bool haveAudio = false; 167 bool haveVideo = false; 168 int numPacketsParsed = 0; 169 170 while (feedMore() == OK) { 171 ATSParser::SourceType type; 172 if (haveAudio && haveVideo) { 173 break; 174 } 175 if (!haveVideo) { 176 sp<AnotherPacketSource> impl = 177 (AnotherPacketSource *)mParser->getSource( 178 ATSParser::AVC_VIDEO).get(); 179 180 if (impl != NULL) { 181 haveVideo = true; 182 mSourceImpls.push(impl); 183 } 184 } 185 186 if (!haveAudio) { 187 sp<AnotherPacketSource> impl = 188 (AnotherPacketSource *)mParser->getSource( 189 ATSParser::MPEG2ADTS_AUDIO).get(); 190 191 if (impl != NULL) { 192 haveAudio = true; 193 mSourceImpls.push(impl); 194 } 195 } 196 197 if (++numPacketsParsed > 2500) { 198 break; 199 } 200 } 201 202 LOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo); 203 } 204 205 static bool isDiscontinuity(const uint8_t *data, ssize_t size) { 206 return size == 188 && data[0] == 0x00; 207 } 208 209 status_t MPEG2TSExtractor::feedMore() { 210 Mutex::Autolock autoLock(mLock); 211 212 uint8_t packet[kTSPacketSize]; 213 ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize); 214 215 if (isDiscontinuity(packet, n)) { 216 LOGI("XXX discontinuity detected"); 217 mParser->signalDiscontinuity(); 218 } else if (n < (ssize_t)kTSPacketSize) { 219 return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM; 220 } else { 221 mParser->feedTSPacket(packet, kTSPacketSize); 222 } 223 224 mOffset += n; 225 226 return OK; 227 } 228 229 void MPEG2TSExtractor::setLiveSource(const sp<LiveSource> &liveSource) { 230 Mutex::Autolock autoLock(mLock); 231 232 mLiveSource = liveSource; 233 } 234 235 void MPEG2TSExtractor::seekTo(int64_t seekTimeUs) { 236 Mutex::Autolock autoLock(mLock); 237 238 if (mLiveSource == NULL) { 239 return; 240 } 241 242 if (mDataSource->flags() & DataSource::kIsCachingDataSource) { 243 static_cast<NuCachedSource2 *>(mDataSource.get())->suspend(); 244 } 245 246 if (mLiveSource->seekTo(seekTimeUs)) { 247 mParser->signalDiscontinuity(true /* isSeek */); 248 mOffset = 0; 249 } 250 251 if (mDataSource->flags() & DataSource::kIsCachingDataSource) { 252 static_cast<NuCachedSource2 *>(mDataSource.get()) 253 ->clearCacheAndResume(); 254 } 255 } 256 257 uint32_t MPEG2TSExtractor::flags() const { 258 Mutex::Autolock autoLock(mLock); 259 260 uint32_t flags = CAN_PAUSE; 261 262 if (mLiveSource != NULL && mLiveSource->isSeekable()) { 263 flags |= CAN_SEEK_FORWARD | CAN_SEEK_BACKWARD | CAN_SEEK; 264 } 265 266 return flags; 267 } 268 269 //////////////////////////////////////////////////////////////////////////////// 270 271 bool SniffMPEG2TS( 272 const sp<DataSource> &source, String8 *mimeType, float *confidence, 273 sp<AMessage> *) { 274 for (int i = 0; i < 5; ++i) { 275 char header; 276 if (source->readAt(kTSPacketSize * i, &header, 1) != 1 277 || header != 0x47) { 278 return false; 279 } 280 } 281 282 *confidence = 0.1f; 283 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 284 285 return true; 286 } 287 288 } // namespace android 289