Qt循环播放音乐后程序异常崩溃 (SIGSEGV错误)

本文介绍了在Qt游戏中添加背景音乐并实现循环播放时遇到的问题及其解决方案。问题在于当音乐播放结束时,程序会出现段错误并崩溃。通过分析,发现是QMediaPlayer在媒体未完全加载时就开始播放导致的。解决方法包括确保QMediaPlaylist中包含多个音频文件以避免播放结束,或者监听QMediaPlayer的mediaStatusChanged信号并在结束时重新开始播放。提供了相应的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、出现问题

当我想为我的游戏添加背景音乐并让它循环播放时,我采取的方式是写一个bgmusic类(文章末尾我会给出没有问题的bgmusic的具体实现),它继承自QThread,并重写其中的run方法。至于这个类的使用,就是在需要播放背景音乐的地方直接new出一个对象,调用其start方法即可

普遍的做法(也是我刚开始出错的做法)如下代码所示:

QMediaPlaylist *playlist = new QMediaPlaylist();
playlist->addMedia(QUrl("qrc:/res/bg-Music.mp3")); // 请关注这里,只添加了一个音频
playlist->setPlaybackMode(QMediaPlaylist::Loop);
playerlist->setCurrentIndex(0);
QMediaPlayer *music = new QMediaPlayer();
music->setPlaylist(playlist);
music->play();

但如果直接这样写的话,当程序播放完背景音乐后,程序便会异常崩溃

小Tips:请关注资源的路径写法 ,如下图所示。

在这里插入图片描述


二、分析问题

经过调试,发现是程序出现段错误,被操作系统异常终止。这个错误是程序中经常出现的一个错误,程序访问了不该访问的地址。
那么,接下来,看qt的官方文档:
在这里插入图片描述
setMedia 函数会立即返回,不会等待媒体加载完毕。崩溃的原因应该就是有时加载快,完成了播放正常,有时加载慢未完成,播放就崩溃。


三、解决问题

3.1 针对上述普遍的做法的解决方案

保证QMediaPlaylist对象中添加了多于1个的音频对象
更改后的代码如下:

QMediaPlaylist *playlist = new QMediaPlaylist();
playlist->addMedia(QUrl("qrc:/res/bg-Music.mp3"));
playlist->addMedia(QUrl("qrc:/res/bg-Music.mp3")); // 新增加的
playlist->setPlaybackMode(QMediaPlaylist::Loop);
playerlist->setCurrentIndex(0);
QMediaPlayer *music = new QMediaPlayer();
music->setPlaylist(playlist);
music->play();

3.2针对于不使用QMediaPlaylist,而只是用QMediaPlayer对象实现循环播放的解决方案

要在你写的类中增加一个槽函数去监听QMediaPlayer::mediaStatusChanged信号


四、具体代码

需要说明的是,我将两种解决方案都写在了同一份代码中,并采用的是方案一,代码中我将方案二注释掉了,读者可以根据需要自行选择。

bgmusic.h

#ifndef BGMUSIC_H
#define BGMUSIC_H

#include <QThread>
#include <QMediaPlayer>
#include <QMediaPlaylist>

class bgmusic : public QThread
{
    Q_OBJECT
    void run() override;
public:
    bgmusic();

private:
    QMediaPlayer* player;
    QMediaPlaylist* playerList;
    void initStatus(QMediaPlayer::MediaStatus status); // 槽函数 监听QMediaPlayer::mediaStatusChanged信号
};

#endif // BGMUSIC_H

bgmusic.cpp

#include "bgmusic.h"

bgmusic::bgmusic()
{
    playerList = new QMediaPlaylist();
    player = new QMediaPlayer();
    playerList->addMedia(QUrl("qrc:/res/LevelWinSound.wav"));
    playerList->addMedia(QUrl("qrc:/res/TapButtonSound.wav")); // 方法一、保证有两个音频(可以相同)被添加
    playerList->setPlaybackMode(QMediaPlaylist::Loop);
    playerList->setCurrentIndex(0);
    player->setPlaylist(playerList);
    player->setVolume(100);
   // connect(player, &QMediaPlayer::mediaStatusChanged,this,&bgmusic::initStatus);// 方法二 槽函数 监听QMediaPlayer::mediaStatusChanged信号   进行连接
}

void bgmusic::run() {
     player->play();
}

void bgmusic::initStatus(QMediaPlayer::MediaStatus status){
    if(status == QMediaPlayer::EndOfMedia)
      {
          // player->setPosition(0);
          // player->play();
      }
}

Qt中捕获和处理SIGSEGV异常主要是通过QSignalMapper和QObject::installEventFilter()这两个工具。以下是一个简单的步骤: 1. 创建一个信号映射器(QSignalMapper)实例,它将信号与槽连接起来,并提供了一种在运行时动态关联信号的方式。 ```cpp QSignalMapper *signalMapper = new QSignalMapper(this); ``` 2. 定义一个槽函数,这个槽将在接收到SIGSEGV信号时被执行,用于处理异常情况。你可以在这里记录错误信息,尝试恢复或者优雅地退出程序。 ```cpp void handleSegFault(QObject *sender, const QString &reason) { qWarning() << "Caught SIGSEGV: " << reason; // 进行异常处理... } ``` 3. 使用`connect()`函数SIGSEGV信号映射到槽函数上,并设置一个唯一的事件ID,以便于识别和解除关联。 ```cpp QObject::connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(handleSegFault(QString)), Qt::QueuedConnection); ``` 4. 当程序触发SIGSEGV时,如果没有被捕获,默认的行为就是终止进程。为了捕捉这个信号,你需要在QObject的构造函数中安装一个事件过滤器: ```cpp QObject::installEventFilter(this); ``` 5. 最后,在适当的地方(如`main()`函数或关键代码块),通过`emit signalMapper->map(signalId)`发送一个信号,模拟接收到了SIGSEGV,其中`signalId`是你之前设置的事件ID。 注意,实际上,SIGSEGV通常是无法避免的,因为它代表了严重的内存错误。在实际项目中,更有效的策略是在编码阶段就避免这类错误,而不是在发生之后处理它们。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值