Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

FFMPEG Video Converter with Progressbar VB.NET

0.00/5 (No votes)
24 Jan 2016 2  
How to make a video converter that shows the conversion progress to the user using ffmpeg

Introduction

Today, we are going to make a video converter using ffmpeg and VB.NET 2010. The source files will be included, except MediaInfo.dll, MediaInfoNet.dll and ffmpeg, you must download these yourself but a quick Google search will suffice. Once you have downloaded these files, copy both medialinfo.dll files and ffmpeg.exe to your project/bin folder.

To follow along, here's what you will need on your form: 5 buttons, add video, browse, convert, cancel, exit, a progressbar, 17 labels for showing imported video stats (optional) and a couple for general labeling purposes.

  • RichTextBox, to show the ffmpeg standarderror out
  • TextBox, to show save path
  • Combobox, for preset options, and a menu strip
  • LinkLabel, you can use a button, instead I use this to hide the RichTextBox
  • Background Worker. this is named Bgw1 in the source files

Add the following items to the menustrip, file, under file add: Add video, SaveTo, and Exit. Next on the menustrip is Clear Information (optional), and I add a Convert, this is also optional.

Be sure to name your buttons and labels for example, btnAddVideo, lblFrameCount, etc. it's easer when coding.

Screenshot.png

Notice how the preset combobox is located above the save location. This is to make the user select a preset first in order to give the savefiledialog filter the correct value, for example preset option1 could be High Quality AVI and preset option2 could be High Quality MP4, so when the user browses for a save location, the correct file extension is added automatically.

Background

Many tutorials use the ffmpeg standard error to parse the time to try and calculate the remaining time left of the conversion process. I had many problems trying this, so I decided to parse the frame value of the standard error out. We do this using mediainfoNet, MediaInfoNet.dll calls MediaInfo.dll, so make sure both are located in your project/bin folder.

Using the Code

'when we  want to hide the ffmpeg standard error out the form is at the normal height
'when we show the ffmpeg out we make the RichTextBox visible and make the form height bigger

Imports MediaInfoNET ' Add a reference to MediaInfoNET also
Imports System.IO

Public Class Form1

    Dim OFD As OpenFileDialog   'Declare new openfiledialog
    Dim SFD As SaveFileDialog   'Declare new savefiledialog
    Dim mFile As MediaFile      '
    Dim InputFile As String     '
    Dim OutputFile As String    '
    Dim pathResult As String    '
    Dim FCount As Integer       '

    Dim KB As Integer'
    Dim MB As Integer' used to calculate file size
    Dim GB As Integer'

    Private prcFFMPEG As New Process                           
    Dim psiProcInfo As New System.Diagnostics.ProcessStartInfo 
    Dim strFFCMD As String                                     
    Dim ffReader As StreamReader                               
    Dim strFFOUT As String                                     
    Dim currentFramestr As String                              
    Dim currentFrameInt As Integer


    'On Load
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
	Handles MyBase.Load
        RichTextBox1.Visible = False    'hide the richtextbox
        Me.Height = 441                 'make sure the form starts at it's normal height
        'Label11.Text = "0%"            'ignore this line
        ProgressBar1.Value = 0          'set the progressbar to 0
        Button5.Enabled = False      'cancel button
        '
        KB = 1024
        MB = KB * 1024      ' for calculating the filesize 
        GB = MB * 1024
        '

    End Sub

    'Show Conversion Information
    Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, _
    ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked

        If Me.Height = 441 Then             'is it at normal size
            Me.Height = 508                 'make the form bigger
            RichTextBox1.Visible = True     'make the richtextbox visible
            Label12.Visible = False
        Else
            Me.Height = 441                 'return the form to normal
            RichTextBox1.Visible = False    'hide the richtextbox
            Label12.Visible = True
        End If

  End Sub

    'Add Button/btnAddVideo
    Private Sub Button1_Click(ByVal sender As System.Object, _
    	ByVal e As System.EventArgs) Handles Button1.Click
        OFD = New OpenFileDialog    'Declare OFD an a new filedialog box

        If OFD.ShowDialog = Windows.Forms.DialogResult.OK _
        	Then    ' has the user selected a file and pressed ok
            mFile = New MediaFile(OFD.FileName)    'Declare the filename as a new MediaInfo Object
            InputFile = OFD.FileName               'set the ffmpeg input file
            pathResult = Path.GetFileNameWithoutExtension_
            (OFD.FileName) 'get the filename without it's extension
            Label3.Text = "Name: " & _
            pathResult  'display the filename without it's extension

            If mFile.FileSize > 1070000000 _
            Then    'if the input file is larger than 1 GB
                Label4.Text = "FileSize: " & String.Format("{0:0.00}", _
                mFile.FileSize / KB / MB) & " GB."   'Display filesize in GB
            Else
                Label4.Text = "FileSize: " & String.Format("_
                {0:0.00}", mFile.FileSize / MB) & " MB."   'Display the filesize as MB
            End If

            Label5.Text = "Duration: " & _
            	mFile.Video(0).DurationString  'Display the video file duration/runtime
            Label6.Text = "Format: " & _
           		mFile.Video(0).Format          'Display the video format
            Label7.Text = "Codec: " & _
            	mFile.Video(0).CodecID          'Display the codec id
            Label8.Text = "Resolution: " & _
            	mFile.Video(0).FrameSize   'Display the framesize/Resolution
            Label9.Text = "Framerate: " & _
            	mFile.Video(0).FrameRate & "fps"  'Display the frame rate

Label14.Text = "NumberOfFrames: " & _
	mFile.Video(0).SourceFile.FrameCount.ToString 'Get the number of frames    
            Label15.Text = "VideoStreams: " & mFile.Video(0).StreamType & _
            " " & mFile.Video(0).StreamIndex  'Display the video stream type and index

            Label16.Text = "AudioStreams: " & mFile.Audio(0).StreamType & _
            " " & mFile.Video(0).StreamIndex  'Display the audio stream type and index

            Label1.Text = "AudioCodec: " & _
            mFile.Audio(0).CodecID       'Display the Audio codec id
            Label17.Text = "Audio Bitrate: " & _
            mFile.Audio(0).Bitrate   'Display the audio bitrate
            Label18.Text = "Audio Samplerate: " & _
            mFile.Audio(0).SamplingRate   'Display the audio samplerate

            FCount = Integer.Parse_
            (mFile.Video(0).SourceFile.FrameCount) 'Convert the number of frames to an integer

            'ProgressBar1.Maximum = FCount + 10     'ignore this for testing
            'Label12.Text = ProgressBar1.Maximum    'ignore this for testing
        End If

    End Sub ' Add exactly the same for the add video menustrip item


    'Save Button
    Private Sub Button2_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles Button2.Click
        SFD = New SaveFileDialog  'declare SFD as a new dialogbox
        SFD.AddExtension = True   'auto add the extension
        SFD.Filter = ""

        ''''''' These filter options must be set now before you show the dialog box ''''''''''''
              ' only 2 preset options will be used as an example but you can add as many as you like

        If ComboBox1.SelectedIndex = 1 Then
            SFD.Filter = "Mp4 (.mp4)|*.mp4"
        End If
        If ComboBox1.SelectedIndex = 2 Then
            SFD.Filter = "Mp4 (.mp4)|*.mp4"
        End If
       
        '''''''''''''''''''''''''''''''''''''''''
        If SFD.ShowDialog = Windows.Forms.DialogResult.OK Then  'has the user selected a file 
								'and pressed ok
            TextBox1.Text = SFD.FileName        'display the filename and path
            OutputFile = SFD.FileName           'set the ffmpeg output filename 
        End If

    End Sub

   ' Main Conversion Process
   Private Sub Convert()   ' function Convert() here is the actual conversion process

        Control.CheckForIllegalCrossThreadCalls = False   'Check for illegal cross threads 
     
        ''''''''''''''''
        'set presets here 'Note Combobox indexes start at 0 not 1 so combobox1.index 0 is blank
        'Chr(34) is the " character
        'we pass the ffmpeg command as a string

        If ComboBox1.SelectedIndex = 1 Then ' High Quality AVI option
            strFFCMD = " -i " & Chr(34) & InputFile & Chr(34) & _
            " -c:v libx264 -s 1280x720 -pix_fmt yuv420p -qp 20 -profile high444 _
            -c:a libvo_aacenc -b:a 128k -ar 44100 -ac 2 " & OutputFile
        End If

        If ComboBox1.SelectedIndex = 2 Then ' High Quality MP4 option
            strFFCMD = " -i " & Chr(34) & InputFile & Chr(34) & " _
            -c:v libx264 -s 1280x720 -pix_fmt yuv420p -qp 20 -profile high444 _
            -c:a libvo_aacenc -b:a 128k -ar 44100 -ac 2 " & OutputFile
        End If
        '''''''''''''''''

        'start Main Process
        psiProcInfo.FileName = Application.StartupPath + "\ffmpeg.exe"  'Location Of FFMPEG.EXE
        psiProcInfo.Arguments = strFFCMD         'start ffmpeg with command strFFCMD string
        psiProcInfo.UseShellExecute = False      'use the shell execute command we always want no
        psiProcInfo.WindowStyle = ProcessWindowStyle.Hidden    'hide the ffmpeg process window
        psiProcInfo.RedirectStandardError = True             'Redirect the error out so we can read it
        psiProcInfo.RedirectStandardOutput = True         'Redirect the standard out so we can read it
        psiProcInfo.CreateNoWindow = True                 'We dont create the ffmpeg window
        prcFFMPEG.StartInfo = psiProcInfo           'ffmpeg process start information = all above 

        prcFFMPEG.Start() 'Start Process

        'ffmpeg uses StandardErrorOut instead of StandardOut
        ffReader = prcFFMPEG.StandardError 'Enable Error Checking For FFMPEG.EXE

        Do       '' Bgw1 = Backgroundworker1
            If Bgw1.CancellationPending Then ' Have we pressed Cancel?
                Exit Sub

            End If

            Button5.Enabled = True      'Enable the cancel button
            Button3.Enabled = False     'Disable the convert button

            strFFOUT = ffReader.ReadLine        'read each line from ffreader
            RichTextBox1.Text = strFFOUT        'Show each read line in the richtextbox

            'Get the progress from the current encoded frame
            If strFFOUT.Contains("frame=") Then         'if the strFFOut contains the string
                currentFramestr = Mid(strFFOUT, 7, 6)   'grab the next part after the string 'frame='
                currentFrameInt = CInt(currentFramestr) 'convert the string back to an integer
            End If

            'Calculate the percentage of the progressbar
            Dim percentage As String = _
            CType((ProgressBar1.Value / ProgressBar1.Maximum * 100), Integer).ToString & "%"

            ' report progress
            ProgressBar1.Maximum = FCount + 1000    'MediaInfo does not always 
            		'get a accurate frame count so always add 1000 on top

            ProgressBar1.Value = (currentFrameInt)  'the current value is the current encoded frame
            Label12.Text = "Current Encoded Frame: _
            	" & currentFrameInt      'show the current frame 
            Label11.Text = percentage               'show the percentage in a label
            'Label12.Text = ProgressBar1.Maximum 'for testing purposes

            ' Loop until done
        Loop Until prcFFMPEG.HasExited And strFFOUT = Nothing Or strFFOUT = ""

        If ProgressBar1.Value <> ProgressBar1.Maximum Then
            ProgressBar1.Value = ProgressBar1.Maximum   'make the progressbar hit its maximum 
							'on completion
        End If

        MsgBox("The Conversion Process has Completed.", _
        	MsgBoxStyle.Information, "Finished.")   'display on completion

        Button5.Enabled = False     'Disable the cancel button
        Button3.Enabled = True      'Reenable the convert button
        ProgressBar1.Value = 0      'reset the progressbar value to 0
        Label11.Text = _ProgressBar1.Value & "%"     'get the progressbar value 
        					'and report it as percent for visual purposes

        Label12.Text = "Current Encoded Frame: "
        If Me.Height = 508 Then     'if the show detailed information button 
        				'was pressed reset the form height back to normal
            Me.Height = 441
            RichTextBox1.Visible = False    'Disable the richtextbox
        End If

    End Sub


    ' BackgroundWorker1DoWork
    Private Sub Bgw1_DoWork(ByVal sender As System.Object, _
    ByVal e As System.ComponentModel.DoWorkEventArgs) Handles Bgw1.DoWork
        Convert()   'run the function to convert
    End Sub


    'Convert button/btnConvert add the same to the convert menustrip item
    Private Sub Button3_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles Button3.Click
        'if no input then return an error
        If InputFile = "" Then
            MsgBox("No input file selected please press the _
            'Add File' button.", MsgBoxStyle.Exclamation, "Error")
        Else
            Bgw1.RunWorkerAsync()
        End If

    End Sub


    'Cancel button 
    Private Sub Button5_Click(ByVal sender As System.Object, _
    	ByVal e As System.EventArgs) Handles Button5.Click
        Bgw1.CancelAsync()
        prcFFMPEG.Kill()

        MsgBox("The Conversion Process has been Cancelled.", _
        	MsgBoxStyle.Information = MsgBoxStyle.YesNo, "Information")

        ProgressBar1.Value = 0
        Label11.Text = ProgressBar1.Value & "%"
        If Me.Height = 508 Then     'if the show detailed information button 
        			'was pressed reset the form height back to normal
            Me.Height = 441
            RichTextBox1.Visible = False    'Disable the richtextbox
            Label12.Text = "Current Encoded Frame: "
        End If
    End Sub

    ' function Clear All
    Private Sub ClearAllInfo()

        Label3.Text = "Name:    "
        Label4.Text = "FileSize: "
        Label4.Text = "FileSize: "
        Label5.Text = "Duration: "
        Label6.Text = "Format: "
        Label7.Text = "Codec: "
        Label8.Text = "Resolution: "
        Label9.Text = "Framerate: "
        Label14.Text = "NumberOfFrames: "
        Label15.Text = "VideoStreams: "
        Label16.Text = "AudioStreams: "
        Label1.Text = "AudioCodec: "
        Label17.Text = "Audio Bitrate: "
        Label18.Text = "Audio Samplerate: "
        InputFile = ""
        OutputFile = ""
        TextBox1.Clear()
    End Sub

    ' Clear Information
    Private Sub ClearInformationToolStripMenuItem_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles ClearInformationToolStripMenuItem.Click

        ClearAllInfo()  'call the function to clear all fields 

    End Sub

'any other options you see in the image or the included project files 
'that are not in the code above are optional

Points of Interest

The code for the progressbar was surprisingly accurate with small sized videos, but for some reason mediainfo didn't get the same frame count because we are converting, changing fps, so to compensate we make sure the progressbar maximum is always 1000 higher than the current value.

History

  • 24th January, 2016: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here