打开MediaPlayer – 在Thread中未处理的事件

我正在尝试创建一个媒体播放器(使用Media.MediaPlayer()类),为此我使用一个线程来处理用户使用OpenFileDialog加载的歌曲。 我正在使用下一个代码来启动歌曲的过程:

public static List MediaList = new List(); public static Queue MediaFilesQueue = new Queue(); 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; } 

这是MediaFile类:

  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时)…这是我的申请时间丢失和性能下降。 问题显然不在于事件本身,因为事件在主线程上运行时会触发(从BackgroundWorker线程调用方法AddMediaFilesToMediaList(),当它检测到新元素中有元素时,会在新线程内启动该方法。队列;使用new Thread()创建AddMediaFilesToMediaList()线程,显然文件正在加载,因为TimeSpan已初始化。 我真的想使用waitHandle或类似的东西使应用程序工作。 我不想使用Thread.Sleep(),因为它很难看,当我尝试加载大量文件时,我的应用程序也有内存泄漏(我需要超过1.2 GB的内存,并且它会因错误而停止(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(); } } 

有一件事是肯定的: Thread.Sleep调用与你的内存问题无关。

我建议你多清理一下你的代码。 您无需为每个加载的文件创建新的MediaCreator和新的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; } } 

这简化了一些事情,只使用了一个MediaPlayer对象,这应该会减少内存使用量。

我真的不知道你的AutoResetEvent无法解决的问题。 看起来不错。

在这个新代码中,您可以在waitHandle.Set调用上放置一个断点,以查看它是否实际被命中。 我不知道什么时候触发MediaOpened事件,或者引发事件时播放器的状态是什么。 该文件对此持怀疑态度。

问题可能是MediaPlayer希望其代码在UI线程上执行。 我对WPF控件说不够熟悉。 您可以调用VerifyAccess来确定您的线程是否可以访问该对象。