5 Replies - 229 Views - Last Post: 27 April 2019 - 10:45 PM Rate Topic: -----

#1 chrisyroid   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 27-December 15

Trying to send commands to ffmpeg by using a button.

Posted 26 April 2019 - 03:19 AM

I'm making a program which opens up ffmpeg and runs a job which then the user can quit the job by pressing a button.

I'm getting "An async read operation has already been started on the stream." on "BeginOutputReadLine" when I try to quit the job a second time.

If I try putting "Dim p3 As New Process" inside "test_run()" I get: "StandardIn has not been redirected." on "StandardInput.WriteLine" if I attempt to quit the job once.

This is a working sample of my code.

Imports System.IO

Public Class Form1
    Dim quote As String = """"
    Dim p3 As New Process

    Function generate_batch(aargs As String) As Integer
        Dim sb As New System.Text.StringBuilder
        sb.AppendLine("@echo off")
        sb.AppendLine("CD " + quote + Application.StartupPath + quote)
        sb.AppendLine("ffmpeg " + aargs)
        sb.AppendLine("(goto) 2>nul & del " + quote + "%~f0" + quote)
        IO.File.WriteAllText(Path.GetTempPath + "ffmpeg.bat", sb.ToString())
    End Function

    Private Sub test_run()
        If TextBox1.Text = "1" Then
            p3.StandardInput.WriteLine("q")
            p3.Close()
        Else
            generate_batch(arg.Text)
            With p3.StartInfo
                .FileName = Path.GetTempPath + "\ffmpeg.bat"
                .CreateNoWindow = True
                .RedirectStandardOutput = True
                .RedirectStandardError = True
                .RedirectStandardInput = True
                .UseShellExecute = False
            End With

            AddHandler p3.OutputDataReceived, AddressOf consoleOutputHandler
            AddHandler p3.ErrorDataReceived, AddressOf consoleErrorHandler

            p3.Start()

            p3.BeginOutputReadLine()
            p3.BeginErrorReadLine()
        End If
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        test_run()
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        TextBox1.Text = "1"
        test_run()
    End Sub

    '///////////////////
    '/ Standard Output /
    '///////////////////
    Private Delegate Sub consoleOutputDelegate(ByVal outputString As String)
    Private Sub consoleOutput(ByVal outputString As String)
        'Invoke the sub to allow cross thread calls to pass safely
        If Me.InvokeRequired Then
            Dim del As New consoleOutputDelegate(AddressOf consoleOutput)
            Dim args As Object() = {outputString}
            Me.Invoke(del, args)
        Else
            'Now we can update your textbox with the data passed from the asynchronous thread
            RichTextBox1.AppendText(String.Concat("", outputString, Environment.NewLine))
        End If
    End Sub
    'Catch the Standard Output
    Sub consoleOutputHandler(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)
        If Not String.IsNullOrEmpty(outLine.Data) Then
            'If the Current output line is not empty then pass it back to your main thread (Form1)
            consoleOutput(outLine.Data)
        End If
    End Sub

    '///////////////////
    '// Error Output ///
    '///////////////////
    Private Delegate Sub consoleErrorDelegate(ByVal errorString As String)
    Private Sub consoleError(ByVal errorString As String)
        'Invoke the sub to allow cross thread calls to pass safely
        If Me.InvokeRequired Then
            Dim del As New consoleErrorDelegate(AddressOf consoleError)
            Dim args As Object() = {errorString}
            Me.Invoke(del, args)
        Else
            'Now we can update your textbox with the data passed from the asynchronous thread
            RichTextBox1.AppendText(String.Concat("", errorString, Environment.NewLine))
        End If
    End Sub
    'Catch the Error Output
    Private Sub consoleErrorHandler(ByVal sendingProcess As Object, ByVal errLine As DataReceivedEventArgs)
        If Not String.IsNullOrEmpty(errLine.Data) Then
            'If the Current error line is not empty then pass it back to your main thread (Form1)
            consoleError(errLine.Data)
        End If
    End Sub
End Class


What's inside "arg.text"

-re -i video.mp4 -c copy -f rtp_mpegts rtp://127.0.0.1:10000?pkt_size=1316


I expect the job to be able to be stopped and started for an unlimited number of times but I keep running into problems and I don't know why.

I'm wondering if I have to stop the async read operation but I don't know if that's possible.

Is This A Good Question/Topic? 0
  • +

Replies To: Trying to send commands to ffmpeg by using a button.

#2 andrewsw   User is offline

  • quantum multiprover
  • member icon

Reputation: 6792
  • View blog
  • Posts: 28,050
  • Joined: 12-December 12

Re: Trying to send commands to ffmpeg by using a button.

Posted 26 April 2019 - 03:41 AM

I don't know much about this but did a quick search. BeginOutputReadLine "Begins asynchronous read operations..."; there is CancelOutputRead method which you should probably investigate.
Was This Post Helpful? 0
  • +
  • -

#3 chrisyroid   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 27-December 15

Re: Trying to send commands to ffmpeg by using a button.

Posted 26 April 2019 - 03:56 AM

View Postandrewsw, on 26 April 2019 - 03:41 AM, said:

I don't know much about this but did a quick search. BeginOutputReadLine "Begins asynchronous read operations..."; there is CancelOutputRead method which you should probably investigate.


That kind of worked. Now the output gets cut short after the process has stopped and when restarting it, the output doubles like the cache or buffer isn't cleared.

  Duration: 00:26:21.57, start: 0.000000, bitrate: 707 kb/s
  Duration: 00:26:21.57, start: 0.000000, bitrate: 707 kb/s
    Stream #0:0: Video: h264 (High), yuv420p(tv, smpte170m/smpte170m/bt709, progressive), 640x360, 30.30 fps, 120 tbr, 1k tbn, 59.94 tbc
    Stream #0:0: Video: h264 (High), yuv420p(tv, smpte170m/smpte170m/bt709, progressive), 640x360, 30.30 fps, 120 tbr, 1k tbn, 59.94 tbc
    Stream #0:1: Audio: aac (LC), 48000 Hz, mono, fltp
    Stream #0:1: Audio: aac (LC), 48000 Hz, mono, fltp
Output #0, rtp_mpegts, to 'rtp://127.0.0.1:10000?pkt_size=1316':
Output #0, rtp_mpegts, to 'rtp://127.0.0.1:10000?pkt_size=1316':

Was This Post Helpful? 0
  • +
  • -

#4 chrisyroid   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 27-December 15

Re: Trying to send commands to ffmpeg by using a button.

Posted 26 April 2019 - 04:01 AM

I also tried adding "StandardOutput.BaseStream.Flush()" thinking that might help but that just gives me the async read operation error.
Was This Post Helpful? 0
  • +
  • -

#5 andrewsw   User is offline

  • quantum multiprover
  • member icon

Reputation: 6792
  • View blog
  • Posts: 28,050
  • Joined: 12-December 12

Re: Trying to send commands to ffmpeg by using a button.

Posted 26 April 2019 - 05:30 AM

I probably cannot help beyond my original post, but you should post your revised code.
Was This Post Helpful? 0
  • +
  • -

#6 chrisyroid   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 27-December 15

Re: Trying to send commands to ffmpeg by using a button.

Posted 27 April 2019 - 10:45 PM

Alright. I finally fixed it! After googling the crap out of my problem, out of desperation, I used "RemoveHandler" and my duplicate output problem was gone. Then I found out that you have to create a new process of the same name after closing it which effectively overwrites the opened "BeginOutputReadLine" and "BeginErrorReadLine"

I found my my new process solution here

Imports System.IO

Public Class Form1
    Dim p3 As New Process
    Dim quote As String = """"
    Dim close_flag As Int32 = 0

    Function generate_batch(aargs As String) As Integer
        Dim sb As New System.Text.StringBuilder
        sb.AppendLine("@echo off")
        sb.AppendLine("CD " + quote + Application.StartupPath + quote)
        sb.AppendLine("ffmpeg " + aargs)
        sb.AppendLine("(goto) 2>nul & del " + quote + "%~f0" + quote)
        IO.File.WriteAllText(Path.GetTempPath + "ffmpeg.bat", sb.ToString())
    End Function

    Private Sub test_run()
        If close_flag = 1 Then
            p3.StandardInput.WriteLine("q")
            p3.Close()            
            p3 = New Process()
            RemoveHandler p3.OutputDataReceived, AddressOf consoleOutputHandler
            RemoveHandler p3.ErrorDataReceived, AddressOf consoleErrorHandler
            Label1.Text = "Closed"
            close_flag = 0
        ElseIf close_flag = 0 Then
            RichTextBox1.Text = ""
            generate_batch(arg.Text)
            With p3.StartInfo
                .FileName = Path.GetTempPath + "\ffmpeg.bat"
                .CreateNoWindow = True
                .RedirectStandardOutput = True
                .RedirectStandardError = True
                .RedirectStandardInput = True
                .UseShellExecute = False
            End With

            AddHandler p3.OutputDataReceived, AddressOf consoleOutputHandler
            AddHandler p3.ErrorDataReceived, AddressOf consoleErrorHandler
            p3.Start()
            Label2.Text = p3.Id
            p3.BeginOutputReadLine()
            p3.BeginErrorReadLine()
        End If
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        test_run()
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        close_flag = 1
        test_run()
    End Sub

    '///////////////////
    '/ Standard Output /
    '///////////////////
    Private Delegate Sub consoleOutputDelegate(ByVal outputString As String)
    Private Sub consoleOutput(ByVal outputString As String)
        'outputString.ToString()
        'Invoke the sub to allow cross thread calls to pass safely
        If Me.InvokeRequired Then
            Dim del As New consoleOutputDelegate(AddressOf consoleOutput)
            Dim args As Object() = {outputString}
            Me.Invoke(del, args)
        Else
            'Now we can update your textbox with the data passed from the asynchronous thread
            RichTextBox1.AppendText(String.Concat("", outputString, Environment.NewLine))
        End If
    End Sub
    'Catch the Standard Output
    Sub consoleOutputHandler(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)
        If Not String.IsNullOrEmpty(outLine.Data) Then
            'If the Current output line is not empty then pass it back to your main thread (Form1)
            consoleOutput(outLine.Data)
        End If
    End Sub

    '///////////////////
    '// Error Output ///
    '///////////////////
    Private Delegate Sub consoleErrorDelegate(ByVal errorString As String)
    Private Sub consoleError(ByVal errorString As String)
        'Invoke the sub to allow cross thread calls to pass safely
        If Me.InvokeRequired Then
            Dim del As New consoleErrorDelegate(AddressOf consoleError)
            Dim args As Object() = {errorString}
            Me.Invoke(del, args)
        Else
            'Now we can update your textbox with the data passed from the asynchronous thread
            RichTextBox1.AppendText(String.Concat("", errorString, Environment.NewLine))
        End If
    End Sub
    'Catch the Error Output
    Private Sub consoleErrorHandler(ByVal sendingProcess As Object, ByVal errLine As DataReceivedEventArgs)
        If Not String.IsNullOrEmpty(errLine.Data) Then
            'If the Current error line is not empty then pass it back to your main thread (Form1)
            consoleError(errLine.Data)
        End If
    End Sub
End Class

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1