存档移动,封面多线程
This commit is contained in:
parent
18afa49b78
commit
9d6e0b92a0
60
Cut5.sln
60
Cut5.sln
@ -7,67 +7,49 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{233774
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Games", "Games", "{DE1F8B53-6C02-3C13-9101-A7C8D96F3FF6}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Cut5", "Intermediate\ProjectFiles\Cut5.vcxproj", "{B95E7D0E-DB45-3765-9058-E00EBBC4B157}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UE5", "Intermediate\ProjectFiles\UE5.vcxproj", "{6EE39883-7339-3FB6-AD82-931FB137D37F}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UE5", "Intermediate\ProjectFiles\UE5.vcxproj", "{C48D0E9D-C862-3EA3-96A7-752EE9D06362}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Cut5", "Intermediate\ProjectFiles\Cut5.vcxproj", "{AF5A253A-0F37-38CE-8998-45CA936C112B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Visualizers", "Visualizers", "{1CCEC849-CC72-4C59-8C36-2F7C38706D4C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\..\Software\UE_5.2\Engine\Extras\VisualStudioDebugging\Unreal.natvis = ..\..\Software\UE_5.2\Engine\Extras\VisualStudioDebugging\Unreal.natvis
|
||||
D:\UE\UE_5.2\Engine\Extras\VisualStudioDebugging\Unreal.natvis = D:\UE\UE_5.2\Engine\Extras\VisualStudioDebugging\Unreal.natvis
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
DebugGame Editor|Android = DebugGame Editor|Android
|
||||
DebugGame Editor|Win64 = DebugGame Editor|Win64
|
||||
DebugGame|Android = DebugGame|Android
|
||||
DebugGame|Win64 = DebugGame|Win64
|
||||
Development Editor|Android = Development Editor|Android
|
||||
Development Editor|Win64 = Development Editor|Win64
|
||||
Development|Android = Development|Android
|
||||
Development|Win64 = Development|Win64
|
||||
Shipping|Android = Shipping|Android
|
||||
Shipping|Win64 = Shipping|Win64
|
||||
EndGlobalSection
|
||||
# UnrealVS Section
|
||||
GlobalSection(ddbf523f-7eb6-4887-bd51-85a714ff87eb) = preSolution
|
||||
AvailablePlatforms=Win64;Android
|
||||
AvailablePlatforms=Win64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame Editor|Android.ActiveCfg = Invalid|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Editor|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame Editor|Win64.Build.0 = DebugGame_Editor|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame|Android.ActiveCfg = Android_DebugGame|Win64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame|Android.Build.0 = Android_DebugGame|Win64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame|Win64.ActiveCfg = DebugGame|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame|Win64.Build.0 = DebugGame|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development Editor|Android.ActiveCfg = Invalid|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development Editor|Win64.ActiveCfg = Development_Editor|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development Editor|Win64.Build.0 = Development_Editor|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development|Android.ActiveCfg = Android_Development|Win64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development|Android.Build.0 = Android_Development|Win64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development|Win64.ActiveCfg = Development|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development|Win64.Build.0 = Development|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Shipping|Android.ActiveCfg = Android_Shipping|Win64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Shipping|Android.Build.0 = Android_Shipping|Win64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Shipping|Win64.ActiveCfg = Shipping|x64
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Shipping|Win64.Build.0 = Shipping|x64
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362}.DebugGame Editor|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362}.DebugGame Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362}.DebugGame|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362}.DebugGame|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362}.Development Editor|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362}.Development Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362}.Development|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362}.Development|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362}.Shipping|Android.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362}.Shipping|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{6EE39883-7339-3FB6-AD82-931FB137D37F}.DebugGame Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{6EE39883-7339-3FB6-AD82-931FB137D37F}.DebugGame|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{6EE39883-7339-3FB6-AD82-931FB137D37F}.Development Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{6EE39883-7339-3FB6-AD82-931FB137D37F}.Development|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{6EE39883-7339-3FB6-AD82-931FB137D37F}.Shipping|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Editor|x64
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B}.DebugGame Editor|Win64.Build.0 = DebugGame_Editor|x64
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B}.DebugGame|Win64.ActiveCfg = DebugGame|x64
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B}.DebugGame|Win64.Build.0 = DebugGame|x64
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B}.Development Editor|Win64.ActiveCfg = Development_Editor|x64
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B}.Development Editor|Win64.Build.0 = Development_Editor|x64
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B}.Development|Win64.ActiveCfg = Development|x64
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B}.Development|Win64.Build.0 = Development|x64
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B}.Shipping|Win64.ActiveCfg = Shipping|x64
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B}.Shipping|Win64.Build.0 = Shipping|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{C48D0E9D-C862-3EA3-96A7-752EE9D06362} = {233774A8-CC9D-3FA9-86D1-90573E92B704}
|
||||
{B95E7D0E-DB45-3765-9058-E00EBBC4B157} = {DE1F8B53-6C02-3C13-9101-A7C8D96F3FF6}
|
||||
{6EE39883-7339-3FB6-AD82-931FB137D37F} = {233774A8-CC9D-3FA9-86D1-90573E92B704}
|
||||
{AF5A253A-0F37-38CE-8998-45CA936C112B} = {DE1F8B53-6C02-3C13-9101-A7C8D96F3FF6}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
virtual void PreSettingBeforeSeek() {};
|
||||
|
||||
virtual void AddNewCard(FEffectCardProperty& CardProperty, FString GroupName) {};
|
||||
virtual void OpenTimeline(const FString& TimelineName, bool NeedSaveBefore = false, bool ForceOpen = false) {};
|
||||
virtual void OpenTimelineWithRelativePath(const FString& TimelineRelativePath, bool NeedSaveBefore = false, bool ForceOpen = false) {};
|
||||
virtual void CloseTimeline() {};
|
||||
virtual bool OpenProject(const FString& Project) { return false; };
|
||||
virtual bool PreNewProject() { return false; };
|
||||
|
@ -1,11 +1,16 @@
|
||||
#include "VideoThumbnailThread.h"
|
||||
|
||||
#include "Cut5/Utils/FFMPEGUtils.h"
|
||||
#include "Cut5/Utils/Utils.h"
|
||||
|
||||
FVideoThumbnailThread::FVideoThumbnailThread(const FString& MoviePath, TFunction<void(FString)> OnFinished)
|
||||
FVideoThumbnailThread::FVideoThumbnailThread(const FString& MoviePath, TFunction<void(FString)> OnFinished, int32 BrushCount, const FClipData ClipData)
|
||||
{
|
||||
this->MoviePath = MoviePath;
|
||||
this->OnFinished = OnFinished;
|
||||
this->BrushCount = BrushCount;
|
||||
this->ClipData = ClipData;
|
||||
|
||||
bMissionStart = true;
|
||||
}
|
||||
|
||||
uint32 FVideoThumbnailThread::Run()
|
||||
@ -18,31 +23,95 @@ uint32 FVideoThumbnailThread::Run()
|
||||
FTimelinePropertyData Info;
|
||||
FFFMPEGUtils::LoadContextPure(MoviePath, &Info);
|
||||
|
||||
|
||||
|
||||
while (true)
|
||||
int32 i = 0;
|
||||
while (bMissionStart)
|
||||
{
|
||||
AVPacket* Packet = av_packet_alloc();
|
||||
if (av_read_frame(Info.Context, Packet) < 0)
|
||||
if (i < BrushCount && ClipData.ResourcePropertyDataPtr && ClipData.ResourcePropertyDataPtr->Context && ClipData.ResourcePropertyDataPtr->VideoStream != -1)
|
||||
{
|
||||
av_packet_free(&Packet);
|
||||
const int32 CurrentFrame = BrushCount - (BrushCount - i);
|
||||
const int64 Timestamp = av_rescale_q(CurrentFrame / FGlobalData::GlobalFPS * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, Info.Context->streams[Info.VideoStream]->time_base);
|
||||
av_seek_frame(Info.Context, Info.VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD);
|
||||
AVPacket Packet;
|
||||
av_init_packet(&Packet);
|
||||
AVFormatContext* FormatContext = Info.Context;
|
||||
AVCodecContext* VideoCodecContext = Info.VideoCodecContext;
|
||||
AVCodec* VideoCodec = Info.VideoCodec;
|
||||
AVFrame* Frame = av_frame_alloc();
|
||||
|
||||
while (av_read_frame(FormatContext, &Packet) >= 0)
|
||||
{
|
||||
if (avcodec_send_packet(VideoCodecContext, &Packet) < 0)
|
||||
{
|
||||
|
||||
}
|
||||
if (avcodec_receive_frame(VideoCodecContext, Frame) >= 0)
|
||||
{
|
||||
if (Frame->best_effort_timestamp >= Timestamp)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
if (Frame)
|
||||
{
|
||||
if (Frame->width == 0 || Frame->height == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
struct SwsContext* swsCtx = sws_getContext(
|
||||
Frame->width, Frame->height, VideoCodecContext->pix_fmt,
|
||||
Frame->width / 10, Frame->height / 10, AV_PIX_FMT_BGRA,
|
||||
SWS_BILINEAR, NULL, NULL, NULL
|
||||
);
|
||||
if (!swsCtx)
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("Error creating swsContext"));
|
||||
}
|
||||
uint8* RawData = new uint8[(Frame->width / 10) * (Frame->height / 10) * 4];
|
||||
uint8* dest[4] = {RawData, 0, 0, 0};
|
||||
int32 dest_linesize[4] = {(Frame->width / 10) * 4, 0, 0, 0};
|
||||
sws_scale(swsCtx, Frame->data, Frame->linesize, 0, Frame->height, dest, dest_linesize);
|
||||
sws_freeContext(swsCtx);
|
||||
|
||||
|
||||
AsyncTask(ENamedThreads::GameThread, [Frame, RawData, this]()
|
||||
{
|
||||
UTexture2D* Texture = UTexture2D::CreateTransient(Frame->width / 10, Frame->height / 10, PF_B8G8R8A8);
|
||||
if (Texture)
|
||||
{
|
||||
void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
|
||||
FMemory::Memcpy(MipData, RawData, (Frame->width / 10) * (Frame->height / 10) * 4);
|
||||
Texture->GetPlatformData()->Mips[0].BulkData.Unlock();
|
||||
Texture->UpdateResource();
|
||||
|
||||
FGuid Guid = FGuid::NewGuid();
|
||||
FFFMPEGUtils::ExportImage(Texture, ToFullPath(FUtils::GetProjectTempPath() / ClipData.ClipGuid.ToString() / Guid.ToString() + ".png"));
|
||||
OnFinished(FUtils::GetProjectTempPath() / ClipData.ClipGuid.ToString() / Guid.ToString() + ".png");
|
||||
|
||||
|
||||
Texture->MarkAsGarbage();
|
||||
delete RawData;
|
||||
}
|
||||
});
|
||||
|
||||
i++;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bMissionStart = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (avcodec_send_packet(Info.VideoCodecContext, Packet) < 0)
|
||||
{
|
||||
|
||||
}
|
||||
AVFrame* Frame = av_frame_alloc();
|
||||
if (avcodec_receive_frame(Info.VideoCodecContext, Frame) >= 0)
|
||||
{
|
||||
|
||||
int32 CurrentTime = av_rescale(Frame->best_effort_timestamp, Info.VideoCodecContext->time_base.den, AV_TIME_BASE);
|
||||
UE_LOG(LogTemp, Warning, TEXT("Frame->best_effort_timestamp: %d"), CurrentTime);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
#include "Cut5/Widgets/DefineGlobal.h"
|
||||
|
||||
class FVideoThumbnailThread : public FRunnable
|
||||
{
|
||||
public:
|
||||
|
||||
FVideoThumbnailThread(const FString& MoviePath, TFunction<void(FString)> OnFinished);
|
||||
FVideoThumbnailThread(const FString& MoviePath, TFunction<void(FString)> OnFinished, int32 BrushCount, const FClipData ClipData);
|
||||
|
||||
virtual bool Init() override { return true; }
|
||||
virtual uint32 Run() override;
|
||||
@ -13,5 +14,7 @@ public:
|
||||
|
||||
FString MoviePath;
|
||||
TFunction<void(FString)> OnFinished;
|
||||
|
||||
int32 BrushCount;
|
||||
FClipData ClipData;
|
||||
bool bMissionStart = false;
|
||||
};
|
||||
|
@ -106,7 +106,7 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
|
||||
|
||||
FGuid Guid = FGuid::NewGuid();
|
||||
ExportImage(Texture, *FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, "Resources", "Thumbnail", Guid.ToString() + ".png"));
|
||||
PropertyData->IconPath = FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, "Resources", "Thumbnail", Guid.ToString() + ".png");
|
||||
PropertyData->IconPath = FString() / TEXT("Resources") / TEXT("Thumbnail") / Guid.ToString() + ".png";
|
||||
Texture->MarkAsGarbage();
|
||||
delete RawData;
|
||||
}
|
||||
@ -197,7 +197,7 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
|
||||
}
|
||||
|
||||
PropertyData->Name = FPaths::GetBaseFilename(Path);
|
||||
PropertyData->MoviePath = NewPath;
|
||||
PropertyData->MoviePath = Path;
|
||||
|
||||
|
||||
return {};
|
||||
@ -205,8 +205,19 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
|
||||
|
||||
FString FFFMPEGUtils::LoadContextPure(const FString& Path, FTimelinePropertyData* PropertyData)
|
||||
{
|
||||
|
||||
FString NewPath;
|
||||
if (FPaths::IsRelative(Path))
|
||||
{
|
||||
NewPath = FGlobalData::BasePath / FGlobalData::CurrentProjectName / Path;
|
||||
}
|
||||
else
|
||||
{
|
||||
NewPath = Path;
|
||||
}
|
||||
|
||||
AVFormatContext* FormatContext = nullptr;
|
||||
if (avformat_open_input(&FormatContext, TCHAR_TO_UTF8(*Path), nullptr, nullptr) != 0)
|
||||
if (avformat_open_input(&FormatContext, TCHAR_TO_UTF8(*NewPath), nullptr, nullptr) != 0)
|
||||
{
|
||||
return TEXT("Failed");
|
||||
}
|
||||
@ -268,7 +279,7 @@ FString FFFMPEGUtils::LoadContextPure(const FString& Path, FTimelinePropertyData
|
||||
PropertyData->Type = ETrackType::AudioTrack;
|
||||
}
|
||||
PropertyData->Name = FPaths::GetBaseFilename(Path);
|
||||
PropertyData->MoviePath = Path;
|
||||
PropertyData->MoviePath = NewPath;
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -358,7 +369,7 @@ TArray<FSlateBrush> FFFMPEGUtils::GetMovieBrush(FClipData* ClipData, bool Regene
|
||||
{
|
||||
for (int32 i = 0; i < ClipData->MovieBrushesPath.Num(); i++)
|
||||
{
|
||||
FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ClipData->MovieBrushesPath[i], FVector2f(0, 0));
|
||||
FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ToFullPath(ClipData->MovieBrushesPath[i]), FVector2f(0, 0));
|
||||
ClipData->MovieBrushNum++;
|
||||
Result.Add(Brush);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ FString FUtils::GetResourcesPath(FString ResourcesName, bool bFullPath)
|
||||
|
||||
FString FUtils::GetProjectTempPath()
|
||||
{
|
||||
return FPaths::ConvertRelativePathToFull(FPaths::Combine(FGlobalData::BasePath / FGlobalData::CurrentProjectName / "/Temp/"));
|
||||
return TEXT("Temp/");
|
||||
}
|
||||
|
||||
FSlateDynamicImageBrush* FUtils::GetBrushFromImage(const FString& ImageName, const FVector2D Size)
|
||||
@ -370,7 +370,7 @@ TArray<FEncodeVideoInfo> FUtils::TrackEncodeVideo(const FTrackData& TrackData, c
|
||||
|
||||
FString StartTime = FString::Printf(TEXT("%02d:%02d:%02d.%s"), StartTimespan.GetHours(), StartTimespan.GetMinutes(), StartTimespan.GetSeconds(), *NewStartMilli);
|
||||
FString EndTime = FString::Printf(TEXT("%02d:%02d:%02d.%s"), EndTimespan.GetHours(), EndTimespan.GetMinutes(), EndTimespan.GetSeconds(), *NewEndMilli);
|
||||
FString InputFile = "\"" + TempClipData.ResourcePropertyDataPtr->MoviePath + "\"";
|
||||
FString InputFile = "\"" + ToFullPath(TempClipData.ResourcePropertyDataPtr->MoviePath) + "\"";
|
||||
|
||||
|
||||
FString OutputFile = "\"" + FPaths::ConvertRelativePathToFull(ExportPath + FString::FromInt(i) + TEXT(".mp4")) + "\"";
|
||||
@ -440,7 +440,7 @@ FEncodeVideoInfo FUtils::TrackEncodeAudio(const FTrackData& TrackData, const FSt
|
||||
|
||||
FString StartTime = FString::Printf(TEXT("%02d:%02d:%02d"), StartTimespan.GetHours(), StartTimespan.GetMinutes(), StartTimespan.GetSeconds());
|
||||
FString EndTime = FString::Printf(TEXT("%02d:%02d:%02d"), EndTimespan.GetHours(), EndTimespan.GetMinutes(), EndTimespan.GetSeconds());
|
||||
FString InputFile = TempClipData.ResourcePropertyDataPtr->MoviePath;
|
||||
FString InputFile = ToFullPath(TempClipData.ResourcePropertyDataPtr->MoviePath);
|
||||
|
||||
FString OutputFile = ExportPath + TEXT(".mp3");
|
||||
|
||||
@ -632,8 +632,7 @@ TArray<FEncodeVideoInfo> FUtils::ExportPsaf(FTrackData TrackData, const FString&
|
||||
FString ExportName = FGuid::NewGuid().ToString();;
|
||||
if (TempClipData.ResourcePropertyDataPtr)
|
||||
{
|
||||
TempClipData.ResourcePropertyDataPtr->MoviePath;
|
||||
FString TempPath = TempClipData.ResourcePropertyDataPtr->MoviePath;
|
||||
FString TempPath = ToFullPath(TempClipData.ResourcePropertyDataPtr->MoviePath);
|
||||
frames.Empty();
|
||||
|
||||
VideoCapture capture;
|
||||
|
@ -2,6 +2,11 @@
|
||||
#include "CoreMinimal.h"
|
||||
#include "Cut5/Widgets/DefineGlobal.h"
|
||||
|
||||
inline FString ToFullPath(const FString& String)
|
||||
{
|
||||
return FGlobalData::BasePath / FGlobalData::CurrentProjectName / String;
|
||||
}
|
||||
|
||||
class FUtils
|
||||
{
|
||||
public:
|
||||
@ -36,22 +41,20 @@ public:
|
||||
static TArray<FEncodeVideoInfo> TrackEncodeVideo(const FTrackData& TrackData, const FString& ExportPath);
|
||||
static FEncodeVideoInfo TrackEncodeAudio(const FTrackData& TrackDataLeft, const FString& ExportPath);
|
||||
static FEncodeVideoInfo CombineAudio(const FEncodeVideoInfo& LeftEncodeData, const FEncodeVideoInfo& RightEncodeData, const FString& ExportPath);
|
||||
static FString CurtainFullPath(const FString& GroupName)
|
||||
|
||||
static FString CurtainRelativePath(const FString& GroupName)
|
||||
{
|
||||
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("Curtain"), GroupName + TEXT(".bin"));
|
||||
return TEXT("Curtain") / GroupName + TEXT(".bin");
|
||||
};
|
||||
static FString GroupFullPath(const FString& GroupName)
|
||||
static FString GroupRelativePath(const FString& GroupName)
|
||||
{
|
||||
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), GroupName + TEXT(".bin"));
|
||||
return TEXT("FX") / GroupName + TEXT(".bin");
|
||||
};
|
||||
static FString SingleCardFullPath(const FString& CardName)
|
||||
static FString SingleCardRelativePath(const FString& CardName)
|
||||
{
|
||||
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), TEXT("SingleCard"), CardName + TEXT(".bin"));
|
||||
return FString() / TEXT("FX") / TEXT("SingleCard") / CardName + TEXT(".bin");
|
||||
};
|
||||
static FString MainSaveFullPath()
|
||||
{
|
||||
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, FGlobalData::CurrentProjectName + TEXT(".bin"));
|
||||
};
|
||||
|
||||
|
||||
static FUtils* GetInstance()
|
||||
{
|
||||
|
@ -163,17 +163,17 @@ TSharedPtr<FCurtainDragDrop> SCurtain::OpenThis()
|
||||
|
||||
|
||||
// 没有Curtain就Create一个
|
||||
if (!FPaths::FileExists(FUtils::CurtainFullPath(Curtain->CurtainUUID.ToString())))
|
||||
if (!FPaths::FileExists(ToFullPath(FUtils::CurtainRelativePath(Curtain->CurtainUUID.ToString()))))
|
||||
{
|
||||
FUtils::CreateDefaultTimelineSave(FUtils::CurtainFullPath(Curtain->CurtainUUID.ToString()), FTimelineInfo::ETimelineType::FX);
|
||||
FUtils::CreateDefaultTimelineSave(ToFullPath(FUtils::CurtainRelativePath(Curtain->CurtainUUID.ToString())), FTimelineInfo::ETimelineType::FX);
|
||||
{
|
||||
FSaveModifier SaveModifier(FUtils::CurtainFullPath(Curtain->CurtainUUID.ToString()));
|
||||
SaveModifier.TimelineInfo.CurrentOpenFullPath = FUtils::CurtainFullPath(Curtain->CurtainUUID.ToString());
|
||||
FSaveModifier SaveModifier(ToFullPath(FUtils::CurtainRelativePath(Curtain->CurtainUUID.ToString())));
|
||||
SaveModifier.TimelineInfo.CurrentOpenRelativePath = FUtils::CurtainRelativePath(Curtain->CurtainUUID.ToString());
|
||||
SaveModifier.TimelineInfo.CurrentOpenType = FTimelineInfo::ETimelineType::FX;
|
||||
Curtain->TimelineInfo = SaveModifier.TimelineInfo;
|
||||
}
|
||||
}
|
||||
CurtainPanel->MainWidgetInterface->OpenTimeline(FUtils::CurtainFullPath(Curtain->CurtainUUID.ToString()), true);
|
||||
CurtainPanel->MainWidgetInterface->OpenTimelineWithRelativePath(FUtils::CurtainRelativePath(Curtain->CurtainUUID.ToString()), true);
|
||||
|
||||
|
||||
|
||||
|
@ -272,10 +272,10 @@ void SCurtainPanel::AddNewCurtain(int32 Index)
|
||||
if (Index < Groups.Num())
|
||||
{
|
||||
FCurtain Curtain;
|
||||
FUtils::CreateDefaultTimelineSave(FUtils::CurtainFullPath(Curtain.CurtainUUID.ToString()), FTimelineInfo::ETimelineType::FX);
|
||||
FUtils::CreateDefaultTimelineSave(ToFullPath(FUtils::CurtainRelativePath(Curtain.CurtainUUID.ToString())), FTimelineInfo::ETimelineType::FX);
|
||||
{
|
||||
FSaveModifier SaveModifier(FUtils::CurtainFullPath(Curtain.CurtainUUID.ToString()));
|
||||
SaveModifier.TimelineInfo.CurrentOpenFullPath = FUtils::CurtainFullPath(Curtain.CurtainUUID.ToString());
|
||||
FSaveModifier SaveModifier(ToFullPath(FUtils::CurtainRelativePath(Curtain.CurtainUUID.ToString())));
|
||||
SaveModifier.TimelineInfo.CurrentOpenRelativePath = FUtils::CurtainRelativePath(Curtain.CurtainUUID.ToString());
|
||||
SaveModifier.TimelineInfo.CurrentOpenType = FTimelineInfo::ETimelineType::FX;
|
||||
Curtain.TimelineInfo = SaveModifier.TimelineInfo;
|
||||
}
|
||||
|
@ -763,18 +763,21 @@ struct CUT5_API FTimelineInfo
|
||||
Main,
|
||||
FX,
|
||||
};
|
||||
FString CurrentOpenFullPath = "";
|
||||
FString CurrentOpenRelativePath = "";
|
||||
|
||||
FTimelineInfo::ETimelineType CurrentOpenType = ETimelineType::Main;
|
||||
|
||||
friend FArchive& operator<<(FArchive& Ar, FTimelineInfo& TimelineInfo)
|
||||
{
|
||||
Ar << TimelineInfo.CurrentOpenFullPath;
|
||||
Ar << TimelineInfo.CurrentOpenRelativePath;
|
||||
Ar << TimelineInfo.CurrentOpenType;
|
||||
return Ar;
|
||||
};
|
||||
FString GetSavePath()
|
||||
|
||||
// 得到完整目录,考虑到项目迁移所以保存的是 相对路径, 但是在打开的时候需要转换成绝对路径
|
||||
FString GetSaveFullPath()
|
||||
{
|
||||
return CurrentOpenFullPath;
|
||||
return FGlobalData::BasePath / FGlobalData::CurrentProjectName / CurrentOpenRelativePath;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -791,13 +791,13 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
|
||||
{
|
||||
NewClipData.ClipType = ETrackType::PlayerTrack;
|
||||
NewClipData.PlayerName = TrackBody->MainWidgetInterface->GetGroupName(TrackHead);
|
||||
NewClipData.PlayerLightData = FOpencvUtils::GetVideoSingleLightColor(ClipDragOperation.TimelinePropertyData->MoviePath);
|
||||
NewClipData.PlayerLightData = FOpencvUtils::GetVideoSingleLightColor(ToFullPath(ClipDragOperation.TimelinePropertyData->MoviePath));
|
||||
}
|
||||
if (TrackHead->TrackData.TrackType == ETrackType::AtomSphereLightTrack)
|
||||
{
|
||||
NewClipData.ClipType = ETrackType::AtomSphereLightTrack;
|
||||
NewClipData.PlayerName = TrackBody->MainWidgetInterface->GetGroupName(TrackHead);
|
||||
NewClipData.PlayerLightData = FOpencvUtils::GetVideoSingleLightColor(ClipDragOperation.TimelinePropertyData->MoviePath);
|
||||
NewClipData.PlayerLightData = FOpencvUtils::GetVideoSingleLightColor(ToFullPath(ClipDragOperation.TimelinePropertyData->MoviePath));
|
||||
}
|
||||
}
|
||||
else if (ClipDragOperation.TimelinePropertyData->Type == ETrackType::LightArrayTrack)
|
||||
|
@ -76,7 +76,7 @@ void SEffectCard::Construct(const FArguments& InArgs)
|
||||
}
|
||||
else
|
||||
{
|
||||
MainInterface->OpenTimeline(FUtils::SingleCardFullPath(CardProperty->Guid.ToString()), true);
|
||||
MainInterface->OpenTimelineWithRelativePath(FUtils::SingleCardRelativePath(CardProperty->Guid.ToString()), true);
|
||||
}
|
||||
|
||||
PropertiesInterfaceGUID = CardProperty->Guid;
|
||||
|
@ -474,8 +474,8 @@ void SEffectCardGroup::OnSelect()
|
||||
{
|
||||
if (EffectCardGroup->bIsDedicated == false)
|
||||
{
|
||||
const FString Name = FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), EffectCardGroup->Guid.ToString() + TEXT(".bin"));
|
||||
MainInterface->OpenTimeline(Name, true);
|
||||
const FString Name = TEXT("FX") / EffectCardGroup->Guid.ToString() + TEXT(".bin");
|
||||
MainInterface->OpenTimelineWithRelativePath(Name, true);
|
||||
MainInterface->CurrentSelectedPropertiesInterfaceGuid = EffectCardGroup->Guid;
|
||||
MainInterface->UpdateProperties(this);
|
||||
MainInterface->GetSelf()->DeselectAll();
|
||||
@ -516,10 +516,10 @@ void SEffectCardGroup::CallRender()
|
||||
|
||||
|
||||
|
||||
FUtils::CreateDefaultTimelineSave(FUtils::SingleCardFullPath(NewCard.Guid.ToString()), FTimelineInfo::ETimelineType::FX);
|
||||
FUtils::CreateDefaultTimelineSave(ToFullPath(FUtils::SingleCardRelativePath(NewCard.Guid.ToString())), FTimelineInfo::ETimelineType::FX);
|
||||
{
|
||||
FSaveModifier SaveModifier(FUtils::SingleCardFullPath(NewCard.Guid.ToString()));
|
||||
SaveModifier.TimelineInfo.CurrentOpenFullPath = FUtils::SingleCardFullPath(NewCard.Guid.ToString());
|
||||
FSaveModifier SaveModifier(ToFullPath(FUtils::SingleCardRelativePath(NewCard.Guid.ToString())));
|
||||
SaveModifier.TimelineInfo.CurrentOpenRelativePath = FUtils::SingleCardRelativePath(NewCard.Guid.ToString());
|
||||
SaveModifier.TimelineInfo.CurrentOpenType = FTimelineInfo::ETimelineType::FX;
|
||||
NewCard.TimelineInfo = SaveModifier.TimelineInfo;
|
||||
}
|
||||
|
@ -110,13 +110,13 @@ void SEffectCardsPanel::CallRender()
|
||||
int32 ID = GetCurrentID(true);
|
||||
Group->ID = ID;
|
||||
|
||||
const FString NewPath = FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), NewGuid.ToString() + TEXT(".bin"));
|
||||
FUtils::CreateDefaultTimelineSave(NewPath, FTimelineInfo::ETimelineType::FX);
|
||||
const FString NewPath = TEXT("FX") / NewGuid.ToString() + TEXT(".bin");
|
||||
FUtils::CreateDefaultTimelineSave(ToFullPath(NewPath), FTimelineInfo::ETimelineType::FX);
|
||||
{
|
||||
FSaveModifier SaveModifier(NewPath);
|
||||
SaveModifier.TimelineInfo.CurrentOpenFullPath = NewPath;
|
||||
FSaveModifier SaveModifier(ToFullPath(NewPath));
|
||||
SaveModifier.TimelineInfo.CurrentOpenRelativePath = NewPath;
|
||||
}
|
||||
Group->TimelineInfo.CurrentOpenFullPath = NewPath;
|
||||
Group->TimelineInfo.CurrentOpenRelativePath = NewPath;
|
||||
CallRender();
|
||||
return FReply::Handled();
|
||||
})
|
||||
@ -157,7 +157,7 @@ void SEffectCardsPanel::RemoveCard(const FGuid& GUID)
|
||||
{
|
||||
if (Group.bIsActive == true)
|
||||
{
|
||||
MainInterface->OpenTimeline(FUtils::MainSaveFullPath(), true);
|
||||
MainInterface->OpenTimelineWithRelativePath("", true);
|
||||
}
|
||||
EffectCardGroups.RemoveAt(j);
|
||||
break;
|
||||
@ -170,7 +170,7 @@ void SEffectCardsPanel::RemoveCard(const FGuid& GUID)
|
||||
{
|
||||
if (Group.Cards[i].bIsActive == true)
|
||||
{
|
||||
MainInterface->OpenTimeline(FUtils::MainSaveFullPath(), true);
|
||||
MainInterface->OpenTimelineWithRelativePath("", true);
|
||||
}
|
||||
Group.Cards.RemoveAt(i);
|
||||
}
|
||||
@ -193,7 +193,7 @@ void SEffectCardsPanel::RemoveCardInGroup(const FGuid& Guid, const FGuid& GroupG
|
||||
{
|
||||
if (Property.bIsActive == true)
|
||||
{
|
||||
MainInterface->OpenTimeline(FUtils::MainSaveFullPath());
|
||||
MainInterface->OpenTimelineWithRelativePath("");
|
||||
}
|
||||
Group.Cards.RemoveAt(i);
|
||||
break;
|
||||
@ -365,9 +365,7 @@ void SEffectCardsPanel::SavePanel(const FString& Path)
|
||||
{
|
||||
for (FEffectCardProperty& Property : Group.Cards)
|
||||
{
|
||||
FString Target = Property.TimelineInfo.CurrentOpenFullPath;
|
||||
FPaths::CollapseRelativeDirectories(Target);
|
||||
IFileManager::Get().Move(*FPaths::Combine(Path, "FX", "Cards"), *Property.TimelineInfo.CurrentOpenFullPath);
|
||||
IFileManager::Get().Move(*FPaths::Combine(Path, "FX", "Cards"), *ToFullPath(Property.TimelineInfo.CurrentOpenRelativePath));
|
||||
}
|
||||
MemoryWriter << Group;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ void SCustomInputResource::Construct(const FArguments& InArgs)
|
||||
[
|
||||
SNew(SImage)
|
||||
.Image( (PropertyData.VideoStream == -1 && PropertyData.AudioStream != -1) ? FUtils::GetBrushFromImage(FUtils::GetResourcesPath(TEXT("Music.png")), {}) :
|
||||
PropertyData.bIsCustomPresetData == false ? FUtils::GetBrushFromImage(PropertyData.IconPath, {}) : FUtils::GetBrushFromImage(FUtils::GetResourcesPath("CustomPreset.png"), {}))
|
||||
PropertyData.bIsCustomPresetData == false ? FUtils::GetBrushFromImage(ToFullPath(PropertyData.IconPath), {}) : FUtils::GetBrushFromImage(FUtils::GetResourcesPath("CustomPreset.png"), {}))
|
||||
]
|
||||
+ SOverlay::Slot()
|
||||
.HAlign(HAlign_Center)
|
||||
@ -91,7 +91,7 @@ FReply SCustomInputResource::OnDragDetected(const FGeometry& MyGeometry, const F
|
||||
[
|
||||
SNew(SImage)
|
||||
.Image( (PropertyData.VideoStream == -1 && PropertyData.AudioStream != -1) ? FUtils::GetBrushFromImage(FUtils::GetResourcesPath(TEXT("Music.png")), {}) :
|
||||
PropertyData.bIsCustomPresetData == false ? FUtils::GetBrushFromImage(PropertyData.IconPath, {}) : FUtils::GetBrushFromImage(FUtils::GetResourcesPath("CustomPreset.png"), {}))
|
||||
PropertyData.bIsCustomPresetData == false ? FUtils::GetBrushFromImage(ToFullPath(PropertyData.IconPath), {}) : FUtils::GetBrushFromImage(FUtils::GetResourcesPath("CustomPreset.png"), {}))
|
||||
];
|
||||
|
||||
return FReply::Handled().BeginDragDrop(Operation.ToSharedRef());
|
||||
|
@ -453,7 +453,7 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
|
||||
}));
|
||||
CommandList->MapAction(FShortCutCommands::Get().ZoomOutTimeline, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
if (CutTimeline->ZoomSlider->GetValue() >= 0.1)
|
||||
if (CutTimeline->ZoomSlider->GetValue() >= 0.0)
|
||||
{
|
||||
const float NewValue = CutTimeline->ZoomSlider->GetValue() - 0.1;
|
||||
CutTimeline->UpdateZoom(NewValue);
|
||||
@ -902,37 +902,29 @@ void SCutMainWindow::AddNewCard(FEffectCardProperty& CardProperty, FString Group
|
||||
EffectCardsPanel->AddNewCard(CardProperty, GroupName);
|
||||
}
|
||||
|
||||
void SCutMainWindow::OpenTimeline(const FString& TimelineName, bool NeedSaveBefore, bool ForceOpen)
|
||||
void SCutMainWindow::OpenTimelineWithRelativePath(const FString& TimelineRelativePath, bool NeedSaveBefore, bool ForceOpen)
|
||||
{
|
||||
CutTimeline->bNeedShowPanel = true;
|
||||
if (NeedSaveBefore)
|
||||
{
|
||||
CutTimeline->SaveTimeline(CutTimeline->TimelineInfo.CurrentOpenFullPath, CutTimeline->TimelineInfo);
|
||||
CutTimeline->TimelineInfo.CurrentOpenFullPath = TimelineName;
|
||||
CutTimeline->SaveTimeline(CutTimeline->TimelineInfo.CurrentOpenRelativePath, CutTimeline->TimelineInfo);
|
||||
CutTimeline->TimelineInfo.CurrentOpenRelativePath = TimelineRelativePath;
|
||||
}
|
||||
//
|
||||
// if (TimelineName == CutTimeline->TimelineInfo.CurrentOpenFullPath && !ForceOpen)
|
||||
// {
|
||||
// CloseTimeline();
|
||||
// return;
|
||||
// }
|
||||
|
||||
FTimelineInfo TimelineInfo;
|
||||
// 拿到TimelineName路径中的名字,也就是倒数第四位开始,去掉后缀
|
||||
|
||||
if (CutTimeline->LoadTimeline(TimelineName, TimelineInfo))
|
||||
if (CutTimeline->LoadTimeline(TimelineRelativePath, TimelineInfo))
|
||||
{
|
||||
CutTimeline->TimelineInfo = TimelineInfo;
|
||||
// CutTimeline->CurrentEditDebug->SetText(FText::FromString(TEXT("当前正在编辑") + TimelineInfo.CurrentOpenFullPath));
|
||||
}
|
||||
|
||||
|
||||
OnAddNewTrack(ETrackType::PlayerTrack);
|
||||
|
||||
}
|
||||
|
||||
void SCutMainWindow::CloseTimeline()
|
||||
{
|
||||
CutTimeline->bNeedShowPanel = false;
|
||||
CutTimeline->SaveTimeline(CutTimeline->TimelineInfo.CurrentOpenFullPath, CutTimeline->TimelineInfo);
|
||||
CutTimeline->SaveTimeline(CutTimeline->TimelineInfo.CurrentOpenRelativePath, CutTimeline->TimelineInfo);
|
||||
CutTimeline->RenderGroup();
|
||||
}
|
||||
|
||||
@ -1261,7 +1253,7 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
|
||||
ExportCard.SerialID.Add(EffectCardsPanel->EffectCardGroups[i].Cards[j].ID);
|
||||
|
||||
|
||||
ExportCard.TimelinePath = FUtils::SingleCardFullPath(EffectCardsPanel->EffectCardGroups[i].Cards[j].Guid.ToString());
|
||||
ExportCard.TimelinePath = ToFullPath(FUtils::SingleCardRelativePath(EffectCardsPanel->EffectCardGroups[i].Cards[j].Guid.ToString()));
|
||||
ExportCard.CardGuid = EffectCardsPanel->EffectCardGroups[i].Cards[j].Guid;
|
||||
ExportCards.Add(ExportCard);
|
||||
UE_LOG(LogTemp, Log, TEXT("ExportCard.TimelinePath = %s"), *ExportCard.TimelinePath);
|
||||
@ -1301,7 +1293,7 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
|
||||
}
|
||||
|
||||
|
||||
ExportCard.TimelinePath = FUtils::GroupFullPath(EffectCardsPanel->EffectCardGroups[i].Guid.ToString());
|
||||
ExportCard.TimelinePath = ToFullPath(FUtils::GroupRelativePath(EffectCardsPanel->EffectCardGroups[i].Guid.ToString()));
|
||||
ExportCard.CardGuid = EffectCardsPanel->EffectCardGroups[i].Guid;
|
||||
ExportCards.Add(ExportCard);
|
||||
}
|
||||
@ -1417,10 +1409,8 @@ void SCutMainWindow::ImportProject(const FString& ImportPath)
|
||||
|
||||
void SCutMainWindow::NewProject(const FString& NewPath)
|
||||
{
|
||||
|
||||
|
||||
FGlobalData::BasePath = NewPath;
|
||||
CutTimeline->TimelineInfo.CurrentOpenFullPath = FUtils::MainSaveFullPath();
|
||||
CutTimeline->TimelineInfo.CurrentOpenRelativePath = "";
|
||||
}
|
||||
|
||||
void SCutMainWindow::SaveProject()
|
||||
@ -1433,7 +1423,7 @@ void SCutMainWindow::SaveProject()
|
||||
// 根 << 记录所有导入资产链接
|
||||
// 根 << 记录所有幕
|
||||
// 根 << 记录所有组轨道链接
|
||||
CutTimeline->SaveTimeline(CutTimeline->TimelineInfo.CurrentOpenFullPath, CutTimeline->TimelineInfo);
|
||||
CutTimeline->SaveTimeline(CutTimeline->TimelineInfo.CurrentOpenRelativePath, CutTimeline->TimelineInfo);
|
||||
|
||||
// 新建项目关联文件.cutlink
|
||||
TArray<uint8> ProjectLinkData;
|
||||
@ -2387,7 +2377,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetProcessA(tinyxml2::XMLElement* Parent,
|
||||
DeselectAll();
|
||||
CurtainPanel->DeSelectedAll();
|
||||
CurtainGroup->Curtains[i].bIsActive = true;
|
||||
OpenTimeline(CurtainGroup->Curtains[i].TimelineInfo.CurrentOpenFullPath, true, true);
|
||||
OpenTimelineWithRelativePath(CurtainGroup->Curtains[i].TimelineInfo.CurrentOpenRelativePath, true, true);
|
||||
GetProcessB(ProcessA, &CurtainGroup->Curtains[i]);
|
||||
}
|
||||
if (CurtainGroup->Curtains.Num() == 0)
|
||||
@ -2487,7 +2477,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffectList(tinyxml2::XMLElement*
|
||||
{
|
||||
DeselectAll();
|
||||
SetActive(ExportCard.CardGuid);
|
||||
OpenTimeline(ExportCard.TimelinePath, true, true);
|
||||
OpenTimelineWithRelativePath(ExportCard.TimelinePath, true, true);
|
||||
|
||||
tinyxml2::XMLElement* SpecialEffect = SpecialEffectsList->InsertNewChildElement("SpecialEffect");
|
||||
tinyxml2::XMLElement* Effect = SpecialEffect->InsertNewChildElement("Effect");
|
||||
@ -3006,7 +2996,7 @@ int32 SCutMainWindow::CalculateExportCount()
|
||||
{
|
||||
for (FCurtain& Curtain : CurtainGroup.Curtains)
|
||||
{
|
||||
FTimelineLoader TimelineLoader(Curtain.TimelineInfo.CurrentOpenFullPath);
|
||||
FTimelineLoader TimelineLoader(ToFullPath(Curtain.TimelineInfo.CurrentOpenRelativePath));
|
||||
Count += TimelineLoader.GetClipData().Num();
|
||||
}
|
||||
}
|
||||
@ -3016,13 +3006,13 @@ int32 SCutMainWindow::CalculateExportCount()
|
||||
{
|
||||
for (FEffectCardProperty& Property : Group.Cards)
|
||||
{
|
||||
FTimelineLoader TimelineLoader(Property.TimelineInfo.CurrentOpenFullPath);
|
||||
FTimelineLoader TimelineLoader(ToFullPath(Property.TimelineInfo.CurrentOpenRelativePath));
|
||||
Count += TimelineLoader.GetClipData().Num();
|
||||
}
|
||||
}
|
||||
for (FEffectCardProperty& Property : Group.Cards)
|
||||
{
|
||||
FTimelineLoader TimelineLoader(Property.TimelineInfo.CurrentOpenFullPath);
|
||||
FTimelineLoader TimelineLoader(ToFullPath(Property.TimelineInfo.CurrentOpenRelativePath));
|
||||
Count += TimelineLoader.GetClipData().Num();
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public:
|
||||
virtual void SelectClip(const FGuid& Guid) override;
|
||||
// 不好 到时候改成 Group Widget 内部操作
|
||||
virtual void AddNewCard(FEffectCardProperty& CardProperty, FString GroupName) override;
|
||||
virtual void OpenTimeline(const FString& TimelineName, bool NeedSaveBefore, bool ForceOpen = false) override;
|
||||
virtual void OpenTimelineWithRelativePath(const FString& TimelineRelativePath, bool NeedSaveBefore, bool ForceOpen = false) override;
|
||||
virtual void CloseTimeline() override;
|
||||
virtual bool OpenProject(const FString& Project) override;
|
||||
virtual void ExportProject(const FString& ExportPath) override;
|
||||
|
@ -418,7 +418,7 @@ void SCutTimeline::Construct(const FArguments& InArgs)
|
||||
|
||||
];
|
||||
TrackHeadScrollBox->SetScrollBarVisibility(EVisibility::Hidden);
|
||||
TimelineInfo.CurrentOpenFullPath = FUtils::MainSaveFullPath();
|
||||
TimelineInfo.CurrentOpenRelativePath = "";
|
||||
|
||||
FDeviceTrack Volume(TEXT("音量数据"), ETrackType::VolumeTrack);
|
||||
AddNewDeviceToGroup(TEXT("固定轨道"), Volume);
|
||||
@ -760,14 +760,26 @@ void SCutTimeline::SaveTimeline(const FString& SavedPath, FTimelineInfo Info)
|
||||
MemoryWriter << ClipLength;
|
||||
MemoryWriter << AllClips;
|
||||
|
||||
FString NewSavedPath = FPaths::ConvertRelativePathToFull(SavedPath);
|
||||
FString NewSavedPath = ToFullPath(SavedPath);
|
||||
|
||||
FFileHelper::SaveArrayToFile(SavedData, *NewSavedPath);
|
||||
}
|
||||
|
||||
bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info)
|
||||
{
|
||||
if (LoadPath == "")
|
||||
{
|
||||
bNeedShowPanel = false;
|
||||
TimelineInfo.CurrentOpenRelativePath = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
FString NewLoadPath = ToFullPath(LoadPath);
|
||||
|
||||
|
||||
MainWidgetInterface->GetSelf()->CloseAllThreads();
|
||||
|
||||
TSharedPtr<FClipProxy> ClipProxy = FClipProxy::GetProxy();
|
||||
@ -775,8 +787,8 @@ bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info)
|
||||
static_cast<SCutMainWindow*>(MainWidgetInterface)->UpdateProperties(nullptr);
|
||||
static_cast<SCutMainWindow*>(MainWidgetInterface)->CloseAllThreads();
|
||||
TArray<uint8> LoadData;
|
||||
FPaths::ConvertRelativePathToFull(LoadPath);
|
||||
FFileHelper::LoadFileToArray(LoadData, *LoadPath);
|
||||
FPaths::ConvertRelativePathToFull(NewLoadPath);
|
||||
FFileHelper::LoadFileToArray(LoadData, *NewLoadPath);
|
||||
if (LoadData.Num() == 0)
|
||||
{
|
||||
return false;
|
||||
@ -798,8 +810,13 @@ bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info)
|
||||
MemoryReader << ClipLength;
|
||||
TArray<FClipData> AllClips;
|
||||
MemoryReader << AllClips;
|
||||
float MaxLength = 0.0f;
|
||||
for (int32 i = 0; i < AllClips.Num(); i++)
|
||||
{
|
||||
if (MaxLength < AllClips[i].ClipEndFrame)
|
||||
{
|
||||
MaxLength = AllClips[i].ClipEndFrame;
|
||||
}
|
||||
AllClips[i].ResourcePropertyDataPtr = MainWidgetInterface->GetResourcePropertyDataPtr(AllClips[i].ResourcePropertyGuid);
|
||||
for (int32 j = 0; j < DeviceTrackGroups.Num(); j++)
|
||||
{
|
||||
@ -823,29 +840,16 @@ bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info)
|
||||
}
|
||||
}
|
||||
|
||||
RenderGroup();
|
||||
|
||||
|
||||
|
||||
|
||||
// int32 Length = 0;
|
||||
// MemoryReader << Length;
|
||||
// TArray<FString> GroupName;
|
||||
// GroupName.Init("", Length);
|
||||
// for (int32 i = 0; i < Length; i++)
|
||||
// {
|
||||
// MemoryReader << GroupName[i];
|
||||
// }
|
||||
// for (int32 i = 0; i < Length; i++)
|
||||
// {
|
||||
// FTrackData TrackData;
|
||||
// MemoryReader << TrackData;
|
||||
// for (FClipData& ClipData : TrackData.ClipData)
|
||||
// {
|
||||
// ClipData.ResourcePropertyDataPtr = MainWidgetInterface->GetResourcePropertyDataPtr(ClipData.ResourcePropertyGuid);
|
||||
// }
|
||||
// AddNewTrackToGroup(GroupName[i], TrackData);
|
||||
// }
|
||||
|
||||
FGlobalData::TrackLength = MaxLength + (MaxLength * 0.2);
|
||||
if (FGlobalData::TrackLength == 0)
|
||||
{
|
||||
FGlobalData::TrackLength = 100;
|
||||
}
|
||||
UpdateTimelineLength();
|
||||
|
||||
RenderGroup();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -93,13 +93,13 @@ public:
|
||||
void RenderGroup();
|
||||
|
||||
/**
|
||||
* @brief Save Current Time line Track to File.
|
||||
* @brief Save Current Time line Track to File. Relative
|
||||
* @param SavedPath Where to save.
|
||||
*/
|
||||
void SaveTimeline(const FString& SavedPath, FTimelineInfo Info);
|
||||
|
||||
/**
|
||||
* @brief Load Time line Track from File.
|
||||
* @brief Load Time line Track from File. Relative
|
||||
* @param LoadPath Where to load.
|
||||
*/
|
||||
bool LoadTimeline(const FString& LoadPath, FTimelineInfo& Info);
|
||||
|
@ -267,15 +267,23 @@ void STimelineClip::Construct(const FArguments& InArgs)
|
||||
FRunnableThread::Create(Thread, TEXT("VideoThread"));
|
||||
MainWidgetInterface->GetSelf()->AddThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid), Thread);
|
||||
}
|
||||
// if (!MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThumbnailThreadGuid(ClipData->ClipGuid)))
|
||||
// {
|
||||
// FVideoThumbnailThread* ThumbnailThread = new FVideoThumbnailThread(ClipData->MoviePath, [this](const FString& PicPath)
|
||||
// {
|
||||
//
|
||||
// });
|
||||
// FRunnableThread::Create(ThumbnailThread, TEXT("VideoThumbnailThread"));
|
||||
// MainWidgetInterface->GetSelf()->AddThread(FUtils::GetVideoThumbnailThreadGuid(ClipData->ClipGuid), ThumbnailThread);
|
||||
// }
|
||||
|
||||
if (ClipData->ClipGuid != FGuid())
|
||||
{
|
||||
if (!MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThumbnailThreadGuid(ClipData->ClipGuid)))
|
||||
{
|
||||
FVideoThumbnailThread* ThumbnailThread = new FVideoThumbnailThread(ClipData->MoviePath, [this](const FString& PicPath)
|
||||
{
|
||||
ClipData->MovieBrushesPath.Add(PicPath);
|
||||
const FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ToFullPath(PicPath), FVector2f(0, 0));
|
||||
ClipData->MovieBrushes.Add(Brush);
|
||||
}, ClipData->MovieBrushNum, *ClipData);
|
||||
|
||||
FRunnableThread::Create(ThumbnailThread, TEXT("VideoThumbnailThread"));
|
||||
MainWidgetInterface->GetSelf()->AddThread(FUtils::GetVideoThumbnailThreadGuid(ClipData->ClipGuid), ThumbnailThread);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -746,6 +754,8 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
|
||||
|
||||
if (CropStartFrameOffset != -1 || NeedDrawCount != -1)
|
||||
{
|
||||
const float StartRange = CurrentStartRange - RangeStart;
|
||||
const float EndRange = CurrentEndRange;
|
||||
for (int32 i = 0; i < NeedDrawCount / DownSample; i++)
|
||||
{
|
||||
const int32 CurrentIndex = (CropStartDataOffset * DownSample) + (i * (Interval * DownSample * 4));
|
||||
@ -755,51 +765,23 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
|
||||
float NewFloat = *reinterpret_cast<float*>(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]);
|
||||
float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y),
|
||||
FMath::Abs(NewFloat));
|
||||
|
||||
|
||||
|
||||
TArray<FVector2D> NewLoc;
|
||||
NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i * DownSample) , AllottedGeometry.GetLocalSize().Y));
|
||||
NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i * DownSample) , Y));
|
||||
|
||||
FSlateDrawElement::MakeLines(OutDrawElements, LayerId + 6, AllottedGeometry.ToPaintGeometry(), NewLoc, ESlateDrawEffect::None,
|
||||
FColor(45, 214, 153, 255), true, DownSample * 1.2);
|
||||
FColor(45, 214, 153, 255), true, DownSample * 1.2);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// GEngine->AddOnScreenDebugMessage(-1, 0.1f, FColor::Red, FString::SanitizeFloat(StartRange));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// int32 NeedDrawCount = ClipData->GetLength() * FGlobalData::DefaultTimeTickSpace;
|
||||
// float DownSample = 4;
|
||||
// // Draw Audio Waveform
|
||||
//
|
||||
//
|
||||
// const float RangeStart = MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().LocalToAbsolute(FVector2D(0, 0)).X;
|
||||
// const float RangeEnd = MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().LocalToAbsolute(FVector2D(MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().GetLocalSize().X, 0)).X;
|
||||
// const float CurrentStartRange = AllottedGeometry.LocalToAbsolute(FVector2D(0, 0)).X;
|
||||
// const float CurrentEndRange = AllottedGeometry.LocalToAbsolute(FVector2D(AllottedGeometry.GetLocalSize().X, 0)).X;
|
||||
//
|
||||
// const int32 StartOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS)
|
||||
// * ClipData->VideoStartFrame
|
||||
// * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) * 2 / DownSample;
|
||||
//
|
||||
// const int32 EndOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS)
|
||||
// * ClipData->VideoEndFrame
|
||||
// * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) * 2 / DownSample;
|
||||
//
|
||||
// const int32 Interval = (EndOffset - StartOffset) / NeedDrawCount;
|
||||
// for (int32 i = 0; i < NeedDrawCount / DownSample; i++)
|
||||
// {
|
||||
// const int32 CurrentIndex = (StartOffset * DownSample) + (i * (Interval * DownSample * 4));
|
||||
// if (CurrentIndex >= ClipData->ResourcePropertyDataPtr->AudioData.Num())
|
||||
// continue;
|
||||
//
|
||||
// float NewFloat = *reinterpret_cast<float*>(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]);
|
||||
// float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y),
|
||||
// FMath::Abs(NewFloat));
|
||||
// TArray<FVector2D> NewLoc;
|
||||
// NewLoc.Add(FVector2D(i * DownSample, AllottedGeometry.GetLocalSize().Y));
|
||||
// NewLoc.Add(FVector2D(i * DownSample, Y));
|
||||
// FSlateDrawElement::MakeLines(OutDrawElements, LayerId + 6, AllottedGeometry.ToPaintGeometry(), NewLoc, ESlateDrawEffect::None,
|
||||
// FColor(45, 214, 153, 255), true, DownSample * 1.2);
|
||||
// }
|
||||
if (ClipData->ClipType == ETrackType::AudioTrack || ClipData->ClipType == ETrackType::AudioTrackR)
|
||||
{
|
||||
FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 5, AllottedGeometry.ToPaintGeometry(),
|
||||
@ -1072,90 +1054,7 @@ void STimelineClip::OnMouseLeave(const FPointerEvent& MouseEvent)
|
||||
|
||||
void STimelineClip::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
|
||||
{
|
||||
if (ClipData->MovieBrushes.Num() < ClipData->MovieBrushNum && ClipData->ResourcePropertyDataPtr && ClipData->ResourcePropertyDataPtr->Context && ClipData->ResourcePropertyDataPtr->VideoStream != -1)
|
||||
{
|
||||
if (ThumbnailCodecContext.Context == nullptr)
|
||||
{
|
||||
FFFMPEGUtils::LoadContextPure(ClipData->ResourcePropertyDataPtr->MoviePath, &ThumbnailCodecContext);
|
||||
return;
|
||||
}
|
||||
|
||||
const int32 CurrentFrame = ClipData->MovieBrushNum - (ClipData->MovieBrushNum - ClipData->MovieBrushes.Num());
|
||||
const int64 Timestamp = av_rescale_q(CurrentFrame / FGlobalData::GlobalFPS * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, ThumbnailCodecContext.Context->streams[ThumbnailCodecContext.VideoStream]->time_base);
|
||||
av_seek_frame(ThumbnailCodecContext.Context, ThumbnailCodecContext.VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD);
|
||||
AVPacket Packet;
|
||||
av_init_packet(&Packet);
|
||||
AVFormatContext* FormatContext = ThumbnailCodecContext.Context;
|
||||
AVCodecContext* VideoCodecContext = ThumbnailCodecContext.VideoCodecContext;
|
||||
AVCodec* VideoCodec = ThumbnailCodecContext.VideoCodec;
|
||||
AVFrame* Frame = av_frame_alloc();
|
||||
|
||||
while (av_read_frame(FormatContext, &Packet) >= 0)
|
||||
{
|
||||
if (avcodec_send_packet(VideoCodecContext, &Packet) < 0)
|
||||
{
|
||||
|
||||
}
|
||||
if (avcodec_receive_frame(VideoCodecContext, Frame) >= 0)
|
||||
{
|
||||
if (Frame->best_effort_timestamp >= Timestamp)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
if (Frame)
|
||||
{
|
||||
if (Frame->width == 0 || Frame->height == 0)
|
||||
{
|
||||
TArray<FSlateBrush> Brushes;
|
||||
Brushes.Init(FSlateBrush(), ClipData->MovieBrushNum - ClipData->MovieBrushes.Num());
|
||||
ClipData->MovieBrushes.Append(Brushes);
|
||||
return;
|
||||
}
|
||||
|
||||
struct SwsContext* swsCtx = sws_getContext(
|
||||
Frame->width, Frame->height, VideoCodecContext->pix_fmt,
|
||||
Frame->width / 10, Frame->height / 10, AV_PIX_FMT_BGRA,
|
||||
SWS_BILINEAR, NULL, NULL, NULL
|
||||
);
|
||||
if (!swsCtx)
|
||||
{
|
||||
UE_LOG(LogTemp, Error, TEXT("Error creating swsContext"));
|
||||
}
|
||||
uint8* RawData = new uint8[(Frame->width / 10) * (Frame->height / 10) * 4];
|
||||
uint8* dest[4] = {RawData, 0, 0, 0};
|
||||
int32 dest_linesize[4] = {(Frame->width / 10) * 4, 0, 0, 0};
|
||||
sws_scale(swsCtx, Frame->data, Frame->linesize, 0, Frame->height, dest, dest_linesize);
|
||||
sws_freeContext(swsCtx);
|
||||
|
||||
|
||||
UTexture2D* Texture = UTexture2D::CreateTransient(Frame->width / 10, Frame->height / 10, PF_B8G8R8A8);
|
||||
if (Texture)
|
||||
{
|
||||
void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
|
||||
FMemory::Memcpy(MipData, RawData, (Frame->width / 10) * (Frame->height / 10) * 4);
|
||||
Texture->GetPlatformData()->Mips[0].BulkData.Unlock();
|
||||
Texture->UpdateResource();
|
||||
|
||||
FGuid Guid = FGuid::NewGuid();
|
||||
FFFMPEGUtils::ExportImage(Texture, *FPaths::Combine(FUtils::GetProjectTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png"));
|
||||
ClipData->MovieBrushesPath.Add(FPaths::Combine(FUtils::GetProjectTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png"));
|
||||
FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ClipData->MovieBrushesPath[ClipData->MovieBrushesPath.Num() - 1], FVector2f(0, 0));
|
||||
ClipData->MovieBrushes.Add(Brush);
|
||||
|
||||
Texture->MarkAsGarbage();
|
||||
delete RawData;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
|
||||
}
|
||||
|
||||
TSharedPtr<SWidget> STimelineClip::GetPropertiesWidget()
|
||||
|
@ -413,8 +413,8 @@ TSharedPtr<SWidget> FClipProxy::GetPropertiesWidget()
|
||||
const FGuid& Guid = InItem.Get()->Guid;
|
||||
FCurtainGroup* Group = nullptr;
|
||||
const FString CurrentPath = // MainInterface->GetSelf()->CurtainPanel->FindCurtain(Guid,Group)->TimelineInfo.CurrentOpenFullPath;
|
||||
MainInterface->GetSelf()->GetSelectTimelineInfoByGuid(Guid).CurrentOpenFullPath;
|
||||
FTimelineLoader TimelineLoader(CurrentPath, true);
|
||||
MainInterface->GetSelf()->GetSelectTimelineInfoByGuid(Guid).CurrentOpenRelativePath;
|
||||
FTimelineLoader TimelineLoader(ToFullPath(CurrentPath), true);
|
||||
if (TimelineLoader.GetSpecifyClipData(ClipData->ClipType).Num() > 0 && State == ECheckBoxState::Checked)
|
||||
{
|
||||
FUtils::AddTips(
|
||||
@ -424,7 +424,7 @@ TSharedPtr<SWidget> FClipProxy::GetPropertiesWidget()
|
||||
.OnEnsure_Lambda([this, State, InItem, CurrentPath](const FString& String)
|
||||
{
|
||||
// 先清空
|
||||
FTimelineLoader ModifyTimelineLoader(CurrentPath, true);
|
||||
FTimelineLoader ModifyTimelineLoader(ToFullPath(CurrentPath), true);
|
||||
TArray<FClipData> Clips = ModifyTimelineLoader.GetSpecifyClipData(ClipData->ClipType);
|
||||
for (int32 i = Clips.Num() - 1; i >= 0; i--)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user