Skip to content
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

Fix HEVC video handling #3247

Merged
merged 4 commits into from
Aug 31, 2021
Merged

Fix HEVC video handling #3247

merged 4 commits into from
Aug 31, 2021

Conversation

JanuszL
Copy link
Contributor

@JanuszL JanuszL commented Aug 12, 2021

  • it seems that preceding frames may appear after the following
    keyframe so the logic that stops sending frames to the decoder
    assuming that each keyframe is IDR doesn't work anymore. Improve
    the logic to stop after seeing the next keyframe as it should be
    very unlikely to have a frame from two keyframes behind
  • adds HEVC test

Signed-off-by: Janusz Lisiecki jlisiecki@nvidia.com

Description

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactoring (Redesign of existing code that doesn't affect functionality)
  • Other (e.g. Documentation, Tests, Configuration)

What happened in this PR

  • it seems that preceding frames may appear after the following
    keyframe so the logic that stops sending frames to the decoder
    assuming that each keyframe is IDR doesn't work anymore. Improve
    the logic to stop after seeing the next keyframe as it should be
    very unlikely to have a frame from two keyframes behind

Additional information

  • Affected modules and functionalities:
    • video_loader.cc
    • video_reader_op_test.cc
  • Key points relevant for the review:
    • NA

Checklist

Tests

  • Existing tests apply
  • New tests added
    • Python tests
    • GTests
    • Benchmark
    • Other
  • N/A

Documentation

  • Existing documentation applies
  • Documentation updated
    • Docstring
    • Doxygen
    • RST
    • Jupyter
    • Other
  • N/A

DALI team only

Requirements

  • Implements new requirements
  • Affects existing requirements
  • N/A

REQ IDs: N/A

Relates to #3243
JIRA TASK: DALI-2243

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2749122]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2749122]: BUILD FAILED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2749188]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2749188]: BUILD PASSED

@JanuszL
Copy link
Contributor Author

JanuszL commented Aug 12, 2021

NVIDIA/DALI_extra#65 is a prerequisite.

Copy link
Contributor

@klecki klecki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some counter how many key frames we've seen and the required number as a constant would feel more natural.

Also, doesn't this impact performance? Shouldn't we do this based on the format that we are dealing with?

@JanuszL
Copy link
Contributor Author

JanuszL commented Aug 13, 2021

I think some counter how many key frames we've seen and the required number as a constant would feel more natural.

I can add it.

Also, doesn't this impact performance?

It may but I don't see any other way to fix that.

Shouldn't we do this based on the format that we are dealing with?

Probably but I don't have sufficient knowledge which one needs that.

@JanuszL
Copy link
Contributor Author

JanuszL commented Aug 13, 2021

Anyway done.

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2760006]: BUILD STARTED

Copy link
Contributor

@klecki klecki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I understand this correctly. Is the req.count the distance between keyframes? If so, there is a bug and we can simplify.

@@ -533,6 +533,11 @@ void VideoLoader::read_file() {
bool is_first_frame = true;
bool key = false;
bool seek_must_succeed = false;
// how many key frames following the last requested frames we need to see so far
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// how many key frames following the last requested frames we need to see so far
// how many key frames following the last requested frames we saw so far

int key_frames_count = 0;
// how many key frames following the last requested frames we need to see before we stop
// feeding the decoder
const int key_frames_treshold = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we want to see two, so I would probably write here 2, and use greater equal, but it's a nitpick:

Suggested change
const int key_frames_treshold = 1;
const int key_frames_treshold = 2;

@@ -585,10 +590,16 @@ void VideoLoader::read_file() {
if (!is_first_frame) {
nonkey_frame_count = 0;
if (frame > req.frame + req.count) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we check for:

Suggested change
if (frame > req.frame + req.count) {
if (frame > req.frame + (1 + key_frames_count) * req.count) {

or something?
I mean, if key frame is every req.count (just guessing), we need to see the multiple of the distance to detect key frame.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, keyframe is the video stream property and it doesn't have to be equally placed in the video. req.count is how many frames we need to decode to between first and the last frame in the sequence.

Comment on lines 592 to 603
if (frame > req.frame + req.count) {
// Found a key frame past the requested range. We can stop searching
// Found a second key frame past the requested range. We can stop searching
// (If there were missing frames in the range they won't be found after
// the next key frame)
break;
// in case HEVC it seems that preceding frames can appear after a given key frame
// but rather not after the next one
if (key_frames_count > key_frames_treshold) {
key_frames_count = 0;
break;
}
++key_frames_count;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If my comment is right, this can be replaced with (note the 2):

const int key_frames_treshold = 2;

if (frame > req.frame + key_frames_treshold * req.count) {
   break;
}

Which is probably simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key_frames_treshold * req.count doesn't make any sense. req.count has nothing to do with keyframes.

@JanuszL
Copy link
Contributor Author

JanuszL commented Aug 13, 2021

I'm not sure if I understand this correctly. Is the req.count the distance between keyframes? If so, there is a bug and we can simplify.

It is the number of frames between the first and the last in the sequence including stride.

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2760331]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2760006]: BUILD PASSED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2760331]: BUILD PASSED

int key_frames_count = 0;
// how many key frames following the last requested frames we need to see before we stop
// feeding the decoder
const int key_frames_treshold = 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we infer this from the file info somehow? I think that there are relatively few formats that support bidirectional prediction - for others, that's just waste of time.
Even in case of HEVC, I think that you don't need the whole interval between keyframes - just from the keyframe to the requested frame (in forward prediction) and from the requested frame to the keyframe (in reverse prediction) - but determining which keyframe is relevant might be non-trivial.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add check only for HEVC but I'm not aware of any simple way to determine what kind of prediction is used in a given stream - I afraid it would require parsing headers/stream on our own what is much beyond the scope of this task.

Even in case of HEVC, I think that you don't need the whole interval between keyframes - just from the keyframe to the requested frame (in forward prediction) and from the requested frame to the keyframe (in reverse prediction) - but determining which keyframe is relevant might be non-trivial.

In some cases we don't get any meaningful timestamp from the frame we read from the stream. So it may not work at all.

@mzient
Copy link
Contributor

mzient commented Aug 16, 2021

Please rename the PR from "Improve" to "Fix" - after all, before this PR it just doesn't work for some valid HEVC videos.

@JanuszL JanuszL changed the title Improve HEVC video handling Fix HEVC video handling Aug 30, 2021
- it seems that preceding frames may appear after the following
  keyframe so the logic that stops sending frames to the decoder
  assuming that each keyframe is IDR doesn't work anymore. Improve
  the logic to stop after seeing the next keyframe as it should be
  very unlikely to have a frame from two keyframes behind
- adds HEVC test

Signed-off-by: Janusz Lisiecki <jlisiecki@nvidia.com>
Signed-off-by: Janusz Lisiecki <jlisiecki@nvidia.com>
Signed-off-by: Janusz Lisiecki <jlisiecki@nvidia.com>
Signed-off-by: Janusz Lisiecki <jlisiecki@nvidia.com>
@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2877236]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2877236]: BUILD PASSED

@JanuszL JanuszL merged commit e2ebfe7 into NVIDIA:main Aug 31, 2021
@JanuszL JanuszL deleted the improve_hevc_handling branch August 31, 2021 08:01
@JanuszL JanuszL added the important-fix Fixes an important issue in the software or development environment. label Sep 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
important-fix Fixes an important issue in the software or development environment.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants