|
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.
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.