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