显示音频时域
This commit is contained in:
parent
50c85f073c
commit
8c0b908ce9
@ -1,7 +1,12 @@
|
|||||||
#include "FFMPEGUtils.h"
|
#include "FFMPEGUtils.h"
|
||||||
|
|
||||||
|
#include "CanvasTypes.h"
|
||||||
#include "ImageUtils.h"
|
#include "ImageUtils.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
#include "Engine/Canvas.h"
|
||||||
|
#include "Engine/TextureRenderTarget2D.h"
|
||||||
|
#include "Kismet/KismetRenderingLibrary.h"
|
||||||
|
#include "Serialization/BufferArchive.h"
|
||||||
|
|
||||||
|
|
||||||
FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* PropertyData)
|
FString FFFMPEGUtils::LoadMedia(const FString& Path, FTimelinePropertyData* PropertyData)
|
||||||
@ -230,3 +235,185 @@ bool FFFMPEGUtils::ExportImage(UTexture2D* Texture2D, const FString& Path)
|
|||||||
FImageUtils::CompressImageArray(width, height, nColors, ImgData);
|
FImageUtils::CompressImageArray(width, height, nColors, ImgData);
|
||||||
return FFileHelper::SaveArrayToFile(ImgData, *Path);
|
return FFileHelper::SaveArrayToFile(ImgData, *Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TArray<FSlateBrush> FFFMPEGUtils::GetMovieBrush(FClipData* ClipData)
|
||||||
|
{
|
||||||
|
for (int32 i = 0; i < ClipData->MovieBrushes.Num(); i++)
|
||||||
|
{
|
||||||
|
ClipData->MovieBrushes[i].SetResourceObject(nullptr);
|
||||||
|
}
|
||||||
|
ClipData->MovieBrushes.Empty();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TArray<FSlateBrush> Result;
|
||||||
|
if (ClipData->ResourcePropertyDataPtr)
|
||||||
|
{
|
||||||
|
const float ClipLength = (ClipData->VideoEndFrame - ClipData->VideoStartFrame) * FGlobalData::DefaultTimeTickSpace;
|
||||||
|
const float FrameNum = ClipLength / 128.0;
|
||||||
|
const float TotalFrame = ClipData->ResourcePropertyDataPtr->VideoCodecContext->framerate.num * ( ClipData->ResourcePropertyDataPtr->Context->duration / AV_TIME_BASE);
|
||||||
|
for (int32 i = 0; i < FrameNum; i++)
|
||||||
|
{
|
||||||
|
// 得到视频总帧数
|
||||||
|
|
||||||
|
int64 Timestamp = av_rescale_q(i * (TotalFrame / 128) / 30.0 * AV_TIME_BASE, AVRational{1, AV_TIME_BASE}, ClipData->ResourcePropertyDataPtr->Context->streams[ClipData->ResourcePropertyDataPtr->VideoStream]->time_base);
|
||||||
|
av_seek_frame(ClipData->ResourcePropertyDataPtr->Context, ClipData->ResourcePropertyDataPtr->VideoStream, Timestamp, AVSEEK_FLAG_BACKWARD);
|
||||||
|
AVPacket Packet;
|
||||||
|
av_init_packet(&Packet);
|
||||||
|
AVFormatContext* FormatContext = ClipData->ResourcePropertyDataPtr->Context;
|
||||||
|
AVCodecContext* VideoCodecContext = ClipData->ResourcePropertyDataPtr->VideoCodecContext;
|
||||||
|
AVCodec* VideoCodec = ClipData->ResourcePropertyDataPtr->VideoCodec;
|
||||||
|
AVFrame* Frame = av_frame_alloc();
|
||||||
|
|
||||||
|
while (av_read_frame(FormatContext, &Packet) >= 0)
|
||||||
|
{
|
||||||
|
if (avcodec_send_packet(VideoCodecContext, &Packet) < 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
if (avcodec_receive_frame(VideoCodecContext, Frame) >= 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (Frame)
|
||||||
|
{
|
||||||
|
struct SwsContext* swsCtx = sws_getContext(
|
||||||
|
Frame->width, Frame->height, VideoCodecContext->pix_fmt,
|
||||||
|
Frame->width, Frame->height, AV_PIX_FMT_RGBA,
|
||||||
|
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* dest[4] = {RawData, 0, 0, 0};
|
||||||
|
int32 dest_linesize[4] = {Frame->width * 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);
|
||||||
|
if (Texture)
|
||||||
|
{
|
||||||
|
void* MipData = Texture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
|
||||||
|
FMemory::Memcpy(MipData, RawData, Frame->width * Frame->height * 4);
|
||||||
|
Texture->GetPlatformData()->Mips[0].BulkData.Unlock();
|
||||||
|
Texture->UpdateResource();
|
||||||
|
|
||||||
|
// FGuid Guid = FGuid::NewGuid();
|
||||||
|
// ExportImage(Texture, *FPaths::Combine(FUtils::GetTempPath() / Guid.ToString() + ".png"));
|
||||||
|
|
||||||
|
FSlateBrush NewBrush;
|
||||||
|
NewBrush.SetResourceObject(Texture);
|
||||||
|
Result.Add(NewBrush);
|
||||||
|
delete RawData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<FSlateBrush> FFFMPEGUtils::GetAudioBrush(FClipData* ClipData)
|
||||||
|
{
|
||||||
|
const float TimeLength = (ClipData->ClipEndFrame - ClipData->ClipStartFrame) * FGlobalData::DefaultTimeTickSpace;
|
||||||
|
|
||||||
|
float MaxValue = 0;
|
||||||
|
float MinValue = 0;
|
||||||
|
for (int32 i = 0; i < ClipData->ResourcePropertyDataPtr->AudioData.Num() / 4; i++)
|
||||||
|
{
|
||||||
|
float NewFloat = *reinterpret_cast<float*>(ClipData->ResourcePropertyDataPtr->AudioData.GetData() + (i * 4));
|
||||||
|
|
||||||
|
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;
|
||||||
|
while (TotalLength > 0)
|
||||||
|
{
|
||||||
|
int32 CurrentLength = 0;
|
||||||
|
if (TotalLength > 4096)
|
||||||
|
{
|
||||||
|
TotalLength -= 4096;
|
||||||
|
CurrentLength = 4096;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentLength = TotalLength;
|
||||||
|
TotalLength = 0;
|
||||||
|
}
|
||||||
|
UTextureRenderTarget2D* TextureRenderTarget2D = NewObject<UTextureRenderTarget2D>();
|
||||||
|
TextureRenderTarget2D->InitCustomFormat(int32(CurrentLength), 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);
|
||||||
|
|
||||||
|
|
||||||
|
float LastPoint = 0.0;
|
||||||
|
int32 StartIndex = (Index * 4096 + CurrentLength) * 4;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < CurrentLength; i++)
|
||||||
|
{
|
||||||
|
float CurrentData = *reinterpret_cast<float*>(ClipData->ResourcePropertyDataPtr->AudioData.GetData() + StartIndex);
|
||||||
|
float NormalizedData = Normalize(CurrentData);
|
||||||
|
Canvas->K2_DrawLine(FVector2D(i - 1, LastPoint), FVector2D(i, NormalizedData), 1, FLinearColor::White);
|
||||||
|
LastPoint = NormalizedData;
|
||||||
|
|
||||||
|
|
||||||
|
StartIndex += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
UKismetRenderingLibrary::EndDrawCanvasToRenderTarget(GWorld->GetWorld(), RenderTargetContext);
|
||||||
|
|
||||||
|
|
||||||
|
FBufferArchive Buffer;
|
||||||
|
FImageUtils::ExportRenderTarget2DAsPNG(TextureRenderTarget2D, Buffer);
|
||||||
|
FFileHelper::SaveArrayToFile(Buffer, *FPaths::Combine(FUtils::GetTempPath(), ClipData->ClipGuid.ToString(), FString::FromInt(Index) + ".png"));
|
||||||
|
|
||||||
|
FSlateDynamicImageBrush SlateBrush = FSlateDynamicImageBrush(*FPaths::Combine(FUtils::GetTempPath(), ClipData->ClipGuid.ToString(), FString::FromInt(Index) + ".png"), FVector2D(CurrentLength, FGlobalData::DefaultTrackHeight));
|
||||||
|
ClipData->AudioBrushLength.Add(CurrentLength);
|
||||||
|
ClipData->AudioBrushes.Add(SlateBrush);
|
||||||
|
Index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FBufferArchive Buffer;
|
||||||
|
// FImageUtils::ExportRenderTarget2DAsPNG(TextureRenderTarget2D, Buffer);
|
||||||
|
// FFileHelper::SaveArrayToFile(Buffer, *FPaths::Combine(FUtils::GetTempPath(), "Audio.png"));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
@ -17,4 +17,6 @@ struct FFFMPEGUtils
|
|||||||
static FString ConvertMediaGoPto1(const FString& Path);
|
static FString ConvertMediaGoPto1(const FString& Path);
|
||||||
static bool ExportImage(UTexture2D* Texture2D, const FString& Path);
|
static bool ExportImage(UTexture2D* Texture2D, const FString& Path);
|
||||||
|
|
||||||
|
static TArray<FSlateBrush> GetMovieBrush(struct FClipData* ClipData);
|
||||||
|
static TArray<FSlateBrush> GetAudioBrush(struct FClipData* ClipData);
|
||||||
};
|
};
|
||||||
|
@ -80,6 +80,11 @@ FString FUtils::GetResourcesPath(FString ResourcesName, bool bFullPath)
|
|||||||
return FPaths::Combine(FPaths::ProjectDir() + "/Resources/", ResourcesName);
|
return FPaths::Combine(FPaths::ProjectDir() + "/Resources/", ResourcesName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FString FUtils::GetTempPath()
|
||||||
|
{
|
||||||
|
return FPaths::ConvertRelativePathToFull(FPaths::Combine(FGlobalData::BasePath / FGlobalData::CurrentProjectName / "/Temp/"));
|
||||||
|
}
|
||||||
|
|
||||||
FSlateDynamicImageBrush* FUtils::GetBrushFromImage(const FString& ImageName, const FVector2D Size)
|
FSlateDynamicImageBrush* FUtils::GetBrushFromImage(const FString& ImageName, const FVector2D Size)
|
||||||
{
|
{
|
||||||
FSlateDynamicImageBrush* Brush = new FSlateDynamicImageBrush(*ImageName, Size);
|
FSlateDynamicImageBrush* Brush = new FSlateDynamicImageBrush(*ImageName, Size);
|
||||||
@ -106,6 +111,14 @@ bool FUtils::DetectDragTypeCanDrop(const FClipData& DraggingType, const ETrackTy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DropTrackType == ETrackType::AudioTrack || DropTrackType == ETrackType::AudioTrackR)
|
||||||
|
{
|
||||||
|
if (DraggingType.ClipType == ETrackType::AudioTrack)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ public:
|
|||||||
static uint8* ConvertTwoChannelSound2PortAudioSound(uint8* Channel1, uint8* Channel2, int32 Size);
|
static uint8* ConvertTwoChannelSound2PortAudioSound(uint8* Channel1, uint8* Channel2, int32 Size);
|
||||||
|
|
||||||
static FString GetResourcesPath(FString ResourcesName, bool bFullPath = false);
|
static FString GetResourcesPath(FString ResourcesName, bool bFullPath = false);
|
||||||
|
static FString GetTempPath();
|
||||||
static FSlateDynamicImageBrush* GetBrushFromImage(const FString& ImageName, const FVector2D Size);
|
static FSlateDynamicImageBrush* GetBrushFromImage(const FString& ImageName, const FVector2D Size);
|
||||||
static TArray<FSlateDynamicImageBrush*> BrushPtr;
|
static TArray<FSlateDynamicImageBrush*> BrushPtr;
|
||||||
|
|
||||||
|
@ -320,6 +320,11 @@ struct CUT5_API FClipData
|
|||||||
|
|
||||||
int32 GetClipRelativeEndFrame() const { return ClipEndFrame - ClipStartFrame; }
|
int32 GetClipRelativeEndFrame() const { return ClipEndFrame - ClipStartFrame; }
|
||||||
FPresetsCustomData PresetsCustomData;
|
FPresetsCustomData PresetsCustomData;
|
||||||
|
TArray<FSlateBrush> MovieBrushes;
|
||||||
|
|
||||||
|
TArray<FSlateBrush> AudioBrushes;
|
||||||
|
TArray<float> AudioBrushLength;
|
||||||
|
|
||||||
|
|
||||||
enum class ECropMethod
|
enum class ECropMethod
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "DragDropOperator.h"
|
#include "DragDropOperator.h"
|
||||||
|
|
||||||
|
#include "Cut5/Utils/FFMPEGUtils.h"
|
||||||
#include "Cut5/Utils/OpencvUtils.h"
|
#include "Cut5/Utils/OpencvUtils.h"
|
||||||
#include "Cut5/Utils/Utils.h"
|
#include "Cut5/Utils/Utils.h"
|
||||||
#include "Cut5/Widgets/DefineGlobal.h"
|
#include "Cut5/Widgets/DefineGlobal.h"
|
||||||
@ -661,6 +662,10 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
|
|||||||
NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + ClipDragOperation.TimelinePropertyData->MovieFrameLength;
|
NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + ClipDragOperation.TimelinePropertyData->MovieFrameLength;
|
||||||
NewClipData.VideoEndFrame = ClipDragOperation.TimelinePropertyData->MovieFrameLength;
|
NewClipData.VideoEndFrame = ClipDragOperation.TimelinePropertyData->MovieFrameLength;
|
||||||
NewClipData.VideoCapture = ClipDragOperation.VideoCapture;
|
NewClipData.VideoCapture = ClipDragOperation.VideoCapture;
|
||||||
|
|
||||||
|
|
||||||
|
NewClipData.MovieBrushes = FFFMPEGUtils::GetMovieBrush(&NewClipData);
|
||||||
|
|
||||||
if (TrackHead->TrackData.TrackType == ETrackType::LightArrayTrack)
|
if (TrackHead->TrackData.TrackType == ETrackType::LightArrayTrack)
|
||||||
{
|
{
|
||||||
NewClipData.ClipType = ETrackType::LightArrayTrack;
|
NewClipData.ClipType = ETrackType::LightArrayTrack;
|
||||||
@ -699,6 +704,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
|
|||||||
NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + ClipDragOperation.TimelinePropertyData->MovieFrameLength;
|
NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + ClipDragOperation.TimelinePropertyData->MovieFrameLength;
|
||||||
NewClipData.VideoEndFrame = ClipDragOperation.TimelinePropertyData->MovieFrameLength;
|
NewClipData.VideoEndFrame = ClipDragOperation.TimelinePropertyData->MovieFrameLength;
|
||||||
NewClipData.ResourcePropertyDataPtr = ClipDragOperation.TimelinePropertyData;
|
NewClipData.ResourcePropertyDataPtr = ClipDragOperation.TimelinePropertyData;
|
||||||
|
FFFMPEGUtils::GetAudioBrush(&NewClipData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,6 +689,32 @@ int32 STimelineClip::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGe
|
|||||||
FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle,
|
FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle,
|
||||||
bool bParentEnabled) const
|
bool bParentEnabled) const
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const float XLength = AllottedGeometry.GetLocalSize().X;
|
||||||
|
{
|
||||||
|
int32 i = 0;
|
||||||
|
float RenderPos = 0;
|
||||||
|
for (FSlateBrush& SlateBrush : ClipData->AudioBrushes)
|
||||||
|
{
|
||||||
|
FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 2, AllottedGeometry.ToPaintGeometry(FVector2f(ClipData->AudioBrushLength[i], AllottedGeometry.GetLocalSize().Y), FSlateLayoutTransform(FVector2f(RenderPos, 0))), &SlateBrush);
|
||||||
|
|
||||||
|
RenderPos += ClipData->AudioBrushLength[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
int32 i = 0;
|
||||||
|
for (FSlateBrush& SlateBrush : ClipData->MovieBrushes)
|
||||||
|
{
|
||||||
|
FSlateDrawElement::MakeBox(OutDrawElements, LayerId + 3, AllottedGeometry.ToPaintGeometry(FVector2f(XLength / ClipData->MovieBrushes.Num(), AllottedGeometry.GetLocalSize().Y), FSlateLayoutTransform(FVector2f(i * (XLength / ClipData->MovieBrushes.Num()), 0))), &SlateBrush);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (ClipData->PresetType == EPresetType::EnableProjector)
|
if (ClipData->PresetType == EPresetType::EnableProjector)
|
||||||
{
|
{
|
||||||
FSlateDrawElement::MakeText(OutDrawElements, LayerId + 2, AllottedGeometry.ToPaintGeometry(), FText::FromString(TEXT("开启投影仪")), FAppStyle::Get().GetWidgetStyle<FTextBlockStyle>("NormalText").Font, ESlateDrawEffect::None, FLinearColor::White);
|
FSlateDrawElement::MakeText(OutDrawElements, LayerId + 2, AllottedGeometry.ToPaintGeometry(), FText::FromString(TEXT("开启投影仪")), FAppStyle::Get().GetWidgetStyle<FTextBlockStyle>("NormalText").Font, ESlateDrawEffect::None, FLinearColor::White);
|
||||||
|
Loading…
Reference in New Issue
Block a user