@@ -1,5 +1,10 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## v0.15.4
|
||||||
|
|
||||||
|
- 修复导出时可能的卡死问题
|
||||||
|
- 增加 webp 格式无损压缩参数
|
||||||
|
|
||||||
## v0.15.3
|
## v0.15.3
|
||||||
|
|
||||||
- 增加 skel.bytes 后缀识别
|
- 增加 skel.bytes 后缀识别
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
||||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
<Version>0.15.2</Version>
|
<Version>0.15.4</Version>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
||||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
<Version>0.15.2</Version>
|
<Version>0.15.4</Version>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ namespace Spine.Exporters
|
|||||||
public int Quality { get => _quality; set => _quality = Math.Clamp(value, 0, 100); }
|
public int Quality { get => _quality; set => _quality = Math.Clamp(value, 0, 100); }
|
||||||
private int _quality = 75;
|
private int _quality = 75;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 无损压缩 (Webp)
|
||||||
|
/// </summary>
|
||||||
|
public bool Lossless { get => _lossless; set => _lossless = value; }
|
||||||
|
private bool _lossless = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CRF
|
/// CRF
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -62,7 +68,8 @@ namespace Spine.Exporters
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected override SFMLImageVideoFrame GetFrame(SpineObject[] spines)
|
protected override SFMLImageVideoFrame GetFrame(SpineObject[] spines)
|
||||||
{
|
{
|
||||||
// XXX: 不知道为什么用 FFmpeg 必须临时创建 RenderTexture, 否则无法正常渲染
|
// BUG: 也许和 SFML 多线程或者 FFmpeg 调用有关, 当渲染线程也在运行的时候此处并行渲染会导致和 SFML 有关的内容都卡死
|
||||||
|
// 不知道为什么用 FFmpeg 必须临时创建 RenderTexture, 否则无法正常渲染, 会导致画面帧丢失
|
||||||
using var tex = new RenderTexture(_renderTexture.Size.X, _renderTexture.Size.Y);
|
using var tex = new RenderTexture(_renderTexture.Size.X, _renderTexture.Size.Y);
|
||||||
using var view = _renderTexture.GetView();
|
using var view = _renderTexture.GetView();
|
||||||
tex.SetView(view);
|
tex.SetView(view);
|
||||||
@@ -112,7 +119,7 @@ namespace Spine.Exporters
|
|||||||
|
|
||||||
private void SetWebpOptions(FFMpegArgumentOptions options)
|
private void SetWebpOptions(FFMpegArgumentOptions options)
|
||||||
{
|
{
|
||||||
var customArgs = $"-vf unpremultiply=inplace=1 -quality {_quality} -loop {(_loop ? 0 : 1)}";
|
var customArgs = $"-vf unpremultiply=inplace=1 -quality {_quality} -loop {(_loop ? 0 : 1)} -lossless {(_lossless ? 1 : 0)}";
|
||||||
options.ForceFormat("webp").WithVideoCodec("libwebp_anim").ForcePixelFormat("yuva420p")
|
options.ForceFormat("webp").WithVideoCodec("libwebp_anim").ForcePixelFormat("yuva420p")
|
||||||
.WithCustomArgument(customArgs);
|
.WithCustomArgument(customArgs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
||||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
<Version>0.15.3</Version>
|
<Version>0.15.4</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -174,6 +174,8 @@
|
|||||||
<s:String x:Key="Str_LoopPlayTooltip">Loop animation; only effective for GIF/WebP formats</s:String>
|
<s:String x:Key="Str_LoopPlayTooltip">Loop animation; only effective for GIF/WebP formats</s:String>
|
||||||
<s:String x:Key="Str_QualityParameter">Quality Parameter</s:String>
|
<s:String x:Key="Str_QualityParameter">Quality Parameter</s:String>
|
||||||
<s:String x:Key="Str_QualityParameterTooltip">Range 0–100; higher is better; only for WebP format</s:String>
|
<s:String x:Key="Str_QualityParameterTooltip">Range 0–100; higher is better; only for WebP format</s:String>
|
||||||
|
<s:String x:Key="Str_LosslessParam">Lossless Compression</s:String>
|
||||||
|
<s:String x:Key="Str_LosslessParamTooltip">Lossless compression. Ignores the quality parameter and only applies to WebP format.</s:String>
|
||||||
<s:String x:Key="Str_CrfParameter">CRF Parameter</s:String>
|
<s:String x:Key="Str_CrfParameter">CRF Parameter</s:String>
|
||||||
<s:String x:Key="Str_CrfParameterTooltip">Range 0–63; lower is higher quality; only for MP4/WebM/MKV formats</s:String>
|
<s:String x:Key="Str_CrfParameterTooltip">Range 0–63; lower is higher quality; only for MP4/WebM/MKV formats</s:String>
|
||||||
|
|
||||||
|
|||||||
@@ -174,6 +174,8 @@
|
|||||||
<s:String x:Key="Str_LoopPlayTooltip">アニメーションをループ再生するか。Gif/Webp形式のみ有効です</s:String>
|
<s:String x:Key="Str_LoopPlayTooltip">アニメーションをループ再生するか。Gif/Webp形式のみ有効です</s:String>
|
||||||
<s:String x:Key="Str_QualityParameter">品質パラメーター</s:String>
|
<s:String x:Key="Str_QualityParameter">品質パラメーター</s:String>
|
||||||
<s:String x:Key="Str_QualityParameterTooltip">品質パラメーター。値の範囲は0-100。数値が大きいほど品質が高くなります。Webp形式のみ有効です</s:String>
|
<s:String x:Key="Str_QualityParameterTooltip">品質パラメーター。値の範囲は0-100。数値が大きいほど品質が高くなります。Webp形式のみ有効です</s:String>
|
||||||
|
<s:String x:Key="Str_LosslessParam">可逆圧縮</s:String>
|
||||||
|
<s:String x:Key="Str_LosslessParamTooltip">可逆圧縮を行います。品質パラメータは無視され、WebP形式にのみ適用されます。</s:String>
|
||||||
<s:String x:Key="Str_CrfParameter">CRFパラメーター</s:String>
|
<s:String x:Key="Str_CrfParameter">CRFパラメーター</s:String>
|
||||||
<s:String x:Key="Str_CrfParameterTooltip">CRFパラメーター。値の範囲は0-63。数値が小さいほど品質が高くなります。Mp4/Webm/Mkv形式のみ有効です</s:String>
|
<s:String x:Key="Str_CrfParameterTooltip">CRFパラメーター。値の範囲は0-63。数値が小さいほど品質が高くなります。Mp4/Webm/Mkv形式のみ有効です</s:String>
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,9 @@
|
|||||||
<s:String x:Key="Str_LoopPlay">循环播放</s:String>
|
<s:String x:Key="Str_LoopPlay">循环播放</s:String>
|
||||||
<s:String x:Key="Str_LoopPlayTooltip">动图是否循环播放,仅对 Gif/Webp 格式生效</s:String>
|
<s:String x:Key="Str_LoopPlayTooltip">动图是否循环播放,仅对 Gif/Webp 格式生效</s:String>
|
||||||
<s:String x:Key="Str_QualityParameter">质量参数</s:String>
|
<s:String x:Key="Str_QualityParameter">质量参数</s:String>
|
||||||
<s:String x:Key="Str_QualityParameterTooltip">质量参数,取值范围 0-100,越高质量越好 仅对 Webp 格式生效</s:String>
|
<s:String x:Key="Str_QualityParameterTooltip">质量参数,取值范围 0-100,越高质量越好, 仅对 Webp 格式生效</s:String>
|
||||||
|
<s:String x:Key="Str_LosslessParam">无损压缩</s:String>
|
||||||
|
<s:String x:Key="Str_LosslessParamTooltip">无损压缩, 会忽略质量参数, 仅对 Webp 格式生效</s:String>
|
||||||
<s:String x:Key="Str_CrfParameter">CRF 参数</s:String>
|
<s:String x:Key="Str_CrfParameter">CRF 参数</s:String>
|
||||||
<s:String x:Key="Str_CrfParameterTooltip">CRF 参数,取值范围 0-63,越小质量越高,仅对 Mp4/Webm/Mkv 格式生效</s:String>
|
<s:String x:Key="Str_CrfParameterTooltip">CRF 参数,取值范围 0-63,越小质量越高,仅对 Mp4/Webm/Mkv 格式生效</s:String>
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
||||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
<Version>0.15.3</Version>
|
<Version>0.15.4</Version>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -142,7 +142,6 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
{
|
{
|
||||||
if (!Export_CanExecute(args)) return;
|
if (!Export_CanExecute(args)) return;
|
||||||
Export(args.Cast<SpineObjectModel>().ToArray());
|
Export(args.Cast<SpineObjectModel>().ToArray());
|
||||||
// XXX: 导出途中应该停掉渲染好一些, 让性能专注在导出上
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Export_CanExecute(IList? args)
|
private bool Export_CanExecute(IList? args)
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
exporter.Rotation = view.Rotation;
|
exporter.Rotation = view.Rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_vmMain.SFMLRendererViewModel.StopRender();
|
||||||
|
|
||||||
if (_exportSingle)
|
if (_exportSingle)
|
||||||
{
|
{
|
||||||
var filename = $"ffmpeg_{timestamp}_{Guid.NewGuid().ToString()[..6]}_{_fps}{FormatSuffix}";
|
var filename = $"ffmpeg_{timestamp}_{Guid.NewGuid().ToString()[..6]}_{_fps}{FormatSuffix}";
|
||||||
@@ -168,6 +170,8 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
}
|
}
|
||||||
_vmMain.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
|
_vmMain.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_vmMain.SFMLRendererViewModel.StartRender();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
public int Quality { get => _quality; set => SetProperty(ref _quality, Math.Clamp(value, 0, 100)); }
|
public int Quality { get => _quality; set => SetProperty(ref _quality, Math.Clamp(value, 0, 100)); }
|
||||||
protected int _quality = 75;
|
protected int _quality = 75;
|
||||||
|
|
||||||
|
public bool Lossless { get => _lossless; set => SetProperty(ref _lossless, value); }
|
||||||
|
protected bool _lossless = false;
|
||||||
|
|
||||||
public int Crf { get => _crf; set => SetProperty(ref _crf, Math.Clamp(value, 0, 63)); }
|
public int Crf { get => _crf; set => SetProperty(ref _crf, Math.Clamp(value, 0, 63)); }
|
||||||
protected int _crf = 23;
|
protected int _crf = 23;
|
||||||
|
|
||||||
@@ -55,6 +58,7 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
Format = _format,
|
Format = _format,
|
||||||
Loop = _loop,
|
Loop = _loop,
|
||||||
Quality = _quality,
|
Quality = _quality,
|
||||||
|
Lossless = _lossless,
|
||||||
Crf = _crf
|
Crf = _crf
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -68,6 +72,10 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
exporter.Rotation = view.Rotation;
|
exporter.Rotation = view.Rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BUG: FFmpeg 导出时对 RenderTexture 的频繁资源申请释放似乎使 SFML 库内部出现问题, 会卡死所有使用 SFML 的地方, 包括渲染线程
|
||||||
|
// 所以临时把渲染线程停掉, 只让此处使用 SFML 资源, 这个问题或许和多个线程同时使用渲染资源有关
|
||||||
|
_vmMain.SFMLRendererViewModel.StopRender();
|
||||||
|
|
||||||
if (_exportSingle)
|
if (_exportSingle)
|
||||||
{
|
{
|
||||||
var filename = $"video_{timestamp}_{Guid.NewGuid().ToString()[..6]}_{_fps}{FormatSuffix}";
|
var filename = $"video_{timestamp}_{Guid.NewGuid().ToString()[..6]}_{_fps}{FormatSuffix}";
|
||||||
@@ -153,6 +161,8 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
}
|
}
|
||||||
_vmMain.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
|
_vmMain.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_vmMain.SFMLRendererViewModel.StartRender();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
exporter.Rotation = view.Rotation;
|
exporter.Rotation = view.Rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_vmMain.SFMLRendererViewModel.StopRender();
|
||||||
|
|
||||||
if (_exportSingle)
|
if (_exportSingle)
|
||||||
{
|
{
|
||||||
var folderName = $"frames_{timestamp}_{Guid.NewGuid().ToString()[..6]}_{_fps}";
|
var folderName = $"frames_{timestamp}_{Guid.NewGuid().ToString()[..6]}_{_fps}";
|
||||||
@@ -132,6 +134,8 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
}
|
}
|
||||||
_vmMain.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
|
_vmMain.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_vmMain.SFMLRendererViewModel.StartRender();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
|
|
||||||
private void AddSpineObject_Execute()
|
private void AddSpineObject_Execute()
|
||||||
{
|
{
|
||||||
MessagePopupService.Info("Not Implemented, try next version :)");
|
MessagePopupService.Info("Not Implemented, please drag files into here or add them from clipboard :)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="{DynamicResource Str_FFmpegVideoExporterTitle}"
|
Title="{DynamicResource Str_FFmpegVideoExporterTitle}"
|
||||||
Width="450"
|
Width="450"
|
||||||
Height="550"
|
Height="580"
|
||||||
ShowInTaskbar="False"
|
ShowInTaskbar="False"
|
||||||
WindowStartupLocation="CenterOwner">
|
WindowStartupLocation="CenterOwner">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
@@ -66,6 +66,7 @@
|
|||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- 水平分辨率 -->
|
<!-- 水平分辨率 -->
|
||||||
@@ -138,9 +139,13 @@
|
|||||||
<Label Grid.Row="15" Grid.Column="0" Content="{DynamicResource Str_QualityParameter}" ToolTip="{DynamicResource Str_QualityParameterTooltip}"/>
|
<Label Grid.Row="15" Grid.Column="0" Content="{DynamicResource Str_QualityParameter}" ToolTip="{DynamicResource Str_QualityParameterTooltip}"/>
|
||||||
<TextBox Grid.Row="15" Grid.Column="1" Text="{Binding Quality}" ToolTip="{DynamicResource Str_QualityParameterTooltip}"/>
|
<TextBox Grid.Row="15" Grid.Column="1" Text="{Binding Quality}" ToolTip="{DynamicResource Str_QualityParameterTooltip}"/>
|
||||||
|
|
||||||
|
<!-- 无损压缩 -->
|
||||||
|
<Label Grid.Row="16" Grid.Column="0" Content="{DynamicResource Str_LosslessParam}" ToolTip="{DynamicResource Str_LosslessParamTooltip}"/>
|
||||||
|
<ToggleButton Grid.Row="16" Grid.Column="1" IsChecked="{Binding Lossless}" ToolTip="{DynamicResource Str_LosslessParamTooltip}"/>
|
||||||
|
|
||||||
<!-- CRF 参数 -->
|
<!-- CRF 参数 -->
|
||||||
<Label Grid.Row="16" Grid.Column="0" Content="{DynamicResource Str_CrfParameter}" ToolTip="{DynamicResource Str_CrfParameterTooltip}"/>
|
<Label Grid.Row="17" Grid.Column="0" Content="{DynamicResource Str_CrfParameter}" ToolTip="{DynamicResource Str_CrfParameterTooltip}"/>
|
||||||
<TextBox Grid.Row="16" Grid.Column="1" Text="{Binding Crf}" ToolTip="{DynamicResource Str_CrfParameterTooltip}"/>
|
<TextBox Grid.Row="17" Grid.Column="1" Text="{Binding Crf}" ToolTip="{DynamicResource Str_CrfParameterTooltip}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user