Skip to content

Instantly share code, notes, and snippets.

@BYJRK
Last active January 19, 2023 09:47
Show Gist options
  • Save BYJRK/78c9323b83b12d0e477bd52912eb9f79 to your computer and use it in GitHub Desktop.
Save BYJRK/78c9323b83b12d0e477bd52912eb9f79 to your computer and use it in GitHub Desktop.
#region GUI
var ffmpeg = new FFmpeg();
ffmpeg.UI.Dump();
#endregion
class FFmpeg
{
TimeSpan duration;
public FFmpeg()
{
inputFilePath.TextInput += (_, _) =>
{
outputFileName.Text = Path.GetFileName(inputFilePath.Text);
};
btn.Click += async (_, _) =>
{
var args = new List<string>();
args.Add("-i");
args.Add(Path.GetFileName(inputFilePath.Text));
args = args.Concat(Arguments).ToList();
args.Add(outputFileName.Text);
await Cli
.Wrap("ffmpeg")
.WithWorkingDirectory(Path.GetDirectoryName(inputFilePath.Text))
.WithArguments(args, true)
.WithStandardErrorPipe(PipeTarget.ToDelegate(HandleOutput))
.ExecuteAsync();
Util.Progress = 100;
};
}
#region Controls
private FilePicker inputFilePath = new();
private TextBox outputFileName = new();
private Button btn = new(" Run ");
private TextBox bitRate = new();
private TextBox resolution = new();
private TextBox frameRate = new();
private TextBox crf = new TextBox();
private SelectBox vcodec = new(new[] { "libx264", "libx265", "libxvid", "vp9", }, 0);
public Control UI => new StackPanel(
false,
new StackPanel
(
false,
new Span("Input"), inputFilePath,
new Span("Output"), new Div(outputFileName, btn),
new FieldSet
(
"Options",
new StackPanel
(
false,
new Span("Bit Rate (e.g. 2M, 500k, etc.)"), bitRate,
new Span("Resolution (e.g. 1920x1080)"), resolution,
new Span("Frame Rate (e.g. 30, 60, etc.)"), frameRate,
new Span("Constant Rate Factor (0~51, default: 23)"), crf,
new Span("Video Codec"), vcodec
)
)
)
);
#endregion
public List<string> Arguments
{
get
{
var args = new List<string>();
void AddIfNotEmpty(string text, string arg)
{
if (string.IsNullOrWhiteSpace(text))
return;
args.Add(arg);
args.Add(text);
}
AddIfNotEmpty(bitRate.Text, "-b");
AddIfNotEmpty(frameRate.Text, "-r");
AddIfNotEmpty(resolution.Text, "-s");
AddIfNotEmpty(crf.Text, "-crf");
args.Add("-vcodec");
args.Add(vcodec.SelectedOption.ToString()!);
return args;
}
}
private void HandleOutput(string line)
{
var durationMatch = Regex.Match(line, @"Duration: (\d+:\d+:\d+\.\d+)");
if (durationMatch.Success)
{
duration = TimeSpan.Parse(durationMatch.Groups[1].Value);
Util.Progress = 0;
return;
}
var timeMatch = Regex.Match(line, @"time=(\d+:\d+:\d+\.\d+)");
if (timeMatch.Success)
{
var current = TimeSpan.Parse(timeMatch.Groups[1].Value);
var percent = current.TotalSeconds / duration.TotalSeconds;
Util.Progress = (int)(percent * 100);
return;
}
}
}
#region GUI
var inputFilePath = new FilePicker().Dump("Input");
var outputFileName = new TextBox().Dump("Output");
var bitRate = new TextBox().Dump("Bit Rate");
var resolution = new TextBox().Dump("Resolution");
var frameRate = new TextBox().Dump("Frame Rate");
var button = new Button("Run").Dump();
Util.ProgressBar bar = null;
#endregion
TimeSpan duration = default;
button.Click += async (_, _) =>
{
var args = new List<string>();
args.Add("-i");
args.Add(Path.GetFileName(inputFilePath.Text));
if (!string.IsNullOrWhiteSpace(bitRate.Text))
{
args.Add("-b");
args.Add(bitRate.Text);
}
if (!string.IsNullOrWhiteSpace(frameRate.Text))
{
args.Add("-r");
args.Add(frameRate.Text);
}
if (!string.IsNullOrWhiteSpace(resolution.Text))
{
args.Add("-s");
args.Add(resolution.Text);
}
args.Add(outputFileName.Text);
await Cli
.Wrap("ffmpeg")
.WithWorkingDirectory(Path.GetDirectoryName(inputFilePath.Text))
.WithArguments(args, true)
.WithStandardErrorPipe(PipeTarget.ToDelegate(HandleOutput))
.ExecuteAsync();
};
void HandleOutput(string line)
{
var durationMatch = Regex.Match(line, @"Duration: (\d+:\d+:\d+\.\d+)");
if (durationMatch.Success)
{
duration = TimeSpan.Parse(durationMatch.Groups[1].Value);
bar = new Util.ProgressBar { HideWhenCompleted = true }.Dump();
return;
}
var timeMatch = Regex.Match(line, @"time=(\d+:\d+:\d+\.\d+)");
if (timeMatch.Success)
{
var current = TimeSpan.Parse(timeMatch.Groups[1].Value);
var percent = current.TotalSeconds / duration.TotalSeconds;
bar.Fraction = percent;
bar.Caption = $"{percent * 100:F0}%";
return;
}
if (line.Contains("final ratefactor"))
bar.Fraction = 1.0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment