开放的MediaPlayer - 在线程事件未处理 [英] Open MediaPlayer - event unhandled in Thread

查看:385
本文介绍了开放的MediaPlayer - 在线程事件未处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个媒体播放器(带Media.MediaPlayer()类),为此我使用一个线程来处理由使用的OpenFileDialog用户加载的歌曲。我使用下面的代码启动进程中的歌曲:

 公共静态列表<&媒体文件GT; medialist中=新名单<&媒体文件GT;(); 
公共静态队列<串GT; MediaFilesQueue =新队列<串GT;();



公共静态无效AddMediaFilesToMediaList()
{

字符串pathToFile;


,而(MediaFilesQueue.Count大于0)
//所有文件都处理之前,
{
pathToFile = MediaFilesQueue加载到队列中。出列();
MediaData.MediaList.Add(新媒体文件(pathToFile));

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


}



}



这是MediaFileCreator类:

 公共类MediaFileCreator 
{

私人INT IndexOfMediaFileCurrentlyProcessed;


公共MediaFileCreator(INT IDX)
{
IndexOfMediaFileCurrentlyProcessed = IDX;
}

公共无效CreateNewMediaFile()
{


VAR indexOfMediaFileCurrentlyProcessed = IndexOfMediaFileCurrentlyProcessed;

VAR tempMediaFile = MediaData.MediaList [indexOfMediaFileCurrentlyProcessed]

变种tempMediaPlayer =新的MediaPlayer();
变种的WaitHandle =新的AutoResetEvent(假);

//事件处理的EventHandler =委托(对象发件人,EventArgs参数)
// {
// waitHandle.Set();
//};


tempMediaPlayer.MediaOpened + =(发件人,参数)=> waitHandle.Set();

tempMediaPlayer.Open(新的URI(tempMediaFile.PathToFile));

waitHandle.WaitOne();


//而(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;


}

这是媒体文件类:

 公共类媒体文件
{
公共BOOL HasAudio = FALSE;
公共BOOL HasVideo = FALSE;

的公共时间跨度TimeSpanOfMediaFile;

公共字符串PathToFile = NULL;

公共媒体文件(字符串pathToFile)
{
PathToFile = pathToFile;
}
}



我的问题是,该计划停止在 waitHandle.WaitOne(); 并尝试重新并再次运行该行。我试图像在第一个注释部分,其他的变种通过该事件处理程序连接到Open事件,但结果却是一样的: waitHandle.Set(); 从不执行和WaitHandle中的值始终为false。我设法得到工作的唯一选项是从第二个注释部分的解决方案:阻塞线程(与Thread.sleep代码),直到文件完全加载(将文件加载例如当时间跨度被初始化)...这是时间损失和性能降低了我的申请。显然,问题不是事件本身,因为该事件触发,如果它在主线程上运行(方法AddMediaFilesToMediaList()从一个BackgroundWorker线程启动一个新的线程里面的方法调用,当它检测到存在的元素在队列;在AddMediaFilesToMediaList()线程与新的Thread()),显然将文件加载,因为时间跨度初始化创建。我真的想使用WaitHandle的或类似的东西应用程序的工作。我不想使用Thread.sleep()方法,因为它的丑陋,我的应用程序也有内存泄漏,当我尝试加载大量的文件(我接管1.2 GB的内存和它有错误停止(内存不足) - 我试图加载2048首歌曲的话),我认为这可能是因为Thread.sleep()方法的。即使不是,它会更容易,而不Thread.sleep()方法的问题进行调试。



那么,如何可以让WaitHandle的工作?我怎样才能让 waitHandle.Set(); 运行?如果任何人有什么地方是,过多的内存使用量可能来自任何想法,这将是伟大的! (我个人认为,这是Thread.sleep()方法的错,但我不知道如何摆脱它)。



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



编辑:我设法得到它的工作使用第二个线程等待事件(不干净的代码的权利,但我会作出正确的)。

 公共类MediaFileCreator 
{

私人的AutoResetEvent openedEvent =新的AutoResetEvent(假);


公共媒体文件CreateNewMediaFile(字符串文件名)
{

变种MFILE =新的媒体文件(文件名);
变种线程=新主题(WaitForEvent);
const int的maxTimeToWait = 2000;
openedEvent.Reset();
thread.Start(MFILE);

变种的MediaPlayer =新的MediaPlayer();

mediaPlayer.Open(新的URI(mFile.PathToFile));

openedEvent.WaitOne(maxTimeToWait);

VAR fromThread = Dispatcher.FromThread(Thread.CurrentThread);
如果(fromThread!= NULL)fromThread.InvokeShutdown();

返回MFILE;

}

私人无效WaitForEvent(对象上下文)
{

VAR MFILE =(媒体文件)范围内;
变种的MediaPlayer =新的MediaPlayer();

mediaPlayer.MediaOpened + =
代表
{
如果(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 + =
代表
{
mFile.Failure = TRUE;
mediaPlayer.Close();
openedEvent.Set();
};

mediaPlayer.Open(新的URI(mFile.PathToFile));

Dispatcher.Run();
}
}


解决方案

一件事是肯定的:在 Thread.sleep代码通话无关,与你的内存问题



我会建议你清理你的代码多一点点。有没有必要为你要创建一个新的 MediaCreator 和新的的MediaPlayer 每个文件加载。这可能是内存使用的很大一部分,因为你创造那些的MediaPlayer 的对象,而不是关闭它们。该垃圾收集器将最终清除它们,但它可以使你的内存使用看起来巨大与此同时



考虑一下:



 公共静态无效AddMediaFilesToMediaList()
{
MediaFileCreator mfCreator =新MediaFileCreator();

,而(MediaFilesQueue.Count大于0)
{
//所有的文件被加载到队列前处理
串pathToFile = MediaFilesQueue.Dequeue() ;

媒体文件MF = mfCreator.CreateNewMediaFile(pathToFile);

MediaData.MediaList.Add(MF);
}
}

公共类MediaFileCreator
{
私人的MediaPlayer播放器=新的MediaPlayer();
私人的ManualResetEvent openedEvent =新的ManualResetEvent(假);

公共MediaFileCreator()
{
player.MediaOpened = MediaOpened;
}

私人无效MediaOpened(对象发件人,EventArgs参数)
{
openedEvent.Set();
}

公共媒体文件CreateNewMediaFile(字符串文件名)
{
openedEvent.Reset();

player.Open(新的URI(tempMediaFile.PathToFile));

//等待它加载
openedEvent.WaitOne();

媒体文件MF =新的媒体文件(文件名);
mf.HasVideo = player.HasVideo;
mf.HasAudio = player.HasAudio;
mf.TimeSpanOfMediaFile = player.NaturalDuration.TimeSpan;

player.Close();

返回MF;
}
}

这简化了的东西相当多,仅使用一个的MediaPlayer 对象,它应该减少对内存的占用了不少。



我真的不知道是什么问题是你的的AutoResetEvent 不工作。它的看起来的权利。



在这个新的代码,你可以把一个断点上的 waitHandle.Set 打电话,看看它的实际打击。当完全 MediaOpened 事件被触发,或什么球员的状态应该是,当引发事件我不知道。该文档是可疑沉默了。



这是可能的,问题是的MediaPlayer 希望其代码中执行上UI线程。我不熟悉不够用WPF控件说。你可以称之为 VerifyAccess 来确定您的线程可以访问该对象。


I'm trying to create a media player (with Media.MediaPlayer() class) and for this I am using a thread to process the songs that are loaded by the user using the OpenFileDialog. I am using the next code to start the process the songs:

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


            }

}

And this is the MediaFileCreator class:

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;


        } 

And this is the MediaFile class:

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

        public TimeSpan TimeSpanOfMediaFile;

        public String PathToFile = null;

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

My problem is that the program stops at waitHandle.WaitOne(); and tries to run that line again and again. I tried other variants like the one in the first commented section by attaching that event handler to the Open event, but the result was the same: waitHandle.Set(); never executes and the value of the waitHandle is always false. The only option that I managed to get working is the the solution from the second commented section: blocking the thread (with Thread.Sleep) until the file is completely loaded (the file is loaded for example when the TimeSpan is initialised) ... which is time lost and performance decrease for my application. The problem is obviously not with the event itself, because the event triggers if it's run on the main thread (the method AddMediaFilesToMediaList() is called from a BackgroundWorker Thread that launches the method inside a new thread when it detects that there are elements in the Queue; the AddMediaFilesToMediaList() thread is created with new Thread() ) and obviously the file is loading because the TimeSpan is initialized. I really want to make the application work using the waitHandle or something like that. I don't want to use the Thread.Sleep() because it's ugly and my application also has a memory leak when I try to load a lot of files (i takes over 1.2 GB of memory and the it stops with errors (OutOfMemory) - I tried to load 2048 songs in it) and I believe that it could be because of the Thread.Sleep(). Even if it isn't, it will be much more easy to debug without the problem of the Thread.Sleep().

So how can I make the waitHandle to work ? How can I make the waitHandle.Set(); to run ? And if anyone has any idea about where that that excessive memory usage could come from, it would be great ! (I personally believe that it's the fault of Thread.Sleep() but I don't know how to get rid of it).

Edit : The reason I use an MediaFileCreator object is that initially I wanted to use a thread pool of 2 to 4 threads to process the media files, but I had the same problem so I removed the ThreadPool and I tried with the code posted above, but the same problem occurred.

Edit : I managed to get it working using a second thread to wait for the event (not the cleanest code right now, but I'll make it right).

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

解决方案

One thing is for certain: the Thread.Sleep call has nothing to do with your memory problem.

I would suggest that you clean up your code a little bit more. There's no need for you to be creating a new MediaCreator and a new MediaPlayer for every file you load. That could be a large part of the memory use, since you're creating all those MediaPlayer objects and not closing them. The garbage collector will eventually clean them up, but it can make your memory use look huge in the meantime.

Consider this:

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

That simplifies things quite a bit and uses only one MediaPlayer object, which should cut down quite a bit on the memory usage.

I really don't know what the problem is with your AutoResetEvent not working. It looks right.

In this new code, you can put a breakpoint on the waitHandle.Set call to see if it's actually hit. I don't know when exactly the MediaOpened event is triggered, or what the state of the player is supposed to be when the event is raised. The documentation is suspiciously silent about that.

It's possible the problem is that MediaPlayer wants its code to be executing on the UI thread. I'm not familiar enough with the WPF controls to say. You might call VerifyAccess to determine if your thread has access to the object.

这篇关于开放的MediaPlayer - 在线程事件未处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆