Files
UnrealEngineUWP/Engine/Source/Runtime/AVEncoder/Private/VideoEncoderFactory.cpp
William Belcher 24ba7c4cc9 Merge /UE5/Dev-Tensorworks to /UE5/Main. This includes:
Refactor player sessions
Fix PixelStreamingAudioComponent had delayed audio.
Fix audio bitrate from Unreal Engine to browser was set to a low default causing compressed audio quality in stream. The new default is now Opus maximum value of 510kb/s.
Fix the Selective Forwarding Unit (SFU) not being added to the Pixel Streaming samples folder for a packaged project
Fix default max bitrate not being high enough to support 4k.
Fix reconnections not autoplaying in the browser.
Add datachannel support to SFU.
Add WebRTC c++ client behaviour to pixel streaming system. This is used for developing unit tests.
Add a unit test that will start streaming, connect a client and check that a data channel message can be sent.
Add the ability for a user to start/stop streaming as needed through the use of PixelStreaming.StartStreaming and PixelStreaming.StopStreaming
Add the ability for the stream resolution to be changed at runtime

Notes: AVEncoder no longer stores a width and height; These properties have been moved to the FVideoEncoderInput. This input is now the source of truth and both AMF and NVENC will adapt their resolution to the input resolution.

#rb luke.bermingham
#fyi mattias.jansson, nick.pace, matthew.cotton, aidan.possemiers, sandor.hadas
#preflight 6204c7aba65a8a28464df03c
#jira none

[CL 18948482 by William Belcher in ue5-main branch]
2022-02-10 21:16:24 -05:00

174 lines
4.3 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "VideoEncoderFactory.h"
#include "VideoEncoderInputImpl.h"
#include "RHI.h"
#include "Encoders/VideoEncoderH264_Dummy.h"
namespace AVEncoder
{
FCriticalSection FVideoEncoderFactory::ProtectSingleton;
FVideoEncoderFactory FVideoEncoderFactory::Singleton;
FThreadSafeCounter FVideoEncoderFactory::NextID = 4711;
FVideoEncoderFactory& FVideoEncoderFactory::Get()
{
if (!Singleton.bWasSetup)
{
ProtectSingleton.Lock();
if (!Singleton.bWasSetup)
{
Singleton.bWasSetup = true;
if (!Singleton.bDebugDontRegisterDefaultCodecs)
{
Singleton.RegisterDefaultCodecs();
}
}
ProtectSingleton.Unlock();
}
return Singleton;
}
void FVideoEncoderFactory::Shutdown()
{
FScopeLock Guard(&ProtectSingleton);
if (Singleton.bWasSetup)
{
Singleton.bWasSetup = false;
Singleton.bDebugDontRegisterDefaultCodecs = false;
Singleton.AvailableEncoders.Empty();
Singleton.CreateEncoders.Empty();
//
#if defined(AVENCODER_VIDEO_ENCODER_AVAILABLE_NVENC)
FNVENCCommon::Shutdown();
#endif
}
}
void FVideoEncoderFactory::Debug_SetDontRegisterDefaultCodecs()
{
check(!Singleton.bWasSetup);
Singleton.bDebugDontRegisterDefaultCodecs = true;
}
void FVideoEncoderFactory::Register(const FVideoEncoderInfo& InInfo, const CreateEncoderCallback& InCreateEncoder)
{
AvailableEncoders.Push(InInfo);
AvailableEncoders.Last().ID = NextID.Increment();
CreateEncoders.Push(InCreateEncoder);
}
void FVideoEncoderFactory::RegisterDefaultCodecs()
{
#if defined(AVENCODER_VIDEO_ENCODER_AVAILABLE_H264_DUMMY)
FVideoEncoderH264_Dummy::Register(*this);
#endif
}
bool FVideoEncoderFactory::GetInfo(uint32 InID, FVideoEncoderInfo& OutInfo) const
{
for (int32 Index = 0; Index < AvailableEncoders.Num(); ++Index)
{
if (AvailableEncoders[Index].ID == InID)
{
OutInfo = AvailableEncoders[Index];
return true;
}
}
return false;
}
bool FVideoEncoderFactory::HasEncoderForCodec(ECodecType CodecType) const
{
for (const AVEncoder::FVideoEncoderInfo& EncoderInfo : AvailableEncoders)
{
if (EncoderInfo.CodecType == CodecType)
{
return true;
}
}
return false;
}
TUniquePtr<FVideoEncoder> FVideoEncoderFactory::Create(uint32 InID, const FVideoEncoder::FLayerConfig& config)
{
// HACK (M84FIX) create encoder without a ready FVideoEncoderInput
TUniquePtr<FVideoEncoder> Result;
for (int32 Index = 0; Index < AvailableEncoders.Num(); ++Index)
{
if (AvailableEncoders[Index].ID == InID)
{
Result = CreateEncoders[Index]();
FString RHIName = GDynamicRHI->GetName();
if (RHIName == TEXT("D3D11"))
{
TSharedRef<FVideoEncoderInput> Input = FVideoEncoderInput::CreateForD3D11(GDynamicRHI->RHIGetNativeDevice(), true, IsRHIDeviceAMD()).ToSharedRef();
if (Result && !Result->Setup(Input, config))
{
Result.Reset();
}
break;
}
else if (RHIName == TEXT("D3D12"))
{
TSharedRef<FVideoEncoderInput> Input = FVideoEncoderInput::CreateForD3D12(GDynamicRHI->RHIGetNativeDevice(), true, IsRHIDeviceNVIDIA()).ToSharedRef();
if (Result && !Result->Setup(Input, config))
{
Result.Reset();
}
break;
}
#if PLATFORM_DESKTOP && !PLATFORM_APPLE
else if (RHIName == TEXT("Vulkan"))
{
AVEncoder::FVulkanDataStruct VulkanData = { static_cast<VkInstance>(GDynamicRHI->RHIGetNativeInstance()),
static_cast<VkPhysicalDevice>(GDynamicRHI->RHIGetNativePhysicalDevice()),
static_cast<VkDevice>(GDynamicRHI->RHIGetNativeDevice())};
TSharedRef<FVideoEncoderInput> Input = FVideoEncoderInput::CreateForVulkan( &VulkanData, true).ToSharedRef();
if (Result && !Result->Setup(Input, config))
{
Result.Reset();
}
break;
}
#endif
}
}
return Result;
}
TUniquePtr<FVideoEncoder> FVideoEncoderFactory::Create(uint32 InID, TSharedPtr<FVideoEncoderInput> InInput, const FVideoEncoder::FLayerConfig& config)
{
TUniquePtr<FVideoEncoder> Result;
if (InInput)
{
TSharedRef<FVideoEncoderInput> Input(InInput.ToSharedRef());
for (int32 Index = 0; Index < AvailableEncoders.Num(); ++Index)
{
if (AvailableEncoders[Index].ID == InID)
{
Result = CreateEncoders[Index]();
if (Result && !Result->Setup(MoveTemp(Input), config))
{
Result.Reset();
}
break;
}
}
}
return Result;
}
} /* namespace AVEncoder */