qt6 多媒体开发代码分析(一)

 音乐播放器关键代码分析

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include    <QMainWindow>

#include    <QtMultimedia>
#include    <QListWidgetItem>


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE


class MainWindow : public QMainWindow
{
    Q_OBJECT

private:
    QMediaPlayer  *player;      //播放器
    bool    loopPlay=true;      //是否循环播放
    QString  durationTime;      //文件总长度,mm:ss字符串
    QString  positionTime;      //当前播放到位置,mm:ss字符串

    QUrl getUrlFromItem(QListWidgetItem *item);         //获取item的用户数据
    bool eventFilter(QObject *watched, QEvent *event);  //事件过滤处理
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    //自定义槽函数
    void do_stateChanged(QMediaPlayer::PlaybackState state);    //播放器状态发生变化

    void do_sourceChanged(const QUrl &media);   //文件发生变化

    void do_durationChanged(qint64 duration);   //文件长度发生变化

    void do_positionChanged(qint64 position);   //播放位置发生变化

    void do_metaDataChanged();          //元数据发生变化

    //
    void on_btnAdd_clicked();

    void on_btnPlay_clicked();

    void on_btnPause_clicked();

    void on_btnStop_clicked();

    void on_listWidget_doubleClicked(const QModelIndex &index);

    void on_btnClear_clicked();

    void on_sliderVolumn_valueChanged(int value);

    void on_btnSound_clicked();

    void on_sliderPosition_valueChanged(int value);

    void on_btnPrevious_clicked();

    void on_btnNext_clicked();

    void on_btnLoop_clicked(bool checked);

    void on_doubleSpinBox_valueChanged(double arg1);

    void on_btnRemove_clicked();
    
    void on_btnClose_clicked();
    
    void on_doubleSpinBox_textChanged(const QString &arg1);
    
    void on_btnLoop_clicked();
    
    void on_sliderVolumn_actionTriggered(int action);
    
    void on_sliderPosition_actionTriggered(int action);
    
private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

这是一个名为"MainWindow"的类,继承自QMainWindow。它是一个主窗口类,用于创建一个具有音频播放功能的应用程序界面。

在私有成员部分,包含了以下成员变量:

  • player:QMediaPlayer类型的指针,用于控制音频的播放。
  • loopPlay:bool类型,表示是否循环播放音频。
  • durationTime:QString类型的变量,表示音频文件的总时长(以mm:ss格式的字符串表示)。
  • positionTime:QString类型的变量,表示当前音频播放的位置(以mm:ss格式的字符串表示)。

还有两个私有函数:

  • getUrlFromItem(QListWidgetItem *item):从QListWidgetItem中获取用户数据(QUrl类型),用于获取音频文件的URL。
  • eventFilter(QObject *watched, QEvent *event):事件过滤处理函数,用于处理特定的事件。

公有部分包含了构造函数和析构函数。

私有槽函数部分定义了一些槽函数,用于响应相关信号的变化,包括:

  • do_stateChanged(QMediaPlayer::PlaybackState state):播放器状态发生变化的槽函数。
  • do_sourceChanged(const QUrl &media):音频文件发生变化的槽函数。
  • do_durationChanged(qint64 duration):音频文件总时长发生变化的槽函数。
  • do_positionChanged(qint64 position):音频播放位置发生变化的槽函数。
  • do_metaDataChanged():音频文件元数据发生变化的槽函数。

还包括一些其他槽函数,用于响应界面上的按钮点击事件和数值变化等。

最后,私有成员ui是一个指向Ui::MainWindow类的指针,用于访问用户界面的元素和操作。

总体上,该类定义了一个主窗口,具有音频播放器的功能,通过界面上的按钮和列表项来控制音频的播放、暂停、停止、添加、删除等操作。同时也显示了音频文件的时长、当前播放位置等信息。

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

#include    <QFileDialog>

QUrl MainWindow::getUrlFromItem(QListWidgetItem *item)
{
    QVariant itemData= item->data(Qt::UserRole);    //获取用户数据
    QUrl source =itemData.value<QUrl>();    //QVariant转换为QUrl类型
    return source;
}

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if (event->type() != QEvent::KeyPress)      //不是KeyPress事件,退出
        return QWidget::eventFilter(watched,event);

    QKeyEvent *keyEvent=static_cast<QKeyEvent *>(event);
    if (keyEvent->key() != Qt::Key_Delete)      //按下的不是Delete键,退出
        return QWidget::eventFilter(watched,event);

    if (watched==ui->listWidget)
    {
        QListWidgetItem *item= ui->listWidget->takeItem(ui->listWidget->currentRow());
        delete  item;
    }
    return true;    //表示事件已经被处理
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    ui->listWidget->installEventFilter(this);       //安装事件过滤器
    ui->listWidget->setDragEnabled(true);           //允许拖放操作
    ui->listWidget->setDragDropMode(QAbstractItemView::InternalMove);   //列表项可移动

    player = new QMediaPlayer(this);
    QAudioOutput *audioOutput = new QAudioOutput(this);   //音频输出,指向默认的音频输出设备
    player->setAudioOutput(audioOutput);    //设置音频输出
    connect(player,&QMediaPlayer::positionChanged,      //播放位置发生变化
            this, &MainWindow::do_positionChanged);

    connect(player,&QMediaPlayer::durationChanged,      //播放源长度发生变化
            this, &MainWindow::do_durationChanged);

    connect(player, &QMediaPlayer::sourceChanged,       //播放源发生变化
            this, &MainWindow::do_sourceChanged);

    connect(player, &QMediaPlayer::playbackStateChanged,    //播放器状态发生变化
            this,  &MainWindow::do_stateChanged);

    connect(player, &QMediaPlayer::metaDataChanged,     //元数据发生变化
            this,  &MainWindow::do_metaDataChanged);
}

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

void MainWindow::do_stateChanged(QMediaPlayer::PlaybackState state)
{//播放器状态变化时执行,更新按钮状态,或播放下一曲
    ui->btnPlay->setEnabled(state!=QMediaPlayer::PlayingState);
    ui->btnPause->setEnabled(state==QMediaPlayer::PlayingState);
    ui->btnStop->setEnabled(state==QMediaPlayer::PlayingState);

    //播放完一曲后停止了,如果loopPlay为true,自动播放下一曲
    if (loopPlay && (state ==QMediaPlayer::StoppedState))
    {
        int count=ui->listWidget->count();
        int curRow=ui->listWidget->currentRow();
        curRow++;
        curRow= curRow>=count? 0:curRow;
        ui->listWidget->setCurrentRow(curRow);
        player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
        player->play();
    }
}

void MainWindow::do_sourceChanged(const QUrl &media)
{//播放的文件发生变化时的响应
    ui->labCurMedia->setText(media.fileName());
}

void MainWindow::do_durationChanged(qint64 duration)
{//播放源时长变化时执行,更新进度显示
    ui->sliderPosition->setMaximum(duration);

    int   secs=duration/1000;  //秒
    int   mins=secs/60;        //分钟
    secs=secs % 60;            //余数秒
    durationTime=QString::asprintf("%d:%d",mins,secs);
    ui->labRatio->setText(positionTime+"/"+durationTime);
}

void MainWindow::do_positionChanged(qint64 position)
{//播放位置变化时执行,更新进度显示
    if (ui->sliderPosition->isSliderDown())     //滑条正被鼠标拖动
        return;

    ui->sliderPosition->setSliderPosition(position);
    int   secs=position/1000;   //秒
    int   mins=secs/60;         //分钟
    secs=secs % 60;             //余数秒
    positionTime=QString::asprintf("%d:%d",mins,secs);
    ui->labRatio->setText(positionTime+"/"+durationTime);
}

void MainWindow::do_metaDataChanged()
{//元数据变化时执行,显示歌曲图片
    QMediaMetaData metaData=player->metaData();     //元数据对象
    QVariant  metaImg= metaData.value(QMediaMetaData::ThumbnailImage);  //获取ThumbnailImage元数据
    if (metaImg.isValid())
    {
        QImage img= metaImg.value<QImage>();        //QVariant转换为QImage
        QPixmap musicPixmp= QPixmap::fromImage(img);
        if (ui->scrollArea->width() <musicPixmp.width())
            ui->labPic->setPixmap(musicPixmp.scaledToWidth(ui->scrollArea->width()-30));
        else
            ui->labPic->setPixmap(musicPixmp);
    }
    else
        ui->labPic->clear();
}

void MainWindow::on_btnAdd_clicked()
{//"添加"按钮,添加文件
    QString curPath=QDir::homePath();  //获取系统当前目录
    QString dlgTitle="选择音频文件";
    QString filter="音频文件(*.mp3 *.wav *.wma);;所有文件(*.*)";   //文件过滤器
    QStringList fileList=QFileDialog::getOpenFileNames(this,dlgTitle,curPath,filter);
    if (fileList.count()<1)
        return;

    for (int i=0; i<fileList.size();i++)
    {
        QString  aFile=fileList.at(i);
        QFileInfo  fileInfo(aFile);
        QListWidgetItem *aItem =new QListWidgetItem(fileInfo.fileName());
        aItem->setIcon(QIcon(":/images/images/musicFile.png"));
        aItem->setData(Qt::UserRole, QUrl::fromLocalFile(aFile));  //设置用户数据,QUrl对象
        ui->listWidget->addItem(aItem);
    }

    if (player->playbackState() != QMediaPlayer::PlayingState)
    {  //当前没有在播放,就播放第1个文件
        ui->listWidget->setCurrentRow(0);
        QUrl source= getUrlFromItem(ui->listWidget->currentItem());
        player->setSource(source);
    }
    player->play();
}

void MainWindow::on_btnPlay_clicked()
{//开始播放
    if (ui->listWidget->currentRow()<0)   //没有选择文件,就播放第1个
        ui->listWidget->setCurrentRow(0);
    player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
    player->play();
    loopPlay=ui->btnLoop->isChecked();  //是否循环播放
}

void MainWindow::on_btnPause_clicked()
{//暂停播放
    player->pause();
}

void MainWindow::on_btnStop_clicked()
{//停止播放
    loopPlay=false;
    player->stop();
}

void MainWindow::on_listWidget_doubleClicked(const QModelIndex &index)
{//双击listWidget时切换播放文件
    Q_UNUSED(index);
    loopPlay=false;     //暂时设置为false,防止do_stateChanged()里切换曲目
    player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
    player->play();
    loopPlay=ui->btnLoop->isChecked();
}

void MainWindow::on_btnClear_clicked()
{//"清空"按钮,清空播放列表
    loopPlay=false;     //防止do_stateChanged()里切换曲目
    ui->listWidget->clear();
    player->stop();
}

void MainWindow::on_sliderVolumn_valueChanged(int value)
{//调整音量
    player->audioOutput()->setVolume(value/100.0);        //0~ 1之间
}

void MainWindow::on_btnSound_clicked()
{//静音控制
    bool mute=player->audioOutput()->isMuted();
    player->audioOutput()->setMuted(!mute);
    if (mute)
        ui->btnSound->setIcon(QIcon(":/images/images/volumn.bmp"));
    else
        ui->btnSound->setIcon(QIcon(":/images/images/mute.bmp"));
}

void MainWindow::on_sliderPosition_valueChanged(int value)
{//播放进度调控
    player->setPosition(value);
}

void MainWindow::on_btnPrevious_clicked()
{//前一曲
    int curRow=ui->listWidget->currentRow();
    curRow--;
    curRow= curRow<0? 0:curRow;
    ui->listWidget->setCurrentRow(curRow);  //设置当前行

    loopPlay=false;     //暂时设置为false,防止do_stateChanged()里切换曲目
    player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
    player->play();
    loopPlay=ui->btnLoop->isChecked();

//    if(ui->btnLoop->isChecked())
//    {
//        loopPlay=false;     //暂时设置为false,防止do_stateChanged()里切换曲目
//        player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
//        player->play();
//        loopPlay=true;
//    }
}

void MainWindow::on_btnNext_clicked()
{//下一曲
    int count=ui->listWidget->count();
    int curRow=ui->listWidget->currentRow();
    curRow++;
    curRow= curRow>=count? count-1:curRow;
    ui->listWidget->setCurrentRow(curRow);

    loopPlay=false;     //暂时设置为false,防止do_stateChanged()里切换曲目
    player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
    player->play();
    loopPlay=ui->btnLoop->isChecked();

//    if(ui->btnLoop->isChecked())
//    {
//        loopPlay=false;     //暂时设置为false,防止do_stateChanged()里切换曲目
//        player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
//        player->play();
//        loopPlay=true;
//    }
}

void MainWindow::on_btnLoop_clicked(bool checked)
{//"循环" 按钮
    loopPlay=checked;
}

void MainWindow::on_doubleSpinBox_valueChanged(double arg1)
{//"倍速" DoubleSpinbox
    player->setPlaybackRate(arg1);
}

void MainWindow::on_btnRemove_clicked()
{//"移除"按钮,移除列表中的当前项
    int index =ui->listWidget->currentRow();
    if (index>=0)
    {
        QListWidgetItem *item= ui->listWidget->takeItem(index);
        delete item;
    }
}

这段代码是一个音乐播放器的主窗口类MainWindow的实现代码。主要功能包括添加音频文件、播放、暂停、停止、切换曲目、调整音量、静音控制、播放进度调控等。

具体分析如下:

  1. getUrlFromItem函数用于从QListWidgetItem中获取保存的QUrl对象。
  2. eventFilter函数是一个事件过滤器,用于捕获并处理QKeyEvent事件(键盘按下事件),当捕获到Delete键按下事件时,删除当前选中的QListWidgetItem。
  3. 构造函数MainWindow初始化了UI界面,并安装了事件过滤器,设置了拖放操作和列表项可移动。
  4. 析构函数MainWindow销毁了UI界面。
  5. do_stateChanged函数根据播放器状态的变化,更新按钮的状态,并在循环播放模式下自动播放下一曲。
  6. do_sourceChanged函数在播放的文件发生变化时更新显示的文件名。
  7. do_durationChanged函数在播放源时长变化时更新进度条的最大值,并转换为分钟:秒的格式显示。
  8. do_positionChanged函数在播放位置变化时更新进度条的位置,并转换为分钟:秒的格式显示。
  9. do_metaDataChanged函数在元数据发生变化时,根据元数据中的缩略图显示歌曲图片。
  10. on_btnAdd_clicked函数是"添加"按钮的点击事件处理函数,通过文件对话框选择音频文件,并将文件名添加到列表中,如果当前没有播放,则自动播放第一个文件。
  11. on_btnPlay_clicked函数是"开始播放"按钮的点击事件处理函数,根据当前选中的列表项设置播放源,并开始播放。
  12. on_btnPause_clicked函数是"暂停播放"按钮的点击事件处理函数,暂停当前播放。
  13. on_btnStop_clicked函数是"停止播放"按钮的点击事件处理函数,停止当前播放。
  14. on_listWidget_doubleClicked函数是当双击列表项时切换播放文件的事件处理函数。
  15. on_btnClear_clicked函数是"清空"按钮的点击事件处理函数,清空播放列表并停止播放。
  16. on_sliderVolumn_valueChanged函数是调整音量的滑动条的值变化事件处理函数,根据滑动条的值设置音量。
  17. on_btnSound_clicked函数是"静音"按钮的点击事件处理函数,切换静音状态。
  18. on_sliderPosition_valueChanged函数是播放进度调节的滑动条的值变化事件处理函数,根据滑动条的值设置播放位置。
  19. on_btnPrevious_clicked函数是"上一曲"按钮的点击事件处理函数,切换到上一曲并播放。
  20. on_btnNext_clicked函数是"下一曲"按钮的点击事件处理函数,切换到下一曲并播放。
  21. on_btnLoop_clicked函数是"循环播放"按钮的点击事件处理函数,设置循环播放的状态。
  22. on_doubleSpinBox_valueChanged函数是"倍速"双精度浮点数输入框的值变化事件处理函数,根据输入的值设置播放速率。
  23. on_btnRemove_clicked函数是"移除"按钮的点击事件处理函数,移除当前选中的列表项。

以上就是代码的详细分析。这段代码实现了一个简单的音乐播放器界面,并提供了基本的播放控制功能。

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if (event->type() != QEvent::KeyPress)      //不是KeyPress事件,退出
        return QWidget::eventFilter(watched,event);

    QKeyEvent *keyEvent=static_cast<QKeyEvent *>(event);
    if (keyEvent->key() != Qt::Key_Delete)      //按下的不是Delete键,退出
        return QWidget::eventFilter(watched,event);

    if (watched==ui->listWidget)
    {
        QListWidgetItem *item= ui->listWidget->takeItem(ui->listWidget->currentRow());
        delete  item;
    }
    return true;    //表示事件已经被处理
} 

这段代码是MainWindow类中的一个事件过滤器函数eventFilter,用于捕获并处理特定的事件。

在这段代码中,首先通过判断事件的类型来确定是否为按键事件(KeyPress)。如果不是按键事件,则直接调用基类的事件过滤器函数进行默认处理。

如果是按键事件,进一步判断按下的键盘键是否为Delete键。如果不是Delete键,则同样调用基类的事件过滤器函数进行默认处理。

如果按下的是Delete键,且被监视的对象是ui->listWidget(列表控件),则获取当前选中的列表项(QListWidgetItem),并从列表中移除该列表项。最后,通过delete操作释放内存。

最后,返回true表示事件已经被处理。

总的来说,这段代码的作用是在用户按下Delete键时,如果当前焦点位于列表控件上(ui->listWidget),则删除选中的列表项。

ps:

低延迟音效文件是指在进行音效处理时,尽可能地减少音效的延迟时间,以保证音频效果的同步和响应速度。在数字音频处理中,无论是采样率、位深度还是传输带宽都会对音效处理的延迟时间产生影响,如果音效延迟时间过长,就会导致音频和视频不同步或者影响用户体验。

为了降低音效处理的延迟时间,一些专业的音效处理器会采用各种优化算法,包括质量损失较小的预测算法、快速近似算法、滤波器设计等方法,以达到尽可能地减少音效延迟时间的目的。同时,低延迟音效也可以通过采用特殊的音频编码算法来实现,如Opus等音频编码格式就具有较低的编码延迟,适合于实时音频应用。

低延迟音效文件通常用于需要高质量音频响应和实时交互的场景,例如电子游戏、虚拟现实、语音通话等。通过使用低延迟音效文件,可以提高用户体验和音频响应速度,增加应用的稳定性和可靠性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值