音频导出

This commit is contained in:
Sch 2023-09-09 14:59:45 +08:00
parent 8005d78372
commit 7613ea06cd
30 changed files with 471 additions and 146 deletions

BIN
Asset/1.wav Normal file

Binary file not shown.

BIN
Asset/A.mp3 Normal file

Binary file not shown.

3
Asset/Start.bat Normal file
View File

@ -0,0 +1,3 @@
D:\Project\Cut5\Binaries\Win64\ffmpeg.exe -i 1.wav -i A.mp3 -filter_complex "[0:a]pan=1c|c0=c0[a];[1:a]pan=1c|c0=c1[b];[a][b]amerge=inputs=2[aout]" -map "[aout]" -t 1000000 output.mp3
pause

BIN
Asset/output.mp3 Normal file

Binary file not shown.

View File

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

View File

@ -368,12 +368,14 @@ TArray<FEncodeVideoInfo> FUtils::TrackEncodeVideo(const FTrackData& TrackData, c
} }
TArray<FEncodeVideoInfo> FUtils::TrackEncodeAudio(const FTrackData& TrackData, const FString& ExportPath) FEncodeVideoInfo FUtils::TrackEncodeAudio(const FTrackData& TrackData, const FString& ExportPath)
{ {
FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FPaths::GetPath(ExportPath));
TArray<FClipData> ClipData = TrackData.ClipData; TArray<FClipData> ClipData = TrackData.ClipData;
ClipData.Sort([](const FClipData& A, const FClipData& B) {return A.ClipStartFrame < B.ClipStartFrame; }); ClipData.Sort([](const FClipData& A, const FClipData& B) {return A.ClipStartFrame < B.ClipStartFrame; });
// 先拆出所有音频 FEncodeVideoInfo EncodeVideoInfo;
FClipData SavedClipData;
int32 AudioCount = 0; int32 AudioCount = 0;
{ {
int32 i = 0; int32 i = 0;
@ -381,7 +383,7 @@ TArray<FEncodeVideoInfo> FUtils::TrackEncodeAudio(const FTrackData& TrackData, c
{ {
if (TempClipData.ResourcePropertyDataPtr->Context) if (TempClipData.ResourcePropertyDataPtr->Context)
{ {
FEncodeVideoInfo EncodeVideoInfo; SavedClipData = TempClipData;
FTimespan EndTimespan = FTimespan::FromSeconds(TempClipData.VideoEndFrame / FGlobalData::GlobalFPS); FTimespan EndTimespan = FTimespan::FromSeconds(TempClipData.VideoEndFrame / FGlobalData::GlobalFPS);
FTimespan StartTimespan = FTimespan::FromSeconds(TempClipData.VideoStartFrame / FGlobalData::GlobalFPS); FTimespan StartTimespan = FTimespan::FromSeconds(TempClipData.VideoStartFrame / FGlobalData::GlobalFPS);
@ -389,47 +391,50 @@ TArray<FEncodeVideoInfo> FUtils::TrackEncodeAudio(const FTrackData& TrackData, c
FString EndTime = FString::Printf(TEXT("%02d:%02d:%02d"), EndTimespan.GetHours(), EndTimespan.GetMinutes(), EndTimespan.GetSeconds()); FString EndTime = FString::Printf(TEXT("%02d:%02d:%02d"), EndTimespan.GetHours(), EndTimespan.GetMinutes(), EndTimespan.GetSeconds());
FString InputFile = TempClipData.ResourcePropertyDataPtr->MoviePath; FString InputFile = TempClipData.ResourcePropertyDataPtr->MoviePath;
FString OutputFile = FPaths::ConvertRelativePathToFull(GetProjectTempPath() / FString::FromInt(i) + TEXT(".mp3")); FString OutputFile = ExportPath + TEXT(".mp3");
int32 StartFrame = (TempClipData.VideoStartFrame) % static_cast<int>(FGlobalData::GlobalFPS);; int32 StartFrame = (TempClipData.VideoStartFrame) % static_cast<int>(FGlobalData::GlobalFPS);;
int32 EndFrame = (TempClipData.VideoEndFrame) % static_cast<int>(FGlobalData::GlobalFPS); int32 EndFrame = (TempClipData.VideoEndFrame) % static_cast<int>(FGlobalData::GlobalFPS);
FString Command = FString::Printf(TEXT("-y -i \"%s\" -ss %s -to %s -c copy \"%s\""), FString Command = FString::Printf(TEXT("-y -i \"%s\" -ss %s -to %s \"%s\""),
*InputFile, *StartTime, *EndTime, *OutputFile); *InputFile, *StartTime, *EndTime, *OutputFile);
FPlatformProcess::CreateProc(*GetFfmepg(), *Command, true, false, false, nullptr, 0, nullptr, nullptr);
FProcHandle ProcHandle = FPlatformProcess::CreateProc(*GetFfmepg(), *Command, true, false, false, nullptr, 0, nullptr, nullptr);
while (FPlatformProcess::IsProcRunning(ProcHandle)){ FPlatformProcess::Sleep(0.1);};
i++; i++;
AudioCount++; AudioCount++;
} }
} }
} }
if (AudioCount > 1)
FString Header = GetFfmepg();
for (int32 i = 0; i < ClipData.Num(); i++)
{ {
Header += " -i "; FString Header = GetFfmepg();
Header += "\"" + GetProjectTempPath() / FString::FromInt(i) + ".mp3" + "\""; for (int32 i = 0; i < ClipData.Num(); i++)
{
Header += " -i ";
Header += "\"" + GetProjectTempPath() / FString::FromInt(i) + ".mp3" + "\"";
}
Header += " -filter_complex";
// [0:0][1:0]...[n:0]concat=n=n=2:v=0:a=1[out]
for (int32 i = 0; i < ClipData.Num(); i++)
{
Header += "[" + FString::FromInt(i) + ":0]";
}
Header += "concat=n=" + FString::FromInt(ClipData.Num()) + ":v=0:a=1[out]";
Header += " -map [out] -y " + ExportPath + ".mp3";
FProcHandle ProcHandle = FPlatformProcess::CreateProc(*GetFfmepg(), *Header, true, false, false, nullptr, 0, nullptr, nullptr);
while (FPlatformProcess::IsProcRunning(ProcHandle)){ FPlatformProcess::Sleep(0.1);};
} }
Header += " -filter_complex";
// [0:0][1:0]...[n:0]concat=n=n=2:v=0:a=1[out]
for (int32 i = 0; i < ClipData.Num(); i++)
{
Header += "[" + FString::FromInt(i) + ":0]";
}
Header += "concat=n=" + FString::FromInt(ClipData.Num()) + ":v=0:a=1[out]";
Header += " -map [out] -y " + ExportPath + ".mp3";
FPlatformProcess::CreateProc(*GetFfmepg(), *Header, true, false, false, nullptr, 0, nullptr, nullptr);
// int32 i = 0; // int32 i = 0;
TArray<FEncodeVideoInfo> EncodeVideoInfos; // TArray<FEncodeVideoInfo> EncodeVideoInfos;
// for (FClipData& TempClipData : ClipData) // for (FClipData& TempClipData : ClipData)
// { // {
// if (TempClipData.ResourcePropertyDataPtr->Context) // if (TempClipData.ResourcePropertyDataPtr->Context)
@ -450,7 +455,8 @@ TArray<FEncodeVideoInfo> FUtils::TrackEncodeAudio(const FTrackData& TrackData, c
// FString Command = FString::Printf(TEXT("-y -i \"%s\" -ss %s -to %s -c copy \"%s\""), // FString Command = FString::Printf(TEXT("-y -i \"%s\" -ss %s -to %s -c copy \"%s\""),
// *InputFile, *StartTime, *EndTime, *OutputFile); // *InputFile, *StartTime, *EndTime, *OutputFile);
// //
// FPlatformProcess::CreateProc(*GetFfmepg(), *Command, true, false, false, nullptr, 0, nullptr, nullptr); // FProcHandle ProcHandle = FPlatformProcess::CreateProc(*GetFfmepg(), *Command, true, false, false, nullptr, 0, nullptr, nullptr);
// while (FPlatformProcess::IsProcRunning(ProcHandle)){ FPlatformProcess::Sleep(0.1);};
// //
// EncodeVideoInfo.EncodedVideoTimeCode = FGlobalData::GetTimeData(TempClipData.ClipStartFrame); // EncodeVideoInfo.EncodedVideoTimeCode = FGlobalData::GetTimeData(TempClipData.ClipStartFrame);
// EncodeVideoInfo.EncodedVideoName = ExportPath + FString::FromInt(i) + TEXT(".mp3"); // EncodeVideoInfo.EncodedVideoName = ExportPath + FString::FromInt(i) + TEXT(".mp3");
@ -463,14 +469,65 @@ TArray<FEncodeVideoInfo> FUtils::TrackEncodeAudio(const FTrackData& TrackData, c
// } // }
// i++; // i++;
// } // }
return EncodeVideoInfos;
EncodeVideoInfo.EncodedVideoTimeCode = FGlobalData::GetTimeData(SavedClipData.ClipStartFrame);
EncodeVideoInfo.EncodedVideoName = ExportPath + TEXT(".mp3");
EncodeVideoInfo.ClipStartFrame = SavedClipData.ClipStartFrame;
EncodeVideoInfo.ClipEndFrame = SavedClipData.ClipEndFrame;
EncodeVideoInfo.TrackData = TrackData;
EncodeVideoInfo.ClipData = SavedClipData;
return EncodeVideoInfo;
} }
TArray<FEncodeVideoInfo> FUtils::CombineAudio(const FEncodeVideoInfo& EncodeVideoInfo, FEncodeVideoInfo FUtils::CombineAudio(const FEncodeVideoInfo& LeftEncodeData,
const FEncodeVideoInfo& EncodeAudioInfo, const FString& ExportPath) const FEncodeVideoInfo& RightEncodeData, const FString& ExportPath)
{ {
return {}; FString LeftPathName = "";
FString RightPathName = "";
if (FPaths::FileExists(LeftEncodeData.EncodedVideoName))
{
LeftPathName = LeftEncodeData.EncodedVideoName;
}
if (FPaths::FileExists(RightEncodeData.EncodedVideoName))
{
RightPathName = RightEncodeData.EncodedVideoName;
}
FString Command = "";
if (LeftPathName == "")
{
Command = FString() + " -i " + "\"" +
RightPathName + "\"" + " -y -af \"pan=stereo|c0=0|c1=0\" " + "\"" +
ExportPath + ".mp3"+ "\"";
}
else if (RightPathName == "")
{
Command = FString() + " -i " + "\"" +
LeftPathName + "\"" + " -y -af \"pan=stereo|c0=c0\" " + "\"" +
ExportPath + ".mp3"+ "\"";
}
else
{
Command = FString() + " -i " + "\"" +
LeftPathName + "\"" + " -i " + "\"" +
RightPathName + "\"" +
" -y -filter_complex \"[0:a]pan=1c|c0=c0[a];[1:a]pan=1c|c0=c1[b];[a][b]amerge=inputs=2[aout]\" " +
"-map \"[aout]\" " +
ExportPath+ ".mp3" + "\"";
}
FProcHandle ProcHandle = FPlatformProcess::CreateProc(*GetFfmepg(), *Command, true, false, false, nullptr, 0, nullptr, nullptr);
while (FPlatformProcess::IsProcRunning(ProcHandle)){ FPlatformProcess::Sleep(0.1);};
FEncodeVideoInfo VideoInfo;
VideoInfo.EncodedVideoName = ExportPath + TEXT(".mp3");
VideoInfo.EncodedVideoTimeCode = FGlobalData::GetTimeData(LeftEncodeData.ClipStartFrame);
VideoInfo.ClipStartFrame = LeftEncodeData.ClipStartFrame;
VideoInfo.ClipData = LeftEncodeData.ClipData;
return VideoInfo;
} }
FString FUtils::GetFfmepg() FString FUtils::GetFfmepg()
@ -759,6 +816,10 @@ FString FUtils::Color2Hex3(FColor Color)
return FString::Printf(TEXT("%02X%02X%02X"), Color.R, Color.G, Color.B); return FString::Printf(TEXT("%02X%02X%02X"), Color.R, Color.G, Color.B);
} }
void FUtils::AddTips(TSharedPtr<SWidget> Widget)
{
GEngine->GameViewport->AddViewportWidgetContent(Widget.ToSharedRef());
}
FSaveModifier::FSaveModifier(const FString& FullSavedPath) FSaveModifier::FSaveModifier(const FString& FullSavedPath)

View File

@ -33,8 +33,8 @@ public:
static void CreateDefaultTimelineSave(const FString& SavedPath, const FTimelineInfo::ETimelineType Type); static void CreateDefaultTimelineSave(const FString& SavedPath, const FTimelineInfo::ETimelineType Type);
static TArray<FEncodeVideoInfo> TrackEncodeVideo(const FTrackData& TrackData, const FString& ExportPath); static TArray<FEncodeVideoInfo> TrackEncodeVideo(const FTrackData& TrackData, const FString& ExportPath);
static TArray<FEncodeVideoInfo> TrackEncodeAudio(const FTrackData& TrackDataLeft, const FString& ExportPath); static FEncodeVideoInfo TrackEncodeAudio(const FTrackData& TrackDataLeft, const FString& ExportPath);
static TArray<FEncodeVideoInfo> CombineAudio(const FEncodeVideoInfo& EncodeVideoInfo, const FEncodeVideoInfo& EncodeAudioInfo, const FString& ExportPath); static FEncodeVideoInfo CombineAudio(const FEncodeVideoInfo& LeftEncodeData, const FEncodeVideoInfo& RightEncodeData, const FString& ExportPath);
static FString CurtainFullPath(const FString& GroupName) static FString CurtainFullPath(const FString& GroupName)
{ {
// GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FGlobalData::BasePath); // GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FGlobalData::BasePath);
@ -88,6 +88,10 @@ public:
static FString GetMsFromString(FString TimeString); static FString GetMsFromString(FString TimeString);
static FString Color2Hex3(FColor Color); static FString Color2Hex3(FColor Color);
static void AddTips(TSharedPtr<SWidget> Widget);
}; };
template <typename T, typename U> template <typename T, typename U>
@ -140,7 +144,6 @@ T* FUtils::CastTypeByFormat(U* InValue, AVSampleFormat* Format)
} }
class FSaveModifier class FSaveModifier
{ {
public: public:

View File

@ -8,6 +8,7 @@
#include "Brushes/SlateBoxBrush.h" #include "Brushes/SlateBoxBrush.h"
#include "Brushes/SlateImageBrush.h" #include "Brushes/SlateImageBrush.h"
#include "Cut5/Utils/Utils.h" #include "Cut5/Utils/Utils.h"
#include "Cut5/Widgets/SCutMainWindow.h"
#include "Cut5/Widgets/Style/CutButtonWidgetStyle.h" #include "Cut5/Widgets/Style/CutButtonWidgetStyle.h"
#include "Widgets/Text/SInlineEditableTextBlock.h" #include "Widgets/Text/SInlineEditableTextBlock.h"
@ -124,6 +125,8 @@ FReply SCurtain::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEv
TSharedPtr<FCurtainDragDrop> SCurtain::OpenThis() TSharedPtr<FCurtainDragDrop> SCurtain::OpenThis()
{ {
CurtainPanel->MainWidgetInterface->GetSelf()->DeselectAll();
CurtainPanel->DeSelectedAll(); CurtainPanel->DeSelectedAll();
Curtain->bIsActive = true; Curtain->bIsActive = true;
CurtainPanel->CallRender(); CurtainPanel->CallRender();

View File

@ -263,7 +263,16 @@ void SCurtainPanel::AddNewCurtain(int32 Index)
{ {
if (Index < Groups.Num()) if (Index < Groups.Num())
{ {
Groups[Index].Curtains.Add(FCurtain()); FCurtain Curtain;
FUtils::CreateDefaultTimelineSave(FUtils::CurtainFullPath(Curtain.CurtainUUID.ToString()), FTimelineInfo::ETimelineType::FX);
{
FSaveModifier SaveModifier(FUtils::CurtainFullPath(Curtain.CurtainUUID.ToString()));
SaveModifier.TimelineInfo.CurrentOpenFullPath = FUtils::CurtainFullPath(Curtain.CurtainUUID.ToString());
SaveModifier.TimelineInfo.CurrentOpenType = FTimelineInfo::ETimelineType::FX;
Curtain.TimelineInfo = SaveModifier.TimelineInfo;
}
Groups[Index].Curtains.Add(Curtain);
CallRender(); CallRender();
} }
} }

View File

@ -335,6 +335,8 @@ struct CUT5_API FClipData : public TSharedFromThis<FClipData>
Ar << ClipData.VolumeData; Ar << ClipData.VolumeData;
Ar << ClipData.bIsCycle; Ar << ClipData.bIsCycle;
Ar << ClipData.AudioCurtains; Ar << ClipData.AudioCurtains;
Ar << ClipData.bIsVirtual;
Ar << ClipData.VirtualCurtainName;
return Ar; return Ar;
}; };
@ -393,6 +395,12 @@ struct CUT5_API FClipData : public TSharedFromThis<FClipData>
} }
} }
} }
void Move(int32 StartFrame)
{
const int32 OriginStartFrame = ClipStartFrame;
ClipStartFrame = StartFrame;
ClipEndFrame = ClipEndFrame + (OriginStartFrame - StartFrame);
}
void CropClip(ECropMethod CropMethod, int32 CropFrame) void CropClip(ECropMethod CropMethod, int32 CropFrame)
{ {
if (CropMethod == ECropMethod::FromFront) if (CropMethod == ECropMethod::FromFront)
@ -427,25 +435,33 @@ struct CUT5_API FClipData : public TSharedFromThis<FClipData>
FTimelinePropertyData* ResourcePropertyDataPtr = nullptr; FTimelinePropertyData* ResourcePropertyDataPtr = nullptr;
FGuid ResourcePropertyGuid; FGuid ResourcePropertyGuid;
AVSampleFormat SampleFormat; AVSampleFormat SampleFormat;
// Movies // Movies
FString MoviePath; FString MoviePath;
int32 VideoStartFrame = 0; int32 VideoStartFrame = 0;
int32 VideoEndFrame = 0; int32 VideoEndFrame = 0;
cv::VideoCapture* VideoCapture;
// Light Array // Light Array
TArray<TArray<FColor>> LightArrayData; TArray<TArray<FColor>> LightArrayData;
// Player // Player
FString PlayerName; FString PlayerName;
TArray<FColor> PlayerLightData; TArray<FColor> PlayerLightData;
EPresetType PresetType = EPresetType::NotAPresets; EPresetType PresetType = EPresetType::NotAPresets;
bool bIsVirtual = false;
FString VirtualCurtainName = "";
// Placeholder
int32 PlaceHolder1 = 0;
int32 PlaceHolder2 = 0;
int32 PlaceHolder3 = 0;
int32 PlaceHolder4 = 0;
float PlaceHolder5 = 0;
float PlaceHolder6 = 0;
float PlaceHolder7 = 0;
float PlaceHolder8 = 0;
bool operator == (const FClipData& Other) const bool operator == (const FClipData& Other) const

View File

@ -805,8 +805,6 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
NewClipData.MoviePath = ClipDragOperation.TimelinePropertyData->MoviePath; NewClipData.MoviePath = ClipDragOperation.TimelinePropertyData->MoviePath;
NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + ClipDragOperation.TimelinePropertyData->MovieFrameLength; NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + ClipDragOperation.TimelinePropertyData->MovieFrameLength;
NewClipData.VideoEndFrame = ClipDragOperation.TimelinePropertyData->MovieFrameLength; NewClipData.VideoEndFrame = ClipDragOperation.TimelinePropertyData->MovieFrameLength;
NewClipData.VideoCapture = ClipDragOperation.VideoCapture;
NewClipData.MovieBrushes = FFFMPEGUtils::GetMovieBrush(&NewClipData); NewClipData.MovieBrushes = FFFMPEGUtils::GetMovieBrush(&NewClipData);
@ -861,6 +859,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
{ {
return; return;
} }
TSharedPtr<STrackHead> TrackHead = StaticCastSharedPtr<STrackBody>(ClipDragOperation.OverrideWidget)->TrackHead; TSharedPtr<STrackHead> TrackHead = StaticCastSharedPtr<STrackBody>(ClipDragOperation.OverrideWidget)->TrackHead;
static_cast<SCutMainWindow*>(TrackHead->MainWidgetInterface)->bRenderLine = false; static_cast<SCutMainWindow*>(TrackHead->MainWidgetInterface)->bRenderLine = false;
@ -912,6 +911,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
TrackHead->TrackData.ClipData.Add(NewClipData); TrackHead->TrackData.ClipData.Add(NewClipData);
UpdateClipProcess(TrackBody->MainWidgetInterface, NewClipData); UpdateClipProcess(TrackBody->MainWidgetInterface, NewClipData);
SavedMainInterface->UpdateProperties(nullptr);
TrackBody->CallRender(); TrackBody->CallRender();
return; return;

View File

@ -81,6 +81,8 @@ void SEffectCard::Construct(const FArguments& InArgs)
PropertiesInterfaceGUID = CardProperty->Guid; PropertiesInterfaceGUID = CardProperty->Guid;
MainInterface->CurrentSelectedPropertiesInterfaceGuid = CardProperty->Guid; MainInterface->CurrentSelectedPropertiesInterfaceGuid = CardProperty->Guid;
MainInterface->UpdateProperties(this); MainInterface->UpdateProperties(this);
MainInterface->GetSelf()->DeselectAll();
MainInterface->OnSelectCard(CardProperty->Guid); MainInterface->OnSelectCard(CardProperty->Guid);
TSharedPtr<FEffectCardDragDrop> EffectCardDragDrop = MakeShared<FEffectCardDragDrop>(); TSharedPtr<FEffectCardDragDrop> EffectCardDragDrop = MakeShared<FEffectCardDragDrop>();

View File

@ -390,6 +390,7 @@ void SEffectCardGroup::OnSelect()
MainInterface->OpenTimeline(Name, true); MainInterface->OpenTimeline(Name, true);
MainInterface->CurrentSelectedPropertiesInterfaceGuid = EffectCardGroup->Guid; MainInterface->CurrentSelectedPropertiesInterfaceGuid = EffectCardGroup->Guid;
MainInterface->UpdateProperties(this); MainInterface->UpdateProperties(this);
MainInterface->GetSelf()->DeselectAll();
MainInterface->OnSelectCard(EffectCardGroup->Guid); MainInterface->OnSelectCard(EffectCardGroup->Guid);
} }
} }

View File

@ -12,7 +12,7 @@ void STips::Construct(const FArguments& InArgs)
{ {
OnEnsure = InArgs._OnEnsure; OnEnsure = InArgs._OnEnsure;
FTextBlockStyle NormalText = FAppStyle::GetWidgetStyle<FTextBlockStyle>("NormalText"); FTextBlockStyle NormalText = FAppStyle::GetWidgetStyle<FTextBlockStyle>("NormalText");
NormalText.SetFontSize(20); NormalText.SetFontSize(18);
ChildSlot ChildSlot
[ [
SNew(SOverlay) SNew(SOverlay)
@ -38,7 +38,7 @@ void STips::Construct(const FArguments& InArgs)
[ [
SNew(SVerticalBox) SNew(SVerticalBox)
+ SVerticalBox::Slot() + SVerticalBox::Slot()
.Padding(0, 30, 0, 0) .Padding(0, 20, 0, 0)
.HAlign(HAlign_Center) .HAlign(HAlign_Center)
.VAlign(VAlign_Top) .VAlign(VAlign_Top)
[ [
@ -47,7 +47,7 @@ void STips::Construct(const FArguments& InArgs)
.TextStyle(&NormalText) .TextStyle(&NormalText)
] ]
+ SVerticalBox::Slot() + SVerticalBox::Slot()
.Padding(0, 16, 0, 0) .Padding(0, 5, 0, 0)
.HAlign(HAlign_Center) .HAlign(HAlign_Center)
.VAlign(VAlign_Top) .VAlign(VAlign_Top)
[ [
@ -109,7 +109,7 @@ void STips::Construct(const FArguments& InArgs)
[ [
SNew(STextBlock) SNew(STextBlock)
.Text(FText::FromString(TEXT("确定"))) .Text(FText::FromString(TEXT("确定")))
.ColorAndOpacity(FSlateColor(FLinearColor(1.0f, 1.0f, 1.0f, 1.0f))) .ColorAndOpacity(FSlateColor(FLinearColor(0.6f, 0.6f, 0.7f, 1.0f)))
] ]
] ]
] ]

View File

@ -964,7 +964,7 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
return; return;
FGlobalData::ExportPath = ExportPath / FGlobalData::CurrentProjectName; FGlobalData::ExportPath = ExportPath / FGlobalData::CurrentProjectName;
FPlatformFileManager::Get().GetPlatformFile().DeleteDirectoryRecursively(*ExportPath); FPlatformFileManager::Get().GetPlatformFile().DeleteDirectoryRecursively(*FGlobalData::ExportPath);
IDList.Empty(); IDList.Empty();
FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FGlobalData::ExportPath); FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FGlobalData::ExportPath);
@ -1874,23 +1874,25 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare
tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Parent, FEncodeVideoInfo EncodeVideoInfo) tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Parent, FEncodeVideoInfo EncodeVideoInfo)
{ {
FTrackData LeftTrackData;
FTrackData RightTrackData;
int32 TempSoundID = 0; int32 TempSoundID = 0;
for (FSingleTrackGroupInstance& SingleTrackGroupInstance : CutTimeline->TrackGroupInstances) for (FSingleTrackGroupInstance& SingleTrackGroupInstance : CutTimeline->TrackGroupInstances)
{ {
const TSharedPtr<STrackHead> TempTrackHead = StaticCastSharedPtr<STrackHead>(SingleTrackGroupInstance.Head); const TSharedPtr<STrackHead> TempTrackHead = StaticCastSharedPtr<STrackHead>(SingleTrackGroupInstance.Head);
if (TempTrackHead->TrackData.TrackType != ETrackType::AudioTrackR) if (TempTrackHead->TrackData.TrackType == ETrackType::AudioTrack)
LeftTrackData = TempTrackHead->TrackData;
if (TempTrackHead->TrackData.TrackType == ETrackType::AudioTrackR)
{ {
continue; if (GetTrackID(TempTrackHead->TrackData.DeviceTrack.Guid) != -1)
} {
if (GetTrackID(TempTrackHead->TrackData.DeviceTrack.Guid) != -1) TempSoundID = GetTrackID(TempTrackHead->TrackData.DeviceTrack.Guid);
{ }
TempSoundID = GetTrackID(TempTrackHead->TrackData.DeviceTrack.Guid); RightTrackData = TempTrackHead->TrackData;
} }
} }
tinyxml2::XMLElement* Sound = Parent->InsertNewChildElement("Sound"); tinyxml2::XMLElement* Sound = Parent->InsertNewChildElement("Sound");
{ {
Sound->InsertNewChildElement("RotationSpeakerID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(TempSoundID))); Sound->InsertNewChildElement("RotationSpeakerID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(TempSoundID)));
@ -1984,8 +1986,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoListElement(tinyxml2::XMLElement*
} }
} }
FString NewExportFilePath = FGlobalData::ExportPath / "Video" / Filename; FString NewExportFilePath = FGlobalData::ExportPath / "Video" / Filename;
GEngine->AddOnScreenDebugMessage(-1, 10.0F, FColor::White, NewExportFilePath); // GEngine->AddOnScreenDebugMessage(-1, 10.0F, FColor::White, NewExportFilePath);
TArray<FEncodeVideoInfo> EncodeVideoInfos = FUtils::TrackEncodeVideo(StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData, NewExportFilePath); TArray<FEncodeVideoInfo> EncodeVideoInfos =
FUtils::TrackEncodeVideo(StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData, NewExportFilePath);
for (const FEncodeVideoInfo EncodeVideoInfo : EncodeVideoInfos) for (const FEncodeVideoInfo EncodeVideoInfo : EncodeVideoInfos)
{ {
GetVideoElement(VideoList, EncodeVideoInfo); GetVideoElement(VideoList, EncodeVideoInfo);
@ -2005,69 +2008,76 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundListElement(tinyxml2::XMLElement*
tinyxml2::XMLElement* AudioList = Parent->InsertNewChildElement("SoundList"); tinyxml2::XMLElement* AudioList = Parent->InsertNewChildElement("SoundList");
{ {
int32 Count = 0; int32 Count = 0;
bool bGlobalAudio = false; FTrackData LeftTrackData;
for (int32 i = 0; i < CutTimeline->TrackGroupInstances.Num(); i++) FTrackData RightTrackData;
for (FSingleTrackGroupInstance& SingleTrackGroupInstance : CutTimeline->TrackGroupInstances)
{ {
const FTrackData& TrackData = StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData; const TSharedPtr<STrackHead> TempTrackHead = StaticCastSharedPtr<STrackHead>(SingleTrackGroupInstance.Head);
if (StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::AudioTrack || if (TempTrackHead->TrackData.TrackType == ETrackType::AudioTrack)
StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::AudioTrackR) LeftTrackData = TempTrackHead->TrackData;
if (TempTrackHead->TrackData.TrackType == ETrackType::AudioTrackR)
RightTrackData = TempTrackHead->TrackData;
}
TArray<FClipData> SavedClipData = LeftTrackData.ClipData;
if (SavedClipData.Num() > 0)
{
Sort(SavedClipData.GetData(), SavedClipData.Num(), [](const FClipData& ClipDataA, const FClipData& ClipDataB)
{ {
FString Filename = GetCurrentSelectFileName(); return ClipDataA.ClipStartFrame < ClipDataB.ClipStartFrame;
});
if (StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::AudioTrackR) if (SavedClipData[0].ClipStartFrame != 0 && SavedClipData[0].bIsVirtual == false)
{ {
Filename += TEXT("_R"); GetSoundElement(AudioList, {});
}
if (StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::AudioTrack)
{
Filename += TEXT("_L");
}
FString NewExportFilePath = FGlobalData::ExportPath / "Sound" / Filename;
bGlobalAudio = false;
FEncodeVideoInfo GlobalAudioEncodeVideoInfo = {};
for (const FEncodeVideoInfo& EncodeVideoInfo : AllGlobalSounds)
{
if (EncodeVideoInfo.ClipData.AudioCurtains.Contains(GetCurrentSelectCurtain()))
{
bGlobalAudio = true;
GlobalAudioEncodeVideoInfo = EncodeVideoInfo;
Count++;
};
}
if (bGlobalAudio == false)
{
TArray<FEncodeVideoInfo> EncodeVideoInfos = FUtils::TrackEncodeAudio(StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData, NewExportFilePath);
for (const FEncodeVideoInfo EncodeVideoInfo : EncodeVideoInfos)
{
if (EncodeVideoInfo.ClipData.AudioCurtains.Num() > 0)
{
AllGlobalSounds.Add(EncodeVideoInfo);
}
}
for (const FEncodeVideoInfo EncodeVideoInfo : EncodeVideoInfos)
{
GetSoundElement(AudioList, EncodeVideoInfo);
Count++;
}
}
else
{
GetSoundElement(AudioList, GlobalAudioEncodeVideoInfo);
}
} }
} }
if (Count == 0 && !bGlobalAudio) bool bIsVirtual = false;
for (FClipData& ClipData : LeftTrackData.ClipData)
{ {
GetSoundElement(AudioList, FEncodeVideoInfo()); if (ClipData.bIsVirtual)
{
bIsVirtual = true;
const FString VirtualFileName = FGlobalData::ExportPath / "Sound" / ClipData.VirtualCurtainName;
FEncodeVideoInfo EncodeVideoInfo;
EncodeVideoInfo.EncodedVideoName = VirtualFileName;
GetSoundElement(AudioList, EncodeVideoInfo);
}
} }
if (!bIsVirtual)
{
for (FClipData& ClipData : RightTrackData.ClipData)
{
if (ClipData.bIsVirtual)
{
bIsVirtual = true;
const FString VirtualFileName = FGlobalData::ExportPath / "Sound" / ClipData.VirtualCurtainName;
FEncodeVideoInfo EncodeVideoInfo;
EncodeVideoInfo.EncodedVideoName = VirtualFileName;
GetSoundElement(AudioList, EncodeVideoInfo);
}
}
}
if (!bIsVirtual)
{
const FString LeftFilename = GetCurrentSelectFileName() + TEXT("_L");
const FString RightFilename = GetCurrentSelectFileName() + TEXT("_R");
const FString LeftNewExportFilePath = FUtils::GetProjectTempPath() / "Sound" / LeftFilename;
const FString RightNewExportFilePath = FUtils::GetProjectTempPath() / "Sound" / RightFilename;
const FEncodeVideoInfo LeftEncodeVideoInfos = FUtils::TrackEncodeAudio(LeftTrackData, LeftNewExportFilePath);
const FEncodeVideoInfo RightEncodeVideoInfos = FUtils::TrackEncodeAudio(RightTrackData, RightNewExportFilePath);
const FString ExportFilename = FGlobalData::ExportPath / "Sound" / GetCurrentSelectFileName();
const FEncodeVideoInfo End = FUtils::CombineAudio(LeftEncodeVideoInfos, RightEncodeVideoInfos, ExportFilename);
GetSoundElement(AudioList, End);
}
} }
return nullptr; return nullptr;
} }
@ -2391,6 +2401,21 @@ FGuid SCutMainWindow::GetCurrentSelectCurtain() const
return FGuid(); return FGuid();
} }
FTimelineInfo SCutMainWindow::GetCurrentSelectCurtainTimelineInfo() const
{
for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups)
{
for (const FCurtain& Curtain : CurtainGroup.Curtains)
{
if (Curtain.bIsActive)
{
return Curtain.TimelineInfo;
}
}
}
return FTimelineInfo();
}
bool SCutMainWindow::IsSelectCurtain() const bool SCutMainWindow::IsSelectCurtain() const
{ {
for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups)
@ -2425,6 +2450,9 @@ void SCutMainWindow::DeselectAll()
} }
} }
} }
CurtainPanel->CallRender();
EffectCardsPanel->CallRender();
} }
int32 SCutMainWindow::GetTrackID(FGuid Guid) const int32 SCutMainWindow::GetTrackID(FGuid Guid) const

View File

@ -125,7 +125,10 @@ public:
tinyxml2::XMLElement* GetFlashLight(tinyxml2::XMLElement* Parent, const FClipData& ClipData); tinyxml2::XMLElement* GetFlashLight(tinyxml2::XMLElement* Parent, const FClipData& ClipData);
tinyxml2::XMLElement* GetGradientLight(tinyxml2::XMLElement* Parent, const FClipData& ClipData); tinyxml2::XMLElement* GetGradientLight(tinyxml2::XMLElement* Parent, const FClipData& ClipData);
FString GetCurrentSelectFileName() const; FString GetCurrentSelectFileName() const;
FGuid GetCurrentSelectCurtain() const; FGuid GetCurrentSelectCurtain() const;
FTimelineInfo GetCurrentSelectCurtainTimelineInfo() const;
bool IsSelectCurtain() const; bool IsSelectCurtain() const;
void DeselectAll(); void DeselectAll();

View File

@ -62,6 +62,7 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F
MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().AddVolumeHere); MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().AddVolumeHere);
} }
if (ClipData->ClipType != ETrackType::ProjectorTrack) if (ClipData->ClipType != ETrackType::ProjectorTrack)
{ {
if (ClipData->bIsCycle) if (ClipData->bIsCycle)
@ -84,6 +85,11 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F
return FReply::Handled(); return FReply::Handled();
} }
if (ClipData->bIsVirtual)
return FReply::Handled();
TSharedPtr<FClipProxy> ClipProxy = FClipProxy::GetProxy(); TSharedPtr<FClipProxy> ClipProxy = FClipProxy::GetProxy();
ClipProxy->UpdateInterface(SharedThis(this)); ClipProxy->UpdateInterface(SharedThis(this));
@ -645,6 +651,10 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
{ {
FSlateDrawElement::MakeText(OutDrawElements, LayerId + 9, AllottedGeometry.ToPaintGeometry(), FText::FromString(TEXT("循环播放")), FAppStyle::Get().GetWidgetStyle<FTextBlockStyle>("NormalText").Font, ESlateDrawEffect::None, FLinearColor::White); FSlateDrawElement::MakeText(OutDrawElements, LayerId + 9, AllottedGeometry.ToPaintGeometry(), FText::FromString(TEXT("循环播放")), FAppStyle::Get().GetWidgetStyle<FTextBlockStyle>("NormalText").Font, ESlateDrawEffect::None, FLinearColor::White);
} }
if (ClipData->bIsVirtual == true)
{
FSlateDrawElement::MakeText(OutDrawElements, LayerId + 9, AllottedGeometry.ToPaintGeometry(), FText::FromString(TEXT("虚拟轨道(不可编辑)")), FAppStyle::Get().GetWidgetStyle<FTextBlockStyle>("NormalText").Font, ESlateDrawEffect::None, FLinearColor::White);
}
if (MainWidgetInterface->GetCutTimeline()->SelectedClips.Contains(ClipData->ClipGuid)) if (MainWidgetInterface->GetCutTimeline()->SelectedClips.Contains(ClipData->ClipGuid))

View File

@ -0,0 +1,71 @@
#include "TimelineLoader.h"
FTimelineLoader::FTimelineLoader(const FString& LoadPath, bool bNeedSaveWhenExit)
{
this->bNeedSaveWhenExit = bNeedSaveWhenExit;
this->LoadPath = FPaths::ConvertRelativePathToFull(LoadPath);
TArray<uint8> LoadData;
const bool Response = FFileHelper::LoadFileToArray(LoadData, *this->LoadPath);
if (LoadData.Num() == 0 || !Response)
{
return;
}
FMemoryReader MemoryReader(LoadData, false);
MemoryReader << TimelineInfo;
int32 ClipCount = 0;
MemoryReader << ClipCount;
MemoryReader << ClipData;
}
FTimelineLoader::~FTimelineLoader()
{
if (bNeedSaveWhenExit)
{
TArray<uint8> SaveData;
FMemoryWriter MemoryWriter(SaveData, false);
int32 ClipCount = ClipData.Num();
MemoryWriter << TimelineInfo;
MemoryWriter << ClipCount;
MemoryWriter << ClipData;
FFileHelper::SaveArrayToFile(SaveData, *LoadPath);
}
}
TArray<FClipData> FTimelineLoader::GetSpecifyClipData(const FTrackData& TrackData) const
{
TArray<FClipData> ResultClipData;
for (const FClipData& Clip : ClipData)
{
if (Clip.BindTrackGuid == TrackData.DeviceTrack.Guid)
{
ResultClipData.Add(Clip);
}
}
return ResultClipData;
}
TArray<FClipData> FTimelineLoader::GetSpecifyClipData(const ETrackType TrackType) const
{
TArray<FClipData> ResultClipData;
for (const FClipData& Clip : ClipData)
{
if (Clip.ClipType == TrackType)
{
ResultClipData.Add(Clip);
}
}
return ResultClipData;
}
void FTimelineLoader::RemoveClipData(int32 Index)
{
ClipData.RemoveAt(Index);
}
void FTimelineLoader::RemoveClipData(const FClipData& RemoveClipData)
{
ClipData.Remove(RemoveClipData);
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "Cut5/Widgets/DefineGlobal.h"
class FTimelineLoader
{
private:
FString Version = "1.0.1";
bool bNeedSaveWhenExit = false;
FString LoadPath = "";
FTimelineInfo TimelineInfo;
TArray<FClipData> ClipData;
public:
explicit FTimelineLoader(const FString& LoadPath, bool bNeedSaveWhenExit = false);
~FTimelineLoader();
TArray<FClipData> GetSpecifyClipData(const FTrackData& TrackData) const;
TArray<FClipData> GetSpecifyClipData(const ETrackType TrackType) const;
TArray<FClipData>& GetClipData() { return ClipData; }
void RemoveClipData(int32 Index = 0);
void RemoveClipData(const FClipData& RemoveClipData);
FTimelineInfo& GetTimelineInfo() { return TimelineInfo; }
};

View File

@ -5,6 +5,8 @@
#include "Cut5/Widgets/SCutTimeline.h" #include "Cut5/Widgets/SCutTimeline.h"
#include "Cut5/Widgets/STimelineClip.h" #include "Cut5/Widgets/STimelineClip.h"
#include "Cut5/Widgets/MicroWidgets/SNewProjectTips.h" #include "Cut5/Widgets/MicroWidgets/SNewProjectTips.h"
#include "Cut5/Widgets/MicroWidgets/STips.h"
#include "Cut5/Widgets/SaveConverter/Timeline/TimelineLoader.h"
#include "Widgets/Input/SSpinBox.h" #include "Widgets/Input/SSpinBox.h"
#include "Widgets/Layout/SSpacer.h" #include "Widgets/Layout/SSpacer.h"
@ -331,15 +333,19 @@ TSharedPtr<SWidget> FClipProxy::GetPropertiesWidget()
]; ];
} }
if (ClipData->ClipType == ETrackType::AudioTrack || ClipData->ClipType == ETrackType::AudioTrackR) if ((ClipData->ClipType == ETrackType::AudioTrack || ClipData->ClipType == ETrackType::AudioTrackR) && MainInterface->GetSelf()->GetCurrentSelectCurtain() != FGuid())
{ {
AudiosCurtainOptions.Empty(); AudiosCurtainOptions.Empty();
TArray<FCurtainGroup>& Groups = MainInterface->GetSelf()->CurtainPanel->Groups; TArray<FCurtainGroup>& Groups = MainInterface->GetSelf()->CurtainPanel->Groups;
for (FCurtainGroup& Group : Groups) for (FCurtainGroup& Group : Groups)
{ {
for (FCurtain& Curtain : Group.Curtains) for (FCurtain& Curtain : Group.Curtains)
{ {
AudiosCurtainOptions.Add(MakeShared<FStringWithGUID>(Curtain.CurtainName, Curtain.CurtainUUID)); if (Curtain.CurtainUUID != MainInterface->GetSelf()->GetCurrentSelectCurtain())
{
AudiosCurtainOptions.Add(MakeShared<FStringWithGUID>(Curtain.CurtainName, Curtain.CurtainUUID));
}
} }
} }
@ -387,18 +393,84 @@ TSharedPtr<SWidget> FClipProxy::GetPropertiesWidget()
.IsChecked(ClipData->AudioCurtains.Contains(*InItem.Get()) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked) .IsChecked(ClipData->AudioCurtains.Contains(*InItem.Get()) ? ECheckBoxState::Checked : ECheckBoxState::Unchecked)
.OnCheckStateChanged_Lambda([this, InItem](const ECheckBoxState& State) .OnCheckStateChanged_Lambda([this, InItem](const ECheckBoxState& State)
{ {
if (State == ECheckBoxState::Checked) const FGuid& Guid = InItem.Get()->Guid;
FCurtainGroup* Group = nullptr;
const FString CurrentPath = MainInterface->GetSelf()->CurtainPanel->FindCurtain(Guid,Group)->TimelineInfo.CurrentOpenFullPath;
FTimelineLoader TimelineLoader(CurrentPath, true);
if (TimelineLoader.GetSpecifyClipData(ClipData->ClipType).Num() > 0 && State == ECheckBoxState::Checked)
{ {
ClipData->AudioCurtains.Add(*InItem.Get()); FUtils::AddTips(
MainInterface->UpdateProperties(this); SNew(STips)
.Title(TEXT("警告"))
.SubTitle(TEXT("选中的幕中的音频轨道已经存在音频片段\n如果继续添加,将会覆盖原有的音频片段\n是否继续?"))
.OnEnsure_Lambda([this, State, InItem, CurrentPath](const FString& String)
{
// 先清空
FTimelineLoader ModifyTimelineLoader(CurrentPath, true);
TArray<FClipData> Clips = ModifyTimelineLoader.GetSpecifyClipData(ClipData->ClipType);
for (int32 i = Clips.Num() - 1; i >= 0; i--)
{
ModifyTimelineLoader.RemoveClipData(Clips[i]);
}
FClipData NewClip = *ClipData;
NewClip.Move(0);
NewClip.bIsVirtual = true;
NewClip.VirtualCurtainName = MainInterface->GetSelf()->GetCurrentSelectFileName();
NewClip.ClipGuid = FGuid::NewGuid();
ModifyTimelineLoader.GetClipData().Add(NewClip);
if (State == ECheckBoxState::Checked)
{
ClipData->AudioCurtains.Add(*InItem.Get());
MainInterface->UpdateProperties(this);
}
else
{
ClipData->AudioCurtains.Remove(*InItem.Get());
MainInterface->UpdateProperties(this);
}
})
);
} }
else else
{ {
ClipData->AudioCurtains.Remove(*InItem.Get()); if (State == ECheckBoxState::Checked)
MainInterface->UpdateProperties(this); {
FClipData NewClip = *ClipData;
NewClip.Move(0);
NewClip.bIsVirtual = true;
NewClip.VirtualCurtainName = MainInterface->GetSelf()->GetCurrentSelectFileName();
NewClip.ClipGuid = FGuid::NewGuid();
TimelineLoader.GetClipData().Add(NewClip);
ClipData->AudioCurtains.Add(*InItem.Get());
MainInterface->UpdateProperties(this);
}
else
{
if (TimelineLoader.GetSpecifyClipData(ClipData->ClipType).Num() > 0)
{
TArray<FClipData> Clips = TimelineLoader.GetSpecifyClipData(ClipData->ClipType);
for (int32 i = Clips.Num() - 1; i >= 0; i--)
{
TimelineLoader.RemoveClipData(Clips[i]);
}
}
ClipData->AudioCurtains.Remove(*InItem.Get());
MainInterface->UpdateProperties(this);
}
} }
}) })
]; ];

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB