大量改动

This commit is contained in:
Sch 2023-08-29 11:23:02 +08:00
parent f6765a04b1
commit c0a718501a
29 changed files with 1266 additions and 517 deletions

View File

@ -1,3 +1,10 @@
[/Script/EngineSettings.GeneralProjectSettings]
ProjectID=DC8863584B4EB976B538D48259B614C0
ProjectDisplayedTitle=NSLOCTEXT("[/Script/EngineSettings]", "AAF6DC1F478F1461B74DFBA59A7881EF", "编辑器")
ProjectDebugTitleInfo=NSLOCTEXT("[/Script/EngineSettings]", "BF92E12B419D88450FDB208106B9DE89", "\"")
bUseBorderlessWindow=True
bAllowMinimize=False
bAllowMaximize=False
bAllowClose=False

BIN
Resources/EngineLogo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

View File

@ -62,4 +62,5 @@ public:
virtual void DeleteAllAssetsInTimeline() {};
virtual ESelectMode GetSelectedMode() { return ESelectMode::SelectMode; };
virtual class SCutTimeline* GetCutTimeline() { return nullptr; };
virtual class SCutMainWindow* GetSelf() { return nullptr; };
};

View File

@ -3,17 +3,19 @@
#include <portaudio.h>
#include "Cut5/Widgets/DefineGlobal.h"
#include "Cut5/Utils/Utils.h"
FCriticalSection Mutex;
FSoundThread::FSoundThread(int32 OutputChannel, int32 SampleRate) : FRunnable()
FSoundThread::FSoundThread(int32 OutputChannel, int32 SampleRate, int32 ByteNum, PaSampleFormat PaSoundType) : FRunnable()
{
Stream = nullptr;
Pa_Initialize();
Pa_OpenDefaultStream(&Stream, 0, OutputChannel, paFloat32, SampleRate, 0, nullptr, nullptr);
Pa_OpenDefaultStream(&Stream, 0, OutputChannel, PaSoundType, SampleRate, 10000, nullptr, nullptr);
Pa_StartStream(Stream);
this->OutputChannel = OutputChannel;
this->SampleRate = SampleRate;
this->ByteNum = ByteNum;
this->PaSoundType = PaSoundType;
}
bool FSoundThread::Init()
@ -37,20 +39,23 @@ uint32 FSoundThread::Run()
{
while (!bStoped)
{
if (SeekedFrame != 0)
{
TArray<uint8, TInlineAllocator<11760>> ResultData;
const int32 FrameLength = Audio.Num();
for (int32 i = SeekedFrame * (SampleRate / 26) * 4 * 2; i < (SeekedFrame + 1) * (SampleRate / 26) * 4 * 2 && i < FrameLength; ++i)
const int32 Offset = SeekedFrame * (SampleRate / FGlobalData::GlobalFPS) * ByteNum * 2;
const int32 Size = SampleRate / FGlobalData::GlobalFPS;
if (Audio.Num() < Offset + Size)
{
if (ResultData.Num() < i && i > 0)
{
ResultData.Add(Audio[i]);
}
SeekedFrame = 0;
continue;
}
Pa_WriteStream(Stream, ResultData.GetData(), ResultData.Num() / 4 / 2);
if (Pa_WriteStream(Stream, Audio.GetData() + Offset, Size) == paOutputUnderflowed)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Underflowed"));
};
SeekedFrame = 0;
}
}
return 0;
}
@ -61,6 +66,23 @@ void FSoundThread::Stop()
FRunnable::Stop();
}
int FSoundThread::PaStreamCallback(const void* input, void* output, unsigned long frameCount,
const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void* userData)
{
// FSoundThread* This = static_cast<FSoundThread*>(userData);
//
// TArray<uint8, TInlineAllocator<11760>> ResultData;
// const int32 FrameLength = This->Audio.Num();
// for (int32 i = This->SeekedFrame * (This->SampleRate / FGlobalData::GlobalFPS) * This->ByteNum * 2; i < This->SeekedFrame * (This->SampleRate / FGlobalData::GlobalFPS) * This->ByteNum * 2 + frameCount && i < FrameLength; ++i)
// {
// if (ResultData.Num() < i && i > 0)
// {
// ResultData.Add(This->Audio[i]);
// }
// }
// output = ResultData.GetData();
return paContinue;
}
bool FSoundThread::CopyAudio(const uint8* Data, int32 Size, ESoundSolveType SolveType)
@ -74,28 +96,28 @@ bool FSoundThread::CopyAudio(const uint8* Data, int32 Size, ESoundSolveType Solv
}
case ESoundSolveType::OnlyLeft:
{
for (int32 i = 0; i < Size / 4; i++)
for (int32 i = 0; i < Size / ByteNum; i++)
{
if (i % 2 == 1)
{
Audio[i * 4] = 0;
Audio[i * 4 + 1] = 0;
Audio[i * 4 + 2] = 0;
Audio[i * 4 + 3] = 0;
for (int32 j = 0; j < ByteNum; j++)
{
Audio[i * ByteNum + j] = 0;
}
}
}
break;
}
case ESoundSolveType::OnlyRight:
{
for (int32 i = 0; i < Size / 4; i++)
for (int32 i = 0; i < Size / ByteNum; i++)
{
if (i % 2 == 0)
{
Audio[i * 4] = 0;
Audio[i * 4 + 1] = 0;
Audio[i * 4 + 2] = 0;
Audio[i * 4 + 3] = 0;
for (int32 j = 0; j < ByteNum; j++)
{
Audio[i * ByteNum + j] = 0;
}
}
}
break;
@ -112,5 +134,23 @@ bool FSoundThread::CopyAudio(const uint8* Data, int32 Size, ESoundSolveType Solv
bool FSoundThread::SeekFrame(int32 SeekFrameLoc)
{
SeekedFrame = SeekFrameLoc;
// for (int32 i = 0; i < 200; i++)
// {
// const int32 Offset = i * (SampleRate / FGlobalData::GlobalFPS) * ByteNum * 2;
// const int32 Size = SampleRate / FGlobalData::GlobalFPS;
// Pa_WriteStream(Stream, Audio.GetData() + Offset, Size);
// }
return true;
}
void FSoundThread::StartPlay()
{
bIsPlaying = true;
}
void FSoundThread::StopPlay()
{
bIsPlaying = false;
}

View File

@ -9,16 +9,22 @@ extern "C"{
class FSoundThread : public FRunnable
{
public:
FSoundThread(int32 OutputChannel, int32 SampleRate);
FSoundThread(int32 OutputChannel, int32 SampleRate, int32 ByteNum, PaSampleFormat PaSoundType);
virtual bool Init();
virtual void Exit() override;
virtual uint32 Run() override;
virtual void Stop() override;
static int PaStreamCallback(
const void *input, void *output,
unsigned long frameCount,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData );
PaStream* Stream;
int32 OutputChannel;
int32 SampleRate;
int32 ByteNum;
uint64 PaSoundType;
bool bStoped = false;
@ -26,4 +32,8 @@ public:
bool SeekFrame(int32 SeekFrameLoc);
int32 SeekedFrame = 0;
TArray<uint8> Audio;
void StartPlay();
void StopPlay();
bool bIsPlaying = false;
};

View File

@ -0,0 +1,177 @@
#include "VideoInterface.h"
#include "CutMainWidgetInterface.h"
#include "Cut5/Utils/FFMPEGUtils.h"
bool FVideoThread::Init()
{
FFFMPEGUtils::LoadContextPure(ClipData.MoviePath, &NewPropertyData);
if (NewPropertyData.VideoCodecContext == nullptr)
{
return false;
}
if (NewPropertyData.Context == nullptr)
{
return false;
}
return true;
}
uint32 FVideoThread::Run()
{
while (!IsStop)
{
if (CurrentSeekingFrame != -1)
{
int32 VideoFPS = NewPropertyData.VideoCodecContext->framerate.num;
if (VideoFPS < FGlobalData::GlobalFPS)
{
const double Interval = FGlobalData::GlobalFPS / VideoFPS;
CurrentSeekingFrame = static_cast<float>(CurrentSeekingFrame) / Interval;
}
else
{
VideoFPS = FGlobalData::GlobalFPS;
}
const int64 Timestamp = av_rescale_q(static_cast<float>(CurrentSeekingFrame) / static_cast<float>(VideoFPS) * AV_TIME_BASE
, AVRational{1, AV_TIME_BASE}
, NewPropertyData.Context->streams[NewPropertyData.VideoStream]->time_base);
if (CurrentSeekingFrame - LastSeekFrame > 1 || CurrentSeekingFrame - LastSeekFrame < 0 || LastSeekFrame == -1)
{
av_seek_frame(NewPropertyData.Context, NewPropertyData.VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD);
}
AVPacket* Packet = av_packet_alloc();
AVFrame* AllocatedFrame = av_frame_alloc();
av_init_packet(Packet);
avcodec_receive_frame(NewPropertyData.VideoCodecContext, AllocatedFrame);
int32 Times = 0;
bool bNeedReadFrame = true;
if (CurrentSeekingFrame == LastSeekFrame && LastSeekFrame != -1)
{
if (LastFrame != nullptr)
{
AllocatedFrame = LastFrame;
bNeedReadFrame = false;
}
}
bool IsFailed = false;
if (bNeedReadFrame)
{
while (av_read_frame(NewPropertyData.Context, Packet) >= 0)
{
if (Packet->stream_index == NewPropertyData.VideoStream)
{
int32 Response = avcodec_send_packet(NewPropertyData.VideoCodecContext, Packet);
if (Response < 0)
{
UE_LOG(LogTemp, Error, TEXT("Error while sending a packet to the decoder: %s"), *FString(FString::FromInt(Response)));
IsFailed = true;
}
Response = avcodec_receive_frame(NewPropertyData.VideoCodecContext, AllocatedFrame);
if (Response == AVERROR(EAGAIN) || Response == AVERROR_EOF)
{
}
else if (Response < 0)
{
UE_LOG(LogTemp, Error, TEXT("Error while receiving a frame from the decoder: %s"), *FString(FString::FromInt(Response)));
IsFailed = true;
}
if (AllocatedFrame->best_effort_timestamp >= Timestamp)
{
LastFrame = AllocatedFrame;
av_packet_unref(Packet);
break;
}
}
}
}
av_packet_unref(Packet);
if (IsFailed == true)
{
CurrentSeekingFrame = -1;
continue;;
}
const AVCodecContext* VideoCodecContext = NewPropertyData.VideoCodecContext;
struct SwsContext* SwsCtx = sws_getContext(
AllocatedFrame->width, AllocatedFrame->height, VideoCodecContext->pix_fmt,
AllocatedFrame->width, AllocatedFrame->height, AV_PIX_FMT_BGRA,
SWS_BILINEAR, nullptr, nullptr, nullptr
);
if (!SwsCtx)
{
UE_LOG(LogTemp, Error, TEXT("Error creating swsContext"));
CurrentSeekingFrame = -1;
continue;;
}
uint8* RawData = new uint8[AllocatedFrame->width * AllocatedFrame->height * 4];
uint8* Dest[4] = {RawData, nullptr, nullptr, nullptr};
const int32 DestLineSize[4] = {AllocatedFrame->width * 4, 0, 0, 0};
sws_scale(SwsCtx, AllocatedFrame->data, AllocatedFrame->linesize, 0, AllocatedFrame->height, Dest, DestLineSize);
sws_freeContext(SwsCtx);
int32 DataSize = AllocatedFrame->width * AllocatedFrame->height * 4;
if (AllocatedFrame->data[0] == nullptr)
{
CurrentSeekingFrame = -1;
delete RawData;
continue;;
}
int32 X = AllocatedFrame->width;
int32 Y = AllocatedFrame->height;
AsyncTask(ENamedThreads::GameThread, [this, X, Y, RawData]()
{
MainInterface->OnUpdateVideo(FGuid(), X, Y, RawData);
});
LastFrame = av_frame_alloc();
// av_frame_copy(LastFrame, AllocatedFrame);
LastFrame = av_frame_clone(AllocatedFrame);
av_frame_free(&AllocatedFrame);
LastSeekFrame = CurrentSeekingFrame.load();
CurrentSeekingFrame = -1;
}
}
return 0;
}
void FVideoThread::Stop()
{
IsStop = true;
}
void FVideoThread::Exit()
{
FRunnable::Exit();
}
FVideoThread::FVideoThread(TFunction<void(uint8* RawData, int32 Size, int32 X, int32 Y)> GameThreadCallbackFunction,
const FClipData& InitClipData, ICutMainWidgetInterface* InMainInterface)
{
BindFunction = GameThreadCallbackFunction;
ClipData = InitClipData;
MainInterface = InMainInterface;
}
void FVideoThread::SeekFrame(int32 Frame)
{
CurrentSeekingFrame = Frame;
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "Cut5/Widgets/DefineGlobal.h"
class FVideoThread final: public FRunnable
{
virtual bool Init() override;
virtual void Exit() override;
public:
virtual void Stop() override;
FVideoThread(TFunction<void(uint8* RawData, int32 Size, int32 X, int32 Y)> GameThreadCallbackFunction, const FClipData& InitClipData, ICutMainWidgetInterface* InMainInterface);
ICutMainWidgetInterface* MainInterface = nullptr;
void SeekFrame(int32 Frame);
virtual uint32 Run() override;
TFunction<void(uint8* RawData, int32 Size, int32 X, int32 Y)> BindFunction;
FClipData ClipData;
FTimelinePropertyData NewPropertyData;
std::atomic<int32> CurrentSeekingFrame = -1;
std::atomic<int32> LastSeekFrame = -1;
AVFrame* LastFrame = nullptr;
bool IsStop = false;
};

View File

@ -13,7 +13,7 @@ AMainHUD::AMainHUD()
{
if (GEngine && GEngine->GameViewport)
{
const TSharedPtr<SCutMainWindow> MainWindow = SNew(SCutMainWindow);
SAssignNew(MainWindow, SCutMainWindow);
GEngine->GameViewport->AddViewportWidgetContent(
MainWindow.ToSharedRef()
);
@ -28,7 +28,12 @@ AMainHUD::AMainHUD()
UWidgetBlueprintLibrary::SetInputMode_UIOnlyEx(UGameplayStatics::GetPlayerController(GWorld, 0), nullptr, EMouseLockMode::DoNotLock);
UGameplayStatics::GetPlayerController(GWorld, 0)->bShowMouseCursor = true;
GEngine->GameViewport->GetWindow()->SetWindowMode(EWindowMode::Windowed);
GEngine->GameViewport->GetWindow()->GetTitleBar()->UpdateBackgroundContent(nullptr);
UGameplayStatics::GetPlayerController(GWorld->GetWorld(), 0)->ConsoleCommand("t.setRes 1280x720w");
}

View File

@ -4,6 +4,7 @@
#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "Widgets/SCutMainWindow.h"
#include "MainHUD.generated.h"
/**
@ -16,4 +17,6 @@ class CUT5_API AMainHUD : public AHUD
AMainHUD();
~AMainHUD();
TSharedPtr<SCutMainWindow> MainWindow;
};

View File

@ -107,18 +107,26 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
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");
}
TArray<uint8> DataResult;
AVPacket Packet = *av_packet_alloc();
AVFrame* Frame = av_frame_alloc();
while (1)
const AVSampleFormat SampleFormat = *AudioCodecContext->codec->sample_fmts;
while (true)
{
if (av_read_frame(FormatContext, &Packet) < 0)
{
@ -127,23 +135,31 @@ FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* Prop
break;
}
}
avcodec_send_packet(AudioCodecContext, &Packet);
if (avcodec_receive_frame(AudioCodecContext, Frame) >= 0)
if (AudioCodec->id < 0x10800 && AudioCodec->id >= 0x10000)
{
const uint8* Result = FUtils::ConvertTwoChannelSound2PortAudioSound(Frame->data[0], Frame->data[1], Frame->nb_samples);
if (Result != nullptr)
{
DataResult.Append(Result, Frame->nb_samples * 4 * 2);
// Pa_WriteStream(Stream, Result, Frame->nb_samples);
}
delete[] Result;
DataResult.Append(Packet.data, Packet.size);
}
else
{
avcodec_send_packet(AudioCodecContext, &Packet);
if (avcodec_receive_frame(AudioCodecContext, Frame) >= 0)
{
const uint8* Result = FUtils::ConvertTwoChannelSound2PortAudioSound(Frame->data, Frame->channels, Frame->nb_samples, FUtils::GetFormatSampleBytesNum(SampleFormat));
if (Result != nullptr)
{
DataResult.Append(Result, Frame->nb_samples * FUtils::GetFormatSampleBytesNum(SampleFormat) * Frame->channels);
}
delete[] Result;
}
}
}
PropertyData->AudioData = DataResult;
PropertyData->AudioCodecContext = AudioCodecContext;
PropertyData->AudioCodec = AudioCodec;
PropertyData->AudioSample = AudioCodecContext->sample_rate;
PropertyData->AudioChannels = AudioCodecContext->channels;
PropertyData->SampleFormat = SampleFormat;
}
@ -419,133 +435,183 @@ TArray<FSlateBrush> FFFMPEGUtils::GetMovieBrush(FClipData* ClipData, bool Regene
TArray<FSlateBrush> FFFMPEGUtils::GetAudioBrush(FClipData* ClipData)
{
const float TimeLength = (ClipData->ClipEndFrame - ClipData->ClipStartFrame) * FGlobalData::DefaultTimeTickSpace;
const int32 PicLength = TimeLength / 8.0;
if (ClipData->ResourcePropertyDataPtr)
{
if (ClipData->ResourcePropertyDataPtr->AudioData.Num() == 0)
{
return {};
}
if (ClipData->ResourcePropertyDataPtr->AudioStream == -1)
{
return {};
}
if (ClipData->ResourcePropertyDataPtr->VideoStream != -1)
{
return {};
}
}
else
{
return {};
}
int32 DownSampleSpace = 128;
TArray<float> DownSampledData;
DownSampledData.SetNumZeroed(ClipData->ResourcePropertyDataPtr->AudioData.Num() / 4 / DownSampleSpace);
for (int32 i = 0; i < ClipData->ResourcePropertyDataPtr->AudioData.Num() / 4; i++)
{
float NewFloat = *reinterpret_cast<float*>(ClipData->ResourcePropertyDataPtr->AudioData.GetData() + (i * 4));
if (i % DownSampleSpace == 0)
{
DownSampledData[i / DownSampleSpace] = NewFloat;
}
}
const float FFTSize = DownSampledData.Num();
kiss_fft_cfg Cfg = kiss_fft_alloc(FFTSize, 0, nullptr, nullptr);
TArray<kiss_fft_cpx> KissIn, KissOut;
KissIn.SetNumZeroed(FFTSize);
KissOut.SetNumZeroed(FFTSize);
for (int32 i = 0; i < DownSampledData.Num(); i++)
{
float NewFloat = DownSampledData[i];
KissIn[i].r = NewFloat;
KissIn[i].i = 0;
}
kiss_fft(Cfg, KissIn.GetData(), KissOut.GetData());
TArray<float> Spectrum;
Spectrum.SetNumZeroed(FFTSize);
for (int32 i = 0; i < DownSampledData.Num(); i++)
{
Spectrum[i] = sqrt(KissOut[i].r * KissOut[i].r + KissOut[i].i * KissOut[i].i);
}
float MaxValue = 0;
float MinValue = 0;
for (int32 i = 0; i < Spectrum.Num(); i++)
{
float NewFloat = ClipData->ResourcePropertyDataPtr->AudioData[i];
if (NewFloat >= MaxValue)
{
MaxValue = NewFloat;
}
if (NewFloat <= MinValue)
{
MinValue = NewFloat;
}
}
auto Normalize = [MaxValue, MinValue](float CurrentValue)
{
return FMath::GetMappedRangeValueClamped(FVector2D(MinValue, MaxValue), FVector2D(FGlobalData::DefaultTrackHeight, 0), CurrentValue);
};
ClipData->AudioBrushLength.Empty();
ClipData->AudioBrushes.Empty();
int32 Index = 0;
int32 TotalLength = TimeLength;
float LastPoint = 0.0;
for (int32 i = 0; i < TotalLength / PicLength; i++)
{
FLinearColor RenderColor(i * (360.0 / 8.0), 1.0, 1.0);
UTextureRenderTarget2D* TextureRenderTarget2D = NewObject<UTextureRenderTarget2D>();
TextureRenderTarget2D->InitCustomFormat(PicLength, int32(FGlobalData::DefaultTrackHeight), PF_B8G8R8A8, false);
TextureRenderTarget2D->UpdateResourceImmediate();
UKismetRenderingLibrary::ClearRenderTarget2D(GWorld->GetWorld(), TextureRenderTarget2D, FLinearColor(0, 0, 0, 0));
UCanvas* Canvas;
FVector2D Size;
FDrawToRenderTargetContext RenderTargetContext;
UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget(GWorld->GetWorld(), TextureRenderTarget2D, Canvas, Size, RenderTargetContext);
int32 StartIndex = (Index * PicLength) / 16;
for (int32 j = 0; j < PicLength; j++)
{
float CurrentData = Spectrum[StartIndex];
float NormalizedData = Normalize(CurrentData);
Canvas->K2_DrawLine(FVector2D(j - 1, LastPoint), FVector2D(j, NormalizedData), 1, RenderColor.HSVToLinearRGB());
LastPoint = NormalizedData;
StartIndex += 1;
}
UKismetRenderingLibrary::EndDrawCanvasToRenderTarget(GWorld->GetWorld(), RenderTargetContext);
FBufferArchive Buffer;
FImageUtils::ExportRenderTarget2DAsPNG(TextureRenderTarget2D, Buffer);
FFileHelper::SaveArrayToFile(Buffer, *FPaths::Combine(FUtils::GetProjectTempPath(), ClipData->ClipGuid.ToString(), FString::FromInt(Index) + ".png"));
TextureRenderTarget2D->MarkAsGarbage();
FSlateDynamicImageBrush SlateBrush = FSlateDynamicImageBrush(*FPaths::Combine(FUtils::GetProjectTempPath(), ClipData->ClipGuid.ToString(), FString::FromInt(Index) + ".png"), FVector2D(PicLength, FGlobalData::DefaultTrackHeight));
ClipData->AudioBrushLength.Add(PicLength);
ClipData->AudioBrushes.Add(SlateBrush);
Index++;
}
// const float TimeLength = (ClipData->ClipEndFrame - ClipData->ClipStartFrame) * FGlobalData::DefaultTimeTickSpace;
//
// const int32 PicLength = TimeLength / 8.0;
//
// if (ClipData->ResourcePropertyDataPtr)
// {
// if (ClipData->ResourcePropertyDataPtr->AudioData.Num() == 0)
// {
// return {};
// }
// if (ClipData->ResourcePropertyDataPtr->AudioStream == -1)
// {
// return {};
// }
// if (ClipData->ResourcePropertyDataPtr->VideoStream != -1)
// {
// return {};
// }
// }
// else
// {
// return {};
// }
//
//
// int32 DownSampleSpace = 128;
// TArray<uint8> DownSampledData;
// DownSampledData.SetNumZeroed(ClipData->ResourcePropertyDataPtr->AudioData.Num() / FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) / DownSampleSpace);
// for (int32 i = 0; i < ClipData->ResourcePropertyDataPtr->AudioData.Num() / FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat) / DownSampleSpace; i++)
// {
// switch (FUtils::GetFormatType(ClipData->ResourcePropertyDataPtr->SampleFormat))
// {
// case 0:
// {
// uint8 NewValue = *reinterpret_cast<uint8*>(ClipData->ResourcePropertyDataPtr->AudioData.GetData() + (i * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat)));
// if (i % DownSampleSpace == 0)
// {
// DownSampledData[i / DownSampleSpace] = NewValue;
// }
// break;
// }
//
// case 1:
// {
// int16 NewValue = *reinterpret_cast<int16*>(ClipData->ResourcePropertyDataPtr->AudioData.GetData() + (i * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat)));
// if (i % DownSampleSpace == 0)
// {
// DownSampledData[i / DownSampleSpace] = NewValue;
// }
// break;
// }
// case 2:
// {
// int32 NewValue = *reinterpret_cast<int32*>(ClipData->ResourcePropertyDataPtr->AudioData.GetData() + (i * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat)));
// if (i % DownSampleSpace == 0)
// {
// DownSampledData[i / DownSampleSpace] = NewValue;
// }
// break;
// }
// case 3:
// {
// float NewValue = *reinterpret_cast<float*>(ClipData->ResourcePropertyDataPtr->AudioData.GetData() + (i * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat)));
// if (i % DownSampleSpace == 0)
// {
// DownSampledData[i / DownSampleSpace] = NewValue;
// }
// break;
// }
// case 4:
// {
// double NewValue = *reinterpret_cast<double*>(ClipData->ResourcePropertyDataPtr->AudioData.GetData() + (i * FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat)));
// if (i % DownSampleSpace == 0)
// {
// DownSampledData[i / DownSampleSpace] = NewValue;
// }
// break;
// }
// default:
// break;
// }
// ;
//
//
// }
//
//
// const float FFTSize = DownSampledData.Num();
// kiss_fft_cfg Cfg = kiss_fft_alloc(FFTSize, 0, nullptr, nullptr);
//
// TArray<kiss_fft_cpx> KissIn, KissOut;
// KissIn.SetNumZeroed(FFTSize);
// KissOut.SetNumZeroed(FFTSize);
//
// for (int32 i = 0; i < DownSampledData.Num(); i++)
// {
// float NewFloat = DownSampledData[i];
// KissIn[i].r = NewFloat;
// KissIn[i].i = 0;
// }
//
// kiss_fft(Cfg, KissIn.GetData(), KissOut.GetData());
//
// TArray<float> Spectrum;
// Spectrum.SetNumZeroed(FFTSize);
// for (int32 i = 0; i < DownSampledData.Num(); i++)
// {
// Spectrum[i] = sqrt(KissOut[i].r * KissOut[i].r + KissOut[i].i * KissOut[i].i);
// }
//
// float MaxValue = 0;
// float MinValue = 0;
// for (int32 i = 0; i < Spectrum.Num(); i++)
// {
// float NewFloat = ClipData->ResourcePropertyDataPtr->AudioData[i];
//
// if (NewFloat >= MaxValue)
// {
// MaxValue = NewFloat;
// }
// if (NewFloat <= MinValue)
// {
// MinValue = NewFloat;
// }
// }
//
//
// auto Normalize = [MaxValue, MinValue](float CurrentValue)
// {
// return FMath::GetMappedRangeValueClamped(FVector2D(MinValue, MaxValue), FVector2D(FGlobalData::DefaultTrackHeight, 0), CurrentValue);
// };
//
// ClipData->AudioBrushLength.Empty();
// ClipData->AudioBrushes.Empty();
// int32 Index = 0;
// int32 TotalLength = TimeLength;
// float LastPoint = 0.0;
// for (int32 i = 0; i < TotalLength / PicLength; i++)
// {
// FLinearColor RenderColor(i * (360.0 / 8.0), 1.0, 1.0);
// UTextureRenderTarget2D* TextureRenderTarget2D = NewObject<UTextureRenderTarget2D>();
// TextureRenderTarget2D->InitCustomFormat(PicLength, int32(FGlobalData::DefaultTrackHeight), PF_B8G8R8A8, false);
// TextureRenderTarget2D->UpdateResourceImmediate();
// UKismetRenderingLibrary::ClearRenderTarget2D(GWorld->GetWorld(), TextureRenderTarget2D, FLinearColor(0, 0, 0, 0));
// UCanvas* Canvas;
// FVector2D Size;
// FDrawToRenderTargetContext RenderTargetContext;
// UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget(GWorld->GetWorld(), TextureRenderTarget2D, Canvas, Size, RenderTargetContext);
//
// int32 StartIndex = (Index * PicLength) / 16;
//
// for (int32 j = 0; j < PicLength; j++)
// {
// float CurrentData = Spectrum[StartIndex];
// float NormalizedData = Normalize(CurrentData);
//
// Canvas->K2_DrawLine(FVector2D(j - 1, LastPoint), FVector2D(j, NormalizedData), 1, RenderColor.HSVToLinearRGB());
// LastPoint = NormalizedData;
// StartIndex += 1;
// }
//
//
//
//
//
// UKismetRenderingLibrary::EndDrawCanvasToRenderTarget(GWorld->GetWorld(), RenderTargetContext);
//
//
// FBufferArchive Buffer;
// FImageUtils::ExportRenderTarget2DAsPNG(TextureRenderTarget2D, Buffer);
// FFileHelper::SaveArrayToFile(Buffer, *FPaths::Combine(FUtils::GetProjectTempPath(), ClipData->ClipGuid.ToString(), FString::FromInt(Index) + ".png"));
// TextureRenderTarget2D->MarkAsGarbage();
// FSlateDynamicImageBrush SlateBrush = FSlateDynamicImageBrush(*FPaths::Combine(FUtils::GetProjectTempPath(), ClipData->ClipGuid.ToString(), FString::FromInt(Index) + ".png"), FVector2D(PicLength, FGlobalData::DefaultTrackHeight));
// ClipData->AudioBrushLength.Add(PicLength);
// ClipData->AudioBrushes.Add(SlateBrush);
// Index++;
// }

View File

@ -47,25 +47,28 @@ uint8* FUtils::ConvertFfMpegSound2PortAudioSound(uint8* inData[8], int32 Size)
}
uint8* FUtils::ConvertTwoChannelSound2PortAudioSound(uint8* Channel1, uint8* Channel2, int32 Size)
uint8* FUtils::ConvertTwoChannelSound2PortAudioSound(uint8* Channel[], const int32 ChannelNum, const int32 Size, const int32 SampleBytes)
{
void* Data = FMemory::Malloc(Size * 4 * 2);
FMemory::Memset(Data, 0, Size * 4 * 2);
if (Channel1 == nullptr)
if (Channel == nullptr)
return nullptr;
if (Channel2 == nullptr)
return nullptr;
if (*Channel1 == '\0' || *Channel2 == '\0')
for (int32 i = 0; i < ChannelNum; i++)
{
FMemory::Free(Data);
Data = nullptr;
return nullptr;
if (Channel[i] == nullptr)
return nullptr;
if (*Channel[i] == '\0')
return nullptr;
}
void* Data = FMemory::Malloc(Size * SampleBytes * ChannelNum);
FMemory::Memset(Data, 0, Size * SampleBytes * ChannelNum);
float* DataPtr = static_cast<float*>(Data);
for (int32 i = 0; i < Size; i++)
{
*(DataPtr + i * 2) = *(reinterpret_cast<float*>(Channel1) + i);
*(DataPtr + i * 2 + 1) = *(reinterpret_cast<float*>(Channel2) + i);
for (int32 j = 0; j < ChannelNum; j++)
{
*(DataPtr + i * ChannelNum + j) = *(reinterpret_cast<float*>(Channel[j]) + i);
}
}
return static_cast<uint8*>(Data);
@ -92,6 +95,150 @@ FSlateDynamicImageBrush* FUtils::GetBrushFromImage(const FString& ImageName, con
return Brush;
}
TArray<FColor> FUtils::SingleColor2ColorArray(FColor Color)
{
int32 i = FGlobalData::LightArrayX * FGlobalData::LightArrayY;
TArray<FColor> ColorArray;
while (i--)
{
ColorArray.Add(Color);
}
return ColorArray;
}
int32 FUtils::GetFormatSampleBytesNum(const AVSampleFormat Format)
{
if (Format == AV_SAMPLE_FMT_U8 || Format == AV_SAMPLE_FMT_U8P)
{
return 1;
}
else if (Format == AV_SAMPLE_FMT_S16 || Format == AV_SAMPLE_FMT_S16P)
{
return 2;
}
else if (Format == AV_SAMPLE_FMT_S32 || Format == AV_SAMPLE_FMT_S32P)
{
return 4;
}
else if (Format == AV_SAMPLE_FMT_FLT || Format == AV_SAMPLE_FMT_FLTP)
{
return 4;
}
else if (Format == AV_SAMPLE_FMT_DBL || Format == AV_SAMPLE_FMT_DBLP)
{
return 8;
}
else if (Format == AV_SAMPLE_FMT_U8P)
{
return 1;
}
else if (Format == AV_SAMPLE_FMT_S16P)
{
return 2;
}
else if (Format == AV_SAMPLE_FMT_S32P)
{
return 4;
}
else if (Format == AV_SAMPLE_FMT_FLTP)
{
return 4;
}
else if (Format == AV_SAMPLE_FMT_DBLP)
{
return 8;
}
else
{
return 0;
}
}
int32 FUtils::GetFormatType(const AVSampleFormat Format)
{
int32 Type = -1;
switch (Format)
{
case AV_SAMPLE_FMT_U8:
{
Type = 0;
}
break;
case AV_SAMPLE_FMT_S16:
{
Type = 1;
}
break;
case AV_SAMPLE_FMT_S32:
{
Type = 2;
}
break;
case AV_SAMPLE_FMT_FLT:
{
Type = 3;
}
break;
case AV_SAMPLE_FMT_DBL:
{
Type = 4;
}
break;
case AV_SAMPLE_FMT_U8P:
{
Type = 0;
}
break;
case AV_SAMPLE_FMT_S16P:
{
Type = 1;
}
break;
case AV_SAMPLE_FMT_S32P:
{
Type = 2;
}
break;
case AV_SAMPLE_FMT_FLTP:
{
Type = 3;
}
break;
case AV_SAMPLE_FMT_DBLP:
{
Type = 4;
}
break;
default:
{
Type = -1;
}
break;
}
return Type;
}
FGuid FUtils::GetSoundThreadGuid(const FGuid& ClipGuid)
{
FGuid NewGuid = ClipGuid;
NewGuid.A += 20;
NewGuid.B += 20;
NewGuid.C += 20;
NewGuid.D += 20;
return NewGuid;
}
FGuid FUtils::GetVideoThreadGuid(const FGuid& ClipGuid)
{
FGuid NewGuid = ClipGuid;
NewGuid.A += 40;
NewGuid.B += 40;
NewGuid.C += 40;
NewGuid.D += 40;
return NewGuid;
}
bool FUtils::DetectDragTypeCanDrop(const FClipData& DraggingType, const ETrackType& DropTrackType)
{
if (DropTrackType == ETrackType::LightArrayTrack || DropTrackType == ETrackType::LightBarTrack || DropTrackType == ETrackType::SpotLightTrack || DropTrackType == ETrackType::AtomSphereLightTrack)

View File

@ -9,13 +9,20 @@ public:
// Size is nb_samples if it was float type
static uint8* ConvertFfMpegSound2PortAudioSound(uint8* inData[8], int32 Size);
static uint8* ConvertTwoChannelSound2PortAudioSound(uint8* Channel1, uint8* Channel2, int32 Size);
static uint8* ConvertTwoChannelSound2PortAudioSound(uint8* Channel[], const int32 ChannelNum, const int32 Size, const int32 SampleBytes);
static FString GetResourcesPath(FString ResourcesName, bool bFullPath = false);
static FString GetProjectTempPath();
static FSlateDynamicImageBrush* GetBrushFromImage(const FString& ImageName, const FVector2D Size);
static TArray<FSlateDynamicImageBrush*> BrushPtr;
static TArray<FColor> SingleColor2ColorArray(FColor Color);
static int32 GetFormatSampleBytesNum(const AVSampleFormat Format);
static int32 GetFormatType(const AVSampleFormat Format);
template <typename T, typename U>
static T* CastTypeByFormat(U* InValue, AVSampleFormat* Format);
static FGuid GetSoundThreadGuid(const FGuid& ClipGuid);
static FGuid GetVideoThreadGuid(const FGuid& ClipGuid);
static bool DetectDragTypeCanDrop(const FClipData& DraggingType, const ETrackType& DropTrackType);
/**
@ -82,6 +89,57 @@ public:
static FString Color2Hex3(FColor Color);
};
template <typename T, typename U>
T* FUtils::CastTypeByFormat(U* InValue, AVSampleFormat* Format)
{
if (*Format == AV_SAMPLE_FMT_U8 || *Format == AV_SAMPLE_FMT_U8P)
{
return reinterpret_cast<uint8*>(InValue);
}
else if (*Format == AV_SAMPLE_FMT_S16 || *Format == AV_SAMPLE_FMT_S16P)
{
return static_cast<int16*>(InValue);
}
else if (*Format == AV_SAMPLE_FMT_S32 || *Format == AV_SAMPLE_FMT_S32P)
{
return static_cast<int32*>(InValue);
}
else if (*Format == AV_SAMPLE_FMT_FLT || *Format == AV_SAMPLE_FMT_FLTP)
{
return static_cast<float*>(InValue);
}
else if (*Format == AV_SAMPLE_FMT_DBL || *Format == AV_SAMPLE_FMT_DBLP)
{
return static_cast<double*>(InValue);
}
else if (*Format == AV_SAMPLE_FMT_U8P)
{
return static_cast<uint8*>(InValue);
}
else if (*Format == AV_SAMPLE_FMT_S16P)
{
return static_cast<int16*>(InValue);
}
else if (*Format == AV_SAMPLE_FMT_S32P)
{
return static_cast<int32*>(InValue);
}
else if (*Format == AV_SAMPLE_FMT_FLTP)
{
return static_cast<float*>(InValue);
}
else if (*Format == AV_SAMPLE_FMT_DBLP)
{
return static_cast<double*>(InValue);
}
else
{
return InValue;
}
}
class FSaveModifier
{
public:

View File

@ -5,5 +5,7 @@ void FTimelineClipCommands::RegisterCommands()
{
UI_COMMAND(Remove, "移除", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(Break, "分割", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(Fill2Start, "填充到开头", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(Fill2End, "填充到结尾", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
}
#undef LOCTEXT_NAMESPACE

View File

@ -19,4 +19,6 @@ public:
TSharedPtr<FUICommandInfo> Remove;
TSharedPtr<FUICommandInfo> Break;
TSharedPtr<FUICommandInfo> Fill2Start;
TSharedPtr<FUICommandInfo> Fill2End;
};

View File

@ -261,7 +261,7 @@ struct CUT5_API FPresetsCustomData
TArray<FLinearColor> Colors = { FLinearColor(1, 1 , 1) };
int32 Times = 1;
float Angle;
float Angle = 0.0;
float Time = 0.3;
EPresetCustomType PresetCustomType = EPresetCustomType::None;
@ -375,8 +375,6 @@ struct CUT5_API FClipData
{
VideoStartFrame += CropFrame;
}
}
else
{
@ -402,6 +400,7 @@ struct CUT5_API FClipData
// A Ptr to Input Resource;
FTimelinePropertyData* ResourcePropertyDataPtr = nullptr;
FGuid ResourcePropertyGuid;
AVSampleFormat SampleFormat;
// Movies
FString MoviePath;
@ -509,6 +508,14 @@ struct CUT5_API FTimelinePropertyData
Type = InType;
IconPath = InIconPath;
}
FTimelinePropertyData(bool InCanUse)
{
CanUse = InCanUse;
Name = "";
Type = ETrackType::None;
IconPath = "";
}
bool bIsValid = true;
FString Name = "";
ETrackType Type = ETrackType::VideoTrack;
@ -526,13 +533,14 @@ struct CUT5_API FTimelinePropertyData
int32 AudioStream = -1;
int32 AudioSample = 0;
int32 AudioChannels = 2;
AVSampleFormat SampleFormat;
// Base Data
FString MoviePath = "";
int32 MovieFrameLength = 0;
TArray<uint8> AudioData;
bool CanUse = true;
bool bIsCustomPresetData = false;
FPresetsCustomData PresetsCustomData = FPresetsCustomData();
@ -994,7 +1002,7 @@ struct FProperties
struct FEncodeVideoInfo
{
FString EncodedVideoName = ".mp4";
FString EncodedVideoName = "";
FString EncodedVideoTimeCode = "00:00:00:00";
int32 ClipStartFrame = 0;
int32 ClipEndFrame = 0;

View File

@ -25,7 +25,7 @@ void DragDropOperator::UpdateClipProcess(ICutMainWidgetInterface* MainInterface,
{
if (!MainInterface)
return;
int32 MaxLength = 0;
for (FSingleTrackGroupInstance& SingleTrackGroupInstance : MainInterface->GetCutTimeline()->TrackGroupInstances)
{
TSharedPtr<STrackHead> TrackHead = StaticCastSharedPtr<STrackHead>(SingleTrackGroupInstance.Head);
@ -33,6 +33,10 @@ void DragDropOperator::UpdateClipProcess(ICutMainWidgetInterface* MainInterface,
for (int32 i = TrackHead->TrackData.ClipData.Num() - 1; i >= 0; i--)
{
if (TrackHead->TrackData.ClipData[i].ClipEndFrame > MaxLength)
{
MaxLength = TrackHead->TrackData.ClipData[i].ClipEndFrame;
}
if (TimelineClip.ClipStartFrame == TrackHead->TrackData.ClipData[i].ClipStartFrame || TimelineClip.ClipEndFrame == TrackHead->TrackData.ClipData[i].ClipEndFrame)
{
continue;
@ -102,6 +106,8 @@ void DragDropOperator::UpdateClipProcess(ICutMainWidgetInterface* MainInterface,
TimelineClip.UpdateGradientCursor();
}
FGlobalData::TrackLength = MaxLength + 30;
MainInterface->GetCutTimeline()->UpdateTimelineLength();
return;
}
@ -518,6 +524,9 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
CloseCursorDecorator();
const auto& DragDropOperation = static_cast<FTrackClipDragOperation&>(DragDropEvent.GetOperation().ToSharedRef().Get());
FSlateApplication::Get().SetKeyboardFocus(static_cast<SCutMainWindow*>(SavedMainInterface)->AsShared());
if (DragDropOperation.DragDropType == FCutDragDropBase::EType::ClipsMove)
{
TSharedPtr<FClipsMoveDragDropOperation> ClipMove = DragDropEvent.GetOperationAs<FClipsMoveDragDropOperation>();
@ -706,14 +715,21 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
TSharedPtr<STrackHead> TrackHead = TrackBody->TrackHead;
TSharedPtr<FDeviceDragDrop> CutDragDropBase = DragDropEvent.GetOperationAs<FDeviceDragDrop>();
if (CutDragDropBase->TrackType == ETrackType::None)
{
return;
}
FTrackData NewTrackData;
NewTrackData.TrackType = CutDragDropBase->TrackType;
NewTrackData.TrackName = CutDragDropBase->DeviceName;
FDeviceTrack NewDeviceTrack;
NewDeviceTrack.DeviceName = CutDragDropBase->DeviceName;
NewDeviceTrack.DeviceType = CutDragDropBase->TrackType;
if (TrackHead->GroupName == TEXT("固定轨道"))
{
return;
}
CutDragDropBase->MainInterface->GetCutTimeline()->AddNewDeviceToGroup(TrackHead->GroupName, NewDeviceTrack);
CutDragDropBase->MainInterface->OnAddNewTrack(ETrackType::PlayerTrack);
return;
@ -886,6 +902,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
return;
}
NewClipData.ClipType = TrackHead->TrackData.TrackType;
NewClipData.BindTrackGuid = TrackHead->TrackData.DeviceTrack.Guid;
TSharedPtr<STrackBody> OriginTrackBody = StaticCastSharedPtr<STrackBody>(TimelineClip->Body);
OriginTrackBody->TrackHead->TrackData.ClipData.Remove(NewClipData);
TrackHead->TrackData.ClipData.Add(NewClipData);

View File

@ -19,7 +19,7 @@ void SColorPanel::Construct(const FArguments& InArgs)
CurrentSelectColor = ColorPtr->LinearRGBToHSV();
ColorS = ColorPtr->LinearRGBToHSV().G;
FTextBlockStyle TextBlockStyle = FAppStyle::GetWidgetStyle<FTextBlockStyle>("NormalText");
TextBlockStyle.SetFontSize(16);
TextBlockStyle.SetFontSize(13);
ChildSlot
[
SNew(SOverlay)

View File

@ -324,7 +324,7 @@ void SCustomInputPanel::Construct(const FArguments& InArgs)
AddPreset(TEXT("结束后常亮"), TEXT(""), EPresetType::Custom);
// AddPreset(TEXT("结束后常亮"), TEXT(""), EPresetType::Custom);
AddPreset(TEXT("渐变"), TEXT(""), EPresetType::Custom, FPresetsCustomData::EPresetCustomType::Gradient);
AddPreset(TEXT("亮白"), TEXT("亮白.dat"), EPresetType::Custom);
AddPreset(TEXT("红色"), TEXT("红色.dat"), EPresetType::Custom);

View File

@ -392,6 +392,7 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
CommandList->MapAction(FShortCutCommands::Get().PlayFrame, FExecuteAction::CreateLambda([this]()
{
CutTimeline->SetAutoPlay(!CutTimeline->AutoPlaying);
CutTimeline->PlayImage->SetImage(FUtils::GetBrushFromImage(FUtils::GetResourcesPath(CutTimeline->AutoPlaying ? "ColorSelectCircle.png" : "PlayButton.png"), {24, 24}));
}));
CommandList->MapAction(FShortCutCommands::Get().Delete, FExecuteAction::CreateLambda([this]()
{
@ -566,6 +567,11 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
FReply SCutMainWindow::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (HasMouseCapture())
{
GEngine->GameViewport->GetWindow()->MoveWindowTo(GEngine->GameViewport->GetWindow()->GetPositionInScreen() + MouseEvent.GetCursorDelta());
}
this->NewMouseEvent = MouseEvent;
return SCompoundWidget::OnMouseMove(MyGeometry, MouseEvent);
}
@ -680,12 +686,34 @@ FReply SCutMainWindow::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
return FReply::Handled().EndDragDrop();
}
void SCutMainWindow::CloseAllThreads()
{
for (int32 i = 0; i < Threads.Num(); i++)
{
TArray<FGuid> Guids;
Threads.GetKeys(Guids);
for (int32 j = 0; j < Guids.Num(); j++)
{
Threads[Guids[j]]->Stop();
delete Threads[Guids[j]];
Threads.Remove(Guids[j]);
}
}
}
void SCutMainWindow::OnUpdateVideo(FGuid UUID, int32 X, int32 Y, uint8* RawData)
{
ICutMainWidgetInterface::OnUpdateVideo(UUID, X, Y, RawData);
StatePanel->VideoPlayer->UpdateVideoData(UUID, X, Y, RawData);
if (!IsInGameThread())
{
}
else
{
ICutMainWidgetInterface::OnUpdateVideo(UUID, X, Y, RawData);
StatePanel->VideoPlayer->UpdateVideoData(UUID, X, Y, RawData);
}
}
void SCutMainWindow::OnUpdateLightArray(const TArray<FColor>& LightArray)
@ -797,7 +825,7 @@ void SCutMainWindow::OpenTimeline(const FString& TimelineName, bool NeedSaveBefo
if (CutTimeline->LoadTimeline(TimelineName, TimelineInfo))
{
CutTimeline->TimelineInfo = TimelineInfo;
CutTimeline->CurrentEditDebug->SetText(FText::FromString(TEXT("当前正在编辑") + TimelineInfo.CurrentOpenFullPath));
// CutTimeline->CurrentEditDebug->SetText(FText::FromString(TEXT("当前正在编辑") + TimelineInfo.CurrentOpenFullPath));
}
OnAddNewTrack(ETrackType::PlayerTrack);
@ -989,7 +1017,8 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
}
}
}
bool bIsLightBar = false;
for (FDeviceTrackGroup& DeviceTrackGroup : CutTimeline->DeviceTrackGroups)
{
for (FDeviceTrack& TrackData : DeviceTrackGroup.DeviceTracks)
@ -1031,14 +1060,21 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
DMLight->InsertNewChildElement("Name")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
DeviceID++;
IDList.Add(TrackData.Guid, DeviceID);
break;
}
case ETrackType::LightBarTrack:
{
if (bIsLightBar)
{
break;
}
tinyxml2::XMLElement* LightArray = LightArrayList->InsertNewChildElement("GuangZhen");
LightArray->InsertNewChildElement("ID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(DeviceID)));
LightArray->InsertNewChildElement("Name")->InsertNewText(TCHAR_TO_UTF8(*TrackData.DeviceName));
DeviceID++;
IDList.Add(TrackData.Guid, DeviceID);
bIsLightBar = true;
break;
}
default:
break;
@ -1131,7 +1167,7 @@ void SCutMainWindow::ExportProject(const FString& ExportPath)
}
// KeyBoard
tinyxml2::XMLElement* Keyboard = RootElement->InsertNewChildElement("KeyBoard");
tinyxml2::XMLElement* Keyboard = DeviceList->InsertNewChildElement("KeyBoard");
{
tinyxml2::XMLElement* KeyCode = Keyboard->InsertNewChildElement("KeyCode");
KeyCode->InsertNewChildElement("CTRL")->InsertNewText("");
@ -1355,8 +1391,12 @@ void SCutMainWindow::DeleteAllAssetsInTimeline()
void SCutMainWindow::PreSettingBeforeSeek()
{
// OnUpdateProjector(0, true);
OnUpdateVideo(FGuid::NewGuid(), 1920, 1080, nullptr);
// OnUpdateVideo(FGuid::NewGuid(), 1920, 1080, nullptr);
OnUpdateSpotLight(0, FColor(255, 255, 255 ,255));
for (int32 i = 0; i < CutTimeline->TrackGroupInstances.Num(); i++)
{
OnUpdatePlayers(CutTimeline->TrackGroupInstances[i].Body, FColor(255, 255, 255, 255));
}
}
void SCutMainWindow::OpenColorPanel(FLinearColor* ColorPtr)
@ -1390,30 +1430,35 @@ ESelectMode SCutMainWindow::GetSelectedMode()
return SelectMode;
}
SCutMainWindow* SCutMainWindow::GetSelf()
{
return this;
}
FReply SCutMainWindow::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
{
if (CommandList->ProcessCommandBindings(InKeyEvent))
{
return FReply::Handled();
return SCompoundWidget::OnKeyDown(MyGeometry, InKeyEvent);
}
return FReply::Handled();
return SCompoundWidget::OnKeyDown(MyGeometry, InKeyEvent);
}
FReply SCutMainWindow::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
return FReply::Handled().ReleaseMouseCapture();
}
FReply SCutMainWindow::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (CommandList->ProcessCommandBindings(MouseEvent))
{
return FReply::Handled();
}
return FReply::Handled();
return FReply::Handled().CaptureMouse(SharedThis(this));
}
FReply SCutMainWindow::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (CommandList->ProcessCommandBindings(MouseEvent))
{
return FReply::Handled();
}
return FReply::Handled();
}
@ -1454,7 +1499,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par
}
if (Count == 0)
{
Event_List->InsertNewText("");
tinyxml2::XMLElement* Event = Event_List->InsertNewChildElement("Event");
Event->InsertNewChildElement("Value")->InsertNewText("0");
Event->InsertNewChildElement("TimeCode")->InsertNewText("0");
}
}
}
@ -1473,7 +1520,14 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par
tinyxml2::XMLElement* SpeicalEffect = PlayerLight->InsertNewChildElement("Special_Effects_List");
if (TrackData.ClipData.Num() == 0)
{
SpeicalEffect->InsertNewText("");
// Default
tinyxml2::XMLElement* NewSpeicalEffect = SpeicalEffect->InsertNewChildElement("Special_Effect");
NewSpeicalEffect->InsertNewChildElement("Mode")->InsertNewText("0");
NewSpeicalEffect->InsertNewChildElement("InitialColor")->InsertNewText("106090");
NewSpeicalEffect->InsertNewChildElement("EndColor")->InsertNewText("000000");
NewSpeicalEffect->InsertNewChildElement("TimeLength")->InsertNewText("-1");
NewSpeicalEffect->InsertNewChildElement("TimeCode")->InsertNewText("0");
NewSpeicalEffect->InsertNewChildElement("Cycle")->InsertNewText("0");
}
for (int32 k = 0; k < TrackData.ClipData.Num(); k++)
{
@ -1501,6 +1555,27 @@ tinyxml2::XMLElement* SCutMainWindow::GetDeviceElement(tinyxml2::XMLElement* Par
NewSpeicalEffect->InsertNewChildElement("TimeCode")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::GetMsFromString(FGlobalData::GetTimeData(TempClipData.ClipStartFrame)))));
NewSpeicalEffect->InsertNewChildElement("Cycle")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%d"), TempClipData.PresetsCustomData.Times)));
}
if (TempClipData.PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Gradient)
{
tinyxml2::XMLElement* NewSpeicalEffect = SpeicalEffect->InsertNewChildElement("Special_Effect");
NewSpeicalEffect->InsertNewChildElement("Mode")->InsertNewText("0");
NewSpeicalEffect->InsertNewChildElement("InitialColor")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(TempClipData.PresetsCustomData.Cursors[0].Color.ToFColor(false)))));
NewSpeicalEffect->InsertNewChildElement("EndColor")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(TempClipData.PresetsCustomData.Cursors[1].Color.ToFColor(false)))));
float PerLength = (TempClipData.PresetsCustomData.Time / TempClipData.PresetsCustomData.Times) / 2;
NewSpeicalEffect->InsertNewChildElement("TimeLength")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%d"), int32(PerLength * 1000))));
NewSpeicalEffect->InsertNewChildElement("TimeCode")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::GetMsFromString(FGlobalData::GetTimeData(TempClipData.ClipStartFrame)))));
NewSpeicalEffect->InsertNewChildElement("Cycle")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%d"), TempClipData.PresetsCustomData.Times)));
}
if (TempClipData.PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None)
{
tinyxml2::XMLElement* NewSpeicalEffect = SpeicalEffect->InsertNewChildElement("Special_Effect");
NewSpeicalEffect->InsertNewChildElement("Mode")->InsertNewText("0");
NewSpeicalEffect->InsertNewChildElement("InitialColor")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(TempClipData.PresetsCustomData.Colors[0].ToFColor(false)))));
NewSpeicalEffect->InsertNewChildElement("EndColor")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::Color2Hex3(TempClipData.PresetsCustomData.Colors[0].ToFColor(false)))));
NewSpeicalEffect->InsertNewChildElement("TimeLength")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%d"), -1)));
NewSpeicalEffect->InsertNewChildElement("TimeCode")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%ls"), *FUtils::GetMsFromString(FGlobalData::GetTimeData(TempClipData.ClipStartFrame)))));
NewSpeicalEffect->InsertNewChildElement("Cycle")->InsertNewText(TCHAR_TO_UTF8(*FString::Printf(TEXT("%d"), 1)));
}
}
j++;
}
@ -1584,7 +1659,15 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare
tinyxml2::XMLElement* Video = Parent->InsertNewChildElement("Video");
tinyxml2::XMLElement* URL = Video->InsertNewChildElement("URL");
{
URL->InsertNewText(TCHAR_TO_UTF8(*(FPaths::GetBaseFilename(EncodeVideoInfo.EncodedVideoName) + TEXT(".mp4"))));
if (EncodeVideoInfo.EncodedVideoName == "")
{
URL->InsertNewText("");
}
else
{
URL->InsertNewText(TCHAR_TO_UTF8(*(FPaths::GetBaseFilename(EncodeVideoInfo.EncodedVideoName) + TEXT(".mp4"))));
}
}
tinyxml2::XMLElement* Timecode = Video->InsertNewChildElement("Timecode");
{
@ -1598,11 +1681,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare
{
Mode->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
}
tinyxml2::XMLElement* ProjectorID = Video->InsertNewChildElement("ProjectorID");
{
ProjectorID->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(TempProjectorID)));
}
tinyxml2::XMLElement* VolumeEventList = Video->InsertNewChildElement("VolumeEventList");
{
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
@ -1625,6 +1704,13 @@ tinyxml2::XMLElement* SCutMainWindow::GetVideoElement(tinyxml2::XMLElement* Pare
}
}
tinyxml2::XMLElement* ProjectorID = Video->InsertNewChildElement("ProjectorID");
{
ProjectorID->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(TempProjectorID)));
}
tinyxml2::XMLElement* ProjectorEventList = Video->InsertNewChildElement("ProjectorEventList");
{
@ -1681,12 +1767,17 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Pare
tinyxml2::XMLElement* Sound = Parent->InsertNewChildElement("Sound");
{
Sound->InsertNewChildElement("RotationSpeakerID")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(RotatorSpeakerIndex)));
Sound->InsertNewChildElement("URL")->InsertNewText(TCHAR_TO_UTF8(*(FPaths::GetBaseFilename(EncodeVideoInfo.EncodedVideoName) + TEXT(".mp3"))));
if (EncodeVideoInfo.EncodedVideoName == "")
{
Sound->InsertNewChildElement("URL")->InsertNewText("");
}
else
{
Sound->InsertNewChildElement("URL")->InsertNewText(TCHAR_TO_UTF8(*(FPaths::GetBaseFilename(EncodeVideoInfo.EncodedVideoName) + TEXT(".mp3"))));
}
Sound->InsertNewChildElement("Loop")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
Sound->InsertNewChildElement("Mode")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
Sound->InsertNewChildElement("Round")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
Sound->InsertNewChildElement("Timecode")->InsertNewText(TCHAR_TO_UTF8(*FUtils::GetMsFromString(EncodeVideoInfo.EncodedVideoTimeCode)));
tinyxml2::XMLElement* VolumeEventList = Sound->InsertNewChildElement("VolumeEventList");
{
tinyxml2::XMLElement* VolumeEvent = VolumeEventList->InsertNewChildElement("VolumeEvent");
@ -1707,6 +1798,12 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Pare
}
}
}
Sound->InsertNewChildElement("Loop")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
Sound->InsertNewChildElement("Mode")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(0)));
Sound->InsertNewChildElement("Round")->InsertNewText(TCHAR_TO_UTF8(*FString::FromInt(1)));
Sound->InsertNewChildElement("Timecode")->InsertNewText(TCHAR_TO_UTF8(*FUtils::GetMsFromString(EncodeVideoInfo.EncodedVideoTimeCode)));
tinyxml2::XMLElement* RotationSpeakerEventList = Sound->InsertNewChildElement("RotationSpeakerEventList");
{
tinyxml2::XMLElement* RotationSpeakerEvent = RotationSpeakerEventList->InsertNewChildElement("RotationSpeakerEvent");
@ -1716,7 +1813,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundElement(tinyxml2::XMLElement* Pare
RotationSpeakerEventTimeCode->InsertNewText("0");
RotationSpeakerEventValue->InsertNewText("0");
RotationSpeakerEventValue->InsertNewText("1");
}
}
}
@ -1772,7 +1869,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetSoundListElement(tinyxml2::XMLElement*
}
if (Count == 0)
{
AudioList->InsertNewText("");
GetSoundElement(AudioList, FEncodeVideoInfo());
}
}
return nullptr;
@ -1787,6 +1884,10 @@ tinyxml2::XMLElement* SCutMainWindow::GetProcessA(tinyxml2::XMLElement* Parent,
OpenTimeline(CurtainGroup->Curtains[i].TimelineInfo.CurrentOpenFullPath, true, true);
GetProcessB(ProcessA, &CurtainGroup->Curtains[i]);
}
if (CurtainGroup->Curtains.Num() == 0)
{
ProcessA->InsertNewText("");
}
return ProcessA;
}
@ -1805,7 +1906,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetProcessB(tinyxml2::XMLElement* Parent,
// 非必须项
tinyxml2::XMLElement* Identity_SpecialEffects = ProcessB->InsertNewChildElement("Identity_SpecialEffects");
{
Identity_SpecialEffects->InsertNewText("");
tinyxml2::XMLElement* SpecialEffects = Identity_SpecialEffects->InsertNewChildElement("SpecialEffects");
SpecialEffects->InsertNewChildElement("PlayerID")->InsertNewText("1");
SpecialEffects->InsertNewChildElement("SpecialEffectID")->InsertNewText("");
}
tinyxml2::XMLElement* IsGlobal = ProcessB->InsertNewChildElement("IsGlobal");
{
@ -1813,7 +1916,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetProcessB(tinyxml2::XMLElement* Parent,
}
tinyxml2::XMLElement* State = ProcessB->InsertNewChildElement("State");
{
State->InsertNewText("");
State->InsertNewText("0");
}
tinyxml2::XMLElement* EnableCard = ProcessB->InsertNewChildElement("EnableCard");
{
@ -1896,6 +1999,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffectGroup(tinyxml2::XMLElement
}
tinyxml2::XMLElement* AutoNext = Effect->InsertNewChildElement("AutoNext");
AutoNext->InsertNewText("0");
Effect->InsertNewChildElement("TimeLength")->InsertNewText("-1");
GetSoundListElement(Effect);
GetDeviceElement(Effect);
GetVideoListElement(Effect);
@ -1909,6 +2015,9 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffectGroup(tinyxml2::XMLElement
{
State->InsertNewText("0");
}
GetTrigger(SpecialEffect);
return Effect;
}
@ -1924,6 +2033,7 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffect(tinyxml2::XMLElement* Par
}
tinyxml2::XMLElement* AutoNext = Effectxml->InsertNewChildElement("AutoNext");
Effectxml->InsertNewChildElement("TimeLength")->InsertNewText("-1");
AutoNext->InsertNewText("0");
GetSoundListElement(Effectxml);
GetDeviceElement(Effectxml);
@ -1938,9 +2048,26 @@ tinyxml2::XMLElement* SCutMainWindow::GetSpecialEffect(tinyxml2::XMLElement* Par
{
State->InsertNewText("0");
}
GetTrigger(SpecialEffect);
return Effectxml;
}
tinyxml2::XMLElement* SCutMainWindow::GetTrigger(tinyxml2::XMLElement* Parent)
{
tinyxml2::XMLElement* Trigger = Parent->InsertNewChildElement("Trigger");
Trigger->InsertNewChildElement("TriggerMode")->InsertNewText("");
Trigger->InsertNewChildElement("SerialNumberList")->InsertNewChildElement("SerialNumber")->InsertNewText("");
Trigger->InsertNewChildElement("SerialNumber")->InsertNewText("");
tinyxml2::XMLElement* KeyCode = Trigger->InsertNewChildElement("KeyCode");
KeyCode->InsertNewChildElement("CTRL")->InsertNewText("");
KeyCode->InsertNewChildElement("SHIFT")->InsertNewText("");
KeyCode->InsertNewChildElement("ALT")->InsertNewText("");
KeyCode->InsertNewChildElement("KEY")->InsertNewText("");
Trigger->InsertNewChildElement("ActionMode")->InsertNewText("");
return Trigger;
}
int32 SCutMainWindow::GetTrackID(FGuid Guid) const
{
const int32* Index = IDList.Find(Guid);
@ -1948,5 +2075,29 @@ int32 SCutMainWindow::GetTrackID(FGuid Guid) const
return NewIndex;
}
FRunnable* SCutMainWindow::GetThread(const FGuid& Guid)
{
if (!Threads.Find(Guid))
{
return nullptr;
}
return *Threads.Find(Guid);
}
void SCutMainWindow::AddThread(const FGuid& Guid, FRunnable* InSoundThread)
{
if (!Threads.Find(Guid))
{
Threads.Add(Guid, InSoundThread);
}
else
{
FRunnable* Thread = *Threads.Find(Guid);
Thread->Stop();
delete Thread;
Threads[Guid] = InSoundThread;
}
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

View File

@ -50,8 +50,13 @@ public:
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
virtual FReply OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
virtual FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
void CloseAllThreads();
FSoundThread* SoundThread;
float TotalTime;
bool bRenderLine = false;
@ -89,10 +94,12 @@ public:
virtual void OpenColorPanel(FLinearColor* ColorPtr);
virtual void AddNewCustomPreset(const FString& Name, const FPresetsCustomData CustomData) override;
virtual ESelectMode GetSelectedMode() override;
virtual SCutMainWindow* GetSelf() override;
FPointerEvent NewMouseEvent;
virtual bool SupportsKeyboardFocus() const override { return true; };
virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) 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;
@ -108,12 +115,17 @@ public:
tinyxml2::XMLElement* GetSpecialEffectList(tinyxml2::XMLElement* Parent);
tinyxml2::XMLElement* GetSpecialEffectGroup(tinyxml2::XMLElement* Parent, FEffectCardGroup* Group);
tinyxml2::XMLElement* GetSpecialEffect(tinyxml2::XMLElement* Parent, FEffectCardProperty* Effect);
tinyxml2::XMLElement* GetTrigger(tinyxml2::XMLElement* Parent);
int32 RotatorSpeakerIndex = 0;
int32 LightArrayIndex = 0;
TMap<FGuid, int32> IDList = {};
int32 GetTrackID(FGuid Guid) const;
TMap<FGuid, FRunnable*> Threads;
FRunnable* GetThread(const FGuid& Guid);
void AddThread(const FGuid& Guid, FRunnable* InSoundThread);
};

View File

@ -3,6 +3,7 @@
#include "SCutTimeline.h"
#include "SCutMainWindow.h"
#include "SlateOptMacros.h"
#include "STimelineTick.h"
#include "STrackBody.h"
@ -91,6 +92,7 @@ int32 SCutTimeline::GetCursorPosition() const
void SCutTimeline::Construct(const FArguments& InArgs)
{
MainWidgetInterface = InArgs._MainWidgetInterface;
ChildSlot
[
@ -150,8 +152,7 @@ void SCutTimeline::Construct(const FArguments& InArgs)
+ SHorizontalBox::Slot()
.FillWidth(300)
.AutoWidth()
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
@ -173,32 +174,50 @@ void SCutTimeline::Construct(const FArguments& InArgs)
.AutoWidth()
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.SizeParam(FAuto())
[
SNew(SImage)
.Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("PlayButton.png"), {}))
SNew(SBox)
.WidthOverride(24)
.HeightOverride(24)
[
SAssignNew(PlayImage, SImage)
.Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath("PlayButton.png"), {24, 24}))
.OnMouseButtonDown_Lambda([this](const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
SetAutoPlay(!AutoPlaying);
PlayImage->SetImage(FUtils::GetBrushFromImage(FUtils::GetResourcesPath(AutoPlaying ? "ColorSelectCircle.png" : "PlayButton.png"), {24, 24}));
return FReply::Handled();
})
]
]
+ SHorizontalBox::Slot()
.SizeParam(FStretch(1.0))
[
SAssignNew(ZoomSlider, SSlider)
.MaxValue(1.0)
.MinValue(0.0)
.Value(0.0f)
.OnValueChanged_Lambda([this](float ChangedValue)
{
FGlobalData::DefaultTimeTickSpace = FMath::GetMappedRangeValueClamped(FVector2D(0, 1.0), FVector2D(GetCachedGeometry().GetLocalSize().X / FGlobalData::TrackLength, 14), ChangedValue);
UpdateCursorPosition(GetCursorPosition());
RenderGroup();
})
]
+ SHorizontalBox::Slot()
.SizeParam(FAuto())
[
SAssignNew(CurrentEditDebug, STextBlock)
.Text(FText::FromString(TEXT("当前正在编辑主面板")))
SNew(SBox)
.WidthOverride(200)
[
SAssignNew(ZoomSlider, SSlider)
.MaxValue(1.0)
.MinValue(0.0)
.Value_Lambda([this]()
{
return FMath::GetMappedRangeValueClamped(FVector2D(GetCachedGeometry().GetLocalSize().X / FGlobalData::TrackLength, 14), FVector2D(0, 1.0), FGlobalData::DefaultTimeTickSpace);
})
.OnValueChanged_Lambda([this](float ChangedValue)
{
FGlobalData::DefaultTimeTickSpace = FMath::GetMappedRangeValueClamped(FVector2D(0, 1.0), FVector2D(GetCachedGeometry().GetLocalSize().X / FGlobalData::TrackLength, 14), ChangedValue);
UpdateCursorPosition(GetCursorPosition());
RenderGroup();
})
]
]
// + SHorizontalBox::Slot()
// .SizeParam(FAuto())
// [
// SAssignNew(CurrentEditDebug, STextBlock)
// .Text(FText::FromString(TEXT("当前正在编辑主面板")))
//
// ]
]
]
@ -366,23 +385,30 @@ void SCutTimeline::Construct(const FArguments& InArgs)
AddNewDeviceToGroup(TEXT("固定轨道"), LightBarData2);
FDeviceTrack SpotLightData(TEXT("投射灯一"), ETrackType::SpotLightTrack);
AddNewDeviceToGroup(TEXT("固定轨道"), SpotLightData);
FTickCursorTimeThread* TickCursorTimeThread = new FTickCursorTimeThread(FGlobalData::GlobalFPS, [this]()
{
UpdateCursorPosition(GetCursorPosition() + 1);
});
FRunnableThread::Create(TickCursorTimeThread, TEXT("TickCursorTimeThread"));
}
void SCutTimeline::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
if (AutoPlaying)
{
TimeSpace += InDeltaTime;
if (TimeSpace >= 1.0 / FGlobalData::GlobalFPS)
if (TimeSpace >= (1.0 / FGlobalData::GlobalFPS))
{
UpdateCursorPosition(GetCursorPosition() + 1);
TimeSpace = 0.0;
}
}
SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
}
bool FSingleTrackGroupInstance::IsThis(TSharedPtr<IWidgetInterface> WidgetInterface) const
@ -428,6 +454,15 @@ void SCutTimeline::AddNewTrackToGroup(FString GroupName, FTrackData TrackData, E
void SCutTimeline::SetAutoPlay(bool bStart)
{
AutoPlaying = bStart;
if (bStart)
{
ClockRun = true;
}
else
{
ClockRun = false;
}
}
int32 SCutTimeline::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect,
@ -833,6 +868,10 @@ void SCutTimeline::AddSelectedClipsOffset(int32 FrameOffset)
ClipData->ClipStartFrame += FrameOffset;
ClipData->ClipEndFrame += FrameOffset;
}
for (FClipData* ClipData : NewSelectedClipData)
{
DragDropOperator::GetDragDropOperator()->UpdateClipProcess(MainWidgetInterface, *ClipData);
}
RenderGroup();
}
}
@ -845,6 +884,11 @@ void SCutTimeline::AddSelectedClipsOffset(int32 FrameOffset)
ClipData->ClipStartFrame += FrameOffset;
ClipData->ClipEndFrame += FrameOffset;
}
for (FClipData* ClipData : NewSelectedClipData)
{
DragDropOperator::GetDragDropOperator()->UpdateClipProcess(MainWidgetInterface, *ClipData);
}
RenderGroup();
}
}

View File

@ -17,6 +17,9 @@
*
*/
static inline std::atomic<bool> ClockRun = false;
struct FTrackGroup
{
// TrackGroup Mean Device
@ -66,8 +69,11 @@ public:
void Construct(const FArguments& InArgs);
virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
float TimeSpace = 0.0f;
float LastTime = 0.1f;
void AddNewTrackToGroup(FString GroupName, FTrackData TrackData, ETrackType GroupType = ETrackType::None);
void SetAutoPlay(bool bStart);
FTimerHandle TimerHandle;
bool AutoPlaying = false;
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
@ -113,6 +119,7 @@ public:
FTimelineInfo TimelineInfo;
FGuid SelectedClipGUID;
TSharedPtr<SImage> PlayImage;
/**
* @brief Selected Clips Guid, Use for Multi-Select.
@ -140,3 +147,45 @@ public:
};
class FTickCursorTimeThread final : public FRunnable
{
public:
FTickCursorTimeThread(int32 InFPS, TFunction<void()> InBindFunction)
{
FPS = InFPS;
BindFunction = InBindFunction;
}
int32 FPS = 0;
TFunction<void()> BindFunction;
bool bIsDead = false;
virtual uint32 Run() override
{
while (!bIsDead)
{
if (ClockRun)
{
FPlatformProcess::Sleep(1.0f / FPS);
FFunctionGraphTask::CreateAndDispatchWhenReady([this]()
{
if (BindFunction)
BindFunction();
}, TStatId(), nullptr, ENamedThreads::GameThread);
}
}
return 0;
};
virtual void Stop() override
{
bIsDead = true;
};
virtual void Exit() override
{
};
virtual bool Init() override
{
return true;
};
};

View File

@ -8,17 +8,20 @@
#include "AudioDevice.h"
#include "ImageUtils.h"
#include "SCutMainWindow.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/Interface/VideoInterface.h"
#include "Cut5/Utils/FFMPEGUtils.h"
#include "Cut5/Utils/Utils.h"
#include "DragDropOperator/DragDropOperator.h"
#include "Engine/Engine.h"
#include "Engine/Texture2D.h"
#include "HAL/ThreadManager.h"
#include "MicroWidgets/SNewProjectTips.h"
#include "Presets/SClipCursor.h"
#include "Rendering/DrawElementPayloads.h"
@ -48,6 +51,8 @@ FReply STimelineClip::OnBorderMouseButtonDown(const FGeometry& Geometry, const F
FMenuBuilder MenuBuilder(true, CommandList);
MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().Remove);
MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().Break);
MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().Fill2Start);
MenuBuilder.AddMenuEntry(FTimelineClipCommands::Get().Fill2End);
MenuContent = MenuBuilder.MakeWidget();
FSlateApplication::Get().PushMenu(AsShared(), FWidgetPath(), MenuContent.ToSharedRef(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect::ContextMenu);
return FReply::Handled();
@ -171,6 +176,8 @@ FReply STimelineClip::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointe
return FReply::Handled();
}
void STimelineClip::Construct(const FArguments& InArgs)
{
CommandList = InArgs._CommandList;
@ -202,7 +209,26 @@ void STimelineClip::Construct(const FArguments& InArgs)
];
if (ClipData->ClipType == ETrackType::AudioTrack)
{
// if (!MainWidgetInterface->GetSelf()->GetThread(ClipData->ClipGuid))
// {
// FVideoThread* Thread = new FVideoThread([this](uint8* RawData, int32 Size, int32 X, int32 Y)
// {
// MainWidgetInterface->OnUpdateVideo(ClipData->ClipGuid, X, Y, RawData);
// }, *ClipData);
// FRunnableThread::Create(Thread, TEXT("VideoThread"));
// }
}
if (ClipData->ClipType == ETrackType::VideoTrack)
{
if (!MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid)))
{
FVideoThread* Thread = new FVideoThread([this](uint8* RawData, int32 Size, int32 X, int32 Y)
{
MainWidgetInterface->OnUpdateVideo(ClipData->ClipGuid, X, Y, RawData);
}, *ClipData, MainWidgetInterface);
FRunnableThread::Create(Thread, TEXT("VideoThread"));
MainWidgetInterface->GetSelf()->AddThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid), Thread);
}
}
if (MainWidgetInterface->GetCutTimeline()->SelectedClipGUID == ClipData->ClipGuid)
{
@ -250,96 +276,14 @@ void STimelineClip::Seek(int32 Frame)
{
return;
}
// FDateTime A = FDateTime::Now();
const int32 Offset = Frame - (ClipData->ClipStartFrame);
int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset;
int32 VideoFPS = ClipData->ResourcePropertyDataPtr->VideoCodecContext->framerate.num;
if (VideoFPS < FGlobalData::GlobalFPS)
const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset;
if (MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid)))
{
const double Interval = FGlobalData::GlobalFPS / VideoFPS;
SeekMovieFrame = float(SeekMovieFrame) / Interval;
static_cast<FVideoThread*>(MainWidgetInterface->GetSelf()->GetThread(FUtils::GetVideoThreadGuid(ClipData->ClipGuid)))->SeekFrame(SeekMovieFrame);
}
else
{
VideoFPS = FGlobalData::GlobalFPS;
}
int64 Timestamp = av_rescale_q(float(SeekMovieFrame) / float(VideoFPS) * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, ClipData->ResourcePropertyDataPtr->Context->streams[ClipData->ResourcePropertyDataPtr->VideoStream]->time_base);
if (VideoFPS < FGlobalData::GlobalFPS || SeekMovieFrame - LastSeekFrame > 1 || SeekMovieFrame - LastSeekFrame < 0 || LastSeekFrame == 0)
{
AVRational frame_rate = ClipData->ResourcePropertyDataPtr->Context->streams[ClipData->ResourcePropertyDataPtr->VideoStream]->avg_frame_rate;
if (av_seek_frame(ClipData->ResourcePropertyDataPtr->Context, ClipData->ResourcePropertyDataPtr->VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD) < 0)
{
};
}
LastSeekFrame = SeekMovieFrame;
AVPacket* Packet = av_packet_alloc();
AVFrame* AllocatedFrame = av_frame_alloc();
av_init_packet(Packet);
avcodec_receive_frame(ClipData->ResourcePropertyDataPtr->VideoCodecContext, AllocatedFrame);
int32 Times = 0;
while (av_read_frame(ClipData->ResourcePropertyDataPtr->Context, Packet) >= 0)
{
if (Packet->stream_index == ClipData->ResourcePropertyDataPtr->VideoStream)
{
int32 Response = avcodec_send_packet(ClipData->ResourcePropertyDataPtr->VideoCodecContext, Packet);
if (Response < 0)
{
UE_LOG(LogTemp, Error, TEXT("Error while sending a packet to the decoder: %s"), *FString(FString::FromInt(Response)));
return;
}
Response = avcodec_receive_frame(ClipData->ResourcePropertyDataPtr->VideoCodecContext, AllocatedFrame);
if (Response == AVERROR(EAGAIN) || Response == AVERROR_EOF)
{
continue;
}
else if (Response < 0)
{
UE_LOG(LogTemp, Error, TEXT("Error while receiving a frame from the decoder: %s"), *FString(FString::FromInt(Response)));
return;
}
if (AllocatedFrame->best_effort_timestamp >= Timestamp)
{
av_packet_unref(Packet);
break;
}
}
}
av_packet_unref(Packet);
AVCodecContext* VideoCodecContext = ClipData->ResourcePropertyDataPtr->VideoCodecContext;
struct SwsContext* swsCtx = sws_getContext(
AllocatedFrame->width, AllocatedFrame->height, VideoCodecContext->pix_fmt,
AllocatedFrame->width, AllocatedFrame->height, AV_PIX_FMT_BGRA,
SWS_BILINEAR, NULL, NULL, NULL
);
if (!swsCtx)
{
UE_LOG(LogTemp, Error, TEXT("Error creating swsContext"));
return;
}
uint8* RawData = new uint8[AllocatedFrame->width * AllocatedFrame->height * 4];
uint8* dest[4] = {RawData, 0, 0, 0};
int32 dest_linesize[4] = {AllocatedFrame->width * 4, 0, 0, 0};
sws_scale(swsCtx, AllocatedFrame->data, AllocatedFrame->linesize, 0, AllocatedFrame->height, dest, dest_linesize);
sws_freeContext(swsCtx);
MainWidgetInterface->OnUpdateVideo(FGuid::NewGuid(), AllocatedFrame->width, AllocatedFrame->height, RawData);
DoSound(ESoundSolveType::None, Frame);
av_frame_free(&AllocatedFrame);
LastSeekFrame = SeekMovieFrame;
}
break;
@ -380,116 +324,34 @@ void STimelineClip::Seek(int32 Frame)
const int32 Offset = Frame - ClipData->ClipStartFrame;
const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset;
if (ClipData->LightArrayData.Num() != 0 && SeekMovieFrame < ClipData->LightArrayData.Num())
{
MainWidgetInterface->OnUpdateLightArray(ClipData->LightArrayData[SeekMovieFrame]);
break;
}
if (ClipData->PresetsCustomData.PresetCustomType != FPresetsCustomData::EPresetCustomType::None)
{
if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Breathe)
{
// 先拿到目前位置在第几个区间
float Between = -1;
int32 SingleAreaLength = (ClipData->ClipEndFrame - ClipData->ClipStartFrame) / ClipData->PresetsCustomData.Times / 2;
if (SeekMovieFrame > 0)
{
Between = (float)SeekMovieFrame / (float)SingleAreaLength;
}
if (Between != -1)
{
FLinearColor LinearColor = FLinearColor::Black;
FLinearColor CustomColor = ClipData->PresetsCustomData.Colors[0];
LinearColor = FMath::Lerp((int32)Between % 2 == 0 ? CustomColor : FLinearColor::Black, (int32)Between % 2 == 0 ? FLinearColor::Black : CustomColor, Between - (int32)Between);
TArray<FColor> Colors;
Colors.Init(LinearColor.ToFColor(false), FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4);
MainWidgetInterface->OnUpdateLightArray(Colors);
}
MainWidgetInterface->OnUpdateLightArray(FUtils::SingleColor2ColorArray(ClipData->GetBreathColor(SeekMovieFrame)));
}
else if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Flash)
{
float Between = -1;
int32 SingleAreaLength = (ClipData->ClipEndFrame - ClipData->ClipStartFrame) / ClipData->PresetsCustomData.Times / 2;
if (SeekMovieFrame > 0)
{
Between = (float)SeekMovieFrame / (float)SingleAreaLength;
}
if (Between != -1)
{
TArray<FColor> Colors;
Colors.Init((int32)Between % 2 == 1 ? ClipData->PresetsCustomData.Colors[0].ToFColor(false) : FLinearColor::Black.ToFColor(false), FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4);
MainWidgetInterface->OnUpdateLightArray(Colors);
}
}
if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None)
{
TArray<FColor> Colors;
Colors.Init(ClipData->ClipColors[0].ToFColor(false), FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4);
MainWidgetInterface->OnUpdateLightArray(Colors);
break;
MainWidgetInterface->OnUpdateLightArray(FUtils::SingleColor2ColorArray(ClipData->GetFlashColor(SeekMovieFrame)));
}
else if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Gradient)
{
int32 Between = -1;
for (int32 i = 0; i < ClipData->PresetsCustomData.Cursors.Num() - 1; i++)
{
if (SeekMovieFrame >= ClipData->PresetsCustomData.Cursors[i].CursorFrameOffset && SeekMovieFrame <= ClipData->PresetsCustomData.Cursors[i + 1].CursorFrameOffset)
{
Between = i;
}
}
if (SeekMovieFrame >= ClipData->PresetsCustomData.Cursors[ClipData->PresetsCustomData.Cursors.Num() - 1].CursorFrameOffset)
{
Between = ClipData->PresetsCustomData.Cursors.Num() - 1;
}
if (Between != -1)
{
if (Between == ClipData->PresetsCustomData.Cursors.Num() - 1)
{
TArray<FColor> Colors;
Colors.Init(ClipData->PresetsCustomData.Cursors[ClipData->PresetsCustomData.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->PresetsCustomData.Cursors[Between].Color, ClipData->PresetsCustomData.Cursors[Between + 1].Color, (float)(SeekMovieFrame - ClipData->PresetsCustomData.Cursors[Between].CursorFrameOffset) / (float)(ClipData->PresetsCustomData.Cursors[Between + 1].CursorFrameOffset - ClipData->PresetsCustomData.Cursors[Between].CursorFrameOffset)).ToFColor(false);
}
MainWidgetInterface->OnUpdateLightArray(Colors);
}
}
break;
MainWidgetInterface->OnUpdateLightArray(FUtils::SingleColor2ColorArray(ClipData->GetGradientColor(SeekMovieFrame)));
}
break;
}
if (SeekMovieFrame < ClipData->LightArrayData.Num())
else if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::None)
{
MainWidgetInterface->OnUpdateLightArray(ClipData->LightArrayData[SeekMovieFrame]);
MainWidgetInterface->OnUpdateLightArray(FUtils::SingleColor2ColorArray(ClipData->ClipColors[0].ToFColor(false)));
}
break;
}
case ETrackType::PlayerTrack:
{
const int32 Offset = Frame - ClipData->ClipStartFrame;
const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset;
if (SeekMovieFrame < ClipData->PlayerLightData.Num())
{
MainWidgetInterface->OnUpdatePlayers(Body, ClipData->PlayerLightData[SeekMovieFrame]);
}
break;
}
break;
case ETrackType::AudioTrack:
{
DoSound(ESoundSolveType::OnlyLeft, Frame);
@ -506,52 +368,25 @@ void STimelineClip::Seek(int32 Frame)
{
const int32 Offset = Frame - ClipData->ClipStartFrame;
const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset;
if (ClipData->PlayerLightData.Num() != 0 && SeekMovieFrame < ClipData->PlayerLightData.Num())
{
MainWidgetInterface->OnUpdatePlayers(Body, ClipData->PlayerLightData[SeekMovieFrame]);
break;
}
if (ClipData->PresetsCustomData.PresetCustomType != FPresetsCustomData::EPresetCustomType::None)
{
if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Breathe)
{
// 先拿到目前位置在第几个区间
float Between = -1;
int32 SingleAreaLength = (ClipData->ClipEndFrame - ClipData->ClipStartFrame) / ClipData->PresetsCustomData.Times / 2;
if (SeekMovieFrame > 0)
{
Between = (float)SeekMovieFrame / (float)SingleAreaLength;
}
if (Between != -1)
{
FLinearColor LinearColor = FLinearColor::Black;
FLinearColor CustomColor = ClipData->PresetsCustomData.Colors[0];
LinearColor = FMath::Lerp((int32)Between % 2 == 0 ? CustomColor : FLinearColor::Black, (int32)Between % 2 == 0 ? FLinearColor::Black : CustomColor, Between - (int32)Between);
// GEngine->AddOnScreenDebugMessage(-1, 0.1f, FColor::Red, FString::Printf(TEXT("Between %s"), *CustomColor.ToString()));
MainWidgetInterface->OnUpdatePlayers(Body, LinearColor.ToFColor(false));
}
MainWidgetInterface->OnUpdatePlayers(Body, ClipData->GetBreathColor(SeekMovieFrame));
}
else if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Flash)
{
float Between = -1;
int32 SingleAreaLength = (ClipData->ClipEndFrame - ClipData->ClipStartFrame) / ClipData->PresetsCustomData.Times / 2;
if (SeekMovieFrame > 0)
{
Between = (float)SeekMovieFrame / (float)SingleAreaLength;
}
if (Between != -1)
{
MainWidgetInterface->OnUpdatePlayers(Body, (int32)Between % 2 == 1 ? ClipData->PresetsCustomData.Colors[0].ToFColor(false) : FLinearColor::Black.ToFColor(false));
}
MainWidgetInterface->OnUpdatePlayers(Body, ClipData->GetFlashColor(SeekMovieFrame));
}
break;
}
if (ClipData->PresetType == EPresetType::NotAPresets)
{
if (SeekMovieFrame < ClipData->PlayerLightData.Num())
else if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Gradient)
{
MainWidgetInterface->OnUpdatePlayers(Body, ClipData->PlayerLightData[SeekMovieFrame]);
MainWidgetInterface->OnUpdatePlayers(Body, ClipData->GetGradientColor(SeekMovieFrame));
}
break;
}
@ -559,35 +394,7 @@ void STimelineClip::Seek(int32 Frame)
{
MainWidgetInterface->OnUpdatePlayers(Body, ClipData->ClipColors[0].ToFColor(false));
}
else if (ClipData->PresetsCustomData.PresetCustomType == FPresetsCustomData::EPresetCustomType::Gradient)
{
int32 Between = -1;
for (int32 i = 0; i < ClipData->PresetsCustomData.Cursors.Num() - 1; i++)
{
if (i == 0)
{
if (SeekMovieFrame <= ClipData->PresetsCustomData.Cursors[i].CursorFrameOffset)
{
Between = i;
}
}
if (i == ClipData->PresetsCustomData.Cursors.Num() - 2)
{
if (SeekMovieFrame >= ClipData->PresetsCustomData.Cursors[i].CursorFrameOffset && SeekMovieFrame <= ClipData->PresetsCustomData.Cursors[i + 1].CursorFrameOffset)
{
Between = i;
}
}
}
if (Between != -1)
{
FLinearColor LinearColor = FLinearColor::Black;
LinearColor = FMath::Lerp(ClipData->PresetsCustomData.Cursors[Between].Color, ClipData->PresetsCustomData.Cursors[Between + 1].Color, (float)(SeekMovieFrame - ClipData->PresetsCustomData.Cursors[Between].CursorFrameOffset) / (float)(ClipData->PresetsCustomData.Cursors[Between + 1].CursorFrameOffset - ClipData->PresetsCustomData.Cursors[Between].CursorFrameOffset));
MainWidgetInterface->OnUpdatePlayers(Body, LinearColor.ToFColor(false));
}
}
break;
}
default:
@ -603,6 +410,16 @@ void STimelineClip::UpdatePosition(int32 StartFrame)
}
const int32 NewPosX = StartFrame * FGlobalData::DefaultTimeTickSpace;
if (StartFrame > 0)
{
if (ClipData->VideoStartFrame + StartFrame - ClipData->ClipStartFrame < 0)
{
return;
}
}
SetRenderTransform(FSlateRenderTransform(FVector2D(NewPosX, 0)));
ClipDataBox->SetWidthOverride((ClipData->ClipEndFrame - StartFrame) * FGlobalData::DefaultTimeTickSpace);
if (ClipData->ClipType == ETrackType::VideoTrack)
@ -630,6 +447,13 @@ void STimelineClip::UpdateLength(int32 EndFrame)
{
return;
}
if (ClipData->ClipType == ETrackType::VideoTrack)
{
}
ClipDataBox->SetWidthOverride((EndFrame - ClipData->ClipStartFrame) * FGlobalData::DefaultTimeTickSpace);
if (ClipData->ClipType == ETrackType::VideoTrack)
{
@ -861,22 +685,64 @@ void STimelineClip::DoSound(ESoundSolveType SolveType, int32 InFrame)
TSharedPtr<STrackBody> NewBody = StaticCastSharedPtr<STrackBody>(Body);
if (NewBody->TrackHead->TrackData.IsMute)
return;
if (SoundThread == nullptr)
if (!static_cast<SCutMainWindow*>(MainWidgetInterface)->GetThread(ClipData->ClipGuid))
{
if (ClipData->ResourcePropertyDataPtr == nullptr)
return;
if (ClipData->ResourcePropertyDataPtr->AudioStream != -1)
{
SoundThread = new FSoundThread(2, ClipData->ResourcePropertyDataPtr->AudioSample);
PaSampleFormat Type = paInt16;
switch (FUtils::GetFormatType(ClipData->ResourcePropertyDataPtr->SampleFormat))
{
case 0:
{
Type = paUInt8;
break;
}
case 1:
{
Type = paInt16;
break;
}
case 2:
{
Type = paInt32;
break;
}
case 3:
{
Type = paFloat32;
break;
}
case 4:
{
break;
}
default:
{
Type = paInt32;
}
break;
}
SoundThread = new FSoundThread(2, ClipData->ResourcePropertyDataPtr->AudioSample, FUtils::GetFormatSampleBytesNum(ClipData->ResourcePropertyDataPtr->SampleFormat), Type);
FRunnableThread* Thread = FRunnableThread::Create(SoundThread, TEXT("SoundThread"));
SoundThread->CopyAudio(ClipData->ResourcePropertyDataPtr->AudioData.GetData(), ClipData->ResourcePropertyDataPtr->AudioData.Num(), SolveType);
static_cast<SCutMainWindow*>(MainWidgetInterface)->AddThread(ClipData->ClipGuid, SoundThread);
if (MainWidgetInterface->GetCutTimeline()->AutoPlaying)
{
SoundThread->StartPlay();
}
}
}
const int32 Offset = InFrame - ClipData->ClipStartFrame;
const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset;
if (SoundThread)
if (static_cast<SCutMainWindow*>(MainWidgetInterface)->GetThread(ClipData->ClipGuid))
{
SoundThread->SeekFrame(SeekMovieFrame);
static_cast<FSoundThread*>(MainWidgetInterface->GetSelf()->GetThread(ClipData->ClipGuid))->SeekFrame(SeekMovieFrame);
}
}

View File

@ -37,6 +37,7 @@ public:
FReply OnBorderMouseButtonDown(const FGeometry& Geometry, const FPointerEvent& PointerEvent);
FReply OnBorderMouseButtonUp(const FGeometry& Geometry, const FPointerEvent& PointerEvent);
virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
/** Constructs this widget with InArgs */
void Construct(const FArguments& InArgs);
FClipData* ClipData;
@ -55,10 +56,10 @@ public:
virtual FReply OnDragOver(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
TSharedPtr<SOverlay> ClipOverlay;
TSharedPtr<FUICommandList> CommandList;
FSoundThread* SoundThread;
void DoSound(ESoundSolveType SolveType, int32 InFrame);
FSoundThread* SoundThread = nullptr;
virtual void OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override;
virtual void OnDragLeave(const FDragDropEvent& DragDropEvent) override;
virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
@ -82,5 +83,7 @@ public:
int32 OriginClipStartFrame = 0;
int32 OriginClipEndFrame = 0;
AVFrame* LastFrame = nullptr;
};

View File

@ -33,6 +33,7 @@ void STimelineProperty::Construct(const FArguments& InArgs)
[
SNew(SImage)
.Image(FUtils::GetBrushFromImage(FUtils::GetResourcesPath(TimelinePropertyData.IconPath), {40, 40}))
.Visibility(TimelinePropertyData.Type == ETrackType::None ? EVisibility::Collapsed : EVisibility::Visible)
]
+ SOverlay::Slot()

View File

@ -151,6 +151,22 @@ void STimelinePropertyPanel::Construct(const FArguments& InArgs)
];
AddNewSelection(FTimelinePropertyData(TEXT("聚光灯"), ETrackType::SpotLightTrack, TEXT("SpotLight.png")));
AddNewSelection(FTimelinePropertyData(TEXT("氛围灯"), ETrackType::AtomSphereLightTrack, TEXT("PlayerLight.png")));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
AddNewSelection(FTimelinePropertyData(false));
}
void STimelinePropertyPanel::AddNewSelection(FTimelinePropertyData TimelinePropertyData)

View File

@ -3,6 +3,7 @@
#include "STrackBody.h"
#include "SCutMainWindow.h"
#include "SlateOptMacros.h"
#include "Commands/TimelineClipCommands.h"
#include "Cut5/Utils/FFMPEGUtils.h"
@ -26,6 +27,14 @@ void STrackBody::Construct(const FArguments& InArgs)
{
BreakClip(SelectedClipGUID);
}), FCanExecuteAction());
CommandList->MapAction(FTimelineClipCommands::Get().Fill2Start, FExecuteAction::CreateLambda([this]()
{
Fill2Start(SelectedClipGUID);
}), FCanExecuteAction());
CommandList->MapAction(FTimelineClipCommands::Get().Fill2End, FExecuteAction::CreateLambda([this]()
{
Fill2End(SelectedClipGUID);
}), FCanExecuteAction());
MainWidgetInterface = InArgs._MainWidgetInterface;
TrackHead = InArgs._TrackHead;
@ -66,15 +75,7 @@ void STrackBody::Construct(const FArguments& InArgs)
void STrackBody::CallRender()
{
Overlay->ClearChildren();
for (TSharedPtr<STimelineClip> Clip : SlateClips)
{
if (Clip->SoundThread)
{
Clip->SoundThread->Stop();
}
}
SlateClips.Empty();
for (FClipData& TempClipData : TrackHead->TrackData.ClipData)
@ -166,6 +167,39 @@ void STrackBody::RemoveClip(const FGuid& Guid)
CallRender();
}
inline void STrackBody::Fill2Start(const FGuid& Guid)
{
for (int32 i = 0; i < SlateClips.Num(); i++)
{
if (TrackHead->TrackData.ClipData[i].ClipGuid == Guid &&
TrackHead->TrackData.ClipData[i].ClipType != ETrackType::VideoTrack ||
TrackHead->TrackData.ClipData[i].ClipType != ETrackType::AudioTrack ||
TrackHead->TrackData.ClipData[i].ClipType != ETrackType::AudioTrackR)
{
TrackHead->TrackData.ClipData[i].ClipStartFrame = 0;
CallRender();
break;
}
}
}
void STrackBody::Fill2End(const FGuid& Guid)
{
for (int32 i = 0; i < SlateClips.Num(); i++)
{
if (TrackHead->TrackData.ClipData[i].ClipGuid == Guid &&
TrackHead->TrackData.ClipData[i].ClipType != ETrackType::VideoTrack ||
TrackHead->TrackData.ClipData[i].ClipType != ETrackType::AudioTrack ||
TrackHead->TrackData.ClipData[i].ClipType != ETrackType::AudioTrackR)
{
TrackHead->TrackData.ClipData[i].ClipEndFrame = FGlobalData::TrackLength;
CallRender();
break;
}
}
}
void STrackBody::BreakClip(const FGuid& Guid)
{
for (int32 i = 0; i < SlateClips.Num(); i++)

View File

@ -34,6 +34,8 @@ public:
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
virtual void RemoveClip(const FGuid& Guid) override;
virtual void BreakClip(const FGuid& Guid) override;
void Fill2Start(const FGuid& Guid);
void Fill2End(const FGuid& Guid);
// virtual bool CanDragOver() override;
@ -55,9 +57,12 @@ public:
};
inline int32 STrackBody::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry,
const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
if (bNeedRenderDragDropOver)

View File

@ -67,7 +67,9 @@ int32 SLightArrayPanel::OnPaint(const FPaintArgs& Args, const FGeometry& Allotte
// const FVector2D SingleLocalSize =
// FVector2D(AllottedGeometry.AbsoluteToLocal(FVector2D(LightGrid->GetCachedGeometry().Size.X / FGlobalData::LightArrayX, LightGrid->GetCachedGeometry().Size.Y / FGlobalData::LightArrayY)));
const FVector2D SingleLocalSize =
FVector2D(LightGrid->GetCachedGeometry().Size.X / FGlobalData::LightArrayX, LightGrid->GetCachedGeometry().Size.Y / FGlobalData::LightArrayY);
FVector2D((LightGrid->GetCachedGeometry().Size.X / FGlobalData::LightArrayX) / 2.0, (LightGrid->GetCachedGeometry().Size.Y / FGlobalData::LightArrayY) / 2.0);
const FVector2D OriginLocalSize =
FVector2D((LightGrid->GetCachedGeometry().Size.X / FGlobalData::LightArrayX), (LightGrid->GetCachedGeometry().Size.Y / FGlobalData::LightArrayY));
for (int32 i = 0; i < FGlobalData::LightArrayX; i++)
{
for (int32 j = 0; j < FGlobalData::LightArrayY; j++)
@ -76,7 +78,7 @@ int32 SLightArrayPanel::OnPaint(const FPaintArgs& Args, const FGeometry& Allotte
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId,
LightGrid->GetPaintSpaceGeometry().ToPaintGeometry(SingleLocalSize, FSlateLayoutTransform(FVector2D(i * SingleLocalSize.X, j * SingleLocalSize.Y))),
LightGrid->GetPaintSpaceGeometry().ToPaintGeometry(SingleLocalSize, FSlateLayoutTransform(FVector2D(i * OriginLocalSize.X, j * OriginLocalSize.Y))),
&Brush,
ESlateDrawEffect::None,
LightGridColors[j * FGlobalData::LightArrayX + i]