2011-02-03 11 views
4

내가 WPF를 사용하여 응용 프로그램을 작성하고 DirectShow를하고 끈적 끈적한 문제로 실행 한하고있다. 내 응용 프로그램은 DirectShowNet (DS 용 C# 래퍼 클래스)을 사용하여 작성된 정적 클래스에서 정적 메서드 Start() 및 Stop()을 통해 DS를 사용합니다. WindowsForms 패널을 WindowsFormsHost 객체를 통해 내 WPF 윈도우에 배치하여 그래프를 렌더링해야합니다. 다음은 앱의 일반적인 흐름입니다. Start() 메소드는 그래프를 작성하고 시작합니다. 내 윈도우 폼 패널의 핸들을 전달하고 IVideoWindow 인터페이스를 사용하여 렌더링합니다. Start()가 반환되고 그래프가 백그라운드에서 실행됩니다. 어떤 시점에서 Stop()이 호출됩니다. 이 메서드는 그래프를 정지 해 파괴합니다.DirectShow에서/WPF 스레딩 문제

모든 오래 저도 같은 스레드에서 시작()와 중지()를 호출로 잘 작동합니다. 그러나, 내 애플 리케이션에서 다른 스레드에서 그들을 호출해야합니다. 이 경우 그래프를 파기하는 코드 부분에서 예외가 발생합니다 (특히 필터를 열거 할 때). DirectShow를 사용할 때 멀티 스레드 아파트를 사용해야한다는 것을 발견했습니다. Windows Forms 앱을 사용하면 쉽습니다. 난 그냥 내 주요 방법에 [MTAThread] 던져 모든 것이 작동합니다. 내 WPF 응용 프로그램에 대한

이 분명히 옵션을 선택하지 않습니다. 내 해결 방법은 Start() 및 Stop() 호출해야 할 때 새 MTA 스레드를 시작했습니다. 이것은 예외를 제거하지만 또 다른 문제점을 야기했습니다. Start() 메서드가 반환되면 렌더링 패널에서 비디오가 사라집니다. Start() 메서드가 끝나면 Sleep을 넣으면 Sleep이 끝날 때까지 비디오가 표시됩니다. 또한 비디오가 사라진 후에 그래프가 계속 실행되는지 확인했습니다. 진행 방법에 대한 조언이있는 사람이 있습니까? 감사. 케빈

+1

코드를 게시하거나 코드 설명을 게시 하시겠습니까? 나는 첫 번째와 함께 갈 것입니다. –

+2

왜 DirectShow를 사용하고 있습니까? WPF는 미디어를 재생할 수 있습니다. –

+1

@Emo - 아마도 파일이나 일반적인 비디오 스트림이 아닌 비디오 소스를 가지고있을 것입니까? 그는 어떤 종류의 커스텀 소스 필터를 가지고 있을지도 모른다. – Kazar

답변

0

는 참고로, 윈도우 폼은 MTAThread 메인 스레드를 지원하지 않습니다. 작동한다면, 당신은 방금 운이 좋았습니다.

STA 스레드에서 DS 개체를 호출 할 수 있어야합니다. DS에 익숙하지 않지만 windowless mode을 사용하고있는 것처럼 들리지만 STA에서 가장 잘 작동하는 것처럼 보입니다. .

그런 경우 항상 기본 스레드에서 Start/Stop으로 전화하지 않으시겠습니까? 다른 스레드가 주 스레드에게 중지 또는 시작하도록 알릴 필요가 있다면 TaskScheduler.FromCurrentSynchronizationContext에 대한 작업 대기열을 주 스레드에서 실행하도록하십시오.

1

어떤 예외가 발생합니까? 나는 "다른 스레드가 소유하고 있기 때문에 호출하는 스레드는이 개체에 액세스 할 수 없습니다."와 같은 것을 추측합니다. 이 경우이 경우 here 설명으로

는 통화를 할 수있는 올바른 디스패처를 사용합니다.

0

좋아, 그래서 너무 비슷하기 전에 문제가 발생했습니다,하지만 WPF와, 그래서 소금 한 스푼 다음과 같은 (매우 해키) 제안을.

다음 방법은 기본적으로 DirectShow를 명령을 실행하기 위해 완전히 별도의 응용 프로그램 스레드를 생성하지만 형태가 WPF 응용 프로그램에서 호스팅 제어하는 ​​윈도우의 핸들을 사용하는 직접 쇼를 알려줍니다.

그래서 먼저 우리는 더미 윈폼은 우리가 전화를 호출하는 데 사용할 수있는 양식이 필요하지만, 그것은 결코 렌더링 얻을 것 없다 :

/// <summary> 
/// Just a dummy invisible form. 
/// </summary> 
private class DummyForm : Form 
{ 

    protected override void SetVisibleCore(bool value) 
    { 
     //just override here, make sure that the form will never become visible 
     if (!IsHandleCreated) 
     { 
      CreateHandle(); 
     } 

     value = false; 
     base.SetVisibleCore(value); 
    } 
} 

다음 단계는 우리가 넣을 수 있습니다 스레드를 만드는 것입니다 메시지 루프에 : 더미 형태 (및 스레드)가 생성 된 후

//this will need to be a class level variable, since all the directshow 
//calls will get invoked on this form 
DummyForm dumbForm; 
Thread separateThread; 


private void CreateDummyForm() 
{ 

    ManualResetEvent reset = new ManualResetEvent(false); 

    //create our thread 
    separateThread = new Thread((ThreadStart) 
    delegate 
    { 

     //we need a dummy form to invoke on 
     dumbForm = new DummyForm(); 

     //signal the calling method that it can continue 
     reset.Set(); 

     //now kick off the message loop 
     Application.Run(dumbForm); 
    }); 

    //set the apartment state of this new thread to MTA 
    separateThread.SetApartmentState(ApartmentState.MTA); 
    separateThread.IsBackground = true; 
    separateThread.Start(); 

    //we need to wait for the windowing thread to have initialised before we can 
    //say that initialisation is finished 
    reset.WaitOne(); 

    //wait for the form handle to be created, since this won't happen until the form 
    //loads inside Application.Run 
    while (!dumbForm.IsHandleCreated) 
    { 
     Thread.Sleep(0); 
    } 

} 

그래서, 당신이 그렇게 같은 MTA 응용 프로그램 스레드에서 호출을 호출 할 수 있습니다

당신은 모든 DirectShow에서 물건 완료 그런

, 그래서 같은 종료 별도의 응용 프로그램 스레드 :이 방법의

//to end the separate thread and application loop, 
//just close your invisible form 
dumbForm.Close(); 

장점은 깔끔하게 별도의 스레드로 DirectShow를 샌드 박스이다. 단점은 Invoke 호출의 컨텍스트 전환과 다른 응용 프로그램 스레드가있는 오버 헤드입니다. 이 아키텍처를 현재 아키텍처에 약간 재미있게 사용할 수도 있지만 도움이 될 것입니다.

당신이 어떻게 시작하는지 알려주세요. 나는 이것이 얼마나 잘 작동하는지에 흥미를 느끼고 있습니다.