diff --git a/Source/Cut5/Interface/VideoInterface.cpp b/Source/Cut5/Interface/VideoInterface.cpp index 24e1121..7680ad0 100644 --- a/Source/Cut5/Interface/VideoInterface.cpp +++ b/Source/Cut5/Interface/VideoInterface.cpp @@ -2,8 +2,6 @@ #include "CutMainWidgetInterface.h" #include "Cut5/Utils/FFMPEGUtils.h" -#include "Utils/SchCounter.h" -#include "Utils/SchUtilsLib.h" bool FVideoThread::Init() { @@ -26,9 +24,6 @@ uint32 FVideoThread::Run() { if (CurrentSeekingFrame != -1) { - - TSharedPtr SchTime = SchUtilsLib::CreateTimeCounter(); - int32 VideoFPS = NewPropertyData.VideoCodecContext->time_base.den; if (VideoFPS < FGlobalData::GlobalFPS) { @@ -48,7 +43,6 @@ uint32 FVideoThread::Run() if (CurrentSeekingFrame - LastSeekFrame > 1 || CurrentSeekingFrame - LastSeekFrame < 0 || LastSeekFrame == -1) { av_seek_frame(NewPropertyData.Context, NewPropertyData.VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD); - SchUtilsLib::PrintImmediately(TEXT("Seeked")); } @@ -68,17 +62,14 @@ uint32 FVideoThread::Run() AllocatedFrame = LastFrame; bNeedReadFrame = false; } + } - SchTime->PrintCurrentTime(TEXT("点1")); - - const TSharedPtr SchCounter = SchUtilsLib::CreateCounter(); bool IsFailed = false; if (bNeedReadFrame) { while (av_read_frame(NewPropertyData.Context, Packet) >= 0) { - SchCounter->AddCount(1); if (Packet->stream_index == NewPropertyData.VideoStream) { int32 Response = avcodec_send_packet(NewPropertyData.VideoCodecContext, Packet); @@ -106,14 +97,12 @@ uint32 FVideoThread::Run() } } av_packet_unref(Packet); - SchCounter->PrintCount("AV_READ_FRAME", true); if (IsFailed == true) { CurrentSeekingFrame = -1; continue;; } - SchTime->PrintCurrentTime(TEXT("点2")); uint8* RawData = nullptr; @@ -209,13 +198,10 @@ uint32 FVideoThread::Run() sws_freeContext(SwsCtx); } - SchTime->PrintCurrentTime(TEXT("点3")); int32 X = AllocatedFrame->width; int32 Y = AllocatedFrame->height; - const float NewTime = 1 / ((FDateTime::Now().GetMillisecond() * 0.001f) - LastTime); - GEngine->AddOnScreenDebugMessage(0, 0.1f, FColor::Red, FString::SanitizeFloat(NewTime)); - LastTime = FDateTime::Now().GetMillisecond() * 0.001f; + AsyncTask(ENamedThreads::GameThread, [this, X, Y, RawData, AllocatedFrame]() { if (ClipData.ClipType == ETrackType::VideoTrack) @@ -236,8 +222,6 @@ uint32 FVideoThread::Run() FMemory::Memcpy(ColorArray.GetData(), RawData, FGlobalData::LightArrayX * FGlobalData::LightArrayY * 4); MainInterface->OnUpdateLightBar(ColorArray); } - - }); // }); @@ -250,7 +234,7 @@ uint32 FVideoThread::Run() } else { - FPlatformProcess::Sleep(0.01f); + FPlatformProcess::Sleep(0.1f); } } return 0; diff --git a/Source/Cut5/Interface/VideoInterface.h b/Source/Cut5/Interface/VideoInterface.h index 0260bc3..060bd60 100644 --- a/Source/Cut5/Interface/VideoInterface.h +++ b/Source/Cut5/Interface/VideoInterface.h @@ -20,6 +20,4 @@ public: std::atomic LastSeekFrame = -1; AVFrame* LastFrame = nullptr; bool IsStop = false; - - float LastTime = 0.0f; }; diff --git a/Source/Cut5/Interface/VideoThumbnailThread.cpp b/Source/Cut5/Interface/VideoThumbnailThread.cpp index c71c99f..022ad9f 100644 --- a/Source/Cut5/Interface/VideoThumbnailThread.cpp +++ b/Source/Cut5/Interface/VideoThumbnailThread.cpp @@ -32,10 +32,8 @@ uint32 FVideoThumbnailThread::Run() { if (i < BrushCount && ClipData->ResourcePropertyDataPtr && ClipData->ResourcePropertyDataPtr->Context && ClipData->ResourcePropertyDataPtr->VideoStream != -1) { - - const int32 CurrentInterval = BrushCount - (BrushCount - i); - const int32 CurrentFrame = (Info.Context->duration / AV_TIME_BASE * Info.VideoCodecContext->time_base.den) / BrushCount * CurrentInterval; - const int64 Timestamp = av_rescale_q(CurrentFrame * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, Info.Context->streams[Info.VideoStream]->time_base); + const int32 CurrentFrame = BrushCount - (BrushCount - i); + const int64 Timestamp = av_rescale_q(CurrentFrame / FGlobalData::GlobalFPS * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, Info.Context->streams[Info.VideoStream]->time_base); av_seek_frame(Info.Context, Info.VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD); AVPacket Packet; av_init_packet(&Packet); diff --git a/Source/Cut5/Utils/FFMPEGUtils.cpp b/Source/Cut5/Utils/FFMPEGUtils.cpp index d1193c2..80c3a29 100644 --- a/Source/Cut5/Utils/FFMPEGUtils.cpp +++ b/Source/Cut5/Utils/FFMPEGUtils.cpp @@ -1,5 +1,6 @@ #include "FFMPEGUtils.h" #include "FFMPEGUtils.h" +#include "FFMPEGUtils.h" @@ -7,6 +8,8 @@ #include "ImageUtils.h" #include "Utils.h" #include "Cut5/FFT/kiss_fft.h" +#include "Cut5/Interface/CutMainWidgetInterface.h" +#include "Cut5/Widgets/SCutMainWindow.h" #include "Engine/Canvas.h" #include "Engine/TextureRenderTarget2D.h" #include "Kismet/KismetRenderingLibrary.h" @@ -661,6 +664,79 @@ TArray FFFMPEGUtils::GetAudioBrush(FClipData* ClipData) return {}; } +void FFFMPEGUtils::GenerateProjectorEvent(const FClipData* ClipData) +{ + // Get Projector Track Data + SCutTimeline* Timeline = FGlobalData::MainWidgetInterface->GetSelf()->GetCutTimeline(); + FTrackData* ProjectorTrackData = Timeline->GetTrackDataByType(ETrackType::ProjectorTrack); + + if (ClipData->ClipType == ETrackType::VideoTrack + && ClipData->ResourcePropertyDataPtr) + { + FTimelinePropertyData Info; + LoadContextPure(ToFullPath(ClipData->MoviePath), &Info); + if (Info.Context == nullptr) + return; + + + + while (1) + { + AVPacket* Packet = av_packet_alloc(); + AVFrame* Frame = av_frame_alloc(); + + if (av_read_frame(Info.Context, Packet) < 0) + { + if (av_read_frame(Info.Context, Packet) < 0) + { + break; + } + } + + if (int32 Response = avcodec_send_packet(Info.VideoCodecContext, Packet) < 0) + { + check(false); + }; + if (int32 Response = avcodec_receive_frame(Info.VideoCodecContext, Frame) >= 0) + { + if (Frame->width == 0 || Frame->height == 0) + continue; + + SwsContext* SwsConvert = + sws_getContext(Frame->width, Frame->height, Info.VideoCodecContext->pix_fmt, + 128, 72, AV_PIX_FMT_RGBA, SWS_BICUBIC, nullptr, nullptr, nullptr); + + uint8* RawData = new uint8[128 * 72 * 4]; + uint8* Dest[4] = {RawData, nullptr, nullptr, nullptr}; + constexpr int32 DestStride[4] = {128 * 4, 0, 0, 0}; + + sws_scale(SwsConvert, Frame->data, Frame->linesize, 0, Frame->height, Dest, DestStride); + sws_freeContext(SwsConvert); + + float RawDataFloat = RawData[0]; + + int32 GrayCount = 0; + for (int32 i = 0; i < 128 * 72; i++) + { + float Gray = RawData[i * 4 + 0] * 0.299 + RawData[i * 4 + 1] * 0.587 + RawData[i * 4 + 2] * 0.114; + } + + + av_packet_free(&Packet); + av_frame_free(&Frame); + continue; + } + + + av_packet_free(&Packet); + av_frame_free(&Frame); + + break; + } + } + +} + TArray> FFFMPEGUtils::GetVideoFrameLightArray(FString VideoPath, int32 X, int32 Y) { @@ -704,4 +780,4 @@ TArray> FFFMPEGUtils::GetVideoFrameLightArray(FString VideoPath, } } return Colors; -} \ No newline at end of file +} diff --git a/Source/Cut5/Utils/FFMPEGUtils.h b/Source/Cut5/Utils/FFMPEGUtils.h index f2ca883..7be4977 100644 --- a/Source/Cut5/Utils/FFMPEGUtils.h +++ b/Source/Cut5/Utils/FFMPEGUtils.h @@ -24,4 +24,6 @@ struct FFFMPEGUtils static TArray GetMovieBrush(struct FClipData* ClipData, bool Regenerate = false); static TArray GetAudioBrush(struct FClipData* ClipData); + + static void GenerateProjectorEvent(const FClipData* ClipData); }; diff --git a/Source/Cut5/Widgets/DefineGlobal.h b/Source/Cut5/Widgets/DefineGlobal.h index df124a0..7c847b6 100644 --- a/Source/Cut5/Widgets/DefineGlobal.h +++ b/Source/Cut5/Widgets/DefineGlobal.h @@ -36,8 +36,8 @@ public: inline static FString ExportPath = ""; inline static bool Export_OnlyXML = false; - inline static TArray ExportErrorString; + inline static class ICutMainWidgetInterface* MainWidgetInterface = nullptr; inline static TArray Colors = { diff --git a/Source/Cut5/Widgets/SCutMainWindow.cpp b/Source/Cut5/Widgets/SCutMainWindow.cpp index 87a56ed..6332143 100644 --- a/Source/Cut5/Widgets/SCutMainWindow.cpp +++ b/Source/Cut5/Widgets/SCutMainWindow.cpp @@ -47,6 +47,9 @@ BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SCutMainWindow::Construct(const FArguments& InArgs) { + + FGlobalData::MainWidgetInterface = this; + SAssignNew(CutTimeline, SCutTimeline).MainWidgetInterface(this); SAssignNew(StatePanel, SStatePanel); SAssignNew(CustomPanel, SCustomPanel); diff --git a/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp b/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp index 69ea16d..b797bdd 100644 --- a/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp +++ b/Source/Cut5/Widgets/TimelineClips/ClipProxy.cpp @@ -1,5 +1,6 @@ #include "ClipProxy.h" +#include "Cut5/Utils/FFMPEGUtils.h" #include "Cut5/Utils/Utils.h" #include "Cut5/Widgets/SCutMainWindow.h" #include "Cut5/Widgets/SCutTimeline.h" @@ -653,6 +654,43 @@ TSharedPtr FClipProxy::GetPropertiesWidget() ] ]; } + if (ClipData->ClipType == ETrackType::VideoTrack) + { + VerticalBox->AddSlot() + .SizeParam(FStretch(1.0)) + [ + SNew(SSpacer) + ]; + VerticalBox->AddSlot() + .HAlign(HAlign_Center) + .VAlign(VAlign_Bottom) + .Padding(0, 0, 0, 24) + [ + SNew(SBox).HeightOverride(40).WidthOverride(144) + [ + SNew(SOverlay) + + SOverlay::Slot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + [ + SNew(SButton) + .OnClicked_Lambda([this]() + { + FFFMPEGUtils::GenerateProjectorEvent(ClipData); + return FReply::Handled(); + }) + ] + + SOverlay::Slot() + [ + SNew(STextBlock) + .Visibility(EVisibility::HitTestInvisible) + .Text(FText::FromString((TEXT("生成投影仪事件")))) + .Font(NormalText.Font) + .Justification(ETextJustify::Center) + ] + ] + ]; + }