diff options
Diffstat (limited to 'src/video_core/host1x/codecs')
| -rw-r--r-- | src/video_core/host1x/codecs/codec.cpp | 165 | ||||
| -rw-r--r-- | src/video_core/host1x/codecs/codec.h | 70 | ||||
| -rwxr-xr-x | src/video_core/host1x/codecs/decoder.cpp | 105 | ||||
| -rwxr-xr-x | src/video_core/host1x/codecs/decoder.h | 73 |
4 files changed, 207 insertions, 206 deletions
diff --git a/src/video_core/host1x/codecs/codec.cpp b/src/video_core/host1x/codecs/codec.cpp index 1030db681..be7e6c6b1 100644 --- a/src/video_core/host1x/codecs/codec.cpp +++ b/src/video_core/host1x/codecs/codec.cpp @@ -12,102 +12,111 @@ namespace Tegra { -Codec::Codec(Host1x::Host1x& host1x_, const Host1x::NvdecCommon::NvdecRegisters& regs) + Codec::Codec(Host1x::Host1x& host1x_, const Host1x::NvdecCommon::NvdecRegisters& regs) : host1x(host1x_), state{regs}, h264_decoder(std::make_unique<Decoder::H264>(host1x)), - vp8_decoder(std::make_unique<Decoder::VP8>(host1x)), - vp9_decoder(std::make_unique<Decoder::VP9>(host1x)) {} + vp8_decoder(std::make_unique<Decoder::VP8>(host1x)), + vp9_decoder(std::make_unique<Decoder::VP9>(host1x)) {} -Codec::~Codec() = default; + Codec::~Codec() = default; -void Codec::Initialize() { - initialized = decode_api.Initialize(current_codec); -} - -void Codec::SetTargetCodec(Host1x::NvdecCommon::VideoCodec codec) { - if (current_codec != codec) { - current_codec = codec; - LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", GetCurrentCodecName()); + void Codec::Initialize() { + initialized = decode_api.Initialize(current_codec); } -} -void Codec::Decode() { - const bool is_first_frame = !initialized; - if (is_first_frame) { - Initialize(); + void Codec::SetTargetCodec(Host1x::NvdecCommon::VideoCodec codec) { + if (current_codec != codec) { + current_codec = codec; + LOG_INFO(Service_NVDRV, "NVDEC video codec initialized to {}", GetCurrentCodecName()); + } } - if (!initialized) { - return; - } + void Codec::Decode() { + const bool is_first_frame = !initialized; + if (is_first_frame) { + Initialize(); + } - // Assemble bitstream. - bool vp9_hidden_frame = false; - size_t configuration_size = 0; - const auto packet_data = [&]() { - switch (current_codec) { - case Tegra::Host1x::NvdecCommon::VideoCodec::H264: - return h264_decoder->ComposeFrame(state, &configuration_size, is_first_frame); - case Tegra::Host1x::NvdecCommon::VideoCodec::VP8: - return vp8_decoder->ComposeFrame(state); - case Tegra::Host1x::NvdecCommon::VideoCodec::VP9: - vp9_decoder->ComposeFrame(state); - vp9_hidden_frame = vp9_decoder->WasFrameHidden(); - return vp9_decoder->GetFrameBytes(); - default: - ASSERT(false); - return std::span<const u8>{}; + if (!initialized) { + return; } - }(); - // Send assembled bitstream to decoder. - if (!decode_api.SendPacket(packet_data, configuration_size)) { - return; - } + // Assemble bitstream. + bool vp9_hidden_frame = false; + size_t configuration_size = 0; + const auto packet_data = [&]() { + switch (current_codec) { + case Tegra::Host1x::NvdecCommon::VideoCodec::H264: + return h264_decoder->ComposeFrame(state, &configuration_size, is_first_frame); + case Tegra::Host1x::NvdecCommon::VideoCodec::VP8: + return vp8_decoder->ComposeFrame(state); + case Tegra::Host1x::NvdecCommon::VideoCodec::VP9: + vp9_decoder->ComposeFrame(state); + vp9_hidden_frame = vp9_decoder->WasFrameHidden(); + return vp9_decoder->GetFrameBytes(); + default: + ASSERT(false); + return std::span<const u8>{}; + } + }(); + + // Send assembled bitstream to decoder. + if (!decode_api.SendPacket(packet_data, configuration_size)) { + return; + } - // Only receive/store visible frames. - if (vp9_hidden_frame) { - return; + // Only receive/store visible frames. + if (vp9_hidden_frame) { + return; + } + + // Receive output frames from decoder. + // The previous code called decode_api.ReceiveFrames(frames); which would queue multiple frames. + // Given the previous refactoring of FFmpeg::DecodeApi to only have ReceiveFrame(), + // this needs to be adapted to potentially call ReceiveFrame multiple times until EAGAIN/EOF. + // For now, I'll adapt it to receive one frame and push it. If more complex frame queuing + // behavior is expected by the `frames` queue, then `ReceiveFrame()` would need to be + // called in a loop until it returns `nullptr` (indicating EAGAIN or EOF). + auto frame = decode_api.ReceiveFrame(); + if (frame) { + frames.push(std::move(frame)); + } + + while (frames.size() > 10) { + LOG_DEBUG(HW_GPU, "ReceiveFrames overflow, dropped frame"); + frames.pop(); + } } - // Receive output frames from decoder. - decode_api.ReceiveFrames(frames); + std::unique_ptr<FFmpeg::Frame> Codec::GetCurrentFrame() { + // Sometimes VIC will request more frames than have been decoded. + // in this case, return a blank frame and don't overwrite previous data. + if (frames.empty()) { + return {}; + } - while (frames.size() > 10) { - LOG_DEBUG(HW_GPU, "ReceiveFrames overflow, dropped frame"); + auto frame = std::move(frames.front()); frames.pop(); + return frame; } -} -std::unique_ptr<FFmpeg::Frame> Codec::GetCurrentFrame() { - // Sometimes VIC will request more frames than have been decoded. - // in this case, return a blank frame and don't overwrite previous data. - if (frames.empty()) { - return {}; + Host1x::NvdecCommon::VideoCodec Codec::GetCurrentCodec() const { + return current_codec; } - auto frame = std::move(frames.front()); - frames.pop(); - return frame; -} - -Host1x::NvdecCommon::VideoCodec Codec::GetCurrentCodec() const { - return current_codec; -} - -std::string_view Codec::GetCurrentCodecName() const { - switch (current_codec) { - case Host1x::NvdecCommon::VideoCodec::None: - return "None"; - case Host1x::NvdecCommon::VideoCodec::H264: - return "H264"; - case Host1x::NvdecCommon::VideoCodec::VP8: - return "VP8"; - case Host1x::NvdecCommon::VideoCodec::H265: - return "H265"; - case Host1x::NvdecCommon::VideoCodec::VP9: - return "VP9"; - default: - return "Unknown"; + std::string_view Codec::GetCurrentCodecName() const { + switch (current_codec) { + case Host1x::NvdecCommon::VideoCodec::None: + return "None"; + case Host1x::NvdecCommon::VideoCodec::H264: + return "H264"; + case Host1x::NvdecCommon::VideoCodec::VP8: + return "VP8"; + case Host1x::NvdecCommon::VideoCodec::H265: + return "H265"; + case Host1x::NvdecCommon::VideoCodec::VP9: + return "VP9"; + default: + return "Unknown"; + } } -} } // namespace Tegra diff --git a/src/video_core/host1x/codecs/codec.h b/src/video_core/host1x/codecs/codec.h index f700ae129..c3622af57 100644 --- a/src/video_core/host1x/codecs/codec.h +++ b/src/video_core/host1x/codecs/codec.h @@ -13,51 +13,51 @@ namespace Tegra { -namespace Decoder { -class H264; -class VP8; -class VP9; -} // namespace Decoder + namespace Decoder { + class H264; + class VP8; + class VP9; + } // namespace Decoder -namespace Host1x { -class Host1x; -} // namespace Host1x + namespace Host1x { + class Host1x; + } // namespace Host1x -class Codec { -public: - explicit Codec(Host1x::Host1x& host1x, const Host1x::NvdecCommon::NvdecRegisters& regs); - ~Codec(); + class Codec { + public: + explicit Codec(Host1x::Host1x& host1x, const Host1x::NvdecCommon::NvdecRegisters& regs); + ~Codec(); - /// Initialize the codec, returning success or failure - void Initialize(); + /// Initialize the codec, returning success or failure + void Initialize(); - /// Sets NVDEC video stream codec - void SetTargetCodec(Host1x::NvdecCommon::VideoCodec codec); + /// Sets NVDEC video stream codec + void SetTargetCodec(Host1x::NvdecCommon::VideoCodec codec); - /// Call decoders to construct headers, decode AVFrame with ffmpeg - void Decode(); + /// Call decoders to construct headers, decode AVFrame with ffmpeg + void Decode(); - /// Returns next decoded frame - [[nodiscard]] std::unique_ptr<FFmpeg::Frame> GetCurrentFrame(); + /// Returns next decoded frame + [[nodiscard]] std::unique_ptr<FFmpeg::Frame> GetCurrentFrame(); - /// Returns the value of current_codec - [[nodiscard]] Host1x::NvdecCommon::VideoCodec GetCurrentCodec() const; + /// Returns the value of current_codec + [[nodiscard]] Host1x::NvdecCommon::VideoCodec GetCurrentCodec() const; - /// Return name of the current codec - [[nodiscard]] std::string_view GetCurrentCodecName() const; + /// Return name of the current codec + [[nodiscard]] std::string_view GetCurrentCodecName() const; -private: - bool initialized{}; - Host1x::NvdecCommon::VideoCodec current_codec{Host1x::NvdecCommon::VideoCodec::None}; - FFmpeg::DecodeApi decode_api; + private: + bool initialized{}; + Host1x::NvdecCommon::VideoCodec current_codec{Host1x::NvdecCommon::VideoCodec::None}; + FFmpeg::DecodeApi decode_api; - Host1x::Host1x& host1x; - const Host1x::NvdecCommon::NvdecRegisters& state; - std::unique_ptr<Decoder::H264> h264_decoder; - std::unique_ptr<Decoder::VP8> vp8_decoder; - std::unique_ptr<Decoder::VP9> vp9_decoder; + Host1x::Host1x& host1x; + const Host1x::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<std::unique_ptr<FFmpeg::Frame>> frames{}; -}; + std::queue<std::unique_ptr<FFmpeg::Frame>> frames{}; + }; } // namespace Tegra diff --git a/src/video_core/host1x/codecs/decoder.cpp b/src/video_core/host1x/codecs/decoder.cpp index 49a601969..69371f610 100755 --- a/src/video_core/host1x/codecs/decoder.cpp +++ b/src/video_core/host1x/codecs/decoder.cpp @@ -9,63 +9,54 @@ namespace Tegra { -Decoder::Decoder(Host1x::Host1x& host1x_, s32 id_, const Host1x::NvdecCommon::NvdecRegisters& regs_, - Host1x::FrameQueue& frame_queue_) + Decoder::Decoder(Host1x::Host1x& host1x_, s32 id_, const Host1x::NvdecCommon::NvdecRegisters& regs_, + Host1x::FrameQueue& frame_queue_) : host1x(host1x_), memory_manager{host1x.GMMU()}, regs{regs_}, id{id_}, frame_queue{ - frame_queue_} {} - -Decoder::~Decoder() = default; - -void Decoder::Decode() { - if (!initialized) { - return; - } - - const auto packet_data = ComposeFrame(); - // Send assembled bitstream to decoder. - if (!decode_api.SendPacket(packet_data)) { - return; - } - - // Only receive/store visible frames. - if (vp9_hidden_frame) { - return; - } - - // Receive output frames from decoder. - auto frame = decode_api.ReceiveFrame(); - - if (IsInterlaced()) { - auto [luma_top, luma_bottom, chroma_top, chroma_bottom] = GetInterlacedOffsets(); - auto frame_copy = frame; - - if (!frame.get()) { - LOG_ERROR(HW_GPU, - "Nvdec {} dailed to decode interlaced frame for top 0x{:X} bottom 0x{:X}", id, - luma_top, luma_bottom); + frame_queue_} {} + + Decoder::~Decoder() = default; + + void Decoder::Decode() { + if (!initialized) { + return; + } + + const auto packet_data = ComposeFrame(); + + // Capture the state needed for queuing BEFORE sending the packet + // and potentially yielding. The main `regs` and `current_context` can be + // overwritten by the time FFmpeg returns a frame. + const bool is_interlaced_frame = IsInterlaced(); + const auto interlaced_offsets = GetInterlacedOffsets(); + const auto progressive_offsets = GetProgressiveOffsets(); + + // Send assembled bitstream to decoder. + if (!decode_api.SendPacket(packet_data)) { + return; + } + + // Only process visible frames. + if (vp9_hidden_frame) { + return; + } + + // Receive output frames from decoder. + // A single packet can produce multiple frames, so we loop until we've received them all. + while (true) { + auto frame = decode_api.ReceiveFrame(); + if (!frame) { // No more frames available for now. + break; + } + + if (is_interlaced_frame) { + auto [luma_top, luma_bottom, chroma_top, chroma_bottom] = interlaced_offsets; + auto frame_copy = frame; + frame_queue.PushDecodeOrder(id, luma_top, std::move(frame)); + frame_queue.PushDecodeOrder(id, luma_bottom, std::move(frame_copy)); + } else { + auto [luma_offset, chroma_offset] = progressive_offsets; + frame_queue.PushDecodeOrder(id, luma_offset, std::move(frame)); + } + } } - - if (UsingDecodeOrder()) { - frame_queue.PushDecodeOrder(id, luma_top, std::move(frame)); - frame_queue.PushDecodeOrder(id, luma_bottom, std::move(frame_copy)); - } else { - frame_queue.PushPresentOrder(id, luma_top, std::move(frame)); - frame_queue.PushPresentOrder(id, luma_bottom, std::move(frame_copy)); - } - } else { - auto [luma_offset, chroma_offset] = GetProgressiveOffsets(); - - if (!frame.get()) { - LOG_ERROR(HW_GPU, "Nvdec {} failed to decode progressive frame for luma 0x{:X}", id, - luma_offset); - } - - if (UsingDecodeOrder()) { - frame_queue.PushDecodeOrder(id, luma_offset, std::move(frame)); - } else { - frame_queue.PushPresentOrder(id, luma_offset, std::move(frame)); - } - } -} - } // namespace Tegra diff --git a/src/video_core/host1x/codecs/decoder.h b/src/video_core/host1x/codecs/decoder.h index 22e6db815..c456bbb1b 100755 --- a/src/video_core/host1x/codecs/decoder.h +++ b/src/video_core/host1x/codecs/decoder.h @@ -16,49 +16,50 @@ namespace Tegra { -namespace Host1x { -class Host1x; -class FrameQueue; -} // namespace Host1x + namespace Host1x { + class Host1x; + class FrameQueue; + } // namespace Host1x -class Decoder { -public: - virtual ~Decoder(); + class Decoder { + public: + virtual ~Decoder(); - /// Call decoders to construct headers, decode AVFrame with ffmpeg - void Decode(); + /// Call decoders to construct headers, decode AVFrame with ffmpeg + void Decode(); - bool UsingDecodeOrder() const { - return decode_api.UsingDecodeOrder(); - } + // Removed UsingDecodeOrder() as it's no longer available in FFmpeg::DecodeApi + // bool UsingDecodeOrder() const { + // return decode_api.UsingDecodeOrder(); + // } - /// Returns the value of current_codec - [[nodiscard]] Host1x::NvdecCommon::VideoCodec GetCurrentCodec() const { - return codec; - } + /// Returns the value of current_codec + [[nodiscard]] Host1x::NvdecCommon::VideoCodec GetCurrentCodec() const { + return codec; + } - /// Return name of the current codec - [[nodiscard]] virtual std::string_view GetCurrentCodecName() const = 0; + /// Return name of the current codec + [[nodiscard]] virtual std::string_view GetCurrentCodecName() const = 0; -protected: - explicit Decoder(Host1x::Host1x& host1x, s32 id, - const Host1x::NvdecCommon::NvdecRegisters& regs, - Host1x::FrameQueue& frame_queue); + protected: + explicit Decoder(Host1x::Host1x& host1x, s32 id, + const Host1x::NvdecCommon::NvdecRegisters& regs, + Host1x::FrameQueue& frame_queue); - virtual std::span<const u8> ComposeFrame() = 0; - virtual std::tuple<u64, u64> GetProgressiveOffsets() = 0; - virtual std::tuple<u64, u64, u64, u64> GetInterlacedOffsets() = 0; - virtual bool IsInterlaced() = 0; + virtual std::span<const u8> ComposeFrame() = 0; + virtual std::tuple<u64, u64> GetProgressiveOffsets() = 0; + virtual std::tuple<u64, u64, u64, u64> GetInterlacedOffsets() = 0; + virtual bool IsInterlaced() = 0; - Host1x::Host1x& host1x; - Tegra::MemoryManager& memory_manager; - const Host1x::NvdecCommon::NvdecRegisters& regs; - s32 id; - Host1x::FrameQueue& frame_queue; - Host1x::NvdecCommon::VideoCodec codec; - FFmpeg::DecodeApi decode_api; - bool initialized{}; - bool vp9_hidden_frame{}; -}; + Host1x::Host1x& host1x; + Tegra::MemoryManager& memory_manager; + const Host1x::NvdecCommon::NvdecRegisters& regs; + s32 id; + Host1x::FrameQueue& frame_queue; + Host1x::NvdecCommon::VideoCodec codec; + FFmpeg::DecodeApi decode_api; + bool initialized{}; + bool vp9_hidden_frame{}; + }; } // namespace Tegra |
