From 5beb9903491eab98e1a3112a384cbd0d66089b39 Mon Sep 17 00:00:00 2001 From: ameerj Date: Wed, 25 Nov 2020 17:10:44 -0500 Subject: Queue decoded frames, cleanup decoders --- src/video_core/command_classes/codecs/codec.cpp | 30 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'src/video_core/command_classes/codecs/codec.cpp') diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 1adf3cd135..1a19341c85 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -18,6 +18,11 @@ extern "C" { namespace Tegra { +void av_frame_deleter(AVFrame* ptr) { + av_frame_unref(ptr); + av_free(ptr); +} + Codec::Codec(GPU& gpu_) : gpu(gpu_), h264_decoder(std::make_unique(gpu)), vp9_decoder(std::make_unique(gpu)) {} @@ -27,7 +32,9 @@ Codec::~Codec() { return; } // Free libav memory + AVFrame* av_frame{nullptr}; avcodec_send_packet(av_codec_ctx, nullptr); + av_frame = av_frame_alloc(); avcodec_receive_frame(av_codec_ctx, av_frame); avcodec_flush_buffers(av_codec_ctx); @@ -60,7 +67,7 @@ void Codec::Decode() { } av_codec_ctx = avcodec_alloc_context3(av_codec); - av_frame = av_frame_alloc(); + av_codec_ctx->refcounted_frames = 1; av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0); // TODO(ameerj): libavcodec gpu hw acceleration @@ -68,8 +75,6 @@ void Codec::Decode() { const auto av_error = avcodec_open2(av_codec_ctx, av_codec, nullptr); if (av_error < 0) { LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed."); - av_frame_unref(av_frame); - av_free(av_frame); avcodec_close(av_codec_ctx); return; } @@ -96,16 +101,21 @@ void Codec::Decode() { if (!vp9_hidden_frame) { // Only receive/store visible frames - avcodec_receive_frame(av_codec_ctx, av_frame); + AVFramePtr frame = AVFramePtr{av_frame_alloc(), av_frame_deleter}; + avcodec_receive_frame(av_codec_ctx, frame.get()); + av_frames.push(std::move(frame)); } } -AVFrame* Codec::GetCurrentFrame() { - return av_frame; -} - -const AVFrame* Codec::GetCurrentFrame() const { - return av_frame; +AVFramePtr Codec::GetCurrentFrame() { + // Sometimes VIC will request more frames than have been decoded. + // in this case, return a nullptr and don't overwrite previous frame data + if (av_frames.size() > 0) { + AVFramePtr frame = std::move(av_frames.front()); + av_frames.pop(); + return frame; + } + return AVFramePtr{nullptr, av_frame_deleter}; } NvdecCommon::VideoCodec Codec::GetCurrentCodec() const { -- cgit v1.2.3 From aa2d90b35cc900f39c1cd1ae516a2dc87364429d Mon Sep 17 00:00:00 2001 From: ameerj Date: Thu, 26 Nov 2020 00:18:26 -0500 Subject: Address PR feedback remove some redundant moves, make deleter match naming guidelines. Co-Authored-By: LC <712067+lioncash@users.noreply.github.com> --- src/video_core/command_classes/codecs/codec.cpp | 15 ++++---- src/video_core/command_classes/codecs/codec.h | 4 +-- src/video_core/command_classes/codecs/vp9.cpp | 2 +- src/video_core/command_classes/codecs/vp9_types.h | 44 +++++++++++------------ 4 files changed, 33 insertions(+), 32 deletions(-) (limited to 'src/video_core/command_classes/codecs/codec.cpp') diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 1a19341c85..412e1e41cc 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -18,7 +18,7 @@ extern "C" { namespace Tegra { -void av_frame_deleter(AVFrame* ptr) { +void AVFrameDeleter(AVFrame* ptr) { av_frame_unref(ptr); av_free(ptr); } @@ -101,7 +101,7 @@ void Codec::Decode() { if (!vp9_hidden_frame) { // Only receive/store visible frames - AVFramePtr frame = AVFramePtr{av_frame_alloc(), av_frame_deleter}; + AVFramePtr frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter}; avcodec_receive_frame(av_codec_ctx, frame.get()); av_frames.push(std::move(frame)); } @@ -110,12 +110,13 @@ void Codec::Decode() { AVFramePtr Codec::GetCurrentFrame() { // Sometimes VIC will request more frames than have been decoded. // in this case, return a nullptr and don't overwrite previous frame data - if (av_frames.size() > 0) { - AVFramePtr frame = std::move(av_frames.front()); - av_frames.pop(); - return frame; + if (av_frames.empty()) { + return AVFramePtr{nullptr, AVFrameDeleter}; } - return AVFramePtr{nullptr, av_frame_deleter}; + + AVFramePtr frame = std::move(av_frames.front()); + av_frames.pop(); + return frame; } NvdecCommon::VideoCodec Codec::GetCurrentCodec() const { diff --git a/src/video_core/command_classes/codecs/codec.h b/src/video_core/command_classes/codecs/codec.h index c26b59fdec..0c6dde4058 100644 --- a/src/video_core/command_classes/codecs/codec.h +++ b/src/video_core/command_classes/codecs/codec.h @@ -23,8 +23,8 @@ namespace Tegra { class GPU; struct VicRegisters; -void av_frame_deleter(AVFrame* ptr); -using AVFramePtr = std::unique_ptr; +void AVFrameDeleter(AVFrame* ptr); +using AVFramePtr = std::unique_ptr; namespace Decoder { class H264; diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp index 31e00c27d7..b1d675cdbc 100644 --- a/src/video_core/command_classes/codecs/vp9.cpp +++ b/src/video_core/command_classes/codecs/vp9.cpp @@ -306,7 +306,7 @@ void VP9::WriteCoefProbabilityUpdate(VpxRangeEncoder& writer, s32 tx_mode, const std::array& old_prob) { constexpr u32 block_bytes = 2 * 2 * 6 * 6 * 3; - const auto needs_update = [&](u32 base_index) -> bool { + const auto needs_update = [&](u32 base_index) { return !std::equal(new_prob.begin() + base_index, new_prob.begin() + base_index + block_bytes, old_prob.begin() + base_index); diff --git a/src/video_core/command_classes/codecs/vp9_types.h b/src/video_core/command_classes/codecs/vp9_types.h index 5ca944f2ac..139501a1c6 100644 --- a/src/video_core/command_classes/codecs/vp9_types.h +++ b/src/video_core/command_classes/codecs/vp9_types.h @@ -245,33 +245,33 @@ struct EntropyProbs { std::array coef_probs{}; void Convert(Vp9EntropyProbs& fc) { - fc.inter_mode_prob = std::move(inter_mode_prob); - fc.intra_inter_prob = std::move(intra_inter_prob); - fc.tx_8x8_prob = std::move(tx_8x8_prob); - fc.tx_16x16_prob = std::move(tx_16x16_prob); - fc.tx_32x32_prob = std::move(tx_32x32_prob); + fc.inter_mode_prob = inter_mode_prob; + fc.intra_inter_prob = intra_inter_prob; + fc.tx_8x8_prob = tx_8x8_prob; + fc.tx_16x16_prob = tx_16x16_prob; + fc.tx_32x32_prob = tx_32x32_prob; - for (s32 i = 0; i < 4; i++) { - for (s32 j = 0; j < 9; j++) { + for (std::size_t i = 0; i < 4; i++) { + for (std::size_t j = 0; j < 9; j++) { fc.y_mode_prob[j + 9 * i] = j < 8 ? y_mode_prob_e0e7[i][j] : y_mode_prob_e8[i]; } } - fc.partition_prob = std::move(partition_prob); - fc.switchable_interp_prob = std::move(switchable_interp_prob); - fc.comp_inter_prob = std::move(comp_inter_prob); - fc.skip_probs = std::move(skip_probs); - fc.joints = std::move(joints); - fc.sign = std::move(sign); - fc.class_0 = std::move(class_0); - fc.fr = std::move(fr); - fc.class_0_hp = std::move(class_0_hp); - fc.high_precision = std::move(high_precision); - fc.classes = std::move(classes); - fc.class_0_fr = std::move(class_0_fr); - fc.prob_bits = std::move(pred_bits); - fc.single_ref_prob = std::move(single_ref_prob); - fc.comp_ref_prob = std::move(comp_ref_prob); + fc.partition_prob = partition_prob; + fc.switchable_interp_prob = switchable_interp_prob; + fc.comp_inter_prob = comp_inter_prob; + fc.skip_probs = skip_probs; + fc.joints = joints; + fc.sign = sign; + fc.class_0 = class_0; + fc.fr = fr; + fc.class_0_hp = class_0_hp; + fc.high_precision = high_precision; + fc.classes = classes; + fc.class_0_fr = class_0_fr; + fc.prob_bits = pred_bits; + fc.single_ref_prob = single_ref_prob; + fc.comp_ref_prob = comp_ref_prob; // Skip the 4th element as it goes unused for (std::size_t i = 0; i < coef_probs.size(); i += 4) { -- cgit v1.2.3 From 0a89ea1ca7c4eda5842b096c82b9a1750912b9b2 Mon Sep 17 00:00:00 2001 From: ameerj Date: Thu, 26 Nov 2020 14:04:06 -0500 Subject: Limit queue size to 10 frames Workaround for ZLA, which seems to decode and queue twice as many frames as it displays. --- src/video_core/command_classes/codecs/codec.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/video_core/command_classes/codecs/codec.cpp') diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index 412e1e41cc..9a88f64e48 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp @@ -104,6 +104,10 @@ void Codec::Decode() { AVFramePtr frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter}; avcodec_receive_frame(av_codec_ctx, frame.get()); av_frames.push(std::move(frame)); + // Limit queue to 10 frames. Workaround for ZLA decode and queue spam + if (av_frames.size() > 10) { + av_frames.pop(); + } } } -- cgit v1.2.3