diff options
author | Andreas Huber <andih@google.com> | 2010-07-20 15:04:28 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2010-07-21 08:51:29 -0700 |
commit | abd1f4f870925d6776dbe4b930b759a1ab6595ca (patch) | |
tree | 1b86ec19a16a2a340afecfd6207b1fd8236228b9 | |
parent | 3108231d90e8aa324923fd8864ca2477948c5d25 (diff) | |
download | frameworks_av-abd1f4f870925d6776dbe4b930b759a1ab6595ca.zip frameworks_av-abd1f4f870925d6776dbe4b930b759a1ab6595ca.tar.gz frameworks_av-abd1f4f870925d6776dbe4b930b759a1ab6595ca.tar.bz2 |
Support finer seek control on MediaSources.
related-to-bug: 2858448
Change-Id: Ifb4b13b990fd5889113e47e2c62249ac43391fa1
31 files changed, 459 insertions, 67 deletions
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h index 9cc94c8..a31395e 100644 --- a/include/media/stagefright/MediaSource.h +++ b/include/media/stagefright/MediaSource.h @@ -62,14 +62,21 @@ struct MediaSource : public RefBase { // a) not request a seek // b) not be late, i.e. lateness_us = 0 struct ReadOptions { + enum SeekMode { + SEEK_PREVIOUS_SYNC, + SEEK_NEXT_SYNC, + SEEK_CLOSEST_SYNC, + SEEK_CLOSEST, + }; + ReadOptions(); // Reset everything back to defaults. void reset(); - void setSeekTo(int64_t time_us); + void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC); void clearSeekTo(); - bool getSeekTo(int64_t *time_us) const; + bool getSeekTo(int64_t *time_us, SeekMode *mode) const; void setLateBy(int64_t lateness_us); int64_t getLateBy() const; @@ -81,6 +88,7 @@ struct MediaSource : public RefBase { uint32_t mOptions; int64_t mSeekTimeUs; + SeekMode mSeekMode; int64_t mLatenessUs; }; diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index cdbf483..e631c7f 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -46,6 +46,7 @@ enum { kKeyIsSyncFrame = 'sync', // int32_t (bool) kKeyIsCodecConfig = 'conf', // int32_t (bool) kKeyTime = 'time', // int64_t (usecs) + kKeyTargetTime = 'tarT', // int64_t (usecs) kKeyDuration = 'dura', // int64_t (usecs) kKeyColorFormat = 'colf', kKeyPlatformPrivate = 'priv', // pointer diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index 214f43a..79e7a2f 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -141,6 +141,8 @@ private: bool mNoMoreOutputData; bool mOutputPortSettingsHaveChanged; int64_t mSeekTimeUs; + ReadOptions::SeekMode mSeekMode; + int64_t mTargetTimeUs; MediaBuffer *mLeftOverBuffer; diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp index 0fea72e..9fc1d27 100644 --- a/media/libstagefright/AMRExtractor.cpp +++ b/media/libstagefright/AMRExtractor.cpp @@ -212,7 +212,8 @@ status_t AMRSource::read( *out = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { int64_t seekFrame = seekTimeUs / 20000ll; // 20ms per frame. mCurrentTimeUs = seekFrame * 20000ll; mOffset = seekFrame * mFrameSize + (mIsWide ? 9 : 6); diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index ffed74f..236a62b 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -914,7 +914,8 @@ void AwesomePlayer::onVideoEvent() { if (mSeeking) { LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); - options.setSeekTo(mSeekTimeUs); + options.setSeekTo( + mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); } for (;;) { status_t err = mVideoSource->read(&mVideoBuffer, &options); diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 6f4c980..4cc176a 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -267,7 +267,8 @@ status_t CameraSource::read( *buffer = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { return ERROR_UNSUPPORTED; } diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp index a4be2dd..ec81097 100644 --- a/media/libstagefright/JPEGSource.cpp +++ b/media/libstagefright/JPEGSource.cpp @@ -112,7 +112,8 @@ status_t JPEGSource::read( *out = NULL; int64_t seekTimeUs; - if (options != NULL && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) { return UNKNOWN_ERROR; } diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp index 69c3a72..2248e23 100644 --- a/media/libstagefright/MP3Extractor.cpp +++ b/media/libstagefright/MP3Extractor.cpp @@ -586,7 +586,8 @@ status_t MP3Source::read( *out = NULL; int64_t seekTimeUs; - if (options != NULL && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) { int32_t bitrate; if (!mMeta->findInt32(kKeyBitRate, &bitrate)) { // bitrate is in bits/sec. diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 0c2f1e6..7cea629 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -1468,12 +1468,45 @@ status_t MPEG4Source::read( *out = NULL; + int64_t targetSampleTimeUs = -1; + int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { + uint32_t findFlags = 0; + switch (mode) { + case ReadOptions::SEEK_PREVIOUS_SYNC: + findFlags = SampleTable::kFlagBefore; + break; + case ReadOptions::SEEK_NEXT_SYNC: + findFlags = SampleTable::kFlagAfter; + break; + case ReadOptions::SEEK_CLOSEST_SYNC: + case ReadOptions::SEEK_CLOSEST: + findFlags = SampleTable::kFlagClosest; + break; + default: + CHECK(!"Should not be here."); + break; + } + uint32_t sampleIndex; - status_t err = mSampleTable->findClosestSample( + status_t err = mSampleTable->findSampleAtTime( seekTimeUs * mTimescale / 1000000, - &sampleIndex, SampleTable::kSyncSample_Flag); + &sampleIndex, findFlags); + + if (mode == ReadOptions::SEEK_CLOSEST) { + // We found the closest sample already, now we want the sync + // sample preceding it (or the sample itself of course), even + // if the subsequent sync sample is closer. + findFlags = SampleTable::kFlagBefore; + } + + uint32_t syncSampleIndex; + if (err == OK) { + err = mSampleTable->findSyncSampleNear( + sampleIndex, &syncSampleIndex, findFlags); + } if (err != OK) { if (err == ERROR_OUT_OF_RANGE) { @@ -1487,7 +1520,27 @@ status_t MPEG4Source::read( return err; } - mCurrentSampleIndex = sampleIndex; + uint32_t sampleTime; + CHECK_EQ(OK, mSampleTable->getMetaDataForSample( + sampleIndex, NULL, NULL, &sampleTime)); + + if (mode == ReadOptions::SEEK_CLOSEST) { + targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale; + } + +#if 0 + uint32_t syncSampleTime; + CHECK_EQ(OK, mSampleTable->getMetaDataForSample( + syncSampleIndex, NULL, NULL, &syncSampleTime)); + + LOGI("seek to time %lld us => sample at time %lld us, " + "sync sample at time %lld us", + seekTimeUs, + sampleTime * 1000000ll / mTimescale, + syncSampleTime * 1000000ll / mTimescale); +#endif + + mCurrentSampleIndex = syncSampleIndex; if (mBuffer != NULL) { mBuffer->release(); mBuffer = NULL; @@ -1536,6 +1589,12 @@ status_t MPEG4Source::read( mBuffer->meta_data()->clear(); mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)dts * 1000000) / mTimescale); + + if (targetSampleTimeUs >= 0) { + mBuffer->meta_data()->setInt64( + kKeyTargetTime, targetSampleTimeUs); + } + ++mCurrentSampleIndex; } @@ -1632,6 +1691,12 @@ status_t MPEG4Source::read( mBuffer->meta_data()->clear(); mBuffer->meta_data()->setInt64( kKeyTime, ((int64_t)dts * 1000000) / mTimescale); + + if (targetSampleTimeUs >= 0) { + mBuffer->meta_data()->setInt64( + kKeyTargetTime, targetSampleTimeUs); + } + ++mCurrentSampleIndex; *out = mBuffer; diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp index ec89b74..fd0e79c 100644 --- a/media/libstagefright/MediaSource.cpp +++ b/media/libstagefright/MediaSource.cpp @@ -34,18 +34,22 @@ void MediaSource::ReadOptions::reset() { mLatenessUs = 0; } -void MediaSource::ReadOptions::setSeekTo(int64_t time_us) { +void MediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) { mOptions |= kSeekTo_Option; mSeekTimeUs = time_us; + mSeekMode = mode; } void MediaSource::ReadOptions::clearSeekTo() { mOptions &= ~kSeekTo_Option; mSeekTimeUs = 0; + mSeekMode = SEEK_CLOSEST_SYNC; } -bool MediaSource::ReadOptions::getSeekTo(int64_t *time_us) const { +bool MediaSource::ReadOptions::getSeekTo( + int64_t *time_us, SeekMode *mode) const { *time_us = mSeekTimeUs; + *mode = mSeekMode; return (mOptions & kSeekTo_Option) != 0; } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 7762bf4..1b63083 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1272,6 +1272,8 @@ OMXCodec::OMXCodec( mNoMoreOutputData(false), mOutputPortSettingsHaveChanged(false), mSeekTimeUs(-1), + mSeekMode(ReadOptions::SEEK_CLOSEST_SYNC), + mTargetTimeUs(-1), mLeftOverBuffer(NULL), mPaused(false) { mPortStatus[kPortIndexInput] = ENABLED; @@ -1640,13 +1642,33 @@ void OMXCodec::on_message(const omx_message &msg) { kKeyBufferID, msg.u.extended_buffer_data.buffer); - mFilledBuffers.push_back(i); - mBufferFilled.signal(); - if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_EOS) { CODEC_LOGV("No more output data."); mNoMoreOutputData = true; } + + if (mTargetTimeUs >= 0) { + CHECK(msg.u.extended_buffer_data.timestamp <= mTargetTimeUs); + + if (msg.u.extended_buffer_data.timestamp < mTargetTimeUs) { + CODEC_LOGV( + "skipping output buffer at timestamp %lld us", + msg.u.extended_buffer_data.timestamp); + + fillOutputBuffer(info); + break; + } + + CODEC_LOGV( + "returning output buffer at target timestamp " + "%lld us", + msg.u.extended_buffer_data.timestamp); + + mTargetTimeUs = -1; + } + + mFilledBuffers.push_back(i); + mBufferFilled.signal(); } break; @@ -2185,12 +2207,24 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) { } MediaSource::ReadOptions options; - options.setSeekTo(mSeekTimeUs); + options.setSeekTo(mSeekTimeUs, mSeekMode); mSeekTimeUs = -1; + mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC; mBufferFilled.signal(); err = mSource->read(&srcBuffer, &options); + + if (err == OK) { + int64_t targetTimeUs; + if (srcBuffer->meta_data()->findInt64( + kKeyTargetTime, &targetTimeUs) + && targetTimeUs >= 0) { + mTargetTimeUs = targetTimeUs; + } else { + mTargetTimeUs = -1; + } + } } else if (mLeftOverBuffer) { srcBuffer = mLeftOverBuffer; mLeftOverBuffer = NULL; @@ -2239,7 +2273,7 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) { int64_t lastBufferTimeUs; CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &lastBufferTimeUs)); - CHECK(timestampUs >= 0); + CHECK(lastBufferTimeUs >= 0); if (offset == 0) { timestampUs = lastBufferTimeUs; @@ -2696,6 +2730,8 @@ status_t OMXCodec::start(MetaData *meta) { mNoMoreOutputData = false; mOutputPortSettingsHaveChanged = false; mSeekTimeUs = -1; + mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC; + mTargetTimeUs = -1; mFilledBuffers.clear(); mPaused = false; @@ -2790,7 +2826,8 @@ status_t OMXCodec::read( bool seeking = false; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode seekMode; + if (options && options->getSeekTo(&seekTimeUs, &seekMode)) { seeking = true; } @@ -2800,6 +2837,7 @@ status_t OMXCodec::read( if (seeking) { CHECK(seekTimeUs >= 0); mSeekTimeUs = seekTimeUs; + mSeekMode = seekMode; // There's no reason to trigger the code below, there's // nothing to flush yet. @@ -2823,6 +2861,7 @@ status_t OMXCodec::read( CHECK(seekTimeUs >= 0); mSeekTimeUs = seekTimeUs; + mSeekMode = seekMode; mFilledBuffers.clear(); diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index 6013b6f..c267a23 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -155,7 +155,8 @@ status_t OggSource::read( *out = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { off_t pos = seekTimeUs * mExtractor->mImpl->approxBitrate() / 8000000ll; LOGI("seeking to offset %ld", pos); diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index 89a522e..2e62f9f 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -314,8 +314,10 @@ uint32_t abs_difference(uint32_t time1, uint32_t time2) { return time1 > time2 ? time1 - time2 : time2 - time1; } -status_t SampleTable::findClosestSample( +status_t SampleTable::findSampleAtTime( uint32_t req_time, uint32_t *sample_index, uint32_t flags) { + *sample_index = 0; + Mutex::Autolock autoLock(mLock); uint32_t cur_sample = 0; @@ -330,16 +332,37 @@ status_t SampleTable::findClosestSample( uint32_t time1 = time + j * delta; uint32_t time2 = time1 + delta; + uint32_t sampleTime; if (i+1 == mTimeToSampleCount || (abs_difference(req_time, time1) < abs_difference(req_time, time2))) { *sample_index = cur_sample + j; + sampleTime = time1; } else { *sample_index = cur_sample + j + 1; + sampleTime = time2; } - if (flags & kSyncSample_Flag) { - return findClosestSyncSample_l(*sample_index, sample_index); + switch (flags) { + case kFlagBefore: + { + if (sampleTime > req_time && *sample_index > 0) { + --*sample_index; + } + break; + } + + case kFlagAfter: + { + if (sampleTime < req_time + && *sample_index + 1 < mNumSampleSizes) { + ++*sample_index; + } + break; + } + + default: + break; } return OK; @@ -352,8 +375,10 @@ status_t SampleTable::findClosestSample( return ERROR_OUT_OF_RANGE; } -status_t SampleTable::findClosestSyncSample_l( - uint32_t start_sample_index, uint32_t *sample_index) { +status_t SampleTable::findSyncSampleNear( + uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) { + Mutex::Autolock autoLock(mLock); + *sample_index = 0; if (mSyncSampleOffset < 0) { @@ -362,29 +387,124 @@ status_t SampleTable::findClosestSyncSample_l( return OK; } - uint32_t x; - uint32_t left = 0; - uint32_t right = mNumSyncSamples; - while (left < right) { - uint32_t mid = (left + right) / 2; + if (mNumSyncSamples == 0) { + *sample_index = 0; + return OK; + } + uint32_t left = 0; + while (left < mNumSyncSamples) { + uint32_t x; if (mDataSource->readAt( - mSyncSampleOffset + 8 + mid * 4, &x, 4) != 4) { + mSyncSampleOffset + 8 + left * 4, &x, 4) != 4) { return ERROR_IO; } x = ntohl(x); + --x; + + if (x >= start_sample_index) { + break; + } + + ++left; + } + + --left; + uint32_t x; + if (mDataSource->readAt( + mSyncSampleOffset + 8 + left * 4, &x, 4) != 4) { + return ERROR_IO; + } + + x = ntohl(x); + --x; + + if (left + 1 < mNumSyncSamples) { + uint32_t y; + if (mDataSource->readAt( + mSyncSampleOffset + 8 + (left + 1) * 4, &y, 4) != 4) { + return ERROR_IO; + } + + y = ntohl(y); + --y; + + // our sample lies between sync samples x and y. + + status_t err = mSampleIterator->seekTo(start_sample_index); + if (err != OK) { + return err; + } + + uint32_t sample_time = mSampleIterator->getSampleTime(); + + err = mSampleIterator->seekTo(x); + if (err != OK) { + return err; + } + uint32_t x_time = mSampleIterator->getSampleTime(); + + err = mSampleIterator->seekTo(y); + if (err != OK) { + return err; + } + + uint32_t y_time = mSampleIterator->getSampleTime(); + + if (abs_difference(x_time, sample_time) + > abs_difference(y_time, sample_time)) { + // Pick the sync sample closest (timewise) to the start-sample. + x = y; + ++left; + } + } + + switch (flags) { + case kFlagBefore: + { + if (x > start_sample_index) { + CHECK(left > 0); + + if (mDataSource->readAt( + mSyncSampleOffset + 8 + (left - 1) * 4, &x, 4) != 4) { + return ERROR_IO; + } + + x = ntohl(x); + --x; - if (x < (start_sample_index + 1)) { - left = mid + 1; - } else if (x > (start_sample_index + 1)) { - right = mid; - } else { + CHECK(x <= start_sample_index); + } break; } + + case kFlagAfter: + { + if (x < start_sample_index) { + if (left + 1 >= mNumSyncSamples) { + return ERROR_OUT_OF_RANGE; + } + + if (mDataSource->readAt( + mSyncSampleOffset + 8 + (left + 1) * 4, &x, 4) != 4) { + return ERROR_IO; + } + + x = ntohl(x); + --x; + + CHECK(x >= start_sample_index); + } + + break; + } + + default: + break; } - *sample_index = x - 1; + *sample_index = x; return OK; } diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp index ec25430..23b7681 100644 --- a/media/libstagefright/ShoutcastSource.cpp +++ b/media/libstagefright/ShoutcastSource.cpp @@ -93,7 +93,8 @@ status_t ShoutcastSource::read( *out = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { return ERROR_UNSUPPORTED; } diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index 7365dfa..7c2b07e 100644 --- a/media/libstagefright/WAVExtractor.cpp +++ b/media/libstagefright/WAVExtractor.cpp @@ -282,7 +282,8 @@ status_t WAVSource::read( *out = NULL; int64_t seekTimeUs; - if (options != NULL && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) { int64_t pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * 2; if (pos > mSize) { pos = mSize; diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp index 8ae1135..c5b51c0 100644 --- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp +++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp @@ -159,7 +159,8 @@ status_t AACDecoder::read( *out = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { CHECK(seekTimeUs >= 0); mNumSamplesOutput = 0; diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp index 2317de6..e8235c2 100644 --- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp +++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp @@ -202,7 +202,8 @@ status_t AACEncoder::read( *out = NULL; int64_t seekTimeUs; - CHECK(options == NULL || !options->getSeekTo(&seekTimeUs)); + ReadOptions::SeekMode mode; + CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode)); MediaBuffer *buffer; CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK); diff --git a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp index 7728597..fb300da 100644 --- a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp +++ b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp @@ -117,7 +117,8 @@ status_t AMRNBDecoder::read( *out = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { CHECK(seekTimeUs >= 0); mNumSamplesOutput = 0; diff --git a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp index 4c02fe9..c875426 100644 --- a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp +++ b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp @@ -145,7 +145,8 @@ status_t AMRNBEncoder::read( *out = NULL; int64_t seekTimeUs; - CHECK(options == NULL || !options->getSeekTo(&seekTimeUs)); + ReadOptions::SeekMode mode; + CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode)); while (mNumInputSamples < kNumSamplesPerFrame) { if (mInputBuffer == NULL) { diff --git a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp b/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp index c17c100..2a21472 100644 --- a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp +++ b/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp @@ -135,7 +135,8 @@ status_t AMRWBDecoder::read( *out = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode seekMode; + if (options && options->getSeekTo(&seekTimeUs, &seekMode)) { CHECK(seekTimeUs >= 0); mNumSamplesOutput = 0; diff --git a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp index 4257c6a..93304d0 100644 --- a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp +++ b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp @@ -196,7 +196,8 @@ status_t AMRWBEncoder::read( *out = NULL; int64_t seekTimeUs; - CHECK(options == NULL || !options->getSeekTo(&seekTimeUs)); + ReadOptions::SeekMode mode; + CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode)); while (mNumInputSamples < kNumSamplesPerFrame) { if (mInputBuffer == NULL) { diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp index 24c361e..050e3da 100644 --- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp +++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp @@ -51,7 +51,9 @@ AVCDecoder::AVCDecoder(const sp<MediaSource> &source) mInputBuffer(NULL), mAnchorTimeUs(0), mNumSamplesOutput(0), - mPendingSeekTimeUs(-1) { + mPendingSeekTimeUs(-1), + mPendingSeekMode(MediaSource::ReadOptions::SEEK_CLOSEST_SYNC), + mTargetTimeUs(-1) { memset(mHandle, 0, sizeof(tagAVCHandle)); mHandle->AVCObject = NULL; mHandle->userData = this; @@ -161,6 +163,8 @@ status_t AVCDecoder::start(MetaData *) { mAnchorTimeUs = 0; mNumSamplesOutput = 0; mPendingSeekTimeUs = -1; + mPendingSeekMode = ReadOptions::SEEK_CLOSEST_SYNC; + mTargetTimeUs = -1; mStarted = true; return OK; @@ -229,11 +233,13 @@ status_t AVCDecoder::read( *out = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { LOGV("seek requested to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6); CHECK(seekTimeUs >= 0); mPendingSeekTimeUs = seekTimeUs; + mPendingSeekMode = mode; if (mInputBuffer) { mInputBuffer->release(); @@ -246,6 +252,8 @@ status_t AVCDecoder::read( if (mInputBuffer == NULL) { LOGV("fetching new input buffer."); + bool seeking = false; + if (!mCodecSpecificData.isEmpty()) { mInputBuffer = mCodecSpecificData.editItemAt(0); mCodecSpecificData.removeAt(0); @@ -258,7 +266,9 @@ status_t AVCDecoder::read( ReadOptions seekOptions; if (mPendingSeekTimeUs >= 0) { - seekOptions.setSeekTo(mPendingSeekTimeUs); + seeking = true; + + seekOptions.setSeekTo(mPendingSeekTimeUs, mPendingSeekMode); mPendingSeekTimeUs = -1; } status_t err = mSource->read(&mInputBuffer, &seekOptions); @@ -276,6 +286,16 @@ status_t AVCDecoder::read( mInputBuffer = NULL; } } + + if (seeking) { + int64_t targetTimeUs; + if (mInputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs) + && targetTimeUs >= 0) { + mTargetTimeUs = targetTimeUs; + } else { + mTargetTimeUs = -1; + } + } } const uint8_t *fragPtr; @@ -394,9 +414,35 @@ status_t AVCDecoder::read( CHECK(index >= 0); CHECK(index < (int32_t)mFrames.size()); - *out = mFrames.editItemAt(index); - (*out)->set_range(0, (*out)->size()); - (*out)->add_ref(); + MediaBuffer *mbuf = mFrames.editItemAt(index); + + bool skipFrame = false; + + if (mTargetTimeUs >= 0) { + int64_t timeUs; + CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); + CHECK(timeUs <= mTargetTimeUs); + + if (timeUs < mTargetTimeUs) { + // We're still waiting for the frame with the matching + // timestamp and we won't return the current one. + skipFrame = true; + + LOGV("skipping frame at %lld us", timeUs); + } else { + LOGV("found target frame at %lld us", timeUs); + + mTargetTimeUs = -1; + } + } + + if (!skipFrame) { + *out = mbuf; + (*out)->set_range(0, (*out)->size()); + (*out)->add_ref(); + } else { + *out = new MediaBuffer(0); + } // Do _not_ release input buffer yet. diff --git a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp index 8350f7a..0f08f6e 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp @@ -37,7 +37,8 @@ M4vH263Decoder::M4vH263Decoder(const sp<MediaSource> &source) mStarted(false), mHandle(new tagvideoDecControls), mInputBuffer(NULL), - mNumSamplesOutput(0) { + mNumSamplesOutput(0), + mTargetTimeUs(-1) { LOGV("M4vH263Decoder"); memset(mHandle, 0, sizeof(tagvideoDecControls)); @@ -146,6 +147,7 @@ status_t M4vH263Decoder::start(MetaData *) { mSource->start(); mNumSamplesOutput = 0; + mTargetTimeUs = -1; mStarted = true; return OK; @@ -175,8 +177,11 @@ status_t M4vH263Decoder::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; + bool seeking = false; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { + seeking = true; CHECK_EQ(PVResetVideoDecoder(mHandle), PV_TRUE); } @@ -186,6 +191,16 @@ status_t M4vH263Decoder::read( return err; } + if (seeking) { + int64_t targetTimeUs; + if (inputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs) + && targetTimeUs >= 0) { + mTargetTimeUs = targetTimeUs; + } else { + mTargetTimeUs = -1; + } + } + uint8_t *bitstream = (uint8_t *) inputBuffer->data() + inputBuffer->range_offset(); @@ -221,17 +236,40 @@ status_t M4vH263Decoder::read( return INFO_FORMAT_CHANGED; } - *out = mFrames[mNumSamplesOutput & 0x01]; - (*out)->add_ref(); - int64_t timeUs; CHECK(inputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); - (*out)->meta_data()->setInt64(kKeyTime, timeUs); - ++mNumSamplesOutput; inputBuffer->release(); inputBuffer = NULL; + bool skipFrame = false; + + if (mTargetTimeUs >= 0) { + CHECK(timeUs <= mTargetTimeUs); + + if (timeUs < mTargetTimeUs) { + // We're still waiting for the frame with the matching + // timestamp and we won't return the current one. + skipFrame = true; + + LOGV("skipping frame at %lld us", timeUs); + } else { + LOGV("found target frame at %lld us", timeUs); + + mTargetTimeUs = -1; + } + } + + if (skipFrame) { + *out = new MediaBuffer(0); + } else { + *out = mFrames[mNumSamplesOutput & 0x01]; + (*out)->add_ref(); + (*out)->meta_data()->setInt64(kKeyTime, timeUs); + } + + ++mNumSamplesOutput; + return OK; } diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp index f40bd11..c4a8280 100644 --- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp +++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp @@ -122,7 +122,8 @@ status_t MP3Decoder::read( *out = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { CHECK(seekTimeUs >= 0); mNumFramesOutput = 0; diff --git a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp index bad8956..fbc97f4 100644 --- a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp +++ b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp @@ -39,7 +39,8 @@ VPXDecoder::VPXDecoder(const sp<MediaSource> &source) mStarted(false), mBufferSize(0), mCtx(NULL), - mBufferGroup(NULL) { + mBufferGroup(NULL), + mTargetTimeUs(-1) { sp<MetaData> inputFormat = source->getFormat(); const char *mime; CHECK(inputFormat->findCString(kKeyMIMEType, &mime)); @@ -94,6 +95,8 @@ status_t VPXDecoder::start(MetaData *) { mBufferGroup->add_buffer(new MediaBuffer(mBufferSize)); mBufferGroup->add_buffer(new MediaBuffer(mBufferSize)); + mTargetTimeUs = -1; + mStarted = true; return OK; @@ -126,6 +129,13 @@ status_t VPXDecoder::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; + bool seeking = false; + int64_t seekTimeUs; + ReadOptions::SeekMode seekMode; + if (options && options->getSeekTo(&seekTimeUs, &seekMode)) { + seeking = true; + } + MediaBuffer *input; status_t err = mSource->read(&input, options); @@ -135,6 +145,16 @@ status_t VPXDecoder::read( LOGV("read %d bytes from source\n", input->range_length()); + if (seeking) { + int64_t targetTimeUs; + if (input->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs) + && targetTimeUs >= 0) { + mTargetTimeUs = targetTimeUs; + } else { + mTargetTimeUs = -1; + } + } + if (vpx_codec_decode( (vpx_codec_ctx_t *)mCtx, (uint8_t *)input->data() + input->range_offset(), @@ -156,6 +176,29 @@ status_t VPXDecoder::read( input->release(); input = NULL; + bool skipFrame = false; + + if (mTargetTimeUs >= 0) { + CHECK(timeUs <= mTargetTimeUs); + + if (timeUs < mTargetTimeUs) { + // We're still waiting for the frame with the matching + // timestamp and we won't return the current one. + skipFrame = true; + + LOGV("skipping frame at %lld us", timeUs); + } else { + LOGV("found target frame at %lld us", timeUs); + + mTargetTimeUs = -1; + } + } + + if (skipFrame) { + *out = new MediaBuffer(0); + return OK; + } + vpx_codec_iter_t iter = NULL; vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter); diff --git a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp index df3f16a..53f0638 100644 --- a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp +++ b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp @@ -200,7 +200,8 @@ status_t VorbisDecoder::read( *out = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { CHECK(seekTimeUs >= 0); mNumFramesOutput = 0; diff --git a/media/libstagefright/include/AVCDecoder.h b/media/libstagefright/include/AVCDecoder.h index 621aa9a..7810171 100644 --- a/media/libstagefright/include/AVCDecoder.h +++ b/media/libstagefright/include/AVCDecoder.h @@ -58,6 +58,9 @@ private: int64_t mAnchorTimeUs; int64_t mNumSamplesOutput; int64_t mPendingSeekTimeUs; + MediaSource::ReadOptions::SeekMode mPendingSeekMode; + + int64_t mTargetTimeUs; void addCodecSpecificData(const uint8_t *data, size_t size); diff --git a/media/libstagefright/include/M4vH263Decoder.h b/media/libstagefright/include/M4vH263Decoder.h index ec49e80..7d73e30 100644 --- a/media/libstagefright/include/M4vH263Decoder.h +++ b/media/libstagefright/include/M4vH263Decoder.h @@ -54,6 +54,7 @@ private: MediaBuffer *mInputBuffer; int64_t mNumSamplesOutput; + int64_t mTargetTimeUs; void allocateFrames(int32_t width, int32_t height); void releaseFrames(); diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h index 533ce84..a2b2c99 100644 --- a/media/libstagefright/include/SampleTable.h +++ b/media/libstagefright/include/SampleTable.h @@ -63,11 +63,17 @@ public: uint32_t *decodingTime); enum { - kSyncSample_Flag = 1 + kFlagBefore, + kFlagAfter, + kFlagClosest }; - status_t findClosestSample( + status_t findSampleAtTime( uint32_t req_time, uint32_t *sample_index, uint32_t flags); + status_t findSyncSampleNear( + uint32_t start_sample_index, uint32_t *sample_index, + uint32_t flags); + status_t findThumbnailSample(uint32_t *sample_index); protected: @@ -111,9 +117,6 @@ private: friend struct SampleIterator; - status_t findClosestSyncSample_l( - uint32_t start_sample_index, uint32_t *sample_index); - status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size); SampleTable(const SampleTable &); diff --git a/media/libstagefright/include/VPXDecoder.h b/media/libstagefright/include/VPXDecoder.h index 550c612..3b8362d 100644 --- a/media/libstagefright/include/VPXDecoder.h +++ b/media/libstagefright/include/VPXDecoder.h @@ -48,6 +48,8 @@ private: void *mCtx; MediaBufferGroup *mBufferGroup; + int64_t mTargetTimeUs; + sp<MetaData> mFormat; VPXDecoder(const VPXDecoder &); diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index 339a7b5..3739be1 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -281,7 +281,8 @@ status_t MatroskaSource::read( *out = NULL; int64_t seekTimeUs; - if (options && options->getSeekTo(&seekTimeUs)) { + ReadOptions::SeekMode mode; + if (options && options->getSeekTo(&seekTimeUs, &mode)) { mBlockIter.seek(seekTimeUs); } |