如何在 Process.Start 中的两个进程之间使用管道
How to use a Pipe between two processes in Process.Start
我必须 运行 这个命令行使用 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: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"
vspipe.exe
运行s test.vpy
脚本并对视频输入应用过滤器或调整其大小,然后将输出通过管道传输到 ffmpeg 进行编码。
如果我在 vspipe 中使用普通的流程声明,它会出现以下错误:
Unknown argument: |
脚本从命令行运行良好。我怀疑这意味着我必须在 vspipe
和 ffmpeg
之间手动进行管道传输。
是否可以手动将一个进程的输出通过管道传输到另一个进程?我必须手动操作吗?
这是我启动进程的函数:
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
然后我有一个 backgroundworker (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 获取 streamreader 的标准错误导致采用字符串 "Invalid Handle." 这是 cmd stderr 的错误或者 streamreader 有问题?
更新 2
我什至尝试启动一个干净的 cmd 进程,只声明参数,但结果只是带有主要信息的控制台。
微软 Windows [版本 6.3.9600]
(c) 2013 年微软公司。全部保留。
H:\Project\bin\Release>
这是澄清的代码:
Dim Proc As New Process
Proc.StartInfo.FileName = "cmd"
Proc.StartInfo.Arguments = params
'start process
Proc.Start()
再次有人可以指导我如何 PIPE/REDIRECT 从一个进程 (vspipe.exe) 到另一个进程 (ffmpeg.exe) 的标准输出?
既然您知道您的命令字符串在命令行上有效,那么最简单的做法就是让 cmd.exe
运行 为您编写代码。正如 Plutonix 在 , in 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
,本质上打开命令提示符 window,然后输入完整的命令行字符串。
接收stdout
和stderr
需要两个步骤。首先,您必须将每个的 'redirect' 属性设置为 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()
回复:更新 2:
这个特定案例中的问题是 Arguments
字符串是一堆双引号,必须对其进行转义。在 vb.net 中,这是通过双引号 (""
) 完成的,如果它们位于字符串的开头或结尾,则可以显示为 "triple double-quotes" ("""
),甚至更长的双引号倍数(如果有很多需要转义的话)。
虽然我的系统上没有测试所需的特定软件,但以下应该可以工作:
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()
我必须 运行 这个命令行使用 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: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"
vspipe.exe
运行s test.vpy
脚本并对视频输入应用过滤器或调整其大小,然后将输出通过管道传输到 ffmpeg 进行编码。
如果我在 vspipe 中使用普通的流程声明,它会出现以下错误:
Unknown argument: |
脚本从命令行运行良好。我怀疑这意味着我必须在 vspipe
和 ffmpeg
之间手动进行管道传输。
是否可以手动将一个进程的输出通过管道传输到另一个进程?我必须手动操作吗?
这是我启动进程的函数:
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
然后我有一个 backgroundworker (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 获取 streamreader 的标准错误导致采用字符串 "Invalid Handle." 这是 cmd stderr 的错误或者 streamreader 有问题?
更新 2
我什至尝试启动一个干净的 cmd 进程,只声明参数,但结果只是带有主要信息的控制台。
微软 Windows [版本 6.3.9600] (c) 2013 年微软公司。全部保留。
H:\Project\bin\Release>
这是澄清的代码:
Dim Proc As New Process
Proc.StartInfo.FileName = "cmd"
Proc.StartInfo.Arguments = params
'start process
Proc.Start()
再次有人可以指导我如何 PIPE/REDIRECT 从一个进程 (vspipe.exe) 到另一个进程 (ffmpeg.exe) 的标准输出?
既然您知道您的命令字符串在命令行上有效,那么最简单的做法就是让 cmd.exe
运行 为您编写代码。正如 Plutonix 在
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
,本质上打开命令提示符 window,然后输入完整的命令行字符串。
接收stdout
和stderr
需要两个步骤。首先,您必须将每个的 'redirect' 属性设置为 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()
回复:更新 2:
这个特定案例中的问题是 Arguments
字符串是一堆双引号,必须对其进行转义。在 vb.net 中,这是通过双引号 (""
) 完成的,如果它们位于字符串的开头或结尾,则可以显示为 "triple double-quotes" ("""
),甚至更长的双引号倍数(如果有很多需要转义的话)。
虽然我的系统上没有测试所需的特定软件,但以下应该可以工作:
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()