diff --git a/Plugins/FFMPEGMedia-master/Source/FFMPEGMedia/Private/FFMPEGMediaModule.cpp b/Plugins/FFMPEGMedia-master/Source/FFMPEGMedia/Private/FFMPEGMediaModule.cpp index c94ff3f..437508f 100644 --- a/Plugins/FFMPEGMedia-master/Source/FFMPEGMedia/Private/FFMPEGMediaModule.cpp +++ b/Plugins/FFMPEGMedia-master/Source/FFMPEGMedia/Private/FFMPEGMediaModule.cpp @@ -175,9 +175,9 @@ public: #endif avformat_network_init(); - av_log_set_level(AV_LOG_INFO); + // av_log_set_level(AV_LOG_INFO); - av_log_set_callback(&log_callback); + // av_log_set_callback(&log_callback); UE_LOG(LogFFMPEGMedia, Display, TEXT("FFmpeg AVCodec version: %d.%d.%d"), LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO); UE_LOG(LogFFMPEGMedia, Display, TEXT("FFmpeg license: %s"), UTF8_TO_TCHAR(avformat_license())); diff --git a/Source/Cut5/Utils/FFMPEGUtils.cpp b/Source/Cut5/Utils/FFMPEGUtils.cpp index 3ac27c4..30e1841 100644 --- a/Source/Cut5/Utils/FFMPEGUtils.cpp +++ b/Source/Cut5/Utils/FFMPEGUtils.cpp @@ -255,6 +255,14 @@ FString FFFMPEGUtils::LoadContextPure(const FString& Path, FTimelinePropertyData return {}; } +FString FFFMPEGUtils::UnLoadContext(FTimelinePropertyData* PropertyData) +{ + avcodec_free_context(&PropertyData->VideoCodecContext); + avcodec_free_context(&PropertyData->AudioCodecContext); + avformat_close_input(&PropertyData->Context); + return {}; +} + FString FFFMPEGUtils::ConvertMediaGoPto1(const FString& Path) { AVFormatContext* FormatContext = nullptr; diff --git a/Source/Cut5/Utils/FFMPEGUtils.h b/Source/Cut5/Utils/FFMPEGUtils.h index 47c5018..1e63850 100644 --- a/Source/Cut5/Utils/FFMPEGUtils.h +++ b/Source/Cut5/Utils/FFMPEGUtils.h @@ -15,6 +15,7 @@ struct FFFMPEGUtils */ static FString LoadMedia(const FString& Path, FTimelinePropertyData* PropertyData); static FString LoadContextPure(const FString& Path, FTimelinePropertyData* PropertyData); + static FString UnLoadContext(FTimelinePropertyData* PropertyData); static FString ConvertMediaGoPto1(const FString& Path); static bool ExportImage(UTexture2D* Texture2D, const FString& Path); static TArray> GetVideoFrameLightArray(FString VideoPath, int32 X, int32 Y); diff --git a/Source/Cut5/Utils/Utils.cpp b/Source/Cut5/Utils/Utils.cpp index 6c8b131..defaaa2 100644 --- a/Source/Cut5/Utils/Utils.cpp +++ b/Source/Cut5/Utils/Utils.cpp @@ -1,6 +1,8 @@ #include "Utils.h" +#include "FFMPEGUtils.h" +#include "FFMPEGUtils.h" #include "Cut5/Widgets/DefineGlobal.h" #include "Kismet/KismetStringLibrary.h" @@ -322,7 +324,7 @@ TArray FUtils::TrackEncodeVideo(const FTrackData& TrackData, c FString InputFile = "\"" + TempClipData.ResourcePropertyDataPtr->MoviePath + "\""; - FString OutputFile = "\"" + FPaths::ConvertRelativePathToFull(ExportPath / FPaths::GetBaseFilename(TempClipData.MoviePath, true) + FString::FromInt(i) + TEXT(".mp4")) + "\""; + FString OutputFile = "\"" + FPaths::ConvertRelativePathToFull(ExportPath + FString::FromInt(i) + TEXT(".mp4")) + "\""; GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FString::Printf(TEXT("OutputFile %s"), *OutputFile)); int32 StartFrame = (TempClipData.VideoStartFrame) % static_cast(FGlobalData::GlobalFPS);; int32 EndFrame = (TempClipData.VideoEndFrame) % static_cast(FGlobalData::GlobalFPS); @@ -334,7 +336,7 @@ TArray FUtils::TrackEncodeVideo(const FTrackData& TrackData, c FPlatformProcess::CreateProc(*GetFfmepg(), *Command, true, false, false, nullptr, 0, nullptr, nullptr); EncodeVideoInfo.EncodedVideoTimeCode = FGlobalData::GetTimeData(TempClipData.ClipStartFrame); - EncodeVideoInfo.EncodedVideoName = ExportPath / FPaths::GetBaseFilename(TempClipData.MoviePath, true) + FString::FromInt(i) + TEXT(".mp4"); + EncodeVideoInfo.EncodedVideoName = ExportPath + FString::FromInt(i) + TEXT(".mp4"); EncodeVideoInfo.ClipStartFrame = TempClipData.ClipStartFrame; EncodeVideoInfo.ClipEndFrame = TempClipData.ClipEndFrame; @@ -390,7 +392,7 @@ TArray FUtils::TrackEncodeAudio(const FTrackData& TrackData, c int32 StartFrame = (TempClipData.VideoStartFrame) % static_cast(FGlobalData::GlobalFPS);; int32 EndFrame = (TempClipData.VideoEndFrame) % static_cast(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 -c copy \"%s\""), *InputFile, *StartTime, *EndTime, *OutputFile); FPlatformProcess::CreateProc(*GetFfmepg(), *Command, true, false, false, nullptr, 0, nullptr, nullptr); @@ -427,240 +429,153 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& FString ExportName = FGuid::NewGuid().ToString();; if (TempClipData.ResourcePropertyDataPtr) { - TempClipData.ResourcePropertyDataPtr->MoviePath; - FString TempPath = TempClipData.ResourcePropertyDataPtr->MoviePath; - frames.Empty(); - - VideoCapture capture; - bool ret = capture.open(TCHAR_TO_UTF8(*TempPath)); - - - //setNumThreads(2); - - std::ofstream outfile; - - FString leftStr; - FString rightStr; - - FString SourceLeft; - FString SourceRight; - UKismetStringLibrary::Split(TempPath,".",SourceLeft, SourceRight, ESearchCase::IgnoreCase,ESearchDir::FromEnd); - UKismetStringLibrary::Split(SourceLeft,"/",SourceLeft, SourceRight, ESearchCase::IgnoreCase,ESearchDir::FromEnd); - - - - - FString psafPath = ExportPath / ExportName + FString::FromInt(i) + ".psaf"; - - FString psafPath2 = leftStr + ".psaf2"; - - //outfile.open(TCHAR_TO_UTF8(*leftStr), ios::binary); - outfile.open(*psafPath, std::ios::binary); - UE_LOG(LogTemp, Log, TEXT("open flie -> %s "), *leftStr); - - uint8 width = capture.get(CAP_PROP_FRAME_WIDTH); - uint8 height = capture.get(CAP_PROP_FRAME_HEIGHT); - Size frameSize = Size(width,height ); - - uint8 fps = capture.get(CAP_PROP_FPS); - - float duration = capture.get(CV_CAP_PROP_FRAME_COUNT) / capture.get(CV_CAP_PROP_FPS); - - Size old_size = frameSize; + FTimelinePropertyData PropertyData; + FFFMPEGUtils::LoadContextPure(TempClipData.ResourcePropertyDataPtr->MoviePath, &PropertyData); + const FString PsafSavePath = ExportPath + FString::FromInt(i) + ".psaf"; - capture.set(CAP_PROP_POS_FRAMES, TempClipData.ClipStartFrame); - int32 frameCount = capture.get(CV_CAP_PROP_FRAME_COUNT); - frameCount -= ClipData[i].ClipStartFrame; - UE_LOG(LogTemp, Log, TEXT("frameCount: %s"), *FString::FromInt(frameCount)); - - char p[128] = "pasf"; - outfile.write(reinterpret_cast(p), sizeof(p)); -#if 1 + int32 TimeStamp = av_rescale_q(static_cast(TempClipData.VideoStartFrame) / FGlobalData::GlobalFPS * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, PropertyData.Context->streams[PropertyData.VideoStream]->time_base); + int32 EndTimeStamp = av_rescale_q(static_cast(TempClipData.VideoEndFrame) / FGlobalData::GlobalFPS * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, PropertyData.Context->streams[PropertyData.VideoStream]->time_base); + av_seek_frame(PropertyData.Context, PropertyData.VideoStream, TimeStamp, AVSEEK_FLAG_BACKWARD); - Mat frameOrg; - Mat frame; - int frameIndex = 0; - - while (ret && frameIndex < frameCount) { - - if (frameIndex % 2 == 0) { - capture.grab(); - frameIndex++; - continue; + + TArray LightArrayResult; + uint8 Width = FGlobalData::LightArrayX; + uint8 Height = FGlobalData::LightArrayY; + uint8 p[128] = "pasf"; + LightArrayResult.Append(p, 128); + + + AVPacket* Packet = av_packet_alloc(); + AVFrame* Frame = av_frame_alloc(); + while (av_read_frame(PropertyData.Context, Packet) >= 0) + { + avcodec_send_packet(PropertyData.VideoCodecContext, Packet); + int32 Response = avcodec_receive_frame(PropertyData.VideoCodecContext, Frame); + if (Response == AVERROR(EAGAIN) || AVERROR_EOF) + { + } - - /* */ - tempIndex = frameIndex; - - if (capture.read(frameOrg)) { - - if (!capture.isOpened()) + if (Frame->best_effort_timestamp >= EndTimeStamp) + { + break; + } + if (Frame->best_effort_timestamp >= TimeStamp) + { + + + SwsContext* FormatContext = sws_getContext( + Frame->width, + Frame->height, + PropertyData.VideoCodecContext->pix_fmt, + FGlobalData::LightArrayX, + FGlobalData::LightArrayY, + AVPixelFormat::AV_PIX_FMT_RGB24, + SWS_BILINEAR, + nullptr, + nullptr, + nullptr + ); + + + + + uint8* RawData = static_cast(FMemory::Malloc(FGlobalData::LightArrayX * FGlobalData::LightArrayY * 3)); + uint8* Dest[4] = {RawData, nullptr, nullptr ,nullptr}; + const int32 DestLineSize[4] = {FGlobalData::LightArrayX * 3, 0, 0, 0}; + sws_scale(FormatContext, Frame->data, Frame->linesize, 0, Frame->height, Dest, DestLineSize); + sws_freeContext(FormatContext); + + + LightArrayResult.Add(static_cast(FGlobalData::GlobalFPS)); + LightArrayResult.Add(blockNum); + LightArrayResult.Add(Height); + LightArrayResult.Add(Width); + LightArrayResult.Add(0); + LightArrayResult.Add(0); + LightArrayResult.Add(0); + LightArrayResult.Add(0); + int32 Length = TempClipData.VideoEndFrame - TempClipData.VideoStartFrame; + LightArrayResult.Append(reinterpret_cast(&Length), sizeof(int32)); + + + for (int32 CurrentHeight = Height / 3 - 1; CurrentHeight >= 0; CurrentHeight--) { - UE_LOG(LogTemp, Log, TEXT("cant open video -> %s"), *TempPath); - i++; - continue;; - } - - if (frameOrg.empty()) - { - UE_LOG(LogTemp, Log, TEXT("no frame")); - i++; - continue;; - } - - UE_LOG(LogTemp, Log, TEXT("frameOrg size - > (%s, %s),frameOrg type -> %s "), - *FString::FromInt(frameOrg.rows),*FString::FromInt(frameOrg.cols), *FString::FromInt(frameOrg.type())); - - resize(frameOrg, frameOrg, Size(70, 42), 0, 0, INTER_LINEAR); - frameOrg.copyTo(frame); - - if (frame.empty()) { - UE_LOG(LogTemp, Log, TEXT(" read none ")); - return EncodeVideoInfos; - } - - /* 每帧标头 */ - outfile.write(reinterpret_cast(&fps), sizeof(uint8)); - outfile.write(reinterpret_cast(&blockNum), sizeof(uint8)); - outfile.write(reinterpret_cast(&height), sizeof(uint8)); - outfile.write(reinterpret_cast(&width), sizeof(uint8)); - outfile.write(reinterpret_cast("00"), sizeof(float)); - outfile.write(reinterpret_cast(&duration), sizeof(float)); - - for (int32 row = frame.rows / 3 - 1; row >= 0; row--) { - if (row % interval == 0) { - - for (int32 col = frame.cols - 1; col >= 0; col--) { - - frame.at(row, col) = frameOrg.at(row, col); - - //outfile.write(reinterpret_cast(&frame.at(row, col)), sizeof(uint8) * 3); - outfile.write(reinterpret_cast(&frame.at(row, col)[2]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[1]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[0]), sizeof(uint8)); - - //UE_LOG(LogTemp, Log, TEXT("row -> %s ,col - > %s "), - // *FString::FromInt(row), *FString::FromInt(col)); + if (CurrentHeight % 2 == 0) + { + for (int32 CurrentWidth = Width - 1; CurrentWidth >= 0; CurrentWidth--) + { + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 0]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 1]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 2]); } - } - else { - for (int32 col = 0; col < frame.cols; col++) { - - frame.at(row, col) = frameOrg.at(row, col); - - - outfile.write(reinterpret_cast(&frame.at(row, col)[2]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[1]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[0]), sizeof(uint8)); - + else + { + for (int32 CurrentWidth = 0; CurrentWidth < Width; CurrentWidth++) + { + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 0]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 1]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 2]); } - } - } - - for (int32 row = frame.rows/3; row < 2 * frame.rows / 3 ; row++) { - if (row % interval == 0) { - - for (int32 col = 0; col < frame.cols; col++) { - frame.at(row, col) = frameOrg.at(row, col); - - outfile.write(reinterpret_cast(&frame.at(row, col)[2]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[1]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[0]), sizeof(uint8)); - - + + for (int32 CurrentHeight = Height / 3; CurrentHeight < 2 * Height / 3 ; CurrentHeight++) { + if (CurrentHeight % 2 == 0) + { + for (int32 CurrentWidth = 0; CurrentWidth < Width; CurrentWidth++) + { + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 0]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 1]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 2]); } - } - else { - - for (int32 col = frame.cols - 1; col >= 0; col--) { - - frame.at(row, col) = frameOrg.at(row, col); - - outfile.write(reinterpret_cast(&frame.at(row, col)[2]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[1]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[0]), sizeof(uint8)); - - + else + { + for (int32 CurrentWidth = Width - 1; CurrentWidth >= 0; CurrentWidth--) + { + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 0]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 1]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 2]); } } } - for (int32 row = 2 * frame.rows/3; row < frame.rows ; row++) { - if (row % interval == 0) { - for (int32 col = 0; col < frame.cols ; col++) { - - frame.at(row, col) = frameOrg.at(row, col); - - outfile.write(reinterpret_cast(&frame.at(row, col)[2]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[1]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[0]), sizeof(uint8)); - - + for (int32 CurrentHeight = 2 * Height / 3; CurrentHeight < Height; CurrentHeight++) { + if (CurrentHeight % 2 == 0) + { + for (int32 CurrentWidth = 0; CurrentWidth < Width; CurrentWidth++) + { + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 0]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 1]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 2]); } - } else { - for (int32 col = frame.cols - 1; col >= 0 ; col--) { - - frame.at(row, col) = frameOrg.at(row, col); - - outfile.write(reinterpret_cast(&frame.at(row, col)[2]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[1]), sizeof(uint8)); - outfile.write(reinterpret_cast(&frame.at(row, col)[0]), sizeof(uint8)); - - + for (int32 CurrentWidth = Width - 1; CurrentWidth >= 0; CurrentWidth--) + { + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 0]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 1]); + LightArrayResult.Add(RawData[CurrentHeight * FGlobalData::LightArrayX + CurrentWidth + 2]); } } } - - -#if EXPORT_PROCESSED_VIDEO - writer.write(frame); -#endif - //frames.Add(MatToTexture2D(frame, width, height, true)); - - frameIndex++; - //UE_LOG(LogTemp, Log, TEXT(" write frame,frameSize( %s, %s )"), *FString::FromInt(frame.rows), *FString::FromInt(frame.cols)); - - } - else - { - frameIndex++; } } + int32 RemainData = 1024 - LightArrayResult.Num() % 1024; + LightArrayResult.AddZeroed(RemainData); + FFileHelper::SaveArrayToFile(LightArrayResult, *PsafSavePath); + FEncodeVideoInfo EncodeVideoInfo; + EncodeVideoInfo.EncodedVideoName = ExportName + FString::FromInt(i) + ".psaf"; + EncodeVideoInfo.EncodedVideoTimeCode = FGlobalData::GetTimeData(TempClipData.ClipStartFrame); + EncodeVideoInfos.Add(EncodeVideoInfo); -#endif - outfile.seekp(0, outfile.end); - size_t fileSize = outfile.tellp(); - UE_LOG(LogTemp, Log, TEXT("fileSize1 -> %s"), *FString::FromInt(fileSize)); - - int32 remains = 1024 - fileSize % (1024); - outfile.write(reinterpret_cast("0x00"), sizeof(uint8)* remains); - fileSize = outfile.tellp(); - UE_LOG(LogTemp, Log, TEXT("fileSize2 -> %s"), *FString::FromInt(fileSize)); - - capture.release(); - -#if EXPORT_PROCESSED_VIDEO - writer.release(); -#endif - outfile.close(); - - UE_LOG(LogTemp, Log, TEXT("proecess completed , video close")); + FFFMPEGUtils::UnLoadContext(&PropertyData); + av_packet_free(&Packet); + av_frame_free(&Frame); } - FEncodeVideoInfo EncodeVideoInfo; - EncodeVideoInfo.EncodedVideoName = ExportName + FString::FromInt(i) + ".psaf"; - EncodeVideoInfo.EncodedVideoTimeCode = FGlobalData::GetTimeData(TempClipData.ClipStartFrame); - - EncodeVideoInfo.TrackData = TrackData; - EncodeVideoInfo.ClipData = TempClipData; - EncodeVideoInfos.Add(EncodeVideoInfo); i++; } return EncodeVideoInfos; diff --git a/Source/Cut5/Widgets/Commands/CursorCommands.cpp b/Source/Cut5/Widgets/Commands/CursorCommands.cpp new file mode 100644 index 0000000..0dda655 --- /dev/null +++ b/Source/Cut5/Widgets/Commands/CursorCommands.cpp @@ -0,0 +1,9 @@ +#include "CursorCommands.h" + +#define LOCTEXT_NAMESPACE "FCursorCommands" +void FCursorCommands::RegisterCommands() +{ + UI_COMMAND(OpenColorPanel, "打开颜色面板", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(Remove, "移除", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); +} +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/Cut5/Widgets/Commands/CursorCommands.h b/Source/Cut5/Widgets/Commands/CursorCommands.h new file mode 100644 index 0000000..3b059e1 --- /dev/null +++ b/Source/Cut5/Widgets/Commands/CursorCommands.h @@ -0,0 +1,23 @@ + + +#pragma once +#include "CoreMinimal.h" +#include "Framework/Commands/Commands.h" + +class FCursorCommands : public TCommands +{ +public: + + FCursorCommands() + : TCommands(TEXT("FCursorCommands"), NSLOCTEXT("Contexts", "FTimelineClipCommands", "FTimelineClipCommands"), NAME_None, FAppStyle::GetAppStyleSetName()) + { + // 这里可以设置你的命令的默认键盘快捷键 + } + + // TCommands<> 接口 + virtual void RegisterCommands() override; + + TSharedPtr OpenColorPanel; + TSharedPtr Remove; + +}; \ No newline at end of file diff --git a/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp b/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp index 5b32339..e46cdd3 100644 --- a/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp +++ b/Source/Cut5/Widgets/Commands/TimelineClipCommands.cpp @@ -9,5 +9,6 @@ void FTimelineClipCommands::RegisterCommands() UI_COMMAND(Fill2End, "填充到结尾", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(Cycle, "循环", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(CancelCycle, "取消循环", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(AddCursorHere, "在此处添加渐变点", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord()); } #undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Source/Cut5/Widgets/Commands/TimelineClipCommands.h b/Source/Cut5/Widgets/Commands/TimelineClipCommands.h index be032a7..15388a7 100644 --- a/Source/Cut5/Widgets/Commands/TimelineClipCommands.h +++ b/Source/Cut5/Widgets/Commands/TimelineClipCommands.h @@ -23,4 +23,5 @@ public: TSharedPtr Fill2End; TSharedPtr CancelCycle; TSharedPtr Cycle; + TSharedPtr AddCursorHere; }; \ No newline at end of file diff --git a/Source/Cut5/Widgets/DefineGlobal.h b/Source/Cut5/Widgets/DefineGlobal.h index e53dfcc..7cb28b9 100644 --- a/Source/Cut5/Widgets/DefineGlobal.h +++ b/Source/Cut5/Widgets/DefineGlobal.h @@ -292,7 +292,7 @@ struct CUT5_API FVolumeData } }; -struct CUT5_API FClipData +struct CUT5_API FClipData : public TSharedFromThis { FClipData() { @@ -384,7 +384,7 @@ struct CUT5_API FClipData if (CropMethod == ECropMethod::FromFront) { ClipStartFrame += CropFrame; - if (ClipType == ETrackType::VideoTrack || ClipType == ETrackType::AudioTrack) + if (ClipType == ETrackType::VideoTrack || ClipType == ETrackType::AudioTrack || ClipType == ETrackType::LightArrayTrack || ClipType == ETrackType::LightBarTrack) { VideoStartFrame += CropFrame; } @@ -392,7 +392,7 @@ struct CUT5_API FClipData else { ClipEndFrame -= CropFrame; - if (ClipType == ETrackType::VideoTrack || ClipType == ETrackType::AudioTrack) + if (ClipType == ETrackType::VideoTrack || ClipType == ETrackType::AudioTrack || ClipType == ETrackType::LightArrayTrack || ClipType == ETrackType::LightBarTrack) { VideoEndFrame -= CropFrame; } diff --git a/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp b/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp index 632ed77..fbb895b 100644 --- a/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp +++ b/Source/Cut5/Widgets/DragDropOperator/DragDropOperator.cpp @@ -106,7 +106,7 @@ void DragDropOperator::UpdateClipProcess(ICutMainWidgetInterface* MainInterface, TimelineClip.UpdateGradientCursor(); } - FGlobalData::TrackLength = MaxLength + 30; + FGlobalData::TrackLength = MaxLength + (MaxLength * 0.2); MainInterface->GetCutTimeline()->UpdateTimelineLength(); return; } diff --git a/Source/Cut5/Widgets/Presets/SClipCursor.cpp b/Source/Cut5/Widgets/Presets/SClipCursor.cpp index fc456a0..8c12c81 100644 --- a/Source/Cut5/Widgets/Presets/SClipCursor.cpp +++ b/Source/Cut5/Widgets/Presets/SClipCursor.cpp @@ -7,6 +7,7 @@ // #include "AppFramework/Public/Widgets/Colors/SColorPicker.h" #include "Cut5/Utils/Utils.h" #include "Cut5/Widgets/STimelineClip.h" +#include "Cut5/Widgets/Commands/CursorCommands.h" BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION @@ -36,19 +37,43 @@ void SClipCursor::Construct(const FArguments& InArgs) } else if (MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton)) { - for (int32 i = 0; i < ClipData->PresetsCustomData.Cursors.Num(); i++) - { - if (ClipData->PresetsCustomData.Cursors[i] == *CursorData) - { - TimelineClip->MainWidgetInterface->OpenColorPanel(&ClipData->PresetsCustomData.Cursors[i].Color); - } - } + FMenuBuilder MenuBuilder(true, CommandList); + MenuBuilder.AddMenuEntry(FCursorCommands::Get().OpenColorPanel); + MenuBuilder.AddMenuEntry(FCursorCommands::Get().Remove); + FSlateApplication::Get().PushMenu(AsShared(), FWidgetPath(), MenuBuilder.MakeWidget(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect::ContextMenu); } return FReply::Handled(); }) ] ]; + FCursorCommands::Register(); + CommandList = MakeShared(); + CommandList->MapAction(FCursorCommands::Get().OpenColorPanel, FExecuteAction::CreateLambda([this]() + { + for (int32 i = 0; i < ClipData->PresetsCustomData.Cursors.Num(); i++) + { + if (ClipData->PresetsCustomData.Cursors[i] == *CursorData) + { + TimelineClip->MainWidgetInterface->OpenColorPanel(&ClipData->PresetsCustomData.Cursors[i].Color); + } + } + })); + CommandList->MapAction(FCursorCommands::Get().Remove, FExecuteAction::CreateLambda([this]() + { + if (ClipData->PresetsCustomData.Cursors.Num() < 3) + return; + for (int32 i = ClipData->PresetsCustomData.Cursors.Num() - 1; i > 0; i--) + { + if (ClipData->PresetsCustomData.Cursors[i] == *CursorData) + { + ClipData->PresetsCustomData.Cursors.RemoveAt(i); + break; + + } + } + })); + } void SClipCursor::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) @@ -60,13 +85,7 @@ FReply SClipCursor::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointe { if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton)) { - for (int32 i = 0; i < ClipData->PresetsCustomData.Cursors.Num(); i++) - { - if (ClipData->PresetsCustomData.Cursors[i] == *CursorData) - { - TimelineClip->MainWidgetInterface->OpenColorPanel(&ClipData->PresetsCustomData.Cursors[i].Color); - } - } + } return FReply::Handled(); } diff --git a/Source/Cut5/Widgets/Presets/SClipCursor.h b/Source/Cut5/Widgets/Presets/SClipCursor.h index 9a2c6f8..65e69af 100644 --- a/Source/Cut5/Widgets/Presets/SClipCursor.h +++ b/Source/Cut5/Widgets/Presets/SClipCursor.h @@ -27,4 +27,5 @@ public: FClipData* ClipData; class STimelineClip* TimelineClip; virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; + TSharedPtr CommandList; }; diff --git a/Source/Cut5/Widgets/SCutMainWindow.cpp b/Source/Cut5/Widgets/SCutMainWindow.cpp index 0bd8b85..ca29bcf 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.cpp +++ b/Source/Cut5/Widgets/SCutMainWindow.cpp @@ -28,6 +28,7 @@ #include "MicroWidgets/SColorPanel.h" #include "MicroWidgets/SNewProjectTips.h" #include "StatePanel/SStatePanel.h" +#include "TimelineClips/ClipProxy.h" #include "Widgets/Layout/SConstraintCanvas.h" #include "Widgets/Layout/SScaleBox.h" #include "Widgets/Layout/SSpacer.h" @@ -695,7 +696,7 @@ void SCutMainWindow::CloseAllThreads() for (int32 j = 0; j < Guids.Num(); j++) { Threads[Guids[j]]->Stop(); - delete Threads[Guids[j]]; + // delete Threads[Guids[j]]; Threads.Remove(Guids[j]); } } @@ -959,10 +960,13 @@ void SCutMainWindow::OpenProject(const FString& Project) void SCutMainWindow::ExportProject(const FString& ExportPath) { - + if (ExportPath.IsEmpty()) return; FGlobalData::ExportPath = ExportPath / FGlobalData::CurrentProjectName; + + FPlatformFileManager::Get().GetPlatformFile().DeleteDirectoryRecursively(*ExportPath); + IDList.Empty(); FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FGlobalData::ExportPath); FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*(FGlobalData::ExportPath / "Video")); @@ -1068,7 +1072,7 @@ void SCutMainWindow::ExportProject(const FString& ExportPath) { break; } - tinyxml2::XMLElement* LightArray = LightArrayList->InsertNewChildElement("GuangZhen"); + tinyxml2::XMLElement* LightArray = LightArrayList->InsertNewChildElement("GuangZhen2"); LightArray->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(DeviceID))); LightArray->InsertNewChildElement("Name")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName)); DeviceID++; @@ -1540,14 +1544,8 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par } if (TempClipData.PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Flash) { - tinyxml2::XMLElement* NewSpeicalEffect = SpeicalEffect->InsertNewChildElement("Special_Effect"); - NewSpeicalEffect->InsertNewChildElement("Mode")->InsertNewText("0"); - NewSpeicalEffect->InsertNewChildElement("InitialColor")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(TempClipData.PresetsCustomData.Colors[0].ToFColor(false))))); - NewSpeicalEffect->InsertNewChildElement("EndColor")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(TempClipData.PresetsCustomData.Colors[0].ToFColor(false))))); - float PerLength = (TempClipData.PresetsCustomData.Time / TempClipData.PresetsCustomData.Times) / 2; - NewSpeicalEffect->InsertNewChildElement("TimeLength")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%d"), int32(PerLength * 1000)))); - NewSpeicalEffect->InsertNewChildElement("TimeCode")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::GetMsFromString(FGlobalData::GetTimeData(TempClipData.ClipStartFrame))))); - NewSpeicalEffect->InsertNewChildElement("Cycle")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%d"), TempClipData.PresetsCustomData.Times))); + tinyxml2::XMLElement* NewSpeicalEffect = SpeicalEffect->InsertNewChildElement("Special_Effect"); + GetFlashLight(NewSpeicalEffect, TempClipData); } if (TempClipData.PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Gradient) { @@ -1582,6 +1580,10 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par const FTrackData& TrackData = StaticCastSharedPtr(CutTimeline->TrackGroupInstances[k].Head)->TrackData; if (TrackData.TrackType == ETrackType::LightArrayTrack || TrackData.TrackType == ETrackType::LightBarTrack) { + if (GetTrackID(TrackData.DeviceTrack.Guid) == -1) + { + continue; + } auto GuangZhen = GuangZhenList->InsertNewChildElement("GuangZhen"); GuangZhen->SetAttribute("ID", TCHAR_TO_UTF8(*FString::FromInt(GetTrackID(TrackData.DeviceTrack.Guid)))); @@ -1591,7 +1593,18 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par { if (StaticCastSharedPtr(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::LightArrayTrack) { - TArray EncodeVideoInfos = FUtils::ExportPsaf(StaticCastSharedPtr(CutTimeline->TrackGroupInstances[i].Head)->TrackData, *(FGlobalData::ExportPath / "PSAF")); + FString Filename; + for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) + { + for (const FCurtain& Curtain : CurtainGroup.Curtains) + { + if (Curtain.bIsActive) + { + Filename = Curtain.CurtainName; + } + } + } + TArray EncodeVideoInfos = FUtils::ExportPsaf(StaticCastSharedPtr(CutTimeline->TrackGroupInstances[i].Head)->TrackData, *(FGlobalData::ExportPath / "PSAF" / Filename)); for (int32 j = 0; j < EncodeVideoInfos.Num(); j++) { auto SpeicalEffect = GuangZhenSpecialEffectList->InsertNewChildElement("SpecialEffect"); @@ -1606,7 +1619,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par } auto SpeicalEffectLoop = SpeicalEffect->InsertNewChildElement("Loop"); { - SpeicalEffectLoop->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(1))); + SpeicalEffectLoop->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(!EncodeVideoInfos[j].ClipData.bIsCycle))); } auto SpeicalEffectMode = SpeicalEffect->InsertNewChildElement("Mode"); { @@ -1665,7 +1678,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare } tinyxml2::XMLElement* Loop = Video->InsertNewChildElement("Loop"); { - Loop->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(1))); + Loop->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(!EncodeVideoInfo.ClipData.bIsCycle))); } tinyxml2::XMLElement* Mode = Video->InsertNewChildElement("Mode"); { @@ -1705,19 +1718,13 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare tinyxml2::XMLElement* ProjectorEventList = Video->InsertNewChildElement("ProjectorEventList"); { - tinyxml2::XMLElement* ProjectorEvent1 = ProjectorEventList->InsertNewChildElement("ProjectorEvent"); + struct FProjectorEvent { - - tinyxml2::XMLElement* ProjectorTimeCode = ProjectorEvent1->InsertNewChildElement("TimeCode"); - { - ProjectorTimeCode->InsertNewText(TCHAR_TO_UTF8(*FUtils::GetMsFromString(FGlobalData::GetTimeData(EncodeVideoInfo.ClipStartFrame)))); - } - tinyxml2::XMLElement* Value = ProjectorEvent1->InsertNewChildElement("Value"); - { - Value->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(1))); - } - } - + FString TimeCode; + int32 Value; + }; + TArray ProjectorEvents; + ProjectorEvents.Add(FProjectorEvent{ FUtils::GetMsFromString(FGlobalData::GetTimeData(EncodeVideoInfo.ClipStartFrame)), 1 }); for (int32 i = 0; i < CutTimeline->TrackGroupInstances.Num(); i++) { if (StaticCastSharedPtr(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::ProjectorTrack) @@ -1726,27 +1733,37 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare { if (ClipData.ClipStartFrame > EncodeVideoInfo.ClipStartFrame - 10 && ClipData.ClipEndFrame < EncodeVideoInfo.ClipEndFrame + 10) { - tinyxml2::XMLElement* ProjectorEvent = ProjectorEventList->InsertNewChildElement("ProjectorEvent"); - { - - tinyxml2::XMLElement* ProjectorTimeCode = ProjectorEvent->InsertNewChildElement("TimeCode"); - { - ProjectorTimeCode->InsertNewText(TCHAR_TO_UTF8(*FUtils::GetMsFromString(FGlobalData::GetTimeData(ClipData.ClipStartFrame - EncodeVideoInfo.ClipStartFrame)))); - } - tinyxml2::XMLElement* Value = ProjectorEvent->InsertNewChildElement("Value"); - { - int32 ShowProjector = 0; - ClipData.PresetType == EPresetType::EnableProjector ? ShowProjector = 1 : ShowProjector = 0; - Value->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(ShowProjector))); - } - } - + int32 ShowProjector = 0; + ClipData.PresetType == EPresetType::EnableProjector ? ShowProjector = 1 : ShowProjector = 0; + ProjectorEvents.Add({FUtils::GetMsFromString(FGlobalData::GetTimeData(ClipData.ClipStartFrame - EncodeVideoInfo.ClipStartFrame)), ShowProjector}); } } } } + Sort(ProjectorEvents.GetData(), ProjectorEvents.Num(), [](const FProjectorEvent& ProjectorEventA, const FProjectorEvent& ProjectorEventB) { + return FCString::Atoi(*ProjectorEventA.TimeCode) < FCString::Atoi(*ProjectorEventB.TimeCode); + }); + + for (const FProjectorEvent& Event : ProjectorEvents) + { + tinyxml2::XMLElement* ProjectorEvent1 = ProjectorEventList->InsertNewChildElement("ProjectorEvent"); + { + tinyxml2::XMLElement* ProjectorTimeCode = ProjectorEvent1->InsertNewChildElement("TimeCode"); + { + ProjectorTimeCode->InsertNewText(TCHAR_TO_UTF8(*Event.TimeCode)); + } + tinyxml2::XMLElement* Value = ProjectorEvent1->InsertNewChildElement("Value"); + { + Value->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(Event.Value))); + } + } + } + + + + } return Parent; @@ -1788,8 +1805,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Pare } } } + - Sound->InsertNewChildElement("Loop")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(1))); + Sound->InsertNewChildElement("Loop")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(!EncodeVideoInfo.ClipData.bIsCycle))); Sound->InsertNewChildElement("Mode")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0))); Sound->InsertNewChildElement("Round")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(1))); Sound->InsertNewChildElement("TimeCode")->InsertNewText(TCHAR_TO_UTF8(*FUtils::GetMsFromString(EncodeVideoInfo.EncodedVideoTimeCode))); @@ -1818,10 +1836,21 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoListElement(tinyxml2::XMLElement* { if (StaticCastSharedPtr(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::VideoTrack) { - FString NewExportFilePath = FGlobalData::ExportPath / "Video/"; + FString Filename; + for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) + { + for (const FCurtain& Curtain : CurtainGroup.Curtains) + { + if (Curtain.bIsActive) + { + Filename = Curtain.CurtainName; + } + } + } + FString NewExportFilePath = FGlobalData::ExportPath / "Video" / Filename; GEngine->AddOnScreenDebugMessage(-1, 10.0F, FColor::White, NewExportFilePath); TArray EncodeVideoInfos = FUtils::TrackEncodeVideo(StaticCastSharedPtr(CutTimeline->TrackGroupInstances[i].Head)->TrackData, NewExportFilePath); - for (FEncodeVideoInfo EncodeVideoInfo : EncodeVideoInfos) + for (const FEncodeVideoInfo EncodeVideoInfo : EncodeVideoInfos) { GetVideoElement(VideoList, EncodeVideoInfo); Count++; @@ -1846,10 +1875,20 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundListElement(tinyxml2::XMLElement* if (StaticCastSharedPtr(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::AudioTrack || StaticCastSharedPtr(CutTimeline->TrackGroupInstances[i].Head)->TrackData.TrackType == ETrackType::AudioTrackR) { - FString Filename = FGuid::NewGuid().ToString(); + FString Filename; + for (FCurtainGroup& CurtainGroup : CurtainPanel->Groups) + { + for (const FCurtain& Curtain : CurtainGroup.Curtains) + { + if (Curtain.bIsActive) + { + Filename = Curtain.CurtainName; + } + } + } FString NewExportFilePath = FGlobalData::ExportPath / "Sound" / Filename; TArray EncodeVideoInfos = FUtils::TrackEncodeAudio(StaticCastSharedPtr(CutTimeline->TrackGroupInstances[i].Head)->TrackData, NewExportFilePath); - for (FEncodeVideoInfo EncodeVideoInfo : EncodeVideoInfos) + for (const FEncodeVideoInfo EncodeVideoInfo : EncodeVideoInfos) { GetSoundElement(AudioList, EncodeVideoInfo); Count++; @@ -1871,6 +1910,8 @@ tinyxml2::XMLElement* SCutMainWindow::GetProcessA(tinyxml2::XMLElement* Parent, ProcessA->SetAttribute("Name", TCHAR_TO_UTF8(*CurtainGroup->GroupName)); for (int32 i = 0; i < CurtainGroup->Curtains.Num(); i++) { + CurtainPanel->DeSelectedAll(); + CurtainGroup->Curtains[i].bIsActive = true; OpenTimeline(CurtainGroup->Curtains[i].TimelineInfo.CurrentOpenFullPath, true, true); GetProcessB(ProcessA, &CurtainGroup->Curtains[i]); } @@ -2092,10 +2133,10 @@ tinyxml2::XMLElement* SCutMainWindow::GetGradientLight(tinyxml2::XMLElement* Par { Parent->InsertNewChildElement("Mode")->InsertNewText("0"); Parent->InsertNewChildElement("InitialColor") - ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(ClipData.PresetsCustomData.Colors[0].ToFColor(false))))); + ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(ClipData.PresetsCustomData.Cursors[0].Color.ToFColor(false))))); Parent->InsertNewChildElement("EndColor") - ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"),*FUtils::Color2Hex3(ClipData.PresetsCustomData.Colors[0].ToFColor(false))))); + ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"),*FUtils::Color2Hex3(ClipData.PresetsCustomData.Cursors[0].Color.ToFColor(false))))); Parent->InsertNewChildElement("TimeLength") ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), @@ -2114,14 +2155,14 @@ tinyxml2::XMLElement* SCutMainWindow::GetGradientLight(tinyxml2::XMLElement* Par const int32 CursorNum = ClipData.PresetsCustomData.Cursors.Num(); for (const FCursorData& CursorData : ClipData.PresetsCustomData.Cursors) { - if (Index == CursorNum - 1 && CursorData.CursorFrameOffset < (ClipData.ClipEndFrame - ClipData.ClipStartFrame)) + if (Index == CursorNum - 1 && CursorData.CursorFrameOffset <= (ClipData.ClipEndFrame - ClipData.ClipStartFrame)) { Parent->InsertNewChildElement("Mode")->InsertNewText("0"); Parent->InsertNewChildElement("InitialColor") - ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(ClipData.PresetsCustomData.Colors[Index].ToFColor(false))))); + ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(ClipData.PresetsCustomData.Cursors[Index].Color.ToFColor(false))))); Parent->InsertNewChildElement("EndColor") - ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"),*FUtils::Color2Hex3(ClipData.PresetsCustomData.Colors[Index].ToFColor(false))))); + ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"),*FUtils::Color2Hex3(ClipData.PresetsCustomData.Cursors[Index].Color.ToFColor(false))))); Parent->InsertNewChildElement("TimeLength") ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), @@ -2142,10 +2183,10 @@ tinyxml2::XMLElement* SCutMainWindow::GetGradientLight(tinyxml2::XMLElement* Par } Parent->InsertNewChildElement("Mode")->InsertNewText("1"); Parent->InsertNewChildElement("InitialColor") - ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(CursorData.Color.ToFColor(false))))); + ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(ClipData.PresetsCustomData.Cursors[Index].Color.ToFColor(false))))); Parent->InsertNewChildElement("EndColor") - ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"),*FUtils::Color2Hex3(ClipData.PresetsCustomData.Colors[Index + 1].ToFColor(false))))); + ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"),*FUtils::Color2Hex3(ClipData.PresetsCustomData.Cursors[Index + 1].Color.ToFColor(false))))); Parent->InsertNewChildElement("TimeLength") ->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), diff --git a/Source/Cut5/Widgets/SCutTimeline.cpp b/Source/Cut5/Widgets/SCutTimeline.cpp index f01d549..db09aab 100644 --- a/Source/Cut5/Widgets/SCutTimeline.cpp +++ b/Source/Cut5/Widgets/SCutTimeline.cpp @@ -11,6 +11,7 @@ #include "Cut5/Utils/Utils.h" #include "DragDropOperator/DragDropOperator.h" #include "MicroWidgets/SClickEditableText.h" +#include "TimelineClips/ClipProxy.h" #include "Widgets/Input/SButton.h" #include "Widgets/Input/SEditableTextBox.h" #include "Widgets/Input/SSlider.h" @@ -38,7 +39,7 @@ FReply SCutTimeline::OnMouseButtonDown(const FGeometry& MyGeometry, const FPoint DragDropOperator->DraggingWidget = SharedThis(this); return FReply::Handled().DetectDrag(SharedThis(this), EKeys::LeftMouseButton).BeginDragDrop(DragDropOperator.ToSharedRef()); } - return FReply::Handled(); + return SCompoundWidget::OnMouseButtonDown(MyGeometry, MouseEvent); } FReply SCutTimeline::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) @@ -670,7 +671,10 @@ void SCutTimeline::SaveTimeline(const FString& SavedPath, FTimelineInfo Info) bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info) { - + TSharedPtr ClipProxy = FClipProxy::GetProxy(); + ClipProxy->Reset(); + static_cast(MainWidgetInterface)->UpdateProperties(nullptr); + static_cast(MainWidgetInterface)->CloseAllThreads(); TArray LoadData; FPaths::ConvertRelativePathToFull(LoadPath); FFileHelper::LoadFileToArray(LoadData, *LoadPath); diff --git a/Source/Cut5/Widgets/STimelineClip.cpp b/Source/Cut5/Widgets/STimelineClip.cpp index 3cd956e..9e4f2c8 100644 --- a/Source/Cut5/Widgets/STimelineClip.cpp +++ b/Source/Cut5/Widgets/STimelineClip.cpp @@ -67,6 +67,10 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().Cycle); } } + if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Gradient) + { + MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().AddCursorHere); + } MenuContent = MenuBuilder.MakeWidget(); @@ -75,7 +79,7 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F } TSharedPtr ClipProxy = FClipProxy::GetProxy(); - ClipProxy->UpdateInterface(this); + ClipProxy->UpdateInterface(SharedThis(this)); if (MainWidgetInterface->GetSelectedMode() == ESelectMode::CutMode) { diff --git a/Source/Cut5/Widgets/STimelineTick.cpp b/Source/Cut5/Widgets/STimelineTick.cpp index d930183..0e2f94c 100644 --- a/Source/Cut5/Widgets/STimelineTick.cpp +++ b/Source/Cut5/Widgets/STimelineTick.cpp @@ -56,6 +56,9 @@ int32 STimelineTick::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe for (int32 j = 0; j < TickCount; j++) { + + const float Space = FGlobalData::GlobalFPS * FGlobalData::DefaultTimeTickSpace; + const int32 TickSpace = FMath::GetMappedRangeValueClamped(FVector2D(1, 500), FVector2D(FGlobalData::GlobalFPS, 2), Space); if (j % 2 == 0) { const FSlateBrush Brush; @@ -68,8 +71,8 @@ int32 STimelineTick::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe FColor(55, 55, 55, 255)); } - const float Space = FGlobalData::GlobalFPS * FGlobalData::DefaultTimeTickSpace; - const int32 Multiplier = FMath::GetMappedRangeValueClamped(FVector2D(300, 2), FVector2D(1, 5), Space); + + const int32 Multiplier = FMath::GetMappedRangeValueClamped(FVector2D(500, 1), FVector2D(1, 6), Space); if (j % (Multiplier * int32(FGlobalData::GlobalFPS)) == 0) { diff --git a/Source/Cut5/Widgets/STrackBody.cpp b/Source/Cut5/Widgets/STrackBody.cpp index 16cb16f..8d6d1ff 100644 --- a/Source/Cut5/Widgets/STrackBody.cpp +++ b/Source/Cut5/Widgets/STrackBody.cpp @@ -21,10 +21,12 @@ void STrackBody::Construct(const FArguments& InArgs) CommandList = MakeShared(); CommandList->MapAction(FTimelineClipCommands::Get().Remove, FExecuteAction::CreateLambda([this]() { + MainWidgetInterface->UpdateProperties(nullptr); RemoveClip(SelectedClipGUID); }), FCanExecuteAction()); CommandList->MapAction(FTimelineClipCommands::Get().Break, FExecuteAction::CreateLambda([this]() { + MainWidgetInterface->UpdateProperties(nullptr); BreakClip(SelectedClipGUID); }), FCanExecuteAction()); CommandList->MapAction(FTimelineClipCommands::Get().Fill2Start, FExecuteAction::CreateLambda([this]() @@ -43,6 +45,10 @@ void STrackBody::Construct(const FArguments& InArgs) { SetCycle(SelectedClipGUID, false); }), FCanExecuteAction()); + CommandList->MapAction(FTimelineClipCommands::Get().AddCursorHere, FExecuteAction::CreateLambda([this]() + { + AddCursor(SelectedClipGUID); + }), FCanExecuteAction()); MainWidgetInterface = InArgs._MainWidgetInterface; TrackHead = InArgs._TrackHead; @@ -192,6 +198,33 @@ inline void STrackBody::Fill2Start(const FGuid& Guid) } } +void STrackBody::AddCursor(const FGuid& Guid) +{ + for (int32 i = 0; i < SlateClips.Num(); i++) + { + if (TrackHead->TrackData.ClipData[i].ClipGuid == Guid) + { + bool bIsFound = false; + for (int32 j = 0; j < TrackHead->TrackData.ClipData[i].PresetsCustomData.Cursors.Num(); j++) + { + if (TrackHead->TrackData.ClipData[i].PresetsCustomData.Cursors[j].CursorFrameOffset > SelectedClipFrame) + { + TrackHead->TrackData.ClipData[i].PresetsCustomData.Cursors.Insert(FCursorData(SelectedClipFrame, FLinearColor::MakeRandomColor()), j); + bIsFound = true; + CallRender(); + break; + } + } + if (bIsFound == false) + { + TrackHead->TrackData.ClipData[i].PresetsCustomData.Cursors.Add(FCursorData(SelectedClipFrame, FLinearColor::MakeRandomColor())); + } + + break; + } + } +} + void STrackBody::Fill2End(const FGuid& Guid) { for (int32 i = 0; i < SlateClips.Num(); i++) @@ -293,4 +326,25 @@ void STrackBody::DeleteUseLessClips() } } +int32 STrackBody::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, + const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, + const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const +{ + + if (bNeedRenderDragDropOver) + { + + for (int32 i = 0; i < DragDropShowProperties.Num(); i++) + { + const FSlateBrush Brush; + FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 4, AllottedGeometry.ToPaintGeometry(DragDropShowProperties[i].Size, FSlateLayoutTransform(DragDropShowProperties[i].Position)), + &Brush, + ESlateDrawEffect::None, DragDropShowProperties[i].Color); + } + + } + return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, + bParentEnabled); +} + END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Source/Cut5/Widgets/STrackBody.h b/Source/Cut5/Widgets/STrackBody.h index 53fa9a6..3dee1e2 100644 --- a/Source/Cut5/Widgets/STrackBody.h +++ b/Source/Cut5/Widgets/STrackBody.h @@ -37,6 +37,7 @@ public: void Fill2Start(const FGuid& Guid); void Fill2End(const FGuid& Guid); void SetCycle(const FGuid& Guid, bool Cycle); + void AddCursor(const FGuid& Guid); // virtual bool CanDragOver() override; @@ -57,27 +58,3 @@ public: }; - - - - -inline int32 STrackBody::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, - const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, - const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const -{ - - if (bNeedRenderDragDropOver) - { - - for (int32 i = 0; i < DragDropShowProperties.Num(); i++) - { - const FSlateBrush Brush; - FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 4, AllottedGeometry.ToPaintGeometry(DragDropShowProperties[i].Size, FSlateLayoutTransform(DragDropShowProperties[i].Position)), - &Brush, - ESlateDrawEffect::None, DragDropShowProperties[i].Color); - } - - } - return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, - bParentEnabled); -} diff --git a/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp b/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp index a25484b..c6161d1 100644 --- a/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp +++ b/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp @@ -13,15 +13,33 @@ TSharedPtr FClipProxy::GetProxy() return Proxy; } -void FClipProxy::UpdateInterface(STimelineClip* InTimeClip) +void FClipProxy::UpdateInterface(TSharedPtr InTimeClip) { + Reset(); + InTimeClip->MainWidgetInterface->UpdateProperties(nullptr); this->ClipData = InTimeClip->ClipData; this->TimelineClip = InTimeClip; this->MainInterface = InTimeClip->MainWidgetInterface; - TimelineClip->MainWidgetInterface->UpdateProperties(nullptr); TimelineClip->MainWidgetInterface->UpdateProperties(this); } +FSlateColor FClipProxy::GetColor() const +{ + if (ClipData) + { + if (ClipData->ClipGuid == FGuid() || ClipData->PresetsCustomData.Colors.Num() == 0) + { + return FLinearColor(1, 1, 1, 0.5); + } + else + { + return ClipData->PresetsCustomData.Colors[0]; + } + } + return FLinearColor(1, 1, 1, 0.5); + +} + TSharedPtr FClipProxy::GetPropertiesWidget() { Selectable.Empty(); @@ -65,22 +83,7 @@ TSharedPtr FClipProxy::GetPropertiesWidget() [ SNew(SImage) .Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("Color.png"), {})) - .ColorAndOpacity_Lambda([this]() - { - if (ClipData) - { - if (ClipData->PresetsCustomData.Colors.Num() == 0) - { - return FLinearColor(1, 1, 1, 0.5); - } - else - { - return ClipData->PresetsCustomData.Colors[0]; - } - } - return FLinearColor(1, 1, 1, 0.5); - - }) + .ColorAndOpacity_Raw(this, &FClipProxy::GetColor) .OnMouseButtonDown_Lambda([this](const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { MainInterface->OpenColorPanel(&ClipData->PresetsCustomData.Colors[0]); @@ -158,6 +161,8 @@ TSharedPtr FClipProxy::GetPropertiesWidget() SNew(STextBlock) .Text_Lambda([this]() { + if (!ClipData) + return FText(); return FText::FromString( ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None ? TEXT("无") : ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Breathe ? TEXT("呼吸") : ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Gradient ? TEXT("渐变") : TEXT("闪烁")); }) ] @@ -197,12 +202,16 @@ TSharedPtr FClipProxy::GetPropertiesWidget() SNew(SSpinBox) .Value_Lambda([this]() { + if (!ClipData) + return 0; return ClipData->PresetsCustomData.Times; }) .MinValue(1) .MaxValue(200) .OnValueChanged_Lambda([this](const int32& Value) { + if (!ClipData) + return; ClipData->PresetsCustomData.Times = Value; }) ] @@ -242,7 +251,8 @@ TSharedPtr FClipProxy::GetPropertiesWidget() .MinValue(0.3) .OnValueChanged_Lambda([this](const float& Value) { - + if (!ClipData) + return; ClipData->ClipEndFrame = ClipData->ClipStartFrame + Value * FGlobalData::GlobalFPS; ClipData->PresetsCustomData.Time = (ClipData->ClipEndFrame - ClipData->ClipStartFrame) / FGlobalData::GlobalFPS; MainInterface->GetCutTimeline()->RenderGroup(); @@ -250,6 +260,8 @@ TSharedPtr FClipProxy::GetPropertiesWidget() }) .Value_Lambda([this]() { + if (!ClipData) + return 0.0f; return (ClipData->ClipEndFrame - ClipData->ClipStartFrame) / FGlobalData::GlobalFPS; }) // .TypeInterface(MakeShared>(EUnit::Seconds)) @@ -305,3 +317,10 @@ TSharedPtr FClipProxy::GetPropertiesWidget() } + +void FClipProxy::Reset() +{ + TimelineClip = nullptr; + ClipData = nullptr; + MainInterface = nullptr; +} diff --git a/Source/Cut5/Widgets/TimelineClips/ClipProxy.h b/Source/Cut5/Widgets/TimelineClips/ClipProxy.h index cd84c8c..1256aba 100644 --- a/Source/Cut5/Widgets/TimelineClips/ClipProxy.h +++ b/Source/Cut5/Widgets/TimelineClips/ClipProxy.h @@ -7,13 +7,15 @@ class FClipProxy : public IPropertiesInterface { public: static TSharedPtr GetProxy(); - void UpdateInterface(class STimelineClip* InTimeClip); + void UpdateInterface(TSharedPtr InTimeClip); + FSlateColor GetColor() const; virtual TSharedPtr GetPropertiesWidget() override; + void Reset(); TSharedPtr>> GroupComboBox; TArray> Selectable; - STimelineClip* TimelineClip; - FClipData* ClipData; - ICutMainWidgetInterface* MainInterface; + TSharedPtr TimelineClip = nullptr; + FClipData* ClipData = nullptr; + ICutMainWidgetInterface* MainInterface = nullptr; };