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