FFmpeg is a little bit of an adventure to parse. But in any case, here's what you need to know.
First, FFmpeg doesn't play well with RedirectOutput options
What you'll need to do is instead of launching ffmpeg directly, launch cmd.exe
, passing in ffmpeg as an argument, and redirecting the output to a "monitor file" through a command line output like so... note that in the while (!proc.HasExited)
loop you can read this file for real-time FFmpeg status, or just read it at the end if this is a quick operation.
FileInfo monitorFile = new FileInfo(Path.Combine(ffMpegExe.Directory.FullName, "FFMpegMonitor_" + Guid.NewGuid().ToString() + ".txt"));
string ffmpegpath = Environment.SystemDirectory + "\\cmd.exe";
string ffmpegargs = "/C " + ffMpegExe.FullName + " " + encodeArgs + " 2>" + monitorFile.FullName;
string fullTestCmd = ffmpegpath + " " + ffmpegargs;
ProcessStartInfo psi = new ProcessStartInfo(ffmpegpath, ffmpegargs);
psi.WorkingDirectory = ffMpegExe.Directory.FullName;
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
psi.Verb = "runas";
var proc = Process.Start(psi);
while (!proc.HasExited)
{
System.Threading.Thread.Sleep(1000);
}
string encodeLog = System.IO.File.ReadAllText(monitorFile.FullName);
Great, now you've got the log of what FFmpeg just spit out. Now to get the duration. The duration line will look something like this:
Duration: 00:10:53.79, start: 0.000000, bitrate: 9963 kb/s
Clean up the results into a List<string>
:
var encodingLines = encodeLog.Split(System.Environment.NewLine[0]).Where(line => string.IsNullOrWhiteSpace(line) == false && string.IsNullOrEmpty(line.Trim()) == false).Select(s => s.Trim()).ToList();
... then loop through them looking for Duration
.
foreach (var line in encodingLines)
{
// Duration: 00:10:53.79, start: 0.000000, bitrate: 9963 kb/s
if (line.StartsWith("Duration"))
{
var duration = ParseDurationLine(line);
}
}
Here's some code that can do the parse for you:
private TimeSpan ParseDurationLine(string line)
{
var itemsOfData = line.Split(" "[0], "="[0]).Where(s => string.IsNullOrEmpty(s) == false).Select(s => s.Trim().Replace("=", string.Empty).Replace(",", string.Empty)).ToList();
string duration = GetValueFromItemData(itemsOfData, "Duration:");
return TimeSpan.Parse(duration);
}
private string GetValueFromItemData(List<string> items, string targetKey)
{
var key = items.FirstOrDefault(i => i.ToUpper() == targetKey.ToUpper());
if (key == null) { return null; }
var idx = items.IndexOf(key);
var valueIdx = idx + 1;
if (valueIdx >= items.Count)
{
return null;
}
return items[valueIdx];
}