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:
parent
5953ee70dc
commit
69ba93ba53
@ -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;
|
||||
}
|
@ -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);
|
||||
|
@ -22,6 +22,10 @@ public:
|
||||
TSharedPtr<FUICommandInfo> TimelineMoveLeft;
|
||||
TSharedPtr<FUICommandInfo> TimelineMoveRight;
|
||||
|
||||
TSharedPtr<FUICommandInfo> StartCollectGarbage;
|
||||
TSharedPtr<FUICommandInfo> EndCollectGarbage;
|
||||
|
||||
TSharedPtr<FUICommandInfo> Copy;
|
||||
TSharedPtr<FUICommandInfo> Paste;
|
||||
|
||||
};
|
||||
|
@ -15,5 +15,11 @@ void FShortCutCommands::RegisterCommands()
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -415,18 +415,26 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
|
||||
ExportProject(String);
|
||||
}));
|
||||
CommandList->MapAction(FShortCutCommands::Get().ZoomInTimeline, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
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]()
|
||||
{
|
||||
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);
|
||||
}));
|
||||
|
||||
// FRunnableThread* Thread = FRunnableThread::Create(SoundThread, TEXT("SoundThread"));
|
||||
// OpenProject(FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("DefaultProject")));
|
||||
// ImportProject("");
|
||||
CommandList->MapAction(FShortCutCommands::Get().StartCollectGarbage, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
GEngine->SetTimeUntilNextGarbageCollection(1);
|
||||
GEngine->ForceGarbageCollection(true);
|
||||
}));
|
||||
|
||||
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)
|
||||
|
@ -89,10 +89,12 @@ public:
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
@ -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,10 +436,6 @@ void STimelineClip::Seek(int32 Frame)
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (ClipData->PresetType == EPresetType::Color)
|
||||
{
|
||||
|
||||
@ -483,6 +481,10 @@ void STimelineClip::Seek(int32 Frame)
|
||||
|
||||
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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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(
|
||||
|
@ -25,7 +25,7 @@ void STrackHead::Construct(const FArguments& InArgs)
|
||||
{
|
||||
if (TrackData.DeviceTrack.DeviceTrackGroup->GroupName != TEXT("固定轨道"))
|
||||
{
|
||||
CutTimeline->RemoveTrack(TrackData.Guid);
|
||||
CutTimeline->RemoveTrack(TrackData.DeviceTrack.Guid);
|
||||
}
|
||||
|
||||
}));
|
||||
|
@ -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);
|
||||
|
@ -18,8 +18,10 @@ public:
|
||||
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user