Files
UnrealEngineUWP/Engine/Source/Runtime/AVEncoder/Private/VideoEncoderInputImpl.h
aidan possemiers 8830772283 Decouple render FPS and encode FPS so that low FPS application can still stream at 60 FPS.
This resolves bitrate issues in WebRTC caused by inconsistent frame rates.

These changes are intended for 5.0 and licencees who are using source builds of the engine to get the updates before 5.0 is released.

#JIRA UCS-2077
#rb Aidan.Possemiers
[FYI] Luke.Bermingham, Nick.Pace, Matthew.Cotton, Marco.Anastasi
#lockdown Mitchell.Wilson

#ROBOMERGE-AUTHOR: aidan.possemiers
#ROBOMERGE-SOURCE: CL 18267227 in //UE4/Main/... via CL 18267244 via CL 18267255
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v895-18170469)
#ROBOMERGE[STARSHIP]: UE5-Main

[CL 18267257 by aidan possemiers in ue5-release-engine-test branch]
2021-11-23 01:47:46 -05:00

170 lines
5.7 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;
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(uint32 InWidth, uint32 InHeight);
bool SetupForYUV420P(uint32 InWidth, uint32 InHeight);
// set up for an encoder that encodes a D3D11 texture (nvenc)
bool SetupForD3D11(void* InApplicationD3DDevice, uint32 InWidth, uint32 InHeight);
// set up for an encoder that encodes a D3D11 texture within a feature level 11.1 D3D11 device (amf)
bool SetupForD3D11Shared(void* InApplicationD3DDevice, uint32 InWidth, uint32 InHeight);
// set up for an encoder that encodes a D3D12 texture (amf)
bool SetupForD3D12(void* InApplicationD3DDevice, uint32 InWidth, uint32 InHeight);
// set up for an encoder that encodes a D3D12 texture in the context of a D3D11 device (i.e. nvenc)
bool SetupForD3D12Shared(void* InApplicationD3DDevice, uint32 InWidth, uint32 InHeight);
// set up an encoder that encodes a CUArray in a CUDA context
bool SetupForCUDA(void* InApplicationContext, uint32 InWidth, uint32 InHeight);
#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, uint32 InWidth, uint32 InHeight);
#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
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<FVideoEncoderInputFrameImpl*> AvailableFrames;
TArray<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;
};
} /* namespace AVEncoder */