MPEG2TSExtractor.cpp revision 0075debd2c559904ee8a2a4e4706ed5af0abaeb9
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/ABuffer.h> 25#include <media/stagefright/foundation/ADebug.h> 26#include <media/stagefright/foundation/ALooper.h> 27#include <media/stagefright/DataSource.h> 28#include <media/stagefright/MediaDefs.h> 29#include <media/stagefright/MediaErrors.h> 30#include <media/stagefright/MediaSource.h> 31#include <media/stagefright/MetaData.h> 32#include <media/IStreamSource.h> 33#include <utils/String8.h> 34 35#include "AnotherPacketSource.h" 36#include "ATSParser.h" 37 38namespace android { 39 40static const size_t kTSPacketSize = 188; 41 42struct MPEG2TSSource : public MediaSource { 43 MPEG2TSSource( 44 const sp<MPEG2TSExtractor> &extractor, 45 const sp<AnotherPacketSource> &impl, 46 bool doesSeek); 47 48 virtual status_t start(MetaData *params = NULL); 49 virtual status_t stop(); 50 virtual sp<MetaData> getFormat(); 51 52 virtual status_t read( 53 MediaBuffer **buffer, const ReadOptions *options = NULL); 54 55private: 56 sp<MPEG2TSExtractor> mExtractor; 57 sp<AnotherPacketSource> mImpl; 58 59 // If there are both audio and video streams, only the video stream 60 // will signal seek on the extractor; otherwise the single stream will seek. 61 bool mDoesSeek; 62 63 DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource); 64}; 65 66MPEG2TSSource::MPEG2TSSource( 67 const sp<MPEG2TSExtractor> &extractor, 68 const sp<AnotherPacketSource> &impl, 69 bool doesSeek) 70 : mExtractor(extractor), 71 mImpl(impl), 72 mDoesSeek(doesSeek) { 73} 74 75status_t MPEG2TSSource::start(MetaData *params) { 76 return mImpl->start(params); 77} 78 79status_t MPEG2TSSource::stop() { 80 return mImpl->stop(); 81} 82 83sp<MetaData> MPEG2TSSource::getFormat() { 84 return mImpl->getFormat(); 85} 86 87status_t MPEG2TSSource::read( 88 MediaBuffer **out, const ReadOptions *options) { 89 *out = NULL; 90 91 int64_t seekTimeUs; 92 ReadOptions::SeekMode seekMode; 93 if (mDoesSeek && options && options->getSeekTo(&seekTimeUs, &seekMode)) { 94 // seek is needed 95 status_t err = mExtractor->seek(seekTimeUs, seekMode); 96 if (err != OK) { 97 return err; 98 } 99 } 100 101 if (mExtractor->feedUntilBufferAvailable(mImpl) != OK) { 102 return ERROR_END_OF_STREAM; 103 } 104 105 return mImpl->read(out, options); 106} 107 108//////////////////////////////////////////////////////////////////////////////// 109 110MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source) 111 : mDataSource(source), 112 mParser(new ATSParser), 113 mOffset(0) { 114 init(); 115} 116 117size_t MPEG2TSExtractor::countTracks() { 118 return mSourceImpls.size(); 119} 120 121sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) { 122 if (index >= mSourceImpls.size()) { 123 return NULL; 124 } 125 126 // The seek reference track (video if present; audio otherwise) performs 127 // seek requests, while other tracks ignore requests. 128 return new MPEG2TSSource(this, mSourceImpls.editItemAt(index), 129 (mSeekSyncPoints == &mSyncPoints.editItemAt(index))); 130} 131 132sp<MetaData> MPEG2TSExtractor::getTrackMetaData( 133 size_t index, uint32_t /* flags */) { 134 return index < mSourceImpls.size() 135 ? mSourceImpls.editItemAt(index)->getFormat() : NULL; 136} 137 138sp<MetaData> MPEG2TSExtractor::getMetaData() { 139 sp<MetaData> meta = new MetaData; 140 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 141 142 return meta; 143} 144 145void MPEG2TSExtractor::init() { 146 bool haveAudio = false; 147 bool haveVideo = false; 148 int64_t startTime = ALooper::GetNowUs(); 149 150 while (feedMore() == OK) { 151 if (haveAudio && haveVideo) { 152 break; 153 } 154 if (!haveVideo) { 155 sp<AnotherPacketSource> impl = 156 (AnotherPacketSource *)mParser->getSource( 157 ATSParser::VIDEO).get(); 158 159 if (impl != NULL) { 160 haveVideo = true; 161 mSourceImpls.push(impl); 162 mSyncPoints.push(); 163 mSeekSyncPoints = &mSyncPoints.editTop(); 164 } 165 } 166 167 if (!haveAudio) { 168 sp<AnotherPacketSource> impl = 169 (AnotherPacketSource *)mParser->getSource( 170 ATSParser::AUDIO).get(); 171 172 if (impl != NULL) { 173 haveAudio = true; 174 mSourceImpls.push(impl); 175 mSyncPoints.push(); 176 if (!haveVideo) { 177 mSeekSyncPoints = &mSyncPoints.editTop(); 178 } 179 } 180 } 181 182 // Wait only for 2 seconds to detect audio/video streams. 183 if (ALooper::GetNowUs() - startTime > 2000000ll) { 184 break; 185 } 186 } 187 188 off64_t size; 189 if (mDataSource->getSize(&size) == OK && (haveAudio || haveVideo)) { 190 sp<AnotherPacketSource> impl = haveVideo 191 ? (AnotherPacketSource *)mParser->getSource( 192 ATSParser::VIDEO).get() 193 : (AnotherPacketSource *)mParser->getSource( 194 ATSParser::AUDIO).get(); 195 int64_t prevBufferedDurationUs = 0; 196 int64_t durationUs = -1; 197 List<int64_t> durations; 198 // Estimate duration --- stabilize until you get <500ms deviation. 199 while (feedMore() == OK && ALooper::GetNowUs() - startTime <= 2000000ll) { 200 status_t err; 201 int64_t bufferedDurationUs = impl->getBufferedDurationUs(&err); 202 if (err != OK) { 203 break; 204 } 205 if (bufferedDurationUs != prevBufferedDurationUs) { 206 durationUs = size * bufferedDurationUs / mOffset; 207 durations.push_back(durationUs); 208 if (durations.size() > 5) { 209 durations.erase(durations.begin()); 210 int64_t min = *durations.begin(); 211 int64_t max = *durations.begin(); 212 for (List<int64_t>::iterator i = durations.begin(); 213 i != durations.end(); 214 ++i) { 215 if (min > *i) { 216 min = *i; 217 } 218 if (max < *i) { 219 max = *i; 220 } 221 } 222 if (max - min < 500 * 1000) { 223 break; 224 } 225 } 226 prevBufferedDurationUs = bufferedDurationUs; 227 } 228 } 229 if (durationUs > 0) { 230 const sp<MetaData> meta = impl->getFormat(); 231 meta->setInt64(kKeyDuration, durationUs); 232 impl->setFormat(meta); 233 } 234 } 235 236 ALOGI("haveAudio=%d, haveVideo=%d, elaspedTime=%lld", 237 haveAudio, haveVideo, ALooper::GetNowUs() - startTime); 238} 239 240status_t MPEG2TSExtractor::feedMore() { 241 Mutex::Autolock autoLock(mLock); 242 243 uint8_t packet[kTSPacketSize]; 244 ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize); 245 246 if (n < (ssize_t)kTSPacketSize) { 247 if (n >= 0) { 248 mParser->signalEOS(ERROR_END_OF_STREAM); 249 } 250 return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM; 251 } 252 253 ATSParser::SyncEvent event(mOffset); 254 mOffset += n; 255 status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event); 256 if (event.isInit()) { 257 for (size_t i = 0; i < mSourceImpls.size(); ++i) { 258 if (mSourceImpls[i].get() == event.getMediaSource().get()) { 259 mSyncPoints.editItemAt(i).add( 260 event.getTimeUs(), event.getOffset()); 261 break; 262 } 263 } 264 } 265 return err; 266} 267 268uint32_t MPEG2TSExtractor::flags() const { 269 return CAN_PAUSE | CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD; 270} 271 272status_t MPEG2TSExtractor::seek(int64_t seekTimeUs, 273 const MediaSource::ReadOptions::SeekMode &seekMode) { 274 if (mSeekSyncPoints == NULL || mSeekSyncPoints->isEmpty()) { 275 ALOGW("No sync point to seek to."); 276 // ... and therefore we have nothing useful to do here. 277 return OK; 278 } 279 280 // Determine whether we're seeking beyond the known area. 281 bool shouldSeekBeyond = 282 (seekTimeUs > mSeekSyncPoints->keyAt(mSeekSyncPoints->size() - 1)); 283 284 // Determine the sync point to seek. 285 size_t index = 0; 286 for (; index < mSeekSyncPoints->size(); ++index) { 287 int64_t timeUs = mSeekSyncPoints->keyAt(index); 288 if (timeUs > seekTimeUs) { 289 break; 290 } 291 } 292 293 switch (seekMode) { 294 case MediaSource::ReadOptions::SEEK_NEXT_SYNC: 295 if (index == mSeekSyncPoints->size()) { 296 ALOGW("Next sync not found; starting from the latest sync."); 297 --index; 298 } 299 break; 300 case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC: 301 case MediaSource::ReadOptions::SEEK_CLOSEST: 302 ALOGW("seekMode not supported: %d; falling back to PREVIOUS_SYNC", 303 seekMode); 304 // fall-through 305 case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC: 306 if (index == 0) { 307 ALOGW("Previous sync not found; starting from the earliest " 308 "sync."); 309 } else { 310 --index; 311 } 312 break; 313 } 314 if (!shouldSeekBeyond || mOffset <= mSeekSyncPoints->valueAt(index)) { 315 int64_t actualSeekTimeUs = mSeekSyncPoints->keyAt(index); 316 mOffset = mSeekSyncPoints->valueAt(index); 317 status_t err = queueDiscontinuityForSeek(actualSeekTimeUs); 318 if (err != OK) { 319 return err; 320 } 321 } 322 323 if (shouldSeekBeyond) { 324 status_t err = seekBeyond(seekTimeUs); 325 if (err != OK) { 326 return err; 327 } 328 } 329 330 // Fast-forward to sync frame. 331 for (size_t i = 0; i < mSourceImpls.size(); ++i) { 332 const sp<AnotherPacketSource> &impl = mSourceImpls[i]; 333 status_t err; 334 feedUntilBufferAvailable(impl); 335 while (impl->hasBufferAvailable(&err)) { 336 sp<AMessage> meta = impl->getMetaAfterLastDequeued(0); 337 sp<ABuffer> buffer; 338 if (meta == NULL) { 339 return UNKNOWN_ERROR; 340 } 341 int32_t sync; 342 if (meta->findInt32("isSync", &sync) && sync) { 343 break; 344 } 345 err = impl->dequeueAccessUnit(&buffer); 346 if (err != OK) { 347 return err; 348 } 349 feedUntilBufferAvailable(impl); 350 } 351 } 352 353 return OK; 354} 355 356status_t MPEG2TSExtractor::queueDiscontinuityForSeek(int64_t actualSeekTimeUs) { 357 // Signal discontinuity 358 sp<AMessage> extra(new AMessage); 359 extra->setInt64(IStreamListener::kKeyMediaTimeUs, actualSeekTimeUs); 360 mParser->signalDiscontinuity(ATSParser::DISCONTINUITY_TIME, extra); 361 362 // After discontinuity, impl should only have discontinuities 363 // with the last being what we queued. Dequeue them all here. 364 for (size_t i = 0; i < mSourceImpls.size(); ++i) { 365 const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i); 366 sp<ABuffer> buffer; 367 status_t err; 368 while (impl->hasBufferAvailable(&err)) { 369 if (err != OK) { 370 return err; 371 } 372 err = impl->dequeueAccessUnit(&buffer); 373 // If the source contains anything but discontinuity, that's 374 // a programming mistake. 375 CHECK(err == INFO_DISCONTINUITY); 376 } 377 } 378 379 // Feed until we have a buffer for each source. 380 for (size_t i = 0; i < mSourceImpls.size(); ++i) { 381 const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i); 382 sp<ABuffer> buffer; 383 status_t err = feedUntilBufferAvailable(impl); 384 if (err != OK) { 385 return err; 386 } 387 } 388 389 return OK; 390} 391 392status_t MPEG2TSExtractor::seekBeyond(int64_t seekTimeUs) { 393 // If we're seeking beyond where we know --- read until we reach there. 394 size_t syncPointsSize = mSeekSyncPoints->size(); 395 396 while (seekTimeUs > mSeekSyncPoints->keyAt( 397 mSeekSyncPoints->size() - 1)) { 398 status_t err; 399 if (syncPointsSize < mSeekSyncPoints->size()) { 400 syncPointsSize = mSeekSyncPoints->size(); 401 int64_t syncTimeUs = mSeekSyncPoints->keyAt(syncPointsSize - 1); 402 // Dequeue buffers before sync point in order to avoid too much 403 // cache building up. 404 sp<ABuffer> buffer; 405 for (size_t i = 0; i < mSourceImpls.size(); ++i) { 406 const sp<AnotherPacketSource> &impl = mSourceImpls[i]; 407 int64_t timeUs; 408 while ((err = impl->nextBufferTime(&timeUs)) == OK) { 409 if (timeUs < syncTimeUs) { 410 impl->dequeueAccessUnit(&buffer); 411 } else { 412 break; 413 } 414 } 415 if (err != OK && err != -EWOULDBLOCK) { 416 return err; 417 } 418 } 419 } 420 if (feedMore() != OK) { 421 return ERROR_END_OF_STREAM; 422 } 423 } 424 425 return OK; 426} 427 428status_t MPEG2TSExtractor::feedUntilBufferAvailable( 429 const sp<AnotherPacketSource> &impl) { 430 status_t finalResult; 431 while (!impl->hasBufferAvailable(&finalResult)) { 432 if (finalResult != OK) { 433 return finalResult; 434 } 435 436 status_t err = feedMore(); 437 if (err != OK) { 438 impl->signalEOS(err); 439 } 440 } 441 return OK; 442} 443 444//////////////////////////////////////////////////////////////////////////////// 445 446bool SniffMPEG2TS( 447 const sp<DataSource> &source, String8 *mimeType, float *confidence, 448 sp<AMessage> *) { 449 for (int i = 0; i < 5; ++i) { 450 char header; 451 if (source->readAt(kTSPacketSize * i, &header, 1) != 1 452 || header != 0x47) { 453 return false; 454 } 455 } 456 457 *confidence = 0.1f; 458 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 459 460 return true; 461} 462 463} // namespace android 464