FFMPEG导出视频测试
This commit is contained in:
parent
3eb8c9ae88
commit
d580c945a6
@ -2,6 +2,11 @@
|
||||
|
||||
#include "Cut5/Widgets/DefineGlobal.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
}
|
||||
|
||||
FString FUtils::MakeStringUpright(const FString& String)
|
||||
{
|
||||
FString Result;
|
||||
@ -79,6 +84,91 @@ void FUtils::CreateDefaultTimelineSave(const FString& SavedPath, const FTimeline
|
||||
FFileHelper::SaveArrayToFile(SavedData, *SavedPath);
|
||||
}
|
||||
|
||||
void FUtils::TrackEncodeVideo(const FTrackData& TrackData, const FString& ExportPath)
|
||||
{
|
||||
|
||||
if (TrackData.ClipData.Num() == 0)
|
||||
return;
|
||||
|
||||
AVFormatContext *outctx = NULL;
|
||||
AVStream *outstream = NULL;
|
||||
AVCodecContext *outcodecctx = NULL;
|
||||
AVCodec *outcodec = NULL;
|
||||
|
||||
avformat_alloc_output_context2(&outctx, NULL, NULL, "output.mp4");
|
||||
outcodec = avcodec_find_encoder(AV_CODEC_ID_H264);
|
||||
outstream = avformat_new_stream(outctx, outcodec);
|
||||
outcodecctx = avcodec_alloc_context3(outcodec);
|
||||
|
||||
|
||||
TArray<FClipData> ClipData = TrackData.ClipData;
|
||||
ClipData.Sort([](const FClipData& A, const FClipData& B) {return A.ClipStartFrame < B.ClipStartFrame; });
|
||||
|
||||
|
||||
|
||||
// 对于每个AVFrame
|
||||
AVFrame *frame = NULL;
|
||||
|
||||
|
||||
|
||||
|
||||
for (FClipData& TempClipData : ClipData)
|
||||
{
|
||||
// 先从 ClipData 中读取这个 Clip 的视频数据。
|
||||
if (TempClipData.ResourcePropertyDataPtr->Context)
|
||||
{
|
||||
FTimespan EndTimespan = FTimespan::FromSeconds(TempClipData.VideoEndFrame / FGlobalData::GlobalFPS);
|
||||
FTimespan StartTimespan = FTimespan::FromSeconds(TempClipData.VideoStartFrame / FGlobalData::GlobalFPS);
|
||||
|
||||
|
||||
FString StartTime = FString::Printf(TEXT("%02d:%02d:%02d"), StartTimespan.GetHours(), StartTimespan.GetMinutes(), StartTimespan.GetSeconds());
|
||||
FString EndTime = FString::Printf(TEXT("%02d:%02d:%02d"), EndTimespan.GetHours(), EndTimespan.GetMinutes(), EndTimespan.GetSeconds());
|
||||
FString InputFile = TempClipData.ResourcePropertyDataPtr->MoviePath;
|
||||
FString OutputFile = FPaths::ConvertRelativePathToFull((FPaths::Combine(FPaths::ProjectDir(), TEXT("output.mp4"))));
|
||||
int32 StartFrame = (TempClipData.VideoStartFrame) % static_cast<int>(FGlobalData::GlobalFPS);;
|
||||
int32 EndFrame = (TempClipData.VideoEndFrame) % static_cast<int>(FGlobalData::GlobalFPS);
|
||||
|
||||
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("StartFrame: %d, EndFrame: %d"), StartFrame, EndFrame));
|
||||
//输出文件名字
|
||||
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("OutputFile: %s"), *OutputFile));
|
||||
//输入文件名字
|
||||
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("InputFile: %s"), *InputFile));
|
||||
//开始时间
|
||||
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("StartTime: %s"), *StartTime));
|
||||
//结束时间
|
||||
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FString::Printf(TEXT("EndTime: %s"), *EndTime));
|
||||
// 构造FFmpeg命令
|
||||
FString Command = FString::Printf(TEXT("-y -i %s -ss %s -to %s -c copy %s"),
|
||||
*InputFile, *StartTime, *EndTime, *OutputFile);
|
||||
|
||||
FString FFmpegPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectDir() / TEXT("Binaries") / TEXT("Win64") / TEXT("ffmpeg.exe"));
|
||||
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, FFmpegPath + " " + FString::Printf(TEXT("%s"), *Command));
|
||||
// FFmpeg的路径,需要根据实际情况修改
|
||||
|
||||
|
||||
// 创建进程
|
||||
FPlatformProcess::CreateProc(*FFmpegPath, *Command, true, false, false, nullptr, 0, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// av_write_trailer(outctx);
|
||||
// avio_close(outctx->pb);
|
||||
// avformat_free_context(outctx);
|
||||
// av_frame_free(&frame);
|
||||
|
||||
|
||||
}
|
||||
|
||||
FSaveModifier::FSaveModifier(const FString& FullSavedPath)
|
||||
{
|
||||
|
||||
|
@ -22,6 +22,7 @@ public:
|
||||
*/
|
||||
static void CreateDefaultTimelineSave(const FString& SavedPath, const FTimelineInfo::ETimelineType Type);
|
||||
|
||||
static void TrackEncodeVideo(const FTrackData& TrackData, const FString& ExportPath);
|
||||
|
||||
static FString GroupFullPath(const FString& GroupName)
|
||||
{
|
||||
|
@ -7,6 +7,7 @@ void FMainMenuCommands::RegisterCommands()
|
||||
UI_COMMAND(OpenProject, "打开", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
|
||||
UI_COMMAND(SaveProject, "保存", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
|
||||
UI_COMMAND(SaveProjectAs, "另存为", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
|
||||
UI_COMMAND(ExportXML, "导出", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
|
||||
UI_COMMAND(Setting, "设置", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
|
||||
UI_COMMAND(Exit, "退出", "Executes My TimelineClipCommands", EUserInterfaceActionType::Button, FInputChord());
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ public:
|
||||
TSharedPtr<FUICommandInfo> OpenProject;
|
||||
TSharedPtr<FUICommandInfo> SaveProject;
|
||||
TSharedPtr<FUICommandInfo> SaveProjectAs;
|
||||
TSharedPtr<FUICommandInfo> ExportXML;
|
||||
TSharedPtr<FUICommandInfo> Setting;
|
||||
TSharedPtr<FUICommandInfo> Exit;
|
||||
};
|
@ -134,6 +134,7 @@ void DragDropOperator::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent&
|
||||
// 如果拖拽物是视频,那么对不同轨道进行不同和操作
|
||||
NewClipData.MoviePath = ClipDragOperation.TimelinePropertyData->MoviePath;
|
||||
NewClipData.ClipEndFrame = NewClipData.ClipStartFrame + ClipDragOperation.TimelinePropertyData->MovieFrameLength;
|
||||
NewClipData.VideoEndFrame = ClipDragOperation.TimelinePropertyData->MovieFrameLength;
|
||||
NewClipData.VideoCapture = ClipDragOperation.VideoCapture;
|
||||
if (TrackHead->TrackData.TrackType == ETrackType::LightArrayTrack)
|
||||
{
|
||||
|
@ -40,32 +40,8 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
|
||||
SAssignNew(StatePanel, SStatePanel);
|
||||
SAssignNew(CustomPanel, SCustomPanel);
|
||||
|
||||
FMainMenuCommands::Register();
|
||||
CommandList = MakeShareable(new FUICommandList);
|
||||
CommandList->MapAction(FMainMenuCommands::Get().NewProject, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
PreNewProject();
|
||||
}));
|
||||
CommandList->MapAction(FMainMenuCommands::Get().OpenProject, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
FString String;
|
||||
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
||||
DesktopPlatform->OpenDirectoryDialog(nullptr, TEXT("选择新建路径"), String, String);
|
||||
if (String.IsEmpty())
|
||||
return;
|
||||
OpenProject(String);
|
||||
}));
|
||||
CommandList->MapAction(FMainMenuCommands::Get().SaveProject, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
SaveProject();
|
||||
}));
|
||||
|
||||
|
||||
CommandList->MapAction(FMainMenuCommands::Get().Exit, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
FPlatformMisc::RequestExit(true);
|
||||
}));
|
||||
|
||||
FTextBlockStyle MainBarTextStyle = FAppStyle::GetWidgetStyle<FTextBlockStyle>("NormalText");
|
||||
MainBarTextStyle.SetFontSize(17);
|
||||
FTextBlockStyle TitleBarTextStyle = FAppStyle::GetWidgetStyle<FTextBlockStyle>("NormalText");
|
||||
@ -131,6 +107,7 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
|
||||
MenuBuilder.AddMenuEntry(FMainMenuCommands::Get().OpenProject, NAME_None, FText::FromString(TEXT("打开")));
|
||||
MenuBuilder.AddMenuEntry(FMainMenuCommands::Get().SaveProject, NAME_None, FText::FromString(TEXT("保存")));
|
||||
MenuBuilder.AddMenuEntry(FMainMenuCommands::Get().SaveProjectAs, NAME_None, FText::FromString(TEXT("保存为")));
|
||||
MenuBuilder.AddMenuEntry(FMainMenuCommands::Get().ExportXML, NAME_None, FText::FromString(TEXT("导出项目到xml")));
|
||||
MenuBuilder.AddMenuEntry(FMainMenuCommands::Get().Setting, NAME_None, FText::FromString(TEXT("设置")));
|
||||
MenuBuilder.AddMenuEntry(FMainMenuCommands::Get().Exit, NAME_None, FText::FromString(TEXT("退出")));
|
||||
FSlateApplication::Get().PushMenu(AsShared(), FWidgetPath(), MenuBuilder.MakeWidget(), FSlateApplication::Get().GetCursorPos(), FPopupTransitionEffect(FPopupTransitionEffect::ContextMenu));
|
||||
@ -350,6 +327,42 @@ void SCutMainWindow::Construct(const FArguments& InArgs)
|
||||
// OpenProject(FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("DefaultProject")));
|
||||
// ImportProject("");
|
||||
|
||||
|
||||
FMainMenuCommands::Register();
|
||||
CommandList = MakeShareable(new FUICommandList);
|
||||
CommandList->MapAction(FMainMenuCommands::Get().ExportXML, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
FString String;
|
||||
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
||||
DesktopPlatform->OpenDirectoryDialog(nullptr, TEXT("选择导出路径"), String, String);
|
||||
if (String.IsEmpty())
|
||||
return;
|
||||
ExportProject(String);
|
||||
}));
|
||||
|
||||
CommandList->MapAction(FMainMenuCommands::Get().NewProject, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
PreNewProject();
|
||||
}));
|
||||
CommandList->MapAction(FMainMenuCommands::Get().OpenProject, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
FString String;
|
||||
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
|
||||
DesktopPlatform->OpenDirectoryDialog(nullptr, TEXT("选择新建路径"), String, String);
|
||||
if (String.IsEmpty())
|
||||
return;
|
||||
OpenProject(String);
|
||||
}));
|
||||
CommandList->MapAction(FMainMenuCommands::Get().SaveProject, FExecuteAction::CreateLambda([this]()
|
||||
{
|
||||
SaveProject();
|
||||
}));
|
||||
|
||||
|
||||
// CommandList->MapAction(FMainMenuCommands::Get().Exit, FExecuteAction::CreateLambda([this]()
|
||||
// {
|
||||
// FPlatformMisc::RequestExit(true);
|
||||
// }));
|
||||
}
|
||||
|
||||
void SCutMainWindow::Render()
|
||||
@ -636,19 +649,20 @@ void SCutMainWindow::OpenProject(const FString& Project)
|
||||
|
||||
void SCutMainWindow::ExportProject(const FString& ExportPath)
|
||||
{
|
||||
// Save Project Link
|
||||
TArray<uint8> Data {0};
|
||||
FMemoryWriter MemoryWriter(Data);
|
||||
FString CustomInputPanelSavePath = ExportPath + "/" + FGlobalData::CurrentProjectName + "/Dataset/" + TEXT("CustomInputPanel.bin");
|
||||
MemoryWriter << CustomInputPanelSavePath;
|
||||
CustomInputPanel->SavePanel(CustomInputPanelSavePath);
|
||||
|
||||
FString FXPath = ExportPath + "/" + FGlobalData::CurrentProjectName + "/Dataset/" + TEXT("FX.bin");
|
||||
MemoryWriter << FXPath;
|
||||
EffectCardsPanel->SavePanel(FXPath);
|
||||
for (FTrackGroup& TrackGroup : CutTimeline->TrackGroups)
|
||||
{
|
||||
for (FTrackData& TrackData : TrackGroup.TrackDataArray)
|
||||
{
|
||||
|
||||
FFileHelper::SaveArrayToFile(Data, *FPaths::Combine(ExportPath, *FGlobalData::CurrentProjectName, FGlobalData::CurrentProjectName + TEXT("_Link.cutlink")));
|
||||
FUtils::TrackEncodeVideo(TrackData, {});
|
||||
}
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < CutTimeline->TrackGroupInstances.Num(); i++)
|
||||
{
|
||||
FUtils::TrackEncodeVideo(StaticCastSharedPtr<STrackHead>(CutTimeline->TrackGroupInstances[i].Head)->TrackData, TEXT("D:\\Project\\Cut5\\Movie.mp4"));
|
||||
}
|
||||
|
||||
if (ExportPath.IsEmpty())
|
||||
return;
|
||||
|
@ -167,7 +167,6 @@ void STimelineClip::Seek(int32 Frame)
|
||||
{
|
||||
case ETrackType::VideoTrack:
|
||||
{
|
||||
|
||||
if (!ClipData->VideoCapture || Frame > ClipData->ClipEndFrame || Frame < 0)
|
||||
{
|
||||
return;
|
||||
|
BIN
output.mp4
Normal file
BIN
output.mp4
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user