Ich habe einen Windowsservice, der Daumenabdrücke von Videos erzeugen soll. Um dies zu erreichen, versuche ich die MediaElement-Klasse (https://msdn.microsoft.com/en-us/library/system.windows.controls.mediaelement(v=vs.110).aspx) zu verwenden. Um Ereignisse beim Öffnen von Medien auszulösen, muss sich dieses Element in einem Visual Tree befinden. Ist es möglich, einen visuellen Baum zu simulieren oder zu fälschen?C#: Ist es möglich, einen visuellen Baum in einem Service zu erzeugen oder zu fälschen?
Edit: Ich benutze jetzt MediaPlayer anstelle von MediaElements, kann aber nicht auf die Ereignisse verlassen, weil sie nicht geworfen werden.
Aktualisiert 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 ist ein visuelles Element. Warum nicht stattdessen [MediaPlayer] (https://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer (v = vs.110) .aspx) verwenden? – icebat
Der MediaPlayer kann Screenshots erstellen, aber das MediaOpened-Ereignis wird nicht ausgelöst und die Positionierung wird 2 bis 3 Mal aktiviert. Ich habe einen hardcoded Thread.Sleep (150000) hinzugefügt; waitHandle.Set(); vor warteHandle.Wait. Dies ist keine zuverlässige Lösung –