After I had so much fun writing a tutorial on how to implement drag and drop function in UWP, I decided to share my knowledge on how to generate a thumbnail from video file in UWP application.
What will you learn today?
- Get a file from Assets folder
- Generating a thumbnail from a video file
- Saving the thumbnail that has been generated
It is relatively easy to achieve that since Microsoft already provide a function called GetThumbnailAsync which will do all the work for us. We only have to prepare the size of thumbnail and the source file. And that’s what makes it tricky! I tried for almost an hour and I got was only a black image.
Specify the video file which you want to generate thumbnail for
protected override async void OnNavigatedTo(NavigationEventArgs e) { string filename = "catvideo.mp4"; StorageFile videofile = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Assets\" + filename); GenerateVideoThumbnail(videofile); }
In the OnNavigatedTo function we will specify the video that we already have in the Assets folder StorageFile videofile = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Assets\" + filename);
. We then gives this video to the function where all the process of generating thumbnail will take place.
How to use GetThumbnailAsync for a video file correctly
MediaComposition mediaComposition = new MediaComposition(); var videoFile = await MediaClip.CreateFromFileAsync(file); mediaComposition.Clips.Add(videoFile); TimeSpan interval = videoFile.OriginalDuration.Add(new TimeSpan(-(videoFile.OriginalDuration.Ticks/2))); var thumbnail = await mediaComposition.GetThumbnailAsync(interval, 640, 360, VideoFramePrecision.NearestKeyFrame); BitmapDecoder decoder = await BitmapDecoder.CreateAsync(thumbnail); var thumbnailWriter = await localFolder.CreateFileAsync("generated_thumbnail.jpg", CreationCollisionOption.ReplaceExisting).AsTask(); System.Diagnostics.Debug.WriteLine("Thumbnail Location: " + localFolder.Path); using (var thumbnailStream = await thumbnailWriter.OpenAsync(FileAccessMode.ReadWrite)) using (var dataReader = new DataReader(thumbnail.GetInputStreamAt(0))) { var output = thumbnailStream.GetOutputStreamAt(0); await dataReader.LoadAsync((uint)thumbnail.Size); while (dataReader.UnconsumedBufferLength > 0) { uint dataToRead = dataReader.UnconsumedBufferLength > 64 ? 64 : dataReader.UnconsumedBufferLength; IBuffer buffer = dataReader.ReadBuffer(dataToRead); await output.WriteAsync(buffer); } await output.FlushAsync(); }
The thumbnail that is going to be created will be saved in the local state folder of the application. If you are not sure where this folder is, makes sure to look at the console since I already put this line of code in the function System.Diagnostics.Debug.WriteLine("Thumbnail Location: " + localFolder.Path);
If the duration of the video is 1 hour (60 minutes), the function will create a thumbnail from the frame which occurs in the minute 30. If it’s a 1-second long video, the thumbnail will be created from the frame from 0.5 second. The function will always generate a thumbnail from a frame that occurs in the middle of the video. This can be modified by editing this line of code TimeSpan interval = videoFile.OriginalDuration.Add(new TimeSpan(-(videoFile.OriginalDuration.Ticks/2)));
But I suggest not to use a fixed value since it can cause unwanted exception.
You can also change the size of the thumbnail by editing this line of code var thumbnail = await mediaComposition.GetThumbnailAsync(interval, 640, 360, VideoFramePrecision.NearestKeyFrame);
This code is also responsible for generating the thumbnail. But only generating a thumbnail is not enough since in most cases we have to save it. To save it we have to use a stream and DataReader. Once you use both, you will be able to see the perfectly generated thumbnail in the local folder, congratulation!
This code is also available on my GitHub page. Just clone it and test it on your machine.