为什么在从我的网络应用转换video时ffmpeg永远不会完成?

我想在用户提交表单时转换video。 它似乎转换正常,但当我尝试用它做任何事情时,文件“正被另一个进程使用”。 看起来ffmpeg.exe永远不会退出。 我的代码在下面是否有任何我应该做的不同以允许进程释放文件? 如果我手动运行它退出正常。

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; } 

经过一番研究后,我发现了这篇文章 。 这让我走上正轨。 我阅读了更多关于RedirectStandardError的内容 ,发现我需要更改我调用的顺序。 在最后调用WaitForExit后,一切都按预期工作。 这是更新的代码:

 protected string RunProcess(string Parameters) { //create a process info var oInfo = new ProcessStartInfo(this.FFmpegLocation, Parameters) { UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true }; var output = string.Empty; try { Process process = System.Diagnostics.Process.Start(oInfo); output = process.StandardError.ReadToEnd(); process.WaitForExit(); process.Close(); } catch (Exception) { output = string.Empty; } return output; } 

在进程运行时,始终读取StandardOutput和StandardError缓冲区 。 每当缓冲区达到其限制时, 该过程将逐渐挂起,直到您读取缓冲区结束

FFMpeg不断报告有关转换的信息。 您在命令提示符底部看到的每次更新信息都会添加到StandardOutput缓冲区,从而填满缓冲区。 转换大文件时,缓冲区可能会很快填满。

您的Web应用程序(应用程序池进程标识)是否对您正在生成的进程线程中执行的操作具有适当的权限?

我在过去遇到过与System.File.Move相关的问题,运行从ASP.NET执行IO的Process Threads,这实际上是一个Win32问题。

使用System.File.Copy或Win32等效项,然后删除旧文件(如果可以)。 我的猜测是你调用(执行)的.exe不是你的(你自己的源代码能够修改),你不能改变它。

您还可以使用SysInternals查看可能持有或阻止资源的内容。