diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs
index 263a7304..761d5e60 100644
--- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs
+++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs
@@ -71,8 +71,9 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes
((FfmpegSubtitleStream)item.stream).Stream;
- var streamArgs = item.stream.GetParameters(new FfmpegStream.GetParametersArgs()
+ var streamArgs = item.stream.GetParameters(new ()
{
+ Logger = args.Logger,
OutputOverallIndex = overallIndex,
OutputTypeIndex = actualIndex,
SourceExtension = sourceExtension,
diff --git a/VideoNodes/FfmpegBuilderNodes/Models/FfmpegStream.cs b/VideoNodes/FfmpegBuilderNodes/Models/FfmpegStream.cs
index 359d590b..5e46b0cf 100644
--- a/VideoNodes/FfmpegBuilderNodes/Models/FfmpegStream.cs
+++ b/VideoNodes/FfmpegBuilderNodes/Models/FfmpegStream.cs
@@ -60,6 +60,11 @@ public abstract class FfmpegStream
/// Gets or sets if the default flag should be set
///
public bool UpdateDefaultFlag { get; set; }
+
+ ///
+ /// Gets or sets the logger
+ ///
+ public ILogger Logger { get; set; }
}
}
diff --git a/VideoNodes/FfmpegBuilderNodes/Models/FfmpegSubtitleStream.cs b/VideoNodes/FfmpegBuilderNodes/Models/FfmpegSubtitleStream.cs
index 0cc11d7e..76cecd2b 100644
--- a/VideoNodes/FfmpegBuilderNodes/Models/FfmpegSubtitleStream.cs
+++ b/VideoNodes/FfmpegBuilderNodes/Models/FfmpegSubtitleStream.cs
@@ -1,72 +1,67 @@
-namespace FileFlows.VideoNodes.FfmpegBuilderNodes.Models
+using FileFlows.VideoNodes.Helpers;
+
+namespace FileFlows.VideoNodes.FfmpegBuilderNodes.Models;
+
+public class FfmpegSubtitleStream : FfmpegStream
{
- public class FfmpegSubtitleStream : FfmpegStream
+ ///
+ /// Gets or sets the source subtitle stream
+ ///
+ public SubtitleStream Stream { get; set; }
+
+ ///
+ /// Gets or sets if this stream has changed
+ ///
+ public override bool HasChange => false;
+
+ ///
+ /// Gets the parameters for this stream
+ ///
+ /// the arguments
+ /// the parameters to pass to FFmpeg for this stream
+ public override string[] GetParameters(GetParametersArgs args)
{
- public SubtitleStream Stream { get; set; }
+ if (Deleted)
+ return new string[] { };
- public override bool HasChange => false;
-
- public override string[] GetParameters(GetParametersArgs args)
+ bool containerSame =
+ string.Equals(args.SourceExtension, args.DestinationExtension, StringComparison.InvariantCultureIgnoreCase);
+
+ string destCodec;
+ if(containerSame)
+ destCodec = "copy";
+ else
{
- if (Deleted)
+ destCodec = SubtitleHelper.GetSubtitleCodec(args.DestinationExtension, Stream.Codec);
+ if (string.IsNullOrEmpty(destCodec))
+ {
+ // this subtitle is not supported by the new container, remove it.
+ args.Logger?.WLog($"Subtitle stream is not supported in destination container, removing: {Stream.Codec} {Stream.Title ?? string.Empty}");
return new string[] { };
-
- List results= new List { "-map", Stream.InputFileIndex + ":s:{sourceTypeIndex}", "-c:s:{index}" };
-
- switch (args.DestinationExtension)
- {
- case "mkv":
- {
- if(Stream.Codec == "mov_text")
- results.Add("srt");
- else
- results.Add("copy");
- }
- break;
- case "mp4":
- {
- if (Helpers.SubtitleHelper.IsImageSubtitle(Stream.Codec))
- {
- results.Add("copy");
- }
- else
- {
- results.Add("mov_text");
- }
- }
- break;
- default:
- {
- results.Add("copy");
- }
- break;
}
-
-
- if (string.IsNullOrWhiteSpace(this.Title) == false)
- {
- // first s: means stream speicific, this is suppose to have :s:s
- // https://stackoverflow.com/a/21059838
- results.Add($"-metadata:s:s:{args.OutputTypeIndex}");
- results.Add($"title={(this.Title == FfmpegStream.REMOVED ? "" : this.Title)}");
- }
- if (string.IsNullOrWhiteSpace(this.Language) == false)
- {
- results.Add($"-metadata:s:s:{args.OutputTypeIndex}");
- results.Add($"language={(this.Language == FfmpegStream.REMOVED ? "" : this.Language)}");
- }
-
- if (Metadata.Any())
- {
- results.AddRange(Metadata.Select(x => x.Replace("{index}", args.OutputTypeIndex.ToString())));
- }
-
- if (args.UpdateDefaultFlag)
- {
- results.AddRange(new[] { "-disposition:a:" + args.OutputTypeIndex, this.IsDefault ? "default" : "0" });
- }
-
- return results.ToArray();
}
+
+ List results= new List { "-map", Stream.InputFileIndex + ":s:{sourceTypeIndex}", "-c:s:{index}", destCodec };
+
+ if (string.IsNullOrWhiteSpace(this.Title) == false)
+ {
+ // first s: means stream specific, this is suppose to have :s:s
+ // https://stackoverflow.com/a/21059838
+ results.Add($"-metadata:s:s:{args.OutputTypeIndex}");
+ results.Add($"title={(this.Title == FfmpegStream.REMOVED ? "" : this.Title)}");
+ }
+ if (string.IsNullOrWhiteSpace(this.Language) == false)
+ {
+ results.Add($"-metadata:s:s:{args.OutputTypeIndex}");
+ results.Add($"language={(this.Language == FfmpegStream.REMOVED ? "" : this.Language)}");
+ }
+
+ if (Metadata.Any())
+ results.AddRange(Metadata.Select(x => x.Replace("{index}", args.OutputTypeIndex.ToString())));
+
+ if (args.UpdateDefaultFlag)
+ results.AddRange(new[] { "-disposition:a:" + args.OutputTypeIndex, this.IsDefault ? "default" : "0" });
+
+ return results.ToArray();
}
-}
+}
\ No newline at end of file
diff --git a/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderRemoveUnsupportedSubtitles.cs b/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderRemoveUnsupportedSubtitles.cs
new file mode 100644
index 00000000..b05e41d1
--- /dev/null
+++ b/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderRemoveUnsupportedSubtitles.cs
@@ -0,0 +1,86 @@
+// namespace FileFlows.VideoNodes.FfmpegBuilderNodes;
+//
+// public class FfmpegBuilderRemoveUnsupportedSubtitles : FfmpegBuilderNode
+// {
+// public override string Icon => "fas fa-comment";
+//
+// public override int Outputs => 2;
+//
+// public readonly string[] Mp4Subtitles = new[]
+// {
+// "ass", // Advanced SubStation Alpha
+// "aqtitle", // AQTitle
+// "cap", // Cheetah CAP
+// "dcin", // D-Cinema subtitles
+// "dvb_subtitle", // DVB Teletext
+// "dvd_subtitle", // DVD subtitle
+// "es", // Enhanced Subtitle
+// "fabsubtitler", // FAB Subtitler
+// "fcpxml", // Final Cut Pro X
+// "jacosub", // JACOsub subtitle
+// "microdvd", // MicroDVD subtitle
+// "mpl2", // MPL2 subtitle
+// "mpsub", // MPlayer subtitle
+// "bin", // Opaque binary subtitle (internal)
+// "pjs", // PJS (Phoenix Japanimation Society) subtitle
+// "realtext", // RealText subtitle format
+// "sami", // SAMI subtitle format
+// "srt", // SubRip subtitle
+// "ssa", // SubStation Alpha subtitle
+// "subviewer", // SubViewer 1.0 subtitle
+// "subviewer1", // SubViewer 2.0 subtitle
+// "teletext", // Teletext subtitle
+// "ttml", // Timed Text Markup Language
+// "ttxt", // TurboTitler subtitle
+// "webvtt", // WebVTT subtitle
+// "zerog" // ZeroG subtitle
+// };
+//
+// public readonly string[] MkvSubtitles = new[]
+// {
+// "ass", // Advanced SubStation Alpha
+// "ssa", // SubStation Alpha subtitle
+// "srt", // SubRip subtitle
+// "subrip", // SubRip subtitle (alternative name)
+// "vtt", // WebVTT subtitle
+// "webvtt", // WebVTT subtitle (alternative name)
+// "smi", // SAMI subtitle format
+// "sami", // SAMI subtitle format (alternative name)
+// "rt", // RealText subtitle format
+// "realtext", // RealText subtitle format (alternative name)
+// "stl", // EBU STL (Subtitling Data Exchange Format)
+// "ttml", // Timed Text Markup Language
+// "ttml_legacy" // Timed Text Markup Language (legacy name)
+// };
+//
+// public readonly string[] WebMSubtitles = new[]
+// {
+// "ass", // Advanced SubStation Alpha
+// "ssa", // SubStation Alpha subtitle
+// "srt", // SubRip subtitle
+// "subrip", // SubRip subtitle (alternative name)
+// "vtt", // WebVTT subtitle
+// "webvtt", // WebVTT subtitle (alternative name)
+// "ttml", // Timed Text Markup Language
+// "ttml_legacy" // Timed Text Markup Language (legacy name)
+// };
+//
+//
+//
+//
+// public override int Execute(NodeParameters args)
+// {
+// this.Init(args);
+// bool removing = false;
+// string[] unsupported = new[] { "" };
+// foreach (var stream in Model.SubtitleStreams)
+// {
+// if (unsupported.Contains(stream.Stream.Codec?.ToLower()))
+// {
+// stream.Deleted = true;
+// removing = true;
+// }
+// }
+// return removing ? 1 : 2;
+// }
+// }
diff --git a/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderUnsupportedMP4Subtitles.cs b/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderUnsupportedMP4Subtitles.cs
deleted file mode 100644
index dbcf75b6..00000000
--- a/VideoNodes/FfmpegBuilderNodes/Subtitle/FfmpegBuilderUnsupportedMP4Subtitles.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-//namespace FileFlows.VideoNodes.FfmpegBuilderNodes
-//{
-// public class FfmpegBuilderUnsupportedMP4Subtitles : FfmpegBuilderNode
-// {
-// public override string Icon => "fas fa-comment";
-
-// public override int Outputs => 2;
-
-// public override int Execute(NodeParameters args)
-// {
-// this.Init(args);
-// bool removing = false;
-// string[] unsupported = new[] { "" };
-// foreach (var stream in Model.SubtitleStreams)
-// {
-// if (unsupported.Contains(stream.Stream.Codec?.ToLower()))
-// {
-// stream.Deleted = true;
-// removing = true;
-// }
-// }
-// return removing ? 1 : 2;
-// }
-// }
-//}
diff --git a/VideoNodes/Helpers/SubtitleHelper.cs b/VideoNodes/Helpers/SubtitleHelper.cs
index 32b219ce..c3f6699e 100644
--- a/VideoNodes/Helpers/SubtitleHelper.cs
+++ b/VideoNodes/Helpers/SubtitleHelper.cs
@@ -1,21 +1,83 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace FileFlows.VideoNodes.Helpers;
+namespace FileFlows.VideoNodes.Helpers;
///
/// Helper for Subtitles
///
internal class SubtitleHelper
{
+
+ public static readonly string[] MkvSubtitles = new[]
+ {
+ "ass", // Advanced SubStation Alpha
+ "ssa", // SubStation Alpha subtitle
+ "srt", // SubRip subtitle
+ "subrip", // SubRip subtitle (alternative name)
+ "vtt", // WebVTT subtitle
+ "webvtt", // WebVTT subtitle (alternative name)
+ "smi", // SAMI subtitle format
+ "sami", // SAMI subtitle format (alternative name)
+ "rt", // RealText subtitle format
+ "realtext", // RealText subtitle format (alternative name)
+ "stl", // EBU STL (Subtitling Data Exchange Format)
+ "ttml", // Timed Text Markup Language
+ "ttml_legacy" // Timed Text Markup Language (legacy name)
+ };
+
///
/// Tests if a subtitle is an image based subtitle
///
/// the subtitle codec
/// true if the subtitle is an image based subtitle
internal static bool IsImageSubtitle(string codec)
- => Regex.IsMatch(codec.Replace("_", ""), "dvbsub|dvdsub|pgs|xsub", RegexOptions.IgnoreCase);
+ => Regex.IsMatch(codec.Replace("_", ""), "dvbsub|pgs|xsub|vobsub", RegexOptions.IgnoreCase);
+
+ ///
+ /// Determines the appropriate subtitle codec for conversion based on the container type and current subtitle codec.
+ ///
+ /// The container type (mp4, mkv, webm).
+ /// The current subtitle codec.
+ /// The appropriate subtitle codec for conversion, or null container does not support this codec.
+ public static string? GetSubtitleCodec(string containerType, string currentCodec)
+ {
+ // Check if the current subtitle codec is image-based
+ bool isImageBased = IsImageSubtitle(currentCodec);
+
+ // Determine the appropriate subtitle codec based on the container type and if the current codec is image-based or text-based
+ switch (containerType.ToLower())
+ {
+ case "mp4":
+ if (isImageBased)
+ {
+ // MP4 container does not support image-based subtitles, so conversion is not possible
+ return null;
+ }
+ return "mov_text";
+ case "mkv":
+ if (isImageBased)
+ return "hdmv_pgs_subtitle";
+ if (IsSupportedSubtitleCodecMKV(currentCodec) == false)
+ return "srt"; // or "ssa" or any other supported codec
+ return currentCodec;
+ case "webm":
+ if (isImageBased)
+ {
+ // WebM container does not support image-based subtitles, so conversion is not possible
+ return null;
+ }
+ // WebM container supports text-based subtitles in the webvtt codec
+ return "webvtt";
+ default:
+ // Invalid or unsupported container type
+ return null;
+ }
+ }
+
+ ///
+ /// Checks if the subtitle codec is supported in MKV container.
+ ///
+ /// The subtitle codec to check.
+ /// True if the codec is supported in MKV, False otherwise.
+ private static bool IsSupportedSubtitleCodecMKV(string codec)
+ => Array.IndexOf(MkvSubtitles, codec.ToLower()) >= 0;
+
}