@@ -626,9 +626,17 @@ FrameOutput SingleStreamDecoder::getFrameAtIndexInternal(
626626 }
627627 validateFrameIndex (streamMetadata, frameIndex);
628628
629- int64_t pts = getPts (frameIndex);
630- setCursorPtsInSeconds (ptsToSeconds (pts, streamInfo.timeBase ));
631- return getNextFrameInternal (preAllocatedOutputTensor);
629+ // Only set cursor if we're not decoding sequentially: when decoding
630+ // sequentially, we don't need to seek anywhere, so by *not* setting the
631+ // cursor we allow canWeAvoidSeeking() to return true early.
632+ if (frameIndex != lastDecodedFrameIndex_ + 1 ) {
633+ int64_t pts = getPts (frameIndex);
634+ setCursorPtsInSeconds (ptsToSeconds (pts, streamInfo.timeBase ));
635+ }
636+
637+ auto result = getNextFrameInternal (preAllocatedOutputTensor);
638+ lastDecodedFrameIndex_ = frameIndex;
639+ return result;
632640}
633641
634642FrameBatchOutput SingleStreamDecoder::getFramesAtIndices (
@@ -1105,7 +1113,11 @@ bool SingleStreamDecoder::canWeAvoidSeeking() const {
11051113 // within getFramesPlayedInRangeAudio(), when setCursorPtsInSeconds() was
11061114 // called. For more context, see [Audio Decoding Design]
11071115 return !cursorWasJustSet_;
1116+ } else if (!cursorWasJustSet_) {
1117+ // For videos, when decoding consecutive frames, we don't need to seek.
1118+ return true ;
11081119 }
1120+
11091121 if (cursor_ < lastDecodedAvFramePts_) {
11101122 // We can never skip a seek if we are seeking backwards.
11111123 return false ;
@@ -1181,10 +1193,8 @@ UniqueAVFrame SingleStreamDecoder::decodeAVFrame(
11811193
11821194 resetDecodeStats ();
11831195
1184- if (cursorWasJustSet_) {
1185- maybeSeekToBeforeDesiredPts ();
1186- cursorWasJustSet_ = false ;
1187- }
1196+ maybeSeekToBeforeDesiredPts ();
1197+ cursorWasJustSet_ = false ;
11881198
11891199 UniqueAVFrame avFrame (av_frame_alloc ());
11901200 AutoAVPacket autoAVPacket;
0 commit comments