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

发布于 2024-12-06 18:00:45 字数 2735 浏览 0 评论 0原文

我试图在用户提交表单时转换视频。它似乎转换正常,但当我尝试用它做任何事情时,文件“正在被另一个进程使用”。看起来 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;
    }

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情绪操控生活 2024-12-13 18:00:45

经过大量研究后,我发现了这个 帖子。这让我走上了正确的道路。我阅读了有关 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;
}

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:

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;
}
毁虫ゝ 2024-12-13 18:00:45

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

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

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.

蓝咒 2024-12-13 18:00:45

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

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

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文