139 lines
4.8 KiB
C#
139 lines
4.8 KiB
C#
using EmbyToolbox.Models;
|
||
|
||
namespace EmbyToolbox.Services;
|
||
|
||
/// <summary>Правила совместимости субтитров с контейнером MKV/MP4 и codec copy в FFmpeg.</summary>
|
||
public static class SubtitleCodecRules
|
||
{
|
||
public static string Normalize(string? codec) =>
|
||
string.IsNullOrWhiteSpace(codec) ? string.Empty : codec.Trim().ToLowerInvariant();
|
||
|
||
public static bool IsTeletext(string? codec) => Normalize(codec) == "dvb_teletext";
|
||
|
||
public static bool IsUnknownSubtitleCodec(string? codec)
|
||
{
|
||
var n = Normalize(codec);
|
||
return n is "" or "?" or "unknown";
|
||
}
|
||
|
||
/// <summary>Кодеки, которые можно mux copy в Matroska (без teletext / mov_text и пр.).</summary>
|
||
public static bool IsMkvCopySafe(string? codec)
|
||
{
|
||
return Normalize(codec) switch
|
||
{
|
||
"subrip" or "srt" or "ass" or "ssa" => true,
|
||
"webvtt" or "wvtt" => true,
|
||
"hdmv_pgs_subtitle" or "pgssub" => true,
|
||
"dvd_subtitle" or "dvdsub" => true,
|
||
_ => false
|
||
};
|
||
}
|
||
|
||
public static bool IsMp4TextDirectCopy(string? codec) => Normalize(codec) == "mov_text";
|
||
|
||
/// <summary>Текстовые дорожки, для MP4 требующие перекодирования в mov_text (не mux copy).</summary>
|
||
public static bool Mp4RequiresSubtitleTranscode(string? codec)
|
||
{
|
||
return Normalize(codec) switch
|
||
{
|
||
"subrip" or "srt" or "ass" or "ssa" => true,
|
||
_ => false
|
||
};
|
||
}
|
||
|
||
public static bool TargetsMkv(string? container) =>
|
||
!string.IsNullOrWhiteSpace(container) &&
|
||
(container.Contains("mkv", StringComparison.OrdinalIgnoreCase) ||
|
||
container.Contains("matro", StringComparison.OrdinalIgnoreCase));
|
||
|
||
public static bool TargetsMp4(string? container) =>
|
||
!string.IsNullOrWhiteSpace(container) &&
|
||
(container.Contains("mp4", StringComparison.OrdinalIgnoreCase) ||
|
||
container.Contains("m4v", StringComparison.OrdinalIgnoreCase) ||
|
||
container.Contains("mov", StringComparison.OrdinalIgnoreCase));
|
||
|
||
/// <summary>Действо по умолчанию для встроенной дорожки субтитров после анализа.</summary>
|
||
public static TrackActionKind DefaultEmbeddedSubtitleAction(string? codecName, string? profileContainer)
|
||
{
|
||
var c = codecName;
|
||
|
||
if (IsTeletext(c) || IsUnknownSubtitleCodec(c))
|
||
{
|
||
return TrackActionKind.Remove;
|
||
}
|
||
|
||
if (TargetsMkv(profileContainer))
|
||
{
|
||
return IsMkvCopySafe(c) ? TrackActionKind.Keep : TrackActionKind.Remove;
|
||
}
|
||
|
||
if (TargetsMp4(profileContainer))
|
||
{
|
||
if (IsMp4TextDirectCopy(c))
|
||
{
|
||
return TrackActionKind.Keep;
|
||
}
|
||
|
||
if (Mp4RequiresSubtitleTranscode(c))
|
||
{
|
||
return TrackActionKind.Convert;
|
||
}
|
||
|
||
return TrackActionKind.Remove;
|
||
}
|
||
|
||
return IsMkvCopySafe(c) ? TrackActionKind.Keep : TrackActionKind.Remove;
|
||
}
|
||
|
||
/// <summary>Встроенную субдорожку с этим решением включают в ffmpeg -map только если истина.</summary>
|
||
public static bool ShouldMapEmbeddedSubtitle(
|
||
MediaAnalysisResult media,
|
||
TrackOverrideEntry t,
|
||
string effectiveContainer)
|
||
{
|
||
if (t.Source != SourceKind.Embedded || t.StreamKind != MediaStreamKind.Subtitle)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
if (t.Action == TrackActionKind.Remove)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
var codec = media.AllStreams.FirstOrDefault(s => s.Index == t.StreamIndex)?.CodecName;
|
||
|
||
if (TargetsMkv(effectiveContainer))
|
||
{
|
||
if (!IsMkvCopySafe(codec))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return t.Action is TrackActionKind.Keep or TrackActionKind.Convert;
|
||
}
|
||
|
||
if (TargetsMp4(effectiveContainer))
|
||
{
|
||
if (IsMp4TextDirectCopy(codec) && t.Action == TrackActionKind.Keep)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
if (Mp4RequiresSubtitleTranscode(codec) &&
|
||
t.Action is TrackActionKind.Convert or TrackActionKind.Keep)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
return IsMkvCopySafe(codec) ? t.Action != TrackActionKind.Remove : false;
|
||
}
|
||
|
||
/// <summary>Строковая подпись Codec для дорожки (субтитры отображать как текстовые / teletext).</summary>
|
||
public static string EmbeddedSubtitleCodecLabel(string? ffprobeCodec) =>
|
||
IsTeletext(ffprobeCodec) ? "dvb_teletext (subtitle)" : ffprobeCodec ?? "?";
|
||
}
|