QMutex使用 & Qt的QMediaPlayer和QVideoWidget的使用

一、QMutex使用

原文链接:https://blog.csdn.net/fanyun_01/article/details/79354106

QMutex类提供的是线程之间的访问顺序化。QMutex的目的是保护一个对象、数据结构或者代码段,所以同一时间只有一个线程可以访问它。

例如,这里有一个方法打印给用户两条消息:

  void DebugInfo()
  {
     qDebug("ABC");
     qDebug("DEF");
  }

如果同时在两个线程中调用这个方法,结果的顺序将是:

ABC ABC DEF DEF

如果你使用了一个互斥量:

  QMutex mutex;
 
  void DebugInfo()
  {
     mutex.lock();
     qDebug("ABC");
     qDebug("DEF");
     mutex.unlock();
  }

然后同一时间只有一个线程可以运行DebugInfo()并且消息的顺序也一直是正确的。当然,这只是一个很简单的例子,但是它适用于任何需要按特定频率发生的情况。
但你在一个线程中调用lock(),其它线程将会在同一地点试图调用lock()来阻塞,知道这个线程调用unlock()之后其它线程才会获得这个锁。lock()的一种非阻塞选择是tryLock()。


成员函数:
QMutex::QMutex ( bool recursive = FALSE )
构造一个新的互斥量。这个互斥量是在没有锁定的状态下创建的。如果recursive为真,就构造一个递归互斥量,如果recursive为假(默认值),就构造一个普通互斥量。对于一个递归互斥量,一个线程可以锁定一个互斥量多次并且只有在相同数量的unlock()调用之后,它才会被解锁。
QMutex::~QMutex () [虚]
销毁这个互斥量。
void QMutex::lock ()
试图锁定互斥量。如果另一个线程已经锁定这个互斥量,那么这次调用将阻塞直到那个线程把它解锁。
也可以参考unlock()和locked()。
bool QMutex::locked ()
如果互斥量被另一个线程锁定了,返回真,否则返回假。
警告:由于不同平台上递归互斥量的实现不同,所以从以前锁定这个互斥量的同一个线程上调用这个函数可能会返回未定义的结果。
也可以参考lock()和unlock()。
bool QMutex::tryLock ()
试图锁定互斥量。如果锁被得到,这个函数返回真。如果另一个进程已经锁定了这个互斥量,这个函数返回假,而不是一直等到这个锁可用为止,比如,它不是阻塞的。
在另一个线程可以成功锁定它之前,这个锁必须被调用unlock()来解锁。
也可以参考lock()、unlock()和locked()。
void QMutex::unlock ()
解锁这个互斥量。试图对不同的线程中锁定的互斥量进行解锁将会返回一个错误。对一个没有锁定的互斥量进行解锁的结果是将导致未定义的行为(不同的操作系统的线程实现是有很大不同的)。
也可以参考lock()和locked()。

QMutexLocker

头文件:#include <QMutexLocker>

而Qt更加推荐的是使用QMutexLocker类,这个类用来管理互斥锁 这是一个方便的类,简化了QMutex的lock()和unlock()

使用同一把锁的地方会互斥

void MyThread::run()
{
    QMutexLock mymutex(&mutex);//实例化会自动上锁
    if(stopped == true)
    {
        stopped = false;
        return;//不需要手动解锁,当QMutexLock实例销毁时会自动解锁
    }
    emit sendMsg(msg);
    return;//不需要手动解锁,当QMutexLock实例销毁时会自动解锁
}

二、Qt的QMediaPlayer和QVideoWidget的使用

原文链接:https://blog.csdn.net/zong596568821xp/article/details/78989133

Qt Multimedia是Qt的一个重要模块,它提供了许多c++类和QML模块来进行多媒体内容的展示和处理,还提供了一些访问录音机和摄像头的必要的api。本篇中,主要讲述的是C++的实现,而不是QML。想要使用Qt Multimedia模块,必须要先在项目的.pro文件中加入下面一行代码

QT += multimedia multimediawidgets

代表在项目中导入该模块,之后,要使用具体的类时,只需要在头文件中加上声明

#include <QtMultimedia>
#include <QtMultimediaWidgets>

本教程中,主要使用下面的类:

QMediaPlayer:从源文件播放媒体。最常用的类,如果你想实现一个播放器,这会是你理想的内核。它可以非常非常方便地播放指定的文件,并提供了很多设置和获取信息的接口。
QMediaPlaylist:它是一个封装好的列表类。储存着每一个媒体文件的信息,并且提供了添加,删除,储存,读取媒体的方法,甚至是播放方式都可以指定,非常方便。
QVideoWidget:用来播放视频的控件,可以理解为是QMediaPlayer的一个输出端。
一.QMediaPlayer
QMediaPlayer集成了底部包括音频输出和音频文件读取等等操作,是一个高层次的,封装好的播放器内核,通过调用它,你可以实现输入任意格式的视频、音频播放,并实现对其播放状态的调整。下面我们用QMediaPlayer来播放一段音乐,顺便体会一下它有多么方便。

player = new QMediaPlayer;
player->setMedia(QMediaContent(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3")));
player->play();

第一步:创建QMediaplayer对象;第二步:设置当前播放的媒体文件;第三步:播放。三行代码足矣。可能有细心的朋友发现QUrl后面跟着fromLocalFile,对的,这是本地的媒体文件。那么网络上的呢? 答案是:也可以!而且不需要去考虑诸如音频流的输入和处理问题,QMediaPlayer已经帮我们做好了。下面我们就来详细的看一下QMediaPlayer能够帮助我们做什么。
首先,看一下QMediaPlayer中的几个重要属性

这些属性都可以通过get和set方法来进行设置和获取。例如获取媒体对象播放进度的方法是QMediaPlayer::position()。该方法返回一个qint64(64位整数,可以近似理解为int)类型。设置进度的方法是QMediaPlayer::setPosition(qint64 position)。

设置当前播放媒体的方法是QMediaPlayer::setMedia(QMediaContent &media,QIODevice *stream = QNULLPTR)。
第二个参数默认即可。第一个参数是一个QMediaContent对象,封装了媒体文件信息。这个对象可以通过QMediaContent(QUrl url)来创建。QUrl可以是一个本地的文件,也可以是网络上的文件。

切换播放状态的的方法有QMediaPlayer::play(),QMediaPlayer::pause,QMediaPlayer::stop();三个,看名字就能知道什么意思对吧。

再说说QMediaPlayer中定义的两个重要的枚举类型State和MediaStatus
State包含着当前的播放状态,有 { StoppedState, PlayingState, PausedState }三种状态,可以通过state()函数获取。
MediaStatus包含当前媒体文件的有效性,有 { UnknownMediaStatus, NoMedia, LoadingMedia, LoadedMedia, …, InvalidMedia }等状态,可以通过mediaStatus()方法获取。

上述的每个属性,在QMediaPlayer类中都有与之对应的on****changed信号。通过绑定信号,就可以实现对QMediaPlayer状态的监控,比如进度条自动移动等。

二.QVideoWidget
QVideoWidget是一个用来展示视频的控件。要使用它,需要先定义一个QMediaPlayer,然后将QMediaPlayer的VideoOutput设置为QVideoWidget对象即可。

player = new QMediaPlayer;
 
player->setMedia(QMediaContent(QUrl("http://example.com/myclip2.mp4")));
videoWidget = new QVideoWidget;
player->setVideoOutput(videoWidget);
 
videoWidget->show();
player->play();

同样从属性去解读这个类

和QMediaPlayer一样,通过设置这些属性就可以实现相应的功能…… 好的解读完成……没错就那么简单

视频默认按原大小显示,不会随着QVideoWidget的缩放而改变,要想视频根据QVideoWidget动态变化,需要设置 “AspectRatioMode” 参数。

这个枚举类型定义了,当拉伸QVideoWidget的时候,图片(或视频)的比例会发生什么变化。

(1)Default -1
显示区域的大小根据视频的原始大小而决定,不会随着QVideoWidget的缩放而改变。
(2)Qt::IgnoreAspectRatio 0
填满QVideoWidget
(3)Qt::KeepAspectRatio 1
视频等比例缩放,并且尽量铺满QVideoWidget,但不超出QVideoWidget的范围。
(4)Qt::KeepAspectRatioByExpanding 2
视屏等比例缩放,充满整个QVideoWidget,超出QVideoWidget的范围的部分不显示。

三.QMediaPlaylist
QMediaPlaylist是一个列表,它可以保存媒体文件,包括媒体路径等信息,它具有着列表的性质,比如添加删除插入等,但它能做的,比单纯的储存要多得多。设置播放顺序,对播放的控制,保存到本地,从本地读取,都可以很方便地实现。用QMediaPlaylist添加媒体文件可以使用addMedia方法。方法接收一个QMediaContent的对象引用。

playlist->addMedia(QMediaContent(QUrl("http://example.com/movie1.mp4")));
playlist->addMedia(QMediaContent(QUrl("http://example.com/movie2.mp4")));
playlist->addMedia(QMediaContent(QUrl("http://example.com/movie3.mp4")));

此时新添加的媒体被插入到列表的最后。同样的也有指定位置的插入方法。除了QMediaContent对象引用,还需要指定插入位置。

playlist->insertMedia(2,QMediaContent(QUrl("http://example.com/movie4.mp4")));

方法clear()可以清除所有的媒体对象。 而希望精确地删除媒体,就要用到removeMedia方法。方法有两个版本,第一个版本接收一个int变量作为被删除媒体的位置,另一个版本接收两个int变量,删除这两个索引之间的所有媒体对象。

playlist->removeMedia(3);//删除位置索引为3的媒体对象
playlist->removeMedia(0,2);//删除位置索引为0,1,2的媒体对象;
playlist->clear();//清空列表

这是一些很简单的list的操作。下面讲讲身为Playlist的高级操作。
我们知道,现在的播放器一般都有选择播放顺序的功能,除了最基本的顺序播放,还有单曲循环、随机播放等模式。现在只需要调用setPlaybackMode(PlaybackMode mode)这个方法,就可以设置播放顺序。 方法接收枚举类型PlaybackMode作为播放顺序。

 调用next()和previous()方法,可以实现按照播放模式进行当前播放的手动切换。当一个媒体播放完毕时,会自动地调用next()方法。使用方法

player = new QMediaPlayer;
 
playlist = new QMediaPlaylist(player);
playlist->addMedia(QUrl("http://example.com/myclip1.mp4"));
playlist->addMedia(QUrl("http://example.com/myclip2.mp4"));
 
videoWidget = new QVideoWidget;
player->setVideoOutput(videoWidget);
 
videoWidget->show();
playlist->setCurrentIndex(1);
player->play();
原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/15080562.html