I am trying to convert a video when the user submits a form. It seems to convert ok but the file "is being used by another proccess" when I try to do anything with it. It looks like ffmpeg.exe never exits. My code is below is there anything I should be doing different to allow the process to release the file? If I run this manually it exits fine.
internal class ConversionUtility : Utility
{
public void Convert(string videoFileName)
{
var video = new VideoFile(videoFileName);
if (!video.infoGathered)
GetVideoInfo(video);
var Params = string.Format("-y -i \"{0}\" -coder ac -me_method full -me_range 16 -subq 5 -sc_threshold 40 -vcodec libx264 -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 -i_qfactor 0.71 -keyint_min 25 -b_strategy 1 -g 250 -r 20 \"{1}\"", video.Path, Path.ChangeExtension(videoFileName,".mp4"));
//var Params = string.Format("-y -i \"{0}\" -acodec libfaac -ar 44100 -ab 96k -coder ac -me_method full -me_range 16 -subq 5 -sc_threshold 40 -vcodec libx264 -s 1280x544 -b 1600k -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 -i_qfactor 0.71 -keyint_min 25 -b_strategy 1 -g 250 -r 20 c:\\output3.mp4", video.Path, videoFileName);
//var Params = String.Format(" {0} \"{1}\"",this.FFmpegLocation, video.Path);
var threadStart = new ParameterizedThreadStart(del => RunProcess(Params));
var thread = new Thread(threadStart);
thread.Start();
//RunProcess(Params);
}
}
internal class Utility
{
public string FFmpegLocation { get; set; }
private string WorkingPath { get { return Path.GetDirectoryName(FFmpegLocation); } }
protected string RunProcess(string Parameters)
{
//create a process info
var oInfo = new ProcessStartInfo(this.FFmpegLocation, Parameters)
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
//Create the output and streamreader to get the output
string output = null; StreamReader srOutput = null;
//try the process
try
{
//run the process
Process proc = System.Diagnostics.Process.Start(oInfo);
proc.WaitForExit();
//if (!proc.WaitForExit(10000))
// proc.Kill();
//get the output
srOutput = proc.StandardError;
//now put it in a string
output = srOutput.ReadToEnd();
proc.Close();
}
catch (Exception)
{
output = string.Empty;
}
finally
{
//now, if we succeded, close out the streamreader
if (srOutput != null)
{
srOutput.Close();
srOutput.Dispose();
}
}
return output;
}
You should always read the StandardOutput and the StandardError buffers while the process is running. Whenever the buffers reach their limits, the process will literally hang until you read the buffers to end.
FFMpeg constantly reports information about the conversion. Every update of the information you see in the bottom of the Command Prompt is added to the StandardOutput buffer, thus filling up the buffer. The buffer is likely to fill up quickly when converting large files.
After a good bit of research I came across this post. Which set me on the right track. I read more about RedirectStandardError and found I needed to change the order I was calling things. After calling
WaitForExit
at the end everything worked as expected. Here is the updated code:Does your web application(app pool process identity) have the proper permissions for what's being done in the process threads you are spawning?
I have had issues like this in the past related to
System.File.Move
running Process Threads doing IO from ASP.NET, which is really a Win32 issue under the hood.Use
System.File.Copy
or the Win32 equivalent and then delete the old file if you can. My guess is the .exe you are calling out(executing) to isn't yours(your own source code to be able to modify) and you can't change it.You can also use SysInternals to see what may be holding on to or blocking resources.