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