Open MediaPlayer-线程中未处理的事件

本文关键字:事件 未处理 MediaPlayer- 线程 Open | 更新日期: 2023-09-27 18:27:10

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

    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;

        } 

这是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初始化时加载文件)。。。这对我的应用程序来说是时间损失和性能下降。问题显然不在于事件本身,因为如果它在主线程上运行,就会触发事件(方法AddMediaFilesToMediaList()是从BackgroundWorker线程调用的,当它检测到队列中有元素时,会在新线程内启动该方法;AddMediaFilesToMediaList()线程是用new Thread()创建的),显然由于TimeSpan已初始化,所以文件正在加载。我真的很想让应用程序使用waitHandle或类似的东西。我不想使用Thread.Sleep(),因为它很难看,而且当我尝试加载很多文件时,我的应用程序也会出现内存泄漏(我占用了超过1.2 GB的内存,它会因错误而停止(OutOfMemory)-我尝试在其中加载2048首歌曲),我相信这可能是因为Thread.Slee普()。即使不是,如果没有Thread.Sleep().的问题,调试会容易得多

那么,我如何使waitHandle工作呢?如何使waitHandle.Set();运行?如果有人知道过度使用内存的原因,那就太好了!(我个人认为这是Thread.Sleep()的错,但我不知道如何摆脱它)。

编辑:我使用MediaFileCreator对象的原因是,最初我想使用2到4个线程的线程池来处理媒体文件,但我遇到了同样的问题,所以我删除了线程池,并尝试使用上面发布的代码,但也出现了同样的问题。

编辑:我设法用第二个线程来等待事件(现在不是最干净的代码,但我会做对的)。

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();
    }
}

Open MediaPlayer-线程中未处理的事件

有一点是肯定的: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来确定您的线程是否有权访问该对象。