Click here to Skip to main content
15,895,799 members
Articles / Programming Languages / C#

Getting Thumbnail from Video using MediaPlayer Class in WPF

Rate me:
Please Sign up or sign in to vote.
4.50/5 (5 votes)
21 Nov 2012CPOL1 min read 39.3K   3.6K   9  
This article shows the use of MediaPlayer class to obtain thumbnails for video files.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace VideoScreenshot
{
    public partial class MainWindow : Window
    {
        ObservableCollection<MediaItem> thumbnailCollection = new ObservableCollection<MediaItem>();
        ObservableCollection<int> speedList = new ObservableCollection<int>();
        ObservableCollection<int> positionList = new ObservableCollection<int>();

        int thumbnailsInProgress = 0;

        public MainWindow()
        {
            InitializeComponent();
            mediaListBox.ItemsSource = thumbnailCollection;
            for (int i = 0; i < 20; i++)
            {
                speedList.Add(i + 1);
                positionList.Add(i);
            }
            waitTimeBox.ItemsSource = speedList;
            positionBox.ItemsSource = positionList;
            waitTimeBox.SelectedIndex = 3;
            positionBox.SelectedIndex = 1;
        }

        private void importMediaButton_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
            ofd.CheckPathExists = true;
            ofd.Multiselect = true;
            bool? result = ofd.ShowDialog();
            if (result == true)
            {  
                foreach (string str in ofd.FileNames)
                {
                    int waitTime = (int)waitTimeBox.SelectedValue;
                    int position = (int)positionBox.SelectedValue;
                    if (thumbnailsInProgress++ == 0)
                    {
                        animationGrid.Visibility = System.Windows.Visibility.Visible;
                        downloadAnimation.StartAnimation();
                    }

                    //Since the Task.Factory.StartNew() will be called after the loop has already exited, 
                    //we need to create a copy of 's'; otherwise the same value will be passed to multiple invocations!!
                    string fileName = str;
                    Task.Factory.StartNew(() => { ImportMediaThreadProc(fileName, waitTime, position); });
                }
            }
        }
        
        //We would like to create thumbnails one after the other; so we will use a lock to give 
        //access to only one path of execution to this method
        object importMediaLock = new object();
        void ImportMediaThreadProc(string mediaFile, int waitTime, int position)
        {
            lock (importMediaLock)
            {
                MediaPlayer player = new MediaPlayer { Volume = 0, ScrubbingEnabled = true };
                player.Open(new Uri(mediaFile));
                player.Pause();
                player.Position = TimeSpan.FromMilliseconds(position * 1000);
                //We need to give MediaPlayer some time to load. The efficiency of the MediaPlayer depends                 
                //upon the capabilities of the machine it is running on
                System.Threading.Thread.Sleep(waitTime * 1000);

                //120 = thumbnail width, 90 = thumbnail height and 96x96 = horizontal x vertical DPI
                //An in actual application, you wouldn's probably use hard coded values!
                RenderTargetBitmap rtb = new RenderTargetBitmap(120, 90, 96, 96, PixelFormats.Pbgra32);
                DrawingVisual dv = new DrawingVisual();
                using (DrawingContext dc = dv.RenderOpen())
                {
                    dc.DrawVideo(player, new Rect(0, 0, 120, 90));
                }
                rtb.Render(dv);
                Duration duration = player.NaturalDuration;
                int videoLength = 0;
                if (duration.HasTimeSpan)
                {
                    videoLength = (int)duration.TimeSpan.TotalSeconds;
                }
                BitmapFrame frame = BitmapFrame.Create(rtb).GetCurrentValueAsFrozen() as BitmapFrame;
                BitmapEncoder encoder = new JpegBitmapEncoder();
                encoder.Frames.Add(frame as BitmapFrame);

                //We cannot create the thumbnail here, as we are not in the UI thread right now
                //It is the responsibility of the calee to close the MemoryStream
                //We will instead call a method which will do its stuff on the UI thread!
                MemoryStream memoryStream = new MemoryStream();
                encoder.Save(memoryStream);
                CreateMediaItem(memoryStream, mediaFile, videoLength);
                player.Close();
            }
        }

        void CreateMediaItem(MemoryStream ms, string name, int duration)
        {
            Dispatcher.Invoke(new Action(delegate
            {
                ms.Position = 0;
                MediaItem mediaItem = new MediaItem();
                BitmapImage bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                bitmapImage.StreamSource = ms;
                bitmapImage.EndInit();
                mediaItem.Thumbnail = bitmapImage;
                mediaItem.Duration = duration;
                mediaItem.Name = System.IO.Path.GetFileName(name);
                //The protocol we defined expects us to close the MemoryStream here.
                //Otherwise our memory consumption would not be optimized. GC can take its time; so we better do it ourselves!
                ms.Close();
                thumbnailCollection.Add(mediaItem);
                if (--thumbnailsInProgress == 0)
                {
                    downloadAnimation.StopAnimation();
                    animationGrid.Visibility = System.Windows.Visibility.Collapsed;
                }
            }));
        }

        class MediaItem
        {
            public BitmapImage Thumbnail { get; set; }
            public int Duration { get; set; }
            public string Name { get; set; }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead https://mathiversity.com
Unknown
I am a full-stack developer. My skills include JavaScript, C#/.Net, MS Azure cloud etc. I love to work on complex programming tasks requiring deep analysis, planning and use of efficient algorithms and data structures.

Comments and Discussions