Zoom integration. Convert YUVRawDataI420 -> RGB to show in texture

Context:

I’m working on Zoom SDK integration in UE4. On the current step I’ve got a raw video data in YUVI420 format and try to show it inside a widget contains UImage. Base texture working code example get for RGB.

Questions:

  1. How to convert this YUV data to RGB?
  2. Should I use shaders for this purposes?

Any help will be appreciated

CODE:

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

	Width = 640;
	Height = 360;

	// Comment here
	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);
}

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

	FScopeLock lock(&Mutex);

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

		UTexture2D* 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.

		const FUpdateTextureRegion2D* TmpUpdateTextureRegion = UpdateTextureRegion;

		RenderTargetTexture = NewRenderTargetTexture;
		UpdateTextureRegion = NewUpdateTextureRegion;

		delete TmpUpdateTextureRegion;

		return;
	 }

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

void UVideoFrameWidget::UpdateBuffer(FZoomVideoRawData Video)
{
	if (!Video.Data)
	{
		return;
	}

	auto DataSize = Video.Data->GetStreamWidth() * Video.Data->GetStreamHeight() / 2;

	UE_LOG(LogTemp, Warning, TEXT("Widget received data with width: %d, height: %d"), Video.Data->GetStreamWidth(), Video.Data->GetStreamHeight())

	if (BufferSize == DataSize)
	{
		FMemory::Memcpy(Buffer, Video.Data->GetBuffer(), DataSize);
	}
	else
	{
		delete[] Buffer;
		BufferSize = DataSize;
		Width = Video.Data->GetStreamWidth();
		Height = Video.Data->GetStreamHeight();
		Buffer = new uint8[BufferSize];
		FMemory::Memcpy(Buffer, Video.Data->GetBuffer(), DataSize);
	}
}

void UVideoFrameWidget::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;
	}
}

UPD: created in-place conversion [YUV 4:2:0 → RGB] but get an artefacts, kind of red ghosts of mine)

If someone knows a solution to fix it or some hints, would be great)

CODE:

    if (BufferSize != DataSize)
	{
		delete[] Buffer;
		BufferSize = DataSize;
		Buffer = new uint8[BufferSize];
	}

	for (int32 i = 0; i < DataSize/4; i++)
	{
		double Y = static_cast<uint8>(Video.Data->GetYBuffer()[i]);
		double U = static_cast<uint8>(Video.Data->GetUBuffer()[i / 4]);
		double V = static_cast<uint8>(Video.Data->GetVBuffer()[i / 4]);

		Y -= 16.0;
		U -= 128.0;
		V -= 128.0;

		// R
		Buffer[i*4] = FMath::Clamp(static_cast<int32>(Y * 1.0 + 1.140 * V), 0, 255);
		// G
		Buffer[i*4+1] = FMath::Clamp(static_cast<int32>(1.0 * Y - 0.395 * U - 0.581 * V), 0, 255);
		// B
		Buffer[i*4+2] = FMath::Clamp(static_cast<int32>(1.0 * Y + 2.032 * U), 0, 255);
	}

Hi Alnsolence, please contact me I need a decoding API from Zoom YUV420p to PNG, ¿are you able to help?

hello.guys, have you resolve this problem.i also meet this issue.can you give me some advice