上传新的时间线绘图

This commit is contained in:
Sch 2023-07-12 16:57:44 +08:00
parent 6b02499289
commit d6317fd7e2
16 changed files with 48 additions and 177 deletions

View File

@ -13,7 +13,7 @@ public class Cut5 : ModuleRules
PrivateDependencyModuleNames.AddRange(new string[] { });
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore", "UMG", "OpenCV", "DesktopPlatform", "RuntimeAudioImporter"});
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore", "UMG", "OpenCV", "DesktopPlatform"});
// Uncomment if you are using online features
// PrivateDependencyModuleNames.Add("OnlineSubsystem");

View File

@ -29,8 +29,7 @@ public:
virtual void OnUpdateLightArray(const TArray<FColor>& LightArray) {};
virtual void OnUpdatePlayers(TSharedPtr<class IWidgetInterface> TrackBody, FColor PlayerColor) {};
virtual void OnAddNewTrack(ETrackType Type) {};
virtual TObjectPtr<UAudioComponent> OnPlaySound(USoundWave* Sound, float StartTime) { return nullptr; };
virtual void OnStopSound(TObjectPtr<UAudioComponent> Component) {};
virtual FString GetGroupName(TSharedPtr<class IWidgetInterface> WidgetInterface) { return FString(); };

View File

@ -3,9 +3,6 @@
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include "IImageWrapperModule.h"
#include "ImageUtils.h"
int32 FOpencvUtils::GetVideoFrameCount(FString VideoPath)
{
cv::VideoCapture VideoCapture;
@ -88,42 +85,3 @@ TArray<FColor> FOpencvUtils::GetVideoSingleLightColor(FString VideoPath)
VideoCapture.release();
return LightArray;
}
FString FOpencvUtils::GetVideoFrameIconName(FString VideoPath)
{
cv::VideoCapture VideoCapture;
VideoCapture.open(TCHAR_TO_UTF8(*VideoPath));
TArray<FColor> LightArray;
while (VideoCapture.isOpened())
{
cv::Mat Array;
if (VideoCapture.grab())
{
VideoCapture.retrieve(Array);
cv::resize(Array, Array, cv::Size(600, 360));
uint8* RGBAData = new uint8[Array.cols * Array.rows * 4];
for (int i = 0; i < Array.cols * Array.rows; i++)
{
RGBAData[i * 4 + 0] = Array.data[i * 3 + 2];
RGBAData[i * 4 + 1] = Array.data[i * 3 + 1];
RGBAData[i * 4 + 2] = Array.data[i * 3 + 0];
RGBAData[i * 4 + 3] = 255;
LightArray.Add(FColor(RGBAData[i * 4 + 0], RGBAData[i * 4 + 1], RGBAData[i * 4 + 2], RGBAData[i * 4 + 3]));
}
delete[] RGBAData;
break;
}
if (Array.empty())
{
break;
}
}
VideoCapture.release();
TArray64<uint8> PNGCompress;
FString SavePath = FPaths::ProjectDir() + "/Temp/" + FGuid::NewGuid().ToString() + ".png";
FImageUtils::PNGCompressImageArray(600, 480, LightArray, PNGCompress);
FFileHelper::SaveArrayToFile(PNGCompress, *SavePath);
return SavePath;
}

View File

@ -8,6 +8,5 @@ public:
static int32 GetVideoFrameCount(FString VideoPath);
static TArray<TArray<FColor>> GetVideoFrameLightArray(FString VideoPath, int32 X, int32 Y);
static TArray<FColor> GetVideoSingleLightColor(FString VideoPath);
static FString GetVideoFrameIconName(FString VideoPath);
};

View File

@ -8,11 +8,11 @@ class CUT5_API FGlobalData
{
public:
inline static int32 DefaultTrackHeight = 50;
inline static int32 TrackLength = 1000;
inline static int32 TrackLength = 10000;
inline static double DefaultTimeTickSpace = 9.0;
inline static int32 LightArrayX = 70;
inline static int32 LightArrayY = 42;
inline static int32 GlobalFPS = 30;
inline static float CurrentTimeScroll = 0.0f;
static int32 GetAlignOfTickSpace(double Align, bool bCeil = false)
{
return bCeil ? FMath::CeilToInt(Align / FGlobalData::DefaultTimeTickSpace) * FGlobalData::DefaultTimeTickSpace :
@ -45,7 +45,6 @@ struct CUT5_API FTrackData
FSlateBrush Brush;
int32 TrackNum = 1;
TArray<FClipData> ClipData;
};
struct CUT5_API FClipData
@ -99,8 +98,6 @@ struct CUT5_API FClipData
FString PlayerName;
TArray<FColor> PlayerLightData;
// Sound
TObjectPtr<USoundWave> Sound;
};
struct CUT5_API FTimelinePropertyData
@ -117,11 +114,6 @@ struct CUT5_API FTimelinePropertyData
// Movie Data
FString MoviePath = "";
int32 MovieFrameLength = 0;
FString IconPath;
// AudioData
TObjectPtr<USoundWave> Sound;
};
class CUT5_API FCutDragDropBase : public FDecoratedDragDropOp

View File

@ -14,7 +14,6 @@
#undef check
#include <opencv2/videoio.hpp>
#include "RuntimeAudioImporterLibrary.h"
#include "Cut5/Utils/OpencvUtils.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
@ -60,45 +59,8 @@ void SCustomInputPanel::Construct(const FArguments& InArgs)
for (int32 i = 0; i < OpenFileName.Num(); i++)
{
if (FPaths::GetExtension(OpenFileName[i]) == "mp3")
{
URuntimeAudioImporterLibrary* AudioImporter = URuntimeAudioImporterLibrary::CreateRuntimeAudioImporter();
AudioImporter->ImportAudioFromFile(OpenFileName[i], ERuntimeAudioFormat::Auto);
AudioImporter->OnResultNoDynamic.AddLambda([&, OpenFileName, i](URuntimeAudioImporterLibrary* Importer,
UImportedSoundWave* ImportedSoundWave, ERuntimeImportStatus Status)
{
switch (Status)
{
case ERuntimeImportStatus::SuccessfulImport:
{
FTimelinePropertyData PropertyData;
PropertyData.Name = OpenFileName[i];
PropertyData.Type = ETrackType::AudioTrack;
PropertyData.MoviePath = OpenFileName[i];
PropertyData.Sound = ImportedSoundWave;
PropertyData.MovieFrameLength = ImportedSoundWave->GetDuration() * FGlobalData::GlobalFPS;
GridPanel->AddSlot(GridPanel->GetChildren()->Num() % 3, GridPanel->GetChildren()->Num() / 3)
[
SNew(SCustomInputResource)
.PropertyData(PropertyData)
];
}
break;
default:
break;
}
});
return FReply::Handled();
}
Async(EAsyncExecution::Thread, [&, this, OpenFileName, i]
{
if (FPaths::GetExtension(OpenFileName[i]) != "mp4")
{
}
FString IconPath = FOpencvUtils::GetVideoFrameIconName(OpenFileName[i]);
cv::VideoCapture NewCapture(TCHAR_TO_UTF8(*OpenFileName[i]));
const int32 FrameCount = NewCapture.get(cv::CAP_PROP_FRAME_COUNT);
@ -109,7 +71,6 @@ void SCustomInputPanel::Construct(const FArguments& InArgs)
PropertyData.Type = ETrackType::VideoTrack;
PropertyData.MoviePath = OpenFileName[i];
PropertyData.MovieFrameLength = FrameCount;
PropertyData.IconPath = IconPath;
GridPanel->AddSlot(GridPanel->GetChildren()->Num() % 3, GridPanel->GetChildren()->Num() / 3)
[
SNew(SCustomInputResource)
@ -137,5 +98,4 @@ FReply SCustomInputPanel::OnDrop(const FGeometry& MyGeometry, const FDragDropEve
return FReply::Handled().EndDragDrop();
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -3,7 +3,6 @@
#pragma once
#include "CoreMinimal.h"
#include "RuntimeAudioImporterLibrary.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Layout/SGridPanel.h"
@ -23,7 +22,6 @@ public:
void Construct(const FArguments& InArgs);
virtual FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
TSharedPtr<SGridPanel> GridPanel;
};

View File

@ -12,7 +12,6 @@ void SCustomInputResource::Construct(const FArguments& InArgs)
{
PropertyData = InArgs._PropertyData;
VideoCapture = InArgs._VideoCapture;
FSlateDynamicImageBrush* SlateDynamicImageBrush = new FSlateDynamicImageBrush(*PropertyData.IconPath, FVector2D(600, 360));
ChildSlot
[
SNew(SBox)
@ -30,8 +29,9 @@ void SCustomInputResource::Construct(const FArguments& InArgs)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SImage).Image(SlateDynamicImageBrush)
SNew(SImage)
]
]
];

View File

@ -11,7 +11,6 @@
#include "STimelinePropertyPanel.h"
#include "STrackBody.h"
#include "STrackHead.h"
#include "Components/AudioComponent.h"
#include "Widgets/Layout/SConstraintCanvas.h"
#include "Widgets/Layout/SScaleBox.h"
#include "Widgets/Views/STreeView.h"
@ -206,24 +205,6 @@ void SCutMainWindow::OnAddNewTrack(ETrackType Type)
}
}
TObjectPtr<UAudioComponent> SCutMainWindow::OnPlaySound(USoundWave* Sound, float StartTime)
{
UAudioComponent* AudioComponent = NewObject<UAudioComponent>();
AudioComponent->SetActive(true);
AudioComponent->Activate(true);
const TObjectPtr<UAudioComponent> AudioComponentPtr = AudioComponent;
AudioComponents.Add(AudioComponentPtr);
AudioComponent->SetSound(Sound);
AudioComponent->Play(StartTime);
return AudioComponentPtr;
}
void SCutMainWindow::OnStopSound(TObjectPtr<UAudioComponent> Component)
{
Component->Stop();
AudioComponents.Remove(Component);
}
FString SCutMainWindow::GetGroupName(TSharedPtr<IWidgetInterface> WidgetInterface)
{
for (FSingleTrackGroupInstance& Instance : CutTimeline->TrackGroupInstances)

View File

@ -45,9 +45,5 @@ 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 TObjectPtr<UAudioComponent> OnPlaySound(USoundWave* Sound, float StartTime) override;
virtual void OnStopSound(TObjectPtr<UAudioComponent> Component) override;
TArray<TObjectPtr<UAudioComponent>> AudioComponents;
virtual FString GetGroupName(TSharedPtr<IWidgetInterface> WidgetInterface) override;
};

View File

@ -164,6 +164,7 @@ void SCutTimeline::Construct(const FArguments& InArgs)
{
TrackBodyHScrollBox->SetScrollOffset(ChangedValue * TrackBodyHScrollBox->GetScrollOffsetOfEnd());
TickScrollBox->SetScrollOffset(ChangedValue * TickScrollBox->GetScrollOffsetOfEnd());
FGlobalData::CurrentTimeScroll = ChangedValue;
})
]
// + SVerticalBox::Slot()
@ -222,10 +223,8 @@ void SCutTimeline::Construct(const FArguments& InArgs)
];
TrackHeadScrollBox->SetScrollBarVisibility(EVisibility::Hidden);
FTrackData AudioDataL(TEXT("音频L"), ETrackType::AudioTrack);
AddNewTrackToGroup(TEXT("固定轨道"), AudioDataL);
FTrackData AudioDataR(TEXT("音频R"), ETrackType::AudioTrack);
AddNewTrackToGroup(TEXT("固定轨道"), AudioDataR);
FTrackData AudioData(TEXT("音频"), ETrackType::AudioTrack);
AddNewTrackToGroup(TEXT("固定轨道"), AudioData);
FTrackData ProjectorData(TEXT("投影仪"), ETrackType::ProjectorTrack);
AddNewTrackToGroup(TEXT("固定轨道"), ProjectorData);
FTrackData VideoData(TEXT("视频"), ETrackType::VideoTrack);

View File

@ -3,12 +3,11 @@
#include "STimelineClip.h"
#include "AudioDevice.h"
#include "SlateOptMacros.h"
#include "Components/AudioComponent.h"
#include "Cut5/WidgetInterface.h"
#include "Engine/Engine.h"
#include "Engine/Texture2D.h"
#include "Kismet/GameplayStatics.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
@ -55,11 +54,7 @@ void STimelineClip::Construct(const FArguments& InArgs)
]
];
if (ClipData->ClipType == ETrackType::AudioTrack)
{
AudioComponent = NewObject<UAudioComponent>();
AudioComponent->SetSound(ClipData->Sound);
}
}
void STimelineClip::Seek(int32 Frame)
@ -96,6 +91,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()));
cv::Mat Read;
ClipData->VideoCapture->retrieve(Read);
@ -113,6 +109,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()));
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();
@ -146,28 +143,14 @@ void STimelineClip::Seek(int32 Frame)
break;
case ETrackType::AudioTrack:
{
const int32 Offset = Frame - (ClipData->ClipStartTime / FGlobalData::DefaultTimeTickSpace);
const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset;
if (bIsPlaying == true)
{
if (SeekMovieFrame >= ClipData->VideoEndFrame)
{
MainWidgetInterface->OnStopSound(AudioComponent);
AudioComponent = nullptr;
bIsPlaying = false;
}
}
else
{
AudioComponent = MainWidgetInterface->OnPlaySound(ClipData->Sound, static_cast<float>(SeekMovieFrame) / 30.0f);
bIsPlaying = true;
}
// 在UE中如何操作声音设备
//
USoundWaveProcedural* SoundWave = NewObject<USoundWaveProcedural>();
SoundWave->SampleByteSize
FPlatformAudioCookOverrides
GEngine->GetMainAudioDevice()->PlaySoundAtLocation()
}
break;
default:
break;
}

View File

@ -39,9 +39,5 @@ public:
virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
TSharedPtr<IWidgetInterface> Body;
int32 LastSeekFrame = 0;
bool bIsPlaying = false;
// Sound
TObjectPtr<UAudioComponent> AudioComponent;
};

View File

@ -3,6 +3,7 @@
#include "STimelineTick.h"
#include "AudioDevice.h"
#include "DefineGlobal.h"
#include "SlateOptMacros.h"
@ -24,16 +25,18 @@ void STimelineTick::Construct(const FArguments& InArgs)
[
SAssignNew(TickCursor, SImage)
.RenderTransform(NewRenderTransform)
.ColorAndOpacity(FColor(255, 255, 0, 255))
]
]
];
GenerateTickBox(FGlobalData::TrackLength / FGlobalData::DefaultTimeTickSpace);
}
void STimelineTick::UpdateNewCursorPosition(const float Position)
{
const FSlateRenderTransform NewRenderTransform =
::Concatenate(FScale2D(0.3, 29), FShear2D(0, 0), FQuat2D(FMath::DegreesToRadians(0)), FVector2D(Position, -2));
::Concatenate(FScale2D(0.3, 38), FShear2D(0, 0), FQuat2D(FMath::DegreesToRadians(0)), FVector2D(Position, -2));
if (TickCursor)
{
TickCursor->SetRenderTransform(NewRenderTransform);
@ -43,17 +46,31 @@ void STimelineTick::UpdateNewCursorPosition(const float Position)
void STimelineTick::GenerateTickBox(int32 TickCount)
{
for (int32 i = 0; i < TickCount; i++)
}
int32 STimelineTick::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect,
FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle,
bool bParentEnabled) const
{
int32 TickCount = //(FGlobalData::TrackLength * FGlobalData::CurrentTimeScroll) / FGlobalData::DefaultTimeTickSpace;
FGlobalData::TrackLength / FGlobalData::DefaultTimeTickSpace;
for (int32 j = 0; j < TickCount; j++)
{
TSharedPtr<STextBlock> TickText = SNew(STextBlock).Text(FText::FromString("|"));
TickBox->AddSlot()
[
TickText.ToSharedRef()
];
TickText->SetRenderTransform(FSlateRenderTransform(FVector2D(i * FGlobalData::DefaultTimeTickSpace, 0)));
const FSlateBrush Brush;
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId,
AllottedGeometry.ToPaintGeometry(FVector2f(2, TickBox->GetCachedGeometry().GetLocalSize().Y), FSlateLayoutTransform(FVector2f(TickBox->GetCachedGeometry().GetLocalPositionAtCoordinates(FVector2f(0.0, 0.0)).X + j * FGlobalData::DefaultTimeTickSpace, 0.0))),
&Brush,
ESlateDrawEffect::None,
FColor(255, 255, 255, 255));
}
return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle,
bParentEnabled);
}
FReply STimelineTick::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)

View File

@ -23,6 +23,7 @@ public:
void Construct(const FArguments& InArgs);
void UpdateNewCursorPosition(const float Position);
void GenerateTickBox(int32 TickCount);
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
int32 GetCursorPosition() const { return CursorPosition; };
TSharedPtr<SOverlay> TickBox;
TSharedPtr<SBox> TickLengthBox;

View File

@ -91,7 +91,6 @@ 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));
// 对拖拽物进行不同的操作
if (ClipDragOperation.TimelinePropertyData.Type == ETrackType::VideoTrack)
{
// 如果拖拽物是视频,那么对不同轨道进行不同和操作
@ -110,19 +109,12 @@ FReply STrackBody::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& Dra
NewClipData.PlayerLightData = FOpencvUtils::GetVideoSingleLightColor(ClipDragOperation.TimelinePropertyData.MoviePath);
}
}
// 如果拖拽物是音频
else if (ClipDragOperation.TimelinePropertyData.Type == ETrackType::AudioTrack)
{
NewClipData.Sound = ClipDragOperation.TimelinePropertyData.Sound;
NewClipData.ClipEndTime = NewClipData.ClipStartTime + ClipDragOperation.TimelinePropertyData.MovieFrameLength * FGlobalData::DefaultTimeTickSpace;
NewClipData.VideoEndFrame = ClipDragOperation.TimelinePropertyData.MovieFrameLength;
}
else if (ClipDragOperation.TimelinePropertyData.Type == ETrackType::PlayerTrack)
else if (ClipDragOperation.TimelinePropertyData.Type == ETrackType::LightArrayTrack)
{
NewClipData.ClipEndTime = NewClipData.ClipStartTime + 200;
}
//Overwrite the clip if it is in the same position
for (int32 i = TrackHead->TrackData.ClipData.Num() - 1; i >= 0; i--)