保存时间轴功能

This commit is contained in:
Sch 2023-07-20 17:14:31 +08:00
parent 17dbb7e107
commit 53184d30d2
12 changed files with 218 additions and 19 deletions

View File

@ -29,9 +29,10 @@ public:
virtual void OnUpdateLightArray(const TArray<FColor>& LightArray) {};
virtual void OnUpdatePlayers(TSharedPtr<class IWidgetInterface> TrackBody, FColor PlayerColor) {};
virtual void OnAddNewTrack(ETrackType Type) {};
virtual void OnRemoveTrack(FGuid UUID) {};
virtual void OnUpdateSound(uint8* Data, int32 Size) {};
virtual FString GetGroupName(TSharedPtr<class IWidgetInterface> WidgetInterface) { return FString(); };
virtual FTimelinePropertyData* GetResourcePropertyDataPtr(FGuid GUID) { return nullptr; };
};

View File

@ -42,12 +42,27 @@ enum class ETrackType
struct FClipData;
struct CUT5_API FTrackData
{
FTrackData() {};
FTrackData()
{
};
FTrackData(const FString& Name, ETrackType Type)
{
TrackName = Name;
TrackType = Type;
};
friend FArchive& operator<<(FArchive& Ar, FTrackData& TrackData)
{
Ar << TrackData.Guid;
Ar << TrackData.TrackName;
Ar << TrackData.TrackType;
Ar << TrackData.TrackNum;
Ar << TrackData.ClipData;
return Ar;
};
FGuid Guid = FGuid::NewGuid();
FString TrackName = "None";
ETrackType TrackType = ETrackType::VideoTrack;
FSlateBrush Brush;
@ -57,6 +72,24 @@ struct CUT5_API FTrackData
struct CUT5_API FClipData
{
friend FArchive& operator<<(FArchive& Ar, FClipData& ClipData)
{
Ar << ClipData.ClipGuid;
Ar << ClipData.ClipType;
Ar << ClipData.ClipStartTime;
Ar << ClipData.ClipEndTime;
Ar << ClipData.ClipColors;
Ar << ClipData.MoviePath;
Ar << ClipData.VideoStartFrame;
Ar << ClipData.VideoEndFrame;
Ar << ClipData.LightArrayData;
Ar << ClipData.PlayerName;
Ar << ClipData.PlayerLightData;
Ar << ClipData.ResourcePropertyGuid;
return Ar;
};
FGuid ClipGuid;
ETrackType ClipType;
double ClipStartTime = 0;
@ -66,6 +99,8 @@ struct CUT5_API FClipData
int32 GetClipStartFrame() const { return ClipStartTime / FGlobalData::DefaultTimeTickSpace; };
int32 GetClipEndFrame() const { return ClipEndTime / FGlobalData::DefaultTimeTickSpace; };
enum class ECropMethod
{
FromFront,
@ -92,7 +127,7 @@ struct CUT5_API FClipData
}
// A Ptr to Input Resource;
FTimelinePropertyData* ResourcePropertyDataPtr = nullptr;
FGuid ResourcePropertyGuid;
// Movies
FString MoviePath;
@ -109,8 +144,6 @@ struct CUT5_API FClipData
FString PlayerName;
TArray<FColor> PlayerLightData;
// Audio
TObjectPtr<USoundWave> Sound;
};
@ -125,6 +158,8 @@ struct CUT5_API FTimelinePropertyData
FString Name = "";
ETrackType Type = ETrackType::VideoTrack;
FGuid Guid = FGuid::NewGuid();
AVFormatContext* Context = nullptr;
AVCodecContext* CodecContext = nullptr;
AVCodec* Codec = nullptr;

View File

@ -137,7 +137,6 @@ void SCustomInputPanel::Construct(const FArguments& InArgs)
PropertyData.AudioData = DataResult;
PropertyData.CodecContext = CodecContext;
PropertyData.Codec = Codec;
GridPanel->AddSlot(GridPanel->GetChildren()->Num() % 3, GridPanel->GetChildren()->Num() / 3)
[
SNew(SCustomInputResource)

View File

@ -24,6 +24,5 @@ public:
void Construct(const FArguments& InArgs);
virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
virtual FReply OnDragDetected(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
cv::VideoCapture VideoCapture;
};

View File

@ -6,6 +6,7 @@
#include "SCurtainPanel.h"
#include "SCustomInputPanel.h"
#include "SCustomInputResource.h"
#include "SCutTimeline.h"
#include "SlateOptMacros.h"
#include "SPlayerLight.h"
@ -49,6 +50,24 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
[
SAssignNew(CurtainPanel, SCurtainPanel)
]
+ SVerticalBox::Slot()
[
SNew(SButton)
.OnClicked_Lambda([this]()
{
CutTimeline->SaveTimeline("Test.sav");
return FReply::Handled();
})
]
+ SVerticalBox::Slot()
[
SNew(SButton)
.OnClicked_Lambda([this]()
{
CutTimeline->LoadTimeline("Test.sav");
return FReply::Handled();
})
]
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Fill)
@ -97,7 +116,7 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
SNew(SVerticalBox)
+ SVerticalBox::Slot()
[
SNew(SCustomInputPanel)
SAssignNew(CustomInputPanel, SCustomInputPanel)
]
]
@ -209,11 +228,36 @@ void SCutMainWindow::OnAddNewTrack(ETrackType Type)
}
void SCutMainWindow::OnRemoveTrack(FGuid Guid)
{
ICutMainWidgetInterface::OnRemoveTrack(Guid);
Render();
}
void SCutMainWindow::OnUpdateSound(uint8* Data, int32 Size)
{
SoundThread->QueueAudio(Data, Size);
}
FTimelinePropertyData* SCutMainWindow::GetResourcePropertyDataPtr(FGuid GUID)
{
if (!GUID.IsValid())
return nullptr;
if (CustomInputPanel)
{
for (int32 i = 0; i < CustomInputPanel->GridPanel->GetChildren()->Num(); i++)
{
TSharedPtr<SWidget> Widget = CustomInputPanel->GridPanel->GetChildren()->GetChildAt(i);
if (StaticCastSharedPtr<SCustomInputResource>(Widget)->PropertyData.Guid == GUID)
{
return &StaticCastSharedPtr<SCustomInputResource>(Widget)->PropertyData;
}
}
}
return nullptr;
}
FString SCutMainWindow::GetGroupName(TSharedPtr<IWidgetInterface> WidgetInterface)
{
for (FSingleTrackGroupInstance& Instance : CutTimeline->TrackGroupInstances)

View File

@ -4,6 +4,7 @@
#include "CoreMinimal.h"
#include "SCurtainPanel.h"
#include "SCutTimeline.h"
#include "SLightArrayPanel.h"
#include "SPlayerLight.h"
@ -33,6 +34,7 @@ public:
TSharedPtr<SCurtainPanel> CurtainPanel;
TSharedPtr<SHorizontalBox> PlayerGroupsPanel1;
TSharedPtr<SHorizontalBox> PlayerGroupsPanel2;
TSharedPtr<class SCustomInputPanel> CustomInputPanel;
TArray<TSharedPtr<SPlayerLight>> PlayerLightsSlateInstances;
@ -46,6 +48,8 @@ public:
virtual void OnUpdateLightArray(const TArray<FColor>& LightArray) override;
virtual void OnUpdatePlayers(TSharedPtr<class IWidgetInterface> TrackBody, FColor PlayerColor) override;
virtual void OnAddNewTrack(ETrackType Type) override;
virtual void OnRemoveTrack(FGuid Guid) override;
virtual void OnUpdateSound(uint8* Data, int32 Size) override;
virtual FTimelinePropertyData* GetResourcePropertyDataPtr(FGuid GUID) override;
virtual FString GetGroupName(TSharedPtr<IWidgetInterface> WidgetInterface) override;
};

View File

@ -283,6 +283,7 @@ void SCutTimeline::AddNewTrack(FTrackData TrackData, int32 TrackIndex, FString G
{
const TSharedPtr<STrackHead> NewTrackHead = SNew(STrackHead).TrackData(TrackData).CutTimeline(SharedThis(this)).MainWidgetInterface(MainWidgetInterface);
const TSharedPtr<STrackBody> NewTrackBody = SNew(STrackBody).TrackHead(NewTrackHead).MainWidgetInterface(MainWidgetInterface);
NewTrackBody->CallRender();
TrackGroupInstances.Add(FSingleTrackGroupInstance(NewTrackHead, NewTrackBody, GroupName));
}
@ -374,6 +375,95 @@ void SCutTimeline::RenderGroup()
}
}
void SCutTimeline::SaveTimeline(const FString& SavedPath)
{
SetAutoPlay(false);
TArray<uint8> SavedData;
FMemoryWriter MemoryWriter(SavedData);
int32 Length = TrackGroupInstances.Num();
MemoryWriter << Length;
for (FSingleTrackGroupInstance& SingleTrackGroupInstance : TrackGroupInstances)
{
MemoryWriter << SingleTrackGroupInstance.GroupName;
}
for (int32 i = 0; i < TrackGroupInstances.Num(); i++)
{
MemoryWriter << StaticCastSharedPtr<STrackHead>(TrackGroupInstances[i].Head)->TrackData;
}
FFileHelper::SaveArrayToFile(SavedData, *FPaths::Combine(FPaths::ProjectSavedDir(), SavedPath));
}
void SCutTimeline::LoadTimeline(const FString& LoadPath)
{
TArray<uint8> LoadData;
if (!FPaths::IsDrive(LoadPath))
{
FFileHelper::LoadFileToArray(LoadData, *FPaths::Combine(FPaths::ProjectSavedDir(), LoadPath));
}
else
{
FFileHelper::LoadFileToArray(LoadData, *LoadPath);
}
if (LoadData.Num() == 0)
{
return;
}
FMemoryReader MemoryReader(LoadData);
TrackGroupInstances.Empty();
TrackGroups.Empty();
RenderGroup();
int32 Length = 0;
MemoryReader << Length;
TArray<FString> GroupName;
GroupName.Init("", Length);
for (int32 i = 0; i < Length; i++)
{
MemoryReader << GroupName[i];
}
for (int32 i = 0; i < Length; i++)
{
FTrackData TrackData;
MemoryReader << TrackData;
for (FClipData& ClipData : TrackData.ClipData)
{
ClipData.ResourcePropertyDataPtr = MainWidgetInterface->GetResourcePropertyDataPtr(ClipData.ResourcePropertyGuid);
}
AddNewTrackToGroup(GroupName[i], TrackData);
}
}
void SCutTimeline::RemoveTrack(const FGuid& TrackGuid)
{
for (int32 i = 0; i < TrackGroups.Num(); i++)
{
for (int32 j = TrackGroups[i].TrackDataArray.Num() - 1; j >= 0; --j)
{
if (TrackGroups[i].TrackDataArray[j].Guid == TrackGuid)
{
TrackGroups[i].TrackDataArray.RemoveAt(j);
break;
}
}
}
for (int32 i = TrackGroupInstances.Num() - 1; i >= 0; --i)
{
if (StaticCastSharedPtr<STrackHead>(TrackGroupInstances[i].Head)->TrackData.Guid == TrackGuid)
{
TrackGroupInstances.RemoveAt(i);
}
}
RenderGroup();
MainWidgetInterface->OnRemoveTrack(TrackGuid);
}
FReply SCutTimeline::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
// Add new Track

View File

@ -66,9 +66,27 @@ public:
void OnGroupNameEdited(FString NewText, FString OldText);
void RenderGroup();
/**
* @brief Save Current Time line Track to File.
* @param SavedPath Where to save.
*/
void SaveTimeline(const FString& SavedPath);
/**
* @brief Load Time line Track from File.
* @param LoadPath Where to load.
*/
void LoadTimeline(const FString& LoadPath);
/**
* @brief Remove Track from Timeline by UUID.
* @param FGuid Track UUID.
*/
void RemoveTrack(const FGuid& FGuid);
ICutMainWidgetInterface* MainWidgetInterface;
TArray<FTrackGroup> TrackGroups;
TSharedPtr<STimelineTick> TimelineTick;
TSharedPtr<SScrollBox> TrackHeadScrollBox;
TSharedPtr<SScrollBox> TrackGroupScrollBox;
@ -78,7 +96,7 @@ public:
TSharedPtr<SScrollBox> TickScrollBox;
TArray<FSingleTrackGroupInstance> TrackGroupInstances;
TArray<FTrackGroup> TrackGroups;
virtual FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
};

View File

@ -21,7 +21,7 @@ BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const FPointerEvent& PointerEvent)
{
const FVector2D LocalPos = Geometry.AbsoluteToLocal(PointerEvent.GetScreenSpacePosition());
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Blue, LocalPos.ToString());
// GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Blue, LocalPos.ToString());
if (LocalPos.X <= 10)
{
const TSharedPtr<FClip2ClipDragDropOperation> Clip2ClipDragDropOperation = MakeShared<FClip2ClipDragDropOperation>();
@ -62,7 +62,7 @@ void STimelineClip::Construct(const FArguments& InArgs)
];
if (ClipData->ClipType == ETrackType::AudioTrack)
{
av_seek_frame(ClipData->ResourcePropertyDataPtr->Context, 0, 990000000, AVSEEK_FLAG_BACKWARD);
}
}
@ -101,7 +101,7 @@ void STimelineClip::Seek(int32 Frame)
}
}
LastSeekFrame = SeekMovieFrame;
GEngine->AddOnScreenDebugMessage(-1, 10.0F, FColor::Red, FString::Printf(TEXT("Read Time: %f"), (FDateTime::Now() - A).GetTotalMilliseconds()));
// GEngine->AddOnScreenDebugMessage(-1, 10.0F, FColor::Red, FString::Printf(TEXT("Read Time: %f"), (FDateTime::Now() - A).GetTotalMilliseconds()));
cv::Mat Read;
ClipData->VideoCapture->retrieve(Read);
@ -119,7 +119,7 @@ void STimelineClip::Seek(int32 Frame)
RGBAData[i * 4 + 2] = Read.data[i * 3 + 2];
RGBAData[i * 4 + 3] = 255;
}
GEngine->AddOnScreenDebugMessage(-1, 10.0F, FColor::Red, FString::Printf(TEXT("RGBA Time: %f"), (FDateTime::Now() - A).GetTotalMilliseconds()));
// GEngine->AddOnScreenDebugMessage(-1, 10.0F, FColor::Red, FString::Printf(TEXT("RGBA Time: %f"), (FDateTime::Now() - A).GetTotalMilliseconds()));
void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(MipData, RGBAData, Read.cols * Read.rows * 4);
Texture->GetPlatformData()->Mips[0].BulkData.Unlock();

View File

@ -59,7 +59,7 @@ void STrackBody::CallRender()
TimelineClip.ToSharedRef()
];
SlateClips.Add(TimelineClip);
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%f"), TempClipData.ClipEndTime - TempClipData.ClipStartTime));
// GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%f"), TempClipData.ClipEndTime - TempClipData.ClipStartTime));
}
}
@ -91,6 +91,7 @@ FReply STrackBody::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& Dra
NewClipData.ClipType = ClipDragOperation.TimelinePropertyData->Type;
NewClipData.ClipStartTime = FMath::TruncToInt(MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition()).X / FGlobalData::DefaultTimeTickSpace) * FGlobalData::DefaultTimeTickSpace;
NewClipData.ClipColors.Add(FLinearColor(1, 1, 1, 1));
NewClipData.ResourcePropertyGuid = ClipDragOperation.TimelinePropertyData->Guid;
if (ClipDragOperation.TimelinePropertyData->Type == ETrackType::VideoTrack)
{
// 如果拖拽物是视频,那么对不同轨道进行不同和操作
@ -169,7 +170,7 @@ FReply STrackBody::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& Dra
}
TrackHead->TrackData.ClipData.Add(NewClipData);
GEngine->AddOnScreenDebugMessage(-1, 10.0, FColor::Green, FString::Printf(TEXT("Track %d"), TrackHead->TrackData.ClipData.Num()));
// GEngine->AddOnScreenDebugMessage(-1, 10.0, FColor::Green, FString::Printf(TEXT("Track %d"), TrackHead->TrackData.ClipData.Num()));
CallRender();
}
if (DragDropOperation.Type == FCutDragDropBase::EType::Clip2Clip)
@ -241,13 +242,13 @@ FReply STrackBody::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent&
TSharedPtr<STimelineClip> TimelineClip = StaticCastSharedPtr<STimelineClip>(DragDropOperation.DraggingWidget);
TimelineClip->UpdatePosition(MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition()).X);
// show the clip length
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("DragLeft %f / %f"), TimelineClip->ClipData->ClipStartTime, TimelineClip->ClipData->ClipEndTime));
// GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("DragLeft %f / %f"), TimelineClip->ClipData->ClipStartTime, TimelineClip->ClipData->ClipEndTime));
}
if (DragDropOperation.DragType == FClip2ClipDragDropOperation::EDragType::DragRight)
{
TSharedPtr<STimelineClip> TimelineClip = StaticCastSharedPtr<STimelineClip>(DragDropOperation.DraggingWidget);
TimelineClip->UpdateLength(MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition()).X);
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("DragLeft %f / %f"), TimelineClip->ClipData->ClipStartTime, TimelineClip->ClipData->ClipEndTime));
// GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("DragLeft %f / %f"), TimelineClip->ClipData->ClipStartTime, TimelineClip->ClipData->ClipEndTime));
}

View File

@ -79,4 +79,10 @@ void STrackHead::Construct(const FArguments& InArgs)
Image->SetImage(Brush);
}
FReply STrackHead::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
CutTimeline->RemoveTrack(TrackData.Guid);
return FReply::Unhandled();
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -27,4 +27,6 @@ public:
FTrackData TrackData;
TSharedPtr<SCutTimeline> CutTimeline;
ICutMainWidgetInterface* MainWidgetInterface;
virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
};