8.23 - 02

1.删除轨道后 轨道组没有对齐 O
2. 纹理回收后导致崩溃  O
3. 拖拽预设会根据当前条长度变化 O
4. 轨道复制片段到其他轨道 O
5. SCutmaininterface 577行报错 O
6. 时间轴自己分离移动了 O
7. 加一个移动时间轴的时候显示时间码功能 O
8. 时间轴tick离近了会取消显示一部分数字 O
9. 音频播放不了 O
10. 幕拖动和上下移 O
11. 片段点阵播放不了 O
This commit is contained in:
Sch 2023-08-23 20:56:11 +08:00
parent 5953ee70dc
commit 69ba93ba53
18 changed files with 553 additions and 179 deletions

View File

@ -1,4 +1,5 @@
#include "FFMPEGUtils.h"
#include "FFMPEGUtils.h"
#include "CanvasTypes.h"
#include "ImageUtils.h"
@ -21,7 +22,7 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
{
return TEXT("Failed");
}
PropertyData->MovieFrameLength = FormatContext->duration / AV_TIME_BASE * 30;
PropertyData->MovieFrameLength = FormatContext->duration / AV_TIME_BASE * FGlobalData::GlobalFPS;
int32 VideoStream = -1;
int32 AudioStream = -1;
for (unsigned int i = 0; i < FormatContext->nb_streams; i++) {
@ -92,6 +93,7 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
FGuid Guid = FGuid::NewGuid();
ExportImage(Texture, *FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, "Resources", "Thumbnail", Guid.ToString() + ".png"));
PropertyData->IconPath = FPaths::Combine(FGlobalData::BasePath, FGlobalData::CurrentProjectName, "Resources", "Thumbnail", Guid.ToString() + ".png");
Texture->MarkAsGarbage();
delete RawData;
}
}
@ -168,6 +170,75 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
return {};
}
FString FFFMPEGUtils::LoadContextPure(const FString& Path, FTimelinePropertyData* PropertyData)
{
AVFormatContext* FormatContext = nullptr;
if (avformat_open_input(&FormatContext, TCHAR_TO_UTF8(*Path), nullptr, nullptr) != 0)
{
return TEXT("Failed");
}
if (avformat_find_stream_info(FormatContext, nullptr) < 0)
{
return TEXT("Failed");
}
PropertyData->MovieFrameLength = FormatContext->duration / AV_TIME_BASE * FGlobalData::GlobalFPS;
int32 VideoStream = -1;
int32 AudioStream = -1;
for (unsigned int i = 0; i < FormatContext->nb_streams; i++) {
if (FormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
VideoStream = i;
} else if (FormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
AudioStream = i;
}
}
if (VideoStream != -1)
{
AVCodecContext* VideoCodecContext = avcodec_alloc_context3(nullptr);
avcodec_parameters_to_context(VideoCodecContext, FormatContext->streams[VideoStream]->codecpar);
AVCodec* VideoCodec = avcodec_find_decoder(VideoCodecContext->codec_id);
VideoCodecContext->time_base = AVRational({1, 30});
VideoCodecContext->gop_size = 1;
if (avcodec_open2(VideoCodecContext, VideoCodec, nullptr) < 0)
{
return TEXT("Failed");
}
PropertyData->VideoCodec = VideoCodec;
PropertyData->VideoCodecContext = VideoCodecContext;
}
if (AudioStream != -1)
{
AVCodecContext* AudioCodecContext = avcodec_alloc_context3(nullptr);
avcodec_parameters_to_context(AudioCodecContext, FormatContext->streams[AudioStream]->codecpar);
AVCodec* AudioCodec = avcodec_find_decoder(AudioCodecContext->codec_id);
if (avcodec_open2(AudioCodecContext, AudioCodec, nullptr) < 0)
{
return TEXT("Failed");
}
PropertyData->AudioCodecContext = AudioCodecContext;
PropertyData->AudioCodec = AudioCodec;
PropertyData->AudioSample = AudioCodecContext->sample_rate;
PropertyData->AudioChannels = AudioCodecContext->channels;
}
PropertyData->VideoStream = VideoStream;
PropertyData->AudioStream = AudioStream;
PropertyData->Context = FormatContext;
if (VideoStream != -1)
{
PropertyData->Type = ETrackType::VideoTrack;
}
else if (AudioStream != -1)
{
PropertyData->Type = ETrackType::AudioTrack;
}
PropertyData->Name = FPaths::GetBaseFilename(Path);
PropertyData->MoviePath = Path;
return {};
}
FString FFFMPEGUtils::ConvertMediaGoPto1(const FString& Path)
{
AVFormatContext* FormatContext = nullptr;
@ -239,18 +310,17 @@ bool FFFMPEGUtils::ExportImage(UTexture2D* Texture2D, const FString& Path)
TArray<FSlateBrush> FFFMPEGUtils::GetMovieBrush(FClipData* ClipData, bool Regenerate)
{
TArray<FSlateBrush> Result;
ClipData->MovieBrushes.Empty();
ClipData->MovieBrushNum = 0;
if (ClipData->MovieBrushesPath.Num() > 0 && !Regenerate)
{
for (int32 i = 0; i < ClipData->MovieBrushesPath.Num(); i++)
{
FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ClipData->MovieBrushesPath[i], FVector2f(0, 0));
ClipData->MovieBrushNum++;
Result.Add(Brush);
}
return Result;
}
@ -279,68 +349,68 @@ TArray<FSlateBrush> FFFMPEGUtils::GetMovieBrush(FClipData* ClipData, bool Regene
for (int32 i = 0; i < FrameNum; i++)
{
// 得到视频总帧数
int64 Timestamp = av_rescale_q((i * (TotalFrame / 128) + ClipData->VideoStartFrame) / 30.0 * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, ClipData->ResourcePropertyDataPtr->Context->streams[ClipData->ResourcePropertyDataPtr->VideoStream]->time_base);
av_seek_frame(ClipData->ResourcePropertyDataPtr->Context, ClipData->ResourcePropertyDataPtr->VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD);
AVPacket Packet;
av_init_packet(&Packet);
AVFormatContext* FormatContext = ClipData->ResourcePropertyDataPtr->Context;
AVCodecContext* VideoCodecContext = ClipData->ResourcePropertyDataPtr->VideoCodecContext;
AVCodec* VideoCodec = ClipData->ResourcePropertyDataPtr->VideoCodec;
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 / 10, Frame->height / 10, AV_PIX_FMT_BGRA,
SWS_BILINEAR, NULL, NULL, NULL
);
if (!swsCtx)
{
UE_LOG(LogTemp, Error, TEXT("Error creating swsContext"));
}
uint8* RawData = new uint8[(Frame->width / 10) * (Frame->height / 10) * 4];
uint8* dest[4] = {RawData, 0, 0, 0};
int32 dest_linesize[4] = {(Frame->width / 10) * 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 / 10, Frame->height / 10, PF_B8G8R8A8);
if (Texture)
{
void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(MipData, RawData, (Frame->width / 10) * (Frame->height / 10) * 4);
Texture->GetPlatformData()->Mips[0].BulkData.Unlock();
Texture->UpdateResource();
FGuid Guid = FGuid::NewGuid();
ExportImage(Texture, *FPaths::Combine(FUtils::GetTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png"));
ClipData->MovieBrushesPath.Add(FPaths::Combine(FUtils::GetTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png"));
FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ClipData->MovieBrushesPath[i], FVector2f(0, 0));
Result.Add(Brush);
delete RawData;
}
}
ClipData->MovieBrushNum ++;
// int64 Timestamp = av_rescale_q((i * (TotalFrame / 128) + ClipData->VideoStartFrame) / 30.0 * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, ClipData->ResourcePropertyDataPtr->Context->streams[ClipData->ResourcePropertyDataPtr->VideoStream]->time_base);
// av_seek_frame(ClipData->ResourcePropertyDataPtr->Context, ClipData->ResourcePropertyDataPtr->VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD);
// AVPacket Packet;
// av_init_packet(&Packet);
// AVFormatContext* FormatContext = ClipData->ResourcePropertyDataPtr->Context;
// AVCodecContext* VideoCodecContext = ClipData->ResourcePropertyDataPtr->VideoCodecContext;
// AVCodec* VideoCodec = ClipData->ResourcePropertyDataPtr->VideoCodec;
// 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 / 10, Frame->height / 10, AV_PIX_FMT_BGRA,
// SWS_BILINEAR, NULL, NULL, NULL
// );
// if (!swsCtx)
// {
// UE_LOG(LogTemp, Error, TEXT("Error creating swsContext"));
// }
// uint8* RawData = new uint8[(Frame->width / 10) * (Frame->height / 10) * 4];
// uint8* dest[4] = {RawData, 0, 0, 0};
// int32 dest_linesize[4] = {(Frame->width / 10) * 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 / 10, Frame->height / 10, PF_B8G8R8A8);
// if (Texture)
// {
// void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
// FMemory::Memcpy(MipData, RawData, (Frame->width / 10) * (Frame->height / 10) * 4);
// Texture->GetPlatformData()->Mips[0].BulkData.Unlock();
// Texture->UpdateResource();
//
// FGuid Guid = FGuid::NewGuid();
// ExportImage(Texture, *FPaths::Combine(FUtils::GetTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png"));
// ClipData->MovieBrushesPath.Add(FPaths::Combine(FUtils::GetTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png"));
// FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ClipData->MovieBrushesPath[i], FVector2f(0, 0));
// Result.Add(Brush);
//
// delete RawData;
// }
//
//
// }
}
}
return Result;
@ -470,7 +540,7 @@ TArray<FSlateBrush> FFFMPEGUtils::GetAudioBrush(FClipData* ClipData)
FBufferArchive Buffer;
FImageUtils::ExportRenderTarget2DAsPNG(TextureRenderTarget2D, Buffer);
FFileHelper::SaveArrayToFile(Buffer, *FPaths::Combine(FUtils::GetTempPath(), ClipData->ClipGuid.ToString(), FString::FromInt(Index) + ".png"));
TextureRenderTarget2D->MarkAsGarbage();
FSlateDynamicImageBrush SlateBrush = FSlateDynamicImageBrush(*FPaths::Combine(FUtils::GetTempPath(), ClipData->ClipGuid.ToString(), FString::FromInt(Index) + ".png"), FVector2D(PicLength, FGlobalData::DefaultTrackHeight));
ClipData->AudioBrushLength.Add(PicLength);
ClipData->AudioBrushes.Add(SlateBrush);
@ -488,3 +558,48 @@ TArray<FSlateBrush> FFFMPEGUtils::GetAudioBrush(FClipData* ClipData)
return {};
}
TArray<TArray<FColor>> FFFMPEGUtils::GetVideoFrameLightArray(FString VideoPath, int32 X, int32 Y)
{
FTimelinePropertyData TimelinePropertyData;
LoadContextPure(VideoPath, &TimelinePropertyData);
TArray<TArray<FColor>> Colors;
if (TimelinePropertyData.Context == nullptr)
return {};
AVPacket* Packet = av_packet_alloc();
AVFrame* Frame = av_frame_alloc();
while (1)
{
TArray<FColor> Color;
if (av_read_frame(TimelinePropertyData.Context, Packet) < 0)
{
if (av_read_frame(TimelinePropertyData.Context, Packet) < 0)
{
break;
}
}
avcodec_send_packet(TimelinePropertyData.VideoCodecContext, Packet);
if (avcodec_receive_frame(TimelinePropertyData.VideoCodecContext, Frame) >= 0)
{
if (SwsContext* SwsContext = sws_getContext(
Frame->width, Frame->height, TimelinePropertyData.VideoCodecContext->pix_fmt,
FGlobalData::LightArrayX, FGlobalData::LightArrayY, AV_PIX_FMT_RGBA,
SWS_BILINEAR, nullptr, nullptr, nullptr))
{
uint8* RawData = new uint8[FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4];
uint8* Dest[4] = {RawData, nullptr, nullptr, nullptr};
int32 DestLineSize[4] = {FGlobalData::LightArrayX * 4, 0, 0, 0};
sws_scale(SwsContext, Frame->data, Frame->linesize, 0, Frame->height, Dest, DestLineSize);
sws_freeContext(SwsContext);
for (int i = 0; i < FGlobalData::LightArrayX * FGlobalData::LightArrayY; i++)
{
Color.Add(FColor(RawData[i * 4 + 0], RawData[i * 4 + 1], RawData[i * 4 + 2], RawData[i * 4 + 3]));
}
Colors.Add(Color);
}
}
}
return Colors;
}

View File

@ -14,8 +14,11 @@ struct FFFMPEGUtils
* @return Return Paths
*/
static FString LoadMedia(const FString& Path, FTimelinePropertyData* PropertyData);
static FString LoadContextPure(const FString& Path, FTimelinePropertyData* PropertyData);
static FString ConvertMediaGoPto1(const FString& Path);
static bool ExportImage(UTexture2D* Texture2D, const FString& Path);
static TArray<TArray<FColor>> GetVideoFrameLightArray(FString VideoPath, int32 X, int32 Y);
static TArray<FSlateBrush> GetMovieBrush(struct FClipData* ClipData, bool Regenerate = false);
static TArray<FSlateBrush> GetAudioBrush(struct FClipData* ClipData);

View File

@ -22,6 +22,10 @@ public:
TSharedPtr<FUICommandInfo> TimelineMoveLeft;
TSharedPtr<FUICommandInfo> TimelineMoveRight;
TSharedPtr<FUICommandInfo> StartCollectGarbage;
TSharedPtr<FUICommandInfo> EndCollectGarbage;
TSharedPtr<FUICommandInfo> Copy;
TSharedPtr<FUICommandInfo> Paste;
};

View File

@ -14,6 +14,12 @@ void FShortCutCommands::RegisterCommands()
UI_COMMAND(RightPerFrame, "右移一帧", "Executes My FCurtainCommands", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::RightBracket));
UI_COMMAND(TimelineMoveLeft, "左侧移动时间轴", "Executes My FCurtainCommands", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::MouseScrollDown, EModifierKey::Shift));
UI_COMMAND(TimelineMoveRight, "右侧移动时间轴", "Executes My FCurtainCommands", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::MouseScrollUp, EModifierKey::Shift));
UI_COMMAND(StartCollectGarbage, "启用垃圾回收", "Executes Start Garbage Collect", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::O, EModifierKey::Shift));
UI_COMMAND(EndCollectGarbage, "结束垃圾回收", "Executes End Garbage Collect", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::P, EModifierKey::Shift));
UI_COMMAND(Copy, "复制", "Executes Start Garbage Collect", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::C, EModifierKey::Control));
UI_COMMAND(Paste, "粘贴", "Executes End Garbage Collect", EUserInterfaceActionType::ToggleButton, FInputChord(EKeys::V, EModifierKey::Control));
}
#undef LOCTEXT_NAMESPACE

View File

@ -36,13 +36,39 @@ void SCurtainPanel::Construct(const FArguments& InArgs)
{
RenameCurtain();
}));
CommandList->MapAction(FCurtainCommands::Get().MoveUp, FExecuteAction::CreateLambda([]()
CommandList->MapAction(FCurtainCommands::Get().MoveUp, FExecuteAction::CreateLambda([this]()
{
if (!IsCurtainGroup(SelectedGuid))
{
FCurtainGroup* Group = nullptr;
FCurtain* Curtain = FindCurtain(SelectedGuid, Group);
if (Curtain - Group->Curtains.GetData() - 1 >= 0)
{
Move(Curtain - Group->Curtains.GetData(), Curtain - Group->Curtains.GetData() - 1, Group - Groups.GetData(), Group - Groups.GetData());
}
}
else
{
}
}));
CommandList->MapAction(FCurtainCommands::Get().MoveDown, FExecuteAction::CreateLambda([]()
CommandList->MapAction(FCurtainCommands::Get().MoveDown, FExecuteAction::CreateLambda([this]()
{
if (!IsCurtainGroup(SelectedGuid))
{
FCurtainGroup* Group = nullptr;
FCurtain* Curtain = FindCurtain(SelectedGuid, Group);
if ((Curtain - Group->Curtains.GetData() + 1) < Group->Curtains.Num())
{
Move(Curtain - Group->Curtains.GetData(), Curtain - Group->Curtains.GetData() + 2, Group - Groups.GetData(), Group - Groups.GetData());
}
}
else
{
}
}));
CommandList->MapAction(FCurtainCommands::Get().InsertUp, FExecuteAction::CreateLambda([this]()
{
@ -396,4 +422,44 @@ void SCurtainPanel::RenameCurtain()
}
}
FCurtain* SCurtainPanel::FindCurtain(const FGuid& Guid, FCurtainGroup*& OutGroup)
{
for (FCurtainGroup& Group : Groups)
{
for (FCurtain& Curtain : Group.Curtains)
{
if (Curtain.CurtainUUID == Guid)
{
OutGroup = &Group;
return &Curtain;
}
}
}
return nullptr;
}
FCurtainGroup* SCurtainPanel::FindCurtainGroup(const FGuid& Guid)
{
for (FCurtainGroup& Group : Groups)
{
if (Group.GroupUID == Guid)
{
return &Group;
}
}
return nullptr;
}
bool SCurtainPanel::IsCurtainGroup(const FGuid& Guid)
{
for (FCurtainGroup& Group : Groups)
{
if (Group.GroupUID == Guid)
{
return true;
}
}
return false;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -40,6 +40,10 @@ public:
void ShowCurtainCommand(const FGuid& Guid);
void RemoveCurtain();
void RenameCurtain();
FCurtain* FindCurtain(const FGuid& Guid, FCurtainGroup*& OutGroup);
FCurtainGroup* FindCurtainGroup(const FGuid& Guid);
bool IsCurtainGroup(const FGuid& Guid);
ICutMainWidgetInterface* MainWidgetInterface = nullptr;
int32 CurrentSelectedTree = 0;
TArray<TSharedPtr<SCurtainTree>> Trees;

View File

@ -324,14 +324,17 @@ struct CUT5_API FClipData
int32 GetClipRelativeEndFrame() const { return ClipEndFrame - ClipStartFrame; }
FPresetsCustomData PresetsCustomData;
TArray<FSlateBrush> MovieBrushes;
TArray<FString> MovieBrushesPath;
int32 MovieBrushNum;
TArray<FSlateBrush> AudioBrushes;
TArray<float> AudioBrushLength;
int32 AudioBrushNum;
enum class ECropMethod
{

View File

@ -438,8 +438,6 @@ void DragDropOperator::OnDragOver(const FGeometry& MyGeometry, const FDragDropEv
if (DragDropOperation.DragType == FClip2ClipDragDropOperation::EDragType::Move)
{
TSharedPtr<STimelineClip> TimelineClip = StaticCastSharedPtr<STimelineClip>(DragDropOperation.DraggingWidget);
// TimelineClip->ClipData->ClipStartFrame += NewPos;
// TimelineClip->ClipData->ClipEndFrame += NewPos;
if (TimelineClip->ClipData->ClipStartFrame + NewPos >= 0)
{
for (FSingleTrackGroupInstance& TrackGroupInstance : Body->MainWidgetInterface->GetCutTimeline()->TrackGroupInstances)
@ -456,6 +454,7 @@ void DragDropOperator::OnDragOver(const FGeometry& MyGeometry, const FDragDropEv
FVector2D(((TimelineClip->ClipData->ClipEndFrame + NewPos) - (TimelineClip->ClipData->ClipStartFrame + NewPos)) * FGlobalData::DefaultTimeTickSpace, Body->GetCachedGeometry().GetLocalSize().Y),
FUtils::DetectDragTypeCanDrop(*TimelineClip->ClipData, Body->TrackHead->TrackData.TrackType) ? FLinearColor(0, 1, 0, 1) : FLinearColor(1, 0, 0, 1));
Body->DragDropShowProperties.Add(NewProperty);
Body->MainWidgetInterface->GetCutTimeline()->CurrentTimeData->SetText(FText::FromString(FGlobalData::GetTimeData(TimelineClip->ClipData->ClipStartFrame + NewPos) + " / "));
}
@ -637,7 +636,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
NewClipData.ClipGuid = FGuid::NewGuid();
NewClipData.ClipType = TrackHead->TrackData.TrackType;
NewClipData.ClipStartFrame = MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition()).X / FGlobalData::DefaultTimeTickSpace;
NewClipData.ClipEndFrame = (MyGeometry.AbsoluteToLocal(DragDropEvent.GetScreenSpacePosition()).X + 100) / FGlobalData::DefaultTimeTickSpace;
NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + 20;
if (PresetDragOperation->PresetData.PresetType == EPresetType::Color)
{
if (PresetDragOperation->PresetData.Colors.Num() == 0)
@ -778,7 +777,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
if (TrackHead->TrackData.TrackType == ETrackType::LightArrayTrack)
{
NewClipData.ClipType = ETrackType::LightArrayTrack;
NewClipData.LightArrayData = FOpencvUtils::GetVideoFrameLightArray(ClipDragOperation.TimelinePropertyData->MoviePath, FGlobalData::LightArrayX, FGlobalData::LightArrayY);
NewClipData.LightArrayData = FFFMPEGUtils::GetVideoFrameLightArray(ClipDragOperation.TimelinePropertyData->MoviePath, FGlobalData::LightArrayX, FGlobalData::LightArrayY);
}
if (TrackHead->TrackData.TrackType == ETrackType::PlayerTrack)
{
@ -856,7 +855,6 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
const int32 Offset = TimelineClip->ClipData->ClipEndFrame - TimelineClip->ClipData->ClipStartFrame;
TimelineClip->ClipData->ClipStartFrame = 0;
TimelineClip->ClipData->ClipEndFrame = Offset;
}
else
{
@ -875,12 +873,12 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
// It mean the clip is not in the same track
FClipData NewClipData = *TimelineClip->ClipData;
NewClipData.ClipType = TrackHead->TrackData.TrackType;
if (FUtils::DetectDragTypeCanDrop(NewClipData, TrackHead->TrackData.TrackType) == false)
{
return;
}
NewClipData.ClipType = TrackHead->TrackData.TrackType;
TSharedPtr<STrackBody> OriginTrackBody = StaticCastSharedPtr<STrackBody>(TimelineClip->Body);
OriginTrackBody->TrackHead->TrackData.ClipData.Remove(NewClipData);
TrackHead->TrackData.ClipData.Add(NewClipData);

View File

@ -416,17 +416,25 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
}));
CommandList->MapAction(FShortCutCommands::Get().ZoomInTimeline, FExecuteAction::CreateLambda([this]()
{
const float NewValue = CutTimeline->ZoomSlider->GetValue() + 0.1;
CutTimeline->ZoomSlider->SetValue(NewValue);
FGlobalData::DefaultTimeTickSpace = FMath::GetMappedRangeValueClamped(FVector2D(0, 1.0), FVector2D(GetCachedGeometry().GetLocalSize().X / FGlobalData::TrackLength, 14), NewValue);
CutTimeline->RenderGroup();
if (CutTimeline->ZoomSlider->GetValue() <= 1.0)
{
const float NewValue = CutTimeline->ZoomSlider->GetValue() + 0.1;
CutTimeline->ZoomSlider->SetValue(NewValue);
FGlobalData::DefaultTimeTickSpace = FMath::GetMappedRangeValueClamped(FVector2D(0, 1.0), FVector2D(GetCachedGeometry().GetLocalSize().X / FGlobalData::TrackLength, 14), NewValue);
CutTimeline->RenderGroup();
CutTimeline->UpdateCursorPosition(CutTimeline->GetCursorPosition());
}
}));
CommandList->MapAction(FShortCutCommands::Get().ZoomOutTimeline, FExecuteAction::CreateLambda([this]()
{
const float NewValue = CutTimeline->ZoomSlider->GetValue() - 0.1;
CutTimeline->ZoomSlider->SetValue(NewValue);
FGlobalData::DefaultTimeTickSpace = FMath::GetMappedRangeValueClamped(FVector2D(0, 1.0), FVector2D(GetCachedGeometry().GetLocalSize().X / FGlobalData::TrackLength, 14), NewValue);
CutTimeline->RenderGroup();
if (CutTimeline->ZoomSlider->GetValue() >= 0.1)
{
const float NewValue = CutTimeline->ZoomSlider->GetValue() - 0.1;
CutTimeline->ZoomSlider->SetValue(NewValue);
FGlobalData::DefaultTimeTickSpace = FMath::GetMappedRangeValueClamped(FVector2D(0, 1.0), FVector2D(GetCachedGeometry().GetLocalSize().X / FGlobalData::TrackLength, 14), NewValue);
CutTimeline->RenderGroup();
CutTimeline->UpdateCursorPosition(CutTimeline->GetCursorPosition());
}
}));
CommandList->MapAction(FShortCutCommands::Get().SelectMode, FExecuteAction::CreateLambda([this]()
@ -448,11 +456,63 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
];
GEngine->GameViewport->AddSoftwareCursorFromSlateWidget(EMouseCursor::Type::Default, NewWidget.ToSharedRef());
}));
CommandList->MapAction(FShortCutCommands::Get().TimelineMoveLeft, FExecuteAction::CreateLambda([this]()
{
if (CutTimeline->TrackBodyHScrollBox->GetScrollOffset() < CutTimeline->TrackBodyHScrollBox->GetScrollOffsetOfEnd())
CutTimeline->TrackBodyHScrollBox->SetScrollOffset(CutTimeline->TrackBodyHScrollBox->GetScrollOffset() - 10);
}));
CommandList->MapAction(FShortCutCommands::Get().TimelineMoveRight, FExecuteAction::CreateLambda([this]()
{
if (CutTimeline->TrackBodyHScrollBox->GetScrollOffset() < CutTimeline->TrackBodyHScrollBox->GetScrollOffsetOfEnd())
CutTimeline->TrackBodyHScrollBox->SetScrollOffset(CutTimeline->TrackBodyHScrollBox->GetScrollOffset() + 10);
}));
CommandList->MapAction(FShortCutCommands::Get().StartCollectGarbage, FExecuteAction::CreateLambda([this]()
{
GEngine->SetTimeUntilNextGarbageCollection(1);
GEngine->ForceGarbageCollection(true);
}));
// FRunnableThread* Thread = FRunnableThread::Create(SoundThread, TEXT("SoundThread"));
// OpenProject(FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("DefaultProject")));
// ImportProject("");
CommandList->MapAction(FShortCutCommands::Get().Copy, FExecuteAction::CreateLambda([this]()
{
CutTimeline->CopyClipData.Empty();
for (FSingleTrackGroupInstance& Instance : CutTimeline->TrackGroupInstances)
{
TSharedPtr<STrackBody> TrackBody = StaticCastSharedPtr<STrackBody>(Instance.Body);
for (FClipData& ClipData : TrackBody->TrackHead->TrackData.ClipData)
{
if (CutTimeline->SelectedClips.Contains(ClipData.ClipGuid))
{
CutTimeline->CopyClipData.Add(ClipData);
break;
}
}
}
}));
CommandList->MapAction(FShortCutCommands::Get().Paste, FExecuteAction::CreateLambda([this]()
{
for (FClipData& ClipData : CutTimeline->CopyClipData)
{
for (FSingleTrackGroupInstance& Instance : CutTimeline->TrackGroupInstances)
{
TSharedPtr<STrackBody> TrackBody = StaticCastSharedPtr<STrackBody>(Instance.Body);
FVector2D Pos = TrackBody->GetCachedGeometry().AbsoluteToLocal(NewMouseEvent.GetScreenSpacePosition());
if (TrackBody->TrackHead->TrackData.DeviceTrack.Guid == ClipData.BindTrackGuid)
{
FClipData NewClipData = ClipData;
NewClipData.ClipGuid = FGuid::NewGuid();
int32 Length = NewClipData.ClipEndFrame - NewClipData.ClipStartFrame;
NewClipData.ClipStartFrame = FMath::RoundToInt(Pos.X / FGlobalData::DefaultTimeTickSpace);
NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + Length;
DragDropOperator::GetDragDropOperator()->UpdateClipProcess(this, NewClipData);
TrackBody->TrackHead->TrackData.ClipData.Add(NewClipData);
TrackBody->CallRender();
}
}
}
}));
FMainMenuCommands::Register();
CommandList->MapAction(FMainMenuCommands::Get().ExportXML, FExecuteAction::CreateLambda([this]()
@ -483,22 +543,21 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
SaveProject();
}));
CommandList->MapAction(FShortCutCommands::Get().TimelineMoveLeft, FExecuteAction::CreateLambda([this]()
{
if (CutTimeline->TrackBodyHScrollBox->GetScrollOffset() < CutTimeline->TrackBodyHScrollBox->GetScrollOffsetOfEnd())
CutTimeline->TrackBodyHScrollBox->SetScrollOffset(CutTimeline->TrackBodyHScrollBox->GetScrollOffset() - 10);
}));
CommandList->MapAction(FShortCutCommands::Get().TimelineMoveRight, FExecuteAction::CreateLambda([this]()
{
if (CutTimeline->TrackBodyHScrollBox->GetScrollOffset() < CutTimeline->TrackBodyHScrollBox->GetScrollOffsetOfEnd())
CutTimeline->TrackBodyHScrollBox->SetScrollOffset(CutTimeline->TrackBodyHScrollBox->GetScrollOffset() + 10);
}));
FInputBindingManager::Get().RegisterCommandList(FShortCutCommands::Get().GetContextName(), CommandList.ToSharedRef());
OnUpdateProjector(0, true);
DragDropOperator::GetDragDropOperator()->SavedMainInterface = this;
}
FReply SCutMainWindow::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
this->NewMouseEvent = MouseEvent;
return SCompoundWidget::OnMouseMove(MyGeometry, MouseEvent);
}
void SCutMainWindow::Render()
{
StatePanel->PlayerList1->ClearChildren();
@ -560,7 +619,7 @@ int32 SCutMainWindow::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedG
FSlateDrawElement::MakeBox(
OutDrawElements,
999999,
LayerId + 4,
AllottedGeometry.ToPaintGeometry(FVector2f(2, CutTimeline->GetCachedGeometry().Size.Y), FSlateLayoutTransform(FVector2f(RenderLineTime, AllottedGeometry.GetLocalSize().Y - CutTimeline->GetCachedGeometry().GetLocalSize().Y))),
&Brush,
ESlateDrawEffect::None,
@ -572,8 +631,7 @@ int32 SCutMainWindow::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedG
return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle,
bParentEnabled);
return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
}
FReply SCutMainWindow::OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)

View File

@ -88,11 +88,13 @@ public:
virtual void OpenColorPanel(FLinearColor* ColorPtr);
virtual void AddNewCustomPreset(const FString& Name, const FPresetsCustomData CustomData) override;
virtual ESelectMode GetSelectedMode() override;
FPointerEvent NewMouseEvent;
virtual bool SupportsKeyboardFocus() const override { return true; };
virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
virtual FReply OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
tinyxml2::XMLElement* GetDeviceElement(tinyxml2::XMLElement* Parent);
tinyxml2::XMLElement* GetVideoElement(tinyxml2::XMLElement* Parent, FEncodeVideoInfo EncodeVideoInfo);
@ -106,3 +108,5 @@ public:
tinyxml2::XMLElement* GetSpecialEffectGroup(tinyxml2::XMLElement* Parent, FEffectCardGroup* Group);
tinyxml2::XMLElement* GetSpecialEffect(tinyxml2::XMLElement* Parent, FEffectCardProperty* Effect);
};

View File

@ -270,6 +270,7 @@ void SCutTimeline::Construct(const FArguments& InArgs)
[
SAssignNew(TickScrollBox, SScrollBox)
.ScrollBarVisibility(EVisibility::Hidden)
.WheelScrollMultiplier(0.0)
.Orientation(EOrientation::Orient_Horizontal)
+ SScrollBox::Slot()
[
@ -711,13 +712,13 @@ bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info)
return true;
}
void SCutTimeline::RemoveTrack(const FGuid& TrackGuid)
void SCutTimeline::RemoveTrack(const FGuid& DeviceGuid)
{
for (int32 i = 0; i < TrackGroups.Num(); i++)
for (int32 i = 0; i < DeviceTrackGroups.Num(); i++)
{
for (int32 j = DeviceTrackGroups.Num() - 1; j >= 0; --j)
for (int32 j = DeviceTrackGroups[i].DeviceTracks.Num() - 1; j >= 0; --j)
{
if (DeviceTrackGroups[i].DeviceTracks[j].Guid == TrackGuid)
if (DeviceTrackGroups[i].DeviceTracks[j].Guid == DeviceGuid)
{
DeviceTrackGroups[i].DeviceTracks.RemoveAt(j);
break;
@ -726,13 +727,13 @@ void SCutTimeline::RemoveTrack(const FGuid& TrackGuid)
}
for (int32 i = TrackGroupInstances.Num() - 1; i >= 0; --i)
{
if (StaticCastSharedPtr<STrackHead>(TrackGroupInstances[i].Head)->TrackData.Guid == TrackGuid)
if (StaticCastSharedPtr<STrackHead>(TrackGroupInstances[i].Head)->TrackData.DeviceTrack.Guid == DeviceGuid)
{
TrackGroupInstances.RemoveAt(i);
}
}
RenderGroup();
MainWidgetInterface->OnRemoveTrack(TrackGuid);
MainWidgetInterface->OnRemoveTrack(DeviceGuid);
}
FTrackGroup* SCutTimeline::GetTrackGroupByName(FString GroupName)

View File

@ -90,7 +90,7 @@ public:
* @brief Remove Track from Timeline by UUID.
* @param FGuid Track UUID.
*/
void RemoveTrack(const FGuid& FGuid);
void RemoveTrack(const FGuid& DeviceGuid);
FTrackGroup* GetTrackGroupByName(FString GroupName);
@ -118,6 +118,7 @@ public:
* @brief Selected Clips Guid, Use for Multi-Select.
*/
TArray<FGuid> SelectedClips;
TArray<FClipData> CopyClipData;

View File

@ -7,12 +7,14 @@
#include "AudioDevice.h"
#include "ImageUtils.h"
#include "SCutTimeline.h"
#include "SlateOptMacros.h"
#include "STrackBody.h"
#include "Commands/TimelineClipCommands.h"
#include "Cut5/WidgetInterface.h"
#include "Cut5/Interface/SoundInterface.h"
#include "Cut5/Utils/FFMPEGUtils.h"
#include "Cut5/Utils/Utils.h"
#include "DragDropOperator/DragDropOperator.h"
#include "Engine/Engine.h"
@ -56,7 +58,7 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F
}
const FVector2D LocalPos = Geometry.AbsoluteToLocal(PointerEvent.GetScreenSpacePosition());
LocalPos = Geometry.AbsoluteToLocal(PointerEvent.GetScreenSpacePosition());
const float DragOffset = MainWidgetInterface->GetCutTimeline()->GetCachedGeometry().AbsoluteToLocal(PointerEvent.GetScreenSpacePosition()).X;
if (LocalPos.X <= 10)
{
@ -434,55 +436,55 @@ void STimelineClip::Seek(int32 Frame)
}
break;
if (ClipData->PresetType == EPresetType::Color)
{
TArray<FColor> Colors;
Colors.Init(ClipData->ClipColors[0].ToFColor(false), FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4);
MainWidgetInterface->OnUpdateLightArray(Colors);
break;
}
else if (ClipData->PresetType == EPresetType::Gradient)
{
int32 Between = -1;
for (int32 i = 0; i < ClipData->Cursors.Num() - 1; i++)
{
if (SeekMovieFrame >= ClipData->Cursors[i].CursorFrameOffset && SeekMovieFrame <= ClipData->Cursors[i + 1].CursorFrameOffset)
{
Between = i;
}
}
if (SeekMovieFrame >= ClipData->Cursors[ClipData->Cursors.Num() - 1].CursorFrameOffset)
{
Between = ClipData->Cursors.Num() - 1;
}
if (Between != -1)
{
if (Between == ClipData->Cursors.Num() - 1)
{
TArray<FColor> Colors;
Colors.Init(ClipData->Cursors[ClipData->Cursors.Num() - 1].Color.ToFColor(false), FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4);
MainWidgetInterface->OnUpdateLightArray(Colors);
}
else
{
TArray<FColor> Colors;
Colors.Init(FLinearColor::Black.ToFColor(false), FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4);
for (int32 i = 0; i < FGlobalData::LightArrayX * FGlobalData::LightArrayY; i++)
{
Colors[i] = FMath::Lerp(ClipData->Cursors[Between].Color, ClipData->Cursors[Between + 1].Color, (float)(SeekMovieFrame - ClipData->Cursors[Between].CursorFrameOffset) / (float)(ClipData->Cursors[Between + 1].CursorFrameOffset - ClipData->Cursors[Between].CursorFrameOffset)).ToFColor(false);
}
MainWidgetInterface->OnUpdateLightArray(Colors);
}
}
break;
}
}
if (ClipData->PresetType == EPresetType::Color)
{
TArray<FColor> Colors;
Colors.Init(ClipData->ClipColors[0].ToFColor(false), FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4);
MainWidgetInterface->OnUpdateLightArray(Colors);
break;
}
else if (ClipData->PresetType == EPresetType::Gradient)
{
int32 Between = -1;
for (int32 i = 0; i < ClipData->Cursors.Num() - 1; i++)
{
if (SeekMovieFrame >= ClipData->Cursors[i].CursorFrameOffset && SeekMovieFrame <= ClipData->Cursors[i + 1].CursorFrameOffset)
{
Between = i;
}
}
if (SeekMovieFrame >= ClipData->Cursors[ClipData->Cursors.Num() - 1].CursorFrameOffset)
{
Between = ClipData->Cursors.Num() - 1;
}
if (Between != -1)
{
if (Between == ClipData->Cursors.Num() - 1)
{
TArray<FColor> Colors;
Colors.Init(ClipData->Cursors[ClipData->Cursors.Num() - 1].Color.ToFColor(false), FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4);
MainWidgetInterface->OnUpdateLightArray(Colors);
}
else
{
TArray<FColor> Colors;
Colors.Init(FLinearColor::Black.ToFColor(false), FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4);
for (int32 i = 0; i < FGlobalData::LightArrayX * FGlobalData::LightArrayY; i++)
{
Colors[i] = FMath::Lerp(ClipData->Cursors[Between].Color, ClipData->Cursors[Between + 1].Color, (float)(SeekMovieFrame - ClipData->Cursors[Between].CursorFrameOffset) / (float)(ClipData->Cursors[Between + 1].CursorFrameOffset - ClipData->Cursors[Between].CursorFrameOffset)).ToFColor(false);
}
MainWidgetInterface->OnUpdateLightArray(Colors);
}
}
break;
}
if (SeekMovieFrame < ClipData->LightArrayData.Num())
@ -676,7 +678,7 @@ void STimelineClip::UpdateMove(int32 X, int32 DragOffset)
FReply STimelineClip::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
const FVector2D LocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
LocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
bNeedPaintDrag = false;
if (LocalPos.X <= 10)
{
@ -688,6 +690,12 @@ FReply STimelineClip::OnMouseMove(const FGeometry& MyGeometry, const FPointerEve
bNeedPaintDrag = true;
PaintDragType = 1;
}
if (MainWidgetInterface->GetSelectedMode() == ESelectMode::CutMode)
{
bNeedPaintDrag = true;
PaintDragType = 2;
}
return FReply::Handled();
}
@ -706,22 +714,22 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
const int32 PicLength = TotalLength / ClipData->AudioBrushes.Num();
for (FSlateBrush& SlateBrush : ClipData->AudioBrushes)
{
FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 3, AllottedGeometry.ToPaintGeometry(FVector2f(PicLength, AllottedGeometry.GetLocalSize().Y), FSlateLayoutTransform(FVector2f(i * PicLength, 0))), &SlateBrush);
FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 4, AllottedGeometry.ToPaintGeometry(FVector2f(PicLength, AllottedGeometry.GetLocalSize().Y), FSlateLayoutTransform(FVector2f(i * PicLength, 0))), &SlateBrush);
i++;
}
}
}
if (ClipData->MovieBrushes.Num() > 0)
if (ClipData->MovieBrushNum > 0)
{
int32 Step = ClipData->MovieBrushes.Num();
const int32 PerImageLength = TotalLength / ClipData->MovieBrushesPath.Num();
int32 Step = ClipData->MovieBrushNum;
const int32 PerImageLength = TotalLength / ClipData->MovieBrushNum;
const int32 ShouldPerImageLength = TotalLength / 128;
if (ShouldPerImageLength != 0)
{
Step = ClipData->MovieBrushes.Num() / ShouldPerImageLength;
Step = ClipData->MovieBrushNum / ShouldPerImageLength;
}
@ -729,14 +737,14 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
int32 Current = 0;
for (int32 j = 0; j < ShouldPerImageLength; j++)
{
if (ClipData->MovieBrushes.Num() > 0)
if (ClipData->MovieBrushes.Num() > 0 && Current < ClipData->MovieBrushes.Num())
NewBrushes.Add(ClipData->MovieBrushes[Current]);
Current += Step;
}
int32 i = 0;
if (NewBrushes.Num() == 0)
{
NewBrushes.Add(ClipData->MovieBrushes[0]);
NewBrushes.Add(ClipData->MovieBrushes.Num() > 0 ? ClipData->MovieBrushes[0] : FSlateBrush());
}
for (FSlateBrush& SlateBrush : NewBrushes)
{
@ -765,9 +773,8 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
Vectors.Add(FVector2f(0, AllottedGeometry.Size.Y));
Vectors.Add(FVector2f(AllottedGeometry.Size.X, AllottedGeometry.Size.Y));
Vectors.Add(FVector2f(AllottedGeometry.Size.X, 0));
FSlateDrawElement::MakeLines(OutDrawElements, LayerId + 3, AllottedGeometry.ToPaintGeometry(), Vectors, ESlateDrawEffect::None, FLinearColor::White, true, 2.0f);
return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId + 1, InWidgetStyle,
bParentEnabled);
Vectors.Add(FVector2f(0, 0));
FSlateDrawElement::MakeLines(OutDrawElements, LayerId + 4, AllottedGeometry.ToPaintGeometry(), Vectors, ESlateDrawEffect::None, FLinearColor::White, true, 2.0f);
}
@ -832,6 +839,12 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 3, AllottedGeometry.ToPaintGeometry(FVector2f(10, AllottedGeometry.Size.Y), FSlateLayoutTransform(FVector2f(AllottedGeometry.Size.X - 10, 0))),
&Brush, ESlateDrawEffect::None, FLinearColor(1.0, 0.0, 1.0, 1.0));
}
else if (PaintDragType == 2)
{
const FSlateBrush Brush;
FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 3, AllottedGeometry.ToPaintGeometry(FVector2f(FGlobalData::DefaultTimeTickSpace, FGlobalData::DefaultTrackHeight), FSlateLayoutTransform(FVector2f(LocalPos.X, 0))),
&Brush, ESlateDrawEffect::None, FLinearColor(1.0, 0.0, 1.0, 1.0));
}
}
@ -852,6 +865,8 @@ void STimelineClip::DoSound(ESoundSolveType SolveType, int32 InFrame)
{
if (SoundThread == nullptr)
{
if (ClipData->ResourcePropertyDataPtr == nullptr)
return;
if (ClipData->ResourcePropertyDataPtr->AudioStream != -1)
{
SoundThread = new FSoundThread(2, ClipData->ResourcePropertyDataPtr->AudioSample);
@ -890,5 +905,82 @@ void STimelineClip::OnMouseLeave(const FPointerEvent& MouseEvent)
bNeedPaintDrag = false;
}
void STimelineClip::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
if (ClipData->MovieBrushes.Num() < ClipData->MovieBrushNum && ClipData->ResourcePropertyDataPtr && ClipData->ResourcePropertyDataPtr->Context && ClipData->ResourcePropertyDataPtr->VideoStream != -1)
{
if (ThumbnailCodecContext.Context == nullptr)
{
FFFMPEGUtils::LoadContextPure(ClipData->ResourcePropertyDataPtr->MoviePath, &ThumbnailCodecContext);
return;
}
const int32 CurrentFrame = ClipData->MovieBrushNum - (ClipData->MovieBrushNum - ClipData->MovieBrushes.Num());
const int64 Timestamp = av_rescale_q(CurrentFrame / 30.0 * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, ThumbnailCodecContext.Context->streams[ThumbnailCodecContext.VideoStream]->time_base);
av_seek_frame(ThumbnailCodecContext.Context, ThumbnailCodecContext.VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD);
AVPacket Packet;
av_init_packet(&Packet);
AVFormatContext* FormatContext = ThumbnailCodecContext.Context;
AVCodecContext* VideoCodecContext = ThumbnailCodecContext.VideoCodecContext;
AVCodec* VideoCodec = ThumbnailCodecContext.VideoCodec;
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 / 10, Frame->height / 10, AV_PIX_FMT_BGRA,
SWS_BILINEAR, NULL, NULL, NULL
);
if (!swsCtx)
{
UE_LOG(LogTemp, Error, TEXT("Error creating swsContext"));
}
uint8* RawData = new uint8[(Frame->width / 10) * (Frame->height / 10) * 4];
uint8* dest[4] = {RawData, 0, 0, 0};
int32 dest_linesize[4] = {(Frame->width / 10) * 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 / 10, Frame->height / 10, PF_B8G8R8A8);
if (Texture)
{
void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(MipData, RawData, (Frame->width / 10) * (Frame->height / 10) * 4);
Texture->GetPlatformData()->Mips[0].BulkData.Unlock();
Texture->UpdateResource();
FGuid Guid = FGuid::NewGuid();
FFFMPEGUtils::ExportImage(Texture, *FPaths::Combine(FUtils::GetTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png"));
ClipData->MovieBrushesPath.Add(FPaths::Combine(FUtils::GetTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png"));
FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ClipData->MovieBrushesPath[ClipData->MovieBrushesPath.Num() - 1], FVector2f(0, 0));
ClipData->MovieBrushes.Add(Brush);
Texture->MarkAsGarbage();
delete RawData;
}
}
}
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -68,8 +68,12 @@ public:
bool bNeedPaintDrag = false;
int32 PaintDragType = 0;
FVector2D LocalPos;
bool bIsDragOver = false;
virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
FTimelinePropertyData ThumbnailCodecContext;
};

View File

@ -67,7 +67,11 @@ int32 STimelineTick::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
ESlateDrawEffect::None,
FColor(55, 55, 55, 255));
}
if (j % 30 == 0)
const float Space = FGlobalData::GlobalFPS * FGlobalData::DefaultTimeTickSpace;
const int32 Multiplier = FMath::GetMappedRangeValueClamped(FVector2D(300, 2), FVector2D(1, 5), Space);
if (j % (Multiplier * 30) == 0)
{
const FSlateBrush Brush;
FSlateDrawElement::MakeBox(

View File

@ -25,11 +25,11 @@ void STrackHead::Construct(const FArguments& InArgs)
{
if (TrackData.DeviceTrack.DeviceTrackGroup->GroupName != TEXT("固定轨道"))
{
CutTimeline->RemoveTrack(TrackData.Guid);
CutTimeline->RemoveTrack(TrackData.DeviceTrack.Guid);
}
}));
}));
TSharedPtr<SImage> Image = SNew(SImage);
ChildSlot

View File

@ -8,6 +8,14 @@
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
SVideoPlayer::~SVideoPlayer()
{
if (Texture->IsValidLowLevel() && Texture->IsRooted())
{
Texture->RemoveFromRoot();
}
}
void SVideoPlayer::Construct(const FArguments& InArgs)
{
@ -33,12 +41,13 @@ void SVideoPlayer::UpdateVideoData(FGuid UUID, int32 X, int32 Y, uint8* RawData)
VideoImage->SetImage(Brush);
return;
}
if (!Texture || Texture->GetSizeX() != X || Texture->GetSizeY() != Y)
if (!Texture->IsValidLowLevel() || Texture->GetSizeX() != X || Texture->GetSizeY() != Y)
{
Texture = UTexture2D::CreateTransient(X, Y, PF_B8G8R8A8);
Texture->AddToRoot();
}
if (Texture)
if (Texture->IsValidLowLevel())
{
void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(MipData, RawData, X * Y * 4);

View File

@ -15,11 +15,13 @@ public:
SLATE_BEGIN_ARGS(SVideoPlayer)
{
}
SLATE_END_ARGS()
virtual ~SVideoPlayer() override;
/** Constructs this widget with InArgs */
void Construct(const FArguments& InArgs);
void UpdateVideoData(FGuid UUID, int32 X, int32 Y, uint8* RawData);
TObjectPtr<UTexture2D> Texture;
TSharedPtr<SImage> VideoImage;