From 9d6e0b92a016eb184dfb5ffac481c275934c3583 Mon Sep 17 00:00:00 2001 From: Sch <3516520171@qq.com> Date: Fri, 13 Oct 2023 21:19:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=98=E6=A1=A3=E7=A7=BB=E5=8A=A8=EF=BC=8C?= =?UTF-8?q?=E5=B0=81=E9=9D=A2=E5=A4=9A=E7=BA=BF=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cut5.sln | 60 +++---- .../Cut5/Interface/CutMainWidgetInterface.h | 2 +- .../Cut5/Interface/VideoThumbnailThread.cpp | 109 +++++++++--- Source/Cut5/Interface/VideoThumbnailThread.h | 7 +- Source/Cut5/Utils/FFMPEGUtils.cpp | 21 ++- Source/Cut5/Utils/Utils.cpp | 9 +- Source/Cut5/Utils/Utils.h | 23 +-- Source/Cut5/Widgets/Curtain/SCurtain.cpp | 10 +- Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp | 6 +- Source/Cut5/Widgets/DefineGlobal.h | 11 +- .../DragDropOperator/DragDropOperator.cpp | 4 +- Source/Cut5/Widgets/FX/SEffectCard.cpp | 2 +- Source/Cut5/Widgets/FX/SEffectCardGroup.cpp | 10 +- Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp | 20 +-- Source/Cut5/Widgets/SCustomInputResource.cpp | 4 +- Source/Cut5/Widgets/SCutMainWindow.cpp | 44 ++--- Source/Cut5/Widgets/SCutMainWindow.h | 2 +- Source/Cut5/Widgets/SCutTimeline.cpp | 56 ++++--- Source/Cut5/Widgets/SCutTimeline.h | 4 +- Source/Cut5/Widgets/STimelineClip.cpp | 157 ++++-------------- .../Cut5/Widgets/TimelineClips/ClipProxy.cpp | 6 +- 21 files changed, 264 insertions(+), 303 deletions(-) diff --git a/Cut5.sln b/Cut5.sln index 8e330d5..6b74737 100644 --- a/Cut5.sln +++ b/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 diff --git a/Source/Cut5/Interface/CutMainWidgetInterface.h b/Source/Cut5/Interface/CutMainWidgetInterface.h index f404153..841de03 100644 --- a/Source/Cut5/Interface/CutMainWidgetInterface.h +++ b/Source/Cut5/Interface/CutMainWidgetInterface.h @@ -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; }; diff --git a/Source/Cut5/Interface/VideoThumbnailThread.cpp b/Source/Cut5/Interface/VideoThumbnailThread.cpp index fbbd379..39dc737 100644 --- a/Source/Cut5/Interface/VideoThumbnailThread.cpp +++ b/Source/Cut5/Interface/VideoThumbnailThread.cpp @@ -1,11 +1,16 @@ #include "VideoThumbnailThread.h" #include "Cut5/Utils/FFMPEGUtils.h" +#include "Cut5/Utils/Utils.h" -FVideoThumbnailThread::FVideoThumbnailThread(const FString& MoviePath, TFunction OnFinished) +FVideoThumbnailThread::FVideoThumbnailThread(const FString& MoviePath, TFunction 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; diff --git a/Source/Cut5/Interface/VideoThumbnailThread.h b/Source/Cut5/Interface/VideoThumbnailThread.h index c2cee11..8d2ebb6 100644 --- a/Source/Cut5/Interface/VideoThumbnailThread.h +++ b/Source/Cut5/Interface/VideoThumbnailThread.h @@ -1,10 +1,11 @@ #pragma once +#include "Cut5/Widgets/DefineGlobal.h" class FVideoThumbnailThread : public FRunnable { public: - FVideoThumbnailThread(const FString& MoviePath, TFunction OnFinished); + FVideoThumbnailThread(const FString& MoviePath, TFunction OnFinished, int32 BrushCount, const FClipData ClipData); virtual bool Init() override { return true; } virtual uint32 Run() override; @@ -13,5 +14,7 @@ public: FString MoviePath; TFunction OnFinished; - + int32 BrushCount; + FClipData ClipData; + bool bMissionStart = false; }; diff --git a/Source/Cut5/Utils/FFMPEGUtils.cpp b/Source/Cut5/Utils/FFMPEGUtils.cpp index ffca877..d1193c2 100644 --- a/Source/Cut5/Utils/FFMPEGUtils.cpp +++ b/Source/Cut5/Utils/FFMPEGUtils.cpp @@ -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 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); } diff --git a/Source/Cut5/Utils/Utils.cpp b/Source/Cut5/Utils/Utils.cpp index 210a4ee..0946c63 100644 --- a/Source/Cut5/Utils/Utils.cpp +++ b/Source/Cut5/Utils/Utils.cpp @@ -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 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 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; diff --git a/Source/Cut5/Utils/Utils.h b/Source/Cut5/Utils/Utils.h index d6aa43e..4eaecf1 100644 --- a/Source/Cut5/Utils/Utils.h +++ b/Source/Cut5/Utils/Utils.h @@ -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 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() { diff --git a/Source/Cut5/Widgets/Curtain/SCurtain.cpp b/Source/Cut5/Widgets/Curtain/SCurtain.cpp index 64fd0e9..3fcaf47 100644 --- a/Source/Cut5/Widgets/Curtain/SCurtain.cpp +++ b/Source/Cut5/Widgets/Curtain/SCurtain.cpp @@ -163,17 +163,17 @@ TSharedPtr 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); diff --git a/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp b/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp index b04e1ee..eb4a425 100644 --- a/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp +++ b/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp @@ -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; } diff --git a/Source/Cut5/Widgets/DefineGlobal.h b/Source/Cut5/Widgets/DefineGlobal.h index 029d8e0..ee4198a 100644 --- a/Source/Cut5/Widgets/DefineGlobal.h +++ b/Source/Cut5/Widgets/DefineGlobal.h @@ -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; } }; diff --git a/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp b/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp index 3271314..8718a6f 100644 --- a/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp +++ b/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp @@ -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) diff --git a/Source/Cut5/Widgets/FX/SEffectCard.cpp b/Source/Cut5/Widgets/FX/SEffectCard.cpp index 300ce07..b4d2f4c 100644 --- a/Source/Cut5/Widgets/FX/SEffectCard.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCard.cpp @@ -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; diff --git a/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp b/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp index ea16acb..3bf7d76 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp @@ -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; } diff --git a/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp b/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp index 87dce3d..ddf6212 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp @@ -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; } diff --git a/Source/Cut5/Widgets/SCustomInputResource.cpp b/Source/Cut5/Widgets/SCustomInputResource.cpp index a3f4984..505ff5e 100644 --- a/Source/Cut5/Widgets/SCustomInputResource.cpp +++ b/Source/Cut5/Widgets/SCustomInputResource.cpp @@ -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()); diff --git a/Source/Cut5/Widgets/SCutMainWindow.cpp b/Source/Cut5/Widgets/SCutMainWindow.cpp index fec9b95..87a56ed 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.cpp +++ b/Source/Cut5/Widgets/SCutMainWindow.cpp @@ -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 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(); } } diff --git a/Source/Cut5/Widgets/SCutMainWindow.h b/Source/Cut5/Widgets/SCutMainWindow.h index 448fcbd..a626d62 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.h +++ b/Source/Cut5/Widgets/SCutMainWindow.h @@ -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; diff --git a/Source/Cut5/Widgets/SCutTimeline.cpp b/Source/Cut5/Widgets/SCutTimeline.cpp index d830fe9..e4a3f05 100644 --- a/Source/Cut5/Widgets/SCutTimeline.cpp +++ b/Source/Cut5/Widgets/SCutTimeline.cpp @@ -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 ClipProxy = FClipProxy::GetProxy(); @@ -775,8 +787,8 @@ bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info) static_cast(MainWidgetInterface)->UpdateProperties(nullptr); static_cast(MainWidgetInterface)->CloseAllThreads(); TArray 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 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 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; } diff --git a/Source/Cut5/Widgets/SCutTimeline.h b/Source/Cut5/Widgets/SCutTimeline.h index 62df955..d3d36e4 100644 --- a/Source/Cut5/Widgets/SCutTimeline.h +++ b/Source/Cut5/Widgets/SCutTimeline.h @@ -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); diff --git a/Source/Cut5/Widgets/STimelineClip.cpp b/Source/Cut5/Widgets/STimelineClip.cpp index ac54b15..2e94d57 100644 --- a/Source/Cut5/Widgets/STimelineClip.cpp +++ b/Source/Cut5/Widgets/STimelineClip.cpp @@ -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(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]); float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y), FMath::Abs(NewFloat)); + + + TArray 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(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]); - // float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y), - // FMath::Abs(NewFloat)); - // TArray 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 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 STimelineClip::GetPropertiesWidget() diff --git a/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp b/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp index 85ded73..69ea16d 100644 --- a/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp +++ b/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp @@ -413,8 +413,8 @@ TSharedPtr 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 FClipProxy::GetPropertiesWidget() .OnEnsure_Lambda([this, State, InItem, CurrentPath](const FString& String) { // 先清空 - FTimelineLoader ModifyTimelineLoader(CurrentPath, true); + FTimelineLoader ModifyTimelineLoader(ToFullPath(CurrentPath), true); TArray Clips = ModifyTimelineLoader.GetSpecifyClipData(ClipData->ClipType); for (int32 i = Clips.Num() - 1; i >= 0; i--) {