Change video quality in C#

(Note that this example was written in Visual Studio 2010.)

This post shows how you can load and save a video with a given video quality. Lately I’ve been recording screencast videos for my next book. Unfortunately I recorded several hours before I was told I had to use a splash screen before each video. Between planning, setup, recording, re-recording when I made big mistakes, and editing, I can only record about 5 to 10 minutes of video per hour of work, so I really didn’t want to re-record everything from scratch.

To avoid a week or so of extra work, I had to learn about Microsoft Expression Encoder. Encoder is a video capture and editing tool that you can download here. It’s not perfect, but it’s good enough for simple editing. It also has a free version that is restricted so you can only record videos of up to 10 minutes.

Encoder also provides an API that lets you write C# programs that build media projects. I used those to perform a few operations on my videos. (Although Encoder can do a lot more than what I needed.)

This example loads a WMV video and saves it in a new file with a different video quality. The picture above shows a clip taken from a videos that I saved with levels of quality ranging from 50 to 90. That picture has been scaled by a factor of 2 so it’s easier to see the loss of quality for the lower levels. On the right you can see the size of the video file for the levels of video quality. The lower quality results save you space.


The picture on the right shows the program in action. Select the name of the video file you want to load and the video quality. When you press Create, the program asks you for the name of the output file and then writes the video into that file with the selected video quality.

Before you start writing code to use the Encoder API, you should add references to these libraries:

  • Microsoft.Expression.Encoder
  • Microsoft.Expression.Encoder.Api2
  • Microsoft.Expression.Encoder.Types
  • Microsoft.Expression.Encoder.Utilities

You may also want to add the following using statements.

using Microsoft.Expression.Encoder;
using Microsoft.Expression.Encoder.Profiles;

The following code shows how the program creates the new video file.

private void btnCreate_Click(object sender, EventArgs e)
{
    if (sfdMerged.ShowDialog() != DialogResult.OK) return;
    Cursor = Cursors.WaitCursor;
    prgEncode.Value = 0;
    prgEncode.Visible = true;
    Refresh();

    try
    {
        // Create a job.
        using (Job job = new Job())
        {
            // Make a MediaItem containing the splash video.
            MediaItem media_item = new MediaItem(txtMovie.Text);
            job.MediaItems.Add(media_item);

            // Use the original size.
            media_item.OutputFormat.VideoProfile.Size =
                media_item.OriginalVideoSize;

            // Set the quality.
            media_item.OutputFormat.VideoProfile.Bitrate =
                new VariableQualityBitrate(trkQuality.Value);

            // Set the output directory.
            FileInfo file_info = new FileInfo(sfdMerged.FileName);
            job.OutputDirectory = file_info.DirectoryName;

            // Set the output file name.
            media_item.OutputFileName = file_info.Name;

            // Don't create a subdirectory.
            job.CreateSubfolder = false;

            // Install the progress event handler.
            job.EncodeProgress += job_EncodeProgress;

            // Encode.
            job.Encode();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }

    Cursor = Cursors.Default;
    prgEncode.Visible = false;
}

The code first uses a SaveFileDialog to let you select the output file name. If you select a file and click Save, the program displays the ProgressBar named prgEncode.

Next the program creates a Job object. It then makes a MediaItem representing the movie file and adds it to the Job.

The code then sets the MediaItem‘s size so the result uses the same dimensions as the original video.

It also sets the MediaItem‘s Bitrate property. The value it uses is a VariableQualityBitrate object initialized with the quality parameter you selected from the trackbar. A variable bitrate allows the result to use different bitrates for different parts of the video so complicated parts of the video might use more bits than simpler parts. The quality parameter makes the object set the bitrate’s bounds appropriately, although you can also set them explicitly (using a VariableConstrained object) or you can use a constant bitrate (using a ConstantBitrate object).

Next the code sets the job’s output directory and the media item’s output file name. To do that, the program gets a FileInfo object representing the output file you selected and uses that object’s DirectoryName and Name properties.

The code sets the job’s CreateSubfolder property to false to prevent the API from putting the result in a subdirectory, installs a progress event handler, and then calls the job’s Encode method. That method creates the output video file.

After the method finishes, the program hides its progress bar.

The following code shows the program’s progress event handler.

// Display progress.
private void job_EncodeProgress(object sender,
    EncodeProgressEventArgs e)
{
    prgEncode.Value = (int)e.Progress;
    Refresh();
}

That code simply sets the progress bar’s Value property to show the job’s progress. Note that the job performs 2 passes, so the progress bar will grow from 0 to 100, restart at 0, and grow to 100 again.

In the next few posts, I’ll describe a few other things you can do with the Encode API.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in animation, API, multimedia and tagged , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

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