我有一個應該生成視頻指紋的windowsservice。 爲了實現這一點,我試圖使用MediaElement類(https://msdn.microsoft.com/en-us/library/system.windows.controls.mediaelement(v=vs.110).aspx)。要在打開媒體時觸發事件,該元素必須位於可視樹中。是否有可能模擬或僞造視覺樹?C#:有可能在服務中生成或僞造可視化樹嗎?
編輯:我現在使用MediaPlayer而不是MediaElement,但不能依賴事件,因爲它們不會被引發。
更新代碼
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是一個視覺元素。爲什麼不使用[MediaPlayer](https://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer(v = vs.110).aspx)呢? – icebat
MediaPlayer能夠完成截圖,但MediaOpened事件沒有被觸發,設置位置正在工作2次中的2次。我添加了一個硬編碼的Thread.Sleep(150000); waitHandle.Set(); waitHandle.Wait之前。這不是一個可靠的解決方案 –