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

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

//VideoViewWidget.h
...

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

public:

...

 void NativeConstruct() override;

 ...
};
//VideoViewWidget.cpp

void UVideoViewWidget::NativeConstruct()
{
 Super::NativeConstruct();

 Width = 640;
 Height = 360;

 RenderTargetTexture = UTexture2D::CreateTransient(Width, Height, PF_R8G8B8A8);
 RenderTargetTexture->UpdateResource();

 BufferSize = Width * Height * 4;
 Buffer = new uint8[BufferSize];
 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;
 }
 UpdateTextureRegion = new FUpdateTextureRegion2D(0, 0, 0, 0, Width, Height);
 RenderTargetTexture->UpdateTextureRegions(0, 1, UpdateTextureRegion, Width * 4, (uint32)4, Buffer);

 Brush.SetResourceObject(RenderTargetTexture);
 RenderTargetImage->SetBrush(Brush);
}

覆盖 NativeDestruct() 方法

//VideoViewWidget.h
...

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

public:

 ...

 void NativeDestruct() override;

 ...
};
//VideoViewWidget.cpp

void UVideoViewWidget::NativeDestruct()
{
 Super::NativeDestruct();

 delete[] Buffer;
 delete UpdateTextureRegion;
}

覆盖 NativeTick() 方法

如果UpdateTextureRegion Width或Height不等于memember的Width Height值,我们需要重新创建RenderTargetTexture以支持更新的值,并像Native Construct成员一样重复初始化。否则只需用Buffer调用UpdateTextureRegions。

//VideoViewWidget.h

...

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

public:

 ...

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

 ...
};
//VideoViewWidget.cpp

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

 FScopeLock lock(&Mutex);

 if (UpdateTextureRegion->Width != Width ||
 UpdateTextureRegion->Height != Height)
 {
 auto NewUpdateTextureRegion = new FUpdateTextureRegion2D(0, 0, 0, 0, Width, Height);

 auto NewRenderTargetTexture = UTexture2D::CreateTransient(Width, Height, PF_R8G8B8A8);
 NewRenderTargetTexture->UpdateResource();
 NewRenderTargetTexture->UpdateTextureRegions(0, 1, NewUpdateTextureRegion, Width * 4, (uint32)4, Buffer);

 Brush.SetResourceObject(NewRenderTargetTexture);
 RenderTargetImage->SetBrush(Brush);

 //UClass's such as UTexture2D are automatically garbage collected when there is no hard pointer references made to that object.
 //So if you just leave it and don't reference it elsewhere then it will be destroyed automatically.

 FUpdateTextureRegion2D* TmpUpdateTextureRegion = UpdateTextureRegion;

 RenderTargetTexture = NewRenderTargetTexture;
 UpdateTextureRegion = NewUpdateTextureRegion;

 delete TmpUpdateTextureRegion;
 return;
 }
 RenderTargetTexture->UpdateTextureRegions(0, 1, UpdateTextureRegion, Width * 4, (uint32)4, Buffer);
}