From b39b33b1fe1a396bb2f9841d48a1cb45cbfde806 Mon Sep 17 00:00:00 2001
From: ameerj <52414509+ameerj@users.noreply.github.com>
Date: Fri, 12 Nov 2021 19:28:21 -0500
Subject: [PATCH] codecs: Add VP8 codec class

---
 src/video_core/CMakeLists.txt                 |  2 ++
 .../command_classes/codecs/codec.cpp          | 34 +++++++++++++------
 src/video_core/command_classes/codecs/codec.h |  2 ++
 src/video_core/command_classes/codecs/vp8.cpp | 20 +++++++++++
 src/video_core/command_classes/codecs/vp8.h   | 31 +++++++++++++++++
 src/video_core/command_classes/codecs/vp9.cpp |  3 +-
 src/video_core/command_classes/codecs/vp9.h   | 11 +++---
 src/video_core/command_classes/nvdec.cpp      |  3 +-
 src/video_core/command_classes/nvdec_common.h |  4 +--
 9 files changed, 90 insertions(+), 20 deletions(-)
 create mode 100644 src/video_core/command_classes/codecs/vp8.cpp
 create mode 100644 src/video_core/command_classes/codecs/vp8.h

diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 269db21a57..6aac7f305d 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -15,6 +15,8 @@ add_library(video_core STATIC
     command_classes/codecs/codec.h
     command_classes/codecs/h264.cpp
     command_classes/codecs/h264.h
+    command_classes/codecs/vp8.cpp
+    command_classes/codecs/vp8.h
     command_classes/codecs/vp9.cpp
     command_classes/codecs/vp9.h
     command_classes/codecs/vp9_types.h
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp
index 61966cbfe8..fc3b8db998 100644
--- a/src/video_core/command_classes/codecs/codec.cpp
+++ b/src/video_core/command_classes/codecs/codec.cpp
@@ -8,6 +8,7 @@
 #include "common/settings.h"
 #include "video_core/command_classes/codecs/codec.h"
 #include "video_core/command_classes/codecs/h264.h"
+#include "video_core/command_classes/codecs/vp8.h"
 #include "video_core/command_classes/codecs/vp9.h"
 #include "video_core/gpu.h"
 #include "video_core/memory_manager.h"
@@ -46,6 +47,7 @@ void AVFrameDeleter(AVFrame* ptr) {
 
 Codec::Codec(GPU& gpu_, const NvdecCommon::NvdecRegisters& regs)
     : gpu(gpu_), state{regs}, h264_decoder(std::make_unique<Decoder::H264>(gpu)),
+      vp8_decoder(std::make_unique<Decoder::VP8>(gpu)),
       vp9_decoder(std::make_unique<Decoder::VP9>(gpu)) {}
 
 Codec::~Codec() {
@@ -135,7 +137,9 @@ void Codec::Initialize() {
         switch (current_codec) {
         case NvdecCommon::VideoCodec::H264:
             return AV_CODEC_ID_H264;
-        case NvdecCommon::VideoCodec::Vp9:
+        case NvdecCommon::VideoCodec::VP8:
+            return AV_CODEC_ID_VP8;
+        case NvdecCommon::VideoCodec::VP9:
             return AV_CODEC_ID_VP9;
         default:
             UNIMPLEMENTED_MSG("Unknown codec {}", current_codec);
@@ -176,19 +180,27 @@ void Codec::Decode() {
         return;
     }
     bool vp9_hidden_frame = false;
-    std::vector<u8> frame_data;
-    if (current_codec == NvdecCommon::VideoCodec::H264) {
-        frame_data = h264_decoder->ComposeFrameHeader(state, is_first_frame);
-    } else if (current_codec == NvdecCommon::VideoCodec::Vp9) {
-        frame_data = vp9_decoder->ComposeFrameHeader(state);
-        vp9_hidden_frame = vp9_decoder->WasFrameHidden();
-    }
+    const auto& frame_data = [&]() {
+        switch (current_codec) {
+        case Tegra::NvdecCommon::VideoCodec::H264:
+            return h264_decoder->ComposeFrameHeader(state, is_first_frame);
+        case Tegra::NvdecCommon::VideoCodec::VP8:
+            return vp8_decoder->ComposeFrameHeader(state, is_first_frame);
+        case Tegra::NvdecCommon::VideoCodec::VP9:
+            vp9_decoder->ComposeFrameHeader(state);
+            vp9_hidden_frame = vp9_decoder->WasFrameHidden();
+            return vp9_decoder->GetFrameBytes();
+        default:
+            UNREACHABLE();
+            return std::vector<u8>{};
+        }
+    }();
     AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter};
     if (!packet) {
         LOG_ERROR(Service_NVDRV, "av_packet_alloc failed");
         return;
     }
-    packet->data = frame_data.data();
+    packet->data = const_cast<u8*>(frame_data.data());
     packet->size = static_cast<s32>(frame_data.size());
     if (const int res = avcodec_send_packet(av_codec_ctx, packet.get()); res != 0) {
         LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", res);
@@ -252,11 +264,11 @@ std::string_view Codec::GetCurrentCodecName() const {
         return "None";
     case NvdecCommon::VideoCodec::H264:
         return "H264";
-    case NvdecCommon::VideoCodec::Vp8:
+    case NvdecCommon::VideoCodec::VP8:
         return "VP8";
     case NvdecCommon::VideoCodec::H265:
         return "H265";
-    case NvdecCommon::VideoCodec::Vp9:
+    case NvdecCommon::VideoCodec::VP9:
         return "VP9";
     default:
         return "Unknown";
diff --git a/src/video_core/command_classes/codecs/codec.h b/src/video_core/command_classes/codecs/codec.h
index f9a80886fc..13ed883821 100644
--- a/src/video_core/command_classes/codecs/codec.h
+++ b/src/video_core/command_classes/codecs/codec.h
@@ -29,6 +29,7 @@ using AVFramePtr = std::unique_ptr<AVFrame, decltype(&AVFrameDeleter)>;
 
 namespace Decoder {
 class H264;
+class VP8;
 class VP9;
 } // namespace Decoder
 
@@ -72,6 +73,7 @@ private:
     GPU& gpu;
     const NvdecCommon::NvdecRegisters& state;
     std::unique_ptr<Decoder::H264> h264_decoder;
+    std::unique_ptr<Decoder::VP8> vp8_decoder;
     std::unique_ptr<Decoder::VP9> vp9_decoder;
 
     std::queue<AVFramePtr> av_frames{};
diff --git a/src/video_core/command_classes/codecs/vp8.cpp b/src/video_core/command_classes/codecs/vp8.cpp
new file mode 100644
index 0000000000..976e9f9b72
--- /dev/null
+++ b/src/video_core/command_classes/codecs/vp8.cpp
@@ -0,0 +1,20 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <array>
+#include <vector>
+
+#include "video_core/command_classes/codecs/vp8.h"
+
+namespace Tegra::Decoder {
+VP8::VP8(GPU& gpu_) : gpu(gpu_) {}
+
+VP8::~VP8() = default;
+
+const std::vector<u8>& VP8::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state,
+                                               bool is_first_frame) {
+    return {};
+}
+
+} // namespace Tegra::Decoder
diff --git a/src/video_core/command_classes/codecs/vp8.h b/src/video_core/command_classes/codecs/vp8.h
new file mode 100644
index 0000000000..70c75f4144
--- /dev/null
+++ b/src/video_core/command_classes/codecs/vp8.h
@@ -0,0 +1,31 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+
+#include "common/common_types.h"
+#include "video_core/command_classes/nvdec_common.h"
+
+namespace Tegra {
+class GPU;
+namespace Decoder {
+
+class VP8 {
+public:
+    explicit VP8(GPU& gpu);
+    ~VP8();
+
+    /// Compose the VP8 header of the frame for FFmpeg decoding
+    [[nodiscard]] const std::vector<u8>& ComposeFrameHeader(
+        const NvdecCommon::NvdecRegisters& state, bool is_first_frame = false);
+
+private:
+    std::vector<u8> frame;
+    GPU& gpu;
+};
+
+} // namespace Decoder
+} // namespace Tegra
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp
index d7e7494851..269adc3f15 100644
--- a/src/video_core/command_classes/codecs/vp9.cpp
+++ b/src/video_core/command_classes/codecs/vp9.cpp
@@ -770,7 +770,7 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
     return uncomp_writer;
 }
 
-const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state) {
+void VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state) {
     std::vector<u8> bitstream;
     {
         Vp9FrameContainer curr_frame = GetCurrentFrame(state);
@@ -792,7 +792,6 @@ const std::vector<u8>& VP9::ComposeFrameHeader(const NvdecCommon::NvdecRegisters
               frame.begin() + uncompressed_header.size());
     std::copy(bitstream.begin(), bitstream.end(),
               frame.begin() + uncompressed_header.size() + compressed_header.size());
-    return frame;
 }
 
 VpxRangeEncoder::VpxRangeEncoder() {
diff --git a/src/video_core/command_classes/codecs/vp9.h b/src/video_core/command_classes/codecs/vp9.h
index e6e9fc17ef..6ab9ef5b51 100644
--- a/src/video_core/command_classes/codecs/vp9.h
+++ b/src/video_core/command_classes/codecs/vp9.h
@@ -116,16 +116,19 @@ public:
     VP9(VP9&&) = default;
     VP9& operator=(VP9&&) = delete;
 
-    /// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec
-    /// documentation
-    [[nodiscard]] const std::vector<u8>& ComposeFrameHeader(
-        const NvdecCommon::NvdecRegisters& state);
+    /// Composes the VP9 frame from the GPU state information.
+    /// Based on the official VP9 spec documentation
+    void ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state);
 
     /// Returns true if the most recent frame was a hidden frame.
     [[nodiscard]] bool WasFrameHidden() const {
         return !current_frame_info.show_frame;
     }
 
+    [[nodiscard]] const std::vector<u8>& GetFrameBytes() const {
+        return frame;
+    }
+
 private:
     /// Generates compressed header probability updates in the bitstream writer
     template <typename T, std::size_t N>
diff --git a/src/video_core/command_classes/nvdec.cpp b/src/video_core/command_classes/nvdec.cpp
index b5c55f14aa..9aaf5247ed 100644
--- a/src/video_core/command_classes/nvdec.cpp
+++ b/src/video_core/command_classes/nvdec.cpp
@@ -35,7 +35,8 @@ AVFramePtr Nvdec::GetFrame() {
 void Nvdec::Execute() {
     switch (codec->GetCurrentCodec()) {
     case NvdecCommon::VideoCodec::H264:
-    case NvdecCommon::VideoCodec::Vp9:
+    case NvdecCommon::VideoCodec::VP8:
+    case NvdecCommon::VideoCodec::VP9:
         codec->Decode();
         break;
     default:
diff --git a/src/video_core/command_classes/nvdec_common.h b/src/video_core/command_classes/nvdec_common.h
index 6a24e00a0c..26c974b002 100644
--- a/src/video_core/command_classes/nvdec_common.h
+++ b/src/video_core/command_classes/nvdec_common.h
@@ -13,9 +13,9 @@ namespace Tegra::NvdecCommon {
 enum class VideoCodec : u64 {
     None = 0x0,
     H264 = 0x3,
-    Vp8 = 0x5,
+    VP8 = 0x5,
     H265 = 0x7,
-    Vp9 = 0x9,
+    VP9 = 0x9,
 };
 
 // NVDEC should use a 32-bit address space, but is mapped to 64-bit,