From 1be1ffc4cd37ae514583a6a557c5ea10e95622b5 Mon Sep 17 00:00:00 2001 From: Sch <3516520171@qq.com> Date: Mon, 21 Aug 2023 05:10:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B7=A6=E5=8F=B3=E5=A3=B0=E9=81=93=EF=BC=8C?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E6=88=AA=E5=9B=BE=EF=BC=8C=E8=BF=9B=E5=BA=A6?= =?UTF-8?q?=E6=9D=A1=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/Cut5/Interface/SoundInterface.cpp | 47 +++++++++++++++++++++- Source/Cut5/Interface/SoundInterface.h | 4 +- Source/Cut5/Utils/FFMPEGUtils.cpp | 50 +++++++++++++++++------- Source/Cut5/Utils/FFMPEGUtils.h | 2 +- Source/Cut5/Utils/Utils.cpp | 10 ++--- Source/Cut5/Widgets/DefineGlobal.h | 10 +++++ Source/Cut5/Widgets/SCutTimeline.cpp | 2 + Source/Cut5/Widgets/SProgressPanel.cpp | 43 ++++++++++++++++++++ Source/Cut5/Widgets/SProgressPanel.h | 32 +++++++++++++++ Source/Cut5/Widgets/STimelineClip.cpp | 39 +++++++++++------- Source/Cut5/Widgets/STimelineClip.h | 2 + Source/Cut5/Widgets/STrackBody.cpp | 13 +++++- 12 files changed, 214 insertions(+), 40 deletions(-) create mode 100644 Source/Cut5/Widgets/SProgressPanel.cpp create mode 100644 Source/Cut5/Widgets/SProgressPanel.h diff --git a/Source/Cut5/Interface/SoundInterface.cpp b/Source/Cut5/Interface/SoundInterface.cpp index a6bf4d6..8fff424 100644 --- a/Source/Cut5/Interface/SoundInterface.cpp +++ b/Source/Cut5/Interface/SoundInterface.cpp @@ -2,6 +2,8 @@ #include +#include "Cut5/Widgets/DefineGlobal.h" + FCriticalSection Mutex; FSoundThread::FSoundThread(int32 OutputChannel, int32 SampleRate) : FRunnable() @@ -33,7 +35,7 @@ uint32 FSoundThread::Run() { TArray> ResultData; const int32 FrameLength = Audio.Num(); - for (int32 i = SeekedFrame * (SampleRate / 27) * 4 * 2; i < (SeekedFrame + 1) * (SampleRate / 27) * 4 * 2 && i < FrameLength; ++i) + for (int32 i = SeekedFrame * (SampleRate / 26) * 4 * 2; i < (SeekedFrame + 1) * (SampleRate / 26) * 4 * 2 && i < FrameLength; ++i) { ResultData.Add(Audio[i]); } @@ -46,14 +48,55 @@ uint32 FSoundThread::Run() void FSoundThread::Stop() { + bStoped = true; FRunnable::Stop(); } -bool FSoundThread::CopyAudio(const uint8* Data, int32 Size) +bool FSoundThread::CopyAudio(const uint8* Data, int32 Size, ESoundSolveType SolveType) { Audio = TArray(Data, Size); + switch (SolveType) + { + case ESoundSolveType::None: + { + break; + } + case ESoundSolveType::OnlyLeft: + { + for (int32 i = 0; i < Size / 4; i++) + { + if (i % 2 == 1) + { + Audio[i * 4] = 0; + Audio[i * 4 + 1] = 0; + Audio[i * 4 + 2] = 0; + Audio[i * 4 + 3] = 0; + } + } + break; + } + case ESoundSolveType::OnlyRight: + { + for (int32 i = 0; i < Size / 4; i++) + { + if (i % 2 == 0) + { + Audio[i * 4] = 0; + Audio[i * 4 + 1] = 0; + Audio[i * 4 + 2] = 0; + Audio[i * 4 + 3] = 0; + } + } + break; + } + default: + { + break; + } + } + return true; } diff --git a/Source/Cut5/Interface/SoundInterface.h b/Source/Cut5/Interface/SoundInterface.h index 085372f..be5671a 100644 --- a/Source/Cut5/Interface/SoundInterface.h +++ b/Source/Cut5/Interface/SoundInterface.h @@ -1,4 +1,6 @@ #pragma once +#include "Cut5/Widgets/DefineGlobal.h" + extern "C"{ #include } @@ -20,7 +22,7 @@ public: bool bStoped = false; - bool CopyAudio(const uint8* Data, int32 Size); + bool CopyAudio(const uint8* Data, int32 Size, ESoundSolveType SolveType); bool SeekFrame(int32 SeekFrameLoc); int32 SeekedFrame = 0; TArray Audio; diff --git a/Source/Cut5/Utils/FFMPEGUtils.cpp b/Source/Cut5/Utils/FFMPEGUtils.cpp index 0954596..81ab348 100644 --- a/Source/Cut5/Utils/FFMPEGUtils.cpp +++ b/Source/Cut5/Utils/FFMPEGUtils.cpp @@ -237,18 +237,36 @@ bool FFFMPEGUtils::ExportImage(UTexture2D* Texture2D, const FString& Path) return FFileHelper::SaveArrayToFile(ImgData, *Path); } -TArray FFFMPEGUtils::GetMovieBrush(FClipData* ClipData) +TArray FFFMPEGUtils::GetMovieBrush(FClipData* ClipData, bool Regenerate) { + + TArray Result; + ClipData->MovieBrushes.Empty(); + if (ClipData->MovieBrushesPath.Num() > 0 && !Regenerate) + { + for (int32 i = 0; i < ClipData->MovieBrushesPath.Num(); i++) + { + FSlateDynamicImageBrush Brush = FSlateDynamicImageBrush(*ClipData->MovieBrushesPath[i], FVector2f(0, 0)); + Result.Add(Brush); + } + + + return Result; + } + + for (int32 i = 0; i < ClipData->MovieBrushes.Num(); i++) { ClipData->MovieBrushes[i].SetResourceObject(nullptr); } - ClipData->MovieBrushes.Empty(); - + + ClipData->MovieBrushesPath.Empty(); - TArray Result; + + + if (ClipData->ResourcePropertyDataPtr) { const float ClipLength = (ClipData->VideoEndFrame - ClipData->VideoStartFrame) * FGlobalData::DefaultTimeTickSpace; @@ -285,37 +303,41 @@ TArray FFFMPEGUtils::GetMovieBrush(FClipData* ClipData) if (Frame) { struct SwsContext* swsCtx = sws_getContext( - Frame->width, Frame->height, VideoCodecContext->pix_fmt, - Frame->width, Frame->height, AV_PIX_FMT_BGRA, - SWS_BILINEAR, NULL, NULL, NULL - ); + Frame->width, Frame->height, VideoCodecContext->pix_fmt, + Frame->width / 10, Frame->height / 10, AV_PIX_FMT_BGRA, + SWS_BILINEAR, NULL, NULL, NULL + ); if (!swsCtx) { UE_LOG(LogTemp, Error, TEXT("Error creating swsContext")); } - uint8* RawData = new uint8[Frame->width * Frame->height * 4]; + uint8* RawData = new uint8[(Frame->width / 10) * (Frame->height / 10) * 4]; uint8* dest[4] = {RawData, 0, 0, 0}; - int32 dest_linesize[4] = {Frame->width * 4, 0, 0, 0}; + int32 dest_linesize[4] = {(Frame->width / 10) * 4, 0, 0, 0}; sws_scale(swsCtx, Frame->data, Frame->linesize, 0, Frame->height, dest, dest_linesize); sws_freeContext(swsCtx); - UTexture2D* Texture = UTexture2D::CreateTransient(Frame->width, Frame->height, PF_B8G8R8A8); + UTexture2D* Texture = UTexture2D::CreateTransient(Frame->width / 10, Frame->height / 10, PF_B8G8R8A8); if (Texture) { void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE); - FMemory::Memcpy(MipData, RawData, Frame->width * Frame->height * 4); + FMemory::Memcpy(MipData, RawData, (Frame->width / 10) * (Frame->height / 10) * 4); Texture->GetPlatformData()->Mips[0].BulkData.Unlock(); Texture->UpdateResource(); - // FGuid Guid = FGuid::NewGuid(); - // ExportImage(Texture, *FPaths::Combine(FUtils::GetTempPath() / Guid.ToString() + ".png")); + FGuid Guid = FGuid::NewGuid(); + ExportImage(Texture, *FPaths::Combine(FUtils::GetTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png")); + ClipData->MovieBrushesPath.Add(FPaths::Combine(FUtils::GetTempPath() / ClipData->ClipGuid.ToString() / Guid.ToString() + ".png")); + FSlateBrush NewBrush; NewBrush.SetResourceObject(Texture); Result.Add(NewBrush); delete RawData; } + + } } } diff --git a/Source/Cut5/Utils/FFMPEGUtils.h b/Source/Cut5/Utils/FFMPEGUtils.h index 0dc1c0d..f5f97fc 100644 --- a/Source/Cut5/Utils/FFMPEGUtils.h +++ b/Source/Cut5/Utils/FFMPEGUtils.h @@ -17,6 +17,6 @@ struct FFFMPEGUtils static FString ConvertMediaGoPto1(const FString& Path); static bool ExportImage(UTexture2D* Texture2D, const FString& Path); - static TArray GetMovieBrush(struct FClipData* ClipData); + static TArray GetMovieBrush(struct FClipData* ClipData, bool Regenerate = false); static TArray GetAudioBrush(struct FClipData* ClipData); }; diff --git a/Source/Cut5/Utils/Utils.cpp b/Source/Cut5/Utils/Utils.cpp index 071b7d9..fef5d24 100644 --- a/Source/Cut5/Utils/Utils.cpp +++ b/Source/Cut5/Utils/Utils.cpp @@ -269,12 +269,10 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& TempClipData.ResourcePropertyDataPtr->MoviePath; FString TempPath = TempClipData.ResourcePropertyDataPtr->MoviePath; frames.Empty(); - - + VideoCapture capture; bool ret = capture.open(TCHAR_TO_UTF8(*TempPath)); - - UE_LOG(LogTemp, Log, TEXT("cv numThreads -> %s"), *FString::FromInt(getNumThreads())); + //setNumThreads(2); @@ -308,8 +306,10 @@ TArray FUtils::ExportPsaf(FTrackData TrackData, const FString& float duration = capture.get(CV_CAP_PROP_FRAME_COUNT) / capture.get(CV_CAP_PROP_FPS); Size old_size = frameSize; - + + capture.set(CAP_PROP_POS_FRAMES, TempClipData.ClipStartFrame); int32 frameCount = capture.get(CV_CAP_PROP_FRAME_COUNT); + frameCount -= ClipData[i].ClipStartFrame; UE_LOG(LogTemp, Log, TEXT("frameCount: %s"), *FString::FromInt(frameCount)); char p[128] = "pasf"; diff --git a/Source/Cut5/Widgets/DefineGlobal.h b/Source/Cut5/Widgets/DefineGlobal.h index 89ca3e0..83a7339 100644 --- a/Source/Cut5/Widgets/DefineGlobal.h +++ b/Source/Cut5/Widgets/DefineGlobal.h @@ -297,6 +297,7 @@ struct CUT5_API FClipData Ar << ClipData.PresetType; Ar << ClipData.bCanDrag; Ar << ClipData.PresetsCustomData; + Ar << ClipData.MovieBrushesPath; return Ar; }; @@ -323,6 +324,8 @@ struct CUT5_API FClipData int32 GetClipRelativeEndFrame() const { return ClipEndFrame - ClipStartFrame; } FPresetsCustomData PresetsCustomData; TArray MovieBrushes; + TArray MovieBrushesPath; + int32 MovieBrushNum; TArray AudioBrushes; @@ -907,4 +910,11 @@ enum class ESelectMode { SelectMode = 0, CutMode = 1, +}; + +enum class ESoundSolveType +{ + None, + OnlyLeft, + OnlyRight, }; \ No newline at end of file diff --git a/Source/Cut5/Widgets/SCutTimeline.cpp b/Source/Cut5/Widgets/SCutTimeline.cpp index 9222d54..7b68513 100644 --- a/Source/Cut5/Widgets/SCutTimeline.cpp +++ b/Source/Cut5/Widgets/SCutTimeline.cpp @@ -6,6 +6,7 @@ #include "SlateOptMacros.h" #include "STimelineTick.h" #include "STrackBody.h" +#include "Cut5/Utils/FFMPEGUtils.h" #include "Cut5/Utils/Utils.h" #include "DragDropOperator/DragDropOperator.h" #include "MicroWidgets/SClickEditableText.h" @@ -667,6 +668,7 @@ bool SCutTimeline::LoadTimeline(const FString& LoadPath, FTimelineInfo& Info) { if (StaticCastSharedPtr(TrackGroupInstances[l].Head)->TrackData.DeviceTrack.Guid == DeviceTrackGroups[j].DeviceTracks[k].Guid) { + AllClips[i].MovieBrushes = FFFMPEGUtils::GetMovieBrush(&AllClips[i], false); StaticCastSharedPtr(TrackGroupInstances[l].Head)->TrackData.ClipData.Add(AllClips[i]); } } diff --git a/Source/Cut5/Widgets/SProgressPanel.cpp b/Source/Cut5/Widgets/SProgressPanel.cpp new file mode 100644 index 0000000..1108600 --- /dev/null +++ b/Source/Cut5/Widgets/SProgressPanel.cpp @@ -0,0 +1,43 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "SProgressPanel.h" + +#include "SlateOptMacros.h" +#include "Widgets/Layout/SBackgroundBlur.h" +#include "Widgets/Layout/SConstraintCanvas.h" +#include "Widgets/Notifications/SProgressBar.h" + +BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION + +void SProgressPanel::Construct(const FArguments& InArgs) +{ + CurrentProgress = InArgs._Limit.X; + TotalProgress = InArgs._Limit.Y; + ChildSlot + [ + SNew(SConstraintCanvas) + + SConstraintCanvas::Slot() + [ + SNew(SBackgroundBlur) + .BlurStrength(100.0) + ] + + SConstraintCanvas::Slot() + [ + SNew(SOverlay) + + SOverlay::Slot() + [ + SNew(SBox).WidthOverride(1000).HeightOverride(80) + [ + SAssignNew(Progress, SProgressBar) + .Percent_Lambda([this]() {return CurrentProgress / TotalProgress; }) + ] + + ] + + ] + ]; + +} + +END_SLATE_FUNCTION_BUILD_OPTIMIZATION diff --git a/Source/Cut5/Widgets/SProgressPanel.h b/Source/Cut5/Widgets/SProgressPanel.h new file mode 100644 index 0000000..65537b8 --- /dev/null +++ b/Source/Cut5/Widgets/SProgressPanel.h @@ -0,0 +1,32 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Widgets/SCompoundWidget.h" +#include "Widgets/Notifications/SProgressBar.h" + +/** + * + */ +class CUT5_API SProgressPanel : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SProgressPanel) + { + } + SLATE_ARGUMENT(FVector2D, Limit) + SLATE_END_ARGS() + + /** Constructs this widget with InArgs */ + void Construct(const FArguments& InArgs); + + TSharedPtr Progress; + + float CurrentProgress; + float TotalProgress; + + void AddPercent(const float Percent) { CurrentProgress += Percent; } + void SetPercent(const float Percent) { CurrentProgress = Percent; } + float GetPercent() const { return CurrentProgress / TotalProgress; } +}; diff --git a/Source/Cut5/Widgets/STimelineClip.cpp b/Source/Cut5/Widgets/STimelineClip.cpp index 194b112..9a3faad 100644 --- a/Source/Cut5/Widgets/STimelineClip.cpp +++ b/Source/Cut5/Widgets/STimelineClip.cpp @@ -303,7 +303,7 @@ void STimelineClip::Seek(int32 Frame) sws_freeContext(swsCtx); MainWidgetInterface->OnUpdateVideo(FGuid::NewGuid(), AllocatedFrame->width, AllocatedFrame->height, RawData); - + DoSound(ESoundSolveType::None, Frame); av_frame_free(&AllocatedFrame); } @@ -517,20 +517,13 @@ void STimelineClip::Seek(int32 Frame) break; case ETrackType::AudioTrack: { - if (SoundThread == nullptr) - { - SoundThread = new FSoundThread(2, ClipData->ResourcePropertyDataPtr->AudioSample); - FRunnableThread* Thread = FRunnableThread::Create(SoundThread, TEXT("SoundThread")); - SoundThread->CopyAudio(ClipData->ResourcePropertyDataPtr->AudioData.GetData(), ClipData->ResourcePropertyDataPtr->AudioData.Num()); - } - - - const int32 Offset = Frame - ClipData->ClipStartFrame; - const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset; - if (SoundThread) - { - SoundThread->SeekFrame(SeekMovieFrame); - } + DoSound(ESoundSolveType::OnlyLeft, Frame); + break; + } + case ETrackType::AudioTrackR: + { + DoSound(ESoundSolveType::OnlyRight, Frame); + break; } break; @@ -820,6 +813,22 @@ FReply STimelineClip::OnDragOver(const FGeometry& MyGeometry, const FDragDropEve return SCompoundWidget::OnDragOver(MyGeometry, DragDropEvent); } +void STimelineClip::DoSound(ESoundSolveType SolveType, int32 InFrame) +{ + if (SoundThread == nullptr) + { + SoundThread = new FSoundThread(2, ClipData->ResourcePropertyDataPtr->AudioSample); + FRunnableThread* Thread = FRunnableThread::Create(SoundThread, TEXT("SoundThread")); + SoundThread->CopyAudio(ClipData->ResourcePropertyDataPtr->AudioData.GetData(), ClipData->ResourcePropertyDataPtr->AudioData.Num(), SolveType); + } + const int32 Offset = InFrame - ClipData->ClipStartFrame; + const int32 SeekMovieFrame = ClipData->VideoStartFrame + Offset; + if (SoundThread) + { + SoundThread->SeekFrame(SeekMovieFrame); + } +} + void STimelineClip::OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) { bIsDragOver = true; diff --git a/Source/Cut5/Widgets/STimelineClip.h b/Source/Cut5/Widgets/STimelineClip.h index f50db9d..2ae6366 100644 --- a/Source/Cut5/Widgets/STimelineClip.h +++ b/Source/Cut5/Widgets/STimelineClip.h @@ -59,6 +59,8 @@ public: TSharedPtr CommandList; FSoundThread* SoundThread; + void DoSound(ESoundSolveType SolveType, int32 InFrame); + virtual void OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override; virtual void OnDragLeave(const FDragDropEvent& DragDropEvent) override; bool bIsDragOver = false; diff --git a/Source/Cut5/Widgets/STrackBody.cpp b/Source/Cut5/Widgets/STrackBody.cpp index f619832..4972966 100644 --- a/Source/Cut5/Widgets/STrackBody.cpp +++ b/Source/Cut5/Widgets/STrackBody.cpp @@ -67,6 +67,15 @@ void STrackBody::CallRender() { Overlay->ClearChildren(); + for (TSharedPtr Clip : SlateClips) + { + if (Clip->SoundThread) + { + Clip->SoundThread->Stop(); + } + + } + SlateClips.Empty(); for (FClipData& TempClipData : TrackHead->TrackData.ClipData) { @@ -178,8 +187,8 @@ void STrackBody::BreakClip(const FGuid& Guid) if (TrackHead->TrackData.ClipData[i].ClipType == ETrackType::VideoTrack) { - TrackHead->TrackData.ClipData[i].MovieBrushes = FFFMPEGUtils::GetMovieBrush(&TrackHead->TrackData.ClipData[i]); - TrackHead->TrackData.ClipData[Index].MovieBrushes = FFFMPEGUtils::GetMovieBrush(&NewClipData); + TrackHead->TrackData.ClipData[i].MovieBrushes = FFFMPEGUtils::GetMovieBrush(&TrackHead->TrackData.ClipData[i], true); + TrackHead->TrackData.ClipData[Index].MovieBrushes = FFFMPEGUtils::GetMovieBrush(&NewClipData, true); } else if (TrackHead->TrackData.ClipData[i].ClipType == ETrackType::AudioTrack || TrackHead->TrackData.ClipData[i].ClipType == ETrackType::AudioTrack) {