diff options
| author | 2021-11-12 17:14:02 -0500 | |
|---|---|---|
| committer | 2021-11-12 23:52:18 -0500 | |
| commit | d35391b9f43c5099b000940a83e795827cea35b8 (patch) | |
| tree | 046b1ee7b8ea4b3f6b3e3d2194d9ea948bd835bd | |
| parent | codecs: Add VP8 codec class (diff) | |
| download | yuzu-d35391b9f43c5099b000940a83e795827cea35b8.tar.gz yuzu-d35391b9f43c5099b000940a83e795827cea35b8.tar.xz yuzu-d35391b9f43c5099b000940a83e795827cea35b8.zip | |
vp8: Implement header composition
Enables frame decoding with FFmpeg
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/command_classes/codecs/codec.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/command_classes/codecs/vp8.cpp | 41 | ||||
| -rw-r--r-- | src/video_core/command_classes/codecs/vp8.h | 46 | ||||
| -rw-r--r-- | src/video_core/command_classes/nvdec_common.h | 7 |
4 files changed, 90 insertions, 6 deletions
diff --git a/src/video_core/command_classes/codecs/codec.cpp b/src/video_core/command_classes/codecs/codec.cpp index fc3b8db99..cf5ede204 100644 --- a/src/video_core/command_classes/codecs/codec.cpp +++ b/src/video_core/command_classes/codecs/codec.cpp | |||
| @@ -185,7 +185,7 @@ void Codec::Decode() { | |||
| 185 | case Tegra::NvdecCommon::VideoCodec::H264: | 185 | case Tegra::NvdecCommon::VideoCodec::H264: |
| 186 | return h264_decoder->ComposeFrameHeader(state, is_first_frame); | 186 | return h264_decoder->ComposeFrameHeader(state, is_first_frame); |
| 187 | case Tegra::NvdecCommon::VideoCodec::VP8: | 187 | case Tegra::NvdecCommon::VideoCodec::VP8: |
| 188 | return vp8_decoder->ComposeFrameHeader(state, is_first_frame); | 188 | return vp8_decoder->ComposeFrameHeader(state); |
| 189 | case Tegra::NvdecCommon::VideoCodec::VP9: | 189 | case Tegra::NvdecCommon::VideoCodec::VP9: |
| 190 | vp9_decoder->ComposeFrameHeader(state); | 190 | vp9_decoder->ComposeFrameHeader(state); |
| 191 | vp9_hidden_frame = vp9_decoder->WasFrameHidden(); | 191 | vp9_hidden_frame = vp9_decoder->WasFrameHidden(); |
diff --git a/src/video_core/command_classes/codecs/vp8.cpp b/src/video_core/command_classes/codecs/vp8.cpp index 976e9f9b7..3ee269948 100644 --- a/src/video_core/command_classes/codecs/vp8.cpp +++ b/src/video_core/command_classes/codecs/vp8.cpp | |||
| @@ -6,15 +6,50 @@ | |||
| 6 | #include <vector> | 6 | #include <vector> |
| 7 | 7 | ||
| 8 | #include "video_core/command_classes/codecs/vp8.h" | 8 | #include "video_core/command_classes/codecs/vp8.h" |
| 9 | #include "video_core/gpu.h" | ||
| 10 | #include "video_core/memory_manager.h" | ||
| 9 | 11 | ||
| 10 | namespace Tegra::Decoder { | 12 | namespace Tegra::Decoder { |
| 11 | VP8::VP8(GPU& gpu_) : gpu(gpu_) {} | 13 | VP8::VP8(GPU& gpu_) : gpu(gpu_) {} |
| 12 | 14 | ||
| 13 | VP8::~VP8() = default; | 15 | VP8::~VP8() = default; |
| 14 | 16 | ||
| 15 | const std::vector<u8>& VP8::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state, | 17 | const std::vector<u8>& VP8::ComposeFrameHeader(const NvdecCommon::NvdecRegisters& state) { |
| 16 | bool is_first_frame) { | 18 | VP8PictureInfo info; |
| 17 | return {}; | 19 | gpu.MemoryManager().ReadBlock(state.picture_info_offset, &info, sizeof(VP8PictureInfo)); |
| 20 | |||
| 21 | const bool is_key_frame = info.key_frame == 1u; | ||
| 22 | const auto bitstream_size = static_cast<size_t>(info.vld_buffer_size); | ||
| 23 | const size_t header_size = is_key_frame ? 10u : 3u; | ||
| 24 | frame.resize(header_size + bitstream_size); | ||
| 25 | |||
| 26 | // Based on page 30 of the VP8 specification. | ||
| 27 | // https://datatracker.ietf.org/doc/rfc6386/ | ||
| 28 | frame[0] = is_key_frame ? 0u : 1u; // 1-bit frame type (0: keyframe, 1: interframes). | ||
| 29 | frame[0] |= static_cast<u8>((info.version & 7u) << 1u); // 3-bit version number | ||
| 30 | frame[0] |= static_cast<u8>(1u << 4u); // 1-bit show_frame flag | ||
| 31 | |||
| 32 | // The next 19-bits are the first partition size | ||
| 33 | frame[0] |= static_cast<u8>((info.first_part_size & 7u) << 5u); | ||
| 34 | frame[1] = static_cast<u8>((info.first_part_size & 0x7f8u) >> 3u); | ||
| 35 | frame[2] = static_cast<u8>((info.first_part_size & 0x7f800u) >> 11u); | ||
| 36 | |||
| 37 | if (is_key_frame) { | ||
| 38 | frame[3] = 0x9du; | ||
| 39 | frame[4] = 0x01u; | ||
| 40 | frame[5] = 0x2au; | ||
| 41 | // TODO(ameerj): Horizontal/Vertical Scale | ||
| 42 | // 16 bits: (2 bits Horizontal Scale << 14) | Width (14 bits) | ||
| 43 | frame[6] = static_cast<u8>(info.frame_width & 0xff); | ||
| 44 | frame[7] = static_cast<u8>(((info.frame_width >> 8) & 0x3f)); | ||
| 45 | // 16 bits:(2 bits Vertical Scale << 14) | Height (14 bits) | ||
| 46 | frame[8] = static_cast<u8>(info.frame_height & 0xff); | ||
| 47 | frame[9] = static_cast<u8>(((info.frame_height >> 8) & 0x3f)); | ||
| 48 | } | ||
| 49 | const u64 bitstream_offset = state.frame_bitstream_offset; | ||
| 50 | gpu.MemoryManager().ReadBlock(bitstream_offset, frame.data() + header_size, bitstream_size); | ||
| 51 | |||
| 52 | return frame; | ||
| 18 | } | 53 | } |
| 19 | 54 | ||
| 20 | } // namespace Tegra::Decoder | 55 | } // namespace Tegra::Decoder |
diff --git a/src/video_core/command_classes/codecs/vp8.h b/src/video_core/command_classes/codecs/vp8.h index 70c75f414..d71917596 100644 --- a/src/video_core/command_classes/codecs/vp8.h +++ b/src/video_core/command_classes/codecs/vp8.h | |||
| @@ -4,8 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 7 | #include <vector> | 8 | #include <vector> |
| 8 | 9 | ||
| 10 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 10 | #include "video_core/command_classes/nvdec_common.h" | 12 | #include "video_core/command_classes/nvdec_common.h" |
| 11 | 13 | ||
| @@ -20,11 +22,53 @@ public: | |||
| 20 | 22 | ||
| 21 | /// Compose the VP8 header of the frame for FFmpeg decoding | 23 | /// Compose the VP8 header of the frame for FFmpeg decoding |
| 22 | [[nodiscard]] const std::vector<u8>& ComposeFrameHeader( | 24 | [[nodiscard]] const std::vector<u8>& ComposeFrameHeader( |
| 23 | const NvdecCommon::NvdecRegisters& state, bool is_first_frame = false); | 25 | const NvdecCommon::NvdecRegisters& state); |
| 24 | 26 | ||
| 25 | private: | 27 | private: |
| 26 | std::vector<u8> frame; | 28 | std::vector<u8> frame; |
| 27 | GPU& gpu; | 29 | GPU& gpu; |
| 30 | |||
| 31 | struct VP8PictureInfo { | ||
| 32 | INSERT_PADDING_WORDS_NOINIT(14); | ||
| 33 | u16 frame_width; // actual frame width | ||
| 34 | u16 frame_height; // actual frame height | ||
| 35 | u8 key_frame; | ||
| 36 | u8 version; | ||
| 37 | union { | ||
| 38 | u8 raw; | ||
| 39 | BitField<0, 2, u8> tile_format; | ||
| 40 | BitField<2, 3, u8> gob_height; | ||
| 41 | BitField<5, 3, u8> reserverd_surface_format; | ||
| 42 | }; | ||
| 43 | u8 error_conceal_on; // 1: error conceal on; 0: off | ||
| 44 | u32 first_part_size; // the size of first partition(frame header and mb header partition) | ||
| 45 | u32 hist_buffer_size; // in units of 256 | ||
| 46 | u32 vld_buffer_size; // in units of 1 | ||
| 47 | // Current frame buffers | ||
| 48 | std::array<u32, 2> frame_stride; // [y_c] | ||
| 49 | u32 luma_top_offset; // offset of luma top field in units of 256 | ||
| 50 | u32 luma_bot_offset; // offset of luma bottom field in units of 256 | ||
| 51 | u32 luma_frame_offset; // offset of luma frame in units of 256 | ||
| 52 | u32 chroma_top_offset; // offset of chroma top field in units of 256 | ||
| 53 | u32 chroma_bot_offset; // offset of chroma bottom field in units of 256 | ||
| 54 | u32 chroma_frame_offset; // offset of chroma frame in units of 256 | ||
| 55 | |||
| 56 | INSERT_PADDING_BYTES_NOINIT(0x1c); // NvdecDisplayParams | ||
| 57 | |||
| 58 | // Decode picture buffer related | ||
| 59 | s8 current_output_memory_layout; | ||
| 60 | // output NV12/NV24 setting. index 0: golden; 1: altref; 2: last | ||
| 61 | std::array<s8, 3> output_memory_layout; | ||
| 62 | |||
| 63 | u8 segmentation_feature_data_update; | ||
| 64 | INSERT_PADDING_BYTES_NOINIT(3); | ||
| 65 | |||
| 66 | // ucode return result | ||
| 67 | u32 result_value; | ||
| 68 | std::array<u32, 8> partition_offset; | ||
| 69 | INSERT_PADDING_WORDS_NOINIT(3); | ||
| 70 | }; | ||
| 71 | static_assert(sizeof(VP8PictureInfo) == 0xc0, "PictureInfo is an invalid size"); | ||
| 28 | }; | 72 | }; |
| 29 | 73 | ||
| 30 | } // namespace Decoder | 74 | } // namespace Decoder |
diff --git a/src/video_core/command_classes/nvdec_common.h b/src/video_core/command_classes/nvdec_common.h index 26c974b00..8a35c44a1 100644 --- a/src/video_core/command_classes/nvdec_common.h +++ b/src/video_core/command_classes/nvdec_common.h | |||
| @@ -50,7 +50,10 @@ struct NvdecRegisters { | |||
| 50 | u64 h264_last_surface_chroma_offset; ///< 0x0858 | 50 | u64 h264_last_surface_chroma_offset; ///< 0x0858 |
| 51 | std::array<u64, 17> surface_luma_offset; ///< 0x0860 | 51 | std::array<u64, 17> surface_luma_offset; ///< 0x0860 |
| 52 | std::array<u64, 17> surface_chroma_offset; ///< 0x08E8 | 52 | std::array<u64, 17> surface_chroma_offset; ///< 0x08E8 |
| 53 | INSERT_PADDING_WORDS_NOINIT(132); ///< 0x0970 | 53 | INSERT_PADDING_WORDS_NOINIT(68); ///< 0x0970 |
| 54 | u64 vp8_prob_data_offset; ///< 0x0A80 | ||
| 55 | u64 vp8_header_partition_buf_offset; ///< 0x0A88 | ||
| 56 | INSERT_PADDING_WORDS_NOINIT(60); ///< 0x0A90 | ||
| 54 | u64 vp9_entropy_probs_offset; ///< 0x0B80 | 57 | u64 vp9_entropy_probs_offset; ///< 0x0B80 |
| 55 | u64 vp9_backward_updates_offset; ///< 0x0B88 | 58 | u64 vp9_backward_updates_offset; ///< 0x0B88 |
| 56 | u64 vp9_last_frame_segmap_offset; ///< 0x0B90 | 59 | u64 vp9_last_frame_segmap_offset; ///< 0x0B90 |
| @@ -81,6 +84,8 @@ ASSERT_REG_POSITION(h264_last_surface_luma_offset, 0x10A); | |||
| 81 | ASSERT_REG_POSITION(h264_last_surface_chroma_offset, 0x10B); | 84 | ASSERT_REG_POSITION(h264_last_surface_chroma_offset, 0x10B); |
| 82 | ASSERT_REG_POSITION(surface_luma_offset, 0x10C); | 85 | ASSERT_REG_POSITION(surface_luma_offset, 0x10C); |
| 83 | ASSERT_REG_POSITION(surface_chroma_offset, 0x11D); | 86 | ASSERT_REG_POSITION(surface_chroma_offset, 0x11D); |
| 87 | ASSERT_REG_POSITION(vp8_prob_data_offset, 0x150); | ||
| 88 | ASSERT_REG_POSITION(vp8_header_partition_buf_offset, 0x151); | ||
| 84 | ASSERT_REG_POSITION(vp9_entropy_probs_offset, 0x170); | 89 | ASSERT_REG_POSITION(vp9_entropy_probs_offset, 0x170); |
| 85 | ASSERT_REG_POSITION(vp9_backward_updates_offset, 0x171); | 90 | ASSERT_REG_POSITION(vp9_backward_updates_offset, 0x171); |
| 86 | ASSERT_REG_POSITION(vp9_last_frame_segmap_offset, 0x172); | 91 | ASSERT_REG_POSITION(vp9_last_frame_segmap_offset, 0x172); |