-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor seeking to only store pts as int64 timestamp #262
Conversation
Can you run benchmarks to ensure there are no regressions? Also explain why this change is being done in the first place, and whether it is intended to keep existing behavior or change it. Will there be any scenarios where behavior is changed? |
@ahmadsharif1, sure I'll get some benchmark numbers. As a pure refactor, we're keeping existing behavior - hence no new tests. Any behavior change would be a bug. And good question on the motivation. There are two main motivations:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should add a random seek test before changing this code because seeking is hard to get right in terms of correctness and performance.
The test should seek forwards/backwards in a loop and grab the next frame and make sure it's at or higher than the seeked value.
It can also add streams in the middle.
We should also test seeking to beginning/end to make sure edge cases are handled correctly.
The original code is as lazy as it can be -- meaning the conversion from user's double to per-stream int64 happens as late as possible. That's actually more robust because user can seek first and add stream later. It's also more efficient.
Unless there is a compelling behavior change, I am inclined to keep the original behavior.
hasDesiredPts_ = true; | ||
} | ||
|
||
void VideoDecoder::setCursorPts(int64_t pts) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know that this function makes sense without all streams having a common timebase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's internal, and we always know a stream index when calling it, I think it's fine if this takes a stream index.
@@ -1179,7 +1178,18 @@ VideoDecoder::DecodedOutput VideoDecoder::getNextDecodedOutputNoDemux() { | |||
} | |||
|
|||
void VideoDecoder::setCursorPtsInSeconds(double seconds) { | |||
maybeDesiredPts_ = seconds; | |||
for (int streamIndex : activeStreamIndices_) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the original change because its lazier -- when the user seeks a bunch of times only the last seek value should affect anything. The new change sets things eagerly
More importantly, if the user adds a stream after calling seek it doesn't seek that stream, so it's less robust too
std::optional<double> maybeDesiredPts_; | ||
// True when the user wants to seek. The actual pts values to seek to are | ||
// stored in the per-stream metadata in discardFramesBeforePts. | ||
bool hasDesiredPts_ = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seeking is hard to implement correctly and I am not confident about this change.
I think at least for debugging purposes we should keep the original double value around and when returning a frame after a seek we should ensure it's >= the value passed in here
@ahmadsharif1, the laziness of the old behavior is a good point - I'm not sure how to retain that with my current approach. I'm going to drop the bigger part of the refactor, but I want to address |
Refactor that:
std::optional<double> maybeDesiredPts_
inVideoDecoder
with:a.
bool hasDesiredPts_
inVideoDecoder
; andb. setting each stream info's
discardFramesBeforePts
directly inVideoDecoder::setCursorPtsInSeconds(double second)
.VideoDecoder::setCursorPts(int64_t pts)
which we can call when we have an int-based pts that came directly from FFmpeg. This is a private API, meant only to be used when we're round-tripping pts values from FFmpeg. We don't expose it to users.Note the
FIXME
comment. It seems like we're "consuming" the values ofdiscardFramesBeforePts
inmaybeSeekToBeforeDesiredPts()
. We resethasDesiredPts_
after calling it (and we previously resetmaybeDesiredPts_
). It seems like we should also reset all of thediscardFramesBeforePts
values.Thinking about it more, I'm also unsure if we need
discardFramesBeforePts
to be an optional. Because we initialize it to be 0 and we never "clear" the value out, that implies two things:If 0 is not a reasonable default, then we can just use the alternative case when the optional is not present in
getNextRawDecodedOutputNoDemux()
:INT64_MIN
.