大量改动
This commit is contained in:
parent
f6765a04b1
commit
c0a718501a
@ -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
BIN
Resources/EngineLogo.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
@ -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; };
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
177
Source/Cut5/Interface/VideoInterface.cpp
Normal file
177
Source/Cut5/Interface/VideoInterface.cpp
Normal 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;
|
||||
}
|
23
Source/Cut5/Interface/VideoInterface.h
Normal file
23
Source/Cut5/Interface/VideoInterface.h
Normal 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;
|
||||
};
|
@ -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");
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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++;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
@ -19,4 +19,6 @@ public:
|
||||
|
||||
TSharedPtr<FUICommandInfo> Remove;
|
||||
TSharedPtr<FUICommandInfo> Break;
|
||||
TSharedPtr<FUICommandInfo> Fill2Start;
|
||||
TSharedPtr<FUICommandInfo> Fill2End;
|
||||
};
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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++)
|
||||
|
@ -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)
|
||||
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user