Introduction
This is a simple video converter developed with .NET while playing with ffmpeg.
Ffmpeg is an open source command line audio / video converter. ffmpeg uses command line arguments for its conversion and this is what we are going to do with our .NET application. We will execute ffmpeg from our application and send these parameters to ffmpeg without displaying the command line window.
Download the source code here to see how it works.
Background
The application uses a background worker. BackgroundWorker
prevents our form from hanging while the conversion is in progress. I had that problem whenever I started the ffmpeg process.
The BackgroundWorker
component gives you the ability to execute time-consuming operations asynchronously ("in the background"), on a thread different from your application's main UI thread. To use a BackgroundWorker
, you simply tell it what time-consuming worker method to execute in the background, and then you call the RunWorkerAsync
method. Your calling thread continues to run normally while the worker method runs asynchronously. When the method is finished, the BackgroundWorker
alerts the calling thread by firing the RunWorkerCompleted
event, which optionally contains the results of the operation. (MSDN 2008)
Ffmpeg is freely available on the internet. You need to have the binary version, i.e.,
ffmpeg.exe in the application directory of your project. It is included in the zip file.
How to Create the Converter
Let's get started by using ffmpeg.exe. Open the command prompt in your Windows environment and navigate to the directory where ffmpeg.exe is located.
Now let's say ffmpeg is located in C:\ i.e., C:\ffmpeg.exe, we navigate to our C: directory on the command prompt and type in a few commands into ffmpeg. Let's say we have a .avi video file in our C: directory and want to convert that video to a .flv file, we just need to enter the command:
ffmpeg -i input.avi output.flv
Note that different arguments can be parsed to ffmpeg for various kinds on conversion, but for the purpose of this tutorial, we will stick to the very basic commands needed to convert our video file. What that argument above does is that it creates a converted video version of the file input.avi to output.flv in our C: directory. Basically, this is what our program is going to do but this time around without the command prompt. We will be sending the arguments through our program to ffmpeg. For more documentation on how to use ffmpeg, checkout this FFmpeg site...
Now let's begin with our program in .NET.
Step 1
Insert three textboxes, a trackbar, a background worker, open and save dialog boxes and four command buttons into your new form. You also need to place ffmpeg.exe in the /bin folder of your application directory.
The dialogSave
and dialogOpen
tools enable us to specify where our file is located and where we want to save the output file. The backgroundWorker
tool allows us to run the ffmpeg process in a different thread from our application's UI thread, this allows our application to run properly without interruption from ffmpeg process while the actual conversion is in progress.
Step 2
Let's create a function that performs the conversion:
Function startConversion()
Control.CheckForIllegalCrossThreadCalls = False
Dim input As String = Me.dlgOpen.FileName Dim output As String = Me.dlgSave.FileName
Dim exepath As String = Application.StartupPath + "\bin\ffmpeg.exe"
Dim quality As Integer = TrackBar1.Value * 2
Dim startinfo As New System.Diagnostics.ProcessStartInfo
Dim sr As StreamReader
Dim cmd As String = " -i """ + input + """ -ar 22050 -qscale " _
& quality & " -y """ + output + """"
Dim ffmpegOutput As String
startinfo.FileName = exepath
startinfo.Arguments = cmd
startinfo.UseShellExecute = False
startinfo.WindowStyle = ProcessWindowStyle.Hidden
startinfo.RedirectStandardError = True startinfo.RedirectStandardOutput = True startinfo.CreateNoWindow = True
proc.StartInfo = startinfo
proc.Start() Me.lblInfo.Text = "Conversion in progress... Please wait..."
sr = proc.StandardError Me.btnStart.Enabled = False
Do
If BackgroundWorker1.CancellationPending Then
Exit Function
End If
ffmpegOutput = sr.ReadLine Me.txtProgress.Text = ffmpegOutput
Loop Until proc.HasExited And ffmpegOutput = Nothing Or ffmpegOutput = ""
Me.txtProgress.Text = "Finished !"
Me.lblInfo.Text = "Completed!"
MsgBox("Completed!", MsgBoxStyle.Exclamation)
Me.btnStart.Enabled = True
Return 0
End Function
We created a function startConversion()
which performs the actual conversion of the file with ffmpeg.
Setting Control.CheckForIllegalCrossThreadCalls
to False
prevents Visual Studio from catching calls on a different thread that accesses a control's Handle
property when an application is being debugged because we will be calling our controls from another thread separate from our form’s thread, i.e., the backgroundWorker
process where our function is located.
Dim cmd As String = " -i """ + input + """ -ar 22050 -qscale " _
& quality & " -y """ + output + """"
This command is parsed to ffmpeg.exe to do the actual conversion for us.
"-i input
" specifies our input file, e.g., sample.avi, the "-ar 22050
" specifies the audio sampling frequency as 22050 which is common for flash video files, we can also specify a different one like 44100 which is actually the default in ffmpeg. "-qscale
" specifies the quality of the video e.g.,. "-qscale 2
" is of higher quality than "-qscale 10
". The value of our quality variable is retrieved from the trackbar. We want our users to specify the quality of the video they want using the trackbar.
Note that startinfo
contains properties that allows us to specify that our process is being run. The WindowStyle
property is set to hidden, this prevents the command prompt console from showing.
RedirectStandardOutput
property is used to redirect whatever is displayed on the command prompt to a different control. But ffmpeg uses standardError
to display its conversion output, this is why we have to use the RedirectStandardError
and set its value to true
.
BackgroundWorker1.CancellationPending
shows that a cancellation request was sent to terminate the process, we use this property to exit our function, this actually kills the ffmpeg process.
A textbox ffmpegOutput
is used to display the output from ffmpeg by assigning sr.ReadLine
to it.
Step 3
On the startButton
, insert the following code:
Private Sub btnStart_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnStart.Click
If txtOpen.Text = "" Or txtOpen.Text <> dlgOpen.FileName Then
MsgBox("Select a file to convert", MsgBoxStyle.Information, "Select a file")
Exit Sub
ElseIf txtSave.Text = "" Or txtSave.Text <> dlgSave.FileName Then
MsgBox("Select your output filename", MsgBoxStyle.Information, "Select a file")
Exit Sub
End If
BackgroundWorker1.RunWorkerAsync() ‘start the background worker
End Sub
RunWorkerAsync()
action of the backgroundWorker
is used to start the process. What this does is that it executes the startConversion()
function we inserted in the BackgroundWorker1_DoWork
procedure.
Step 4
On the save dialog tool, insert the following code:
Private Sub dlgSave_FileOk(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.CancelEventArgs) Handles dlgSave.FileOk
dlgSave.OverwritePrompt = True
dlgSave.DereferenceLinks = True
dlgSave.CreatePrompt = True
dlgSave.DefaultExt = ".flv" txtSave.Text = dlgSave.FileName
End Sub
Private Sub btnStop_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnStop.Click
On Error GoTo handle
BackgroundWorker1.CancelAsync()
If btnStart.Enabled = False Then
lblInfo.Text = ("Conversion Canceled!")
MsgBox("Conversion has been cancelled!", MsgBoxStyle.Exclamation)
btnStart.Enabled = True
Else
MsgBox("Start conversion first", MsgBoxStyle.Critical)
End If
proc.Kill()
handle:
Exit Sub
End Sub
On our stop button, we send a CancelAsync()
request to the backgroundWorker
. This request enables us to handle anything we need to display or do before we end the process. For example, we can display a message box that confirms cancellation and also perform a different task on the process before the process ends.
Step 5
The backgroundWorker
calls the conversion function here:
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
startConversion()
End Sub
Points of Interest
This application only converts different video files to .flv (Flash video). To save your videos in any other format, simply add more video file extensions to the save dialog box filter property. I hope you’ll have fun with this.
History
Just the first application.
Regards,
Tunde Olabenjo