I have a windowsservice that is supposed to generate thumbprints of videos. To achieve this i am trying to use the MediaElement-class (https://msdn.microsoft.com/en-us/library/system.windows.controls.mediaelement(v=vs.110).aspx). To fire events when opening medias this element has to be in a visualtree. Is it possible to simulate or fake a visual tree ?
Edit: I now use MediaPlayer instead of MediaElements but can't rely on the events because they are not thrown.
Updated code
public class Mp4ThumbnailExtractor : IDisposable
{
private ManualResetEvent waitHandle;
private TimeSpan mediaOpenTimeout;
public TimeSpan Time { get; set; }
= TimeSpan.Parse("00:00:30");
public TimeSpan FallbackTime { get; set; }
= TimeSpan.Parse("00:00:10");
public int Height { get; set; }
= 400;
public int Width { get; set; }
= 400;
public int Dpi { get; set; }
= 96;
public Mp4ThumbnailExtractor()
{
waitHandle = new ManualResetEvent(false);
mediaOpenTimeout = TimeSpan.Parse("00:00:15");
}
public MemoryStream CreateThumbnail(string videoPath)
{
MemoryStream memory = new MemoryStream();
Uri sourceUri = new Uri(videoPath);
MediaPlayer media = new MediaPlayer();
media.MediaOpened += Media_MediaOpened;
media.ScrubbingEnabled = true;
try
{
media.Open(new Uri(videoPath));
//TODO: media.opened event will not get fired
Thread.Sleep(mediaOpenTimeout);
waitHandle.Set();
//15sec timeout for loading the media
if (waitHandle.WaitOne(mediaOpenTimeout))
{
SetPosition(media);
//TODO: this is bad...
Thread.Sleep(2000);
DrawingVisual dv = new DrawingVisual();
DrawingContext dc = dv.RenderOpen();
dc.DrawVideo(media, new Rect(0, 0, Width, Height));
dc.Close();
RenderTargetBitmap bmp = new RenderTargetBitmap(Width, Height, Dpi, Dpi, PixelFormats.Pbgra32);
bmp.Render(dv);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
encoder.Save(memory);
memory.Seek(0, SeekOrigin.Begin);
}
else
{
throw new Exception($"Unable to open media '{videoPath}' in '{mediaOpenTimeout}'");
}
}
finally
{
media.Close();
}
return memory;
}
private void SetPosition(MediaPlayer player)
{
if (player.NaturalDuration.HasTimeSpan)
{
TimeSpan naturalTime = player.NaturalDuration.TimeSpan;
if (naturalTime < Time)
{
if (naturalTime > FallbackTime)
{
player.Position = FallbackTime;
}
}
else
{
player.Position = Time;
}
}
}
private void Media_MediaOpened(object sender, EventArgs e)
{
waitHandle.Set();
}
public void Dispose()
{
waitHandle.Dispose();
}
}
MediaElement is basically a visual control for hosting media content:
Represents a control that contains audio and/or video
You need a UI-less MediaPlayer. Just don't forget to call Open
method or MediaOpened
won't fire.