From f859840d7bcf41b8eeb088289b4bd1746c5d6fa2 Mon Sep 17 00:00:00 2001 From: Sch <3516520171@qq.com> Date: Tue, 1 Aug 2023 08:02:29 +0800 Subject: [PATCH] =?UTF-8?q?=E6=AD=A3=E5=B8=B8=E7=89=B9=E6=95=88=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=BF=9D=E5=AD=98=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DefaultProject/Dataset/CustomInputPanel.bin | Bin 0 -> 518 bytes DefaultProject/DefaultProject.xml | 64 ++++++++ DefaultProject/DefaultProject_Link.cutlink | Bin 0 -> 64 bytes Resources/EffectCardUnSelected.png | Bin 0 -> 447 bytes .../Cut5/Interface/CutMainWidgetInterface.h | 4 + Source/Cut5/Utils/FFMPEGUtils.cpp | 140 +++++++++++++++++- Source/Cut5/Utils/FFMPEGUtils.h | 4 + Source/Cut5/Utils/Utils.cpp | 5 + Source/Cut5/Utils/Utils.h | 2 + Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp | 18 +++ Source/Cut5/Widgets/DefineGlobal.h | 29 +++- Source/Cut5/Widgets/FX/SEffectCard.cpp | 40 +++-- Source/Cut5/Widgets/FX/SEffectCardGroup.cpp | 24 +++ Source/Cut5/Widgets/FX/SEffectCardGroup.h | 1 + Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp | 56 ++++++- Source/Cut5/Widgets/FX/SEffectCardsPanel.h | 4 + Source/Cut5/Widgets/SCustomInputPanel.cpp | 54 ++++++- Source/Cut5/Widgets/SCustomInputPanel.h | 7 +- Source/Cut5/Widgets/SCustomInputResource.cpp | 6 +- Source/Cut5/Widgets/SCutMainWindow.cpp | 56 ++++++- Source/Cut5/Widgets/SCutMainWindow.h | 3 + Source/Cut5/Widgets/SCutTimeline.cpp | 7 + Source/Cut5/Widgets/SCutTimeline.h | 1 + Source/Cut5/Widgets/STimelineClip.cpp | 20 --- .../Cut5/Widgets/StatePanel/SStatePanel.cpp | 13 +- 25 files changed, 500 insertions(+), 58 deletions(-) create mode 100644 DefaultProject/Dataset/CustomInputPanel.bin create mode 100644 DefaultProject/DefaultProject.xml create mode 100644 DefaultProject/DefaultProject_Link.cutlink create mode 100644 Resources/EffectCardUnSelected.png diff --git a/DefaultProject/Dataset/CustomInputPanel.bin b/DefaultProject/Dataset/CustomInputPanel.bin new file mode 100644 index 0000000000000000000000000000000000000000..e050ad089986f65d26c8f8daf5f2991d0b129d7e GIT binary patch literal 518 zcmZQ#U|{Ht54~l6`jhv}eLS}goSrTq2owtpG%_$UHa9fT1=1#_=0G6^hAbe~)6+*r z0Y&*)smUe!&ZQ-$`oW21sVVv{scDI&IVCWepw#00(xT+lV*QYe(%huH#LOIh3r7Qb`oYN=K!c03 zOY#f!!!lD+^YzhPsFzz{!l1 + + + Sch + + + + + + + + 2 + 光阵 + + + + + 0 + 音频R + + + + + 1 + 投影仪 + + + + + + 0 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DefaultProject/DefaultProject_Link.cutlink b/DefaultProject/DefaultProject_Link.cutlink new file mode 100644 index 0000000000000000000000000000000000000000..8f30ea97fcfa8fde506851b6390d580888897c80 GIT binary patch literal 64 zcmcCvU|?{u(hn%g&q_@$(RVH_G1YfTO-n4zDS?T(B$gx=r-I~)OY(C)^9o8!0uu95 KbM%rj^B4f3Xci&> literal 0 HcmV?d00001 diff --git a/Resources/EffectCardUnSelected.png b/Resources/EffectCardUnSelected.png new file mode 100644 index 0000000000000000000000000000000000000000..4fb0687ac55553a547a30f620933fdbefd949047 GIT binary patch literal 447 zcmeAS@N?(olHy`uVBq!ia0vp^J|N7&1|*M957Y)yjKx9jP7LeL$-D$|Sc;uILpXq- zh9ji|D3|H!;uumf=j|QC>_Y((ZVx9*cP;Qcx^k)a|NrZScI}LKqp)YuOjpc*S?z-o^U#2TFHVkuWGG1t4p8S)a-t0Qd6zjbNQ6; b WidgetInterface) { return FString(); }; virtual FTimelinePropertyData* GetResourcePropertyDataPtr(FGuid GUID) { return nullptr; }; + + + virtual void OnSelectCard(const FGuid& SelectedCard) {}; }; diff --git a/Source/Cut5/Utils/FFMPEGUtils.cpp b/Source/Cut5/Utils/FFMPEGUtils.cpp index 07eaadf..fc99dba 100644 --- a/Source/Cut5/Utils/FFMPEGUtils.cpp +++ b/Source/Cut5/Utils/FFMPEGUtils.cpp @@ -1,5 +1,8 @@ #include "FFMPEGUtils.h" +#include "ImageUtils.h" +#include "Utils.h" + FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* PropertyData) { @@ -8,6 +11,11 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop { check(false) } + if (avformat_find_stream_info(FormatContext, nullptr) < 0) + { + check(false) + } + PropertyData->MovieFrameLength = FormatContext->duration / AV_TIME_BASE * 30; int32 VideoStream = -1; int32 AudioStream = -1; for (unsigned int i = 0; i < FormatContext->nb_streams; i++) { @@ -33,6 +41,57 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop } PropertyData->VideoCodec = VideoCodec; PropertyData->VideoCodecContext = VideoCodecContext; + + AVPacket* Packet = av_packet_alloc(); + AVFrame* Frame = av_frame_alloc(); + while (av_read_frame(FormatContext, Packet) >= 0) + { + if (avcodec_send_packet(VideoCodecContext, Packet) < 0) + { + + } + if (avcodec_receive_frame(VideoCodecContext, Frame) >= 0) + { + break; + } + }; + + + if (Frame) + { + struct SwsContext* swsCtx = sws_getContext( + Frame->width, Frame->height, VideoCodecContext->pix_fmt, + Frame->width, Frame->height, AV_PIX_FMT_RGBA, + SWS_BILINEAR, NULL, NULL, NULL + ); + if (!swsCtx) + { + UE_LOG(LogTemp, Error, TEXT("Error creating swsContext")); + } + uint8* RawData = new uint8[Frame->width * Frame->height * 4]; + uint8* dest[4] = {RawData, 0, 0, 0}; + int32 dest_linesize[4] = {Frame->width * 4, 0, 0, 0}; + sws_scale(swsCtx, Frame->data, Frame->linesize, 0, Frame->height, dest, dest_linesize); + sws_freeContext(swsCtx); + + + UTexture2D* Texture = UTexture2D::CreateTransient(Frame->width, Frame->height, PF_B8G8R8A8); + if (Texture) + { + void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE); + FMemory::Memcpy(MipData, RawData, Frame->width * Frame->height * 4); + Texture->GetPlatformData()->Mips[0].BulkData.Unlock(); + Texture->UpdateResource(); + + FGuid Guid = FGuid::NewGuid(); + ExportImage(Texture, *FPaths::Combine(FPaths::ProjectSavedDir(), FGlobalData::CurrentProjectName, "Resources", "Thumbnail", Guid.ToString() + ".png")); + PropertyData->IconPath = FPaths::Combine(FPaths::ProjectSavedDir(), FGlobalData::CurrentProjectName, "Resources", "Thumbnail", Guid.ToString() + ".png"); + delete RawData; + } + } + av_seek_frame(FormatContext, VideoStream, 0, AVSEEK_FLAG_BACKWARD); + + } @@ -47,6 +106,32 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop { check(false) } + + TArray DataResult; + AVPacket Packet = *av_packet_alloc(); + AVFrame* Frame = av_frame_alloc(); + while (1) + { + if (av_read_frame(FormatContext, &Packet) < 0) + { + if (av_read_frame(FormatContext, &Packet) < 0) + { + break; + } + } + avcodec_send_packet(AudioCodecContext, &Packet); + if (avcodec_receive_frame(AudioCodecContext, Frame) >= 0) + { + const uint8* Result = FUtils::ConvertTwoChannelSound2PortAudioSound(Frame->data[0], Frame->data[1], Frame->nb_samples); + if (Result != nullptr) + { + DataResult.Append(Result, Frame->nb_samples * 4 * 2); + // Pa_WriteStream(Stream, Result, Frame->nb_samples); + } + delete[] Result; + } + } + PropertyData->AudioData = DataResult; PropertyData->AudioCodecContext = AudioCodecContext; PropertyData->AudioCodec = AudioCodec; } @@ -70,7 +155,7 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop PropertyData->Name = FPaths::GetBaseFilename(Path); PropertyData->MoviePath = Path; - PropertyData->MovieFrameLength = FormatContext->duration / AV_TIME_BASE * 30; + return {}; } @@ -93,3 +178,56 @@ FString FFFMPEGUtils::ConvertMediaGoPto1(const FString& Path) } return {}; } + +bool FFFMPEGUtils::ExportImage(UTexture2D* Texture2D, const FString& Path) +{ + // setup required parameters + TextureCompressionSettings OldCompressionSettings = Texture2D->CompressionSettings; + TextureMipGenSettings OldMipGenSettings = Texture2D->MipGenSettings; + bool OldSRGB = Texture2D->SRGB; + + Texture2D->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap; + Texture2D->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps; + Texture2D->SRGB = false; + Texture2D->UpdateResource(); + + FTexture2DMipMap& mipmap = Texture2D->PlatformData->Mips[0]; + uint8* Data = (uint8*)mipmap.BulkData.Lock(LOCK_READ_WRITE); + //FColor* FormatedImageData = static_cast(mipmap.BulkData.Lock(LOCK_READ_WRITE)); + if (Data == nullptr) + { + mipmap.BulkData.Unlock(); // 不释放,会卡住 + Texture2D->UpdateResource(); + return false; + } + + int width = Texture2D->PlatformData->SizeX; + int height = Texture2D->PlatformData->SizeY; + TArray nColors; + + for (int32 y = 0; y < height; y++) + { + for (int32 x = 0; x < width; x++) + { + FColor bColor; + bColor.B = Data[(y * width + x) * 4 + 0];//B 0 - 255 + bColor.G = Data[(y * width + x) * 4 + 1];//G + bColor.R = Data[(y * width + x) * 4 + 2];//R + bColor.A = Data[(y * width + x) * 4 + 3];//A + nColors.Add(bColor); + } + } + mipmap.BulkData.Unlock(); + + // return old parameters + Texture2D->CompressionSettings = OldCompressionSettings; + Texture2D->MipGenSettings = OldMipGenSettings; + Texture2D->SRGB = OldSRGB; + + Texture2D->UpdateResource(); + + //获取 uint8 数据,保存 + TArray ImgData; + FImageUtils::CompressImageArray(width, height, nColors, ImgData); + return FFileHelper::SaveArrayToFile(ImgData, *Path); +} diff --git a/Source/Cut5/Utils/FFMPEGUtils.h b/Source/Cut5/Utils/FFMPEGUtils.h index 5a02e70..96398a7 100644 --- a/Source/Cut5/Utils/FFMPEGUtils.h +++ b/Source/Cut5/Utils/FFMPEGUtils.h @@ -1,9 +1,11 @@ #pragma once +#include "ImageUtils.h" #include "Cut5/Widgets/DefineGlobal.h" extern "C"{ #include + #include } struct FFFMPEGUtils { @@ -13,4 +15,6 @@ struct FFFMPEGUtils */ static FString LoadMedia(const FString& Path, FTimelinePropertyData* PropertyData); static FString ConvertMediaGoPto1(const FString& Path); + static bool ExportImage(UTexture2D* Texture2D, const FString& Path); + }; diff --git a/Source/Cut5/Utils/Utils.cpp b/Source/Cut5/Utils/Utils.cpp index 65130a2..5059a3f 100644 --- a/Source/Cut5/Utils/Utils.cpp +++ b/Source/Cut5/Utils/Utils.cpp @@ -110,5 +110,10 @@ FSaveModifier::~FSaveModifier() { MemoryWriter << TrackData[i]; } + if (bNewSavePath) + { + FFileHelper::SaveArrayToFile(SavedData, *NewSavePath); + return; + } FFileHelper::SaveArrayToFile(SavedData, *FullSavedPath); } diff --git a/Source/Cut5/Utils/Utils.h b/Source/Cut5/Utils/Utils.h index 3733ee6..9eb0038 100644 --- a/Source/Cut5/Utils/Utils.h +++ b/Source/Cut5/Utils/Utils.h @@ -47,4 +47,6 @@ public: int32 GroupLength = 0; TArray GroupName; TArray TrackData; + bool bNewSavePath = false; + FString NewSavePath = ""; }; diff --git a/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp b/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp index 14bb0b6..a8782ab 100644 --- a/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp +++ b/Source/Cut5/Widgets/Curtain/SCurtainPanel.cpp @@ -76,8 +76,26 @@ void SCurtainPanel::Construct(const FArguments& InArgs) MainWidgetInterface->ExportProject(String); return FReply::Handled(); }) + .Text(FText::FromString(TEXT("导出"))) ] + ] + + SVerticalBox::Slot() + .SizeParam(FAuto()) + [ + SNew(SBox) + .WidthOverride(100) + .HeightOverride(50) + [ + SNew(SButton) + .OnClicked_Lambda([this]() + { + MainWidgetInterface->ImportProject(""); + return FReply::Handled(); + }) + .Text(FText::FromString(TEXT("导入"))) + ] + ] + SVerticalBox::Slot() .SizeParam(FAuto()) diff --git a/Source/Cut5/Widgets/DefineGlobal.h b/Source/Cut5/Widgets/DefineGlobal.h index 77f60b7..1656ce7 100644 --- a/Source/Cut5/Widgets/DefineGlobal.h +++ b/Source/Cut5/Widgets/DefineGlobal.h @@ -190,13 +190,26 @@ struct CUT5_API FTimelinePropertyData int32 VideoStream = -1; int32 AudioStream = -1; - // Movie Data + // Base Data FString MoviePath = ""; int32 MovieFrameLength = 0; - TObjectPtr Sound; - - // Audio Data TArray AudioData; + + friend FArchive& operator<<(FArchive& Ar, FTimelinePropertyData& PropertyData) + { + Ar << PropertyData.Guid; + Ar << PropertyData.Name; + Ar << PropertyData.Type; + Ar << PropertyData.IconPath; + Ar << PropertyData.MoviePath; + Ar << PropertyData.MovieFrameLength; + Ar << PropertyData.AudioData; + Ar << PropertyData.VideoStream; + Ar << PropertyData.AudioStream; + Ar << PropertyData.MoviePath; + Ar << PropertyData.MovieFrameLength; + return Ar; + } }; class CUT5_API FCutDragDropBase : public FDecoratedDragDropOp @@ -273,7 +286,7 @@ struct CUT5_API FEffectCardProperty FGuid Guid = FGuid::NewGuid(); FString Name = ""; FTimelineInfo TimelineInfo; - + bool bIsActive = false; friend FArchive& operator<<(FArchive& Ar, FEffectCardProperty& EffectCardProperty) { Ar << EffectCardProperty.Guid; @@ -290,7 +303,9 @@ struct CUT5_API FEffectCardGroup bool bIsDedicated = false; bool bCanEditName = false; bool bIsExpanded = true; - + bool bIsActive = false; + FGuid Guid = FGuid::NewGuid(); + FTimelineInfo TimelineInfo; friend FArchive& operator<<(FArchive& Ar, FEffectCardGroup& EffectCard) { Ar << EffectCard.GroupName; @@ -298,6 +313,8 @@ struct CUT5_API FEffectCardGroup Ar << EffectCard.bIsDedicated; Ar << EffectCard.bCanEditName; Ar << EffectCard.bIsExpanded; + Ar << EffectCard.Guid; + Ar << EffectCard.TimelineInfo; return Ar; }; }; diff --git a/Source/Cut5/Widgets/FX/SEffectCard.cpp b/Source/Cut5/Widgets/FX/SEffectCard.cpp index 40d92c2..daa3bd1 100644 --- a/Source/Cut5/Widgets/FX/SEffectCard.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCard.cpp @@ -7,23 +7,27 @@ #include "Cut5/Utils/Utils.h" #include "Cut5/Widgets/MicroWidgets/SClickEditableText.h" +#include "Widgets/Text/SInlineEditableTextBlock.h" BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SEffectCard::OnNameEdited(FString New, FString Old) { CardProperty->Name = New; - SetSavePath({TEXT("FX"), TEXT("SingleCard"), New + TEXT(".bin")}); - if (!IFileManager::Get().FileExists(*GetSavePath())) + if (!IFileManager::Get().FileExists(*FUtils::SingleCardFullPath(CardProperty->Name))) { TArray BinaryData; FFileHelper::LoadFileToArray(BinaryData, *CardProperty->TimelineInfo.CurrentOpenFullPath); - CardProperty->TimelineInfo.CurrentOpenFullPath = FUtils::SingleCardFullPath(CardProperty->Name); - FFileHelper::SaveArrayToFile(BinaryData, *CardProperty->TimelineInfo.CurrentOpenFullPath); + { + FSaveModifier SaveModifier(CardProperty->TimelineInfo.CurrentOpenFullPath); + SaveModifier.TimelineInfo.CurrentOpenFullPath = FUtils::SingleCardFullPath(CardProperty->Name); + SaveModifier.bNewSavePath = true; + SaveModifier.NewSavePath = FUtils::SingleCardFullPath(CardProperty->Name); + } } else { - + } } @@ -32,7 +36,6 @@ void SEffectCard::Construct(const FArguments& InArgs) CardProperty = InArgs._CardProperty; GroupName = InArgs._GroupName; MainInterface = InArgs._MainInterface; - SetSavePath({TEXT("FX"), TEXT("SingleCard"), CardProperty->Name + TEXT(".bin")}); ChildSlot [ SNew(SBox) @@ -40,31 +43,38 @@ void SEffectCard::Construct(const FArguments& InArgs) .HeightOverride(125.0f) [ SNew(SOverlay) + // + SOverlay::Slot() + // [ + // SNew(SButton) + // ] + SOverlay::Slot() - [ - SNew(SButton) - ] - + SOverlay::Slot() + .VAlign(VAlign_Fill) + .HAlign(HAlign_Fill) [ SNew(SImage) - .Visibility(EVisibility::HitTestInvisible) - .Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("EffectCard.png"), FVector2D(125.0, 125.0))) + .Image(CardProperty->bIsActive ? FUtils::GetBrushFromImage(FUtils::GetResourcesPath("EffectCard.png"), FVector2D(125.0, 125.0)) : + FUtils::GetBrushFromImage(FUtils::GetResourcesPath("EffectCardUnSelected.png"), FVector2D(125.0, 125.0))) .OnMouseButtonDown_Lambda([this](const FGeometry&, const FPointerEvent& PointerEvent) { - MainInterface->OpenTimeline(FUtils::SingleCardFullPath(CardProperty->TimelineInfo.CurrentOpenFullPath), true); + MainInterface->OpenTimeline(FUtils::SingleCardFullPath(CardProperty->Name), true); + MainInterface->OnSelectCard(CardProperty->Guid); return FReply::Handled(); }) ] + SOverlay::Slot() + .VAlign(VAlign_Center) + .HAlign(HAlign_Center) [ SNew(SClickEditableText) .InitTextPtr(&CardProperty->Name) .OnEdited_Raw(this, &SEffectCard::OnNameEdited) - .CanEdit(true) + .CanEdit(!CardProperty->bIsActive) .OnSingleClick_Lambda([this]() { - MainInterface->OpenTimeline(FUtils::SingleCardFullPath(CardProperty->Name), true); + }) + + ] ] diff --git a/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp b/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp index 58c71c6..bc82e43 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCardGroup.cpp @@ -13,6 +13,27 @@ BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION + +void SEffectCardGroup::OnNameEdited(FString New, FString Old) +{ + EffectCardGroup->GroupName = New; + if (!IFileManager::Get().FileExists(*FUtils::GroupFullPath(EffectCardGroup->GroupName))) + { + TArray BinaryData; + FFileHelper::LoadFileToArray(BinaryData, *EffectCardGroup->TimelineInfo.CurrentOpenFullPath); + { + FSaveModifier SaveModifier(EffectCardGroup->TimelineInfo.CurrentOpenFullPath); + SaveModifier.TimelineInfo.CurrentOpenFullPath = FUtils::GroupFullPath(EffectCardGroup->GroupName); + SaveModifier.bNewSavePath = true; + SaveModifier.NewSavePath = FUtils::GroupFullPath(EffectCardGroup->GroupName); + } + } + else + { + + } +} + void SEffectCardGroup::Construct(const FArguments& InArgs) { EffectCardGroup = InArgs._EffectCardGroup; @@ -38,12 +59,15 @@ void SEffectCardGroup::Construct(const FArguments& InArgs) .InitTextPtr(&EffectCardGroup->GroupName) .CanEdit(EffectCardGroup->bCanEditName) .IsNeedUpright(false) + .OnEdited_Raw(this, &SEffectCardGroup::OnNameEdited) ] .BodyContent() [ SNew(SBorder) .HAlign(HAlign_Fill) .VAlign(VAlign_Fill) + // .ColorAndOpacity(EffectCardGroup->bIsDedicated ? FLinearColor(0.5, 0.5, 0.5, 1) : + // EffectCardGroup->bIsActive ? FLinearColor(1, 0, 0, 1) : FLinearColor(0.5, 0.5, 0.5, 1)) [ SNew(SOverlay) + SOverlay::Slot() diff --git a/Source/Cut5/Widgets/FX/SEffectCardGroup.h b/Source/Cut5/Widgets/FX/SEffectCardGroup.h index 8a605fd..537b837 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardGroup.h +++ b/Source/Cut5/Widgets/FX/SEffectCardGroup.h @@ -23,6 +23,7 @@ public: SLATE_ARGUMENT(ICutMainWidgetInterface*, MainInterface) SLATE_END_ARGS() + void OnNameEdited(FString New, FString Old); /** Constructs this widget with InArgs */ void Construct(const FArguments& InArgs); diff --git a/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp b/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp index a73ff94..b9aae23 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp +++ b/Source/Cut5/Widgets/FX/SEffectCardsPanel.cpp @@ -45,9 +45,7 @@ void SEffectCardsPanel::Construct(const FArguments& InArgs) DedicatedGroup.GroupName = TEXT("独立特效卡"); EffectCardGroups.Add(DedicatedGroup); - FEffectCardProperty CardProperty; - CardProperty.Name = TEXT("鲨鱼卡"); - AddNewCard(CardProperty, ""); + CallRender(); } void SEffectCardsPanel::CallRender() @@ -82,6 +80,8 @@ void SEffectCardsPanel::CallRender() FSaveModifier SaveModifier(NewPath); SaveModifier.TimelineInfo.CurrentOpenFullPath = NewPath; } + Group->TimelineInfo.CurrentOpenFullPath = NewPath; + CallRender(); return FReply::Handled(); }) ] @@ -193,4 +193,54 @@ FEffectCardGroup* SEffectCardsPanel::GetDedicatedGroupFromName() return nullptr; } +void SEffectCardsPanel::SelectCard(const FGuid& Guid) +{ + if (Guid == CurrentSelectedCardGuid) + { + MainInterface->OpenTimeline(FUtils::MainSaveFullPath()); + CurrentSelectedCardGuid.Invalidate(); + CallRender(); + } + else + { + for (FEffectCardGroup& EffectCardGroup : EffectCardGroups) + { + if (EffectCardGroup.bIsDedicated) + { + for (FEffectCardProperty& Property : EffectCardGroup.Cards) + { + Property.bIsActive = false; + } + } + else + { + EffectCardGroup.bIsActive = false; + } + } + CurrentSelectedCardGuid = Guid; + } + for (FEffectCardGroup& EffectCardGroup : EffectCardGroups) + { + if (EffectCardGroup.bIsDedicated) + { + for (FEffectCardProperty& Property : EffectCardGroup.Cards) + { + if (Guid == Property.Guid) + { + Property.bIsActive = true; + } + } + } + else + { + if (EffectCardGroup.Guid == Guid) + { + EffectCardGroup.bIsActive = true; + } + } + } + CallRender(); + +} + END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Source/Cut5/Widgets/FX/SEffectCardsPanel.h b/Source/Cut5/Widgets/FX/SEffectCardsPanel.h index 59612b9..6e6c6e0 100644 --- a/Source/Cut5/Widgets/FX/SEffectCardsPanel.h +++ b/Source/Cut5/Widgets/FX/SEffectCardsPanel.h @@ -83,5 +83,9 @@ public: * @return Dedicated Group Ptr. */ FEffectCardGroup* GetDedicatedGroupFromName(); + + void SelectCard(const FGuid& Guid); + + FGuid CurrentSelectedCardGuid; }; diff --git a/Source/Cut5/Widgets/SCustomInputPanel.cpp b/Source/Cut5/Widgets/SCustomInputPanel.cpp index bfa8f4d..a594938 100644 --- a/Source/Cut5/Widgets/SCustomInputPanel.cpp +++ b/Source/Cut5/Widgets/SCustomInputPanel.cpp @@ -154,17 +154,24 @@ void SCustomInputPanel::Construct(const FArguments& InArgs) { FTimelinePropertyData Data; FFFMPEGUtils::LoadMedia(OpenFileName[i], &Data); + GridPanel->AddSlot(GridPanel->GetChildren()->Num() % 2, GridPanel->GetChildren()->Num() / 2) + [ + SNew(SCustomInputResource) + .PropertyData(Data) + ]; + PropertyData.Add(Data); return FReply::Handled(); } else { FTimelinePropertyData Data; FFFMPEGUtils::LoadMedia(OpenFileName[i], &Data); - GridPanel->AddSlot(GridPanel->GetChildren()->Num() % 3, GridPanel->GetChildren()->Num() / 3) + GridPanel->AddSlot(GridPanel->GetChildren()->Num() % 2, GridPanel->GetChildren()->Num() / 2) [ SNew(SCustomInputResource) .PropertyData(Data) ]; + PropertyData.Add(Data); } } return FReply::Handled(); @@ -317,5 +324,50 @@ int SCustomInputPanel::AudioCallback(const void* input, void* output, unsigned l return 0; } +void SCustomInputPanel::SavePanel(const FString& SavePlace) +{ + TArray NewData; + FMemoryWriter Writer(NewData); + int32 PropertyDataNum = PropertyData.Num(); + Writer << PropertyDataNum; + for (FTimelinePropertyData& Data : PropertyData) + { + Writer << Data; + } + FFileHelper::SaveArrayToFile(NewData, *SavePlace); +} + +void SCustomInputPanel::LoadPanel(const FString& LoadPlace) +{ + ClearPanel(); + TArray LoadData; + FFileHelper::LoadFileToArray(LoadData, *LoadPlace); + FMemoryReader Reader(LoadData); + int32 PropertyDataNum = 0; + Reader << PropertyDataNum; + for (int32 i = 0; i < PropertyDataNum; i++) + { + FTimelinePropertyData Data; + Reader << Data; + FTimelinePropertyData ReloadPropertyData; + FFFMPEGUtils::LoadMedia(Data.MoviePath, &ReloadPropertyData); + ReloadPropertyData.Guid = Data.Guid; + + GridPanel->AddSlot(GridPanel->GetChildren()->Num() % 2, GridPanel->GetChildren()->Num() / 2) + [ + SNew(SCustomInputResource) + .PropertyData(ReloadPropertyData) + ]; + PropertyData.Add(ReloadPropertyData); + } + +} + +void SCustomInputPanel::ClearPanel() +{ + GridPanel->ClearChildren(); + PropertyData.Empty(); +} + END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Source/Cut5/Widgets/SCustomInputPanel.h b/Source/Cut5/Widgets/SCustomInputPanel.h index 4320911..c0ddab8 100644 --- a/Source/Cut5/Widgets/SCustomInputPanel.h +++ b/Source/Cut5/Widgets/SCustomInputPanel.h @@ -47,7 +47,8 @@ public: void *userData ); TSharedPtr Switcher; - - - + TArray PropertyData; + void SavePanel(const FString& SavePlace); + void LoadPanel(const FString& LoadPlace); + void ClearPanel(); }; diff --git a/Source/Cut5/Widgets/SCustomInputResource.cpp b/Source/Cut5/Widgets/SCustomInputResource.cpp index 9c5f04e..9c0d331 100644 --- a/Source/Cut5/Widgets/SCustomInputResource.cpp +++ b/Source/Cut5/Widgets/SCustomInputResource.cpp @@ -5,6 +5,7 @@ #include "DefineGlobal.h" #include "SlateOptMacros.h" +#include "Cut5/Utils/Utils.h" BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION @@ -15,8 +16,8 @@ void SCustomInputResource::Construct(const FArguments& InArgs) ChildSlot [ SNew(SBox) - .WidthOverride(100) - .HeightOverride(100) + .WidthOverride(173.5) + .HeightOverride(97.5) [ SNew(SOverlay) + SOverlay::Slot() @@ -30,6 +31,7 @@ void SCustomInputResource::Construct(const FArguments& InArgs) .VAlign(VAlign_Fill) [ SNew(SImage) + .Image(FUtils::GetBrushFromImage(PropertyData.IconPath, {})) ] ] diff --git a/Source/Cut5/Widgets/SCutMainWindow.cpp b/Source/Cut5/Widgets/SCutMainWindow.cpp index 8f8e2c2..7566e01 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.cpp +++ b/Source/Cut5/Widgets/SCutMainWindow.cpp @@ -290,6 +290,8 @@ void SCutMainWindow::OnUpdateSound(uint8* Data, int32 Size) SoundThread->QueueAudio(Data, Size); } + + void SCutMainWindow::AddNewCard(FEffectCardProperty& CardProperty, FString GroupName) { EffectCardsPanel->AddNewCard(CardProperty, GroupName); @@ -320,6 +322,7 @@ void SCutMainWindow::OpenTimeline(const FString& TimelineName, bool NeedSaveBefo if (CutTimeline->LoadTimeline(TimelineName, TimelineInfo)) { CutTimeline->TimelineInfo = TimelineInfo; + CutTimeline->CurrentEditDebug->SetText(FText::FromString(TEXT("当前正在编辑") + TimelineInfo.CurrentOpenFullPath)); } } @@ -332,6 +335,17 @@ void SCutMainWindow::OpenProject(const FString& Project) void SCutMainWindow::ExportProject(const FString& ExportPath) { + // Save Project Link + TArray Data {0}; + FMemoryWriter MemoryWriter(Data); + FString CustomInputPanelSavePath = ExportPath + "/" + FGlobalData::CurrentProjectName + "/Dataset/" + TEXT("CustomInputPanel.bin"); + MemoryWriter << CustomInputPanelSavePath; + CustomInputPanel->SavePanel(CustomInputPanelSavePath); + + + FFileHelper::SaveArrayToFile(Data, *(ExportPath + "/" + FGlobalData::CurrentProjectName + "/" + FGlobalData::CurrentProjectName + TEXT("_Link.cutlink"))); + + if (ExportPath.IsEmpty()) return; tinyxml2::XMLDocument Document; @@ -449,14 +463,46 @@ void SCutMainWindow::ExportProject(const FString& ExportPath) - - - - TArray Data {0}; - FFileHelper::SaveArrayToFile(Data, *(ExportPath + "/" + FGlobalData::CurrentProjectName + "/" + FGlobalData::CurrentProjectName + TEXT(".bin"))); Document.SaveFile(TCHAR_TO_UTF8(*(ExportPath + "/" + FGlobalData::CurrentProjectName + "/" + FGlobalData::CurrentProjectName + TEXT(".xml")))); } +void SCutMainWindow::ImportProject(const FString& ImportPath) +{ + FString Path = FPaths::ConvertRelativePathToFull(FPaths::ProjectDir()); + IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); + if (DesktopPlatform) + { + const void* ParentWindowWindowHandle = FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr); + FString OutFolderNames; + bool bFolderSelected = DesktopPlatform->OpenDirectoryDialog(ParentWindowWindowHandle, TEXT("选择项目文件夹"), Path, OutFolderNames); + if (bFolderSelected) + { + // 检查有没有后缀为 cutlink 的文件 + TArray Files; + IFileManager::Get().FindFiles(Files, *OutFolderNames, TEXT("cutlink")); + if (Files.Num() != 0) + { + TArray Data; + FFileHelper::LoadFileToArray(Data, *(OutFolderNames + "/" + Files[0])); + FMemoryReader Reader(Data); + FString CustomPanelInputPath = ""; + Reader << CustomPanelInputPath; + CustomInputPanel->LoadPanel(CustomPanelInputPath); + } + } + } + return; + +} + +void SCutMainWindow::OnSelectCard(const FGuid& SelectedCard) +{ + if (SelectedCard.IsValid()) + { + EffectCardsPanel->SelectCard(SelectedCard); + } +} + FTimelinePropertyData* SCutMainWindow::GetResourcePropertyDataPtr(FGuid GUID) { diff --git a/Source/Cut5/Widgets/SCutMainWindow.h b/Source/Cut5/Widgets/SCutMainWindow.h index 2a10814..39a3a15 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.h +++ b/Source/Cut5/Widgets/SCutMainWindow.h @@ -56,7 +56,10 @@ public: virtual void OpenTimeline(const FString& TimelineName, bool NeedSaveBefore) override; virtual void OpenProject(const FString& Project) override; virtual void ExportProject(const FString& ExportPath) override; + virtual void ImportProject(const FString& ImportPath) override; + virtual void OnSelectCard(const FGuid& SelectedCard) override; + virtual FTimelinePropertyData* GetResourcePropertyDataPtr(FGuid GUID) override; virtual FString GetGroupName(TSharedPtr WidgetInterface) override; }; diff --git a/Source/Cut5/Widgets/SCutTimeline.cpp b/Source/Cut5/Widgets/SCutTimeline.cpp index 82d3842..1784ef1 100644 --- a/Source/Cut5/Widgets/SCutTimeline.cpp +++ b/Source/Cut5/Widgets/SCutTimeline.cpp @@ -84,6 +84,13 @@ void SCutTimeline::Construct(const FArguments& InArgs) SNew(SHorizontalBox) ] + SVerticalBox::Slot() + .SizeParam(FAuto()) + [ + SAssignNew(CurrentEditDebug, STextBlock) + .Text(FText::FromString(TEXT("当前正在编辑主面板"))) + + ] + + SVerticalBox::Slot() [ // Timeline SNew(SHorizontalBox) diff --git a/Source/Cut5/Widgets/SCutTimeline.h b/Source/Cut5/Widgets/SCutTimeline.h index a1fdcc3..f54d5fb 100644 --- a/Source/Cut5/Widgets/SCutTimeline.h +++ b/Source/Cut5/Widgets/SCutTimeline.h @@ -96,6 +96,7 @@ public: TSharedPtr TrackBodyHScrollBox; TSharedPtr TimelineTickBox; TSharedPtr TickScrollBox; + TSharedPtr CurrentEditDebug; TArray TrackGroupInstances; TArray TrackGroups; diff --git a/Source/Cut5/Widgets/STimelineClip.cpp b/Source/Cut5/Widgets/STimelineClip.cpp index 3675ba6..2193c5d 100644 --- a/Source/Cut5/Widgets/STimelineClip.cpp +++ b/Source/Cut5/Widgets/STimelineClip.cpp @@ -195,28 +195,10 @@ void STimelineClip::Seek(int32 Frame) FMemory::Memcpy(MipData, RawData, AllocatedFrame->width * AllocatedFrame->height * 4); Texture->GetPlatformData()->Mips[0].BulkData.Unlock(); Texture->UpdateResource(); - - - MainWidgetInterface->OnUpdateVideo(FGuid::NewGuid(), Texture); delete RawData; } - - - - av_frame_free(&AllocatedFrame); - - // AVFrame* frameRGBA = av_frame_alloc(); - // int numBytes = avpicture_get_size(AV_PIX_FMT_RGBA, VideoCodecContext->width, VideoCodecContext->height); - // uint8_t* buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t)); - // avpicture_fill((AVPicture*)frameRGBA, buffer, AV_PIX_FMT_RGBA, VideoCodecContext->width, VideoCodecContext->height); - // sws_scale(swsCtx, AllocatedFrame->data, AllocatedFrame->linesize, 0, VideoCodecContext->height, frameRGBA->data, frameRGBA->linesize); - // - // UTexture2D* texture = UTexture2D::CreateTransient(VideoCodecContext->width, VideoCodecContext->height); - // FUpdateTextureRegion2D region(0, 0, 0, 0, VideoCodecContext->width, VideoCodecContext->height); - // texture->UpdateTextureRegions(0, 1, ®ion, VideoCodecContext->width * 4, 4, frameRGBA->data[0]); - // MainWidgetInterface->OnUpdateVideo(FGuid::NewGuid(), texture); } break; @@ -243,8 +225,6 @@ void STimelineClip::Seek(int32 Frame) break; case ETrackType::AudioTrack: { - - if (Stream == nullptr) { Pa_Initialize(); diff --git a/Source/Cut5/Widgets/StatePanel/SStatePanel.cpp b/Source/Cut5/Widgets/StatePanel/SStatePanel.cpp index 5be9728..7fe1b10 100644 --- a/Source/Cut5/Widgets/StatePanel/SStatePanel.cpp +++ b/Source/Cut5/Widgets/StatePanel/SStatePanel.cpp @@ -95,7 +95,7 @@ void SStatePanel::Construct(const FArguments& InArgs) ] + SOverlay::Slot() - .HAlign(HAlign_Center) + .HAlign(HAlign_Left) .VAlign(VAlign_Center) [ SNew(SBox) @@ -107,7 +107,7 @@ void SStatePanel::Construct(const FArguments& InArgs) ] ] + SOverlay::Slot() - .HAlign(HAlign_Center) + .HAlign(HAlign_Right) .VAlign(VAlign_Center) [ SNew(SBox) @@ -127,6 +127,15 @@ void SStatePanel::Construct(const FArguments& InArgs) ] ] + + SVerticalBox::Slot() + .SizeParam(FAuto()) + [ + SNew(SBox) + .HeightOverride(125.0) + [ + SAssignNew(PlayerList2, SHorizontalBox) + ] + ] ] ]