261 lines
7.0 KiB
C++
261 lines
7.0 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "MovieSceneCaptureProtocolBase.h"
|
|
#include "CoreMinimal.h"
|
|
#include "HAL/FileManager.h"
|
|
#include "Slate/SceneViewport.h"
|
|
#include "Misc/Paths.h"
|
|
#include "HAL/PlatformFileManager.h"
|
|
#include "UnrealEngine.h"
|
|
#include "ViewportClient.h"
|
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(MovieSceneCaptureProtocolBase)
|
|
|
|
#define LOCTEXT_NAMESPACE "MovieSceneCaptureProtocol"
|
|
|
|
UMovieSceneCaptureProtocolBase::UMovieSceneCaptureProtocolBase(const FObjectInitializer& ObjInit)
|
|
: Super(ObjInit)
|
|
{
|
|
State = EMovieSceneCaptureProtocolState::Idle;
|
|
CaptureHost = nullptr;
|
|
|
|
bFrameRequested[0] = false;
|
|
bFrameRequested[1] = false;
|
|
}
|
|
|
|
bool UMovieSceneCaptureProtocolBase::Setup(const FCaptureProtocolInitSettings& InSettings, const ICaptureProtocolHost* Host)
|
|
{
|
|
InitSettings = InSettings;
|
|
CaptureHost = Host;
|
|
|
|
switch (State)
|
|
{
|
|
case EMovieSceneCaptureProtocolState::Capturing:
|
|
BeginFinalize();
|
|
// fallthrough
|
|
case EMovieSceneCaptureProtocolState::Finalizing:
|
|
Finalize();
|
|
// fallthrough
|
|
default:
|
|
break;
|
|
}
|
|
|
|
State = EMovieSceneCaptureProtocolState::Idle;
|
|
if (!SetupImpl())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
State = EMovieSceneCaptureProtocolState::Initialized;
|
|
return true;
|
|
}
|
|
|
|
UWorld* UMovieSceneCaptureProtocolBase::GetWorld() const
|
|
{
|
|
if (InitSettings.IsSet())
|
|
{
|
|
// Retrieve the world from the Scene Viewport client.
|
|
return InitSettings->SceneViewport->GetClient()->GetWorld();
|
|
}
|
|
|
|
// Otherwise we don't have a world yet - we might be instances created in the
|
|
// UI that aren't tied to the world yet. When Setup is called then the world
|
|
// will be available. We don't want to rely on the Outer for the world as it requires
|
|
// reinitializing the UMovieSceneCaptureProtocolBase just to change the outer.
|
|
return nullptr;
|
|
}
|
|
|
|
void UMovieSceneCaptureProtocolBase::WarmUp()
|
|
{
|
|
if (State == EMovieSceneCaptureProtocolState::Capturing)
|
|
{
|
|
PauseCaptureImpl();
|
|
}
|
|
|
|
if (State == EMovieSceneCaptureProtocolState::Capturing || State == EMovieSceneCaptureProtocolState::Initialized)
|
|
{
|
|
State = EMovieSceneCaptureProtocolState::Initialized;
|
|
WarmUpImpl();
|
|
}
|
|
}
|
|
|
|
bool UMovieSceneCaptureProtocolBase::StartCapture()
|
|
{
|
|
if (State == EMovieSceneCaptureProtocolState::Idle)
|
|
{
|
|
return false;
|
|
}
|
|
else if (State == EMovieSceneCaptureProtocolState::Capturing)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
ensure(State == EMovieSceneCaptureProtocolState::Initialized);
|
|
|
|
State = EMovieSceneCaptureProtocolState::Capturing;
|
|
|
|
if (!StartCaptureImpl())
|
|
{
|
|
State = EMovieSceneCaptureProtocolState::Initialized;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void UMovieSceneCaptureProtocolBase::CaptureFrame(const FFrameMetrics& FrameMetrics)
|
|
{
|
|
if (State == EMovieSceneCaptureProtocolState::Capturing)
|
|
{
|
|
bFrameRequested[GFrameCounter % 2] = true;
|
|
CaptureFrameImpl(FrameMetrics);
|
|
}
|
|
}
|
|
|
|
bool UMovieSceneCaptureProtocolBase::HasFinishedProcessing() const
|
|
{
|
|
return bFrameRequested[GFrameCounter % 2] == false && HasFinishedProcessingImpl();
|
|
}
|
|
|
|
void UMovieSceneCaptureProtocolBase::PreTick()
|
|
{
|
|
// Reset the frame requested bool for the next frame
|
|
bFrameRequested[(GFrameCounter + 1) % 2] = false;
|
|
|
|
PreTickImpl();
|
|
}
|
|
|
|
void UMovieSceneCaptureProtocolBase::Tick()
|
|
{
|
|
TickImpl();
|
|
}
|
|
|
|
void UMovieSceneCaptureProtocolBase::BeginFinalize()
|
|
{
|
|
if (State == EMovieSceneCaptureProtocolState::Idle)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (State == EMovieSceneCaptureProtocolState::Capturing)
|
|
{
|
|
PauseCaptureImpl();
|
|
}
|
|
|
|
State = EMovieSceneCaptureProtocolState::Finalizing;
|
|
BeginFinalizeImpl();
|
|
}
|
|
|
|
void UMovieSceneCaptureProtocolBase::Finalize()
|
|
{
|
|
if (State != EMovieSceneCaptureProtocolState::Finalizing)
|
|
{
|
|
BeginFinalize();
|
|
}
|
|
|
|
if (State == EMovieSceneCaptureProtocolState::Finalizing)
|
|
{
|
|
State = EMovieSceneCaptureProtocolState::Idle;
|
|
FinalizeImpl();
|
|
}
|
|
}
|
|
|
|
void UMovieSceneCaptureProtocolBase::AddFormatMappings(TMap<FString, FStringFormatArg>& FormatMappings) const
|
|
{
|
|
AddFormatMappingsImpl(FormatMappings);
|
|
}
|
|
|
|
void UMovieSceneCaptureProtocolBase::OnReleaseConfig(FMovieSceneCaptureSettings& InSettings)
|
|
{
|
|
OnReleaseConfigImpl(InSettings);
|
|
}
|
|
|
|
void UMovieSceneCaptureProtocolBase::OnLoadConfig(FMovieSceneCaptureSettings& InSettings)
|
|
{
|
|
OnLoadConfigImpl(InSettings);
|
|
}
|
|
|
|
bool UMovieSceneCaptureProtocolBase::CanWriteToFile(const TCHAR* InFilename, bool bOverwriteExisting) const
|
|
{
|
|
return CanWriteToFileImpl(InFilename, bOverwriteExisting);
|
|
}
|
|
|
|
bool UMovieSceneCaptureProtocolBase::CanWriteToFileImpl(const TCHAR* InFilename, bool bOverwriteExisting) const
|
|
{
|
|
return bOverwriteExisting || IFileManager::Get().FileSize(InFilename) == -1;
|
|
}
|
|
|
|
FCaptureProtocolInitSettings FCaptureProtocolInitSettings::FromSlateViewport(TSharedRef<FSceneViewport> InSceneViewport)
|
|
{
|
|
FCaptureProtocolInitSettings Settings;
|
|
Settings.SceneViewport = InSceneViewport;
|
|
Settings.DesiredSize = InSceneViewport->GetSize();
|
|
|
|
// hack for FORT-94554 -- viewport not yet initialized so pull resolution settings from GSystemResolution
|
|
if (Settings.DesiredSize == FIntPoint::ZeroValue)
|
|
{
|
|
Settings.DesiredSize.X = GSystemResolution.ResX;
|
|
Settings.DesiredSize.Y = GSystemResolution.ResY;
|
|
InSceneViewport->SetViewportSize(Settings.DesiredSize.X, Settings.DesiredSize.Y);
|
|
}
|
|
// end hack
|
|
|
|
return Settings;
|
|
}
|
|
|
|
void UMovieSceneCaptureProtocolBase::EnsureFileWritableImpl(const FString& File) const
|
|
{
|
|
FString Directory = FPaths::GetPath(File);
|
|
|
|
if (!IFileManager::Get().DirectoryExists(*Directory))
|
|
{
|
|
IFileManager::Get().MakeDirectory(*Directory);
|
|
}
|
|
|
|
if (CaptureHost->GetSettings().bOverwriteExisting)
|
|
{
|
|
// Try and delete it first
|
|
while (IFileManager::Get().FileSize(*File) != -1 && !FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*File))
|
|
{
|
|
// Pop up a message box
|
|
FText MessageText = FText::Format(LOCTEXT("UnableToRemoveFile_Format", "The destination file '{0}' could not be deleted because it's in use by another application.\n\nPlease close this application before continuing."), FText::FromString(File));
|
|
FPlatformMisc::MessageBoxExt(EAppMsgType::Ok, *MessageText.ToString(), *LOCTEXT("UnableToRemoveFile", "Unable to remove file").ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
FString UMovieSceneCaptureProtocolBase::GenerateFilenameImpl(const FFrameMetrics& FrameMetrics, const TCHAR* Extension, const FString* NameFormatString) const
|
|
{
|
|
FString OutputDirectoryPath = CaptureHost->GetSettings().OutputDirectory.Path;
|
|
FPaths::NormalizeFilename(OutputDirectoryPath);
|
|
|
|
if (!NameFormatString)
|
|
{
|
|
NameFormatString = &CaptureHost->GetSettings().OutputFormat;
|
|
}
|
|
|
|
const FString BaseFilename = CaptureHost->ResolveFileFormat(OutputDirectoryPath, FrameMetrics) / CaptureHost->ResolveFileFormat(*NameFormatString, FrameMetrics);
|
|
|
|
FString ThisTry = BaseFilename + Extension;
|
|
|
|
if (CanWriteToFile(*ThisTry, CaptureHost->GetSettings().bOverwriteExisting))
|
|
{
|
|
return ThisTry;
|
|
}
|
|
|
|
int32 DuplicateIndex = 2;
|
|
for (;;)
|
|
{
|
|
ThisTry = BaseFilename + FString::Printf(TEXT("_(%d)"), DuplicateIndex) + Extension;
|
|
|
|
// If the file doesn't exist, we can use that, else, increment the index and try again
|
|
if (CanWriteToFile(*ThisTry, CaptureHost->GetSettings().bOverwriteExisting))
|
|
{
|
|
return ThisTry;
|
|
}
|
|
|
|
++DuplicateIndex;
|
|
}
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE // "MovieSceneCaptureProtocol"
|