// Copyright Epic Games, Inc. All Rights Reserved. #include "MetaHumanVideoLiveLinkSubject.h" #include "MetaHumanPipelineMediaPlayerUENode.h" #include "MetaHumanPipelineMediaPlayerWMFNode.h" #include "MetaHumanPipelineMediaPlayerWMFReaderNode.h" #include "Async/Async.h" TAutoConsoleVariable CVarMetaHumanLiveLinkMediaPlayer { TEXT("mh.LiveLink.MediaPlayer"), "WMF", TEXT("Controls which media player is used. Options are \"WMF\", \"WMFReader\" or \"UE\""), ECVF_Default }; FMetaHumanVideoLiveLinkSubject::FMetaHumanVideoLiveLinkSubject(ILiveLinkClient* InLiveLinkClient, const FGuid& InSourceGuid, const FName& InSubjectName, UMetaHumanVideoLiveLinkSubjectSettings* InSettings) : FMetaHumanVideoBaseLiveLinkSubject(InLiveLinkClient, InSourceGuid, InSubjectName, InSettings) { AnalyticsItems.Add(TEXT("DeviceFormat"), InSettings->MediaSourceCreateParams.VideoTrackFormatName); if (InSettings->MediaSourceCreateParams.VideoURL.StartsWith(UE::MetaHuman::Pipeline::FMediaPlayerNode::BundleURL)) { AnalyticsItems.Add(TEXT("DeviceModel"), TEXT("MediaBundle")); MediaPlayer = MakeShared("MediaPlayerUE"); } else { AnalyticsItems.Add(TEXT("DeviceModel"), InSettings->MediaSourceCreateParams.VideoName); const FString MediaPlayerType = CVarMetaHumanLiveLinkMediaPlayer.GetValueOnAnyThread(); if (MediaPlayerType == "WMF") { MediaPlayer = MakeShared("MediaPlayerWMF"); } else if (MediaPlayerType == "WMFReader") { MediaPlayer = MakeShared("MediaPlayerWMFReader"); } else if (MediaPlayerType == "UE") { MediaPlayer = MakeShared("MediaPlayerUE"); } else { UE_LOG(LogMetaHumanLocalLiveLinkSubject, Warning, TEXT("Unknown media player option: %s"), *MediaPlayerType); MediaPlayer = MakeShared("MediaPlayerWMF"); } } UE_LOG(LogMetaHumanLocalLiveLinkSubject, Display, TEXT("Using media player: %s"), *MediaPlayer->Name); MediaPlayer->StartTimeout = InSettings->MediaSourceCreateParams.StartTimeout; MediaPlayer->FormatWaitTime = InSettings->MediaSourceCreateParams.FormatWaitTime; MediaPlayer->SampleTimeout = InSettings->MediaSourceCreateParams.SampleTimeout; MediaPlayer->Play(InSettings->MediaSourceCreateParams.VideoURL, InSettings->MediaSourceCreateParams.VideoTrack, InSettings->MediaSourceCreateParams.VideoTrackFormat); for (UE::MetaHuman::Pipeline::FPin& Pin : MediaPlayer->Pins) { Pin.Address = MediaPlayer->Name + "." + Pin.Name; } } FMetaHumanVideoLiveLinkSubject::~FMetaHumanVideoLiveLinkSubject() { AsyncTask(ENamedThreads::GameThread, [MediaPlayer = this->MediaPlayer]() { if (!MediaPlayer->Close()) { UE_LOG(LogMetaHumanLocalLiveLinkSubject, Warning, TEXT("Failed to close media player")); } }); MediaPlayer.Reset(); } void FMetaHumanVideoLiveLinkSubject::MediaSamplerMain() { TSharedPtr PipelineData; MediaPlayer->bAbort = GetIsRunningPtr(); PipelineData = MakeShared(); if (!MediaPlayer->Start(PipelineData)) { SetError(PipelineData->GetErrorNodeMessage()); return; } int32 Frame = 0; while (IsRunning()) { PipelineData = MakeShared(); PipelineData->SetFrameNumber(Frame++); if (!MediaPlayer->Process(PipelineData)) { SetError(PipelineData->GetErrorNodeMessage()); break; } UE::MetaHuman::Pipeline::FUEImageDataType Image = PipelineData->MoveData(MediaPlayer->Name + ".UE Image Out"); FVideoSample VideoSample; VideoSample.Width = Image.Width; VideoSample.Height = Image.Height; VideoSample.Data = MoveTemp(Image.Data); VideoSample.Time = PipelineData->GetData(MediaPlayer->Name + TEXT(".UE Image Sample Time Out")); VideoSample.TimeSource = static_cast(PipelineData->GetData(MediaPlayer->Name + TEXT(".UE Image Sample Time Source Out"))); AddVideoSample(MoveTemp(VideoSample)); } PipelineData = MakeShared(); if (!MediaPlayer->End(PipelineData)) { SetError(PipelineData->GetErrorNodeMessage()); return; } }