parent
6ed3334760
commit
fe4a3c9b9b
8 changed files with 240 additions and 20 deletions
@ -0,0 +1,159 @@ |
|||||||
|
|
||||||
|
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 async void CreateVideoFromPngList(List<PngBitmapEncoder> pngEncoders, string outputPath) |
||||||
|
{ |
||||||
|
string tempDirectory = Path.Combine(System.Environment.CurrentDirectory, "PngFrames"); |
||||||
|
Directory.CreateDirectory(tempDirectory); |
||||||
|
await Task.Delay(1); |
||||||
|
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 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 < 10000; i += 50) |
||||||
|
{ |
||||||
|
// 使用 Dispatcher.Invoke 来确保 UI 操作在主线程中执行 |
||||||
|
var encoder = Application.Current.Dispatcher.Invoke(() => CutPng(viewport)); |
||||||
|
result.Add(encoder); |
||||||
|
Thread.Sleep(50); // 模拟处理过程 |
||||||
|
} |
||||||
|
|
||||||
|
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(5000); |
||||||
|
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; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue