gpt4 book ai didi

c# - 打开MediaPlayer-线程中未处理事件

转载 作者:行者123 更新时间:2023-12-03 13:20:28 27 4
gpt4 key购买 nike

我正在尝试创建一个媒体播放器(带有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(),当检测到线程中有元素时,该线程会在新线程内启动该方法。队列; AddMediaFilesToMediaList()线程是使用 new Thread()创建的,并且显然是在加载文件,因为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来确定您的线程是否有权访问该对象。

关于c# - 打开MediaPlayer-线程中未处理事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18156870/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com