2012-07-27 2 views
1

는 나뿐만 아니라하는 VideoRenderer 인스턴스가있는 이미지 컨트롤하는 myVideo를 클래스를 상속 VideoRenderer 클래스, 그리고 그 클래스의 관련 부분을 첨부했습니다 코드 숨김GUI를 멈추지 않고 contentcontrol을 비디오 프레임으로 지속적으로 업데이트하려면 어떻게해야합니까?

MainWindow를에 RenderFrames 방법을 아래의 RenderFrames 메소드와 약간의 MainWindow 코드 숨김 생성자로.

VideoRenderer는 외부 비디오를 수신하고 "비트 맵"필드에 저장된 비트 맵 객체로 비디오 프레임을 생성합니다. 완성 된 각 프로세스가 끝나면 "bitmapCopy"필드에 비트 맵의 ​​복제본을 저장합니다.

MyVideo는 VideoRenderer 인스턴스 인 "sharedVideoRenderer"가 MainPlayer.QueueUserWorkItem을 사용하여 VideoRenderer 인스턴스를 객체 매개 변수로 전달하여 MainWindow RenderFrames 메서드로 프레임 수신 및 전송을 시작하고 중지 할 때 제어합니다.

RenderFrames는 MyVideo가 bool의 "렌더링 중입니까?"속성을 변경하여 중지 할 때까지 반복되고 비트 맵 -> 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

답변

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를 가리켜 이미지 데이터를 blit하면됩니다.참조 : What is a fast way to generate and draw video in WPF?

관련 문제