Fix MediaMetadataRetriever seek option OPTION_CLOSEST
When seeking with OPTION_CLOSEST, extractor returns the actual
closest target time via kKeyTargetTime, and read sample is the
sync frame before that. extractVideoFrame() needs to decode to
target time.
bug: 25783325
Change-Id: I94d6c196e2378b5efb608829b11aacf252d1fd46
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index d2ba02e..b111c28 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -254,6 +254,10 @@
bool isAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
|| !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
+ bool isSeekingClosest = (seekMode == MediaSource::ReadOptions::SEEK_CLOSEST);
+ bool firstSample = true;
+ int64_t targetTimeUs = -1ll;
+
do {
size_t inputIndex = -1;
int64_t ptsUs = 0ll;
@@ -280,6 +284,11 @@
haveMoreInputs = false;
break;
}
+ if (firstSample && isSeekingClosest) {
+ mediaBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs);
+ ALOGV("Seeking closest: targetTimeUs=%lld", (long long)targetTimeUs);
+ }
+ firstSample = false;
if (mediaBuffer->range_length() > codecBuffer->capacity()) {
ALOGE("buffer size (%zu) too large for codec input size (%zu)",
@@ -292,8 +301,9 @@
memcpy(codecBuffer->data(),
(const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
mediaBuffer->range_length());
- if (isAvcOrHevc && IsIDR(codecBuffer)) {
- // Only need to decode one IDR frame.
+ if (isAvcOrHevc && IsIDR(codecBuffer) && !isSeekingClosest) {
+ // Only need to decode one IDR frame, unless we're seeking with CLOSEST
+ // option, in which case we need to actually decode to targetTimeUs.
haveMoreInputs = false;
flags |= MediaCodec::BUFFER_FLAG_EOS;
}
@@ -340,8 +350,13 @@
ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
err = OK;
} else if (err == OK) {
- ALOGV("Received an output buffer");
- done = true;
+ // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
+ // from the extractor, decode to the specified frame. Otherwise we're done.
+ done = (targetTimeUs < 0ll) || (timeUs >= targetTimeUs);
+ ALOGV("Received an output buffer, timeUs=%lld", (long long)timeUs);
+ if (!done) {
+ err = decoder->releaseOutputBuffer(index);
+ }
} else {
ALOGW("Received error %d (%s) instead of output", err, asString(err));
done = true;