Playing Video with QML on Linux: Solving Audio Dependency Issues and Implementing a Complete Player

In cross-platform Qt development, QML provides concise and powerful multimedia support, allowing for easy video playback functionality through the <span>MediaPlayer</span> and <span>VideoOutput</span> components. However, when running QML video playback applications on Linux systems (especially Ubuntu/Debian-based), users often encounter issues such as “no sound” or “unable to play”. The root cause lies in the fact that Qt’s multimedia backend (such as GStreamer) relies on the system’s audio service, and the default installation of Qt may lack development support for the PulseAudio audio system.

This article will delve into this issue and provide a complete solution from environment configuration, code writing, to debugging verification, helping you achieve sound-enabled QML video playback on Linux.

1. Problem Phenomenon and Root Cause

1.1 Typical Error Manifestations

  • The video displays normally, but there is no sound;
  • The console outputs warnings similar to:
    GStreamer-CRITICAL**: gst_element_make_from_uri: assertion 'type == GST_URI_SRC || type == GST_URI_SINK' failed
    Warning:"No decoder available for type 'audio/x-raw'."
  • Or it directly indicates that audio plugins are missing.

1.2 Root Cause Analysis

The Qt Multimedia module on Linux typically relies on the GStreamer multimedia framework. For GStreamer to output audio to the system, it must go through PulseAudio (the mainstream audio service for modern Linux desktops) or ALSA.

When you install Qt from official sources or online, its precompiled <span>libQt6Multimedia.so</span> (or the Qt5 version) may not be linked with PulseAudio support because the <span>libpulse-dev</span> development package was missing during the build.

βœ… Solution: Install the PulseAudio development headers, then rebuild the Qt Multimedia module (or ensure that the complete dependencies are installed on the system).

2. Environment Preparation: Installing Necessary Dependencies

2.1 Install PulseAudio Development Package (Key Step)

# Ubuntu / Debian / Linux Mint
sudo apt-get update
sudo apt-get install libpulse-dev

# It is also recommended to install the complete GStreamer plugins
sudo apt-get install gstreamer1.0-plugins-base \
                     gstreamer1.0-plugins-good \
                     gstreamer1.0-plugins-bad \
                     gstreamer1.0-plugins-ugly \
                     gstreamer1.0-libav \
                     gstreamer1.0-pulseaudio

πŸ’‘ <span>libpulse-dev</span> provides headers such as <span>pulse/pulseaudio.h</span>, enabling Qt to activate the PulseAudio backend when building the Multimedia module.

2.2 Verify if PulseAudio is Running

# Check service status
pactl info

# You should see output similar to:
# Server Name: pulseaudio
# Default Sink: alsa_output.pci-0000_00_1f.3.analog-stereo

If it is not running, you can start it manually:

pulseaudio --start

3. Complete Implementation of QML Video Player

3.1 Project Structure

VideoPlayer/
β”œβ”€β”€ main.cpp
β”œβ”€β”€ main.qml
└── VideoPlayer.pro (or CMakeLists.txt)

3.2 C++ Main Program (main.cpp)

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QLoggingCategory>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

// Optional: Enable multimedia debug logging
    QLoggingCategory::setFilterRules(QStringLiteral("qt.multimedia.*=true"));

    QQmlApplicationEngine engine;
    const QUrl url(u"qrc:/main.qml"_qs);
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

3.3 QML Video Playback Interface (main.qml)

import QtQuick
import QtQuick.Controls
import QtMultimedia

ApplicationWindow {
    id: window
    width: 800
    height: 600
    visible: true
    title: "QML Video Player on Linux"

    MediaPlayer {
        id: mediaPlayer
        // Supports local files or network streams
        source: "file:///home/user/videos/sample.mp4"
        // or source: "https://example.com/video.mp4"

        // Auto play (optional)
        // autoPlay: true

        // Error handling
        onErrorChanged: {
            if (error !== MediaPlayer.NoError) {
                console.error("MediaPlayer error:", errorString)
            }
        }
    }

    VideoOutput {
        id: videoOutput
        anchors.fill: parent
        source: mediaPlayer
    }

    // Control bar
    Rectangle {
        anchors.bottom: parent.bottom
        width: parent.width
        height: 60
        color: "#333333"

        Row {
            anchors.centerIn: parent
            spacing: 10

            Button {
                text: mediaPlayer.playbackState === MediaPlayer.PlayingState ? "⏸️ Pause" : "▢️ Play"
                onClicked: {
                    if (mediaPlayer.playbackState === MediaPlayer.PlayingState)
                        mediaPlayer.pause()
                    else
                        mediaPlayer.play()
                }
            }

            Button {
                text: "⏹️ Stop"
                onClicked: mediaPlayer.stop()
            }

            Slider {
                id: volumeSlider
                from: 0
                to: 1
                value: mediaPlayer.volume
                onValueChanged: mediaPlayer.volume = value
                Layout.fillWidth: true
                width: 150
            }

            Label {
                text: "Volume: " + Math.round(volumeSlider.value * 100) + "%"
                color: "white"
            }
        }
    }

    // Loading indicator
    BusyIndicator {
        anchors.centerIn: parent
        running: mediaPlayer.status === MediaPlayer.Loading
        visible: running
    }
}

3.4 Project File (VideoPlayer.pro)

QT += quick multimedia

CONFIG += c++17

SOURCES += \
    main.cpp

RESOURCES += qml.qrc

target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/video
INSTALLS += target

πŸ“Œ If using CMake, ensure to link <span>Qt6::Multimedia</span>.

4. Compilation and Execution

4.1 Build with qmake

cd VideoPlayer
qmake
make -j$(nproc)
./VideoPlayer

4.2 Build with CMake (Recommended for Qt6)

# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(VideoPlayer VERSION 1.0)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)

find_package(Qt6 REQUIRED COMPONENTS Quick Multimedia)

qt_add_executable(VideoPlayer
    main.cpp
    main.qml
)

target_link_libraries(VideoPlayer PRIVATE Qt6::Quick Qt6::Multimedia)

Build command:

mkdir build && cd build
cmake ..
cmake --build .
./VideoPlayer

5. Debugging and Verification

5.1 Check if Qt Multimedia Plugin Includes PulseAudio

# Check multimedia plugins in the Qt installation directory
ls $QTDIR/plugins/mediaservice/

# Should normally include:
# libgstmediaplayer.so  (GStreamer backend)
# libqtmedia_pulse.so   ← Key! PulseAudio audio plugin

If <span>libqtmedia_pulse.so</span> is missing, it indicates that Qt Multimedia is not correctly linked with PulseAudio, and you need to recompile Qt or install the official full version (e.g., by selecting “Full installation” through the online installer).

5.2 Enable Detailed Logging

Add the following in <span>main.cpp</span>:

qputenv("QT_LOGGING_RULES", "qt.multimedia.*=true");

During runtime, observe the console output to confirm that the audio pipeline is established successfully:

qt.multimedia.gstreamer: Created audio sink: pulsesink

6. Common Problem Troubleshooting

Problem Solution
Video with no sound 1. Ensure that <span>libpulse-dev</span> is installed and the project is rebuilt. 2. Check if <span>pactl list sinks</span> shows any output devices. 3. Verify that the video file itself has an audio track.
Unable to play MP4/H.264 Install <span>gstreamer1.0-libav</span> and <span>gstreamer1.0-plugins-ugly</span>
Black screen or stuttering Try setting <span>videoOutput.fillMode = VideoOutput.PreserveAspectFit</span>
Network video fails to load Ensure the URL is accessible and that GStreamer supports the protocol (e.g., HTTP/RTSP).

7. Alternative Solution: Using VLC Backend (Advanced)

If GStreamer remains unstable, consider using QtVLC or Phonon-VLC, but this requires additional integration of the VLC library, which is more complex. For most scenarios, correctly configuring GStreamer + PulseAudio is sufficient.

8. Conclusion

To play videos with sound using QML on Linux, the key is to ensure that the Qt Multimedia module can correctly call the PulseAudio audio service. The following steps can resolve the issue:

βœ… 1. Install development dependencies:

sudo apt-get install libpulse-dev gstreamer1.0-pulseaudio

βœ… 2. Write standard QML video playback code (using <span>MediaPlayer</span> + <span>VideoOutput</span>);

βœ… 3. Rebuild the project (ensuring it is linked to PulseAudio support);

βœ… 4. Verify the existence of audio plugins and enable debug logging.

By following this guide, you will be able to build a fully functional, synchronized QML video playback application on mainstream Linux distributions such as Ubuntu, Debian, and Fedora.

Other

  1. Domestic Open Source: https://gitee.com/feiyangqingyun
  2. International Open Source: https://github.com/feiyangqingyun
  3. Project Collection: https://qtchina.blog.csdn.net/article/details/97565652
  4. Contact: WeChat feiyangqingyun
  5. Official Store: https://shop114595942.taobao.com/

Leave a Comment