1

미디어 플레이어 (Media.MediaPlayer() 클래스 사용)를 만들려고합니다.이 때문에 스레드를 사용하여 OpenFileDialog를 사용하여 사용자가로드 한 노래를 처리하고 있습니다. 나는 과정 노래 시작하려면 다음 코드를 사용하고 있습니다 :Open MediaPlayer - 스레드에서 처리되지 않은 이벤트

public static List<MediaFile> MediaList = new List<MediaFile>(); 
    public static Queue<String> MediaFilesQueue = new Queue<String>(); 



public static void AddMediaFilesToMediaList() 
     { 

      String pathToFile; 


      while (MediaFilesQueue.Count > 0) 
      // all the files are loaded into the Queue before processing 
      { 
      pathToFile = MediaFilesQueue.Dequeue(); 
      MediaData.MediaList.Add(new MediaFile(pathToFile)); 

      MediaFileCreator mfCreator = 
          new MediaFileCreator(MediaData.MediaList.Count - 1); 
      mfCreator.CreateNewMediaFile(); 


      } 

}

을 그리고 이것은 MediaFileCreator 클래스입니다 :

public class MediaFileCreator 
    { 

     private int IndexOfMediaFileCurrentlyProcessed; 


     public MediaFileCreator(int idx) 
     { 
      IndexOfMediaFileCurrentlyProcessed = idx; 
     } 

     public void CreateNewMediaFile() 
     { 


      var indexOfMediaFileCurrentlyProcessed = IndexOfMediaFileCurrentlyProcessed; 

      var tempMediaFile = MediaData.MediaList[indexOfMediaFileCurrentlyProcessed]; 

      var tempMediaPlayer = new MediaPlayer(); 
      var waitHandle = new AutoResetEvent(false); 

      //EventHandler eventHandler = delegate(object sender, EventArgs args) 
      //{ 
      // waitHandle.Set(); 
      //}; 


      tempMediaPlayer.MediaOpened += (sender, args) => waitHandle.Set(); 

      tempMediaPlayer.Open(new Uri(tempMediaFile.PathToFile)); 

      waitHandle.WaitOne(); 


      //while (!tempMediaPlayer.NaturalDuration.HasTimeSpan) 
      //{ 
      // Thread.Sleep(100); 
      //} 


      var tempTimeSpan = tempMediaPlayer.NaturalDuration.TimeSpan; 
      var hasVideo = tempMediaPlayer.HasVideo; 
      var hasAudio = tempMediaPlayer.HasAudio; 

      MediaData.MediaList[indexOfMediaFileCurrentlyProcessed].HasVideo = hasVideo; 
      MediaData.MediaList[indexOfMediaFileCurrentlyProcessed].HasAudio = hasAudio; 
      MediaData.MediaList[indexOfMediaFileCurrentlyProcessed].TimeSpanOfMediaFile 
                     = tempTimeSpan; 


     } 

그리고 이것은 미디어 파일 클래스입니다 :

public class MediaFile 
    { 
     public bool HasAudio = false; 
     public bool HasVideo = false; 

     public TimeSpan TimeSpanOfMediaFile; 

     public String PathToFile = null; 

     public MediaFile(String pathToFile) 
     { 
      PathToFile = pathToFile; 
     } 
    } 

제 문제는 프로그램이 waitHandle.WaitOne();에 멈추고 그 프로그램을 실행하려고하는 것입니다. 다시 계속해서. 첫 번째 주석 처리 된 섹션의 이벤트 핸들러를 Open 이벤트에 연결하여 다른 변형을 시도했지만 결과는 같았습니다. waitHandle.Set();이 실행되지 않으며 waitHandle의 값은 항상 false입니다. 필자가 관리 할 수 ​​있었던 유일한 옵션은 두 번째 주석 처리 된 섹션의 솔루션입니다. 파일이 완전히로드 될 때까지 Thread.Sleep을 사용하여 스레드를 차단합니다 (예 : TimeSpan이 초기화 될 때 파일이로드 됨). 이는 내 응용 프로그램의 시간 손실과 성능 저하입니다. 문제는 분명히 이벤트 자체가 아닙니다. 이벤트가 주 스레드에서 실행되는 경우 트리거되기 때문에 (AddMediaFilesToMediaList() 메서드는 백그라운드 스레드에 요소가 있음을 감지하면 새 스레드 내부에서 메서드를 시작하는 BackgroundWorker 스레드에서 호출됩니다. Queue : AddMediaFilesToMediaList() 스레드는 new Thread()으로 생성됩니다. 분명히 TimeSpan이 초기화되어 있기 때문에 파일이로드되고 있습니다. 나는 waitHandle 같은 것을 사용하여 응용 프로그램을 만들고 싶습니다. Thread.Sleep()을 사용하고 싶지 않습니다. 추한 것이기 때문에 많은 응용 프로그램을로드하려고 할 때 응용 프로그램에 메모리 누수가 있습니다. 1.2GB 이상의 메모리가 필요하고 오류 (OutOfMemory)가 발생합니다. - 2048 곡을로드하려고했습니다.) 그리고 Thread.Sleep() 때문에 그럴 수 있다고 생각합니다. 그렇지 않은 경우에도 Thread.Sleep() 문제없이 디버깅하는 것이 훨씬 쉽습니다.

어떻게하면 waitHandle을 작동시킬 수 있습니까? waitHandle.Set();을 실행하려면 어떻게해야합니까? 그리고 과도한 메모리 사용량이 어디서 올 수 있었는지에 대한 생각이 있다면 큰 도움이 될 것입니다! (나는 개인적으로 그것이 Thread.Sleep()의 잘못이라고 믿지만 그것을 제거하는 방법을 모른다.)

편집 : MediaFileCreator 객체를 사용하는 이유는 처음에 미디어 파일을 처리하기 위해 2에서 4 개의 스레드 풀을 사용하기를 원했지만 동일한 문제가있어서 ThreadPool을 제거하고 위의 코드를 게시했지만 동일한 문제가 발생했습니다.

편집 : 두 번째 스레드를 사용하여 이벤트를 기다릴 수 있었지만 (지금은 가장 깨끗한 코드가 아니지만 올바르게 만들 것입니다.)

public class MediaFileCreator 
{ 

    private AutoResetEvent openedEvent = new AutoResetEvent(false); 


    public MediaFile CreateNewMediaFile(string filename) 
    { 

     var mFile = new MediaFile(filename); 
     var thread = new Thread(WaitForEvent); 
     const int maxTimeToWait = 2000; 
     openedEvent.Reset(); 
     thread.Start(mFile); 

     var mediaPlayer = new MediaPlayer(); 

     mediaPlayer.Open(new Uri(mFile.PathToFile)); 

     openedEvent.WaitOne(maxTimeToWait); 

     var fromThread = Dispatcher.FromThread(Thread.CurrentThread); 
     if (fromThread != null) fromThread.InvokeShutdown(); 

     return mFile; 

    } 

    private void WaitForEvent(object context) 
    { 

     var mFile = (MediaFile)context; 
     var mediaPlayer = new MediaPlayer(); 

     mediaPlayer.MediaOpened += 
      delegate 
      { 
       if (mediaPlayer.NaturalDuration.HasTimeSpan) 
        mFile.TimeSpanOfMediaFile = mediaPlayer.NaturalDuration.TimeSpan; 
       mFile.HasAudio = mediaPlayer.HasAudio; 
       mFile.HasVideo = mediaPlayer.HasVideo; 
       mFile.Success = true; 
       mediaPlayer.Close(); 
       openedEvent.Set(); 
      }; 

     mediaPlayer.MediaFailed += 
      delegate 
      { 
       mFile.Failure = true; 
       mediaPlayer.Close(); 
       openedEvent.Set(); 
      }; 

     mediaPlayer.Open(new Uri(mFile.PathToFile)); 

     Dispatcher.Run(); 
    } 
} 
+0

완성 된 답변을 참조하십시오. –

답변

3

한 가지는 확실하다 다음 Thread.Sleep 통화가 메모리 문제와는 아무 상관이있다.

코드를 조금 더 정리하는 것이 좋습니다. 로드하는 모든 파일에 대해 새로 MediaCreatorMediaPlayer을 새로 작성할 필요가 없습니다. 당신이 모든 그 MediaPlayer 객체를 만들고 그것들을 닫지 않기 때문에 이것은 메모리 사용의 큰 부분 일 수 있습니다. 가비지 컬렉터가 결국 정리할 것이지만 그 동안에는 메모리 사용량이 크게 늘어날 수 있습니다.

이를 고려

것을 상당히 단순화하고 메모리 사용에 상당히 삭감해야 하나 MediaPlayer 객체를 사용
public static void AddMediaFilesToMediaList() 
{ 
    MediaFileCreator mfCreator = new MediaFileCreator(); 

    while (MediaFilesQueue.Count > 0) 
    { 
     // all the files are loaded into the Queue before processing 
     string pathToFile = MediaFilesQueue.Dequeue(); 

     MediaFile mf = mfCreator.CreateNewMediaFile(pathToFile); 

     MediaData.MediaList.Add(mf); 
    } 
} 

public class MediaFileCreator 
{ 
    private MediaPlayer player = new MediaPlayer(); 
    private ManualResetEvent openedEvent = new ManualResetEvent(false); 

    public MediaFileCreator() 
    { 
     player.MediaOpened = MediaOpened; 
    } 

    private void MediaOpened(object sender, EventArgs args) 
    { 
     openedEvent.Set(); 
    } 

    public MediaFile CreateNewMediaFile(string filename) 
    { 
     openedEvent.Reset(); 

     player.Open(new Uri(tempMediaFile.PathToFile)); 

     // wait for it to load 
     openedEvent.WaitOne(); 

     MediaFile mf = new MediaFile(filename); 
     mf.HasVideo = player.HasVideo; 
     mf.HasAudio = player.HasAudio; 
     mf.TimeSpanOfMediaFile = player.NaturalDuration.TimeSpan; 

     player.Close(); 

     return mf; 
    } 
} 

.

나는 실제로 문제가 무엇인지 모르겠다. AutoResetEvent이 작동하지 않는다. 그것은 보이는 오른쪽.

이 새로운 코드에서는 waitHandle.Set 호출에 중단 점을 넣어 실제로 충돌했는지 확인할 수 있습니다. MediaOpened 이벤트가 정확히 언제 발생했는지, 또는 이벤트가 발생했을 때 플레이어의 상태를 알 수는 없습니다. 그 문서는 그것에 대해 의심의 여지없이 침묵합니다.

MediaPlayer은 코드가 UI 스레드에서 실행되기를 원할 수도 있습니다. WPF 컨트롤을 익히는데 익숙하지 않습니다. 스레드에 객체에 대한 액세스 권한이 있는지 확인하려면 VerifyAccess으로 전화하십시오.

+0

예, 그게 전부입니다 (http://msdn.microsoft.com/en-us/library/system.windows.media.mediaplayer.mediaopened.aspx). MediaPlayer 객체가 Timespan, HasAudio, HasVideo 및 기타 이와 같은 필요한 정보를 제공 한 후 이벤트가 발생했습니다. 좋아, 그럼 아침에 코드를 테스트 해 볼께.하지만 똑같은 문제가 있다면 어떻게해야합니까? UI 스레드에서 수천 곡을로드 할 수 없습니다. – TheQuestioner

+0

@TheQuestioner,'ManualResetEvent'와'AutoResetEvent'가 작동하지 않으면'Thread.Sleep (10)'(100 대신에)로 루프를 시도 할 수 있습니다. 보기 흉하지만 넷을 둘러 보면서 볼 수있는 유일한 해결책입니다. –

+0

그것은 작동하지 않았지만 솔루션을 찾기 위해 관리했습니다 (이벤트와 디스패처를 기다리는 두 번째 스레드를 사용하여). 초기 텍스트에 솔루션을 추가했습니다. 그런데 고맙습니다, 당신의 솔루션은 많은 도움이되었습니다! – TheQuestioner

관련 문제