Transcode media files

You can use the Windows.Media.Transcoding APIs to transcode video files from one format to another.

Transcoding is the conversion of a digital media file, such as a video or audio file, from one format to another. This is usually done by decoding and then re-encoding the file. For example, you might convert a Windows Media file to MP4 so that it can be played on a portable device that supports MP4 format. Or, you might convert a high-definition video file to a lower resolution. In that case, the re-encoded file might use the same codec as the original file, but it would have a different encoding profile.

Set up your project for transcoding

In addition to the namespaces referenced by the default project template, you will need to reference these namespaces in order to transcode media files using the code in this article.

using Windows.Storage;
using Windows.Media.MediaProperties;
using Windows.Media.Transcoding;

Select source and destination files

The way that your app determines the source and destination files for transcoding depends on your implementation. This example uses a FileOpenPicker and a FileSavePicker to allow the user to pick a source and a destination file.

var openPicker = new Windows.Storage.Pickers.FileOpenPicker();

openPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
openPicker.FileTypeFilter.Add(".wmv");
openPicker.FileTypeFilter.Add(".mp4");

StorageFile source = await openPicker.PickSingleFileAsync();

var savePicker = new Windows.Storage.Pickers.FileSavePicker();

savePicker.SuggestedStartLocation =
    Windows.Storage.Pickers.PickerLocationId.VideosLibrary;

savePicker.DefaultFileExtension = ".mp4";
savePicker.SuggestedFileName = "New Video";

savePicker.FileTypeChoices.Add("MPEG4", new string[] { ".mp4" });

StorageFile destination = await savePicker.PickSaveFileAsync();

Create a media encoding profile

The encoding profile contains the settings that determine how the destination file will be encoded. This is where you have the greatest number of options when you transcode a file.

The MediaEncodingProfile class provides static methods for creating predefined encoding profiles:

Methods for creating Audio-only encoding profiles

Method Profile
CreateAlac Apple Lossless Audio Codec (ALAC) audio
CreateFlac Free Lossless Audio Codec (FLAC) audio.
CreateM4a AAC audio (M4A)
CreateMp3 MP3 audio
CreateWav WAV audio
CreateWmv Windows Media Audio (WMA)

Methods for creating audio / video encoding profiles

Method Profile
CreateAvi AVI
CreateHevc High Efficiency Video Coding (HEVC) video, also known as H.265 video
CreateMp4 MP4 video (H.264 video plus AAC audio)
CreateWmv Windows Media Video (WMV)

The following code creates a profile for MP4 video.

MediaEncodingProfile profile =
    MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD720p);

The static CreateMp4 method creates an MP4 encoding profile. The parameter for this method gives the target resolution for the video. In this case, VideoEncodingQuality.hd720p means 1280 x 720 pixels at 30 frames per second. ("720p" stands for 720 progressive scan lines per frame.) The other methods for creating predefined profiles all follow this pattern.

Alternatively, you can create a profile that matches an existing media file by using the MediaEncodingProfile.CreateFromFileAsync method. Or, if you know the exact encoding settings that you want, you can create a new MediaEncodingProfile object and fill in the profile details.

Transcode the file

To transcode the file, create a new MediaTranscoder object and call the MediaTranscoder.PrepareFileTranscodeAsync method. Pass in the source file, the destination file, and the encoding profile. Then call the TranscodeAsync method on the PrepareTranscodeResult object that was returned from the async transcode operation.

MediaTranscoder transcoder = new MediaTranscoder();

PrepareTranscodeResult prepareOp = await
    transcoder.PrepareFileTranscodeAsync(source, destination, profile);

if (prepareOp.CanTranscode)
{
    var transcodeOp = prepareOp.TranscodeAsync();

    transcodeOp.Progress +=
        new AsyncActionProgressHandler<double>(TranscodeProgress);
    transcodeOp.Completed +=
        new AsyncActionWithProgressCompletedHandler<double>(TranscodeComplete);
}
else
{
    switch (prepareOp.FailureReason)
    {
        case TranscodeFailureReason.CodecNotFound:
            System.Diagnostics.Debug.WriteLine("Codec not found.");
            break;
        case TranscodeFailureReason.InvalidProfile:
            System.Diagnostics.Debug.WriteLine("Invalid profile.");
            break;
        default:
            System.Diagnostics.Debug.WriteLine("Unknown failure.");
            break;
    }
}

Respond to transcoding progress

You can register events to respond when the progress of the asynchronous TranscodeAsync changes. These events are part of the async programming framework for Universal Windows Platform (UWP) apps and are not specific to the transcoding API.

void TranscodeProgress(IAsyncActionWithProgress<double> asyncInfo, double percent)
{
    // Display or handle progress info.
}

void TranscodeComplete(IAsyncActionWithProgress<double> asyncInfo, AsyncStatus status)
{
    asyncInfo.GetResults();
    if (asyncInfo.Status == AsyncStatus.Completed)
    {
        // Display or handle complete info.
    }
    else if (asyncInfo.Status == AsyncStatus.Canceled)
    {
        // Display or handle cancel info.
    }
    else
    {
        // Display or handle error info.
    }
}

Encode a metadata stream

Starting with Windows 10, version 1803, you can include timed metadata when transcoding media files. Unlike the video transcoding examples above, which use the built-in media encoding profile creation methods, like MediaEncodingProfile.CreateMp4, you must manually create the metadata encoding profile to support the type of metadata you are encoding.

This first step in creating a metadata incoding profile is to create a [TimedMetadataEncodingProperties] object that describes the encoding of the metadata to be transcoded. The Subtype property is a GUID that specifies the type of the metadata. The encoding details for each metadata type is proprietary and is not provided by Windows. In this example, the GUID for GoPro metadata (gprs) is used. Next, SetFormatUserData is called to set a binary blob of data describing the stream format that is specific to the metadata format. Next, a TimedMetadataStreamDescriptor(https://docs.microsoft.com/uwp/api/windows.media.core.timedmetadatastreamdescriptor) is created from the encoding properites, and a track label and name are to allow an application reading the endcoded stream to identify the metadata stream and optionally display the stream name in the UI.

TimedMetadataEncodingProperties encodingProperties = new TimedMetadataEncodingProperties
{
    Subtype = "{67706D64-BF10-48B4-BC18-593DC1DB950F}"
};
byte[] streamDescriptionData = GetStreamDescriptionDataForGpmdEncodingSubtype();
encodingProperties.SetFormatUserData(streamDescriptionData);

TimedMetadataStreamDescriptor descriptor = new TimedMetadataStreamDescriptor(encodingProperties)
{
    Name = "GPS Info",
    Label = "GPS Info"
};

After creating the TimedMetadataStreamDescriptor, you can create a MediaEncodingProfile that describes the video, audio, and metadata to be encoded in the file. The TimedMetadataStreamDescriptor created in the last example is passed into this example helper function and is added to the MediaEncodingProfile by calling SetTimedMetadataTracks.

public MediaEncodingProfile CreateProfileForTranscoder(VideoStreamDescriptor videoStream1, VideoStreamDescriptor videoStream2, AudioStreamDescriptor audioStream, TimedMetadataStreamDescriptor timedMetadataStream)
{
    ContainerEncodingProperties container = new ContainerEncodingProperties()
    {
        Subtype = MediaEncodingSubtypes.Mpeg4
    };

    MediaEncodingProfile profile = new MediaEncodingProfile()
    {
        Container = container
    };


    VideoStreamDescriptor encodingVideoStream1 = videoStream1.Copy();
    encodingVideoStream1.EncodingProperties.Subtype = MediaEncodingSubtypes.H264;
    encodingVideoStream1.Label = videoStream1.Name;

    VideoStreamDescriptor encodingVideoStream2 = videoStream2.Copy();
    encodingVideoStream2.EncodingProperties.Subtype = MediaEncodingSubtypes.H264;
    encodingVideoStream2.Label = videoStream2.Name;

    AudioStreamDescriptor encodingAudioStream = audioStream.Copy();
    encodingAudioStream.EncodingProperties.Subtype = MediaEncodingSubtypes.Ac3;
    encodingAudioStream.Label = audioStream.Name;

    TimedMetadataStreamDescriptor encodingTimedMetadataStream = timedMetadataStream.Copy();

    profile.SetTimedMetadataTracks(new TimedMetadataStreamDescriptor[] { encodingTimedMetadataStream });
    profile.SetVideoTracks(new VideoStreamDescriptor[] { encodingVideoStream1, encodingVideoStream2 });
    profile.SetAudioTracks(new AudioStreamDescriptor[] { encodingAudioStream });
    return profile;
}