QMediaPlayer(状态)

Posted 旷工锁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QMediaPlayer(状态)相关的知识,希望对你有一定的参考价值。

在音乐播放中介绍了QMediaPlayer的基本用法,在这里更深度的使用QMediaPlayer。

媒体播放器的当前媒体的状态:

QMediaPalyer::MediaStatus

会发射 mediaStatusChanged()信号

QMediaPlayer::UnknownMediaStatus无法确定介质的状态。
QMediaPlayer::NoMedia目前没有媒体。玩家处于停止状态
QMediaPlayer::LoadingMedia正在加载当前介质。玩家可以处于任何状态。
QMediaPlayer::LoadedMedia当前介质已加载。玩家处于停止状态
QMediaPlayer::StalledMedia由于缓冲不足或其他一些临时中断,当前媒体的播放已停止。玩家处于“播放状态”或暂停状态”。
QMediaPlayer::BufferingMedia播放器正在缓冲数据,但缓冲了足够的数据以供播放,以便在不久的将来继续播放。玩家处于“播放状态”或暂停状态”。
QMediaPlayer::BufferedMedia播放器已完全缓冲当前媒体。玩家处于“播放状态”或暂停”。
QMediaPlayer::EndOfMedia播放已到达当前媒体的末尾。玩家处于停止状态。
QMediaPlayer::InvalidMedia当前媒体无法播放。玩家处于停止状态。

错误状态:

QMediaPlayer::error

会发射error()信号

QMediaPlayer::NoError未发生错误。
QMediaPlayer::ResourceError无法解析媒体资源。
QMediaPlayer::FormatError媒体资源的格式不受(完全)支持。播放可能仍然可以,但没有音频或视频组件。
QMediaPlayer::NetworkError发生网络错误。
QMediaPlayer::AccessDeniedError没有播放媒体资源的适当权限。
QMediaPlayer::ServiceMissingError找不到有效的播放服务,无法继续播放。

媒体播放器的当前状态:

QMediaPlayer::State

会发射 stateChanged()信号

QMediaPalyer::StopedState停止状态
QMediaPalyer::PlayingState播放状态
QMediaPalyer::PauseState暂停状态

 输出各种状态:

QMediaPlayer *player=new QMediaPlayer(this);
    //状态的显示
    connect(player,&QMediaPlayer::stateChanged,[=]()
    
        switch(player->state())
        
            case QMediaPlayer::StoppedState:
                ui->label->setText("停止状态");
                break;
            case QMediaPlayer::PlayingState:
                ui->label->setText("播放状态");
                break;
            case QMediaPlayer::PausedState:
                ui->label->setText("暂停状态");
                break;
            default:
            break;
        
    );
    //媒体设备状态
    connect(player,&QMediaPlayer::mediaStatusChanged,[=]()
    
        switch(player->mediaStatus())
        
            case QMediaPlayer::UnknownMediaStatus:
                ui->label_2->setText("媒体未知状况");
                break;
            case QMediaPlayer::NoMedia:
                ui->label_2->setText("没有媒体文件");
                break;
            case QMediaPlayer::BufferedMedia:
                ui->label_2->setText("缓冲媒体文件完成");
                break;
            case QMediaPlayer::BufferingMedia:
                ui->label_2->setText("正在缓冲媒体文件");
                break;
            case QMediaPlayer::LoadingMedia:
                ui->label_2->setText("正在加载媒体");
                break;
            case QMediaPlayer::StalledMedia:
                ui->label_2->setText("播放停滞");
                break;
            case QMediaPlayer::EndOfMedia:
                ui->label_2->setText("播放结束");
            break;
            default:
            break;
        
    );
    //错误
    //需要转换为函数指针
    void(QMediaPlayer::*p1)(QMediaPlayer::Error)=&QMediaPlayer::error;
    connect(player,p1,[=]()
    
        switch(player->error())
        
            case QMediaPlayer::NoError:
                ui->label_3->setText("没有错误");
                break;
            case QMediaPlayer::ResourceError:
                ui->label_3->setText("媒体资源无法解析");
                break;
            case QMediaPlayer::FormatError:
                ui->label_3->setText("不支持该媒体格式");
                break;
            case QMediaPlayer::NetworkError:
                ui->label_3->setText("网络问题");
                break;
            case QMediaPlayer::AccessDeniedError:
                ui->label_3->setText("没有播放权限");
                break;
            case QMediaPlayer::ServiceMissingError:
                ui->label_3->setText("没有有效的服务");
                break;
            default:
            break;
        
    );

获取媒体元数据:

QMediaPlayer使用metaData()函数获取媒体的元数据

    player=new QMediaPlayer(this);
    player->setMedia(QUrl::fromLocalFile("F:/music/That Girl - Olly Murs.mp3"));
    player->play();
    connect(player,&QMediaPlayer::metaDataAvailableChanged,[=]()
    
        QString title=player->metaData("Title").toString().toUtf8().data();//获取标题
        QString author=player->metaData("Author").toString().toUtf8().data();//获取作者
        qDebug()<<title;
        qDebug()<<author;

    );

 QMediaPlayList(播放媒体列表)

  • QMediaPlayList是播放媒体列表,但其实是一个QMediaContent对象列表
  • QMediaPlay可以通过setPlayList()来设置一个播放列表

常用函数:

insertMedia()插入项目
addMedia()添加项目
load()加载网络资源
clear()清空项目
currentIndex()获取当前项目在列表中的索引
currentMedia()获取当前项目的内容
Media()返回索引处的项目
moveMedia()移动
nextMedia()下一个项目
removeMedia()删除项目
save()保存
setPlaybackMode(QMediaPlaylist::PlaybackMode mode)设置播放模式

槽函数: 

shuffle()随机播放
next()下一个
setCurrentIndex()激活播放列表中的位置播放列表中的媒体内容位置

 QMediaPlaylist::PlaybackMode:

QMediaPlaylist::CurrentItemOnce当前项目仅播放一次。
QMediaPlaylist::CurrentItemInLoop循环播放当前项目
QMediaPlaylist::Sequential播放从当前开始,在每个连续的项目之间移动,直到到达最后一个项目,然后停止。当最后一个项目当前正在播放时,下一个项目是空项目。
QMediaPlaylist::Loop在最后一个项目播放完毕后,播放将在第一个项目重新开始
QMediaPlaylist::Random以随机顺序播放项目

 QMediaPlaylist::error

QMediaPlaylist::NoError没有错误
QMediaPlaylist::FormatError格式错误
QMediaPlaylist::FormatNotSupportedError格式不受支持
QMediaPlaylist::NetworkError网络错误
QMediaPlaylist::AccessDeniedError访问被拒绝错误

例子:创建一个可以显示歌曲列表的播放器,可以开始,暂停,停止,随机播放,下一首

在ui界面中添加如下控件:

一个QListWidget

一个Label 边框为Box

五个QPushButton

 在pro文件中添加:

QT       += multimedia

在widget.h文件中添加以下头文件:

#include<QMediaPlayer>
#include<QMediaPlaylist>
#include<QDebug>
#include<QTime>

再添加以下函数和成员:

    QMediaPlayer *player;//
    QMediaPlaylist *list;
    void changerIndex(int x);//列表的项目改变
    void changerIndex_list(int x);//播放列表的项目改变

widgat.cpp文件中的构造函数添加以下内容:

    player=new QMediaPlayer(this);
    list=new QMediaPlaylist(this);
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));//设置随机种子

    QStringList stringlist;//创建一个容器
    stringlist<<"F:/music/24 magic.mp3"<<"F:/music/Baby - Justin Bieber.mp3"<<"F:/music/bad guy - Billie Eilish.mp3";//导入音乐地址

    //在ListWidget中导入列表
    ui->listWidget->addItems(stringlist);
    for(auto i:stringlist)
    
        list->addMedia(QUrl(i));//导入到播放列表
    
    list->setCurrentIndex(0);//设置初始位置为0
    ui->listWidget->setCurrentRow(0);//设置初始位置为0
    player->setPlaylist(list);//添加播放列表
    ui->label->setText(player->currentMedia().canonicalUrl().toString());//设置路径

    //滑块功能的实现
    ui->horizontalSlider->setMinimum(0);//设置滑块最小值
    connect(player,&QMediaPlayer::durationChanged,[=]()
    
        ui->horizontalSlider->setMaximum(player->duration());//设置滑块的最大值
    );
    connect(player,&QMediaPlayer::positionChanged,[=]()
    
        int p=player->position();
        ui->horizontalSlider->setValue(p);
    );
    //在这里未实现移动滑块,改变音乐位置。添加该功能时,音乐会短暂暂停,所以未给出相应的代码



    //开始按钮的实现
    connect(ui->pushButton,&QPushButton::clicked,player,&QMediaPlayer::play);
    //暂停按钮的实现
    connect(ui->pushButton_2,&QPushButton::clicked,player,&QMediaPlayer::pause);
    //停止按钮的实现
    connect(ui->pushButton_3,&QPushButton::clicked,player,&QMediaPlayer::stop);
    //点击左边列表换歌的实现
    connect(ui->listWidget,&QListWidget::currentRowChanged,this,&Widget::changerIndex);
    //随机播放的实现
    connect(ui->pushButton_4,&QPushButton::clicked,[=]()mutable
    
        int x=qrand()%(list->mediaCount());//随机数
        qDebug()<<x;
        list->setCurrentIndex(x);
        changerIndex_list(x);
    );
    //下一首歌的实现
    connect(ui->pushButton_5,&QPushButton::clicked,[=]()mutable
    
        int x=list->nextIndex();//获取下一首歌的索引
        if(x<0||x>=list->mediaCount())//当索引不合规时,不做操作
        
            return;
        
        list->setCurrentIndex(x);
        changerIndex_list(x);
    );

两个函数的实现:

void Widget::changerIndex(int x)//列表的项目改变

    list->setCurrentIndex(x);
    ui->label->setText(player->currentMedia().canonicalUrl().toString());//获取路径

void Widget::changerIndex_list(int x)//播放列表的项目改变

    ui->listWidget->setCurrentRow(x);
    ui->label->setText(player->currentMedia().canonicalUrl().toString());//获取路径

运行结果:

当状态更改为媒体结束时,QMediaPlayer 状态未停止

【中文标题】当状态更改为媒体结束时,QMediaPlayer 状态未停止【英文标题】:QMediaPlayer state not stopped when status changed to end of media 【发布时间】:2016-11-18 09:04:43 【问题描述】:

我在使用 QMediaPlayer.mediaStatusChanged 时遇到问题。

根据Qt5.7文档,当媒体状态更改为EndOfMedia时,QMediaPlayer状态应为StoppedState

播放已到达当前媒体的结尾。播放器处于 StoppedState。

Qt5.7

但是,状态并未停止。以下是重现该问题的示例:

import sys

from PyQt5 import QtWidgets
from PyQt5.QtCore import QUrl

from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent

class MediaPlayer(QMediaPlayer):
    default = 'test.mp3'

    def __init__(self):
        super(MediaPlayer, self).__init__()
        self.mediaStatusChanged[QMediaPlayer.MediaStatus].connect(self.media_status_changed)

        self.setup_media(self.default)

    def setup_media(self, media):
        url = QUrl.fromLocalFile(media)
        self.setMedia(QMediaContent(url))

    def media_status_changed(self, status):
        if status == QMediaPlayer.EndOfMedia:
            print(self.state() == QMediaPlayer.StoppedState) # I get False
            # self.state() is QMediaPlayer.PlayingState


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    m = MediaPlayer()
    m.play()
    sys.exit(app.exec_())

有人遇到同样的问题吗? 我可以通过变通方法解决问题,但我认为这可能是 Qt 问题。

【问题讨论】:

我可以确认这一点。可能是在更改后不久的状态,但经验似乎与文档相矛盾(至少对于 C++ QT 文档)。这可能是一个错误。 顺便说一句。你的解决方法是什么? 我已经用变通方法更新了这个问题,我个人使用第一个,我只是在处理之前强制停止,但我不喜欢方法 1 或方法 2,如果你想到更好的方法,请告诉我,谢谢。 在使用 Qt-5.7 和 PyQt-5.7(gstreamer 后端 + alsa)的 Linux 上工作正常。 那么,一定是windows的问题,我也试过在Qt Creator(Qt 5.7)上运行C++代码,还是一样的问题。 【参考方案1】:

我向 Qt 报告了 issue,因为它似乎是一个仅限 Windows 的错误:

解决问题的可能解决方法:

    处理前强制停止

    def media_status_changed(self, status):
        if status == QMediaPlayer.EndOfMedia:
            super(MediaPlayer, self).stop()
            # process
    

    投票直到收到StoppedState

    def media_status_changed(self, status):
        if status == QMediaPlayer.EndOfMedia:
            while not (self.state() == QMediaPlayer.StoppedState):
                time.sleep(0.1)
            # process
    

我将在此处添加有关 Qt 问题的任何更新。

编辑:问题已在 Qt v5.10.1 中更新和修复

【讨论】:

以上是关于QMediaPlayer(状态)的主要内容,如果未能解决你的问题,请参考以下文章

Qt视频播放器[QMediaPlayer+QVideowidget]

Qt系列文章之二十六(基于QMediaPlayer 在 QVideoWidget或QGraphicsVideoItem 组件上播放视频)

Qt系列文章之二十六(基于QMediaPlayer 在 QVideoWidget或QGraphicsVideoItem 组件上播放视频)

QVideoWidget 和 QMediaPlayer (QT 5.2.1) 无法在 Android 上显示视频

Qt实用技巧:使用QMediaPlayer和Windows自带组件播放swfrmvbmpgmp4等视频文件

哪些视频文件可以在 Android 上播放 QMediaPlayer?