Converting YouTube Videos Using ffmpeg

We now have the video on our hard drive in the Flash (FLV) format, and although we could build a simple HTML page to embed the Flash videos to watch them locally, what we really want to do is convert the video from FLV format to WMV (Zune) or MP4 (iTunes) format. To do that, we'll use an open source tool called ffmpeg, which is a C++ library and command-line tool for converting, resizing, or resampling media from one format to another, with more than 50 formats supported.

In its simplest form, you can call ffmpeg.exe by passing in two command-line arguments, the source file that you want to convert and the name of the new file you want it converted to. For example, we can convert a Flash video file named source.flv into an MP4 (MPEG-4) format file named destination.mp4 using the command shown in Example 4-26.

Example 4-26. Converting a flash video to the MP4 video format

ffmpeg.exe -i "source.flv" "destination.mp4"

To convert the source.flv file into a .wmv (Windows Media Video) file, add the -vcodec wmv2 command-line arguments, as shown in Example 4-27.

Example 4-27. Converting a flash video to the WMV video format

ffmpeg.exe -i "source.flv" -vcodec wmv2 "destination.wmv"

You can even add metadata—such as the author, title, and comment—to the newly converted video by setting additional ffmpeg.exe command-line arguments, as shown in Example 4-28.

Example 4-28. Setting metadata when converting a video

ffmpeg.exe -title "My Video Title" -author "Dan" -comment "best video ever" -i
"source.flv" -vcodec wmv2 "destination.wmv"

To call ffmpeg.exe programmatically, first we'll build a ConversionType enum to state the possible types of conversion our application allows (see Example 4-29 and Example 4-30).

Example 4-29.  C# code for the ConversionType enum

public enum ConversionType
{
  Mp4,
  Wmv
}

Example 4-30.  Visual Basic code for the ConversionType enum

Public Enum ConversionType
  Mp4
  Wmv
End Enum

We want to programmatically call the ffmpeg.exe console application from code using the System.Diagnostics.Process class. The call to ffmpeg is wrapped in the VideoConverter class, which has one method, ConvertFlv, with multiple overloads. The ConvertFlv method overload we'll want to use accepts an InnerTubeVideo and a ConversionType enum (MP4 or WMV). We use this overload because we'll use the video's title, author, and description to set the video's metadata, as described in Example 4-28. Since these fields might contain illegal characters, in which case ffmpeg.exe would not work, we will use the ReplaceIllegalCharacters method to clean them up.

As you can see in Example 4-31 and Example 4-32, we are building the command-line arguments to pass into ffmpeg.exe based on the type of conversion we are doing (MP4 or WMV).

Example 4-31.  C# code for setting ffmpeg parameters

public static void ConvertFlv(InnerTubeVideo source, ConversionType conversion)
{
  string title = FileHelper.ReplaceIllegalCharacters(source.Title);
  string author = FileHelper.ReplaceIllegalCharacters(source.Author);
  string description = FileHelper.ReplaceIllegalCharacters(source.Description);

  //set values based on switch
  string cmdLineArgs = String.Empty;
  string destination = String.Empty;

  switch (conversion)
  {
    case ConversionType.Mp4:
    //ffmpeg.exe -title "Chocolate Rain" -author "TayZonday" -comment "Original
    //Song by Tay Zonday" -i "Chocolate Rain.flv" "Chocolate Rain.mp4"
      destination = source.DownloadedMp4;
      cmdLineArgs = String.Format(" -title \"{0}\" -author \"{1}\" -comment \"{2}\"
        -i \"{3}\" \"{4}\"",title, author, description, source.DownloadedFlv,
        destination);
    break;
    case ConversionType.Wmv:
    //ffmpeg.exe -title "Chocolate Rain" -author "TayZonday" -comment "Original
    //Song by Tay Zonday" -i "Chocolate Rain.flv" -vcodec wmv2 "Chocolate Rain.wmv"
      destination = source.DownloadedWmv;
      cmdLineArgs = String.Format(" -title \"{0}\" -author \"{1}\" -comment \"{2}\"
      -i \"{3}\" -vcodec wmv2 \"{4}\"", title, author, description,
      source.DownloadedFlv, destination);
    break;
  }
  ConvertFlv(source.DownloadedFlv, destination, cmdLineArgs);
}

Example 4-32.  Visual Basic code for setting ffmpeg parameters

Public Shared Sub ConvertFlv(ByVal source As InnerTubeVideo, ByVal conversion _
  As ConversionType)
  Dim title As String = FileHelper.ReplaceIllegalCharacters(source.Title)
  Dim author As String = FileHelper.ReplaceIllegalCharacters(source.Author)
  Dim description As String = FileHelper.ReplaceIllegalCharacters(source.Description)

  'set values based on switch
  Dim cmdLineArgs As String = String.Empty
  Dim destination As String = String.Empty
  Select Case conversion
    Case ConversionType.Mp4
      'ffmpeg.exe -title "Chocolate Rain" -author "TayZonday" -comment "Original Song
      'by Tay Zonday" -i "Chocolate Rain.flv" "Chocolate Rain.mp4"
      destination = source.DownloadedMp4
      cmdLineArgs = String.Format(" -title ""{0}"" -author ""{1}"" " & _
        "-comment ""{2}"" -i ""{3}"" ""{4}""", title, author, _
        description, source.DownloadedFlv, destination)
   Case ConversionType.Wmv
    'ffmpeg.exe -title "Chocolate Rain" -author "TayZonday" -comment "Original Song
    'by Tay Zonday" -i "Chocolate Rain.flv" -vcodec wmv2 "Chocolate Rain.wmv"
    destination = source.DownloadedWmv
    cmdLineArgs = String.Format(" -title ""{0}"" -author ""{1}"" -comment " & _
      " ""{2}"" -i ""{3}"" -vcodec wmv2 ""{4}""", title, author, description, _
      source.DownloadedFlv, destination)
  End Select
  ConvertFlv(source.DownloadedFlv, destination, cmdLineArgs)
 End Sub

As you may have noticed in Example 4-31 and Example 4-32, the last line of code calls another overload for the ConvertFlv method, which actually calls ffmpeg from the command line, which we'll discuss next.

In Example 4-33 and Example 4-34, the ConvertFlv method code includes the location of the ffmpeg.exe executable. The file itself is distributed in the SharedUtilities directory in an ffmpeg folder, so we can call Environment.CurrentDirectory to point to the executable and store the path into the exePath variable.

We'll also make sure that we have the source file and don't have the destination file. Assuming we have everything to run, we create a process and set some properties, such as the command-line arguments, the location of the .exe file, and other properties that will keep the console window from appearing while we convert a file. To get everything running, you call the Start method of the convert class. Since ffmpeg.exe will automatically close when it is finished converting a file, we'll use the Wait ForExit() method, which means that the ConvertFlv method will not return until the conversion is complete.

Example 4-33.  C# code to create a process and call ffmpeg.exe

private static void ConvertFlv(string sourceFile, string destination,
  string cmdLineArgs)
{
  //point to ffmpeg conversion tool
  string exePath = Path.Combine(Environment.CurrentDirectory, @"ffmpeg\ffmpeg.exe");

  //ensure sourceFile files exist and the destination doesn't
  if (File.Exists(sourceFile) && File.Exists(exePath) && !File.Exists(destination))
  {
    //Start a Process externally as we're converting from the command line
    using (Process convert = new Process())
    {
      //Set properties
      convert.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
      convert.StartInfo.CreateNoWindow = true;
      convert.StartInfo.RedirectStandardOutput = true;
      convert.StartInfo.UseShellExecute = false;
      convert.StartInfo.Arguments = cmdLineArgs;
      convert.StartInfo.FileName = exePath;
      convert.Start();
      convert.WaitForExit();
    }
  }
}

Example 4-34.  Visual Basic code to create a process and call ffmpeg.exe

Private Shared Sub ConvertFlv(ByVal sourceFile As String, ByVal destination As _
  String, ByVal cmdLineArgs As String)
  'point to ffmpeg conversion tool
  Dim exePath As String = Path.Combine(Environment.CurrentDirectory, _
    "ffmpeg\ffmpeg.exe")

  'ensure sourceFile files exist and the destination doesn't
  If File.Exists(sourceFile) AndAlso File.Exists(exePath) AndAlso _
    (Not File.Exists(destination)) Then

    'Start a Process externally as we're converting from the command line
    Using convert As New Process()
      'Set properties
      convert.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
      convert.StartInfo.CreateNoWindow = True
      convert.StartInfo.RedirectStandardOutput = True
      convert.StartInfo.UseShellExecute = False
      convert.StartInfo.Arguments = cmdLineArgs
      convert.StartInfo.FileName = exePath
      convert.Start()
      convert.WaitForExit()
    End Using
  End If
 End Sub

Now that we have converted the Flash videos into MP4 and/or WMV files, let's show how you can sync them to iTunes or the Zune client software.

Get Coding4Fun now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.