C#, Tools – Video Converter with ffmpeg

Last month I bought a new digital camera Canon PowerShot SX210IS 14.1 MP Digital Camera with 14x Wide Angle Optical Image Stabilized Zoom and 3.0-Inch LCD (Black) . My old one is somehow broken, the taken photos were not as good as before. So I decide to buy a new one with better video capturing feature. Canon PowerShot SX210IS can capture
– stunning HD movies with Dynamic mode for enhanced image stabilization when shooting movies using wide-angle settings or
– smooth HD video (720p) with stereo sound for a truly natural, high quality HD experience.
It sounds great, doesn’t it?

However, as you know, the file size of a HD video is always too big. It’s about over 100 MB for only some minutes which is a big disadvantage for sharing over internet. Therefore I would like to write a small tool basing on ffmpeg – an open source command line video converter – to convert the video from MOV to AVI format (can be played in any version of Windows Media Player ) and to reduce simultaneously the file size up to 90% of the original. The GUI of this tool is very simple as below

VidCon

This tool takes path to original video file as his input then call the ffmpeg with this syntax

ffmpeg.exe -i "inputfile" "outputfile"

to convert file into AVI. The important metadata like duration and fps will be displayed when user gives him the input video file. It is very simple tool because I do not write any code for video converting. I simply parse ffmpeg input / output and write this tool as ffmpeg GUI. There is nothing special in the code if you read this blog post before http://hintdesk.com/c-read-console-output-asynchronously/

Just using the same code of this post in combination with some regex rules you can read the metadata of input file as well as the current progress when converting

enum VideoProperties
{
	[DescriptionAttribute(@"[D|d]uration:.((\d|:|\.)*)")]
	Duration,
	[DescriptionAttribute(@"[s,].([0-9]+(?:\.[0-9]*)?) fps")]
	Fps,
	[DescriptionAttribute(@"frame=\s+([0-9]*)")]
	CurrentFrame,	
}

There is only a small problem with Drag and Drop on text box when I was writing this software because in the text box control of WPF, the Drag and Drop events are marked as handled and prevent us from handling these events ourselves. Therefore although we set the AllowDrop on true, the cursor is always shown as not drop allowed when we drop something on it. To solve this problem we must set the triggers for 3 events: PreviewDragEnter, PreviewDragOver, PreviewDrop and handle these events as below

<TextBox AllowDrop="True" Grid.Column="0" Text="{Binding SelectedFilePath}"   Name="txtIpodPath" VerticalAlignment="Center" Height="31">
	<i:Interaction.Triggers>                        
		<i:EventTrigger EventName="PreviewDragEnter">
			<cmd:EventToCommand Command="{Binding PreviewDragCommand, Mode=OneWay}" PassEventArgsToCommand="True" />
		</i:EventTrigger>
		<i:EventTrigger EventName="PreviewDragOver">
			<cmd:EventToCommand Command="{Binding PreviewDragCommand, Mode=OneWay}" PassEventArgsToCommand="True" />
		</i:EventTrigger>
		<i:EventTrigger EventName="PreviewDrop">
			<cmd:EventToCommand Command="{Binding PreviewDropCommand, Mode=OneWay}" PassEventArgsToCommand="True" />
		</i:EventTrigger>
	</i:Interaction.Triggers>
</TextBox>   
private RelayCommand<DragEventArgs> handleDropCommand;
public ICommand HandleDropCommand
{
	get
	{
		if (handleDropCommand == null)
			handleDropCommand = new RelayCommand<DragEventArgs>(e => HandleDropEvent(e));
		return handleDropCommand;
	}
}

private void HandleDropEvent(DragEventArgs e)
{
	if (e.Data == null)
	{
		return;
	}

	string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
	SelectedFilePath = files[0];
	ffmpegWrapper.ReadInputFile(SelectedFilePath);
}

private RelayCommand<DragEventArgs> previewDragCommand;
public ICommand PreviewDragCommand
{
	get
	{
		if (previewDragCommand == null)
			previewDragCommand = new RelayCommand<DragEventArgs>(e => HandlePreviewDragEvent(e));
		return previewDragCommand;
	}
}

private void HandlePreviewDragEvent(DragEventArgs e)
{
	e.Effects = DragDropEffects.All;
	e.Handled = true;
}


private RelayCommand<DragEventArgs> previewDropCommand;
public ICommand PreviewDropCommand
{
	get
	{
		if (previewDropCommand == null)
			previewDropCommand = new RelayCommand<DragEventArgs>(e => HandleDropEvent(e));
		return previewDropCommand;
	}
}

You can see that in the code above I use the same function to handle 2 events PreviewDragEnter and PreviewDragOver. Just allow all DragDropEffects and set the Handled on true to tell that we would like to handle these events ourselves. If you do not set Handled on true, you won’t get any information when catching the Drop event.

Maybe it’s interesting for you about the formula to calculate the number of frames of a video file : Frame = Duration * Fps. Using this information I can display the converting progress smoothly with a progress bar because ffmpeg does not give us any info about number of frames but he shows the current frame when he converts the video. Knowing total number of frames of video file in combining with current frame, we can estimate how long ffmpeg will take until finishing. In C#, the formula will be implemented as below.

public int Frame
{ 
	get 
	{
		TimeSpan tempTimeSpan = new TimeSpan();
		string[] timepieces = Duration.Split(new char[] { ':', '.' });
		if (timepieces.Length == 4)
		{
			 tempTimeSpan = new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
		}

		if (Duration != null && Fps != null)
			return (int)(tempTimeSpan.TotalSeconds * double.Parse(Fps, CultureInfo.InvariantCulture));
		else
			return 0;
	}
}

In this first version, I do not provide any advanced features so that one can set the frame rate,fps, codec or something like that. And I do not intend to build these features into this tool because I think as normal user I have no idea about frame rate or codec. In next version I will build only one feature more allowing user to set the size of output video. For example, user can set that he would like to have an AVI about 2 MB so that he can attach it in an email. The tool will change the video properties inside to reach the given output size.

In summary, this tool can be used to convert any video format to AVI format which has smaller file size and is compatible to any version of Windows Media Player meaning can be played under any version of Windows operating system. If you want to try it, you can easily download it here “VidCon – Video Converter with ffmpeg“. As normal no source code avaible for any tool.

4 thoughts on “C#, Tools – Video Converter with ffmpeg”

Leave a Reply

Your email address will not be published. Required fields are marked *