Results 1 to 9 of 9

Thread: VB.NET Streaming Image Using Imag2Pipe Issue

Threaded View

  1. #8
    Frenzied Member
    Join Date
    Jul 2011
    Location
    UK
    Posts
    1,335

    Re: VB.NET Streaming Image Using Imag2Pipe Issue

    Quote Originally Posted by Shohag_ifas View Post
    1. sir, i don't think tehre isn't a proper way to pass thousands of images (every single frame) as pipe/stream to ffmepg, ffmpeg is very well known and it's been running for many years. so, i hope it support that function very well.
    I wasn't implying the fault was with ffmpeg. I was saying that ffmpeg was freezing because your code wasn't properly handling the output from ffmpeg, especially when processing many hundreds of images.


    Quote Originally Posted by Shohag_ifas View Post
    the main culprit StandardError, after you have pointed out, i tried to skipping following line:
    Code:
    Rem strCLIText = objFProcess.StandardError.ReadToEnd
    but that doesn't solve the problem..

    then i tried to handle the StandardError in a handler event.. using flowing codes:

    Code:
    	objFProcess.StartInfo.RedirectStandardError = True
    	AddHandler objFProcess.ErrorDataReceived, AddressOf consoleErrorHandler
    
        rem Catch the Error Output
        Private Sub consoleErrorHandler(ByVal sendingProcess As Object, ByVal errLine As DataReceivedEventArgs)
            If Not String.IsNullOrEmpty(errLine.Data) Then
                lstCLIErr.Add(errLine.Data)
            End If
        End Sub
    you see, i tried to get the data as it comes, but that also doesn't solve the problem..
    can you please figure out a way to handle the standard error so that i can also have that data without freezing?
    Yeah, commenting out objFProcess.StandardError.ReadToEnd won't help because you actually need something to read from standard error before it fills up and so make space for ffmpeg to write more data to it. You just need to read the data while it is being written, i.e. not wait until the end of the process.

    Handling the ErrorDataReceived event should do that for you. However, it's not enough to just register the event handler (AddHandler objFProcess.ErrorDataReceived, AddressOf consoleErrorHandler), you also have to call objFProcess.BeginErrorReadLine() in order to start the asynchronous reads:
    Code:
    AddHandler objFProcess.ErrorDataReceived, AddressOf consoleErrorHandler
    
    objFProcess.Start()
    
    objFProcess.BeginErrorReadLine()
    Ok, so based on your original code, the following should allow you to process thousands of images and log the output from standard error:
    VB.NET Code:
    1. Dim objFProcess As System.Diagnostics.Process
    2. Dim strFiles() As String
    3. Dim strEachFile As String
    4.  
    5. objFProcess = New System.Diagnostics.Process
    6. objFProcess.StartInfo.FileName = txtFMPEG.Text
    7. objFProcess.StartInfo.Arguments = "-y -f image2pipe -r 25 -s 1280x720 -vcodec bmp -i pipe:.bmp -crf 25.0 -vcodec libx264 -vf scale=1280:720 -coder 1 -rc_lookahead 60 -threads 0 g:\test.mp4"
    8. objFProcess.StartInfo.UseShellExecute = False
    9. objFProcess.StartInfo.CreateNoWindow = True
    10. objFProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
    11. objFProcess.StartInfo.RedirectStandardError = True
    12. objFProcess.StartInfo.RedirectStandardInput = True
    13.  
    14. AddHandler objFProcess.ErrorDataReceived, AddressOf consoleErrorHandler
    15.  
    16. objFProcess.Start()
    17.  
    18. 'initialise List used to store lines from StandardError (in Sub consoleErrorHandler)
    19. 'and start listening to StandardError
    20. lstCLIErr = New List(Of String)
    21. objFProcess.BeginErrorReadLine()
    22.  
    23.  
    24. strFiles = System.IO.Directory.GetFiles(txtIMGDir.Text, "*.bmp", IO.SearchOption.TopDirectoryOnly)
    25. For Each strEachFile In strFiles
    26.     Me.Text = System.IO.Path.GetFileNameWithoutExtension(strEachFile)
    27.     My.Application.DoEvents()
    28.  
    29.     'load bitmap from file
    30.     Using o2 As New System.Drawing.Bitmap(strEachFile)
    31.  
    32.         ' ##########################
    33.         'alter bitmap as needed here
    34.         ' ##########################
    35.  
    36.  
    37.         'save bitmap to memorystream first,
    38.         'then write MemoryStream to StandardInput's stream.
    39.         'We can't use the BitMap.Save(stream, format) method
    40.         'to write directly to the StandardInput stream
    41.         'because that method MUST write to position 0 in the stream.
    42.         'StandardInput stream won't be at postion 0
    43.         'when we need to save images to it.
    44.         Using ms As New MemoryStream
    45.             o2.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp)
    46.             ms.WriteTo(objFProcess.StandardInput.BaseStream)
    47.         End Using ' ms
    48.  
    49.     End Using ' o2
    50.  
    51. Next
    52.  
    53.  
    54. 'finished writing images to StandarInput
    55. objFProcess.StandardInput.Close()
    56.  
    57. objFProcess.WaitForExit()
    58.  
    59. objFProcess.Close()
    60. objFProcess.Dispose()
    61.  
    62.  
    63. ' #############################################
    64. 'lstCLIErr now holds output from standard error
    65. ' #############################################

    The changes I made are:
    1. Got rid of BinaryWriter (o1) as not being used in code given.
    2. Create BitMap directly from file instead of explicitly creating a FileStream and then using Image.FromStream method.
    3. Wrapped BitMap creation in Using...End Using block so it is disposed of properly.
    4. Save Bitmap to MemoryStream then write MemoryStream to StandardInput's Stream as discussed above in Post#5.
    5. Removed call to StandardError.ReadToEnd because we are now handling the ErrorDataReceived event.
    6. Added line to close StandardInput when all images have been written. Was previously being closed when the BinaryWriter was closed.


    You should think about getting rid of the call to My.Application.DoEvents(). It can often cause you unexpected problems. Using a BackgroundWorker might be a relatively simple alternative, or an awaitable Task would be preferred and is even simpler to code at a basic level (but can be a concept that is more difficult to wrap your head around).
    Last edited by Inferrd; Oct 22nd, 2019 at 05:41 AM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width