2012-07-27 39 views
1

我有一个VideoRenderer类,它继承的图像控制,一类MyVideo网站,其中有一个VideoRenderer实例,并在主窗口一个RenderFrames方法代码隐藏如何在不冻结GUI的情况下不断更新视频帧的内容控件?

我已附加这些类的相关部分,以及作为RenderFrames方法和下面的一些MainWindow代码隐藏构造函数。

VideoRenderer接收外部视频并将视频帧生成为位图对象,存储在“位图”字段中。每完成一次处理后,我将位图的副本存储在“bitmapCopy”字段中。

MyVideo控制何时VideoRenderer实例“sharedVideoRenderer”启动和停止接收和发送帧到MainWindow RenderFrames方法,使用ThreadPool.QueueUserWorkItem传递VideoRenderer实例作为对象参数。

RenderFrames循环,直到MyVideo网站说,停止通过改变它的布尔“是我们渲染”特性,以及它与位图做了转换 - >的BitmapImage - > Image.Source,然后设置VideoContentControl.Content作为图像,使用MainWindow Dispatcher。

一切正常,视频呈现,但GUI控制基本上是冻结的,其他按钮和事情不起作用,因为调度整个操作到MainWindow线程和循环不断正在捆绑线程。

我的问题是:我可以尝试使用其他方法将位图帧从“sharedVideoRenderer”传输到VideoContentControl,并在不冻结GUI的情况下使用新图像继续更新它?

任何帮助,将不胜感激。

相关的代码:

VideoRenderer.cs:

internal void DrawBitmap() 
{ 
    lock (bitmapLock) 
    { 
     bitmapCopy = (Bitmap)bitmap.Clone(); 
    } 
} 

MyVideo.cs:

public static void RenderVideoPreview() 
{ 
    sharedVideoRenderer.VideoObject = videoPreview; 

    sharedVideoRenderer.Start(); 

    videoPreviewIsRendering = true; 

    ThreadPool.QueueUserWorkItem((Application.Current.MainWindow as MainWindow).RenderFrames, sharedVideoRenderer); 
    } 

MainWindow.xaml.cs:

Dispatcher mainWindowDispatcher; 

public MainWindow() 
{ 
    InitializeComponent(); 

    mainWindowDispatcher = this.Dispatcher; 
... 

public void RenderFrames(object videoRenderer) 
{ 
    while (MyVideo.VideoPreviewIsRendering || MyVideo.LiveSessionParticipantVideoIsRendering) 
    { 
     mainWindowDispatcher.Invoke(new Action(() => 
     { 
      try 
      { 
       System.Drawing.Bitmap bitmap; 

       bitmap = (videoRenderer as VideoRenderer).BitmapCopy; 

       using (MemoryStream memory = new MemoryStream()) 
       { 
        BitmapImage bitmapImage = new BitmapImage(); 
        ImageSource imageSource; 
        Image image; 
        image = new Image(); 

        bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp); 

        memory.Position = 0; 

        bitmapImage.BeginInit(); 
        bitmapImage.StreamSource = memory; 
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad; 
        bitmapImage.EndInit(); 

        imageSource = bitmapImage; 

        image.Source = imageSource; 

        VideoContentControl.Content = image; 

        memory.Close(); 
       } 
      } 
      catch (Exception) 
      { 

      } 
     })); 
    } 

    mainWindowDispatcher.Invoke(new Action(() => 
     { 
      VideoContentControl.ClearValue(ContentProperty); 

      VideoContentControl.InvalidateVisual(); 
     })); 
} 
+0

我认为您需要利用GPU来使其可靠工作。 – Kos 2012-07-27 15:33:22

回答

1
ThreadPool.QueueUserWorkItem((Application.Current.MainWindow as MainWindow).RenderFrames, sharedVideoRenderer); 

////  

public void RenderFrames(object videoRenderer) 
{ 
    while (MyVideo.VideoPreviewIsRendering || MyVideo.LiveSessionParticipantVideoIsRendering) 
    { 
     mainWindowDispatcher.Invoke(new Action(() => 

这些线条引起了我的猜测。

虽然在线程池线程上调用Renderframes方法,但它所做的主要事情是将控制权交还给UI线程,从而声明/阻止它。

你可以尝试找到一个较小的范围:

while (MyVideo.VideoPreviewIsRendering || MyVideo.LiveSessionParticipantVideoIsRendering) 
{ 

     try 
     { 
      System.Drawing.Bitmap bitmap; 

      bitmap = (videoRenderer as VideoRenderer).BitmapCopy; 

      using (MemoryStream memory = new MemoryStream()) 
      { 
       BitmapImage bitmapImage = new BitmapImage(); 
       ImageSource imageSource; 
       Image image; 
       image = new Image(); 

       bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp); 

       memory.Position = 0; 

       bitmapImage.BeginInit(); 
       bitmapImage.StreamSource = memory; 
       bitmapImage.CacheOption = BitmapCacheOption.OnLoad; 
       bitmapImage.EndInit(); 

       imageSource = bitmapImage; 

       mainWindowDispatcher.Invoke(new Action(() => 
       { 
        image.Source = imageSource; 

        VideoContentControl.Content = image; 

        memory.Close(); 
       } 
      } 
     } 
     catch (Exception) 
     { 

     } 
    })); 
} 

我不太清楚,我改变了范围过少或过多,因为我真的不知道什么属于UI线程但这可能给你一个开始,你可能想要移动的东西。

您可以/应该使用的另一个技巧是尽量减少您制作的UI元素的数量。在当前代码中,您正在每帧创建一个Image元素。相反,您可以制作一个单独的WriteableBitmap,将Image的ImageSource指向它并简单地将图片数据提交给它。请参阅:What is a fast way to generate and draw video in WPF?

相关问题