260 lines
6.0 KiB
C++
260 lines
6.0 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "MetaHumanPipelineMediaPlayerNode.h"
|
|
|
|
#include "Async/ParallelFor.h"
|
|
|
|
namespace UE::MetaHuman::Pipeline
|
|
{
|
|
|
|
FString FMediaPlayerNode::BundleURL = TEXT("bundle://");
|
|
|
|
FMediaPlayerNode::FMediaPlayerNode(const FString& InTypeName, const FString& InName) : FNode(InTypeName, InName)
|
|
{
|
|
Pins.Add(FPin("UE Image Out", EPinDirection::Output, EPinType::UE_Image));
|
|
Pins.Add(FPin("Audio Out", EPinDirection::Output, EPinType::Audio));
|
|
Pins.Add(FPin("UE Image Sample Time Out", EPinDirection::Output, EPinType::QualifiedFrameTime, 0));
|
|
Pins.Add(FPin("Audio Sample Time Out", EPinDirection::Output, EPinType::QualifiedFrameTime, 1));
|
|
Pins.Add(FPin("Dropped Frame Out", EPinDirection::Output, EPinType::Bool));
|
|
Pins.Add(FPin("UE Image Sample Time Source Out", EPinDirection::Output, EPinType::Int, 0));
|
|
Pins.Add(FPin("Audio Sample Time Source Out", EPinDirection::Output, EPinType::Int, 1));
|
|
}
|
|
|
|
static void RGBfromYUV(double& R, double& G, double& B, double Y, double U, double V)
|
|
{
|
|
Y -= 16;
|
|
U -= 128;
|
|
V -= 128;
|
|
R = 1.164 * Y + 1.596 * V;
|
|
G = 1.164 * Y - 0.392 * U - 0.813 * V;
|
|
B = 1.164 * Y + 2.017 * U;
|
|
|
|
if (R < 0) R = 0;
|
|
if (G < 0) G = 0;
|
|
if (B < 0) B = 0;
|
|
if (R > 255) R = 255;
|
|
if (G > 255) G = 255;
|
|
if (B > 255) B = 255;
|
|
}
|
|
|
|
void FMediaPlayerNode::ConvertSample(const FIntPoint& InRes, const int32 InStride, const EMediaTextureSampleFormat InFormat, const uint8* InVideoSampleData, FUEImageDataType &OutImage) const
|
|
{
|
|
OutImage.Width = InRes.X;
|
|
OutImage.Height = InRes.Y;
|
|
OutImage.Data.SetNumUninitialized(OutImage.Width * OutImage.Height * 4);
|
|
|
|
if (InFormat == EMediaTextureSampleFormat::CharNV12)
|
|
{
|
|
ParallelFor(InRes.Y, [&](int32 Y)
|
|
{
|
|
const uint8* SampleLumData = InVideoSampleData;
|
|
SampleLumData += Y * InStride;
|
|
|
|
const uint8* SampleUVData = InVideoSampleData;
|
|
SampleUVData += (InRes.Y * InStride) + (Y / 2 * InStride / 2 * 2);
|
|
|
|
uint8* RGBData = OutImage.Data.GetData();
|
|
RGBData += Y * InRes.X * 4;
|
|
|
|
for (int32 X = 0; X < InRes.X; ++X)
|
|
{
|
|
double R, G, B;
|
|
|
|
RGBfromYUV(R, G, B, SampleLumData[0], SampleUVData[0], SampleUVData[1]);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
++SampleLumData;
|
|
if (X % 2 == 1) SampleUVData += 2;
|
|
}
|
|
});
|
|
}
|
|
else if (InFormat == EMediaTextureSampleFormat::CharYUY2)
|
|
{
|
|
ParallelFor(InRes.Y, [&](int32 Y)
|
|
{
|
|
const uint8* SampleData = InVideoSampleData;
|
|
SampleData += Y * InStride;
|
|
|
|
uint8* RGBData = OutImage.Data.GetData();
|
|
RGBData += Y * InRes.X * 4;
|
|
|
|
for (int32 X = 0; X < InRes.X; X += 2)
|
|
{
|
|
double R, G, B;
|
|
|
|
RGBfromYUV(R, G, B, SampleData[0], SampleData[1], SampleData[3]);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
RGBfromYUV(R, G, B, SampleData[2], SampleData[1], SampleData[3]);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
SampleData += 4;
|
|
}
|
|
});
|
|
}
|
|
else if (InFormat == EMediaTextureSampleFormat::CharUYVY)
|
|
{
|
|
ParallelFor(InRes.Y, [&](int32 Y)
|
|
{
|
|
const uint8* SampleData = InVideoSampleData;
|
|
SampleData += Y * InStride;
|
|
|
|
uint8* RGBData = OutImage.Data.GetData();
|
|
RGBData += Y * InRes.X * 4;
|
|
|
|
for (int32 X = 0; X < InRes.X; X += 2)
|
|
{
|
|
double R, G, B;
|
|
|
|
RGBfromYUV(R, G, B, SampleData[1], SampleData[0], SampleData[2]);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
RGBfromYUV(R, G, B, SampleData[3], SampleData[0], SampleData[2]);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
SampleData += 4;
|
|
}
|
|
});
|
|
}
|
|
else if (InFormat == EMediaTextureSampleFormat::CharBGRA)
|
|
{
|
|
if (InStride == InRes.X * 4)
|
|
{
|
|
FMemory::Memcpy(OutImage.Data.GetData(), InVideoSampleData, OutImage.Data.Num());
|
|
}
|
|
else
|
|
{
|
|
ParallelFor(InRes.Y, [&](int32 Y)
|
|
{
|
|
const uint8* SampleData = InVideoSampleData;
|
|
SampleData += Y * InStride;
|
|
|
|
uint8* RGBData = OutImage.Data.GetData();
|
|
RGBData += Y * InRes.X * 4;
|
|
|
|
FMemory::Memcpy(RGBData, SampleData, InRes.X * 4);
|
|
});
|
|
}
|
|
}
|
|
else if (InFormat == EMediaTextureSampleFormat::YUVv210)
|
|
{
|
|
ParallelFor(InRes.Y, [&](int32 Y)
|
|
{
|
|
const uint8* SampleData = InVideoSampleData;
|
|
SampleData += Y * InStride;
|
|
|
|
uint8* RGBData = OutImage.Data.GetData();
|
|
RGBData += Y * InRes.X * 4;
|
|
|
|
for (int32 X = 0; X < InRes.X; X += 6)
|
|
{
|
|
// Sample is 128 bits. Thats 12 values where each is 10 bits. Those 12
|
|
// values (UYVY x 3) make 6 pixels.
|
|
// 10 bit values are downsized to 8 bit.
|
|
// See https://wiki.multimedia.cx/index.php/V210
|
|
|
|
double R, G, B;
|
|
uint32* SampleData32 = (uint32*) SampleData;
|
|
|
|
uint8 U8 = (SampleData32[0] >> 2);
|
|
uint8 Y8 = (SampleData32[0] >> 12);
|
|
uint8 V8 = (SampleData32[0] >> 22);
|
|
|
|
RGBfromYUV(R, G, B, Y8, U8, V8);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
Y8 = (SampleData32[1] >> 2);
|
|
|
|
RGBfromYUV(R, G, B, Y8, U8, V8);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
U8 = (SampleData32[1] >> 12);
|
|
Y8 = (SampleData32[1] >> 22);
|
|
V8 = (SampleData32[2] >> 2);
|
|
|
|
RGBfromYUV(R, G, B, Y8, U8, V8);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
Y8 = (SampleData32[2] >> 12);
|
|
|
|
RGBfromYUV(R, G, B, Y8, U8, V8);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
U8 = (SampleData32[2] >> 22);
|
|
Y8 = (SampleData32[3] >> 2);
|
|
V8 = (SampleData32[3] >> 12);
|
|
|
|
RGBfromYUV(R, G, B, Y8, U8, V8);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
Y8 = (SampleData32[3] >> 22);
|
|
|
|
RGBfromYUV(R, G, B, Y8, U8, V8);
|
|
|
|
RGBData[0] = B;
|
|
RGBData[1] = G;
|
|
RGBData[2] = R;
|
|
RGBData[3] = 255;
|
|
RGBData += 4;
|
|
|
|
SampleData += 16; // 128 bits
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
check(false);
|
|
}
|
|
}
|
|
|
|
} |