You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
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]
170 lines
5.7 KiB
C++
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 */
|