存档移动,封面多线程

This commit is contained in:
Sch 2023-10-13 21:19:22 +08:00
parent 18afa49b78
commit 9d6e0b92a0
21 changed files with 264 additions and 303 deletions

View File

@ -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

View File

@ -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; };

View File

@ -1,11 +1,16 @@
#include "VideoThumbnailThread.h"
#include "Cut5/Utils/FFMPEGUtils.h"
#include "Cut5/Utils/Utils.h"
FVideoThumbnailThread::FVideoThumbnailThread(const FString& MoviePath, TFunction<void(FString)> OnFinished)
FVideoThumbnailThread::FVideoThumbnailThread(const FString& MoviePath, TFunction<void(FString)> OnFinished, int32 BrushCount, const FClipData ClipData)
{
this->MoviePath = MoviePath;
this->OnFinished = OnFinished;
this->BrushCount = BrushCount;
this->ClipData = ClipData;
bMissionStart = true;
}
uint32 FVideoThumbnailThread::Run()
@ -18,31 +23,95 @@ uint32 FVideoThumbnailThread::Run()
FTimelinePropertyData Info;
FFFMPEGUtils::LoadContextPure(MoviePath, &Info);
while (true)
int32 i = 0;
while (bMissionStart)
{
AVPacket* Packet = av_packet_alloc();
if (av_read_frame(Info.Context, Packet) < 0)
if (i < BrushCount && ClipData.ResourcePropertyDataPtr && ClipData.ResourcePropertyDataPtr->Context && ClipData.ResourcePropertyDataPtr->VideoStream != -1)
{
av_packet_free(&Packet);
const int32 CurrentFrame = BrushCount - (BrushCount - i);
const int64 Timestamp = av_rescale_q(CurrentFrame / FGlobalData::GlobalFPS * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, Info.Context->streams[Info.VideoStream]->time_base);
av_seek_frame(Info.Context, Info.VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD);
AVPacket Packet;
av_init_packet(&Packet);
AVFormatContext* FormatContext = Info.Context;
AVCodecContext* VideoCodecContext = Info.VideoCodecContext;
AVCodec* VideoCodec = Info.VideoCodec;
AVFrame* Frame = av_frame_alloc();
while (av_read_frame(FormatContext, &Packet) >= 0)
{
if (avcodec_send_packet(VideoCodecContext, &Packet) < 0)
{
}
if (avcodec_receive_frame(VideoCodecContext, Frame) >= 0)
{
if (Frame->best_effort_timestamp >= Timestamp)
{
break;
}
}
};
if (Frame)
{
if (Frame->width == 0 || Frame->height == 0)
{
continue;
}
struct SwsContext* swsCtx = sws_getContext(
Frame->width, Frame->height, VideoCodecContext->pix_fmt,
Frame->width / 10, Frame->height / 10, AV_PIX_FMT_BGRA,
SWS_BILINEAR, NULL, NULL, NULL
);
if (!swsCtx)
{
UE_LOG(LogTemp, Error, TEXT("Error creating swsContext"));
}
uint8* RawData = new uint8[(Frame->width / 10) * (Frame->height / 10) * 4];
uint8* dest[4] = {RawData, 0, 0, 0};
int32 dest_linesize[4] = {(Frame->width / 10) * 4, 0, 0, 0};
sws_scale(swsCtx, Frame->data, Frame->linesize, 0, Frame->height, dest, dest_linesize);
sws_freeContext(swsCtx);
AsyncTask(ENamedThreads::GameThread, [Frame, RawData, this]()
{
UTexture2D* Texture = UTexture2D::CreateTransient(Frame->width / 10, Frame->height / 10, PF_B8G8R8A8);
if (Texture)
{
void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(MipData, RawData, (Frame->width / 10) * (Frame->height / 10) * 4);
Texture->GetPlatformData()->Mips[0].BulkData.Unlock();
Texture->UpdateResource();
FGuid Guid = FGuid::NewGuid();
FFFMPEGUtils::ExportImage(Texture, ToFullPath(FUtils::GetProjectTempPath() / ClipData.ClipGuid.ToString() / Guid.ToString() + ".png"));
OnFinished(FUtils::GetProjectTempPath() / ClipData.ClipGuid.ToString() / Guid.ToString() + ".png");
Texture->MarkAsGarbage();
delete RawData;
}
});
i++;
}
}
else
{
bMissionStart = false;
break;
}
if (avcodec_send_packet(Info.VideoCodecContext, Packet) < 0)
{
}
AVFrame* Frame = av_frame_alloc();
if (avcodec_receive_frame(Info.VideoCodecContext, Frame) >= 0)
{
int32 CurrentTime = av_rescale(Frame->best_effort_timestamp, Info.VideoCodecContext->time_base.den, AV_TIME_BASE);
UE_LOG(LogTemp, Warning, TEXT("Frame->best_effort_timestamp: %d"), CurrentTime);
};
}
return 0;

View File

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

View File

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

View File

@ -87,7 +87,7 @@ FString FUtils::GetResourcesPath(FString ResourcesName, bool bFullPath)
FString FUtils::GetProjectTempPath()
{
return FPaths::ConvertRelativePathToFull(FPaths::Combine(FGlobalData::BasePath / FGlobalData::CurrentProjectName / "/Temp/"));
return TEXT("Temp/");
}
FSlateDynamicImageBrush* FUtils::GetBrushFromImage(const FString& ImageName, const FVector2D Size)
@ -370,7 +370,7 @@ TArray<FEncodeVideoInfo> FUtils::TrackEncodeVideo(const FTrackData& TrackData, c
FString StartTime = FString::Printf(TEXT("%02d:%02d:%02d.%s"), StartTimespan.GetHours(), StartTimespan.GetMinutes(), StartTimespan.GetSeconds(), *NewStartMilli);
FString EndTime = FString::Printf(TEXT("%02d:%02d:%02d.%s"), EndTimespan.GetHours(), EndTimespan.GetMinutes(), EndTimespan.GetSeconds(), *NewEndMilli);
FString InputFile = "\"" + TempClipData.ResourcePropertyDataPtr->MoviePath + "\"";
FString InputFile = "\"" + ToFullPath(TempClipData.ResourcePropertyDataPtr->MoviePath) + "\"";
FString OutputFile = "\"" + FPaths::ConvertRelativePathToFull(ExportPath + FString::FromInt(i) + TEXT(".mp4")) + "\"";
@ -440,7 +440,7 @@ FEncodeVideoInfo FUtils::TrackEncodeAudio(const FTrackData& TrackData, const FSt
FString StartTime = FString::Printf(TEXT("%02d:%02d:%02d"), StartTimespan.GetHours(), StartTimespan.GetMinutes(), StartTimespan.GetSeconds());
FString EndTime = FString::Printf(TEXT("%02d:%02d:%02d"), EndTimespan.GetHours(), EndTimespan.GetMinutes(), EndTimespan.GetSeconds());
FString InputFile = TempClipData.ResourcePropertyDataPtr->MoviePath;
FString InputFile = ToFullPath(TempClipData.ResourcePropertyDataPtr->MoviePath);
FString OutputFile = ExportPath + TEXT(".mp3");
@ -632,8 +632,7 @@ TArray<FEncodeVideoInfo> FUtils::ExportPsaf(FTrackData TrackData, const FString&
FString ExportName = FGuid::NewGuid().ToString();;
if (TempClipData.ResourcePropertyDataPtr)
{
TempClipData.ResourcePropertyDataPtr->MoviePath;
FString TempPath = TempClipData.ResourcePropertyDataPtr->MoviePath;
FString TempPath = ToFullPath(TempClipData.ResourcePropertyDataPtr->MoviePath);
frames.Empty();
VideoCapture capture;

View File

@ -2,6 +2,11 @@
#include "CoreMinimal.h"
#include "Cut5/Widgets/DefineGlobal.h"
inline FString ToFullPath(const FString& String)
{
return FGlobalData::BasePath / FGlobalData::CurrentProjectName / String;
}
class FUtils
{
public:
@ -36,22 +41,20 @@ public:
static TArray<FEncodeVideoInfo> TrackEncodeVideo(const FTrackData& TrackData, const FString& ExportPath);
static FEncodeVideoInfo TrackEncodeAudio(const FTrackData& TrackDataLeft, const FString& ExportPath);
static FEncodeVideoInfo CombineAudio(const FEncodeVideoInfo& LeftEncodeData, const FEncodeVideoInfo& RightEncodeData, const FString& ExportPath);
static FString CurtainFullPath(const FString& GroupName)
static FString CurtainRelativePath(const FString& GroupName)
{
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("Curtain"), GroupName + TEXT(".bin"));
return TEXT("Curtain") / GroupName + TEXT(".bin");
};
static FString GroupFullPath(const FString& GroupName)
static FString GroupRelativePath(const FString& GroupName)
{
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), GroupName + TEXT(".bin"));
return TEXT("FX") / GroupName + TEXT(".bin");
};
static FString SingleCardFullPath(const FString& CardName)
static FString SingleCardRelativePath(const FString& CardName)
{
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, TEXT("FX"), TEXT("SingleCard"), CardName + TEXT(".bin"));
return FString() / TEXT("FX") / TEXT("SingleCard") / CardName + TEXT(".bin");
};
static FString MainSaveFullPath()
{
return FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, FGlobalData::CurrentProjectName + TEXT(".bin"));
};
static FUtils* GetInstance()
{

View File

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

View File

@ -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;
}

View File

@ -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;
}
};

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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());

View File

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

View File

@ -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;

View File

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

View File

@ -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);

View File

@ -267,15 +267,23 @@ void STimelineClip::Construct(const FArguments& InArgs)
FRunnableThread::Create(Thread, TEXT("VideoThread"));
MainWidgetInterface->GetSelf()->AddThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid), Thread);
}
// if (!MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThumbnailThreadGuid(ClipData->ClipGuid)))
// {
// FVideoThumbnailThread* ThumbnailThread = new FVideoThumbnailThread(ClipData->MoviePath, [this](const FString& PicPath)
// {
//
// });
// FRunnableThread::Create(ThumbnailThread, TEXT("VideoThumbnailThread"));
// MainWidgetInterface->GetSelf()->AddThread(FUtils::GetVideoThumbnailThreadGuid(ClipData->ClipGuid), ThumbnailThread);
// }
if (ClipData->ClipGuid != FGuid())
{
if (!MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThumbnailThreadGuid(ClipData->ClipGuid)))
{
FVideoThumbnailThread* ThumbnailThread = new FVideoThumbnailThread(ClipData->MoviePath, [this](const FString& PicPath)
{
ClipData->MovieBrushesPath.Add(PicPath);
const FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ToFullPath(PicPath), FVector2f(0, 0));
ClipData->MovieBrushes.Add(Brush);
}, ClipData->MovieBrushNum, *ClipData);
FRunnableThread::Create(ThumbnailThread, TEXT("VideoThumbnailThread"));
MainWidgetInterface->GetSelf()->AddThread(FUtils::GetVideoThumbnailThreadGuid(ClipData->ClipGuid), ThumbnailThread);
}
}
}
@ -746,6 +754,8 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
if (CropStartFrameOffset != -1 || NeedDrawCount != -1)
{
const float StartRange = CurrentStartRange - RangeStart;
const float EndRange = CurrentEndRange;
for (int32 i = 0; i < NeedDrawCount / DownSample; i++)
{
const int32 CurrentIndex = (CropStartDataOffset * DownSample) + (i * (Interval * DownSample * 4));
@ -755,51 +765,23 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
float NewFloat = *reinterpret_cast<float*>(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]);
float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y),
FMath::Abs(NewFloat));
TArray<FVector2D> NewLoc;
NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i * DownSample) , AllottedGeometry.GetLocalSize().Y));
NewLoc.Add(FVector2D((CropStartFrameOffset * FGlobalData::DefaultTimeTickSpace + i * DownSample) , Y));
FSlateDrawElement::MakeLines(OutDrawElements, LayerId + 6, AllottedGeometry.ToPaintGeometry(), NewLoc, ESlateDrawEffect::None,
FColor(45, 214, 153, 255), true, DownSample * 1.2);
FColor(45, 214, 153, 255), true, DownSample * 1.2);
}
// GEngine->AddOnScreenDebugMessage(-1, 0.1f, FColor::Red, FString::SanitizeFloat(StartRange));
}
//
// int32 NeedDrawCount = ClipData->GetLength() * FGlobalData::DefaultTimeTickSpace;
// float DownSample = 4;
// // Draw Audio Waveform
//
//
// const float RangeStart = MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().LocalToAbsolute(FVector2D(0, 0)).X;
// const float RangeEnd = MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().LocalToAbsolute(FVector2D(MainWidgetInterface->GetCutTimeline()->TrackBodyHScrollBox->GetCachedGeometry().GetLocalSize().X, 0)).X;
// const float CurrentStartRange = AllottedGeometry.LocalToAbsolute(FVector2D(0, 0)).X;
// const float CurrentEndRange = AllottedGeometry.LocalToAbsolute(FVector2D(AllottedGeometry.GetLocalSize().X, 0)).X;
//
// const int32 StartOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS)
// * ClipData->VideoStartFrame
// * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) * 2 / DownSample;
//
// const int32 EndOffset = (ClipData->ResourcePropertyDataPtr->AudioSample / FGlobalData::GlobalFPS)
// * ClipData->VideoEndFrame
// * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) * 2 / DownSample;
//
// const int32 Interval = (EndOffset - StartOffset) / NeedDrawCount;
// for (int32 i = 0; i < NeedDrawCount / DownSample; i++)
// {
// const int32 CurrentIndex = (StartOffset * DownSample) + (i * (Interval * DownSample * 4));
// if (CurrentIndex >= ClipData->ResourcePropertyDataPtr->AudioData.Num())
// continue;
//
// float NewFloat = *reinterpret_cast<float*>(&ClipData->ResourcePropertyDataPtr->AudioData[CurrentIndex]);
// float Y = FMath::GetMappedRangeValueClamped(FVector2D(1.0, 0.0), FVector2D(0.0, AllottedGeometry.GetLocalSize().Y),
// FMath::Abs(NewFloat));
// TArray<FVector2D> NewLoc;
// NewLoc.Add(FVector2D(i * DownSample, AllottedGeometry.GetLocalSize().Y));
// NewLoc.Add(FVector2D(i * DownSample, Y));
// FSlateDrawElement::MakeLines(OutDrawElements, LayerId + 6, AllottedGeometry.ToPaintGeometry(), NewLoc, ESlateDrawEffect::None,
// FColor(45, 214, 153, 255), true, DownSample * 1.2);
// }
if (ClipData->ClipType == ETrackType::AudioTrack || ClipData->ClipType == ETrackType::AudioTrackR)
{
FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 5, AllottedGeometry.ToPaintGeometry(),
@ -1072,90 +1054,7 @@ void STimelineClip::OnMouseLeave(const FPointerEvent& MouseEvent)
void STimelineClip::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
if (ClipData->MovieBrushes.Num() < ClipData->MovieBrushNum && ClipData->ResourcePropertyDataPtr && ClipData->ResourcePropertyDataPtr->Context && ClipData->ResourcePropertyDataPtr->VideoStream != -1)
{
if (ThumbnailCodecContext.Context == nullptr)
{
FFFMPEGUtils::LoadContextPure(ClipData->ResourcePropertyDataPtr->MoviePath, &ThumbnailCodecContext);
return;
}
const int32 CurrentFrame = ClipData->MovieBrushNum - (ClipData->MovieBrushNum - ClipData->MovieBrushes.Num());
const int64 Timestamp = av_rescale_q(CurrentFrame / FGlobalData::GlobalFPS * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, ThumbnailCodecContext.Context->streams[ThumbnailCodecContext.VideoStream]->time_base);
av_seek_frame(ThumbnailCodecContext.Context, ThumbnailCodecContext.VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD);
AVPacket Packet;
av_init_packet(&Packet);
AVFormatContext* FormatContext = ThumbnailCodecContext.Context;
AVCodecContext* VideoCodecContext = ThumbnailCodecContext.VideoCodecContext;
AVCodec* VideoCodec = ThumbnailCodecContext.VideoCodec;
AVFrame* Frame = av_frame_alloc();
while (av_read_frame(FormatContext, &Packet) >= 0)
{
if (avcodec_send_packet(VideoCodecContext, &Packet) < 0)
{
}
if (avcodec_receive_frame(VideoCodecContext, Frame) >= 0)
{
if (Frame->best_effort_timestamp >= Timestamp)
{
break;
}
}
};
if (Frame)
{
if (Frame->width == 0 || Frame->height == 0)
{
TArray<FSlateBrush> Brushes;
Brushes.Init(FSlateBrush(), ClipData->MovieBrushNum - ClipData->MovieBrushes.Num());
ClipData->MovieBrushes.Append(Brushes);
return;
}
struct SwsContext* swsCtx = sws_getContext(
Frame->width, Frame->height, VideoCodecContext->pix_fmt,
Frame->width / 10, Frame->height / 10, AV_PIX_FMT_BGRA,
SWS_BILINEAR, NULL, NULL, NULL
);
if (!swsCtx)
{
UE_LOG(LogTemp, Error, TEXT("Error creating swsContext"));
}
uint8* RawData = new uint8[(Frame->width / 10) * (Frame->height / 10) * 4];
uint8* dest[4] = {RawData, 0, 0, 0};
int32 dest_linesize[4] = {(Frame->width / 10) * 4, 0, 0, 0};
sws_scale(swsCtx, Frame->data, Frame->linesize, 0, Frame->height, dest, dest_linesize);
sws_freeContext(swsCtx);
UTexture2D* Texture = UTexture2D::CreateTransient(Frame->width / 10, Frame->height / 10, PF_B8G8R8A8);
if (Texture)
{
void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(MipData, RawData, (Frame->width / 10) * (Frame->height / 10) * 4);
Texture->GetPlatformData()->Mips[0].BulkData.Unlock();
Texture->UpdateResource();
FGuid Guid = FGuid::NewGuid();
FFFMPEGUtils::ExportImage(Texture, *FPaths::Combine(FUtils::GetProjectTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png"));
ClipData->MovieBrushesPath.Add(FPaths::Combine(FUtils::GetProjectTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png"));
FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ClipData->MovieBrushesPath[ClipData->MovieBrushesPath.Num() - 1], FVector2f(0, 0));
ClipData->MovieBrushes.Add(Brush);
Texture->MarkAsGarbage();
delete RawData;
}
}
}
SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
}
TSharedPtr<SWidget> STimelineClip::GetPropertiesWidget()

View File

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