You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
8.7 KiB

using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using HelixToolkit.Wpf.SharpDX;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Media.Imaging;
using System.Drawing;
using System.Windows;
namespace SparkClient.Views.UserControl.ViewportData.Helper;
public class VideoHelper
{
public static void CreateVideoFromPngList(List<PngBitmapEncoder> pngEncoders, string outputPath)
{
string tempDirectory = Path.Combine(System.Environment.CurrentDirectory, "PngFrames");
Directory.CreateDirectory(tempDirectory);
try
{
// Save each PNG frame to a temporary directory
for (int i = 0; i < pngEncoders.Count; i++)
{
string framePath = Path.Combine(tempDirectory, $"frame_{i:D5}.png");
using (FileStream fs = new FileStream(framePath, FileMode.Create))
{
pngEncoders[i].Save(fs);
}
}
// Use FFmpeg to create a video from the PNG frames
string ffmpegPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ffmpeg.exe"); // Assuming ffmpeg.exe is in the same directory as the application
if (!File.Exists(ffmpegPath))
{
throw new FileNotFoundException("FFmpeg executable not found.", ffmpegPath);
}
string framePattern = Path.Combine(tempDirectory, "frame_%05d.png").Replace("\\", "/"); // Replace backslashes with forward slashes for FFmpeg compatibility
string arguments = $"-framerate 30 -i \"{framePattern}\" -vf \"scale=640:480\" -c:v libx264 -pix_fmt yuv420p \"{outputPath}\"";
var processInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = ffmpegPath,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using (var process = System.Diagnostics.Process.Start(processInfo))
{
string error = process.StandardError.ReadToEnd();
process.WaitForExit();
if (process.ExitCode != 0)
{
throw new Exception($"FFmpeg error: {error}");
}
}
var dicName = Path.GetDirectoryName(outputPath);
var fileName =Path.GetFileNameWithoutExtension(outputPath);
Microsoft.VisualBasic.FileIO.FileSystem.RenameFile(outputPath, fileName+".dat");
}
finally
{
// Clean up temporary frames
Directory.Delete(tempDirectory, true);
}
}
public static async Task CreateVideoFromPngListAsync(List<PngBitmapEncoder> pngEncoders, string outputPath)
{
string tempDirectory = Path.Combine(Environment.CurrentDirectory, "PngFrames");
Directory.CreateDirectory(tempDirectory);
await Task.Delay(1).ConfigureAwait(false);
try
{
// Save each PNG frame to a temporary directory
for (int i = 0; i < pngEncoders.Count; i++)
{
string framePath = Path.Combine(tempDirectory, $"frame_{i:D5}.png");
await Task.Run(() =>
{
Application.Current.Dispatcher.Invoke(() =>
{
using (FileStream fs = new FileStream(framePath, FileMode.Create))
{
pngEncoders[i].Save(fs);
}
});
}).ConfigureAwait(false);
}
// Use FFmpeg to create a video from the PNG frames
string ffmpegPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ffmpeg.exe"); // Assuming ffmpeg.exe is in the same directory as the application
if (!File.Exists(ffmpegPath))
{
// throw new FileNotFoundException("", ffmpegPath);
MessageBox.Show("FFmpeg executable not found.", ffmpegPath);
}
string framePattern = Path.Combine(tempDirectory, "frame_%05d.png").Replace("\\", "/"); // Replace backslashes with forward slashes for FFmpeg compatibility
string arguments = $"-framerate 30 -i \"{framePattern}\" -vf \"scale=640:480\" -c:v libx264 -pix_fmt yuv420p \"{outputPath}\"";
var processInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = ffmpegPath,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using (var process = System.Diagnostics.Process.Start(processInfo))
{
string error = await process.StandardError.ReadToEndAsync().ConfigureAwait(false);
process.WaitForExit();
if (process.ExitCode != 0)
{
throw new Exception($"FFmpeg error: {error}");
}
}
// var dicName = Path.GetDirectoryName(outputPath);
// var fileName = Path.GetFileNameWithoutExtension(outputPath);
// Microsoft.VisualBasic.FileIO.FileSystem.RenameFile(outputPath, fileName + ".dat");
}
finally
{
// Clean up temporary frames
Directory.Delete(tempDirectory, true);
}
}
public static void ConvertMp4ToDat(string inputFilePath, string outputFilePath)
{
string ffmpegPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ffmpeg.exe"); // Assuming ffmpeg.exe is in the same directory as the application
if (!File.Exists(ffmpegPath))
{
throw new FileNotFoundException("FFmpeg executable not found.", ffmpegPath);
}
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = ffmpegPath,
Arguments = $"-i \"{outputFilePath}\" \"{inputFilePath}\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
File.Delete(outputFilePath);
}
public static async Task<List<PngBitmapEncoder>> StartGenerationAndRotation(Viewport3DX viewport)
{
var genPngTask = Task.Run(() => GenPng(viewport));
var rotateModelTask = Task.Run(() => RotateModel());
await Task.WhenAll(genPngTask, rotateModelTask);
return genPngTask.Result;
}
public static List<PngBitmapEncoder> GenPng(Viewport3DX viewport)
{
List<PngBitmapEncoder> result = new List<PngBitmapEncoder>();
for (int i = 0; i < 21000; i+=50)
{
// 使用 Dispatcher.Invoke 来确保 UI 操作在主线程中执行
var encoder = Application.Current.Dispatcher.Invoke(() => CutPng(viewport));
result.Add(encoder);
Thread.Sleep(20); // 模拟处理过程
}
return result;
}
public static async void RotateModel()
{
await Application.Current.Dispatcher.InvokeAsync(() =>
{
var center = ViewportManager.ModelBounds.Center;
var maxDimension = ViewportManager.ModelBounds.Size.Length();
var distance = maxDimension *1.2; // 调整相机到模型的距离,保证视野范围内
var camera = ViewportManager.GetViewport3D().Camera as HelixToolkit.Wpf.SharpDX.PerspectiveCamera;
camera.Position = new Point3D(center.X, center.Y, center.Z + distance); // 从前面看,Z轴正方向
camera.UpDirection = new Vector3D(0, -1, 0);
camera.LookDirection = new Vector3D(center.X - camera.Position.X, center.Y - camera.Position.Y, center.Z - camera.Position.Z);
ViewportHelperPro.RotateModel(new Vector3D(0,-1,0));
});
await Task.Delay(7000);
await Application.Current.Dispatcher.InvokeAsync(() =>
{
ViewportHelperPro.RotateModel(new Vector3D(-1, 0, 0));
});
}
public static PngBitmapEncoder CutPng(Viewport3DX viewport)
{
int width = (int)viewport.ActualWidth;
int height = (int)viewport.ActualHeight;
var renderTargetBitmap = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(viewport);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
return encoder;
}
}