Either my home media server or the media server client on my TV have a problem with MKV videos. Sometimes I cannot fast forward, sometimes it doesn't know the length of the video or the current position. I am not sure where the problem lies, but I know it has none of these problems with MP4 videos. Since both MKV and MP4 are basically containers for video and audio streams, I wanted to use FFmpeg to do the conversion.
I didn't want to have to either keep typing in long command-lines or start creating batch files for each type of conversion, so I wrote a C Sharp front-end for my conversions with FFmpeg. I wanted my app to call the FFmpeg program and monitor/parse the output. Here is the full function call. Note: the FFmpeg executable is currently hard coded in this version of the app, but I will be fixing that soon.
using System.Diagnostics;
private void RunConversion(string args)
{
int pos, progress;
string line;
Process p = new Process();
p.StartInfo.FileName = @"c:\Program Files\ffmpeg\bin\ffmpeg.exe";
p.StartInfo.Arguments = args;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.Start();
//FFmpeg puts its output through standard error, not standard out, for some reason
while ((line = p.StandardError.ReadLine()) != null)
{
//read and process each output, line by line
line = line.Trim();
//lines that start with frame= has a time stamp so we can calculate progress
//frame=31210...
if (line.Substring(0, 6) == "frame=")
{
//this is a progress line
pos = line.IndexOf("time=");
if (pos > -1)
{
//found a "time=00:21:41.63" entry, so update progress
progress = HMStoSeconds(line.Substring(pos + 5, 8));
progbarConvert.Value = progress;
}
}
}
progbarConvert.Value = progbarConvert.Maximum;
p.WaitForExit();
//dispose
p.Dispose();
}
Setting up to run a new process involves the following.
Process p = new Process();
p.StartInfo.FileName = @"c:\Program Files\ffmpeg\bin\ffmpeg.exe";
p.StartInfo.Arguments = args;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.Start();
FileName
sets the executable and Arguments
are passed in. To disable the standard Windows command line output you need to set UseShellExecute
to false and CreateNoWindow
to true. To capture the output text you need to set both RedirectStandardOutput
and RedirectStandardError
to true. In this case FFmpeg puts all of its output through Standard Errror rather than Standard Out like most apps.
The basic output processing loop is as follows:
p.Start();
while ((line = p.StandardError.ReadLine()) != null)
{
//processing code here
}
p.WaitForExit();
p.Dispose();
Start()
runs the executable and the while loop reads any output from Standard Error, in this case. Once there is no more output, it will fall out of the loop. WaitForExit()
lets the executable shut down and then we dispose of the process object that was created.
While this handled the the running of FFmpeg, I did start running into situations where the UI became unresponsive and even whited out when the FFmpeg command was running. In another blog post, I will show how I added threading to solve this problem.