From e6e07fc2fe0e5c480d31e211f4048818781a909c Mon Sep 17 00:00:00 2001 From: alex6dj Date: Fri, 1 Oct 2021 23:34:56 -0400 Subject: [PATCH 1/3] Fixed error when burning subtitle with some special charaters in path --- FFMpegCore.Test/ArgumentBuilderTest.cs | 17 +++++- FFMpegCore/Extend/StringExtensions.cs | 57 ++++++++++++++++++- .../Arguments/SubtitleHardBurnArgument.cs | 2 +- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/FFMpegCore.Test/ArgumentBuilderTest.cs b/FFMpegCore.Test/ArgumentBuilderTest.cs index 082d9bf..5f2ce5c 100644 --- a/FFMpegCore.Test/ArgumentBuilderTest.cs +++ b/FFMpegCore.Test/ArgumentBuilderTest.cs @@ -341,7 +341,22 @@ public void Builder_BuildString_SubtitleHardBurnFilter() .WithParameter("PrimaryColour", "&HAA00FF00"))))) .Arguments; - Assert.AreEqual("-i \"input.mp4\" -vf \"subtitles=sample.srt:charenc=UTF-8:original_size=1366x768:stream_index=0:force_style='FontName=DejaVu Serif\\,PrimaryColour=&HAA00FF00'\" \"output.mp4\"", + Assert.AreEqual("-i \"input.mp4\" -vf \"subtitles='sample.srt':charenc=UTF-8:original_size=1366x768:stream_index=0:force_style='FontName=DejaVu Serif\\,PrimaryColour=&HAA00FF00'\" \"output.mp4\"", + str); + } + + [TestMethod] + public void Builder_BuildString_SubtitleHardBurnFilterFixedPaths() + { + var str = FFMpegArguments + .FromFileInput("input.mp4") + .OutputToFile("output.mp4", false, opt => opt + .WithVideoFilters(filterOptions => filterOptions + .HardBurnSubtitle(SubtitleHardBurnOptions + .Create(subtitlePath: @"sample( \ : [ ] , ).srt")))) + .Arguments; + + Assert.AreEqual(@"-i ""input.mp4"" -vf ""subtitles='sample( \\ \: \[ \] \, ).srt'"" ""output.mp4""", str); } diff --git a/FFMpegCore/Extend/StringExtensions.cs b/FFMpegCore/Extend/StringExtensions.cs index ddcf54b..7afcc34 100644 --- a/FFMpegCore/Extend/StringExtensions.cs +++ b/FFMpegCore/Extend/StringExtensions.cs @@ -1,7 +1,19 @@ -namespace FFMpegCore.Extend +using System.Collections.Generic; +using System.Text; + +namespace FFMpegCore.Extend { internal static class StringExtensions { + private static Dictionary CharactersSubstitution { get; } = new Dictionary + { + {'\\', @"\\"}, + {':', @"\:"}, + {'[', @"\["}, + {']', @"\]"}, + // {'\'', @"\'"} TODO: Quotes need to be escaped but i failed miserably + }; + /// /// Enclose string between quotes if contains an space character /// @@ -11,5 +23,48 @@ public static string EncloseIfContainsSpace(this string input) { return input.Contains(" ") ? $"'{input}'" : input; } + + /// + /// Enclose an string in quotes + /// + /// + /// + public static string EncloseInQuotes(this string input) + { + return $"'{input}'"; + } + + /// + /// Scape several characters in subtitle path used by FFmpeg + /// + /// + /// This is needed because internally FFmpeg use Libav Filters + /// and the info send to it must be in an specific format + /// + /// + /// Scaped path + public static string ToFFmpegLibavfilterPath(this string source) + { + return source.Replace(CharactersSubstitution); + } + + public static string Replace(this string str, Dictionary replaceList) + { + var parsedString = new StringBuilder(); + + foreach (var l in str) + { + if (replaceList.ContainsKey(l)) + { + parsedString.Append(replaceList[l]); + } + else + { + parsedString.Append(l); + } + } + + return parsedString.ToString(); + } } } \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Arguments/SubtitleHardBurnArgument.cs b/FFMpegCore/FFMpeg/Arguments/SubtitleHardBurnArgument.cs index a48f845..d7ec3aa 100644 --- a/FFMpegCore/FFMpeg/Arguments/SubtitleHardBurnArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/SubtitleHardBurnArgument.cs @@ -103,7 +103,7 @@ public SubtitleHardBurnOptions WithParameter(string key, string value) return this; } - internal string TextInternal => string.Join(":", new[] { _subtitle.EncloseIfContainsSpace() }.Concat(Parameters.Select(parameter => parameter.FormatArgumentPair(enclose: true)))); + internal string TextInternal => string.Join(":", new[] { _subtitle.ToFFmpegLibavfilterPath().EncloseInQuotes() }.Concat(Parameters.Select(parameter => parameter.FormatArgumentPair(enclose: true)))); } public class StyleOptions From 975bd75c5de76f5ae0dea8c468f216d38d02f5be Mon Sep 17 00:00:00 2001 From: alex6dj Date: Sun, 3 Oct 2021 11:07:15 -0400 Subject: [PATCH 2/3] Fixed single quotes escape in subtitle file path --- FFMpegCore.Test/ArgumentBuilderTest.cs | 4 ++-- FFMpegCore/Extend/StringExtensions.cs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/FFMpegCore.Test/ArgumentBuilderTest.cs b/FFMpegCore.Test/ArgumentBuilderTest.cs index 5f2ce5c..9a358ae 100644 --- a/FFMpegCore.Test/ArgumentBuilderTest.cs +++ b/FFMpegCore.Test/ArgumentBuilderTest.cs @@ -353,10 +353,10 @@ public void Builder_BuildString_SubtitleHardBurnFilterFixedPaths() .OutputToFile("output.mp4", false, opt => opt .WithVideoFilters(filterOptions => filterOptions .HardBurnSubtitle(SubtitleHardBurnOptions - .Create(subtitlePath: @"sample( \ : [ ] , ).srt")))) + .Create(subtitlePath: @"sample( \ : [ ] , ' ).srt")))) .Arguments; - Assert.AreEqual(@"-i ""input.mp4"" -vf ""subtitles='sample( \\ \: \[ \] \, ).srt'"" ""output.mp4""", + Assert.AreEqual(@"-i ""input.mp4"" -vf ""subtitles='sample( \\ \: \[ \] \, '\\\'' ).srt'"" ""output.mp4""", str); } diff --git a/FFMpegCore/Extend/StringExtensions.cs b/FFMpegCore/Extend/StringExtensions.cs index 7afcc34..2c33681 100644 --- a/FFMpegCore/Extend/StringExtensions.cs +++ b/FFMpegCore/Extend/StringExtensions.cs @@ -7,11 +7,11 @@ internal static class StringExtensions { private static Dictionary CharactersSubstitution { get; } = new Dictionary { - {'\\', @"\\"}, - {':', @"\:"}, - {'[', @"\["}, - {']', @"\]"}, - // {'\'', @"\'"} TODO: Quotes need to be escaped but i failed miserably + { '\\', @"\\" }, + { ':', @"\:" }, + { '[', @"\[" }, + { ']', @"\]" }, + { '\'', @"'\\\''" } }; /// From 1b67ea76f0b9fef26fbb9cb22c42b693c8d81d6d Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 21 Oct 2021 19:43:13 +0200 Subject: [PATCH 3/3] Minor fixes --- FFMpegCore/Extend/KeyValuePairExtensions.cs | 2 +- FFMpegCore/Extend/StringExtensions.cs | 6 +++--- FFMpegCore/FFMpeg/Arguments/SubtitleHardBurnArgument.cs | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/FFMpegCore/Extend/KeyValuePairExtensions.cs b/FFMpegCore/Extend/KeyValuePairExtensions.cs index 28cc087..c2c6813 100644 --- a/FFMpegCore/Extend/KeyValuePairExtensions.cs +++ b/FFMpegCore/Extend/KeyValuePairExtensions.cs @@ -16,7 +16,7 @@ internal static class KeyValuePairExtensions public static string FormatArgumentPair(this KeyValuePair pair, bool enclose) { var key = pair.Key; - var value = enclose ? pair.Value.EncloseIfContainsSpace() : pair.Value; + var value = enclose ? StringExtensions.EncloseIfContainsSpace(pair.Value) : pair.Value; return $"{key}={value}"; } diff --git a/FFMpegCore/Extend/StringExtensions.cs b/FFMpegCore/Extend/StringExtensions.cs index 2c33681..29c8d42 100644 --- a/FFMpegCore/Extend/StringExtensions.cs +++ b/FFMpegCore/Extend/StringExtensions.cs @@ -19,7 +19,7 @@ internal static class StringExtensions /// /// The input /// The enclosed string - public static string EncloseIfContainsSpace(this string input) + public static string EncloseIfContainsSpace(string input) { return input.Contains(" ") ? $"'{input}'" : input; } @@ -29,7 +29,7 @@ public static string EncloseIfContainsSpace(this string input) /// /// /// - public static string EncloseInQuotes(this string input) + public static string EncloseInQuotes(string input) { return $"'{input}'"; } @@ -43,7 +43,7 @@ public static string EncloseInQuotes(this string input) /// /// /// Scaped path - public static string ToFFmpegLibavfilterPath(this string source) + public static string ToFFmpegLibavfilterPath(string source) { return source.Replace(CharactersSubstitution); } diff --git a/FFMpegCore/FFMpeg/Arguments/SubtitleHardBurnArgument.cs b/FFMpegCore/FFMpeg/Arguments/SubtitleHardBurnArgument.cs index d7ec3aa..2acd7ca 100644 --- a/FFMpegCore/FFMpeg/Arguments/SubtitleHardBurnArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/SubtitleHardBurnArgument.cs @@ -103,7 +103,9 @@ public SubtitleHardBurnOptions WithParameter(string key, string value) return this; } - internal string TextInternal => string.Join(":", new[] { _subtitle.ToFFmpegLibavfilterPath().EncloseInQuotes() }.Concat(Parameters.Select(parameter => parameter.FormatArgumentPair(enclose: true)))); + internal string TextInternal => string + .Join(":", new[] { StringExtensions.EncloseInQuotes(StringExtensions.ToFFmpegLibavfilterPath(_subtitle)) } + .Concat(Parameters.Select(parameter => parameter.FormatArgumentPair(enclose: true)))); } public class StyleOptions