You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt6.2 QMediaPlayer setActiveAudioTrack()致主线程死锁问题求助

Qt6.2 QMediaPlayer切换音轨导致主窗口死锁/无声问题解决

问题场景

在Ubuntu22.04系统使用Qt6.2的QMediaPlayer开发C++应用时,切换0号以外的音频通道经常出现主窗口冻结卡死,表现为:

  • 有时能正常切换到对应音轨
  • 有时切换后无声
  • 有时直接触发死锁,调试时程序停留在低级别锁等待代码(__GI___lll_lock_wait相关指令)

简化复现代码

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QMediaPlayer>
#include <QVideoWidget>
#include <QAudioOutput>


QMediaPlayer *Player;
QVideoWidget *VideoWidg;
QAudioOutput *AudioOutp;
int audio = 0;


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    Player  = new QMediaPlayer(this);
    VideoWidg = new QVideoWidget(this);
    VideoWidg->setFixedSize(640, 480);
    AudioOutp = new QAudioOutput(this);
    Player->setVideoOutput(VideoWidg);
    Player->setAudioOutput(AudioOutp);
    Player->setSource(QUrl::fromLocalFile("/home/wappler/movie.mkv"));
//    Player->setActiveAudioTrack(1); // <<<< does nothing here !!!!
    Player->play();
//    Player->setActiveAudioTrack(0); // <<<<  does nothing here !!!!
//    qt.multimedia.player: Attempt to set an incorrect index 0 for the track type 1
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_pushButton_clicked()
{
    if (audio == 0) {
        audio = 1;
    }
    else {
        audio = 0;
    }
    Player->setActiveAudioTrack(audio);    //sometimes (!) works / sometimes disables sound / sometimes locks
    qDebug () << audio << Player->activeAudioTrack();   //looks ok
}

死锁调试栈片段

0x7ffff60912a5  <+   21>        85 c0                    test   %eax,%eax
0x7ffff60912a7  <+   23>        74 47                    je     0x7ffff60912f0 <__GI___lll_lock_wait+96>
        48 [1]  in ./nptl/lowlevellock.c
0x7ffff60912a9  <+   25>        90                       nop
        ../sysdeps/nptl/futex-internal.h:
0x7ffff60912aa  <+   26>        44 89 c6                 mov    %r8d,%esi
0x7ffff60912ad  <+   29>        45 31 d2                 xor    %r10d,%r10d
0x7ffff60912b0  <+   32>        ba 02 00 00 00           mov    $0x2,%edx
0x7ffff60912b5  <+   37>        b8 ca 00 00 00           mov    $0xca,%eax
0x7ffff60912ba  <+   42>        40 80 f6 80              xor    $0x80,%sil
0x7ffff60912be  <+   46>        0f 05                    syscall
0x7ffff60912c0  <+   48>        48 3d 00 f0 ff ff        cmp    $0xfffffffffffff000,%rax
0x7ffff60912c6  <+   54>        76 d6                    jbe    0x7ffff609129e <__GI___lll_lock_wait+14>
        147 [1] in ../sysdeps/nptl/futex-internal.h
0x7ffff60912c8  <+   56>        83 c0 0b                 add    $0xb,%eax
0x7ffff60912cb  <+   59>        83 f8 0b                 cmp    $0xb,%eax
0x7ffff60912ce  <+   62>        77 0b                    ja     0x7ffff60912db <__GI___lll_lock_wait+75>
0x7ffff60912d0  <+   64>        ba 81 08 00 00           mov    $0x881,%edx
0x7ffff60912d5  <+   69>        48 0f a3 c2              bt     %rax,%rdx
0x7ffff60912d9  <+   73>        72 c3                    jb     0x7ffff609129e <__GI___lll_lock_wait+14>
        87 [1]  in ../sysdeps/nptl/futex-internal.h
0x7ffff60912db  <+   75>        50                       push   %rax

解决方案

1. 等待媒体加载完成后再操作音轨

Qt6.2中QMediaPlayer设置源后需等待元数据加载完成才能正确操作音轨,否则会出现索引无效问题。修改初始化逻辑,监听mediaStatusChanged信号:

// 替换原初始化中的play()调用,改为监听信号
connect(Player, &QMediaPlayer::mediaStatusChanged, this, [this](QMediaPlayer::MediaStatus status) {
    if (status == QMediaPlayer::LoadedMedia) {
        // 此时可安全设置初始音轨或播放
        Player->play();
    }
});

2. 切换音轨时先暂停播放器

直接在播放状态切换音轨易触发线程死锁,改为先暂停、切换、再播放:

void MainWindow::on_pushButton_clicked()
{
    QMediaPlayer::PlaybackState prevState = Player->playbackState();
    if (prevState == QMediaPlayer::PlayingState) {
        Player->pause();
    }

    audio = (audio == 0) ? 1 : 0;
    
    // 验证音轨索引有效性
    auto audioTracks = Player->audioTracks();
    if (audio >= 0 && audio < audioTracks.count()) {
        Player->setActiveAudioTrack(audio);
        qDebug () << "Switched to track:" << audio << "Active track:" << Player->activeAudioTrack();
    } else {
        qDebug () << "Invalid audio track index:" << audio;
    }

    if (prevState == QMediaPlayer::PlayingState) {
        Player->play();
    }
}

3. 升级Qt版本到6.5+

Qt6.2属于早期版本,多媒体模块存在不少稳定性问题,音轨切换死锁是已知bug之一,升级到Qt6.5及以上版本可修复大部分底层锁竞争问题。

4. 避免全局变量引发的线程竞争

将Player、AudioOutp等变量改为类成员变量而非全局变量,减少跨线程访问的竞争风险:

// 在MainWindow类中声明
private:
    QMediaPlayer *Player;
    QVideoWidget *VideoWidg;
    QAudioOutput *AudioOutp;
    int audio = 0;

额外验证步骤

  • 使用Player->audioTracks()获取所有可用音轨,确认目标索引存在,避免传入无效值
  • 检查系统音频后端(PipeWire/PulseAudio)是否正常,Ubuntu22.04默认使用PipeWire,可尝试切换到PulseAudio测试是否为后端兼容问题

内容的提问来源于stack exchange,提问作者Marsoupilami

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 06:17:32