1

I have to run this command line using 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 runs the test.vpy script and applies filters to or resizes video input, then the output is piped to ffmpeg for the encoding.

If I use a normal Process declaration with vspipe it gives the following error:

Unknown argument: |

From the command line the script works well. I suspect that means that I have to manually pipe between vspipe and ffmpeg.

Is it possible to manually pipe output from one process to another? Must I do it manually?

Here is my function to start process:

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

Update:

This is the block I have changed, this function get job name and parameters for the job that needs to be created, then it saves the process in a dictionary.

              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

then i have a backgroundworker ( ConversionStats ) that get stderr from every process in the dictionary and print them into textboxes:

           '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

so this is my code... but now with cmd getting standarderror with streamreader result in taking a string "Invalid Handle." this is an error from cmd stderr or there is a problem with the streamreader?

UPDATE 2

I have even tried to start a clean cmd process declaring only parameters but the result is just the console with main infos.

Microsoft Windows [Versione 6.3.9600] (c) 2013 Microsoft Corporation. Tutti i diritti riservati.

H:\Project\bin\Release>

this is the code to clarify:

                Dim Proc As New Process

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

                'start process
                Proc.Start()

SO AGAIN THERE IS SOMEONE WHO CAN GUIDE ME HOW TO PIPE/REDIRECT STDOUTPUT FROM ONE PROCESS (vspipe.exe) TO THE STDIN OF ANOTHER PROCESS (ffmpeg.exe)?

Zed Machine
  • 67
  • 1
  • 10
  • 1
    Please add the code you are using to execute that line to your question. – Justin Ryan May 30 '15 at 13:05
  • entering that in a command window means the OS is processing the args, and it knows how to pipe. If the bulk of that is passed as an arg to vspipe using shell or Process.Start, it likely is not going to know what `|` is, which is what the message says. So how do you "run: that from VB? – Ňɏssa Pøngjǣrdenlarp May 30 '15 at 13:09
  • ok added my VB.Net block.. i use a simple process start so my question is how can i do "|" in VB.NET? – Zed Machine May 30 '15 at 14:04
  • let the OS do it. `StartInfo.FileName = "cmd"` then prepend `executablepath` to `params` so it looks the way you would enter it in a command window; `StartInfo.Arguments = params` then start the process – Ňɏssa Pøngjǣrdenlarp May 30 '15 at 15:13
  • I would like to maintain stderr from ffmpeg cause I need to output conversion statistics for the user... there is a way to pipe manually? – Zed Machine May 30 '15 at 19:31
  • Regarding your update, this may be helpful to you. The example is in C#, but the explanation is there. http://stackoverflow.com/questions/628191/net-process-start-process-error-using-credentials-the-handle-is-invalid – Justin Ryan Jun 02 '15 at 09:39

1 Answers1

3

Since you know your command string works on the command line, the easiest thing to do would be to let cmd.exe run the code for you. As Plutonix suggested in his comment, in this answer, Mark provides an example of how to do this in C# code.

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

Adapting this to your purposes, and translating to VB.net might look something like this (using the same variables you declared in your code):

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

How does this differ from what you were doing previously? You used Process.Start to run vspipe.exe, and then passed it your params. This new code above uses Process.Start to instead run cmd.exe, opening a command prompt window essentially, and inputting your complete command line string.

Receiving stdout and stderr requires two steps. First you have to set the 'redirect' properties for each to True, then after starting the process, manually retrieve the desired output.

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: UPDATE 2:

The problem in this specific case is that the Arguments string is a mess of double quotes, which must be escaped. In vb.net this is done with double double-quotes (""), which can appear as "triple double-quotes" (""") if they are at the beginning or end of a string, or even longer multiples of double quotes if there are many that need to be escaped.

Although I do not have the specific software necessary on my system to test, the following should work:

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()
Community
  • 1
  • 1
Justin Ryan
  • 1,409
  • 1
  • 12
  • 25
  • Hi, thank you for the comment, the problem is that i have to get ffmpeg stderr.. if i use "cmd" can I get stderr with no problems? – Zed Machine May 31 '15 at 08:38
  • @ZedMachine Yes; example added. – Justin Ryan May 31 '15 at 18:35
  • i think I will give it a try ;) thank you so much :) – Zed Machine Jun 01 '15 at 13:35
  • no way to get it work... redirected stdin stdout stderr the process start but the handle linked to the Process (in debug mode) is not in task manager.. and when i try to use .readnewline() using StreamReader it just break the debug and return in the program window.... I have just tried to get the arguments passed to cmd by the function and it works perfectly! help me...please :) – Zed Machine Jun 02 '15 at 10:48
  • @ZedMachine Read the 'Remarks' section of [Process.StandardError Property](https://msdn.microsoft.com/en-us/library/system.diagnostics.process.standarderror(v=vs.110).aspx), specifically the paragraphs about synchronous and asynchronous reads, and dead lock. – Justin Ryan Jun 02 '15 at 11:14
  • @ZedMachine Here's a [Stack Overflow Q/A](http://stackoverflow.com/questions/4137346/correct-way-to-handle-standard-error-and-output-from-a-program-when-spawned-via) about what I think you are experiencing, which might help. – Justin Ryan Jun 02 '15 at 11:21
  • does not work... I try even start cmd with windows without any restriction but it does not work... Dim Proc As New Process Proc.StartInfo.FileName = "cmd" Proc.StartInfo.Arguments = params 'start process Proc.Start() – Zed Machine Jun 04 '15 at 10:06
  • You may want to edit the question, or post a new question, with your complete code, and an explanation of the problem and any error messages. It is difficult to provide extra help in the comments. – Justin Ryan Jun 04 '15 at 10:10
  • no the quotes are well managed... simply this method does not work if i use /C params it return invalid character – Zed Machine Jun 06 '15 at 20:59
  • Have you tried copy/pasting my `.Arguments` line? I did notice that your `arguments` variable in the fist code snippet of your question does not make a valid string. – Justin Ryan Jun 06 '15 at 21:27
  • here is the string taken in debug mode in the process arguments.. /C "H:\Project\VapourSynth\core64\vspipe.exe" "H:\videotest\test.vpy" - -y | "H:\Project\Suite HEVC\bin\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 "H:\videotest\outpuawdwdt.mkv" – Zed Machine Jun 06 '15 at 21:35
  • You need to wrap everything after `/C` in **another** set of double quotes. Look closely at my example. – Justin Ryan Jun 06 '15 at 21:39
  • another question justin... there is a way to kill all linked processes to my cmd process? cause now if I try to kill my process ffmpeg and vspipe just stay idle without closing.. can I see all linked process inside my Process variable? – Zed Machine Jun 07 '15 at 11:12
  • You'd have to loop through `jobs_processes` and use something like [Process.Kill](https://msdn.microsoft.com/en-us/library/system.diagnostics.process.kill(v=vs.110).aspx). – Justin Ryan Jun 07 '15 at 23:08
  • 1
    Yea i have managed to kill only the related ffmpeg process with the dame start time as my process. so I guess it's over now !! Thank you just in for all answers ;) – Zed Machine Jun 10 '15 at 06:07