Files
UnrealEngine/Engine/Source/Runtime/AVEncoder/Private/VideoEncoderInputImpl.h
2025-05-18 13:04:45 +08:00

171 lines
5.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "VideoEncoderInput.h"
#include "Containers/Queue.h"
#include "Misc/ScopeLock.h"
#include "Templates/RefCounting.h"
#include "CudaModule.h"
// HACK (M84FIX) need to break these dependencies
#if PLATFORM_WINDOWS
struct ID3D11DeviceContext;
#endif
namespace AVEncoder
{
class FVideoEncoderInputFrameImpl;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
class FVideoEncoderInputImpl : public FVideoEncoderInput
{
public:
FVideoEncoderInputImpl() = default;
virtual ~FVideoEncoderInputImpl();
// --- properties
uint32 GetNumActiveFrames() const { FScopeLock Guard(&ProtectFrames); return ActiveFrames.Num(); }
bool GetHasFreeFrames() const { FScopeLock Guard(&ProtectFrames); return !AvailableFrames.IsEmpty(); }
// --- construct video encoder input based on expected input frame format
bool SetupForDummy();
bool SetupForYUV420P(uint32 InWidth, uint32 InHeight);
// set up for an encoder that encodes a D3D11 texture (nvenc)
bool SetupForD3D11(void* InApplicationD3DDevice);
// set up for an encoder that encodes a D3D11 texture within a feature level 11.1 D3D11 device (amf)
bool SetupForD3D11Shared(void* InApplicationD3DDevice);
// set up for an encoder that encodes a D3D12 texture (amf)
bool SetupForD3D12(void* InApplicationD3DDevice);
// set up for an encoder that encodes a D3D12 texture in the context of a D3D11 device (i.e. nvenc)
bool SetupForD3D12Shared(void* InApplicationD3DDevice);
// set up an encoder that encodes a CUArray in a CUDA context
bool SetupForCUDA(void* InApplicationContext);
#if PLATFORM_DESKTOP && !PLATFORM_APPLE
// set up an encoder that encodes a VkImage in the context of a VkDevice
bool SetupForVulkan(VkInstance InApplicationVulkanInstance, VkPhysicalDevice InApplicationVulkanPhysicalDevice, VkDevice InApplicationVulkanDevice);
#endif
// --- available encoders
// get a list of supported video encoders
const TArray<FVideoEncoderInfo>& GetAvailableEncoders() override;
// --- encoder input frames - user managed
// create a user managed buffer
FVideoEncoderInputFrame* CreateBuffer(OnFrameReleasedCallback InOnFrameReleased) override;
// destroy user managed buffer
void DestroyBuffer(FVideoEncoderInputFrame* Buffer) override;
// --- encoder input frames - managed by this object
// obtain a video frame that can be used as a buffer for input to a video encoder
TSharedPtr<FVideoEncoderInputFrame> ObtainInputFrame() override;
// release (free) an input frame and make it available for future use
void ReleaseInputFrame(FVideoEncoderInputFrame* InFrame) override;
// destroy/release any frames that are not currently in use
void Flush() override;
// indicates whether a given frame is a user managed frame or not
bool IsUserManagedFrame(const FVideoEncoderInputFrame* InBuffer) const;
// --- input properties
#if PLATFORM_WINDOWS
TRefCountPtr<ID3D11Device> GetD3D11EncoderDevice() const override;
TRefCountPtr<ID3D12Device> GetD3D12EncoderDevice() const override;
#endif
CUcontext GetCUDAEncoderContext() const override;
#if PLATFORM_DESKTOP && !PLATFORM_APPLE
void* GetVulkanEncoderDevice() const override;
#endif
private:
// collect any encoder that can handle frame format
void CollectAvailableEncoders();
TArray<FVideoEncoderInfo> AvailableEncoders;
FVideoEncoderInputFrameImpl* CreateFrame();
void SetupFrameYUV420P(FVideoEncoderInputFrameImpl* Frame);
void SetupFrameD3D11(FVideoEncoderInputFrameImpl* Frame);
void SetupFrameD3D12(FVideoEncoderInputFrameImpl* Frame);
void SetupFrameVulkan(FVideoEncoderInputFrameImpl* Frame);
void SetupFrameCUDA(FVideoEncoderInputFrameImpl* Frame);
struct FFrameInfoDummy
{
} FrameInfoDummy;
struct FFrameInfoYUV420P
{
uint32 StrideY = 0;
uint32 StrideU = 0;
uint32 StrideV = 0;
} FrameInfoYUV420P;
#if PLATFORM_WINDOWS
struct FFrameInfoD3D
{
TRefCountPtr<ID3D11Device> EncoderDeviceD3D11;
TRefCountPtr<ID3D11DeviceContext> EncoderDeviceContextD3D11;
TRefCountPtr<ID3D12Device> EncoderDeviceD3D12;
} FrameInfoD3D;
#endif
struct FFrameInfoCUDA
{
CUcontext EncoderContextCUDA;
} FrameInfoCUDA;
#if PLATFORM_DESKTOP && !PLATFORM_APPLE
FVulkanDataStruct FrameInfoVulkan;
#endif
mutable FCriticalSection ProtectFrames;
TQueue<TSharedPtr<FVideoEncoderInputFrameImpl>> AvailableFrames;
TArray<TSharedPtr<FVideoEncoderInputFrameImpl>> ActiveFrames;
using UserManagedFrame = TPair<FVideoEncoderInputFrameImpl*, OnFrameReleasedCallback>;
TArray<UserManagedFrame> UserManagedFrames;
};
class FVideoEncoderInputFrameImpl : public FVideoEncoderInputFrame
{
public:
explicit FVideoEncoderInputFrameImpl(FVideoEncoderInputImpl* InInput);
FVideoEncoderInputFrameImpl(const FVideoEncoderInputFrameImpl& InCloneFrom) = delete;
explicit FVideoEncoderInputFrameImpl(const FVideoEncoderInputFrameImpl& InCloneFrom, FCloneDestroyedCallback InCloneDestroyedCallback);
~FVideoEncoderInputFrameImpl();
// Clone frame - this will create a copy that references the original until destroyed
const FVideoEncoderInputFrame* Clone(FCloneDestroyedCallback InCloneDestroyedCallback) const override;
// Release (decrease reference count) of this input frame
void Release() const override;
void SetFormat(EVideoFrameFormat InFormat) { Format = InFormat; }
void SetWidth(uint32 InWidth) { Width = InWidth; }
void SetHeight(uint32 InHeight) { Height = InHeight; }
private:
FVideoEncoderInputImpl* Input;
const FVideoEncoderInputFrame* ClonedReference = nullptr;
const FCloneDestroyedCallback OnCloneDestroyed;
};
PRAGMA_ENABLE_DEPRECATION_WARNINGS
} /* namespace AVEncoder */