101 lines
3.9 KiB
C#
101 lines
3.9 KiB
C#
using FFMpegCore;
|
|
using FFMpegCore.Pipes;
|
|
using SFML.Graphics;
|
|
using SFML.System;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Spine.Exporters
|
|
{
|
|
/// <summary>
|
|
/// 自定义参数的 FFmpeg 导出类
|
|
/// </summary>
|
|
public class CustomFFmpegExporter : VideoExporter
|
|
{
|
|
public CustomFFmpegExporter(uint width = 100, uint height = 100) : base(width, height) { }
|
|
public CustomFFmpegExporter(Vector2u resolution) : base(resolution) { }
|
|
|
|
/// <summary>
|
|
/// <c>-f</c>
|
|
/// </summary>
|
|
public string? Format { get => _format; set => _format = value; }
|
|
private string? _format;
|
|
|
|
/// <summary>
|
|
/// <c>-c:v</c>
|
|
/// </summary>
|
|
public string? Codec { get => _codec; set => _codec = value; }
|
|
private string? _codec;
|
|
|
|
/// <summary>
|
|
/// <c>-pix_fmt</c>
|
|
/// </summary>
|
|
public string? PixelFormat { get => _pixelFormat; set => _pixelFormat = value; }
|
|
private string? _pixelFormat;
|
|
|
|
/// <summary>
|
|
/// <c>-b:v</c>
|
|
/// </summary>
|
|
public string? Bitrate { get => _bitrate; set => _bitrate = value; }
|
|
private string? _bitrate;
|
|
|
|
/// <summary>
|
|
/// <c>-vf</c>
|
|
/// </summary>
|
|
public string? Filter { get => _filter; set => _filter = value; }
|
|
private string? _filter;
|
|
|
|
/// <summary>
|
|
/// 其他自定义参数
|
|
/// </summary>
|
|
public string? CustomArgs { get => _customArgs; set => _customArgs = value; }
|
|
private string? _customArgs;
|
|
|
|
private void SetOutputOptions(FFMpegArgumentOptions options)
|
|
{
|
|
if (!string.IsNullOrEmpty(_format)) options.ForceFormat(_format);
|
|
if (!string.IsNullOrEmpty(_codec)) options.WithVideoCodec(_codec);
|
|
if (!string.IsNullOrEmpty(_pixelFormat)) options.ForcePixelFormat(_pixelFormat);
|
|
if (!string.IsNullOrEmpty(_bitrate)) options.WithCustomArgument($"-b:v {_bitrate}");
|
|
if (!string.IsNullOrEmpty(_filter)) options.WithCustomArgument($"-vf \"unpremultiply=inplace=1, {_filter}\"");
|
|
else options.WithCustomArgument("-vf unpremultiply=inplace=1");
|
|
if (!string.IsNullOrEmpty(_customArgs)) options.WithCustomArgument($"{_customArgs}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取的一帧, 结果是预乘的
|
|
/// </summary>
|
|
protected override SFMLImageVideoFrame GetFrame(SpineObject[] spines)
|
|
{
|
|
// BUG: 也许和 SFML 多线程或者 FFmpeg 调用有关, 当渲染线程也在运行的时候此处并行渲染会导致和 SFML 有关的内容都卡死
|
|
// 不知道为什么用 FFmpeg 必须临时创建 RenderTexture, 否则无法正常渲染, 会导致画面帧丢失
|
|
using var tex = new RenderTexture(_renderTexture.Size.X, _renderTexture.Size.Y);
|
|
using var view = _renderTexture.GetView();
|
|
tex.SetView(view);
|
|
tex.Clear(_backgroundColorPma);
|
|
foreach (var sp in spines.Reverse()) tex.Draw(sp);
|
|
tex.Display();
|
|
return new(tex.Texture.CopyToImage());
|
|
}
|
|
|
|
public override void Export(string output, CancellationToken ct, params SpineObject[] spines)
|
|
{
|
|
var videoFramesSource = new RawVideoPipeSource(GetFrames(spines, output, ct)) { FrameRate = _fps };
|
|
try
|
|
{
|
|
var ffmpegArgs = FFMpegArguments.FromPipeInput(videoFramesSource).OutputToFile(output, true, SetOutputOptions);
|
|
_logger.Info("FFmpeg arguments: {0}", ffmpegArgs.Arguments);
|
|
ffmpegArgs.ProcessSynchronously();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Debug(ex.ToString());
|
|
_logger.Error("Failed to export {0} {1}, {2}", _format, output, ex.Message);
|
|
}
|
|
}
|
|
}
|
|
}
|