summaryrefslogtreecommitdiffstats
path: root/media/libstagefright
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-07-20 15:04:28 -0700
committerAndreas Huber <andih@google.com>2010-07-21 08:51:29 -0700
commitabd1f4f870925d6776dbe4b930b759a1ab6595ca (patch)
tree1b86ec19a16a2a340afecfd6207b1fd8236228b9 /media/libstagefright
parent3108231d90e8aa324923fd8864ca2477948c5d25 (diff)
downloadframeworks_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
Diffstat (limited to 'media/libstagefright')
-rw-r--r--media/libstagefright/AMRExtractor.cpp3
-rw-r--r--media/libstagefright/AwesomePlayer.cpp3
-rw-r--r--media/libstagefright/CameraSource.cpp3
-rw-r--r--media/libstagefright/JPEGSource.cpp3
-rw-r--r--media/libstagefright/MP3Extractor.cpp3
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp73
-rw-r--r--media/libstagefright/MediaSource.cpp8
-rw-r--r--media/libstagefright/OMXCodec.cpp51
-rw-r--r--media/libstagefright/OggExtractor.cpp3
-rw-r--r--media/libstagefright/SampleTable.cpp154
-rw-r--r--media/libstagefright/ShoutcastSource.cpp3
-rw-r--r--media/libstagefright/WAVExtractor.cpp3
-rw-r--r--media/libstagefright/codecs/aacdec/AACDecoder.cpp3
-rw-r--r--media/libstagefright/codecs/aacenc/AACEncoder.cpp3
-rw-r--r--media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp3
-rw-r--r--media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp3
-rw-r--r--media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp3
-rw-r--r--media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp3
-rw-r--r--media/libstagefright/codecs/avc/dec/AVCDecoder.cpp58
-rw-r--r--media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp52
-rw-r--r--media/libstagefright/codecs/mp3dec/MP3Decoder.cpp3
-rw-r--r--media/libstagefright/codecs/on2/dec/VPXDecoder.cpp45
-rw-r--r--media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp3
-rw-r--r--media/libstagefright/include/AVCDecoder.h3
-rw-r--r--media/libstagefright/include/M4vH263Decoder.h1
-rw-r--r--media/libstagefright/include/SampleTable.h13
-rw-r--r--media/libstagefright/include/VPXDecoder.h2
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp3
28 files changed, 446 insertions, 65 deletions
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);
}