Experiment with seeking to closest frame instead of closest syncframe
Also supports SEEK_CLOSEST mode in the Matroska/Webm extractor.
Change-Id: I257771648dfe41392a4cf8932f625489dcb9f234
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8073af8..aacfbdd 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1609,7 +1609,7 @@
mSeekTimeUs,
mSeeking == SEEK_VIDEO_ONLY
? MediaSource::ReadOptions::SEEK_NEXT_SYNC
- : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+ : MediaSource::ReadOptions::SEEK_CLOSEST);
}
for (;;) {
status_t err = mVideoSource->read(&mVideoBuffer, &options);
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index a1644d2..a0db719 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -93,7 +93,10 @@
void advance();
void reset();
- void seek(int64_t seekTimeUs, bool seekToKeyFrame);
+
+ void seek(
+ int64_t seekTimeUs, bool seekToKeyFrame,
+ int64_t *actualFrameTimeUs);
const mkvparser::Block *block() const;
int64_t blockTimeUs() const;
@@ -303,22 +306,52 @@
} while (!eos() && block()->GetTrackNumber() != mTrackNum);
}
-void BlockIterator::seek(int64_t seekTimeUs, bool seekToKeyFrame) {
+void BlockIterator::seek(
+ int64_t seekTimeUs, bool seekToKeyFrame,
+ int64_t *actualFrameTimeUs) {
Mutex::Autolock autoLock(mExtractor->mLock);
- mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
+ *actualFrameTimeUs = -1ll;
+
+ int64_t seekTimeNs = seekTimeUs * 1000ll;
+
+ mCluster = mExtractor->mSegment->FindCluster(seekTimeNs);
mBlockEntry = NULL;
mBlockEntryIndex = 0;
- do {
- advance_l();
- }
- while (!eos() && block()->GetTrackNumber() != mTrackNum);
+ long prevKeyFrameBlockEntryIndex = -1;
- if (seekToKeyFrame) {
- while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
- advance_l();
+ for (;;) {
+ advance_l();
+
+ if (eos()) {
+ break;
}
+
+ if (block()->GetTrackNumber() != mTrackNum) {
+ continue;
+ }
+
+ if (block()->IsKey()) {
+ prevKeyFrameBlockEntryIndex = mBlockEntryIndex - 1;
+ }
+
+ int64_t timeNs = block()->GetTime(mCluster);
+
+ if (timeNs >= seekTimeNs) {
+ *actualFrameTimeUs = (timeNs + 500ll) / 1000ll;
+ break;
+ }
+ }
+
+ if (eos()) {
+ return;
+ }
+
+ if (seekToKeyFrame && !block()->IsKey()) {
+ CHECK_GE(prevKeyFrameBlockEntryIndex, 0);
+ mBlockEntryIndex = prevKeyFrameBlockEntryIndex;
+ advance_l();
}
}
@@ -397,6 +430,8 @@
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
+ int64_t targetSampleTimeUs = -1ll;
+
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
if (options && options->getSeekTo(&seekTimeUs, &mode)
@@ -406,10 +441,14 @@
// Apparently keyframe indication in audio tracks is unreliable,
// fortunately in all our currently supported audio encodings every
// frame is effectively a keyframe.
- mBlockIter.seek(seekTimeUs, !mIsAudio);
+ int64_t actualFrameTimeUs;
+ mBlockIter.seek(seekTimeUs, !mIsAudio, &actualFrameTimeUs);
+
+ if (mode == ReadOptions::SEEK_CLOSEST) {
+ targetSampleTimeUs = actualFrameTimeUs;
+ }
}
-again:
while (mPendingFrames.empty()) {
status_t err = readBlock();
@@ -424,6 +463,11 @@
mPendingFrames.erase(mPendingFrames.begin());
if (mType != AVC) {
+ if (targetSampleTimeUs >= 0ll) {
+ frame->meta_data()->setInt64(
+ kKeyTargetTime, targetSampleTimeUs);
+ }
+
*out = frame;
return OK;
@@ -506,6 +550,11 @@
frame->release();
frame = NULL;
+ if (targetSampleTimeUs >= 0ll) {
+ buffer->meta_data()->setInt64(
+ kKeyTargetTime, targetSampleTimeUs);
+ }
+
*out = buffer;
return OK;