重定向 stdin 和 stdout,其中 stdin 首先关闭

发布于 2024-08-04 13:26:50 字数 2060 浏览 2 评论 0原文

这实际上与我已经回答的另一个问题有关。这个问题在这里: 将一个进程对象的 stdout 重定向到另一个的stdin

我的问题是(我认为)获取输入的程序应该在程序输出之前退出。这是与我正在做的事情等效的 bash: tccat -i /dev/sr0 -T 1 | ffmpeg -i - -r 1 -t 1 -s 96x72 -ss 5 /tmp/wsmanage/preview_tmp/test\%03d.jpg

这只是使用一个名为 tccat 的程序来读取 DVD 的第一个标题。这将输出到 ffmpeg,它将以每秒 1 帧的速度创建一个 1 秒长的 .jpg 格式的输出文件。一旦它输出它的帧(或两个),它就存在。这很好用。

然而,下面的代码却没有。我得到了大量的“打印行到 ffmpeg”,而命令行版本仅在一秒多一点的时间内退出。然后,它会在 30 或 40 秒左右后停止打印。 FFmpeg 永远不会退出,我的程序也永远不会继续。

我这样做对吗?

Process tccatProcess = new Process();           
tccatProcess.StartInfo.FileName = "tccat";
tccatProcess.StartInfo.Arguments = String.Format("-i {0} -T {1}", devNode, title);
tccatProcess.StartInfo.UseShellExecute = false;
tccatProcess.StartInfo.RedirectStandardOutput = true;

Process ffmpegProcess = new Process();
string bashSafePreviewTemplate = slasher.bashSlash(previewTempDir + "/test%03d.jpg");
ffmpegProcess.StartInfo.FileName = "ffmpeg";
ffmpegProcess.StartInfo.Arguments = String.Format("-i - -r 1 -t 1 -s {1}x{2} -ss {3} {0}", 
    bashSafePreviewTemplate, width, height, timePosition);
ffmpegProcess.StartInfo.UseShellExecute = false;
ffmpegProcess.StartInfo.RedirectStandardInput = true;


try{
    tccatProcess.Start();
    ffmpegProcess.Start();

    StreamReader tccatOutput = tccatProcess.StandardOutput;
    StreamWriter ffmpegInput = ffmpegProcess.StandardInput;

    string line;
    while(!ffmpegProcess.HasExited)
    {
        ffmpegProcess.Refresh();
        if((line = tccatOutput.ReadLine()) != null)
        {
            Console.WriteLine("Printing line to ffmpeg");
            Console.Out.Flush();
            ffmpegInput.WriteLine(line);
            ffmpegInput.Flush();
        }
    }

    Console.WriteLine("Closing tccat");
    Console.Out.Flush();
    tccatProcess.Close();
    Console.WriteLine("Tccat closed");
    Console.Out.Flush();


}catch(Exception e){
    //uninteresting log code
    return false;
}

This is actually related to another question I had that was already answered. That question is here: Redirecting stdout of one process object to stdin of another

My issue is (I think) that the program who is getting the input should exit before the program outputting. Here is the bash equivalent of what I'm doing: tccat -i /dev/sr0 -T 1 | ffmpeg -i - -r 1 -t 1 -s 96x72 -ss 5 /tmp/wsmanage/preview_tmp/test\%03d.jpg

This just uses a program called tccat to read the first title of a dvd. That gets output to ffmpeg, which is going to create an output file at 1 frame per second that is 1 second long in .jpg format. As soon as it outputs its frame (or two) it exists. This works fine.

The following code, however, does not. I get scads of "Printing line to ffmpeg", whereas the command line version exits in just over a second. Then, it just stops printing after 30 or 40 seconds or so. FFmpeg never exits, and my program never continues.

I'm I doing this right?

Process tccatProcess = new Process();           
tccatProcess.StartInfo.FileName = "tccat";
tccatProcess.StartInfo.Arguments = String.Format("-i {0} -T {1}", devNode, title);
tccatProcess.StartInfo.UseShellExecute = false;
tccatProcess.StartInfo.RedirectStandardOutput = true;

Process ffmpegProcess = new Process();
string bashSafePreviewTemplate = slasher.bashSlash(previewTempDir + "/test%03d.jpg");
ffmpegProcess.StartInfo.FileName = "ffmpeg";
ffmpegProcess.StartInfo.Arguments = String.Format("-i - -r 1 -t 1 -s {1}x{2} -ss {3} {0}", 
    bashSafePreviewTemplate, width, height, timePosition);
ffmpegProcess.StartInfo.UseShellExecute = false;
ffmpegProcess.StartInfo.RedirectStandardInput = true;


try{
    tccatProcess.Start();
    ffmpegProcess.Start();

    StreamReader tccatOutput = tccatProcess.StandardOutput;
    StreamWriter ffmpegInput = ffmpegProcess.StandardInput;

    string line;
    while(!ffmpegProcess.HasExited)
    {
        ffmpegProcess.Refresh();
        if((line = tccatOutput.ReadLine()) != null)
        {
            Console.WriteLine("Printing line to ffmpeg");
            Console.Out.Flush();
            ffmpegInput.WriteLine(line);
            ffmpegInput.Flush();
        }
    }

    Console.WriteLine("Closing tccat");
    Console.Out.Flush();
    tccatProcess.Close();
    Console.WriteLine("Tccat closed");
    Console.Out.Flush();


}catch(Exception e){
    //uninteresting log code
    return false;
}

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

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

发布评论

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

评论(2

任谁 2024-08-11 13:26:50

对于任何想要做类似事情的人,这里是应用了 KeeperOfTheSoul 建议的新版本:

        Process tccatProcess = new Process();           
        tccatProcess.StartInfo.FileName = "tccat";
        tccatProcess.StartInfo.Arguments = String.Format("-i {0} -T {1}", devNode, title);
        tccatProcess.StartInfo.UseShellExecute = false;
        tccatProcess.StartInfo.RedirectStandardOutput = true;

        Process ffmpegProcess = new Process();
        string bashSafePreviewTemplate = slasher.bashSlash(previewTempDir + "/test%03d.jpg");
        ffmpegProcess.StartInfo.FileName = "ffmpeg";
        ffmpegProcess.StartInfo.Arguments = String.Format("-i - -r 1 -t 1 -s {1}x{2} -ss {3} {0}", 
            bashSafePreviewTemplate, width, height, timePosition);
        ffmpegProcess.StartInfo.UseShellExecute = false;
        ffmpegProcess.StartInfo.RedirectStandardInput = true;

        Console.WriteLine("tccat command: {0} {1}", tccatProcess.StartInfo.FileName, tccatProcess.StartInfo.Arguments);
        Console.WriteLine("ffmpeg command: {0} {1}", ffmpegProcess.StartInfo.FileName, ffmpegProcess.StartInfo.Arguments);

        //return true;

        try{
            tccatProcess.Start();
            ffmpegProcess.Start();

            BinaryReader tccatOutput = new BinaryReader(tccatProcess.StandardOutput.BaseStream);
            BinaryWriter ffmpegInput = new BinaryWriter(ffmpegProcess.StandardInput.BaseStream);
            int buffSize = 4096;
            byte[] buff = new byte[buffSize];


            while(!ffmpegProcess.HasExited)
            {
                ffmpegProcess.Refresh();
                buff = tccatOutput.ReadBytes(buffSize);
                ffmpegInput.Write(buff);
                ffmpegInput.Flush();
            }


            tccatProcess.Kill();
            tccatProcess.Close();
            ffmpegProcess.Close();


        }catch(Exception e){
                    //uninteresting log code
                    return false;

        }

For anyone who wants to do something similar, here is the new version with KeeperOfTheSoul's advice applied:

        Process tccatProcess = new Process();           
        tccatProcess.StartInfo.FileName = "tccat";
        tccatProcess.StartInfo.Arguments = String.Format("-i {0} -T {1}", devNode, title);
        tccatProcess.StartInfo.UseShellExecute = false;
        tccatProcess.StartInfo.RedirectStandardOutput = true;

        Process ffmpegProcess = new Process();
        string bashSafePreviewTemplate = slasher.bashSlash(previewTempDir + "/test%03d.jpg");
        ffmpegProcess.StartInfo.FileName = "ffmpeg";
        ffmpegProcess.StartInfo.Arguments = String.Format("-i - -r 1 -t 1 -s {1}x{2} -ss {3} {0}", 
            bashSafePreviewTemplate, width, height, timePosition);
        ffmpegProcess.StartInfo.UseShellExecute = false;
        ffmpegProcess.StartInfo.RedirectStandardInput = true;

        Console.WriteLine("tccat command: {0} {1}", tccatProcess.StartInfo.FileName, tccatProcess.StartInfo.Arguments);
        Console.WriteLine("ffmpeg command: {0} {1}", ffmpegProcess.StartInfo.FileName, ffmpegProcess.StartInfo.Arguments);

        //return true;

        try{
            tccatProcess.Start();
            ffmpegProcess.Start();

            BinaryReader tccatOutput = new BinaryReader(tccatProcess.StandardOutput.BaseStream);
            BinaryWriter ffmpegInput = new BinaryWriter(ffmpegProcess.StandardInput.BaseStream);
            int buffSize = 4096;
            byte[] buff = new byte[buffSize];


            while(!ffmpegProcess.HasExited)
            {
                ffmpegProcess.Refresh();
                buff = tccatOutput.ReadBytes(buffSize);
                ffmpegInput.Write(buff);
                ffmpegInput.Flush();
            }


            tccatProcess.Kill();
            tccatProcess.Close();
            ffmpegProcess.Close();


        }catch(Exception e){
                    //uninteresting log code
                    return false;

        }
↘人皮目录ツ 2024-08-11 13:26:50

因为您正在处理视频和图像,所以 tccat 不输出二进制数据吗?如果是这样,您不应该直接读取/写入输入/输出流,而不是将它们包装在文本阅读器中吗?

如果是这样,您想使用 我可以将二进制文件放入标准输入吗? C#

Doesn't tccat output binary data since you're working with video and images? If so shouldn't you be reading/writing to the input/output streams directly rather than wrapping them in a text reader?

If so you want to be using Can i put binary in stdin? C#

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