# Conflicts:
#	Source/Cut5/Widgets/STimelineClip.cpp
This commit is contained in:
Sch 2023-10-16 03:16:51 +08:00
commit 991260947f
21 changed files with 266 additions and 268 deletions

View File

@ -7,67 +7,49 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{233774
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Games", "Games", "{DE1F8B53-6C02-3C13-9101-A7C8D96F3FF6}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Games", "Games", "{DE1F8B53-6C02-3C13-9101-A7C8D96F3FF6}"
EndProject 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 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 EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Visualizers", "Visualizers", "{1CCEC849-CC72-4C59-8C36-2F7C38706D4C}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Visualizers", "Visualizers", "{1CCEC849-CC72-4C59-8C36-2F7C38706D4C}"
ProjectSection(SolutionItems) = preProject 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 EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
DebugGame Editor|Android = DebugGame Editor|Android
DebugGame Editor|Win64 = DebugGame Editor|Win64 DebugGame Editor|Win64 = DebugGame Editor|Win64
DebugGame|Android = DebugGame|Android
DebugGame|Win64 = DebugGame|Win64 DebugGame|Win64 = DebugGame|Win64
Development Editor|Android = Development Editor|Android
Development Editor|Win64 = Development Editor|Win64 Development Editor|Win64 = Development Editor|Win64
Development|Android = Development|Android
Development|Win64 = Development|Win64 Development|Win64 = Development|Win64
Shipping|Android = Shipping|Android
Shipping|Win64 = Shipping|Win64 Shipping|Win64 = Shipping|Win64
EndGlobalSection EndGlobalSection
# UnrealVS Section # UnrealVS Section
GlobalSection(ddbf523f-7eb6-4887-bd51-85a714ff87eb) = preSolution GlobalSection(ddbf523f-7eb6-4887-bd51-85a714ff87eb) = preSolution
AvailablePlatforms=Win64;Android AvailablePlatforms=Win64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame Editor|Android.ActiveCfg = Invalid|x64 {6EE39883-7339-3FB6-AD82-931FB137D37F}.DebugGame Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Editor|x64 {6EE39883-7339-3FB6-AD82-931FB137D37F}.DebugGame|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame Editor|Win64.Build.0 = DebugGame_Editor|x64 {6EE39883-7339-3FB6-AD82-931FB137D37F}.Development Editor|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame|Android.ActiveCfg = Android_DebugGame|Win64 {6EE39883-7339-3FB6-AD82-931FB137D37F}.Development|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame|Android.Build.0 = Android_DebugGame|Win64 {6EE39883-7339-3FB6-AD82-931FB137D37F}.Shipping|Win64.ActiveCfg = BuiltWithUnrealBuildTool|Win64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame|Win64.ActiveCfg = DebugGame|x64 {AF5A253A-0F37-38CE-8998-45CA936C112B}.DebugGame Editor|Win64.ActiveCfg = DebugGame_Editor|x64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.DebugGame|Win64.Build.0 = DebugGame|x64 {AF5A253A-0F37-38CE-8998-45CA936C112B}.DebugGame Editor|Win64.Build.0 = DebugGame_Editor|x64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development Editor|Android.ActiveCfg = Invalid|x64 {AF5A253A-0F37-38CE-8998-45CA936C112B}.DebugGame|Win64.ActiveCfg = DebugGame|x64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development Editor|Win64.ActiveCfg = Development_Editor|x64 {AF5A253A-0F37-38CE-8998-45CA936C112B}.DebugGame|Win64.Build.0 = DebugGame|x64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development Editor|Win64.Build.0 = Development_Editor|x64 {AF5A253A-0F37-38CE-8998-45CA936C112B}.Development Editor|Win64.ActiveCfg = Development_Editor|x64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development|Android.ActiveCfg = Android_Development|Win64 {AF5A253A-0F37-38CE-8998-45CA936C112B}.Development Editor|Win64.Build.0 = Development_Editor|x64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development|Android.Build.0 = Android_Development|Win64 {AF5A253A-0F37-38CE-8998-45CA936C112B}.Development|Win64.ActiveCfg = Development|x64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development|Win64.ActiveCfg = Development|x64 {AF5A253A-0F37-38CE-8998-45CA936C112B}.Development|Win64.Build.0 = Development|x64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Development|Win64.Build.0 = Development|x64 {AF5A253A-0F37-38CE-8998-45CA936C112B}.Shipping|Win64.ActiveCfg = Shipping|x64
{B95E7D0E-DB45-3765-9058-E00EBBC4B157}.Shipping|Android.ActiveCfg = Android_Shipping|Win64 {AF5A253A-0F37-38CE-8998-45CA936C112B}.Shipping|Win64.Build.0 = Shipping|x64
{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
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{C48D0E9D-C862-3EA3-96A7-752EE9D06362} = {233774A8-CC9D-3FA9-86D1-90573E92B704} {6EE39883-7339-3FB6-AD82-931FB137D37F} = {233774A8-CC9D-3FA9-86D1-90573E92B704}
{B95E7D0E-DB45-3765-9058-E00EBBC4B157} = {DE1F8B53-6C02-3C13-9101-A7C8D96F3FF6} {AF5A253A-0F37-38CE-8998-45CA936C112B} = {DE1F8B53-6C02-3C13-9101-A7C8D96F3FF6}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -40,7 +40,7 @@ public:
virtual void PreSettingBeforeSeek() {}; virtual void PreSettingBeforeSeek() {};
virtual void AddNewCard(FEffectCardProperty& CardProperty, FString GroupName) {}; 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 void CloseTimeline() {};
virtual bool OpenProject(const FString& Project) { return false; }; virtual bool OpenProject(const FString& Project) { return false; };
virtual bool PreNewProject() { return false; }; virtual bool PreNewProject() { return false; };

View File

@ -1,11 +1,16 @@
#include "VideoThumbnailThread.h" #include "VideoThumbnailThread.h"
#include "Cut5/Utils/FFMPEGUtils.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->MoviePath = MoviePath;
this->OnFinished = OnFinished; this->OnFinished = OnFinished;
this->BrushCount = BrushCount;
this->ClipData = ClipData;
bMissionStart = true;
} }
uint32 FVideoThumbnailThread::Run() uint32 FVideoThumbnailThread::Run()
@ -18,32 +23,96 @@ uint32 FVideoThumbnailThread::Run()
FTimelinePropertyData Info; FTimelinePropertyData Info;
FFFMPEGUtils::LoadContextPure(MoviePath, &Info); FFFMPEGUtils::LoadContextPure(MoviePath, &Info);
int32 i = 0;
while (bMissionStart)
while (true)
{ {
AVPacket* Packet = av_packet_alloc(); if (i < BrushCount && ClipData.ResourcePropertyDataPtr && ClipData.ResourcePropertyDataPtr->Context && ClipData.ResourcePropertyDataPtr->VideoStream != -1)
if (av_read_frame(Info.Context, Packet) < 0)
{ {
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; 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; return 0;
} }

View File

@ -1,10 +1,11 @@
#pragma once #pragma once
#include "Cut5/Widgets/DefineGlobal.h"
class FVideoThumbnailThread : public FRunnable class FVideoThumbnailThread : public FRunnable
{ {
public: 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 bool Init() override { return true; }
virtual uint32 Run() override; virtual uint32 Run() override;
@ -13,5 +14,7 @@ public:
FString MoviePath; FString MoviePath;
TFunction<void(FString)> OnFinished; TFunction<void(FString)> OnFinished;
int32 BrushCount;
FClipData ClipData;
bool bMissionStart = false;
}; };

View File

@ -106,7 +106,7 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
FGuid Guid = FGuid::NewGuid(); FGuid Guid = FGuid::NewGuid();
ExportImage(Texture, *FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, "Resources", "Thumbnail", Guid.ToString() + ".png")); 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(); Texture->MarkAsGarbage();
delete RawData; delete RawData;
} }
@ -197,7 +197,7 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
} }
PropertyData->Name = FPaths::GetBaseFilename(Path); PropertyData->Name = FPaths::GetBaseFilename(Path);
PropertyData->MoviePath = NewPath; PropertyData->MoviePath = Path;
return {}; return {};
@ -205,8 +205,19 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
FString FFFMPEGUtils::LoadContextPure(const FString& Path, FTimelinePropertyData* PropertyData) 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; 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"); return TEXT("Failed");
} }
@ -268,7 +279,7 @@ FString FFFMPEGUtils::LoadContextPure(const FString& Path, FTimelinePropertyData
PropertyData->Type = ETrackType::AudioTrack; PropertyData->Type = ETrackType::AudioTrack;
} }
PropertyData->Name = FPaths::GetBaseFilename(Path); PropertyData->Name = FPaths::GetBaseFilename(Path);
PropertyData->MoviePath = Path; PropertyData->MoviePath = NewPath;
return {}; return {};
} }
@ -358,7 +369,7 @@ TArray<FSlateBrush> FFFMPEGUtils::GetMovieBrush(FClipData* ClipData, bool Regene
{ {
for (int32 i = 0; i < ClipData->MovieBrushesPath.Num(); i++) 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++; ClipData->MovieBrushNum++;
Result.Add(Brush); Result.Add(Brush);
} }

View File

@ -87,7 +87,7 @@ FString FUtils::GetResourcesPath(FString ResourcesName, bool bFullPath)
FString FUtils::GetProjectTempPath() 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) 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 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 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")) + "\""; 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 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 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"); FString OutputFile = ExportPath + TEXT(".mp3");
@ -632,8 +632,7 @@ TArray<FEncodeVideoInfo> FUtils::ExportPsaf(FTrackData TrackData, const FString&
FString ExportName = FGuid::NewGuid().ToString();; FString ExportName = FGuid::NewGuid().ToString();;
if (TempClipData.ResourcePropertyDataPtr) if (TempClipData.ResourcePropertyDataPtr)
{ {
TempClipData.ResourcePropertyDataPtr->MoviePath; FString TempPath = ToFullPath(TempClipData.ResourcePropertyDataPtr->MoviePath);
FString TempPath = TempClipData.ResourcePropertyDataPtr->MoviePath;
frames.Empty(); frames.Empty();
VideoCapture capture; VideoCapture capture;

View File

@ -2,6 +2,11 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Cut5/Widgets/DefineGlobal.h" #include "Cut5/Widgets/DefineGlobal.h"
inline FString ToFullPath(const FString& String)
{
return FGlobalData::BasePath / FGlobalData::CurrentProjectName / String;
}
class FUtils class FUtils
{ {
public: public:
@ -36,22 +41,20 @@ public:
static TArray<FEncodeVideoInfo> TrackEncodeVideo(const FTrackData& TrackData, const FString& ExportPath); static TArray<FEncodeVideoInfo> TrackEncodeVideo(const FTrackData& TrackData, const FString& ExportPath);
static FEncodeVideoInfo TrackEncodeAudio(const FTrackData& TrackDataLeft, 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 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() static FUtils* GetInstance()
{ {

View File

@ -163,17 +163,17 @@ TSharedPtr<FCurtainDragDrop> SCurtain::OpenThis()
// 没有Curtain就Create一个 // 没有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())); FSaveModifier SaveModifier(ToFullPath(FUtils::CurtainRelativePath(Curtain->CurtainUUID.ToString())));
SaveModifier.TimelineInfo.CurrentOpenFullPath = FUtils::CurtainFullPath(Curtain->CurtainUUID.ToString()); SaveModifier.TimelineInfo.CurrentOpenRelativePath = FUtils::CurtainRelativePath(Curtain->CurtainUUID.ToString());
SaveModifier.TimelineInfo.CurrentOpenType = FTimelineInfo::ETimelineType::FX; SaveModifier.TimelineInfo.CurrentOpenType = FTimelineInfo::ETimelineType::FX;
Curtain->TimelineInfo = SaveModifier.TimelineInfo; Curtain->TimelineInfo = SaveModifier.TimelineInfo;
} }
} }
CurtainPanel->MainWidgetInterface->OpenTimeline(FUtils::CurtainFullPath(Curtain->CurtainUUID.ToString()), true); CurtainPanel->MainWidgetInterface->OpenTimelineWithRelativePath(FUtils::CurtainRelativePath(Curtain->CurtainUUID.ToString()), true);

View File

@ -272,10 +272,10 @@ void SCurtainPanel::AddNewCurtain(int32 Index)
if (Index < Groups.Num()) if (Index < Groups.Num())
{ {
FCurtain Curtain; 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())); FSaveModifier SaveModifier(ToFullPath(FUtils::CurtainRelativePath(Curtain.CurtainUUID.ToString())));
SaveModifier.TimelineInfo.CurrentOpenFullPath = FUtils::CurtainFullPath(Curtain.CurtainUUID.ToString()); SaveModifier.TimelineInfo.CurrentOpenRelativePath = FUtils::CurtainRelativePath(Curtain.CurtainUUID.ToString());
SaveModifier.TimelineInfo.CurrentOpenType = FTimelineInfo::ETimelineType::FX; SaveModifier.TimelineInfo.CurrentOpenType = FTimelineInfo::ETimelineType::FX;
Curtain.TimelineInfo = SaveModifier.TimelineInfo; Curtain.TimelineInfo = SaveModifier.TimelineInfo;
} }

View File

@ -766,19 +766,22 @@ struct CUT5_API FTimelineInfo
Main, Main,
FX, FX,
}; };
FString CurrentOpenFullPath = ""; FString CurrentOpenRelativePath = "";
FTimelineInfo::ETimelineType CurrentOpenType = ETimelineType::Main; FTimelineInfo::ETimelineType CurrentOpenType = ETimelineType::Main;
friend FArchive& operator<<(FArchive& Ar, FTimelineInfo& TimelineInfo) friend FArchive& operator<<(FArchive& Ar, FTimelineInfo& TimelineInfo)
{ {
Ar << TimelineInfo.CurrentOpenFullPath; Ar << TimelineInfo.CurrentOpenRelativePath;
Ar << TimelineInfo.CurrentOpenType; Ar << TimelineInfo.CurrentOpenType;
return Ar; return Ar;
}; };
FString GetSavePath()
// 得到完整目录,考虑到项目迁移所以保存的是 相对路径, 但是在打开的时候需要转换成绝对路径
FString GetSaveFullPath()
{ {
return CurrentOpenFullPath; return FGlobalData::BasePath / FGlobalData::CurrentProjectName / CurrentOpenRelativePath;
} }
}; };

View File

@ -819,13 +819,13 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
{ {
NewClipData.ClipType = ETrackType::PlayerTrack; NewClipData.ClipType = ETrackType::PlayerTrack;
NewClipData.PlayerName = TrackBody->MainWidgetInterface->GetGroupName(TrackHead); 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) if (TrackHead->TrackData.TrackType == ETrackType::AtomSphereLightTrack)
{ {
NewClipData.ClipType = ETrackType::AtomSphereLightTrack; NewClipData.ClipType = ETrackType::AtomSphereLightTrack;
NewClipData.PlayerName = TrackBody->MainWidgetInterface->GetGroupName(TrackHead); 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) else if (ClipDragOperation.TimelinePropertyData->Type == ETrackType::LightArrayTrack)

View File

@ -76,7 +76,7 @@ void SEffectCard::Construct(const FArguments& InArgs)
} }
else else
{ {
MainInterface->OpenTimeline(FUtils::SingleCardFullPath(CardProperty->Guid.ToString()), true); MainInterface->OpenTimelineWithRelativePath(FUtils::SingleCardRelativePath(CardProperty->Guid.ToString()), true);
} }
PropertiesInterfaceGUID = CardProperty->Guid; PropertiesInterfaceGUID = CardProperty->Guid;

View File

@ -474,8 +474,8 @@ void SEffectCardGroup::OnSelect()
{ {
if (EffectCardGroup->bIsDedicated == false) if (EffectCardGroup->bIsDedicated == false)
{ {
const FString Name = FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), EffectCardGroup->Guid.ToString() + TEXT(".bin")); const FString Name = TEXT("FX") / EffectCardGroup->Guid.ToString() + TEXT(".bin");
MainInterface->OpenTimeline(Name, true); MainInterface->OpenTimelineWithRelativePath(Name, true);
MainInterface->CurrentSelectedPropertiesInterfaceGuid = EffectCardGroup->Guid; MainInterface->CurrentSelectedPropertiesInterfaceGuid = EffectCardGroup->Guid;
MainInterface->UpdateProperties(this); MainInterface->UpdateProperties(this);
MainInterface->GetSelf()->DeselectAll(); 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())); FSaveModifier SaveModifier(ToFullPath(FUtils::SingleCardRelativePath(NewCard.Guid.ToString())));
SaveModifier.TimelineInfo.CurrentOpenFullPath = FUtils::SingleCardFullPath(NewCard.Guid.ToString()); SaveModifier.TimelineInfo.CurrentOpenRelativePath = FUtils::SingleCardRelativePath(NewCard.Guid.ToString());
SaveModifier.TimelineInfo.CurrentOpenType = FTimelineInfo::ETimelineType::FX; SaveModifier.TimelineInfo.CurrentOpenType = FTimelineInfo::ETimelineType::FX;
NewCard.TimelineInfo = SaveModifier.TimelineInfo; NewCard.TimelineInfo = SaveModifier.TimelineInfo;
} }

View File

@ -110,13 +110,13 @@ void SEffectCardsPanel::CallRender()
int32 ID = GetCurrentID(true); int32 ID = GetCurrentID(true);
Group->ID = ID; Group->ID = ID;
const FString NewPath = FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), NewGuid.ToString() + TEXT(".bin")); const FString NewPath = TEXT("FX") / NewGuid.ToString() + TEXT(".bin");
FUtils::CreateDefaultTimelineSave(NewPath, FTimelineInfo::ETimelineType::FX); FUtils::CreateDefaultTimelineSave(ToFullPath(NewPath), FTimelineInfo::ETimelineType::FX);
{ {
FSaveModifier SaveModifier(NewPath); FSaveModifier SaveModifier(ToFullPath(NewPath));
SaveModifier.TimelineInfo.CurrentOpenFullPath = NewPath; SaveModifier.TimelineInfo.CurrentOpenRelativePath = NewPath;
} }
Group->TimelineInfo.CurrentOpenFullPath = NewPath; Group->TimelineInfo.CurrentOpenRelativePath = NewPath;
CallRender(); CallRender();
return FReply::Handled(); return FReply::Handled();
}) })
@ -157,7 +157,7 @@ void SEffectCardsPanel::RemoveCard(const FGuid& GUID)
{ {
if (Group.bIsActive == true) if (Group.bIsActive == true)
{ {
MainInterface->OpenTimeline(FUtils::MainSaveFullPath(), true); MainInterface->OpenTimelineWithRelativePath("", true);
} }
EffectCardGroups.RemoveAt(j); EffectCardGroups.RemoveAt(j);
break; break;
@ -170,7 +170,7 @@ void SEffectCardsPanel::RemoveCard(const FGuid& GUID)
{ {
if (Group.Cards[i].bIsActive == true) if (Group.Cards[i].bIsActive == true)
{ {
MainInterface->OpenTimeline(FUtils::MainSaveFullPath(), true); MainInterface->OpenTimelineWithRelativePath("", true);
} }
Group.Cards.RemoveAt(i); Group.Cards.RemoveAt(i);
} }
@ -193,7 +193,7 @@ void SEffectCardsPanel::RemoveCardInGroup(const FGuid& Guid, const FGuid& GroupG
{ {
if (Property.bIsActive == true) if (Property.bIsActive == true)
{ {
MainInterface->OpenTimeline(FUtils::MainSaveFullPath()); MainInterface->OpenTimelineWithRelativePath("");
} }
Group.Cards.RemoveAt(i); Group.Cards.RemoveAt(i);
break; break;
@ -365,9 +365,7 @@ void SEffectCardsPanel::SavePanel(const FString& Path)
{ {
for (FEffectCardProperty& Property : Group.Cards) for (FEffectCardProperty& Property : Group.Cards)
{ {
FString Target = Property.TimelineInfo.CurrentOpenFullPath; IFileManager::Get().Move(*FPaths::Combine(Path, "FX", "Cards"), *ToFullPath(Property.TimelineInfo.CurrentOpenRelativePath));
FPaths::CollapseRelativeDirectories(Target);
IFileManager::Get().Move(*FPaths::Combine(Path, "FX", "Cards"), *Property.TimelineInfo.CurrentOpenFullPath);
} }
MemoryWriter << Group; MemoryWriter << Group;
} }

View File

@ -43,7 +43,7 @@ void SCustomInputResource::Construct(const FArguments& InArgs)
[ [
SNew(SImage) SNew(SImage)
.Image( (PropertyData.VideoStream == -1 && PropertyData.AudioStream != -1) ? FUtils::GetBrushFromImage(FUtils::GetResourcesPath(TEXT("Music.png")), {}) : .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() + SOverlay::Slot()
.HAlign(HAlign_Center) .HAlign(HAlign_Center)
@ -91,7 +91,7 @@ FReply SCustomInputResource::OnDragDetected(const FGeometry& MyGeometry, const F
[ [
SNew(SImage) SNew(SImage)
.Image( (PropertyData.VideoStream == -1 && PropertyData.AudioStream != -1) ? FUtils::GetBrushFromImage(FUtils::GetResourcesPath(TEXT("Music.png")), {}) : .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()); return FReply::Handled().BeginDragDrop(Operation.ToSharedRef());

View File

@ -453,7 +453,7 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
})); }));
CommandList->MapAction(FShortCutCommands::Get().ZoomOutTimeline, FExecuteAction::CreateLambda([this]() 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; const float NewValue = CutTimeline->ZoomSlider->GetValue() - 0.1;
CutTimeline->UpdateZoom(NewValue); CutTimeline->UpdateZoom(NewValue);
@ -902,37 +902,29 @@ void SCutMainWindow::AddNewCard(FEffectCardProperty& CardProperty, FString Group
EffectCardsPanel->AddNewCard(CardProperty, GroupName); 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; CutTimeline->bNeedShowPanel = true;
if (NeedSaveBefore) if (NeedSaveBefore)
{ {
CutTimeline->SaveTimeline(CutTimeline->TimelineInfo.CurrentOpenFullPath, CutTimeline->TimelineInfo); CutTimeline->SaveTimeline(CutTimeline->TimelineInfo.CurrentOpenRelativePath, CutTimeline->TimelineInfo);
CutTimeline->TimelineInfo.CurrentOpenFullPath = TimelineName; CutTimeline->TimelineInfo.CurrentOpenRelativePath = TimelineRelativePath;
} }
//
// if (TimelineName == CutTimeline->TimelineInfo.CurrentOpenFullPath && !ForceOpen)
// {
// CloseTimeline();
// return;
// }
FTimelineInfo TimelineInfo; FTimelineInfo TimelineInfo;
// 拿到TimelineName路径中的名字也就是倒数第四位开始去掉后缀 // 拿到TimelineName路径中的名字也就是倒数第四位开始去掉后缀
if (CutTimeline->LoadTimeline(TimelineRelativePath, TimelineInfo))
if (CutTimeline->LoadTimeline(TimelineName, TimelineInfo))
{ {
CutTimeline->TimelineInfo = TimelineInfo; CutTimeline->TimelineInfo = TimelineInfo;
// CutTimeline->CurrentEditDebug->SetText(FText::FromString(TEXT("当前正在编辑") + TimelineInfo.CurrentOpenFullPath));
} }
OnAddNewTrack(ETrackType::PlayerTrack); OnAddNewTrack(ETrackType::PlayerTrack);
} }
void SCutMainWindow::CloseTimeline() void SCutMainWindow::CloseTimeline()
{ {
CutTimeline->bNeedShowPanel = false; CutTimeline->bNeedShowPanel = false;
CutTimeline->SaveTimeline(CutTimeline->TimelineInfo.CurrentOpenFullPath, CutTimeline->TimelineInfo); CutTimeline->SaveTimeline(CutTimeline->TimelineInfo.CurrentOpenRelativePath, CutTimeline->TimelineInfo);
CutTimeline->RenderGroup(); CutTimeline->RenderGroup();
} }
@ -1261,7 +1253,7 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
ExportCard.SerialID.Add(EffectCardsPanel->EffectCardGroups[i].Cards[j].ID); 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; ExportCard.CardGuid = EffectCardsPanel->EffectCardGroups[i].Cards[j].Guid;
ExportCards.Add(ExportCard); ExportCards.Add(ExportCard);
UE_LOG(LogTemp, Log, TEXT("ExportCard.TimelinePath = %s"), *ExportCard.TimelinePath); 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; ExportCard.CardGuid = EffectCardsPanel->EffectCardGroups[i].Guid;
ExportCards.Add(ExportCard); ExportCards.Add(ExportCard);
} }
@ -1417,10 +1409,8 @@ void SCutMainWindow::ImportProject(const FString& ImportPath)
void SCutMainWindow::NewProject(const FString& NewPath) void SCutMainWindow::NewProject(const FString& NewPath)
{ {
FGlobalData::BasePath = NewPath; FGlobalData::BasePath = NewPath;
CutTimeline->TimelineInfo.CurrentOpenFullPath = FUtils::MainSaveFullPath(); CutTimeline->TimelineInfo.CurrentOpenRelativePath = "";
} }
void SCutMainWindow::SaveProject() 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 // 新建项目关联文件.cutlink
TArray<uint8> ProjectLinkData; TArray<uint8> ProjectLinkData;
@ -2387,7 +2377,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetProcessA(tinyxml2::XMLElement* Parent,
DeselectAll(); DeselectAll();
CurtainPanel->DeSelectedAll(); CurtainPanel->DeSelectedAll();
CurtainGroup->Curtains[i].bIsActive = true; 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]); GetProcessB(ProcessA, &CurtainGroup->Curtains[i]);
} }
if (CurtainGroup->Curtains.Num() == 0) if (CurtainGroup->Curtains.Num() == 0)
@ -2487,7 +2477,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffectList(tinyxml2::XMLElement*
{ {
DeselectAll(); DeselectAll();
SetActive(ExportCard.CardGuid); SetActive(ExportCard.CardGuid);
OpenTimeline(ExportCard.TimelinePath, true, true); OpenTimelineWithRelativePath(ExportCard.TimelinePath, true, true);
tinyxml2::XMLElement* SpecialEffect = SpecialEffectsList->InsertNewChildElement("SpecialEffect"); tinyxml2::XMLElement* SpecialEffect = SpecialEffectsList->InsertNewChildElement("SpecialEffect");
tinyxml2::XMLElement* Effect = SpecialEffect->InsertNewChildElement("Effect"); tinyxml2::XMLElement* Effect = SpecialEffect->InsertNewChildElement("Effect");
@ -3006,7 +2996,7 @@ int32 SCutMainWindow::CalculateExportCount()
{ {
for (FCurtain& Curtain : CurtainGroup.Curtains) for (FCurtain& Curtain : CurtainGroup.Curtains)
{ {
FTimelineLoader TimelineLoader(Curtain.TimelineInfo.CurrentOpenFullPath); FTimelineLoader TimelineLoader(ToFullPath(Curtain.TimelineInfo.CurrentOpenRelativePath));
Count += TimelineLoader.GetClipData().Num(); Count += TimelineLoader.GetClipData().Num();
} }
} }
@ -3016,13 +3006,13 @@ int32 SCutMainWindow::CalculateExportCount()
{ {
for (FEffectCardProperty& Property : Group.Cards) for (FEffectCardProperty& Property : Group.Cards)
{ {
FTimelineLoader TimelineLoader(Property.TimelineInfo.CurrentOpenFullPath); FTimelineLoader TimelineLoader(ToFullPath(Property.TimelineInfo.CurrentOpenRelativePath));
Count += TimelineLoader.GetClipData().Num(); Count += TimelineLoader.GetClipData().Num();
} }
} }
for (FEffectCardProperty& Property : Group.Cards) for (FEffectCardProperty& Property : Group.Cards)
{ {
FTimelineLoader TimelineLoader(Property.TimelineInfo.CurrentOpenFullPath); FTimelineLoader TimelineLoader(ToFullPath(Property.TimelineInfo.CurrentOpenRelativePath));
Count += TimelineLoader.GetClipData().Num(); Count += TimelineLoader.GetClipData().Num();
} }
} }

View File

@ -94,7 +94,7 @@ public:
virtual void SelectClip(const FGuid& Guid) override; virtual void SelectClip(const FGuid& Guid) override;
// 不好 到时候改成 Group Widget 内部操作 // 不好 到时候改成 Group Widget 内部操作
virtual void AddNewCard(FEffectCardProperty& CardProperty, FString GroupName) override; 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 void CloseTimeline() override;
virtual bool OpenProject(const FString& Project) override; virtual bool OpenProject(const FString& Project) override;
virtual void ExportProject(const FString& ExportPath) override; virtual void ExportProject(const FString& ExportPath) override;

View File

@ -418,7 +418,7 @@ void SCutTimeline::Construct(const FArguments& InArgs)
]; ];
TrackHeadScrollBox->SetScrollBarVisibility(EVisibility::Hidden); TrackHeadScrollBox->SetScrollBarVisibility(EVisibility::Hidden);
TimelineInfo.CurrentOpenFullPath = FUtils::MainSaveFullPath(); TimelineInfo.CurrentOpenRelativePath = "";
FDeviceTrack Volume(TEXT("音量数据"), ETrackType::VolumeTrack); FDeviceTrack Volume(TEXT("音量数据"), ETrackType::VolumeTrack);
AddNewDeviceToGroup(TEXT("固定轨道"), Volume); AddNewDeviceToGroup(TEXT("固定轨道"), Volume);
@ -760,13 +760,25 @@ void SCutTimeline::SaveTimeline(const FString& SavedPath, FTimelineInfo Info)
MemoryWriter << ClipLength; MemoryWriter << ClipLength;
MemoryWriter << AllClips; MemoryWriter << AllClips;
FString NewSavedPath = FPaths::ConvertRelativePathToFull(SavedPath); FString NewSavedPath = ToFullPath(SavedPath);
FFileHelper::SaveArrayToFile(SavedData, *NewSavedPath); FFileHelper::SaveArrayToFile(SavedData, *NewSavedPath);
} }
bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info) bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info)
{ {
if (LoadPath == "")
{
bNeedShowPanel = false;
TimelineInfo.CurrentOpenRelativePath = "";
return true;
}
FString NewLoadPath = ToFullPath(LoadPath);
MainWidgetInterface->GetSelf()->CloseAllThreads(); MainWidgetInterface->GetSelf()->CloseAllThreads();
@ -775,8 +787,8 @@ bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info)
static_cast<SCutMainWindow*>(MainWidgetInterface)->UpdateProperties(nullptr); static_cast<SCutMainWindow*>(MainWidgetInterface)->UpdateProperties(nullptr);
static_cast<SCutMainWindow*>(MainWidgetInterface)->CloseAllThreads(); static_cast<SCutMainWindow*>(MainWidgetInterface)->CloseAllThreads();
TArray<uint8> LoadData; TArray<uint8> LoadData;
FPaths::ConvertRelativePathToFull(LoadPath); FPaths::ConvertRelativePathToFull(NewLoadPath);
FFileHelper::LoadFileToArray(LoadData, *LoadPath); FFileHelper::LoadFileToArray(LoadData, *NewLoadPath);
if (LoadData.Num() == 0) if (LoadData.Num() == 0)
{ {
return false; return false;
@ -798,8 +810,13 @@ bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info)
MemoryReader << ClipLength; MemoryReader << ClipLength;
TArray<FClipData> AllClips; TArray<FClipData> AllClips;
MemoryReader << AllClips; MemoryReader << AllClips;
float MaxLength = 0.0f;
for (int32 i = 0; i < AllClips.Num(); i++) 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); AllClips[i].ResourcePropertyDataPtr = MainWidgetInterface->GetResourcePropertyDataPtr(AllClips[i].ResourcePropertyGuid);
for (int32 j = 0; j < DeviceTrackGroups.Num(); j++) for (int32 j = 0; j < DeviceTrackGroups.Num(); j++)
{ {
@ -823,30 +840,17 @@ bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info)
} }
} }
FGlobalData::TrackLength = MaxLength + (MaxLength * 0.2);
if (FGlobalData::TrackLength == 0)
{
FGlobalData::TrackLength = 100;
}
UpdateTimelineLength();
RenderGroup(); 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);
// }
return true; return true;
} }

View File

@ -93,13 +93,13 @@ public:
void RenderGroup(); void RenderGroup();
/** /**
* @brief Save Current Time line Track to File. * @brief Save Current Time line Track to File. Relative
* @param SavedPath Where to save. * @param SavedPath Where to save.
*/ */
void SaveTimeline(const FString& SavedPath, FTimelineInfo Info); 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. * @param LoadPath Where to load.
*/ */
bool LoadTimeline(const FString& LoadPath, FTimelineInfo& Info); bool LoadTimeline(const FString& LoadPath, FTimelineInfo& Info);

View File

@ -267,15 +267,23 @@ void STimelineClip::Construct(const FArguments& InArgs)
FRunnableThread::Create(Thread, TEXT("VideoThread")); FRunnableThread::Create(Thread, TEXT("VideoThread"));
MainWidgetInterface->GetSelf()->AddThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid), Thread); MainWidgetInterface->GetSelf()->AddThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid), Thread);
} }
// if (!MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThumbnailThreadGuid(ClipData->ClipGuid)))
// { if (ClipData->ClipGuid != FGuid())
// FVideoThumbnailThread* ThumbnailThread = new FVideoThumbnailThread(ClipData->MoviePath, [this](const FString& PicPath) {
// { 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); 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) if (CropStartFrameOffset != -1 || NeedDrawCount != -1)
{ {
const float StartRange = CurrentStartRange - RangeStart;
const float EndRange = CurrentEndRange;
for (int32 i = 0; i < NeedDrawCount / DownSample; i++) for (int32 i = 0; i < NeedDrawCount / DownSample; i++)
{ {
const int32 CurrentIndex = (CropStartDataOffset * DownSample) + (i * (Interval * DownSample * 4)); const int32 CurrentIndex = (CropStartDataOffset * DownSample) + (i * (Interval * DownSample * 4));
@ -755,14 +765,23 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
float NewFloat = *reinterpret_cast<float*>(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]); float NewFloat = *reinterpret_cast<float*>(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]);
float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y), float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y),
FMath::Abs(NewFloat)); FMath::Abs(NewFloat));
TArray<FVector2D> NewLoc; TArray<FVector2D> NewLoc;
NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i * DownSample) , AllottedGeometry.GetLocalSize().Y)); NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i * DownSample) , AllottedGeometry.GetLocalSize().Y));
NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i * DownSample) , Y)); NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i * DownSample) , Y));
FSlateDrawElement::MakeLines(OutDrawElements, LayerId + 6, AllottedGeometry.ToPaintGeometry(), NewLoc, ESlateDrawEffect::None, 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));
} }
if (ClipData->ClipType == ETrackType::AudioTrack || ClipData->ClipType == ETrackType::AudioTrackR) if (ClipData->ClipType == ETrackType::AudioTrack || ClipData->ClipType == ETrackType::AudioTrackR)
{ {
FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 5, AllottedGeometry.ToPaintGeometry(), FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 5, AllottedGeometry.ToPaintGeometry(),
@ -1034,90 +1053,7 @@ void STimelineClip::OnMouseLeave(const FPointerEvent& MouseEvent)
void STimelineClip::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) 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) SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
{
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;
}
}
}
} }
TSharedPtr<SWidget> STimelineClip::GetPropertiesWidget() TSharedPtr<SWidget> STimelineClip::GetPropertiesWidget()

View File

@ -413,8 +413,8 @@ TSharedPtr<SWidget> FClipProxy::GetPropertiesWidget()
const FGuid& Guid = InItem.Get()->Guid; const FGuid& Guid = InItem.Get()->Guid;
FCurtainGroup* Group = nullptr; FCurtainGroup* Group = nullptr;
const FString CurrentPath = // MainInterface->GetSelf()->CurtainPanel->FindCurtain(Guid,Group)->TimelineInfo.CurrentOpenFullPath; const FString CurrentPath = // MainInterface->GetSelf()->CurtainPanel->FindCurtain(Guid,Group)->TimelineInfo.CurrentOpenFullPath;
MainInterface->GetSelf()->GetSelectTimelineInfoByGuid(Guid).CurrentOpenFullPath; MainInterface->GetSelf()->GetSelectTimelineInfoByGuid(Guid).CurrentOpenRelativePath;
FTimelineLoader TimelineLoader(CurrentPath, true); FTimelineLoader TimelineLoader(ToFullPath(CurrentPath), true);
if (TimelineLoader.GetSpecifyClipData(ClipData->ClipType).Num() > 0 && State == ECheckBoxState::Checked) if (TimelineLoader.GetSpecifyClipData(ClipData->ClipType).Num() > 0 && State == ECheckBoxState::Checked)
{ {
FUtils::AddTips( FUtils::AddTips(
@ -424,7 +424,7 @@ TSharedPtr<SWidget> FClipProxy::GetPropertiesWidget()
.OnEnsure_Lambda([this, State, InItem, CurrentPath](const FString& String) .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); TArray<FClipData> Clips = ModifyTimelineLoader.GetSpecifyClipData(ClipData->ClipType);
for (int32 i = Clips.Num() - 1; i >= 0; i--) for (int32 i = Clips.Num() - 1; i >= 0; i--)
{ {