FFMPEG Video Converter with Progressbar VB.NET





5.00/5 (3 votes)
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.
- Link to MediaInfo: http://www.teejeetech.in/2013/01/mediainfo-wrapper-for-net-projects.html
- Link to ffmpeg: https://www.ffmpeg.org/download.html
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 theffmpeg standarderror out
TextBox
, to show save pathCombobox
, for preset options, and a menu stripLinkLabel
, you can use a button, instead I use this to hide theRichTextBox
- 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.
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