【问题标题】:How to use a Pipe between two processes in Process.Start如何在 Process.Start 中的两个进程之间使用管道
【发布时间】:2015-08-13 07:41:10
【问题描述】:

我必须使用 VB.NET 运行这个命令行:

"H:\videotest\test.vpy" - -y | "H:\Release\data\bin64\ffmpeg.exe" -hwaccel auto -y -i - -map 0:v:0 -c:v libx265 -crf 20.0 -preset 5 -x265-params level=0:profile= undefined:pmode:no-pme:pme:no-high-tier:ref=3:bframes=4:open-gop:keyint=250:min-keyint=25:b-adapt=2:bframe-bias=0: rc-lookahead=20:no-scenecut:b-pyramid:me=hex:subme=2:merange=57:temporal-mvp:weightp:no-weightb:max-merge=2:no-weightb:no-rect: no-amp:vbv-bufsize=0:vbv-maxrate=0:vbv-init=0.9:no-strict-cbr:qcomp=0.6:qstep=4:aq-mode=1:aq-strength=1.0:cutree:不提前跳过:min-cu-size=8:ctu=64:no-fast-cfb:ipratio=1.4:pbratio=1.3:cbqpoffs=0:crqpoffs=0:rd=3:psy-rd=0.3: psy-rdoq=1:no-b-intra:no-fast-intra:rdoq-level=1:no-tskip:no-tskip-fast:cu-lossless:tu-intra-depth=1:tu-inter- depth=1:strong-intra-smoothing:no-constrained-intra:nr-intra=0:nr-inter=0:qblur=0.5:cplxblur=20:signhide:sar=16 "H:\videotest\outputawdwd.mkv"

vspipe.exe 运行 test.vpy 脚本并对视频输入应用过滤器或调整其大小,然后将输出通过管道传输到 ffmpeg 进行编码。

如果我在 vspipe 中使用正常的 Process 声明,则会出现以下错误:

未知参数:|

从命令行脚本运行良好。我怀疑这意味着我必须在 vspipeffmpeg 之间手动进行管道传输。

是否可以手动将输出从一个进程传送到另一个进程?我必须手动操作吗?

这是我启动进程的函数:

executablepath = "H:\Project\VapourSynth\core64\vspipe.exe"

params = "H:\videotest\test.vpy" - -y | "H:\Release\data\bin64\ffmpeg.exe" -hwaccel auto -y -i - -map 0:v:0 -c:v libx265 -crf 20.0 -preset 5 -x265-params level=0:profile=undefined:pmode:no-pme:pme:no-high-tier:ref=3:bframes=4:open-gop:keyint=250:min-keyint=25:b-adapt=2:bframe-bias=0:rc-lookahead=20:no-scenecut:b-pyramid:me=hex:subme=2:merange=57:temporal-mvp:weightp:no-weightb:max-merge=2:no-weightb:no-rect:no-amp:vbv-bufsize=0:vbv-maxrate=0:vbv-init=0.9:no-strict-cbr:qcomp=0.6:qstep=4:aq-mode=1:aq-strength=1.0:cutree:no-early-skip:min-cu-size=8:ctu=64:no-fast-cfb:ipratio=1.4:pbratio=1.3:cbqpoffs=0:crqpoffs=0:rd=3:psy-rd=0.3:psy-rdoq=1:no-b-intra:no-fast-intra:rdoq-level=1:no-tskip:no-tskip-fast:cu-lossless:tu-intra-depth=1:tu-inter-depth=1:strong-intra-smoothing:no-constrained-intra:nr-intra=0:nr-inter=0:qblur=0.5:cplxblur=20:signhide:sar=16 "H:\videotest\outputawdwd.mkv"

Private Sub CreateJobProcess(ByVal Name, ByVal executablepath, ByVal params)

    Try

        If Not jobs_processes.ContainsKey(Name) Then

            Dim Proc As New Process

            Proc.StartInfo.UseShellExecute = False
            Proc.StartInfo.CreateNoWindow = True
            Proc.StartInfo.RedirectStandardError = True
            Proc.StartInfo.FileName = "" & executablepath & ""
            Proc.StartInfo.Arguments = params

            'start process
            Proc.Start()

            'add new process to dictionary
            jobs_processes.Add(Name, Proc)

            'TEMP
            My.Settings.giobbe -= 1

            'start background workers for statistics
            If Not ConversionStats.IsBusy Then
                ConversionStats.WorkerSupportsCancellation = True
                ConversionStats.RunWorkerAsync()
            End If

            If Not UpdateListJob.IsBusy Then
                UpdateListJob.WorkerSupportsCancellation = True
                UpdateListJob.RunWorkerAsync()
            End If

        End If

    Catch ex As Exception
        Me.Invoke(New MethodInvoker(Sub() Logbox.AppendText(Environment.NewLine & ">Program exception:" & Environment.NewLine & ex.Message & Environment.NewLine)))
        MsgBox(ex.Message)
    End Try
End Sub

更新:

这是我更改的块,该函数获取需要创建的作业的作业名称和参数,然后将过程保存在字典中。

              Dim Proc As New Process

                Proc.StartInfo.UseShellExecute = False
                Proc.StartInfo.CreateNoWindow = True
                Proc.StartInfo.RedirectStandardError = True
                Proc.StartInfo.FileName = "cmd"
                Proc.StartInfo.Arguments = params

                'start process
                Proc.Start()

                'add new process to dictionary
                jobs_processes.Add(Name, Proc)

                'TEMP
                My.Settings.giobbe -= 1

                'start background workers for statistics
                If Not ConversionStats.IsBusy Then
                    ConversionStats.WorkerSupportsCancellation = True
                    ConversionStats.RunWorkerAsync()
                End If

                If Not UpdateListJob.IsBusy Then
                    UpdateListJob.WorkerSupportsCancellation = True
                    UpdateListJob.RunWorkerAsync()
                End If

然后我有一个后台工作程序( ConversionStats ),它从字典中的每个进程获取 stderr 并将它们打印到文本框中:

           'take current selected process and set streamreader
            Dim tmpproc As Process = jobs_processes(CurrentJob)
            Dim ffmpeg_stats As StreamReader
            Dim stdoutput As String = ""

            'something that verify if the job is started 

            If statejob = 1 Then    'if job is working

                'take stderr from ffmpeg
                ffmpeg_stats = tmpproc.StandardError
                stdoutput = ffmpeg_stats.ReadLine()

                If stdoutput IsNot Nothing Then 'if ffmpeg stderr is not nothing 

                    'IF FFMPEG IS RETURNING STATS
                    If stdoutput.Contains("frame=") Or stdoutput.Contains("size=") Then

所以这是我的代码... 但现在 cmd 使用流读取器获取标准错误导致获取字符串“无效句柄”。这是 cmd stderr 的错误还是流读取器有问题?

更新 2

我什至尝试启动一个干净的 cmd 进程,只声明参数,但结果只是带有主要信息的控制台。

Microsoft Windows [版本 6.3.9600] (c) 2013 年微软公司。 Tutti i diritti risrvati。

H:\Project\bin\Release>

这是要澄清的代码:

                Dim Proc As New Process

                Proc.StartInfo.FileName = "cmd"
                Proc.StartInfo.Arguments = params

                'start process
                Proc.Start()

那么再次有人可以指导我如何将标准输出从一个进程 (vspipe.exe) 管道/重定向到另一个进程的标准输入 (ffmpeg.exe)?

【问题讨论】:

  • 请将您用于执行该行的代码添加到您的问题中。
  • 在命令窗口中输入它意味着操作系统正在处理参数,并且它知道如何管道。如果使用 shell 或 Process.Start 将其中的大部分作为 arg 传递给 vspipe,它可能不会知道 | 是什么,这就是消息所说的。那么你如何“运行:从 VB 运行?
  • ok 添加了我的 VB.Net 块。我使用简单的流程启动,所以我的问题是我该怎么做“|”在 VB.NET 中?
  • 让操作系统来做。 StartInfo.FileName = "cmd" 然后将 executablepath 添加到 params,这样它看起来就像您在命令窗口中输入它的方式; StartInfo.Arguments = params 然后启动进程
  • 我想维护来自 ffmpeg 的 stderr,因为我需要为用户输出转换统计信息...有办法手动管道吗?

标签: vb.net ffmpeg pipeline video-encoding


【解决方案1】:

既然您知道您的命令字符串可以在命令行上运行,那么最简单的方法就是让cmd.exe 为您运行代码。正如 Plutonix 在 his comment 中建议的那样,在 this answer 中,Mark 提供了一个如何在 C# 代码中执行此操作的示例。

Process test = new Process();
test.StartInfo.FileName = "cmd";
test.StartInfo.Arguments = @"/C ""echo testing | grep test""";
test.Start();

根据您的目的调整它并翻译成 VB.net 可能看起来像这样(使用您在代码中声明的相同变量):

Dim Proc As New Process()
Proc.StartInfo.FileName = "cmd"
Proc.StartInfo.Arguments = "/C """ & executablepath & " " & params & """
Proc.Start()

这与您之前所做的有什么不同?您使用Process.Start 运行vspipe.exe,然后将其传递给您的params。上面的这个新代码使用Process.Start 代替运行cmd.exe,本质上是打开一个命令提示符窗口,并输入完整的命令行字符串。

接收stdoutstderr 需要两个步骤。首先,您必须将每个的“重定向”属性设置为 True,然后在启动该过程后,手动检索所需的输出。

Dim Proc As New Process()
Proc.StartInfo.FileName = "cmd"
Proc.StartInfo.Arguments = executablepath & " " & params

'Capture stdio & stderr:
Proc.StartInfo.RedirectStandardOutput = True
Proc.StartInfo.RedirectStandardError = True

Proc.Start()

'Read stdio & stderr:
Dim StdIO As String = Proc.StandardOutput.ReadToEnd()
Dim StdErr As String = Proc.StandardError.ReadToEnd()

RE:更新 2

在这种特定情况下的问题是Arguments 字符串是一堆双引号,必须对其进行转义。在 vb.net 中,这是通过双双引号 ("") 完成的,如果它们位于字符串的开头或结尾,或者甚至更长的倍数,则它们可以显示为“三重双引号”(""")如果有很多需要转义,请使用双引号。

虽然我的系统上没有测试所需的特定软件,但以下应该可以工作:

Dim Proc As New Process
Proc.StartInfo.CreateNoWindow = True
Proc.StartInfo.UseShellExecute = False
Proc.StartInfo.FileName = "cmd"
Proc.StartInfo.Arguments = "/C ""H:\Project\VapourSynth\core64\vspipe.exe ""H:\videotest\test.vpy"" - -y | ""H:\Release\data\bin64\ffmpeg.exe"" -hwaccel auto -y -i - -map 0:v:0 -c:v libx265 -crf 20.0 -preset 5 -x265-params level=0:profile=undefined:pmode:no-pme:pme:no-high-tier:ref=3:bframes=4:open-gop:keyint=250:min-keyint=25:b-adapt=2:bframe-bias=0:rc-lookahead=20:no-scenecut:b-pyramid:me=hex:subme=2:merange=57:temporal-mvp:weightp:no-weightb:max-merge=2:no-weightb:no-rect:no-amp:vbv-bufsize=0:vbv-maxrate=0:vbv-init=0.9:no-strict-cbr:qcomp=0.6:qstep=4:aq-mode=1:aq-strength=1.0:cutree:no-early-skip:min-cu-size=8:ctu=64:no-fast-cfb:ipratio=1.4:pbratio=1.3:cbqpoffs=0:crqpoffs=0:rd=3:psy-rd=0.3:psy-rdoq=1:no-b-intra:no-fast-intra:rdoq-level=1:no-tskip:no-tskip-fast:cu-lossless:tu-intra-depth=1:tu-inter-depth=1:strong-intra-smoothing:no-constrained-intra:nr-intra=0:nr-inter=0:qblur=0.5:cplxblur=20:signhide:sar=16 ""H:\videotest\outputawdwd.mkv"""
Proc.StartInfo.RedirectStandardOutput = True
Proc.StartInfo.RedirectStandardError = True

Proc.Start()
Dim so As String = Proc.StandardOutput.ReadToEnd
Dim se As String = Proc.StandardError.ReadToEnd
Proc.WaitForExit()

【讨论】:

  • 嗨,谢谢你的评论,问题是我必须得到 ffmpeg 标准错误。如果我使用“cmd”,我可以毫无问题地获得标准错误吗?
  • @ZedMachine 是的;添加示例。
  • 我想我会试试看 ;) 非常感谢 :)
  • 没有办法让它工作......重定向标准输入标准输出标准错误进程启动但链接到进程的句柄(在调试模式下)不在任务管理器中......当我尝试使用. readnewline() 使用 StreamReader 它只是中断调试并在程序窗口中返回......我刚刚尝试让函数传递给 cmd 的参数,它工作得很好!帮帮我...请:)
  • 是的,我已经设法只杀死了相关的 ffmpeg 进程,并将 dame 开始时间作为我的进程。所以我想它现在结束了!感谢您提供所有答案;)
猜你喜欢
  • 1970-01-01
  • 2011-07-11
  • 2013-08-28
  • 2014-06-20
  • 2011-10-16
  • 2011-05-17
  • 1970-01-01
  • 2020-01-06
  • 2011-06-18
相关资源
最近更新 更多