OpenCV实现视频播放器,其思路大致就是在线程中使用OpenCV中的VideoCapture循环读取本地视频的每一帧Mat,然后发送到界面转换成QImage进行显示,而进度条拖动则用到了VideoCapture中的set函数,进度条则是使用Qslider;并且通过自定义新的进度条类实现点击跳转功能;

效果:

1.进行播放,线程循环读取视频帧并计数当前帧数,把Mat帧和当前帧数通过信号发送到窗口

窗口中创建线程,然后点击播放时在调用start启动线程;

void videothread::run()
{while(stop==false)//线程运行和停止  卡住线程 暂停时不退出线程{while(isrun==true)//视频运行和暂停{if(cap.read(frame))//捕获视频帧{this->currentFramecount++;cvtColor(frame, frame, CV_BGR2RGB);//opencvBGR格式转成Image用到的RGBemit sendFrame(currentFramecount,frame);//发送帧数据}msleep(40);//延时}}cap.release();//释放打开的视频
}

2.获取当前帧数设置进度条当前值

3.通过VideoCapture中的get方法获取视频总帧数并保存

    if(cap.open(filename));//创建视频对象{this->allFramecount=cap.get(CAP_PROP_FRAME_COUNT);//获取视频文件中的总帧数this->fps=int(round(cap.get(CAP_PROP_FPS)));//获取视频帧率}

4.设置进度条取值范围,即0-总帧数

    ui->horizontalSlider->setRange(0,pthread->getVideoAllFramecount());//设置进度条取值范围ui->horizontalSlider->setSingleStep(1);//设置单步长为1ui->label_4->setText(QString::number(pthread->getVideoAllFramecount()));//设置总帧数

接下来就是进度条拖动,在知道如何做之前,我们要先了解Qslider的几个信号,我们拖动时就需要用到点击、滑动和释放信号

Qslider常用信号

1.移动滑动条时发出的信号

void sliderMove(int value);

2.点击滑动条时所发出的信号

void sliderPressed();

3.释放时所发出的信号

void sliderReleased();

5.首先是拖动进度条,拖动的时候先把播放的视频暂停

就是停止循环读帧

void Widget::on_horizontalSlider_sliderMoved(int position)//进度条拖动
{pthread->pauseThread();//播放暂停
}
void videothread::pauseThread()//这两个函数用于确保是在运行情况下才能切换状态
{if(this->isRunning()&&this->isrun==true)//当前线程运行且视频运行{this->isrun=false;}
}

6.释放进度条

获取拖动后的进度条的值,然后通过set中的CV_CAP_PROP_POS_FRAMES进行设置

void Widget::on_horizontalSlider_sliderReleased()//释放进度条
{//ui->horizontalSlider->value();获取当前进度条值pthread->setCurrentFrame(ui->horizontalSlider->value());pthread->resumeThread();//播放继续 设置为true}
void videothread::setCurrentFrame(int value)
{this->currentFramecount=value;//当前帧数cap.set(CV_CAP_PROP_POS_FRAMES,currentFramecount);//进度条跳转对应帧
}

7.点击进度条,重写一个进度条类

因为系统自带的进度条点击时只能移动一小段,不能实现点哪就移动到哪,所以我们要自己重写一个进度条类,然后在ui中提升为重写的进度条

完整源码:

自定义进度条

#ifndef NEWQSLIDER_H
#define NEWQSLIDER_H#include <QWidget>
#include <QSlider>
#include <QMouseEvent>
class newqslider : public QSlider
{Q_OBJECT
public:explicit newqslider(QWidget *parent = 0);void mousePressEvent(QMouseEvent *ev);
signals:void costomSliderClicked();//自定义的鼠标单击信号,用于捕获并处理
public slots:
};#endif // NEWQSLIDER_H
#include "newqslider.h"newqslider::newqslider(QWidget *parent) : QSlider(parent)
{
}
/*****************************************************************
* 函数名称:mousePressEvent(QMouseEvent *ev)
* 功能描述:重写鼠标点击事件,实现进度条点击哪跳到哪
* 参数说明: 无
* 返回值:   无
******************************************************************/
void newqslider::mousePressEvent(QMouseEvent *ev)
{//先调用父类的鼠标点击处理事件,这样可以不影响拖动的情况QSlider::mousePressEvent(ev);//获取鼠标的位置,这里并不能直接从ev中取值(因为如果是拖动的话,鼠标开始点击的位置没有意义了)double pos = ev->pos().x() / (double)width();setValue(pos * (maximum() - minimum()) + minimum());//发送自定义的鼠标单击信号emit costomSliderClicked();
}

线程类

#ifndef VIDEOTHREAD_H
#define VIDEOTHREAD_H#include <QObject>
#include <QThread>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <QDebug>
#include <QDateTime>
using namespace  std;
using namespace  cv;
class videothread : public QThread
{Q_OBJECT
public:videothread(char*filename);void run();int getVideoAllFramecount();//获取视频总帧数void setCurrentFrame(int value);//设置当前进度条bool getStop() const;void setStop(bool value);//设置视频结束标识bool getIsrun() const;void setIsrun(bool value);void pauseThread();//暂停void resumeThread();//继续void stopThread();//停止signals:void sendFrame(int currentFrame,Mat frame);//当前帧和 帧数
private:VideoCapture cap;//视频对象Mat frame;int currentFramecount;//视频当前帧数int allFramecount;//总帧数int fps;//视频帧率int videoWriterFrame;//录制视频帧bool stop;//线程结束标识位bool isrun;//视频暂停标识位};#endif // VIDEOTHREAD_H
#include "videothread.h"videothread::videothread(char*filename)
{this->stop = false;this->isrun =false;this->currentFramecount=0;this->videoWriterFrame=0;if(cap.open(filename));//创建视频对象{this->allFramecount=cap.get(CAP_PROP_FRAME_COUNT);//获取视频文件中的总帧数this->fps=int(round(cap.get(CAP_PROP_FPS)));//获取视频帧率}
}void videothread::run()
{while(stop==false)//线程运行和停止  卡住线程 暂停时不退出线程{while(isrun==true)//视频运行和暂停{if(cap.read(frame))//捕获视频帧{this->currentFramecount++;cvtColor(frame, frame, CV_BGR2RGB);//opencvBGR格式转成Image用到的RGBemit sendFrame(currentFramecount,frame);//发送帧数据}msleep(40);//延时}}cap.release();//释放打开的视频
}int videothread::getVideoAllFramecount()
{return allFramecount;
}void videothread::setStop(bool value)
{stop = value;
}void videothread::setCurrentFrame(int value)
{this->currentFramecount=value;//当前帧数cap.set(CV_CAP_PROP_POS_FRAMES,currentFramecount);//进度条跳转对应帧
}bool videothread::getIsrun() const
{return isrun;
}void videothread::setIsrun(bool value)
{isrun = value;
}void videothread::pauseThread()//这两个函数用于确保是在运行情况下才能切换状态
{if(this->isRunning()&&this->isrun==true)//当前线程运行且视频运行{this->isrun=false;}
}void videothread::resumeThread()
{if(this->isRunning()&&this->isrun==false)//当前线程运行且视频暂停{this->isrun=true;}
}void videothread::stopThread()
{if(this->isRunning())//当前线程运行{this->stop=true;//结束线程//msleep(10);this->terminate();}
}bool videothread::getStop() const
{return stop;
}

窗口类

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QSlider>
#include "videothread.h"
namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();void paintEvent(QPaintEvent *e);public slots:void receiveFrame(int currentFrame,Mat frame);
private slots:void on_pushButton_clicked();void sliderClickedSlot();//点击进度条信号槽void on_horizontalSlider_sliderReleased();void on_horizontalSlider_sliderMoved(int position);void on_pushButton_pause_clicked();void on_pushButton_pause_2_clicked();void on_pushButton_pause_3_clicked();
private:Ui::Widget *ui;videothread *pthread;int receiveCurrentFramecount;QImage img1;bool isend;
};#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{this->receiveCurrentFramecount=0;this->isend=false;ui->setupUi(this);pthread=new videothread("carMove.mp4");//第五个参数采用Qt::BlockingQueuedConnection   信号发出后发送线程阻塞,直到槽函数执行完毕,继续发送下一条信号connect(pthread,SIGNAL(sendFrame(int,Mat)),this,SLOT(receiveFrame(int,Mat)),Qt::BlockingQueuedConnection);//接收每一帧Mat//connect(pthread,SIGNAL(endPlayVideo()),this,SLOT(setPlayEndSlot()),Qt::BlockingQueuedConnection);connect(ui->horizontalSlider,SIGNAL(costomSliderClicked()),this,SLOT(sliderClickedSlot()));//点击进度条信号槽ui->horizontalSlider->setRange(0,pthread->getVideoAllFramecount());//设置进度条取值范围ui->horizontalSlider->setSingleStep(1);//设置单步长为1ui->label_4->setText(QString::number(pthread->getVideoAllFramecount()));//设置总帧数
}Widget::~Widget()
{delete ui;
}void Widget::receiveFrame(int currentFrame, Mat frame)
{this->receiveCurrentFramecount=currentFrame;this->img1 = QImage(frame.data,frame.cols,frame.rows,QImage::Format_RGB888);this->img1 = this->img1.scaled(ui->label->width(),ui->label->height());ui->horizontalSlider->setValue(this->receiveCurrentFramecount);//设置当前进度条取值ui->label_2->setText(QString::number(this->receiveCurrentFramecount));//设置当前帧数update();
}void Widget::setPlayEndSlot()
{pthread->setStop(true);//播放完毕 设置为true
}void Widget::on_pushButton_clicked()
{pthread->start();pthread->setIsrun(true);//视频开始}
void Widget::on_pushButton_pause_clicked()//暂停
{if(pthread->getIsrun()==false&&pthread->isRunning())//暂停状态且线程运行{pthread->resumeThread();//修改为播放状态ui->pushButton_pause->setText("暂停播放");}else if(pthread->getIsrun()==true&&pthread->isRunning())//播放状态{pthread->pauseThread();;//视频暂停ui->pushButton_pause->setText("继续播放");}
}
void Widget::paintEvent(QPaintEvent *e)
{ui->label->setPixmap(QPixmap::fromImage(this->img1));
}void Widget::sliderClickedSlot()//点击进度条 信号槽
{//自定义鼠标点击信号,可以实现点哪 跳转到哪qDebug()<<"点击了进度条";pthread->pauseThread();//播放暂停pthread->setCurrentFrame(ui->horizontalSlider->value());pthread->resumeThread();//播放继续 设置为true
}void Widget::on_horizontalSlider_sliderReleased()//释放进度条
{//ui->horizontalSlider->value();获取当前进度条值pthread->setCurrentFrame(ui->horizontalSlider->value());pthread->resumeThread();//播放继续 设置为true//此处一定要先设置进度条再开启线程,否则线程开启时再设置会冲突
}void Widget::on_horizontalSlider_sliderMoved(int position)//进度条拖动
{pthread->pauseThread();//播放暂停
}void Widget::on_pushButton_pause_2_clicked()//结束播放
{pthread->stopThread();//结束线程qDebug()<<"结束播放,线程关闭";if(!pthread->isRunning())//线程不在运行{if(this->isend!=true)//此时线程结束 已释放,就不再释放{//断开连接disconnect(pthread,SIGNAL(sendFrame(int,Mat)),this,SLOT(receiveFrame(int,Mat)));//接收每一帧Matdelete pthread;qDebug()<<"释放线程000000000000";//this->pthread = NULL;this->isend=true;//表明此时线程结束 已释放//ui->pushButton_pause_2->setEnabled(false);}}
}void Widget::on_pushButton_pause_3_clicked()//重新播放
{pthread->stopThread();//结束线程qDebug()<<"重新播放";if(!pthread->isRunning())//线程不在运行{if(this->isend!=true)//此时线程结束 已释放,就不再释放{//断开连接disconnect(pthread,SIGNAL(sendFrame(int,Mat)),this,SLOT(receiveFrame(int,Mat)));//接收每一帧Matdelete pthread;qDebug()<<"重播111111111111111";}//创建新线程pthread=new videothread("carMove.mp4");pthread->start();pthread->setIsrun(true);//视频开始qDebug()<<"重播新创建线程333";connect(pthread,SIGNAL(sendFrame(int,Mat)),this,SLOT(receiveFrame(int,Mat)),Qt::BlockingQueuedConnection);//接收每一帧Matthis->isend=false;//表明此时线程还未结束//ui->pushButton_pause_2->setEnabled(true);}}

由于只是读取帧,所以该播放器只能播放画面,声音暂时还没做;

感谢观看!!!!

以上就是全部内容,如果对您有帮助,欢迎点赞评论,或者发现有哪里写错的,欢迎指正!

【OpenCV+Qt】实现简易视频播放器——支持进度条拖动相关推荐

  1. 使用python加PyQt5,利用QMediaPlayer写一个简易的音乐播放器(进度条拖动,音量改变,播放停止切换,歌曲列表))

    当你学习了python之后,总想着利用它去做些什么,无论是制作小工具还是小游戏,都是一种锻炼. 那么,利用python加上PyQt5写一个简单的音乐播放器,可能会是一个有趣的体验. 下面我会分享一下如 ...

  2. Qt视频播放器(支持mp4/mkv/wmv/avi)

    Qt基于QMediaPlayer实现视频播放 目前支持mp4/mkv/wmv/avi格式 并支持进度条拖动播放 打开文件扫描视频 void MainWindow::scanVideoFiles() { ...

  3. Qt实用技巧:使用OpenCV库的视频播放器(支持播放器操作,如暂停、恢复、停止、时间、进度条拽托等...

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 需求 使用OpenCV库的视频播放器(支持播放器操作,如暂停.恢复 ...

  4. 【基于QMediaPlayer的简易视频播放器】— 3、结合QSlider实现播放进度控制和音量控制

    基于QMediaPlayer的简易视频播放器 1.创建基本布局 2.QMediaPlayer的基本使用 3.结合QSlider实现播放进度控制和音量控制 4.重载QSlider鼠标响应事件,实现单击跳 ...

  5. java视频播放器制作_java创建简易视频播放器

    java创建简易视频播放器 发布时间:2020-09-23 04:28:09 来源:脚本之家 阅读:98 作者:南柯一梦xihe 最近有个多媒体的作业,要求使用visualC++和OpenCV编写一个 ...

  6. 【Java】简易视频播放器

    [效果图] [功能] 1.当窗口获取焦点后,按空格暂停/播放 2.原速播放键.暂停/播放键.倍速播放键(最高3倍速,每次递增0.5) 3.进度条可点击选择播放位置 4.时间显示.播放速度显示 [项目与 ...

  7. 嵌入式Qt 开发一个视频播放器

    上篇文章:嵌入式 Qt开发一个音乐播放器,使用Qt制作了一个音乐播放器,并在OK3568开发板上进行了运行测试,实际测试效果还不错. 本篇继续来实现一个Qt视频播放器软件,可以实现视频列表的显示与选择 ...

  8. Video标签自定义简易视频播放器

    Video标签自定义简易视频播放器 提示:以下是本篇文章正文内容,下面案例可供参考 一.Dom结构 <template><el-dialog :title="winTitl ...

  9. 视频播放页php,html jquery简易视频播放器

    html jquery js 简易视频播放器 直接上代码:html> Document #durationbar{ width: 500px; height: 20px; } #duration ...

最新文章

  1. VTK:小部件之CaptionWidget
  2. MetroGridHelper: A helpful debugging assistant for designers and developers alike
  3. 使用Netbeans开发App Engine Java
  4. [vue] 在移动端使用vue,你觉得最佳实践有哪些?
  5. FileInputStream 把文件作为字节流进行读操作
  6. Mac OSX 命令行知识
  7. IntelliJ Idea取消Could not autowire. No beans of 'xxxx' type found的错误提示
  8. sublime配置markdown
  9. C++ 类型转换归纳
  10. 把Android系统签名弄成jks
  11. 进销存excel_excel进销存仓库表格同步手机操作
  12. python傅里叶变换相位谱图_[转载]图像傅立叶变换及相位谱
  13. YOLACT论文阅读及解析
  14. 【组合优化】旅行商问题Traveling Salesman Problem(TSP)-概述
  15. 苹果cms function.php,送你们几个字!对!就是MACCMS注入!
  16. 水星路由器登录界面找不到服务器,新版水星(Mercurey)路由器后台登陆界面打不开怎么办?...
  17. 把人脑“森林”上传到计算机:人类脑计划只是一个科幻野心?
  18. 如何将Excel表格中的数据粘贴到记事本中,且每列间距都为一个空格?
  19. Map转为String
  20. Springer的latex压缩包上传转不了pdf

热门文章

  1. 螺旋图形Linux,一个实例带你熟练使用UG中的螺旋线,新手必备!
  2. 【云原生】Hadoop HA on k8s 环境部署
  3. 入网许可证_入网许可证怎么查询方法 入网许可证查询方法【图文演示】
  4. Flutter 最佳扫码插件
  5. 【用户投稿】优麒麟社区懒人版本(含软件全家桶)一键安装
  6. 由EIG牵头的财团与沙特阿美达成124亿美元的基础设施交易
  7. 信捷plc c 语言全局变量,三菱PLC编程中,跳转指令CJ、子程序调用CALL和中断指令有什么区别?...
  8. Java学习07–前端基础之CSS
  9. webpack--黑洞级入门
  10. 计算机二级c语言预测,计算机二级C语言考前预测上机试题及解析