-
Notifications
You must be signed in to change notification settings - Fork 66
Add sort and dedup logic in C++ to getFramesAtIndices
#280
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
Changes from all commits
823c8a3
61b4937
f7a70ba
133c213
f391582
b8284cc
d1f5645
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1034,24 +1034,57 @@ VideoDecoder::BatchDecodedOutput VideoDecoder::getFramesAtIndices( | |
| validateUserProvidedStreamIndex(streamIndex); | ||
| validateScannedAllStreams("getFramesAtIndices"); | ||
|
|
||
| auto indicesAreSorted = | ||
| std::is_sorted(frameIndices.begin(), frameIndices.end()); | ||
|
|
||
| std::vector<size_t> argsort; | ||
| if (!indicesAreSorted) { | ||
| // if frameIndices is [13, 10, 12, 11] | ||
| // when sorted, it's [10, 11, 12, 13] <-- this is the sorted order we want | ||
| // to use to decode the frames | ||
| // and argsort is [ 1, 3, 2, 0] | ||
| argsort.resize(frameIndices.size()); | ||
| for (size_t i = 0; i < argsort.size(); ++i) { | ||
| argsort[i] = i; | ||
| } | ||
| std::sort( | ||
| argsort.begin(), argsort.end(), [&frameIndices](size_t a, size_t b) { | ||
| return frameIndices[a] < frameIndices[b]; | ||
| }); | ||
| } | ||
|
|
||
| const auto& streamMetadata = containerMetadata_.streams[streamIndex]; | ||
| const auto& stream = streams_[streamIndex]; | ||
| const auto& options = stream.options; | ||
| BatchDecodedOutput output(frameIndices.size(), options, streamMetadata); | ||
|
|
||
| auto previousIndexInVideo = -1; | ||
| for (auto f = 0; f < frameIndices.size(); ++f) { | ||
| auto frameIndex = frameIndices[f]; | ||
| if (frameIndex < 0 || frameIndex >= stream.allFrames.size()) { | ||
| auto indexInOutput = indicesAreSorted ? f : argsort[f]; | ||
| auto indexInVideo = frameIndices[indexInOutput]; | ||
| if (indexInVideo < 0 || indexInVideo >= stream.allFrames.size()) { | ||
| throw std::runtime_error( | ||
| "Invalid frame index=" + std::to_string(frameIndex)); | ||
| "Invalid frame index=" + std::to_string(indexInVideo)); | ||
| } | ||
| DecodedOutput singleOut = | ||
| getFrameAtIndex(streamIndex, frameIndex, output.frames[f]); | ||
| if (options.colorConversionLibrary == ColorConversionLibrary::FILTERGRAPH) { | ||
| output.frames[f] = singleOut.frame; | ||
| if ((f > 0) && (indexInVideo == previousIndexInVideo)) { | ||
| // Avoid decoding the same frame twice | ||
| auto previousIndexInOutput = indicesAreSorted ? f - 1 : argsort[f - 1]; | ||
| output.frames[indexInOutput].copy_(output.frames[previousIndexInOutput]); | ||
| output.ptsSeconds[indexInOutput] = | ||
| output.ptsSeconds[previousIndexInOutput]; | ||
| output.durationSeconds[indexInOutput] = | ||
| output.durationSeconds[previousIndexInOutput]; | ||
| } else { | ||
| DecodedOutput singleOut = getFrameAtIndex( | ||
| streamIndex, indexInVideo, output.frames[indexInOutput]); | ||
| if (options.colorConversionLibrary == | ||
| ColorConversionLibrary::FILTERGRAPH) { | ||
| output.frames[indexInOutput] = singleOut.frame; | ||
| } | ||
|
Comment on lines
+1080
to
+1083
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this needed when we are passing output.frames[indexInOutput] in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's because the pre-allocated buffer isn't used with filtergraph, only with swscale. (Just a note that this is not something that was introduced in this PR, you'll see the same pattern in other callers)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like the wrong behavior. When a user passes in a pre-allocated tensor it should work with either color conversion library. I guess this behavior is introduced by the PR to add pre-allocated tensor. That PR should have done it for either color conversion library. Maybe make that change first before merging in this PR? That would be my vote because otherwise the caller has to think about what color conversion library was used.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| output.ptsSeconds[indexInOutput] = singleOut.ptsSeconds; | ||
| output.durationSeconds[indexInOutput] = singleOut.durationSeconds; | ||
| } | ||
| // Note that for now we ignore the pts and duration parts of the output, | ||
| // because they're never used in any caller. | ||
| previousIndexInVideo = indexInVideo; | ||
| } | ||
| output.frames = MaybePermuteHWC2CHW(options, output.frames); | ||
| return output; | ||
|
|
||
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.
Digging a bit, I think we're probably better off not checking to see if the sequence is already sorted, and just always sorting. Modern implementations of
std::sortseem to be Introsort, which was designed to be nearly linear with an already sorted sequence. I'm also fine if we commit this as is. We can always investigate more later if it becomes important.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.
Nit: I like to keep object definitions as close as possible to their initial use. So I'd prefer to see lines 1037-1040 appear after the sorting, right before we use
outputin the loop. (I just ran into this trying to find the definition of whatoutputis when reading the loop.)