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

Extend decoding support #4480

Merged
merged 29 commits into from
Dec 13, 2022
Merged

Extend decoding support #4480

merged 29 commits into from
Dec 13, 2022

Conversation

awolant
Copy link
Contributor

@awolant awolant commented Nov 30, 2022

Category:

New feature

Description:

Adds ability for FramesDecoderGpu to decode raw H264 i H265 streams from memory.

Additional information:

Affected modules and functionalities:

FramesDecoderGpu and its tests. Some changes to its base class FramesDecoder were also necessary.

Key points relevant for the review:

Tests:

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

Checklist

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

JIRA TASK: DALI-3147

Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6696799]: BUILD FAILED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6696815]: BUILD FAILED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6703268]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6703268]: BUILD FAILED

Signed-off-by: Albert Wolant <awolant@nvidia.com>
@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6703703]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6703703]: BUILD FAILED

Signed-off-by: Albert Wolant <awolant@nvidia.com>
@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6704652]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6704652]: BUILD PASSED

Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6727772]: BUILD STARTED

CreateAvState(tmp_av_state, false);

while (av_read_frame(tmp_av_state->ctx_, tmp_av_state->packet_) >= 0) {
// We want to make sure that we call av_packet_unref in every iteration
Copy link
Contributor

@JanuszL JanuszL Dec 9, 2022

Choose a reason for hiding this comment

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

Do you think we can extract this to a function as the same pattern in applied in L291.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, called CountFrames.

if (ctx_->pb != nullptr) {
avio_context_free(&ctx_->pb);
}
avformat_close_input(&ctx_);
Copy link
Contributor

Choose a reason for hiding this comment

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

Based on https://ffmpeg.org/doxygen/trunk/demux_8c_source.html#l00369, 'avformat_close_input' seems to call avformat_free_context and avio_close which calls avio_context_free. Still please double check this in the version of FFmpeg we use (asan doesn't complain so I think we are not leaking anything).

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 did that based on the documentation that said that allocation of this context should be freed. Since in this scenario that we use it the wrapping object destructor takes care of it, I removed the call in our code.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that sometimes the examples and docs of FFmpeg are not fully accurate.

NVDECLease GetDecoder(CUVIDEOFORMAT *video_format) {
std::unique_lock lock(access_lock);

auto codec_type = video_format->codec;
unsigned height = video_format->display_area.bottom - video_format->display_area.top;
unsigned width = video_format->display_area.right - video_format->display_area.left;
unsigned height = video_format->coded_height;
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems to affect the decoding speed but it was the only way to get some decoders working 🤷

// If so, we need to return frame from the buffer before sending last packet.
if (frame_index_if_no_pts_ != 0) {
if (NumEmptySpots() < (piped_pts_.size())) {
for (size_t i = 0; i < frame_buffer_.size(); ++i) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible that we won't find desired frame in the frame_buffer_ as it has not been decoded yet?

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 think that theoretically, this can happen. The ultimately resilient solution for this issue I have found is to allocate spaces in the buffer dynamically as much as needed.
In practice, I have never encountered this issue yet, we have buffer big enough for the files that we have seen so far.

I would like to leave it as it is now. When we do decoupling mentioned above, we can revisit it and allow for buffer dynamic extension or something like that. Is that ok?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we can error in such case instead of silently returning the wrong result so the user can provide us with a failing sample and we can adjust?

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 think right now it should error out with Could not find empty slot in the frame buffer. It should try to find the next frame, fail to do it, than call for another frame, try to place it in the buffer and error out due to lack of empty spots.

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6727772]: BUILD PASSED

Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
Signed-off-by: Albert Wolant <awolant@nvidia.com>
@JanuszL JanuszL assigned JanuszL and unassigned stiepan Dec 12, 2022
Comment on lines +275 to +284
av_state->codec_ctx_ = avcodec_alloc_context3(av_state->codec_);
DALI_ENFORCE(av_state->codec_ctx_, "Could not alloc av codec context");

ret = avcodec_parameters_to_context(av_state->codec_ctx_, av_state->codec_params_);
DALI_ENFORCE(
ret >= 0,
make_string("Could not fill the codec based on parameters: ", detail::av_error_string(ret)));

av_state->packet_ = av_packet_alloc();
DALI_ENFORCE(av_state->packet_, "Could not allocate av packet");
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can replace it with InitAvState().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

CreateAvState covers some parts of the InitAvState and some parts of other functions. I would like to decouple the av state manipulation from this code altogether, so I will refactor it during that, if that is fine?

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

@awolant
Copy link
Contributor Author

awolant commented Dec 12, 2022

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6752073]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [6752073]: BUILD PASSED

@awolant awolant merged commit c7d6ddf into NVIDIA:main Dec 13, 2022
@JanuszL JanuszL mentioned this pull request Sep 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants