在 stdin 首先关闭的地方重定向 stdin 和 stdout

Posted

技术标签:

【中文标题】在 stdin 首先关闭的地方重定向 stdin 和 stdout【英文标题】:Redirecting stdin and stdout where stdin closes first 【发布时间】:2009-09-03 13:21:58 【问题描述】:

这实际上与我已经回答的另一个问题有关。这个问题在这里:Redirecting stdout of one process object to stdin of another

我的问题是(我认为)获取输入的程序应该在程序输出之前退出。这是我正在做的 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 帧的速度创建一个 .jpg 格式的 1 秒长的输出文件。一旦它输出它的帧(或两个),它就存在了。这很好用。

但是,下面的代码没有。我得到大量“打印到 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 1x2 -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;

【问题讨论】:

【参考方案1】:

对于任何想做类似事情的人,这里是采用 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 1x2 -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;

        

【讨论】:

【参考方案2】:

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

如果你想使用Can i put binary in stdin? C#

【讨论】:

啊,这可能是我的问题。我没有意识到 streamreader/streamwriter 不是二进制安全的。我会尽快尝试这个并返回结果!也感谢您的链接。我明白我需要做什么。即使这不是我唯一的问题,我也可以看到它肯定需要修复。

以上是关于在 stdin 首先关闭的地方重定向 stdin 和 stdout的主要内容,如果未能解决你的问题,请参考以下文章

Linux学习笔记 -- stdin/stdout 重定向

C和C++的文件操作

运行包含带有屏幕的 STDIN 重定向的命令

如何检测 Console.In (stdin) 是不是已被重定向?

如何在使用os.execl替换进程时重定向stdin / stdout / stderr

如何添加nohup? - 将stdin重定向到程序和背景