Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Qt 6 QML MediaPlayer not playing M3U8 streams on Android, while WebView does

Qt 6 QML MediaPlayer not playing M3U8 streams on Android, while WebView does

Scheduled Pinned Locked Moved Unsolved Mobile and Embedded
14 Posts 2 Posters 160 Views 1 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.
  • W Offline
    W Offline
    woodpecker
    wrote last edited by
    #1

    Hello!
    I'm trying to stream an IP camera, but the application output window first displays a warning:
    W/qt.multimedia.ffmpeg.mediadataholder(14712): Failed to open media file. FFmpeg error description: Invalid data encountered while processing input.

    Then, in onErrorOccurred, I get the error:
    E/qml(14712): MediaPlayer Error: 2 Failed to open file.
    Here's my code:

    ...
                       MediaPlayer {
                            id: mediaPlayer
    
                            source:  "https://cdn.some_domen/.../stream.m3u8?uuid=some_uuid&token=some_token"
                            videoOutput: videoOutput
                            audioOutput: AudioOutput {}
    
                            onErrorOccurred: {
                                console.error("MediaPlayer error:", mediaPlayer.error, mediaPlayer.errorString);
                            }
                        }
    
                        VideoOutput {
                            id: videoOutput
                            anchors.fill: parent
                            fillMode: VideoOutput.PreserveAspectFit
    
                            MouseArea {
                                anchors.fill: parent
                                onClicked: {
                                    if (mediaPlayer.playbackState === MediaPlayer.PlayingState)
                                        mediaPlayer.pause();
                                    else
                                        mediaPlayer.play();
                                }
                            }
                        }
    ...
    

    In the C++ code, I check for OpenSSL:

    qDebug() << "OpenSSL supported:" << QSslSocket::supportsSsl();
    
    qDebug() << QSslSocket::supportsSsl() << QSslSocket::sslLibraryBuildVersionString() <<" , "<< QSslSocket::sslLibraryVersionString();
    
    qDebug() << manager->supportedSchemes();
    
    

    In the application output window, I see:
    D/default (14712): OpenSSL supported: true
    D/default (14712): true "OpenSSL 3.0.7 1 Nov 2022", "OpenSSL 3.1.8 11 Feb 2025"
    D/default (14712): QList("file", "qrc", "assets", "http", "unix+http", "local+http", "https", "data")

    .
    However, if I use WebView instead of MediaPlayer, like this:

    ...
                    WebView {
                        id: webview
                        ...
                        url: "https://cdn.some_domen/.../stream.m3u8?uuid=some_uuid&token=some_token"
                       ...
                    }
    ...
    

    , then stream playback is working.
    The Qt version is 6.10.1.
    Has anyone come across this?
    Thanks in advance!

    1 Reply Last reply
    0
    • W Offline
      W Offline
      woodpecker
      wrote last edited by woodpecker
      #2

      I tried using the libvlc library, c++:

      #include <vlc/vlc.h>
      #include "vlc/libvlc_media.h"
      #include "vlc/libvlc_media_player.h"
      #include <QQuickItem>
      
      class VLCPlayer : public QQuickItem {
          Q_OBJECT
          QML_ELEMENT // This makes the class available for use/instantiation on the QML side.
          Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
      
      public:
          VLCPlayer() {
              qDebug() << "libvlc_new(0, nullptr)...";
      
              _vlcInstance = libvlc_new(0, nullptr);
      
              qDebug() << "libvlc_media_player_new...";
      
              _vlcPlayer = libvlc_media_player_new(_vlcInstance);
          }
      
          void setSource(const QString &path) {
              libvlc_media_t *m = libvlc_media_new_path(_vlcInstance, path.toUtf8().data());
              libvlc_media_player_set_media(_vlcPlayer, m);
              libvlc_media_release(m);
              libvlc_media_player_play(_vlcPlayer);
              emit sourceChanged();
          }
      
          QString source() const
          {
              return "";
          }
      
      signals:
          void sourceChanged();
      
      private:
          libvlc_instance_t *_vlcInstance;
          libvlc_media_player_t *_vlcPlayer;
      };
      

      and QML:

                          VLCPlayer {
                              id: player
                              anchors.fill: parent
                              source: "https://cdn.some_domen/.../stream.m3u8?uuid=some_uuid&token=some_token"
                          }
      
      

      ,
      but in the constructor, on the line
      _vlcInstance = libvlc_new(0, nullptr);
      the program crashes with the error:
      Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) in tid 10680 (qtMainLoopThrea)... .

      1 Reply Last reply
      0
      • W Offline
        W Offline
        woodpecker
        wrote last edited by
        #3

        After a long conversation with the AI, I managed to get playback working using the libvlc library!

        1 Reply Last reply
        0
        • W Offline
          W Offline
          woodpecker
          wrote last edited by
          #4

          If anyone is interested, here is the code:
          main.cpp

          #include <QGuiApplication>
          #include <QQmlApplicationEngine>
          
          int main(int argc, char *argv[])
          {
              QGuiApplication app(argc, argv);
          
              // 1. Load dependencies in the correct order via the Java layer
              // This will automatically call JNI_OnLoad and install s_jvm in VLC
              QJniObject::callStaticMethod<void>(
                  "java/lang/System",
                  "loadLibrary",
                  "(Ljava/lang/String;)V",
                  QJniObject::fromString("vlc").object() // core first
                  );
          
              QQmlApplicationEngine engine;
              QObject::connect(
                  &engine,
                  &QQmlApplicationEngine::objectCreationFailed,
                  &app,
                  []() { QCoreApplication::exit(-1); },
                  Qt::QueuedConnection);
              engine.loadFromModule("myproject", "Main");
          
              return app.exec();
          }
          
          

          .

          1 Reply Last reply
          0
          • W Offline
            W Offline
            woodpecker
            wrote last edited by
            #5

            vlcplayer.h

            #ifndef VLCPLAYER_H
            #define VLCPLAYER_H
            
            #include <vlc/vlc.h>
            #include "vlc/libvlc_media.h"
            #include "vlc/libvlc_media_player.h"
            #include <QtQml/qqmlregistration.h> //for QML_ELEMENT
            #include <QMutex>
            #include <vector>
            #include <QPointer>
            #include <QVideoSink>
            
            // using namespace QNativeInterface;
            
            // extern "C" {
            // // We declare the function we found using nm
            // void libvlc_media_player_set_android_context(libvlc_media_player_t *p_mi, void *p_jvm_or_surface);
            // }
            
            class VLCPlayer : public QObject {
                Q_OBJECT
                QML_ELEMENT // This makes the class available for use/instantiation on the QML side.
                Q_PROPERTY(QVideoSink* videoSink READ videoSink WRITE setVideoSink NOTIFY videoSinkChanged)
            public:
                VLCPlayer();
            
                Q_INVOKABLE void setSource(const QString &path);
            
               // 1. LOCK: VLC asks where to write the pixels of the next frame
               static void* lock(void *opaque, void **planes);
            
               // 2. UNLOCK: The frame has been written to the buffer
               static void unlock(void *opaque, void *picture, void *const *planes);
            
               // 3. DISPLAY: It's time to tell Qt that the image has been updated
               static void display(void *opaque, void *picture);
            
               QVideoSink *videoSink() const;
               void setVideoSink(QVideoSink *newVideoSink);
            
                // Video settings (can be changed)
                const int VIDEO_WIDTH = 1280;
                const int VIDEO_HEIGHT = 720;
            
                std::vector<uchar> videoBuffer;
                QMutex bufferMutex;
                libvlc_media_player_t *mp = nullptr;
            signals:
                void videoSinkChanged();
                void frameReady();
            
            public slots:
                void onframeReady();
            
            private:
                libvlc_instance_t *_vlcInstance;
                libvlc_media_player_t *_vlcPlayer;
                QPointer<QVideoSink> m_videoSink;
            };
            1 Reply Last reply
            0
            • W Offline
              W Offline
              woodpecker
              wrote last edited by
              #6

              vlcplayer.cpp

              1 Reply Last reply
              0
              • W Offline
                W Offline
                woodpecker
                wrote last edited by
                #7

                I can't paste it - I get a message that it's spam...

                1 Reply Last reply
                0
                • W Offline
                  W Offline
                  woodpecker
                  wrote last edited by
                  #8
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • W Offline
                    W Offline
                    woodpecker
                    wrote last edited by
                    #9
                    This post is deleted!
                    1 Reply Last reply
                    0
                    • W Offline
                      W Offline
                      woodpecker
                      wrote last edited by
                      #10
                      This post is deleted!
                      1 Reply Last reply
                      0
                      • W Offline
                        W Offline
                        woodpecker
                        wrote last edited by
                        #11
                        #include "vlcplayer.h"
                        #include <QPainter>
                        #include <QVideoFrame>
                        
                        VLCPlayer::VLCPlayer() {
                            videoBuffer.resize(VIDEO_WIDTH * VIDEO_HEIGHT * 4); // RGBA
                            connect(this, &VLCPlayer::frameReady, this, &VLCPlayer::onframeReady);
                        }
                        
                        void VLCPlayer::setSource(const QString &path) {
                            // const char* vlc_args[] = { "--no-osd" };
                            _vlcInstance = libvlc_new(0, nullptr); //libvlc_new(1, vlc_args);
                            _vlcPlayer = libvlc_media_player_new(_vlcInstance);
                        
                            // Set the format: RGBA (4 bytes per pixel), width, height, pitch
                            libvlc_video_set_format(_vlcPlayer, "RGBA", VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_WIDTH * 4);
                        
                            // Link our functions
                            libvlc_video_set_callbacks(_vlcPlayer, &VLCPlayer::lock, &VLCPlayer::unlock, &VLCPlayer::display, this);
                        
                            libvlc_media_t *m = libvlc_media_new_location(_vlcInstance, path.toUtf8().constData());
                            libvlc_media_player_set_media(_vlcPlayer, m);
                            libvlc_media_release(m);
                            libvlc_media_player_play(_vlcPlayer);
                        }
                        
                        QVideoSink* VLCPlayer::videoSink() const
                        {
                            return m_videoSink.get();
                        }
                        
                        void VLCPlayer::setVideoSink(QVideoSink *newVideoSink)
                        {
                            if (m_videoSink == newVideoSink)
                                return;
                            m_videoSink = newVideoSink;
                            emit videoSinkChanged();
                        }
                        
                        void* VLCPlayer::lock(void *opaque, void **planes) {
                            VLCPlayer *player = static_cast<VLCPlayer*>(opaque);
                            player->bufferMutex.lock();
                            *planes = player->videoBuffer.data();
                            return nullptr;
                        }
                        
                        void VLCPlayer::unlock(void *opaque, void *picture, void *const *planes) {
                            VLCPlayer *player = static_cast<VLCPlayer*>(opaque);
                            player->bufferMutex.unlock();
                        }
                        
                        void VLCPlayer::display(void *opaque, void *picture) {
                            VLCPlayer *player = static_cast<VLCPlayer*>(opaque);
                            // Generate a signal to redraw the user interface in Qt's main thread
                            emit player->frameReady();
                        }
                        
                        void VLCPlayer::onframeReady()
                        {
                            if(!m_videoSink)
                                return;
                        
                            bufferMutex.lock();
                        
                            // Create a QImage object that simply "looks" at your video buffer (without copying)
                            QImage img(videoBuffer.data(), VIDEO_WIDTH, VIDEO_HEIGHT, QImage::Format_RGBA8888);
                        
                            // In Qt 6, you can create a frame directly from a QImage
                            // if the formats match, Qt will try to minimize overhead
                            QVideoFrame frame(img);
                        
                            // Sending to Sink
                            m_videoSink->setVideoFrame(frame);
                        
                            bufferMutex.unlock();
                        }
                        
                        
                        1 Reply Last reply
                        0
                        • W Offline
                          W Offline
                          woodpecker
                          wrote last edited by
                          #12

                          Because of the phrase "#include <Q D e b u g>," Askit considered this code spam.)
                          However, QDebug still needs to be enabled.

                          1 Reply Last reply
                          1
                          • W Offline
                            W Offline
                            woodpecker
                            wrote last edited by
                            #13

                            QML

                                                VLCPlayer {
                                                    id: vlcplayer
                                                    videoSink: videoOutput.videoSink
                                                }
                            
                                                VideoOutput {
                                                    id: videoOutput
                                                    anchors.fill: parent
                                                    fillMode: VideoOutput.PreserveAspectFit
                                                }
                                                
                                                Component.onCompleted: vlcplayer.setSource("https://cdn.some_domen/.../stream.m3u8?uuid=some_uuid&token=some_token")
                            
                            
                            
                            1 Reply Last reply
                            1
                            • KH-219DesignK Offline
                              KH-219DesignK Offline
                              KH-219Design
                              wrote last edited by KH-219Design
                              #14

                              Interesting! I recently did some experimentation with Qt combined with IP camera, and I had less-than-ideal results (which I planned to revisit at some point but have not gotten around to).

                              @woodpecker How is the timing/lag/performance?

                              My principal issue was huge lag, which I also experienced when just using ffmpeg at the command line. (Since Qt uses ffmpeg under the hood I suspect the actual source of lag is therefore ffmpeg.)

                              I had come across:

                              https://forum.qt.io/topic/79208/how-to-kill-delay-in-live-streaming (which never got any reply at all)

                              https://stackoverflow.com/questions/7759695/terrible-performance-with-qmediaplayer-and-qvideowidget

                              But your (very) recent outcome will be of interest to myself and others! How's the lag?

                              (Also, you mentioned 6.10.1 but can you also state which OS or OSes?) EDIT: Android is in the title! But still I'm curious if you build for Linux/Windows also?

                              www.219design.com
                              Software | Electrical | Mechanical | Product Design

                              1 Reply Last reply
                              0

                              • Login

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