From a832aa699f783f6ae0a6a1468b0aa6bc7d68c5d2 Mon Sep 17 00:00:00 2001
From: ameerj <52414509+ameerj@users.noreply.github.com>
Date: Sat, 7 Aug 2021 23:57:22 -0400
Subject: codec: Improve libav memory alloc and cleanup

---
 src/video_core/command_classes/codecs/codec.cpp | 31 ++++++++++++++-----------
 src/video_core/command_classes/codecs/codec.h   |  2 ++
 2 files changed, 19 insertions(+), 14 deletions(-)

(limited to 'src')

diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp
index 400834129e..18aa40ca3c 100644
--- a/src/video_core/command_classes/codecs/codec.cpp
+++ b/src/video_core/command_classes/codecs/codec.cpp
@@ -20,6 +20,12 @@ namespace {
 constexpr AVPixelFormat PREFERRED_GPU_FMT = AV_PIX_FMT_NV12;
 constexpr AVPixelFormat PREFERRED_CPU_FMT = AV_PIX_FMT_YUV420P;
 
+void AVPacketDeleter(AVPacket* ptr) {
+    av_packet_free(&ptr);
+}
+
+using AVPacketPtr = std::unique_ptr<AVPacket, decltype(&AVPacketDeleter)>;
+
 AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pix_fmts) {
     for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
         if (*p == av_codec_ctx->pix_fmt) {
@@ -46,11 +52,7 @@ Codec::~Codec() {
         return;
     }
     // Free libav memory
-    avcodec_send_packet(av_codec_ctx, nullptr);
-    AVFramePtr av_frame{av_frame_alloc(), AVFrameDeleter};
-    avcodec_receive_frame(av_codec_ctx, av_frame.get());
-    avcodec_flush_buffers(av_codec_ctx);
-    avcodec_close(av_codec_ctx);
+    avcodec_free_context(&av_codec_ctx);
     av_buffer_unref(&av_gpu_decoder);
 }
 
@@ -111,6 +113,11 @@ bool Codec::CreateGpuAvDevice() {
     return false;
 }
 
+void Codec::InitializeAvCodecContext() {
+    av_codec_ctx = avcodec_alloc_context3(av_codec);
+    av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
+}
+
 void Codec::InitializeGpuDecoder() {
     if (!CreateGpuAvDevice()) {
         av_buffer_unref(&av_gpu_decoder);
@@ -135,13 +142,11 @@ void Codec::Initialize() {
         }
     }();
     av_codec = avcodec_find_decoder(codec);
-    av_codec_ctx = avcodec_alloc_context3(av_codec);
-    av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
-
+    InitializeAvCodecContext();
     InitializeGpuDecoder();
     if (const int res = avcodec_open2(av_codec_ctx, av_codec, nullptr); res < 0) {
         LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed with result {}", res);
-        avcodec_close(av_codec_ctx);
+        avcodec_free_context(&av_codec_ctx);
         av_buffer_unref(&av_gpu_decoder);
         return;
     }
@@ -174,17 +179,15 @@ void Codec::Decode() {
         frame_data = vp9_decoder->ComposeFrameHeader(state);
         vp9_hidden_frame = vp9_decoder->WasFrameHidden();
     }
-    AVPacket* packet = av_packet_alloc();
+    AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter};
     if (!packet) {
         LOG_ERROR(Service_NVDRV, "av_packet_alloc failed");
         return;
     }
     packet->data = frame_data.data();
     packet->size = static_cast<s32>(frame_data.size());
-    const int send_pkt_ret = avcodec_send_packet(av_codec_ctx, packet);
-    av_packet_free(&packet);
-    if (send_pkt_ret != 0) {
-        LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", send_pkt_ret);
+    if (const int res = avcodec_send_packet(av_codec_ctx, packet.get()); res != 0) {
+        LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", res);
         return;
     }
     // Only receive/store visible frames
diff --git a/src/video_core/command_classes/codecs/codec.h b/src/video_core/command_classes/codecs/codec.h
index f51ab9df02..1508d36c2b 100644
--- a/src/video_core/command_classes/codecs/codec.h
+++ b/src/video_core/command_classes/codecs/codec.h
@@ -55,6 +55,8 @@ public:
     [[nodiscard]] std::string_view GetCurrentCodecName() const;
 
 private:
+    void InitializeAvCodecContext();
+
     void InitializeGpuDecoder();
 
     bool CreateGpuAvDevice();
-- 
cgit v1.2.3-70-g09d2