Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Crash when deleting QMediaPlayer
Forum Updated to NodeBB v4.3 + New Features

Crash when deleting QMediaPlayer

Scheduled Pinned Locked Moved Unsolved General and Desktop
10 Posts 2 Posters 981 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    DarioA
    wrote on last edited by
    #1

    I have a custom QAbstractVideoSurface attached to using QMediaPlayer using QMediaPlayer::setVideoOutput. I setup the media player like this:

      m_MediaPlayer = new QMediaPlayer(this, QMediaPlayer::VideoSurface);
      m_MediaPlayer->setMedia(url);
      m_MediaPlayer->setVideoOutput(m_VideoSurface);
    

    When my class containing these objects is deleted, the video surface gets deleted with it (since the video surface is a child QObject). This causes a crash in dsengined.dll!EVRCustomPresenter::flush() Line 1146 at c:\users\qt\work\qt\qtmultimedia\src\plugins\common\evr\evrcustompresenter.cpp(1146)

        if (m_renderState == RenderStopped && m_surface->isActive()) {
    

    since m_surface is junk at that point.

    To work around this, I have to unparent the video surface from my parent object and then in the destructor do a m_videoSurface->deleteLater()

    Feels like the dsengined.dll!EVRCustomPresenter::flush() should check to make sure m_surface is not null before dereferencing it.

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi and welcome to devnet,

      How are you building that object ?
      What version of Qt are you using ?
      On what version of Windows ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • D Offline
        D Offline
        DarioA
        wrote on last edited by DarioA
        #3

        Hi and welcome to devnet,

        Thanks :)

        How are you building that object ?

        class VideoFileVideoSource : public AbstractVideoSource
        {
          friend class VideoFileVideoSurface;
          Q_OBJECT
        
        public:
          VideoFileVideoSource(const QUrl &url, QObject *parent);
          ~VideoFileVideoSource();
        
          // Overrides
          virtual bool CanEditSettings() const;
          virtual void EditSettings(QWidget *parent);
        
        signals:
          void FrameAvailable(const QVideoFrame &frame);
        
        private slots:
          void MediaPlayerError(QMediaPlayer::Error error);
          void MediaPlayerMediaStatusChanged(QMediaPlayer::MediaStatus status);
          void MediaPlayerStateChanged(QMediaPlayer::State newState);
        
        private:
          // AbstractVideoSource overrides
          void DoStart();
          void DoStop();
        
          // Called by VideoFileVideoSurface when a new video frame is available
          void VideoSurfaceFrameAvailable(const QVideoFrame &frame);
        
          void LoadSettings();
          void SaveSettings();
        
          QMediaPlayer *m_MediaPlayer;
          VideoFileVideoSurface *m_VideoSurface;
        };
        
        
        class VideoFileVideoSurface : public QAbstractVideoSurface
        {
          VideoFileVideoSource *m_Parent;
        public:
        
          VideoFileVideoSurface(VideoFileVideoSource *parent)
          : QAbstractVideoSurface(nullptr) // Don't pass parent in here since we want to control when things get deleted
          , m_Parent(parent)
          {
          }
        
          QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const
          {
            // Return the formats you will support
            Q_UNUSED(handleType);
        
            return AppUtils::GetSupportedPixelFormats();
          }
        
          bool present(const QVideoFrame &frame)
          {
            // Handle the frame and do your processing
            Q_UNUSED(frame);
        
        //    qDebug() << "VideoSurface::present pixelFormat: " << frame.pixelFormat();
        
            m_Parent->VideoSurfaceFrameAvailable(frame);
        
            return true;
          }
        };
        
        ///////////////////////////////////////////////////////////////////////////////////////////////////
        VideoFileVideoSource::VideoFileVideoSource(const QUrl &url, QObject *parent)
        : AbstractVideoSource(parent)
        , m_MediaPlayer(nullptr)
        , m_VideoSurface(nullptr)
        {
          m_VideoSurface = new VideoFileVideoSurface(this);
        
          m_MediaPlayer = new QMediaPlayer(this, QMediaPlayer::VideoSurface);
          m_MediaPlayer->setMedia(url);
          m_MediaPlayer->setVideoOutput(m_VideoSurface);
        
          // This will set the playback rate directly onto the media player object
          LoadSettings();
        
          connect(m_MediaPlayer, SIGNAL(error(QMediaPlayer::Error)),
                                 SLOT(MediaPlayerError(QMediaPlayer::Error)));
          connect(m_MediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
                                 SLOT(MediaPlayerMediaStatusChanged(QMediaPlayer::MediaStatus)));
          connect(m_MediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)),
                                 SLOT(MediaPlayerStateChanged(QMediaPlayer::State)));
        }
        
        VideoFileVideoSource::~VideoFileVideoSource()
        {
          // Can't delete it now since there is a crash deep in Qt's directshow relatd code that assumes
          // that the surface still exists (only on windows).
          m_VideoSurface->deleteLater();
          m_VideoSurface = nullptr;
        }
        
        bool VideoFileVideoSource::CanEditSettings() const
        {
          return m_MediaPlayer->playbackRate() > 0.0;
        }
        
        void VideoFileVideoSource::EditSettings(QWidget *parent)
        {
          double playbackRate = m_MediaPlayer->playbackRate();
          VideoFilesSettingsDialog dlg(playbackRate, parent);
          int result = dlg.exec();
          if (result == QDialog::Accepted)
          {
            double playbackRate = dlg.GetPlaybackRate();
            m_MediaPlayer->setPlaybackRate(playbackRate);
        
            SaveSettings();
          }
        }
        
        void VideoFileVideoSource::MediaPlayerError(QMediaPlayer::Error error)
        {
          qCritical() << "MediaPlayerError: " << error;
        }
        
        void VideoFileVideoSource::MediaPlayerMediaStatusChanged(QMediaPlayer::MediaStatus status)
        {
          qDebug() << "MediaPlayerMediaStatusChanged: " << status;
        }
        
        void VideoFileVideoSource::MediaPlayerStateChanged(QMediaPlayer::State newState)
        {
          qDebug() << "MediaPlayerStateChanged: " << newState;
        
          // Loop
          if (newState == QMediaPlayer::StoppedState)
          {
            m_MediaPlayer->setPosition(0);
            m_MediaPlayer->play();
          }
        }
        
        void VideoFileVideoSource::DoStart()
        {
          m_MediaPlayer->play();
        }
        
        void VideoFileVideoSource::DoStop()
        {
          m_MediaPlayer->pause();
        }
        
        void VideoFileVideoSource::VideoSurfaceFrameAvailable(const QVideoFrame &frame)
        {
          // So, present on the QAbstractVideoSurface gets called even when we call pause and stop
          // so let's only forward the frame when the players state is actually playing
          if (m_MediaPlayer->state() == QMediaPlayer::PlayingState)
          {
            emit FrameAvailable(frame);
          }
        }
        
        void VideoFileVideoSource::LoadSettings()
        {
          QSettings settings(AppUtils::GetSettingsPath(), QSettings::IniFormat);
        
          settings.beginGroup("VideoFileVideoSource");
          double playbackRate = settings.value("PlaybackRate", m_MediaPlayer->playbackRate()).toDouble();
          if (playbackRate > 0.001)
          {
            m_MediaPlayer->setPlaybackRate(playbackRate);
          }
          settings.endGroup();
        }
        
        void VideoFileVideoSource::SaveSettings()
        {
          QSettings settings(AppUtils::GetSettingsPath(), QSettings::IniFormat);
        
          settings.beginGroup("VideoFileVideoSource");
          settings.setValue("PlaybackRate", m_MediaPlayer->playbackRate());
          settings.endGroup();
        }
        
        
        

        What version of Qt are you using ?

        5.13.1

        On what version of Windows ?

        Windows 10 Pro Version: 1903

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Since you seem to be properly parenting your object, why are you trying to delete them in the destructor ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          D 1 Reply Last reply
          2
          • SGaistS SGaist

            Since you seem to be properly parenting your object, why are you trying to delete them in the destructor ?

            D Offline
            D Offline
            DarioA
            wrote on last edited by
            #5

            @sgaist This is the code with the workaround. The original code didn't do anything in the destructor and was relying on the QObject child lifecycle management for the object to be destroyed.

            The original code (which I guess I should have posted) passed in the VideoFileVideoSource as the parent to the QAbstractVideoSurface constructor:

            VideoFileVideoSurface(VideoFileVideoSource *parent)
              : QAbstractVideoSurface(parent) // Code above passes in nullptr
            

            And the destructor of VideoFileVideoSource was just this:

            VideoFileVideoSource::~VideoFileVideoSource()
            {
            }
            

            One tick after that destructor executed was the crash, as the surface was automatically deleted by QObject (but the direct show code, which was running on some system callback or something, still assumed that the surface was alive). If I set the video surface to nullptr in the destructor m_MediaPlayer->setVideoOutput((QAbstractVideoSurface *)nullptr);, the crash would be immediate (i.e. right in the destructor call, as all over the directshow code, the surface is assumed to be non-null and still alive.

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              Do you have the full stack trace ?

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              D 1 Reply Last reply
              0
              • SGaistS SGaist

                Do you have the full stack trace ?

                D Offline
                D Offline
                DarioA
                wrote on last edited by DarioA
                #7

                @sgaist ![Here's the Visual Studio call stack](0_1568809382430_75d15e07-94ca-453d-bd89-163aca23f18d-image.png image url)
                That's when I pass the VideoFileVideoSource parent to the QAbstractVideoSurface constructor and empty the constructor, as in the last code snippet I sent.

                The line numbers all correspond to source line numbers of Qt 5.13.1

                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  Do you get the same crash with Qt 5.12 ?

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  D 1 Reply Last reply
                  0
                  • SGaistS SGaist

                    Do you get the same crash with Qt 5.12 ?

                    D Offline
                    D Offline
                    DarioA
                    wrote on last edited by
                    #9

                    @sgaist I haven't tried any other versions of Qt. First time working with Qt in about 8 years and this is a brand new project

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      Then I recommend testing the latest Qt 5.12 to see if you found a new issue or if there's something specific to your machine.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply
                      1

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved