发布时间:2025-12-09 11:52:21 浏览次数:1
操作系统: win10 64位
QT版本: QT5.12.6
编译器: MinGW 32
QMediaPlayer是Qt提供的一个跨平台媒体播放器类,它没有自带解码库,而是对平台相关的播放器框架做了封装,提供了平台无关的API。所以使用QMediaPlayer播放视频,需要提前安装解码库。 在win系统下可以下载K-Lite_Codec_Pack或者LAVFilters解码库安装。
下载地址:https://download.csdn.net/download/xiaolong1126626497/15702561
工程完整源码下载: https://download.csdn.net/download/xiaolong1126626497/15804157
1. 支持命令行传入视频播放
2. 支持图像旋转播放
3. 支持查看媒体信息
4. 支持选择GPU加速解码
5. 支持快进、快退
6. 支持预览画面(鼠标放在进度条上查看画面缩略图)
7. 支持单帧播放,就是一帧一帧的点击切换画面
8. 支持画面拍照、截图
9. 支持复位到视频首页
10. 支持音量调整
11. 支持拖拽文件到窗口播放
12. 默认打开视频不会自动播放。 自动显示在第一帧,视频放完停留在最后一帧。
为了更加方便处理视频帧,代码里重写了QAbstractVideoSurface 类,接收解码的视频帧,自己完成绘制。
头文件:
#ifndef MEDIAVIDEOFRAME_H#define MEDIAVIDEOFRAME_H#include <QAbstractVideoSurface>class MediaVideoFrame : public QAbstractVideoSurface{ Q_OBJECTpublic: explicit MediaVideoFrame(QObject *parent = nullptr);signals: void SendOneFrame(QImage img);public slots: // QAbstractVideoSurface interfacepublic: QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const; bool present(const QVideoFrame &frame);};#endif // MEDIAVIDEOFRAME_H源文件:
#include "MediaVideoFrame.h"MediaVideoFrame::MediaVideoFrame(QObject *parent) : QAbstractVideoSurface(parent){}QList<QVideoFrame::PixelFormat> MediaVideoFrame::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const{ QList<QVideoFrame::PixelFormat> list; list<<QVideoFrame::Format_RGB32; //支持的格式 return list;}bool MediaVideoFrame::present(const QVideoFrame &frame){ if(frame.isValid()) { QVideoFrame cloneFrame(frame); cloneFrame.map(QAbstractVideoBuffer::ReadOnly); QImage img(cloneFrame.bits(),cloneFrame.width(),cloneFrame.height(),QVideoFrame::imageFormatFromPixelFormat(cloneFrame.pixelFormat())); cloneFrame.unmap(); emit SendOneFrame(img); return true; } return false;}#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include <QFile>#include <QFileDialog>#include <QActionGroup>#include <QMenu>#include <QApplication>#include <QClipboard>#include <QStyle>#include <QToolTip>#include <QDragEnterEvent>#include <QDropEvent>#include <QMimeData>#include <QMouseEvent>#include "work_thread.h"#include "dialog_waitcomplete.h"#include <QDesktopWidget>#include <QMessageBox>#include <QMediaPlayer>#include "MediaVideoFrame.h"QT_BEGIN_NAMESPACEnamespace Ui { class Widget; }QT_END_NAMESPACEenum MENU_ITEM{ MENU_COPY_CLIPBOARD = 0, MENU_SAVE_FILE_SYSTEM, MENU_EDIT_SUBTITLE, MENU_SHOW_SUBTITLE, MENU_PLAY_NARRATOR, MENU_TO_KeyFrame, //转为关键帧 MENU_APP_INFO,//APP信息介绍};enum MEDIA_STATE{ MEDIA_NOLOAD,//视频未加载 MEDIA_LOAD,//视频加载};//媒体状态信息struct MediaStateInfo{ MEDIA_STATE state; QString mediaName;};//配置文件名称#define ConfigFile "cofnig.ini"class Widget : public QWidget{ Q_OBJECTpublic: Widget(QString filename=nullptr,QWidget *parent = nullptr); ~Widget(); //加载样式表 void SetStyle(const QString &qssFile); //UI界面初始化 void UI_InitConfig(); //加载视频文件 bool load_video_file(bool flag, QString file_path); //保存配置 void SaveConfig(); //读取配置 void ReadConfig(); //播放器初始化 void MediaPlayer_InitConfig(void); signals: void s_pause_state(bool pause_state,qint64 current_time); void s_PlayPosTime(qint64 pos_time);protected: bool eventFilter(QObject *obj, QEvent *event); void dragEnterEvent(QDragEnterEvent *e); void dropEvent(QDropEvent *e);private slots: void slot_stateChanged(QMediaPlayer::State); void slot_PlayError(QMediaPlayer::Error); void slot_wheelEvent(bool type); void seek(); void seek(int); void onTimeSliderHover(int pos, int value); void onTimeSliderLeave(); void slot_onMediaSnapshot(QAction *action); void slot_onConfigurationFunction(QAction *action); void slot_onMediaRotate(QAction *action); void slot_onSetTimeSpeed(QAction *action); void updateSliderPosition(qint64 value); void media_durationChanged(qint64); void on_toolButton_load_clicked(); void on_toolButton_init_load_clicked(); void on_MediaPauseBtn_clicked(); void on_MediaResetBtn_clicked(); void on_MediaPrevBtn_clicked(); void on_MediaPlayBtn_clicked(); void on_ReverseFrameBtn_clicked(); void on_ForwardFrameBtn_clicked(); void on_VolumeBtn_clicked(); void on_horizontalSlider_AudioValue_valueChanged(int value); void on_MediaSpeedBtn_clicked(); void on_MediaRotateBtn_clicked(); void on_MediaSnapshotBtn_clicked(); void on_toolButton_set_clicked(); void on_toolButton_media_info_clicked(); void on_checkBox_gpu_set_clicked(bool checked);private: Ui::Widget *ui; struct MediaStateInfo MediaInfo; QActionGroup *m_TimeSpeedGrp; QMenum_SpeedMenu; QActionGroup*m_RotateGrp; QMenum_RotateMenu; QActionGroup*m_SnapshotGrp; QMenum_SnapshotMenu; QActionGroup*m_ConfigurationFunctionGrp; QMenum_ConfigurationFunctionMenu; //视频名称 char video_name[1024]; //视频名称 //工作线程 CWorkThread *work_thread; QMediaPlayer *MeadiaPlayer; MediaVideoFrame *VideoFrame;};#endif // WIDGET_H#include "widget.h"#include "ui_widget.h"Widget::Widget(QString filename,QWidget *parent) : QWidget(parent) , ui(new Ui::Widget){ ui->setupUi(this); //设置窗口的标题名称 this->setWindowTitle("视频播放器-K-Lite_Codec_Pack"); //加载样式表 SetStyle(":/resource/ECRS_VideoPlayer.qss"); //读取配置文件 ReadConfig(); //播放器初始化 MediaPlayer_InitConfig(); //UI界面相关初始化 UI_InitConfig(); //如果构造函数传入的视频文件就直接加载 if(!filename.isEmpty()) { load_video_file(0,filename); }}Widget::~Widget(){ delete ui;}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 加载样式表*/void Widget::SetStyle(const QString &qssFile){ QFile file(qssFile); if (file.open(QFile::ReadOnly)) { QByteArray qss=file.readAll(); qApp->setStyleSheet(qss); file.close(); }}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: UI界面初始化*/void Widget::UI_InitConfig(){ //音量滑块范围设置 ui->horizontalSlider_AudioValue->setMaximum(10); ui->horizontalSlider_AudioValue->setMinimum(0); //播放速度设置 ui->MediaSpeedBtn->setCheckable(true); m_TimeSpeedGrp = new QActionGroup(this); QStringList strSpeedItems; strSpeedItems << tr("0.03X") << tr("0.06X") << tr("0.1X") << tr("0.15X") << tr("0.2X") << tr("0.3X") << tr("0.4X") << tr("0.5X") << tr("0.6X") << tr("0.8X") << tr("1.0X") << tr("1.25X") << tr("1.5X") << tr("2.0X") << tr("4.0X") << tr("8.0X"); float speeds[] = { 0.03, 0.06, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5,0.6,0.8,1.0,1.25,1.5,2.0,4.0,8.0}; for (int i = 0; i < strSpeedItems.size(); i++) { QAction *pSpeedItem = m_SpeedMenu.addAction(strSpeedItems.at(i)); pSpeedItem->setData(QVariant::fromValue(speeds[i])); pSpeedItem->setCheckable(true); m_TimeSpeedGrp->addAction(pSpeedItem); if (i == 10) { pSpeedItem->setChecked(true); } } connect(m_TimeSpeedGrp, SIGNAL(triggered(QAction *)), this, SLOT(slot_onSetTimeSpeed(QAction *))); //图像的旋转方向 m_RotateGrp = new QActionGroup(this); QStringList strDegrees; strDegrees << tr("0~") << tr("90~") << tr("180~") << tr("270~"); int Degrees[] = {0, 90, 180, 270 }; for (int i = 0; i < strDegrees.size(); i++) { QAction *pItem = m_RotateMenu.addAction(strDegrees.at(i)); pItem->setData(QVariant::fromValue(Degrees[i])); pItem->setCheckable(true); m_RotateGrp->addAction(pItem); } connect(m_RotateGrp, SIGNAL(triggered(QAction *)), this, SLOT(slot_onMediaRotate(QAction *))); //功能设置 // ui->toolButton_set->setCheckable(true); m_ConfigurationFunctionGrp = new QActionGroup(this); QAction *pToKeyFrame = m_ConfigurationFunctionMenu.addAction(tr("转为关键帧")); QAction *pAppInfo = m_ConfigurationFunctionMenu.addAction(tr("功能说明")); pToKeyFrame->setData(MENU_TO_KeyFrame); //保存到剪切板 pAppInfo->setData(MENU_APP_INFO); //保存到文件 m_ConfigurationFunctionGrp->addAction(pToKeyFrame); //添加到分组 m_ConfigurationFunctionGrp->addAction(pAppInfo); //添加到分组 connect(m_ConfigurationFunctionGrp, SIGNAL(triggered(QAction *)), this, SLOT(slot_onConfigurationFunction(QAction *))); //截图保存 // ui->MediaSnapshotBtn->setCheckable(true); m_SnapshotGrp = new QActionGroup(this); QAction *pClipboard = m_SnapshotMenu.addAction(tr("保存到剪切板")); QAction *pFileDirectory = m_SnapshotMenu.addAction(tr("保存到文件")); pClipboard->setData(MENU_COPY_CLIPBOARD); //保存到剪切板 pFileDirectory->setData(MENU_SAVE_FILE_SYSTEM); //保存到文件 m_SnapshotGrp->addAction(pClipboard); //添加到分组 m_SnapshotGrp->addAction(pFileDirectory); //添加到分组 connect(m_SnapshotGrp, SIGNAL(triggered(QAction *)), this, SLOT(slot_onMediaSnapshot(QAction *))); //安装事件监听器 事件筛选器是接收发送到此对象的所有事件的对象 ui->horizontalSlider_PlayPosition->installEventFilter(this); ui->widget_videoDisplay->installEventFilter(this); //状态信息初始化 MediaInfo.state=MEDIA_NOLOAD; //工具提示信息 ui->toolButton_init_load->setToolTip(tr("加载视频,也可以直接将视频文件拖拽到窗口")); ui->toolButton_load->setToolTip(tr("加载视频,也可以直接将视频文件拖拽到窗口")); ui->toolButton_media_info->setToolTip(tr("媒体信息")); ui->MediaPrevBtn->setToolTip(tr("快退")); ui->MediaPlayBtn->setToolTip(tr("快进")); ui->MediaPauseBtn->setToolTip(tr("暂停/继续")); ui->MediaSpeedBtn->setToolTip(tr("倍速选择")); ui->MediaResetBtn->setToolTip(tr("复位")); ui->MediaSnapshotBtn->setToolTip(tr("截图")); ui->MediaRotateBtn->setToolTip(tr("画面旋转")); ui->ReverseFrameBtn->setToolTip(tr("左一帧")); ui->ForwardFrameBtn->setToolTip(tr("右一帧")); ui->VolumeBtn->setToolTip(tr("静音切换")); ui->checkBox_gpu_set->setToolTip(tr("GPU硬件解码支持(需要重启软件才能生效)")); //播放进度条滑块初始化 connect(ui->horizontalSlider_PlayPosition, SIGNAL(onLeave()), SLOT(onTimeSliderLeave())); connect(ui->horizontalSlider_PlayPosition, SIGNAL(onHover(int,int)), SLOT(onTimeSliderHover(int,int))); connect(ui->horizontalSlider_PlayPosition, SIGNAL(sliderMoved(int)), SLOT(seek(int))); connect(ui->horizontalSlider_PlayPosition, SIGNAL(sliderPressed()), SLOT(seek())); this->setMouseTracking(true); connect(this, SIGNAL(s_pause_state(bool,qint64)),ui->widget_videoDisplay,SLOT(slot_pause_state(bool,qint64))); connect(this, SIGNAL(s_PlayPosTime(qint64)),ui->widget_videoDisplay,SLOT(slot_PlayPosTime(qint64))); //工作线程 work_thread =new CWorkThread;}/*工程: ECRS_VideoPlayer日期: 2021-03-15作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: MediaPlayer初始化*/void Widget::MediaPlayer_InitConfig(void){ /*多媒体类*/ MeadiaPlayer = new QMediaPlayer(this); VideoFrame = new MediaVideoFrame; /*设置视频解码输出的位置*/ MeadiaPlayer->setVideoOutput(VideoFrame); //关联播放器的视频帧显示 connect(VideoFrame, SIGNAL(SendOneFrame(QImage)),ui->widget_videoDisplay,SLOT(slotGetOneFrame(QImage))); //添加播放进度的信号 connect(MeadiaPlayer, SIGNAL(positionChanged(qint64)),this, SLOT(updateSliderPosition(qint64))); //添加获取播放总时间的信号 connect(MeadiaPlayer, SIGNAL(durationChanged(qint64)),this, SLOT(media_durationChanged(qint64))); //关联鼠标事件 connect(ui->widget_videoDisplay, SIGNAL(s_wheelEvent(bool)),this,SLOT(slot_wheelEvent(bool))); //关联错误提示信号 connect(MeadiaPlayer, SIGNAL(error(QMediaPlayer::Error)),this,SLOT(slot_PlayError(QMediaPlayer::Error))); //状态发生改变 connect(MeadiaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)),this,SLOT(slot_stateChanged(QMediaPlayer::State))); //设置更新间隔 MeadiaPlayer->setNotifyInterval(100);}/*工程: ECRS_VideoPlayer日期: 2021-03-15作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 设置播放器*/void Widget::slot_PlayError(QMediaPlayer::Error error){ QString text; if(QMediaPlayer::NoError==error) { text="正常解码!"; } else if(QMediaPlayer::ResourceError==error) { text="媒体资源无法解析。"; } else if(QMediaPlayer::FormatError==error) { text="不支持该媒体资源的格式,没有解码器!"; } else if(QMediaPlayer::NetworkError==error) { text="发生网络错误。"; } else if(QMediaPlayer::AccessDeniedError==error) { text="没有适当的权限来播放媒体资源。"; } else if(QMediaPlayer::ServiceMissingError==error) { text="没有找到有效的播放服务,播放无法继续。"; } QMessageBox::critical(this,"播放器提示",text,QMessageBox::Ok,QMessageBox::Ok);}/*工程: ECRS_VideoPlayer日期: 2021-03-15作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 状态发生改变*/void Widget::slot_stateChanged(QMediaPlayer::State state){ switch (state) { case QMediaPlayer::StoppedState: qDebug()<<"视频停止播放"; break; case QMediaPlayer::PlayingState: qDebug()<<"视频继续播放"; ui->MediaPauseBtn->setChecked(false); break; case QMediaPlayer::PausedState: qDebug()<<"视频暂停播放"; ui->MediaPauseBtn->setChecked(true); break; }}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 更新播放进度*/void Widget::updateSliderPosition(qint64 value){ //设置进度条的时间 ui->horizontalSlider_PlayPosition->setValue(int(value)); //通知播放器显示窗体 emit s_PlayPosTime(value); //设置右上角的时间 ui->label_current_Time->setText(QTime(0, 0, 0).addMSecs(int(value)).toString(QString::fromLatin1("HH:mm:ss")));}/*工程: ECRS_VideoPlayer日期: 2021-03-15作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 媒体总时间*/void Widget::media_durationChanged(qint64 value){ //最大值最小值 ui->horizontalSlider_PlayPosition->setMinimum(int(0)); ui->horizontalSlider_PlayPosition->setMaximum(int(value)); ui->label_Total_Time->setText(QTime(0, 0, 0).addMSecs(int(value)).toString(QString::fromLatin1("HH:mm:ss")));}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 加载视频文件 flag=0 重新加载文件 flag=1 重新开始播放QString file_path 这参数可以传入文件名称,因为窗口支持拖放文件进来返回值: true 成功 false 失败*/bool Widget::load_video_file(bool flag,QString file_path){ if(flag==false) { QString filename=file_path; if(filename.isEmpty()) { filename=QFileDialog::getOpenFileName(this,"选择播放的视频","D:/",tr("*.mp4 *.wmv *.*")); } strncpy(video_name,filename.toUtf8().data(),sizeof(video_name)); ui->toolButton_init_load->setVisible(false); } //判断文件是否存在 if(QFileInfo::exists(video_name)==false) { return false; } else { MediaInfo.state=MEDIA_LOAD; MediaInfo.mediaName=video_name; } //每次加载新文件设置播放进度条为0 ui->horizontalSlider_PlayPosition->setValue(0); qDebug()<<"停止原视频"; //停止播放 MeadiaPlayer->stop(); //播放视频 MeadiaPlayer->setMedia(QUrl::fromLocalFile(video_name)); MeadiaPlayer->pause(); qDebug()<<"当期播放视频:"<<video_name; //设置当前播放的视频名称 QFileInfo info(video_name); ui->label_FileName->setText(QString("%1").arg(info.fileName())); return true;}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 加载视频文件*/void Widget::on_toolButton_load_clicked(){ qDebug()<<"加载视频文件状态:"<<load_video_file(0,"");}void Widget::on_toolButton_init_load_clicked(){ load_video_file(0,"");}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 暂停播放*/void Widget::on_MediaPauseBtn_clicked(){ //暂停状态 if (MeadiaPlayer->state()==QMediaPlayer::PausedState) { //通知播放器 s_pause_state(true,ui->horizontalSlider_PlayPosition->value()); //继续播放 MeadiaPlayer->play(); return; } else { //暂停播放 MeadiaPlayer->pause(); }}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 重新开始播放*/void Widget::on_MediaResetBtn_clicked(){ //加重新开始播放 load_video_file(true,"");}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 快退播放*/void Widget::on_MediaPrevBtn_clicked(){ //得到播放进度的当前位置 int value=ui->horizontalSlider_PlayPosition->value(); int m_unit = MeadiaPlayer->notifyInterval();//获取更新间隔时间 //设置每次点击快退的距离 MeadiaPlayer->setPosition(value-m_unit*10);}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 快进播放*/void Widget::on_MediaPlayBtn_clicked(){ //得到播放进度的当前位置 int value=ui->horizontalSlider_PlayPosition->value(); int m_unit = MeadiaPlayer->notifyInterval();//获取更新间隔时间 //设置每次点击快退的距离 MeadiaPlayer->setPosition(value+m_unit*10);}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 向左一帧*/void Widget::on_ReverseFrameBtn_clicked(){ //得到播放进度的当前位置 int value=ui->horizontalSlider_PlayPosition->value(); int m_unit = MeadiaPlayer->notifyInterval();//获取更新间隔时间 //设置每次点击快退的距离 MeadiaPlayer->setPosition(value-m_unit);}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 向右一帧*/void Widget::on_ForwardFrameBtn_clicked(){ //得到播放进度的当前位置 int value=ui->horizontalSlider_PlayPosition->value(); int m_unit = MeadiaPlayer->notifyInterval();//获取更新间隔时间 //设置每次点击快退的距离 MeadiaPlayer->setPosition(value+m_unit);}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 音量设置*/void Widget::on_VolumeBtn_clicked(){ bool checked=ui->VolumeBtn->isChecked(); if(checked) { //静音 //音量设置 MeadiaPlayer->setVolume(0); } else { //设置正常音量 int volume_val=ui->horizontalSlider_AudioValue->value(); //音量设置 MeadiaPlayer->setVolume(int(volume_val)); }}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 音量设置*/void Widget::on_horizontalSlider_AudioValue_valueChanged(int value){ //音量设置 MeadiaPlayer->setVolume(value);}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 播放速度设置菜单选择*/void Widget::slot_onSetTimeSpeed(QAction *action){ action->setChecked(true); ui->MediaSpeedBtn->setToolTip(action->text()); ui->MediaSpeedBtn->setText(action->text()); //设置速度 正常速度是1.0 MeadiaPlayer->setPlaybackRate(qreal(action->data().toFloat()));}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 点击了速度设置按钮*/void Widget::on_MediaSpeedBtn_clicked(){ QPoint ptWgt = ui->MediaSpeedBtn->mapToGlobal(QPoint(0, 0)); ptWgt -= QPoint(10, 180); QAction *pSelect = m_SpeedMenu.exec(ptWgt); if (pSelect == nullptr) return;}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 点击了旋转选择菜单*/void Widget::slot_onMediaRotate(QAction *action){ action->setChecked(true); ui->MediaRotateBtn->setToolTip(action->text()); ui->widget_videoDisplay->Set_Rotate(action->data().toInt());}/*工程: ECRS_VideoPlayer日期: 2021-02-23作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 点击了画面旋转菜单*/void Widget::on_MediaRotateBtn_clicked(){ QPoint ptWgt = ui->MediaRotateBtn->mapToGlobal(QPoint(0, 0)); ptWgt -= QPoint(10, 94); QAction *pSelect = m_RotateMenu.exec(ptWgt); if (pSelect == nullptr) return;}/*工程: ECRS_VideoPlayer日期: 2021-03-08作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 点击了功能设置菜单*/void Widget::slot_onConfigurationFunction(QAction *action){ if (action == nullptr) return; //得到按下的序号 MENU_ITEM item = MENU_ITEM(action->data().toInt()); //转视频为关键帧 if (item == MENU_TO_KeyFrame) { qDebug()<<"转视频为关键帧"; //创建窗口,显示导出的过程信息,并绑定信号. Dialog_WaitComplete wait; connect(work_thread, &CWorkThread::exit_close,&wait, &Dialog_WaitComplete::dialog_close); QString video_file=QFileDialog::getOpenFileName(this,"选择打开的视频文件","D:/",tr("*.*")); //filename==选择文件的绝对路径 if(video_file.isEmpty())return; QFileInfo info(video_file); QString output_video=info.absolutePath()+info.baseName()+"_KeyFrame"+"."+info.suffix(); qDebug()<<"output_video:"<<output_video; //拼接命令 QString strCmd=QCoreApplication::applicationDirPath(); //得到程序的执行路径 strCmd += QString("/ffmpeg_422.exe -i %1 -strict -2 -qscale 0 -intra %2") .arg(video_file) //输入视频文件路径 .arg(output_video); //输出的文件名称 qDebug()<<"strCmd:"<<strCmd; //判断输出文件是否已经存在 QFileInfo out_file(output_video); if(out_file.exists()) //文件存在就不需要转换 { QFile::remove(output_video); //return; } //先退出线程 work_thread->quit(); work_thread->wait(); work_thread->SetRunCmd(strCmd); work_thread->start(); //执行线程 //设置遮罩窗口 QWidget mask_window(this); //设置窗体的背景色,这里的百分比就是透明度 mask_window.setStyleSheet(QString("background-color: rgba(0, 0, 0, 50%);")); mask_window.setGeometry(this->rect()); //设置当前窗口 mask_window.show(); //显示状态窗口 wait.SetText("请等待..."); wait.show(); wait.exec(); //关闭遮罩窗口 mask_window.close(); } //APP功能介绍 else if(item==MENU_APP_INFO) { qDebug()<<"APP功能介绍"; QString text= "Bug提交: QQ1126626497n" "1. 支持命令行传入视频播放n" "2. 支持图像旋转播放n" "3. 支持查看媒体信息n" "4. 支持选择GPU加速解码n" "5. 支持快进、快退n" "6. 支持预览画面(鼠标放在进度条上查看画面缩略图)n" " 7. 支持单帧播放,就是一帧一帧的点击切换画面n" " 8. 支持画面拍照、截图n" " 9. 支持复位到视频首页n" "10. 支持音量调整n" "11. 支持拖拽文件到窗口播放n" "12. 默认打开视频不会自动播放。自动显示在第一帧,视频放完停留在最后一帧。n" "13. 支持视频转关键帧输出.方便鼠标滚轮单帧跳转n"; QMessageBox::about(this,"播放器功能介绍",text); }}/*工程: ECRS_VideoPlayer日期: 2021-02-24作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 点击了截图菜单*/void Widget::slot_onMediaSnapshot(QAction *action){ if (action == nullptr) return; //得到按下的序号 MENU_ITEM item = MENU_ITEM(action->data().toInt()); QImage Pic=ui->widget_videoDisplay->GetImage(); if (Pic.isNull() || Pic.height() <= 0)return; //保存到剪切板 if (item == MENU_COPY_CLIPBOARD) { QApplication::clipboard()->setImage(Pic); } //保存到文件 else if (item == MENU_SAVE_FILE_SYSTEM) { QString strFile = QDateTime::currentDateTime().toString("yyyyMMddHHmmss") + ".png"; QString strFileName = QFileDialog::getSaveFileName(nullptr, "保存图片", strFile, "PNG(*.png);;BMP(*.bmp);;JPEG(*.jpg *.jpeg)"); if (!strFileName.isEmpty()) { strFileName = QDir::toNativeSeparators(strFileName); QFileInfo fInfo(strFileName); Pic.save(strFileName, fInfo.completeSuffix().toStdString().c_str(), 80); } }}/*工程: ECRS_VideoPlayer日期: 2021-02-24作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 点击了截图按钮*/void Widget::on_MediaSnapshotBtn_clicked(){ QPoint ptWgt = ui->MediaSnapshotBtn->mapToGlobal(QPoint(0, 0)); ptWgt -= QPoint(10, 48); QAction *pSelect = m_SnapshotMenu.exec(ptWgt); if (pSelect == nullptr) return;}/*工程: ECRS_VideoPlayer日期: 2021-02-24作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 拦截事件*/bool Widget::eventFilter(QObject *obj, QEvent *event){ //判断是否在视频窗口范围内按下的鼠标 if(obj==ui->widget_videoDisplay) { //视频加载成功才能进行下面的操作 if(MediaInfo.state==MEDIA_LOAD) { //判断是否是鼠标事件 if (event->type()==QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); //如果按下的是左键 if(mouseEvent->button() == Qt::LeftButton) { //如果是暂停状态 if(MeadiaPlayer->state()==QMediaPlayer::PausedState) { //继续播放 MeadiaPlayer->play(); //通知播放器 s_pause_state(true,ui->horizontalSlider_PlayPosition->value()); } else { //暂停播放 MeadiaPlayer->pause(); } } } } } return QObject::eventFilter(obj,event);}/*工程: ECRS_VideoPlayer日期: 2021-03-08作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 点击了设置按钮*/void Widget::on_toolButton_set_clicked(){ QPoint ptWgt = ui->toolButton_set->mapToGlobal(QPoint(0, 0)); ptWgt -= QPoint(10, 48); QAction *pSelect = m_ConfigurationFunctionMenu.exec(ptWgt); if (pSelect == nullptr) return;}/*工程: ECRS_VideoPlayer日期: 2021-02-24作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 查看媒体信息*/void Widget::on_toolButton_media_info_clicked(){}void Widget::onTimeSliderHover(int pos, int value){}void Widget::onTimeSliderLeave(){}void Widget::seek(int value){ MeadiaPlayer->setPosition(qint64(value));}void Widget::seek(){ seek(ui->horizontalSlider_PlayPosition->value());}void Widget::dragEnterEvent(QDragEnterEvent *e){ if (e->mimeData()->hasUrls()) { e->acceptProposedAction(); }}void Widget::dropEvent(QDropEvent *e){ foreach (const QUrl &url, e->mimeData()->urls()) { QString fileName = url.toLocalFile(); qDebug() << "拖入的文件名称:" << fileName; //加载视频文件 load_video_file(false,fileName); }}/*工程: ECRS_VideoPlayer日期: 2021-02-24作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 保存配置*/void Widget::SaveConfig(){ //从UI界面获取用户的个性化配置参数 bool val=ui->checkBox_gpu_set->isChecked(); /*保存数据到文件,方便下次加载*/ QString text; text=QCoreApplication::applicationDirPath()+"/"+ConfigFile; QFile filesrc(text); filesrc.open(QIODevice::WriteOnly); QDataStream out(&filesrc); out << val; //序列化 filesrc.flush(); filesrc.close();}/*工程: ECRS_VideoPlayer日期: 2021-02-24作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 读取配置*/void Widget::ReadConfig(){// //读取配置文件// QString text;// text=QCoreApplication::applicationDirPath()+"/"+ConfigFile;// bool val;// //判断文件是否存在// if(QFile::exists(text))// {// QFile filenew(text);// filenew.open(QIODevice::ReadOnly);// QDataStream in(&filenew); // 从文件读取序列化数据// in >> val; //提取写入的数据// filenew.close();// //设置界面值// ui->checkBox_gpu_set->setChecked(val);// } //因为使用的系统接口,默认就是使用GPU ui->checkBox_gpu_set->setChecked(true);}/*工程: ECRS_VideoPlayer日期: 2021-02-24作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: GPU支持选择*/void Widget::on_checkBox_gpu_set_clicked(bool checked){ SaveConfig();}/*工程: ECRS_VideoPlayer日期: 2021-03-07作者: DS小龙哥环境: win10 QT5.12.6 MinGW32功能: 鼠标滚轮事件true 向前false 向后*/void Widget::slot_wheelEvent(bool type){ //鼠标滚轮向前 if(type) { on_ForwardFrameBtn_clicked(); } //鼠标滚轮向后 else { on_ReverseFrameBtn_clicked(); }}注意: 运行的时候,需要把QT安装目录下的“mediaservice” 目录拷贝到程序运行目录下。
比如我的目录路径:C:QtQt5.12.65.12.6mingw73_32pluginsmediaservice
解码器安装之后的目录如下:
最后程序打包的时候,可以把解码库一起打包放在程序执行目录下,注册3个ax文件即可。
可以将以下代码写入到xxx.bat文件中,直接运行。 注意: 要用管理员身份运行。
cd /d %~dp0@regsvr32 LAVAudio.ax@regsvr32 LAVSplitter.ax@regsvr32 LAVVideo.ax@exit