unosquare / ffmediaelement

FFME: The Advanced WPF MediaElement (based on FFmpeg)
https://unosquare.github.io/ffmediaelement/
Other
1.17k stars 240 forks source link

Crash after some calls of MediaElement.Close or MediaElement.Open #521

Closed VrezhAleksDev closed 3 years ago

VrezhAleksDev commented 4 years ago

We are working on a media library, which contains a lot of media files. When the mouse is over some of the library element it starts playing, when the mouse exit from the element or enter another element it closes or force open of new file. So in our flow, there are a lot of calls of Open and Close in different orders, and to avoid crashes we have written some class which is checking all states, and if no player is now working only in that case it starts doing some work like opening video or closing. But it still doesn't help and we get random crashes. Logs are attached bellow

Logs

Crash1Clean.txt Crash2Clean.txt Crash3Clean.txt

Issue Categories

Version Information

Steps to Reproduce

Open and close video or audio files in different orders, for example:

  1. Open video or audio file
  2. Close video or audio file
  3. Open another video or audio file
    1. Open another video or audio file again
    2. Close video or audio file

OR

  1. Open video or audio file
  2. Open another video or audio file again
  3. Open another video or audio file again
  4. Open another video or audio file again
  5. Close video or audio file

C

     private static bool MediaIsOpening
        {
            get
            {
                for (int i = 0; i < Instances.Count; i++)
                {
                    if (Instances[i].Player != null)
                    {
                        if (Instances[i].Player.IsOpening)
                        {
                            return true;
                        }
                    }

                    if (Instances[i].PlayerState == FFMEPlayerState.IsOpening)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        private static bool MediaIsClosing
        {
            get
            {
                for (int i = 0; i < Instances.Count; i++)
                {
                    if (Instances[i].Player != null)
                    {
                        if (Instances[i].Player.IsClosing)
                        {
                            return true;
                        }
                    }

                    if (Instances[i].PlayerState == FFMEPlayerState.IsClosing)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        private static bool MediaIsChanging
        {
            get
            {
                for (int i = 0; i < Instances.Count; i++)
                {
                    if (Instances[i].Player != null)
                    {
                        if (Instances[i].Player.IsChanging)
                        {
                            return true;
                        }
                    }
                }
                return false;
            }
        }

        private static bool MediaIsPlaying
        {
            get
            {
                for (int i = 0; i < Instances.Count; i++)
                {
                    if (Instances[i].Player != null)
                    {
                        if (Instances[i].Player.IsPlaying)
                        {
                            return true;
                        }
                    }
                }
                return false;
            }
        }

        private static bool MediaIsSeeking
        {
            get
            {
                for (int i = 0; i < Instances.Count; i++)
                {
                    if (Instances[i].Player != null)
                    {
                        if (Instances[i].Player.IsSeeking)
                        {
                            return true;
                        }
                    }
                }
                return false;
            }
        }

        //business logic is working with this method
        public void TryOpen(string path)
        {
            if (!Player.IsPlaying)
            {
                if (!MediaIsClosing && !MediaIsOpening && !MediaIsChanging && !MediaIsSeeking)
                {
                    Debug.WriteLine("Open:" + path);
                    PlayerState = FFMEPlayerState.IsOpening;
                    Open(path);
                }
            }
            else
            {
                ManagerState = MediaManagerState.Stoped;
            }

            PlayerState = FFMEPlayerState.None;
        }

        //business logic is working with this method
        public void TryClose()
        {
            if (!Player.IsMuted)
            {
                Player.IsMuted = true;
            }

            PlayerState = FFMEPlayerState.CloseRequested;
        }

        private void TryCloseAndDispose(bool disposeRequired)
        {
            if (Player.IsOpen && Player.Source != null)
            {
                if (!Player.IsPlaying)
                {
                    if (!MediaIsClosing && !MediaIsOpening && !MediaIsChanging && !MediaIsSeeking)
                    {
                        PlayerState = FFMEPlayerState.IsClosing;

                        Debug.WriteLine("Close:" + Player.Source.AbsolutePath);

                        Close(disposeRequired);
                    }
                }
                else
                {
                    ManagerState = MediaManagerState.Stoped;
                }
            }
        }

        //called every 100 ms
        public static void Loop()
        {
            for (int i = 0; i < Instances.Count; i++)
            {
                if (Instances[i].PlayerState == FFMEPlayerState.CloseRequested || Instances[i].PlayerState == FFMEPlayerState.DisposeRequested)
                {
                    Instances[i].TryCloseAndDispose(Instances[i].PlayerState == FFMEPlayerState.DisposeRequested);
                }
            }
        }

        async Task Open(string path)
        {
            //potentional crash reason
            await Player.Open(new Uri(path));
        }

        async Task Close(bool dispose)
        {
            //potentional crash reason
            await Player.Close();

            if (dispose)
            {
                Instances.Remove(this);
                Player.Dispose();
                _player = null;
            }
        }

Expected Results

rauba-code commented 3 years ago

I have this issue too. Please fix it.

alesebi91 commented 3 years ago

I have this issue too:

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.