C++ 在 Unreal 中为游戏增加实时音视频互动的教程详解

2020-05-29 11:02:26于丽

增加 UpdateBuffer() 方法

通过调用来更新 Buffer 值。我们希望从 Agora SDK 线程接收到新的值。由于 UE4 的限制,我们将值保存到变量 Buffer 中,并在 NativeTick 方法中更新纹理,所以这里不调用UpdateTextureRegions。

//VideoViewWidget.h
...

UCLASS()
class AGORAVIDEOCALL_API UVideoViewWidget : public UUserWidget
{
 GENERATED_BODY()

public:

 ...

 void UpdateBuffer( uint8* RGBBuffer, uint32_t Width, uint32_t Height, uint32_t Size );
 void ResetBuffer();
 ...
};
//VideoViewWidget.cpp 

void UVideoViewWidget::UpdateBuffer(
 uint8* RGBBuffer,
 uint32_t NewWidth,
 uint32_t NewHeight,
 uint32_t NewSize)
{
 FScopeLock lock(&Mutex);

 if (!RGBBuffer)
 {
 return;
 }

 if (BufferSize == NewSize)
 {
 std::copy(RGBBuffer, RGBBuffer + NewSize, Buffer);
 }
 else
 {
 delete[] Buffer;
 BufferSize = NewSize;
 Width = NewWidth;
 Height = NewHeight;
 Buffer = new uint8[BufferSize];
 std::copy(RGBBuffer, RGBBuffer + NewSize, Buffer);
 }
}

void UVideoViewWidget::ResetBuffer()
{
 for (uint32 i = 0; i < Width * Height; ++i)
 {
 Buffer[i * 4 + 0] = 0x32;
 Buffer[i * 4 + 1] = 0x32;
 Buffer[i * 4 + 2] = 0x32;
 Buffer[i * 4 + 3] = 0xFF;
 }
}

创建 VideoCallViewWidget C++类

VideoCallViewWidget 类的作用是显示本地和远程用户的视频。我们需要两个 VideoViewWidget 小部件,一个用来显示来自本地摄像头的视频,另一个用来显示从远程用户收到的视频(假设我们只支持一个远程用户)。

创建类和添加所需的 include

像之前那样创建Widget C++类,添加所需的include。

//VideoCallViewWidget.h 

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/SizeBox.h"

#include "VideoViewWidget.h"

#include "VideoCallViewWidget.generated.h"
//VideoCallViewWidget.cpp

#include "Components/CanvasPanelSlot.h"

添加成员变量

//VideoCallViewWidget.h 

...

UCLASS()
class AGORAVIDEOCALL_API UVideoCallViewWidget : public UUserWidget
{
 GENERATED_BODY()

public:

 UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
 UVideoViewWidget* MainVideoViewWidget = nullptr;

 UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
 USizeBox* MainVideoSizeBox = nullptr;

 UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
 UVideoViewWidget* AdditionalVideoViewWidget = nullptr;

 UPROPERTY(BlueprintReadOnly, meta = (BindWidget))
 USizeBox* AdditionalVideoSizeBox = nullptr;

public:
 int32 MainVideoWidth = 0;
 int32 MainVideoHeight = 0;

 ...
};

覆盖 NativeTick() 方法

``
//VideoCallViewWidget.h 

...

UCLASS()
class AGORAVIDEOCALL_API UVideoCallViewWidget : public UUserWidget
{
 GENERATED_BODY()

public:

 ...

 void NativeTick(const FGeometry& MyGeometry, float DeltaTime) override;

 ...
};
//VideoCallViewWidget.cpp

void UVideoCallViewWidget::NativeTick(const FGeometry& MyGeometry, float DeltaTime)
{
 Super::NativeTick(MyGeometry, DeltaTime);

 auto ScreenSize = MyGeometry.GetLocalSize();

 if (MainVideoHeight != 0)
 {
 float AspectRatio = 0;
 AspectRatio = MainVideoWidth / (float)MainVideoHeight;

 auto MainVideoGeometry = MainVideoViewWidget->GetCachedGeometry();
 auto MainVideoScreenSize = MainVideoGeometry.GetLocalSize();
 if (MainVideoScreenSize.X == 0)
 {
 return;
 }

 auto NewMainVideoHeight = MainVideoScreenSize.Y;
 auto NewMainVideoWidth = AspectRatio * NewMainVideoHeight;

 MainVideoSizeBox->SetMinDesiredWidth(NewMainVideoWidth);
 MainVideoSizeBox->SetMinDesiredHeight(NewMainVideoHeight);

 UCanvasPanelSlot* CanvasSlot = Cast<UCanvasPanelSlot>(MainVideoSizeBox->Slot);
 CanvasSlot->SetAutoSize(true);

 FVector2D NewPosition;
 NewPosition.X = -NewMainVideoWidth / 2;
 NewPosition.Y = -NewMainVideoHeight / 2;
 CanvasSlot->SetPosition(NewPosition);
 }
}