Skip to content

Commit

Permalink
Linux related fixes
Browse files Browse the repository at this point in the history
-Linux: fetching now additionally the StdErr output (FFmpeg is not using StdOut)
-Linux: FFmpeg path auto generation now without file extension
-Linux: fixed not found input files when using relative paths like ./
-FFmpeg version is now shown in info header
-Refactoring
  • Loading branch information
feuster committed Apr 22, 2023
1 parent ca21c98 commit eef3da7
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 19 deletions.
3 changes: 2 additions & 1 deletion FFchapters2/FFchapters2.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<Description>FFchapters2 is a FFmpeg based video chapter generation tool</Description>
<Copyright>© Alexander Feuster 2023</Copyright>
<PackageTags>FFchapter2, ffmpeg, chapter, chapters, metainfo, MKV, Matroska</PackageTags>
<NeutralLanguage>en</NeutralLanguage>
<NeutralLanguage>en-001</NeutralLanguage>
<PackageLicenseExpression>GPL-2.0-only</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<Authors>Alexander Feuster</Authors>
Expand All @@ -26,6 +26,7 @@
<DefineConstants Condition="'$(RuntimeIdentifier)' == 'win-x64'">$(DefineConstants);WINDOWS</DefineConstants>
<DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-x86'">$(DefineConstants);LINUX</DefineConstants>
<DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-x64'">$(DefineConstants);LINUX</DefineConstants>
<Version>$(AssemblyVersion)</Version>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net6.0' ">
Expand Down
1 change: 1 addition & 0 deletions FFchapters2/FFchapters2.csproj.user
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<PropertyGroup>
<_LastSelectedProfileId>C:\Sourcecodes\FFchapters2\FFchapters2\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
<ActiveDebugProfile>FFchapters2</ActiveDebugProfile>
<ActiveDebugFramework>net7.0</ActiveDebugFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
Expand Down
131 changes: 113 additions & 18 deletions FFchapters2/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#region using
using CommandLine;
using Spectre.Console;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
Expand All @@ -25,7 +26,7 @@
string ChapterFile = "";
string InputFile = "";
string FFmpeg = "";
string TempFile = "";
string FFmpegVersion = "";
string MetaFile = "";
string AppVersion = $"[green]Version: {"V" + Assembly.GetEntryAssembly().GetName().Version.Major.ToString() + "." + Assembly.GetEntryAssembly().GetName().Version.MinorRevision.ToString()}[/]";
string? AppName = Assembly.GetEntryAssembly().GetName().Name;
Expand All @@ -35,7 +36,7 @@
bool ChapterStyle2 = false;
bool OSLinux = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Linux);
//GitVersion will be only be actualized/overwritten when using Cake build!
const string GitVersion = "git-e3313f9";
const string GitVersion = "git-ca21c98";
#endregion

#region Title
Expand Down Expand Up @@ -69,6 +70,7 @@
Parser.Default.ParseArguments<Options>(args)
.WithParsed<Options>(o =>
{
//FFmpeg options
if (o.FFmpeg != "")
{
if (File.Exists(o.FFmpeg))
Expand All @@ -85,20 +87,39 @@
if (buffer == null)
{
AnsiConsole.MarkupLine($"[yellow]FFmpeg path: \"{ShortString(o.FFmpeg, ShortStringMaxLength)}\" not found[/]");
if (OSLinux)
FFmpeg = "/usr/bin/ffmpeg";
else
FFmpeg = "ffmpeg.exe";
if (OSLinux)
FFmpeg = "/usr/bin/ffmpeg";
else
FFmpeg = "ffmpeg.exe";
AnsiConsole.MarkupLine($"[green]FFmpeg path: \"{ShortString(FFmpeg, ShortStringMaxLength)}\" (Default Fallback)[/]");
}
else
{
FFmpeg = buffer + "\\ffmpeg.exe";
if (OSLinux)
FFmpeg = buffer + "\\ffmpeg.exe";
else
FFmpeg = buffer + "\\ffmpeg.exe";
AnsiConsole.MarkupLine($"[green]FFmpeg path: \"{ShortString(FFmpeg, ShortStringMaxLength)}\" (in Environment Path)[/]");
}
}
}
//FFmpeg not found abort
if (!File.Exists(FFmpeg))
{
AnsiConsole.MarkupLine($"[red]FFmpeg not found! Abort chapter creation![/]");
AnyKey();
Environment.Exit(-1);
}
//FFmpeg version
FFmpegVersion = GetFFmpegVersion();
if (FFmpegVersion != string.Empty)
AnsiConsole.MarkupLine($"[green]FFmpeg version: {FFmpegVersion}[/]");
else
AnsiConsole.MarkupLine($"[yellow]FFmpeg version: unknown[/]");
//Input file option
if (o.InputFile != "")
{
if (File.Exists(o.InputFile))
Expand Down Expand Up @@ -147,6 +168,7 @@
}
}
//Chapter options
if (o.IgnoreExistingChapters)
{
IgnoreExistingChapters = o.IgnoreExistingChapters;
Expand Down Expand Up @@ -320,36 +342,48 @@
.AutoRefresh(false)
.Start("[green]FFmpeg running[/]", ctx =>
{
TempFile = Path.ChangeExtension(ChapterFile, ".tmp");
try
{
if (File.Exists(TempFile))
File.Delete(TempFile);
Process RunProcess = new Process();
RunProcess.StartInfo.FileName = "cmd.exe";
RunProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(FFmpeg);
RunProcess.StartInfo.Arguments = $"/c {@FFmpeg} -hide_banner -i \"{@InputFile}\" -vf blackdetect=d=1.0:pic_th=0.90:pix_th=0.00,blackframe=98:32,\"select='gt(scene,0.10)',showinfo\" -an -f null - 2>&1"; // > \"{@TempFile}\"";
if (OSLinux)
{
RunProcess.StartInfo.FileName = $"{@FFmpeg}";
RunProcess.StartInfo.Arguments = $"-hide_banner -i \"{@InputFile}\" -vf blackdetect=d=1.0:pic_th=0.90:pix_th=0.00,blackframe=98:32,\"select='gt(scene,0.10)',showinfo\" -an -f null -";
}
else
{
RunProcess.StartInfo.FileName = "cmd.exe";
RunProcess.StartInfo.Arguments = $"/c {@FFmpeg} -hide_banner -i \"{@InputFile}\" -vf blackdetect=d=1.0:pic_th=0.90:pix_th=0.00,blackframe=98:32,\"select='gt(scene,0.10)',showinfo\" -an -f null - 2>&1";
}
RunProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(@InputFile);
RunProcess.StartInfo.UseShellExecute = false;
RunProcess.StartInfo.RedirectStandardOutput = true;
RunProcess.StartInfo.RedirectStandardError = true;
RunProcess.StartInfo.RedirectStandardInput = false;
RunProcess.StartInfo.Verb = "";
RunProcess.EnableRaisingEvents = true;
RunProcess.StartInfo.CreateNoWindow = true;
RunProcess.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
//Optional preparation in case environment variables might be used in the future. Uncomment next line if needed.
//RunProcess.StartInfo.EnvironmentVariables["FFREPORT"] = $"file='{TempFile}':level=32";
void DataReadHandler(object sender, DataReceivedEventArgs e)
{
if (!String.IsNullOrEmpty(e.Data))
{
ScenesRaw.Add(e.Data);
}
});
}
RunProcess.ErrorDataReceived += DataReadHandler;
RunProcess.OutputDataReceived += DataReadHandler;
var Start = DateTime.Now;
AnsiConsole.MarkupLine("[Green]Start: " + Start.ToLongTimeString() + "[/]");
RunProcess.Start();
RunProcess.BeginOutputReadLine();
RunProcess.BeginErrorReadLine();
while (!RunProcess.HasExited)
{
ctx.Refresh();
}
var Stop = DateTime.Now;
AnsiConsole.MarkupLine("[Green]Stop: " + Stop.ToLongTimeString() + "[/]");
AnsiConsole.MarkupLine("[Green]Time: " + (Stop - Start).ToString(@"hh\:mm\:ss") + "[/]");
Expand All @@ -362,6 +396,7 @@
Environment.Exit(-1);
}
});

if (ScenesRaw.Count == 0)
{
AnsiConsole.MarkupLine($"[red]FFmpeg could not create raw scenes![/]");
Expand Down Expand Up @@ -691,6 +726,8 @@
#endregion

#region Functions & Classes

#region AnyKey
void AnyKey()
{
if (!Close)
Expand All @@ -700,7 +737,9 @@ void AnyKey()
Console.ReadKey();
}
}
#endregion

#region ShortString
string ShortString(string Text, int MaxLength)
{
if (Text.Length < 6 || MaxLength > Text.Length)
Expand All @@ -715,20 +754,74 @@ string ShortString(string Text, int MaxLength)
Part2 = Text.Substring(Text.Length - PartLength);
return Part1 + "..." + Part2;
}
#endregion

#region Read ffmpeg version
string GetFFmpegVersion()
{
try
{
buffer = string.Empty;
Process RunProcess = new Process();
if (OSLinux)
{
RunProcess.StartInfo.FileName = $"{@FFmpeg}";
RunProcess.StartInfo.Arguments = $"-version";
}
else
{
RunProcess.StartInfo.FileName = "cmd.exe";
RunProcess.StartInfo.Arguments = $"/c {@FFmpeg} -version 2>&1";
}
RunProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(@FFmpeg);
RunProcess.StartInfo.UseShellExecute = false;
RunProcess.StartInfo.RedirectStandardOutput = true;
RunProcess.StartInfo.RedirectStandardError = true;
RunProcess.StartInfo.RedirectStandardInput = false;
RunProcess.StartInfo.Verb = "";
RunProcess.EnableRaisingEvents = true;
RunProcess.StartInfo.CreateNoWindow = true;

void DataReadHandler(object sender, DataReceivedEventArgs e)
{
if (!String.IsNullOrEmpty(e.Data))
{
buffer += e.Data;
}
}
RunProcess.ErrorDataReceived += DataReadHandler;
RunProcess.OutputDataReceived += DataReadHandler;

RunProcess.Start();
RunProcess.BeginOutputReadLine();
RunProcess.BeginErrorReadLine();
RunProcess.WaitForExit();
return Regex.Match(buffer, @"[\d][\.][\d\.]*(?=-)").Value.Trim();
}
catch (Exception e)
{
AnsiConsole.MarkupLine("[White on Red]Exception: " + e.Message + "[/]");
return string.Empty;
}
}
#endregion

#region Options
public class Options
{
public Options() { }

[Value(0)]
public IEnumerable<string> Props { get; set; } = new List<string>();

#if LINUX
[Option('f', "ffmpeg", Default = "/usr/local/bin/ffmpeg", Required = false, HelpText = "Set path to FFmpeg")]
public string FFmpeg { get; set; } = "/usr/local/bin/ffmpeg";
#else
[Option('f', "ffmpeg", Default = "ffmpeg.exe", Required = false, HelpText = "Set path to FFmpeg.exe")]
public string FFmpeg { get; set; } = "ffmpeg.exe";
#endif

[Option('i', "input", Default = "", Required = false, HelpText = "Set path to input video")]
public string InputFile { get; set; } = "";

Expand All @@ -751,4 +844,6 @@ public Options() { }
public string ChapterStyle { get; set; } = "";

}
#endregion

#endregion

0 comments on commit eef3da7

Please sign in to comment.