2017-08-28 92 views
0

我有一個應該生成視頻指紋的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(); 
    } 
} 
+1

MediaElement是一個視覺元素。爲什麼不使用[MediaPlayer](https://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer(v = vs.110).aspx)呢? – icebat

+0

MediaPlayer能夠完成截圖,但MediaOpened事件沒有被觸發,設置位置正在工作2次中的2次。我添加了一個硬編碼的Thread.Sleep(150000); waitHandle.Set(); waitHandle.Wait之前。這不是一個可靠的解決方案 –

回答

1

MediaElement基本上是託管媒體內容的可視化控制:

表示包含一個控制音頻和/或視頻

你需要一個UI無MediaPlayer。只是不要忘記調用Open方法或MediaOpened不會觸發。

+0

我現在能夠捕捉屏幕,但事件不起作用。我現在有2個編碼延遲讓代碼運行(對於大多數情況,但不可靠,位置設置也有點不可靠) –