QT软件开发:基于libVLC内核设计视频播放器
Posted DS小龙哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT软件开发:基于libVLC内核设计视频播放器相关的知识,希望对你有一定的参考价值。
一、环境介绍
操作系统: win10 64位
QT版本: QT5.12.6
编译器: MinGW 32
libvlc版本: 3.0.12
完整工程下载地址(下载即可编译运行): https://download.csdn.net/download/xiaolong1126626497/20479530
二、播放器运行效果与功能介绍
播放器的功能介绍:
1. 图像旋转播放(90°、0°、180°、360°)
2. 视频画面截图保存到本地
3. 倍速切换、速度切换不会改变声音音色
4. 音量调整,静音切换
5. 快进、快退支持
6. 点击按钮加载文件、鼠标拖拽文件进行播放
7. 重播按钮支持
8. 暂停与继续切换
9. 单帧切换、前一帧、后一帧
10. 流媒体播放,输入流媒体链接
11. 进度条显示,支持鼠标点击任意跳转到点击位置
12. 播放时间实时更新显示
其他功能可自己增加.....
三、libVLC介绍
3.1 下载VLC的SDK文件
VLC官网地址: https://www.videolan.org/
所有的VLC版本下载地址: http://ftp.heanet.ie/pub/videolan/vlc
3.0.12的SDK下载地址: http://ftp.heanet.ie/pub/videolan/vlc/last/win32/
3.2 libvlc介绍
来至官网的介绍:
libVLC是核心引擎,也是VLC 媒体播放器所基于的多媒体框架的接口。
libVLC被模块化为数百个插件,可以在运行时加载。这种架构为开发人员(VLC 开发人员和使用该库的开发人员)提供了极大的灵活性。它允许开发人员使用VLC功能创建范围广泛的多媒体应用程序。
- 播放每种媒体文件格式、每种编解码器和每种流媒体协议。
- 在各种平台上运行,从桌面(Windows、Linux、Mac)到移动设备(android、ios)和电视。
- 每个平台上的硬件和高效解码,高达 8K。
- 远程文件系统(SMB、FTP、SFTP、NFS...)和服务器(UPnP、DLNA)的网络浏览。
- 使用菜单导航播放音频 CD、DVD 和蓝光。
- 支持 HDR,包括 SDR 流的色调映射。
- 具有 SPDIF 和 HDMI 的音频直通,包括音频高清编解码器,如 DD+、TrueHD 或 DTS-HD。
- 支持视频和音频过滤器。
- 支持 360 度视频和 3D 音频播放,包括 Ambisonics。
- 能够投射和流式传输到远程渲染器,如 Chromecast 和 UPnP 渲染器。
libVLC是一个 C 库,可以嵌入到您自己的应用程序中。它适用于大多数流行的操作系统平台,包括移动设备和桌面设备。它在LGPL2.1 许可下。
libVLC版本控制本质上与 VLC 应用程序版本控制相关联。libVLC 当前稳定的主要版本是 version 3,预览/开发版本是 version 4。
libVLC 的各种编程语言绑定可用于在您选择的生态系统中无缝使用该库。
VideoLAN 绑定
- 用于 C++ 的libvlcpp
- 用于 Apple 平台的VLCKit,使用 Objective-C/Swift。
- 用于 Android 平台的libvlcjni,使用 Java/Kotlin。
- LibVLCSharp适用于大多数操作系统平台,使用 .NET/Mono。
社区绑定
- vlcj用于使用 Java 的桌面平台。
- python-vlc用于使用 Python 的桌面平台。
- vlc-rs使用 Rust 编程语言。
- libvlc-go使用 Go 编程语言。
四、播放器程序设计
#include "widget.h"
#include "ui_widget.h"
Widget* Widget::pThis = nullptr;
Widget::Widget(QString filename,QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
pThis=this;
//设置窗口的标题名称
this->setWindowTitle("VLC内核视频播放器");
//获取VLC版本号
qDebug()<<"VLC内核版本:"<<libvlc_get_version();
qDebug()<<"编译LIBVLC的编译器版本:"<<libvlc_get_compiler();
//加载样式表
SetStyle(":/resource/VideoPlayer.qss");
//读取配置文件
ReadConfig();
//播放器初始化
VLC_InitConfig();
//UI界面相关初始化
UI_InitConfig();
//如果构造函数传入的视频文件就直接加载
if(!filename.isEmpty())
{
load_video_file(0,filename);
}
//拖放文件需要使用
setAcceptDrops(true);
}
Widget::~Widget()
{
delete ui;
libvlc_release(vlc_base); //减少libvlc实例的引用计数,并销毁它
}
/*
工程: 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(100);
ui->horizontalSlider_AudioValue->setMinimum(0);
//安装事件过滤器
ui->horizontalSlider_AudioValue->installEventFilter(this);
//播放速度设置
ui->MediaSpeedBtn->setCheckable(true);
m_TimeSpeedGrp = new QActionGroup(this);
QStringList strSpeedItems;
strSpeedItems << tr("0.5X") << tr("1.0X") << tr("1.5X") << tr("2.0X") << tr("4.0X");
float speeds[] = {0.5,1.0,1.5,2.0,4.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 == 1)
{
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);
if (i == 0)
{
pItem->setChecked(true);
}
}
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("保留1"));
QAction *pAppInfo = m_ConfigurationFunctionMenu.addAction(tr("保留2"));
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_load->setToolTip(tr("加载视频,也可以直接将视频文件拖拽到窗口"));
ui->MediaPrevBtn->setToolTip(tr("快退5秒"));
ui->MediaPlayBtn->setToolTip(tr("快进5秒"));
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->toolButton_link->setToolTip(tr("流媒体链接"));
//播放进度条滑块初始化
connect(ui->horizontalSlider_PlayPosition, SIGNAL(sliderMoved(int)), SLOT(seek(int)));
connect(ui->horizontalSlider_PlayPosition, SIGNAL(sliderPressed()), SLOT(seek()));
this->setMouseTracking(true);
}
/*
工程: ECRS_VideoPlayer
日期: 2021-03-15
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: MediaPlayer初始化
*/
void Widget::VLC_InitConfig(void)
{
const char *tempArg = "";
// tempArg = "--demux=h264";
const char *vlc_args[9] = {"-I", "dummy", "--no-osd", "--no-stats", "--ignore-config", "--no-video-on-top", "--no-video-title-show", "--no-snapshot-preview", tempArg};
//VLC相关的初始化
//vlc_base=libvlc_new(0, nullptr); //创建并初始化libvlc实例
vlc_base=libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
if(!vlc_base)
{
qDebug()<<"libvlc_new 执行错误.";
}
//图像缓冲区申请空间
ctx.pixels = new uchar[MAX_WIDTH * MAX_HEIGHT * 4];
}
/*
工程: ECRS_VideoPlayer
日期: 2021-02-23
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 更新播放进度
*/
void Widget::updateSliderPosition(qint64 value)
{
//设置进度条的时间
ui->horizontalSlider_PlayPosition->setValue(int(value));
//设置右上角的时间
ui->label_current_Time->setText(QTime(0, 0, 0,0).addMSecs(int(value)).toString(QString::fromLatin1("HH:mm:ss:zzz")));
}
/*
工程: 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,0).addMSecs(int(value)).toString(QString::fromLatin1("HH:mm:ss:zzz")));
}
/*
工程: QtVLC_Player
日期: 2021-03-24
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: VLC的事件回调
*/
void Widget::vlcEvents(const libvlc_event_t *ev, void *param)
{
libvlc_time_t play_ms_pos=0;
switch (ev->type){
case libvlc_MediaPlayerTimeChanged:
//获取当前视频的播放位置
play_ms_pos=libvlc_media_player_get_time(pThis->vlc_mediaPlayer);
//设置右上角的时间
pThis->ui->label_current_Time->setText(QTime(0, 0, 0,0).addMSecs(int(play_ms_pos)).toString(QString::fromLatin1("HH:mm:ss:zzz")));
//设置进度条
pThis->ui->horizontalSlider_PlayPosition->setValue(int(play_ms_pos));
break;
case libvlc_MediaPlayerEndReached:
qDebug() << "VLC播放完毕.";
break;
case libvlc_MediaPlayerStopped:
qDebug() << "VLC停止播放";
//获取当前视频的播放位置
play_ms_pos=libvlc_media_player_get_time(pThis->vlc_mediaPlayer);
//设置右上角的时间
pThis->ui->label_current_Time->setText(QTime(0, 0, 0,0).addMSecs(int(play_ms_pos)).toString(QString::fromLatin1("HH:mm:ss:zzz")));
//设置进度条
pThis->ui->horizontalSlider_PlayPosition->setValue(int( pThis->ui->horizontalSlider_PlayPosition->maximum()));
break;
case libvlc_MediaPlayerPlaying:
qDebug() << "VLC开始播放";
break;
case libvlc_MediaPlayerPaused:
qDebug() << "VLC暂停播放";
break;
case libvlc_MediaParsedChanged:
qDebug() << "获取到元数据";
int state=ev->u.media_parsed_changed.new_status;
if(libvlc_media_parsed_status_done==state)
{
qDebug()<<"媒体元数据:"<<libvlc_media_get_meta(pThis->vlc_media,libvlc_meta_Date);
}
break;
}
}
void Widget::display(void *opaque, void *picture)
{
(void)opaque;
}
void *Widget::vlc_lock(void *opaque, void **planes)
{
struct Context *ctx = (struct Context *)opaque;
ctx->mutex.lock();
// 告诉 VLC 将解码的数据放到缓冲区中
*planes = ctx->pixels;
return nullptr;
}
//获取 argb 帧
void Widget::vlc_unlock(void *opaque, void *picture, void *const *planes)
{
struct Context *ctx = (struct Context *)opaque;
unsigned char *data = static_cast<unsigned char *>(*planes);
quint32 w=pThis->video_width;
quint32 h=pThis->video_height;
if(w>0 && h>0 && data!=nullptr)
{
QImage image(data, int(w),int(h), QImage::Format_RGB32);
if(!image.isNull())
{
pThis->ui->widget_videoDisplay->slotGetOneFrame(image.copy());
}
}
ctx->mutex.unlock();
}
/*
工程: 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())
{
//获取路径,如果没有默认路径,就使用当前C盘根目录
if(open_dir_path.isEmpty())
{
open_dir_path="C:/";
}
filename=QFileDialog::getOpenFileName(this,"选择播放的视频",open_dir_path,tr("*.mkv *.flv *.mp4 *.wmv *.*"));
if(filename.isEmpty())return false;
open_dir_path=QFileInfo(filename).path();
qDebug()<<"路径:"<<open_dir_path;
}
media_filename=filename;
}
//判断文件是否存在
if(QFileInfo::exists(media_filename)==false)
{
if(media_filename.contains("rtsp:", Qt::CaseInsensitive)==false&&
media_filename.contains("rtmp:", Qt::CaseInsensitive)==false)
{
return false;
}
else
{
qDebug()<<"播放的流媒体:"<<media_filename;
}
}
else
{
/* 将 / 转为windows下的右斜杆 */
std::replace(media_filename.begin(), media_filename.end(), QChar('/'), QChar('\\\\'));
qDebug()<<"播放的本地媒体:"<<media_filename;
}
MediaInfo.state=MEDIA_LOAD;
MediaInfo.mediaName=media_filename;
//设置当前播放的视频名称
QFileInfo info(media_filename);
ui->label_FileName->setText(QString("%1").arg(info.fileName()));
//宽高清0
video_width=0;
video_height=0;
/*为特定文件路径创建媒体*/
if(vlc_media)libvlc_media_release(vlc_media);
vlc_media=libvlc_media_new_path(vlc_base,media_filename.toUtf8());
if(vlc_media==nullptr)
{
qDebug()<<"libvlc_media_new_path 执行错误.";
return false;
}
/*根据给定的媒体对象创建一个播放器对象*/
if(vlc_mediaPlayer)libvlc_media_player_release(vlc_mediaPlayer);
vlc_mediaPlayer=libvlc_media_player_new_from_media(vlc_media);
//设置回调,用于提取帧或者在界面上显示。
libvlc_video_set_callbacks(vlc_mediaPlayer, vlc_lock, vlc_unlock, display, &ctx);
/*获取媒体播放器事件管理器*/
libvlc_event_manager_t *em = libvlc_media_player_event_manager(vlc_mediaPlayer);
libvlc_event_attach(em, libvlc_MediaPlayerTimeChanged, vlcEvents, this); //进度改变
libvlc_event_attach(em, libvlc_MediaPlayerEndReached, vlcEvents, this); //播放完毕
libvlc_event_attach(em, libvlc_MediaPlayerStopped, vlcEvents, this); //停止
libvlc_event_attach(em, libvlc_MediaPlayerPlaying, vlcEvents, this); //开始播放
libvlc_event_attach(em, libvlc_MediaPlayerPaused, vlcEvents, this); //暂停
libvlc_event_attach(em, libvlc_MediaParsedChanged, vlcEvents, this); //获取到元数据
/*播放媒体文件*/
if(vlc_mediaPlayer)libvlc_media_player_play(vlc_mediaPlayer);
//等待VLC解析文件.否则下面的时间获取不成功
QThread::msleep(100);
//获取媒体文件总长度 ms
libvlc_time_t length = libvlc_media_player_get_length(vlc_mediaPlayer);
qDebug()<<"媒体文件总长度:"<<length;
ui->label_Total_Time->setText(QTime(0, 0, 0,0).addMSecs(int(length)).toString(QString::fromLatin1("HH:mm:ss:zzz")));
//每次加载新文件设置播放进度条为0
ui->horizontalSlider_PlayPosition->setValue(0);
//设置进度条的范围
ui->horizontalSlider_PlayPosition->setMaximum(int(length));
ui->horizontalSlider_PlayPosition->setMinimum(0);
//获取当前媒体播放的位置
libvlc_time_t current_movie_time=libvlc_media_player_get_time(vlc_mediaPlayer);
qDebug()<<"获取当前媒体播放的位置:"<<current_movie_time;
libvlc_video_get_size(vlc_mediaPlayer,0,&video_width,&video_height);
qDebug()<<"视频尺寸:"<<"width:"<<video_width<<"height:"<<video_height;
memset(ctx.pixels, 0, MAX_WIDTH * MAX_HEIGHT * 4);
//设置图像颜色格式
libvlc_video_set_format(vlc_mediaPlayer, "RV32", video_width, video_height, video_width * 4);
libvlc_media_add_option(vlc_media, ":rtsp=tcp"); //连接方式
libvlc_media_add_option(vlc_media, ":network-caching=200"); //缓存
//设置按钮状态为播放状态
ui->MediaPauseBtn->setChecked(false);
//隐藏标签控件
ui->label->setVisible(false);
//获取媒体的元数据信息--异步方式
libvlc_media_parse_with_options(vlc_media,libvlc_media_parse_local,1000);
qDebug()<<"媒体元数据获取---媒体标题:"<<libvlc_media_get_meta(vlc_media,libvlc_meta_Title);
//获取媒体描述符的基本流描述
libvlc_media_track_t **tracks;
//正常的视频获取的流的数量是2. 一个视频流 一个音频流
if(libvlc_media_tracks_get(vlc_media,&tracks))
{
qDebug()<<"视频宽:"<<tracks[0]->video->i_width;
qDebug()<<"视频高:"<<tracks[0]->video->i_height;
//手机拍的视频是翻转(宽高反过来的),电脑上播放需要翻转回去
qDebug()<<"旋转度数:"<<tracks[0]->video->i_orientation;
//逆时针旋转90°
if(tracks[0]->video->i_orientation==libvlc_video_orient_right_top)
{
// video_width=tracks[0]->video->i_height;
// video_height=tracks[0]->video->i_width;
//ui->widget_videoDisplay->Set_Rotate(90);
//libvlc_media_add_option(vlc_media, ":transform-type=90");
}
// libvlc_video_set_scale(vlc_mediaPlayer,1);
}
/*
libvlc_media_add_option(vlc_media, ":rtsp=tcp"); //连接方式
libvlc_media_add_option(vlc_media, ":codec=ffmpeg");
libvlc_media_add_option(vlc_media, ":avcodec-threads=1");
libvlc_media_add_option(vlc_media, ":avcodec-hw=any"); //硬件解码
libvlc_media_add_option(vlc_media, ":network-caching=200"); //缓存
libvlc_media_add_option(vlc_media, ":prefetch-buffer-size=1024"); //预装取缓冲大小512K
libvlc_media_add_option(vlc_media, ":prefetch-read-size=65535"); //预装取读取大小64K
*/
return true;
}
/*
工程: ECRS_VideoPlayer
日期: 2021-02-23
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 加载视频文件
*/
void Widget::on_toolButton_load_clicked()
{
qDebug()<<"加载视频文件状态:"<<load_video_file(0,"");
}
/*
工程: ECRS_VideoPlayer
日期: 2021-02-23
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 暂停播放
*/
void Widget::on_MediaPauseBtn_clicked()
{
//暂停与继续
if(vlc_mediaPlayer)libvlc_media_player_pause(vlc_mediaPlayer);
}
/*
工程: 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();
seek(value-1000*5);
}
/*
工程: ECRS_VideoPlayer
日期: 2021-02-23
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 快进播放
*/
void Widget::on_MediaPlayBtn_clicked()
{
//得到播放进度的当前位置
int value=ui->horizontalSlider_PlayPosition->value();
seek(value+1000*5);
}
/*
工程: ECRS_VideoPlayer
日期: 2021-02-23
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 向左一帧
*/
void Widget::on_ReverseFrameBtn_clicked()
{
//得到播放进度的当前位置
int value=ui->horizontalSlider_PlayPosition->value();
value+=100;
if(value<=ui->horizontalSlider_PlayPosition->maximum())
{
ui->horizontalSlider_PlayPosition->setValue(value);
ui->label_current_Time->setText(QTime(0, 0, 0,0).addMSecs(int(value)).toString(QString::fromLatin1("HH:mm:ss:zzz")));
//跳转播放器
float f_value=(float)value/(float)ui->horizontalSlider_PlayPosition->maximum();
qDebug()<<"f_value:"<<f_value;
libvlc_media_player_set_position(vlc_mediaPlayer,f_value);
}
}
/*
工程: ECRS_VideoPlayer
日期: 2021-02-23
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 向右一帧
*/
void Widget::on_ForwardFrameBtn_clicked()
{
//得到播放进度的当前位置
int value=ui->horizontalSlider_PlayPosition->value();
value-=100;
if(value>=0)
{
ui->horizontalSlider_PlayPosition->setValue(value);
ui->label_current_Time->setText(QTime(0, 0, 0,0).addMSecs(int(value)).toString(QString::fromLatin1("HH:mm:ss:zzz")));
//跳转播放器
float f_value=(float)value/(float)ui->horizontalSlider_PlayPosition->maximum();
qDebug()<<"f_value:"<<f_value;
libvlc_media_player_set_position(vlc_mediaPlayer,f_value);
}
}
/*
工程: ECRS_VideoPlayer
日期: 2021-02-23
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 音量设置
*/
void Widget::on_VolumeBtn_clicked()
{
bool checked=ui->VolumeBtn->isChecked();
if(checked)
{
//静音
if(vlc_mediaPlayer)libvlc_audio_set_volume(vlc_mediaPlayer,0);
}
else
{
//设置正常音量
int volume_val=ui->horizontalSlider_AudioValue->value();
//音量设置
if(vlc_mediaPlayer)libvlc_audio_set_volume(vlc_mediaPlayer,volume_val);
}
}
/*
工程: ECRS_VideoPlayer
日期: 2021-02-23
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 音量设置
*/
void Widget::on_horizontalSlider_AudioValue_valueChanged(int value)
{
//音量设置
if(vlc_mediaPlayer)libvlc_audio_set_volume(vlc_mediaPlayer,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());
/*设置播放速率*/
if(vlc_mediaPlayer)libvlc_media_player_set_rate(vlc_mediaPlayer,float(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, 94);
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)
{
}
//APP功能介绍
else if(item==MENU_APP_INFO)
{
}
}
/*
工程: 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)
{
}
//点击的是音量滑块
else if(obj==ui->horizontalSlider_AudioValue)
{
if (event->type()==QEvent::MouseButtonPress) //判断类型
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent->button() == Qt::LeftButton) //判断左键
{
int value = QStyle::sliderValueFromPosition(ui->horizontalSlider_AudioValue->minimum(), ui->horizontalSlider_AudioValue->maximum(), mouseEvent->pos().x(), ui->horizontalSlider_AudioValue->width());
ui->horizontalSlider_AudioValue->setValue(value);
}
}
}
return QObject::eventFilter(obj,event);
}
/*
工程: ASS_SubtitleVideoPlayer
日期: 2021-06-15
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 按键事件
*/
void Widget::keyPressEvent(QKeyEvent *event)
{
switch(event->key())
{
case Qt::Key_Space:
//视频加载成功才能进行下面的操作
if(MediaInfo.state==MEDIA_LOAD)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Space)
{
if(vlc_mediaPlayer)
{
//暂停与继续切换
libvlc_media_player_pause(vlc_mediaPlayer);
//4表示暂停 3表示继续 5表示停止
int state=libvlc_media_player_get_state(vlc_mediaPlayer);
if(state==4 || state==5)
{
//设置按钮状态
ui->MediaPauseBtn->setChecked(false);
}
else if(state==3)
{
//设置按钮状态
ui->MediaPauseBtn->setChecked(true);
}
}
}
}
break;
}
}
/*
工程: 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;
}
void Widget::seek(int value)
{
if(vlc_mediaPlayer)
{
float pos=value*1.0/ui->horizontalSlider_PlayPosition->maximum();
libvlc_media_player_set_position(vlc_mediaPlayer,pos);
qDebug()<<"跳转的位置:"<<pos;
ui->horizontalSlider_PlayPosition->setValue(value);
ui->label_current_Time->setText(QTime(0, 0, 0,0).addMSecs(int(value)).toString(QString::fromLatin1("HH:mm:ss:zzz")));
//跳转播放器
float f_value=(float)value/(float)ui->horizontalSlider_PlayPosition->maximum();
qDebug()<<"f_value:"<<f_value;
libvlc_media_player_set_position(vlc_mediaPlayer,f_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界面获取用户的个性化配置参数
/*保存数据到文件,方便下次加载*/
QString text;
text=QCoreApplication::applicationDirPath()+"/"+ConfigFile;
QFile filesrc(text);
filesrc.open(QIODevice::WriteOnly);
QDataStream out(&filesrc);
out << open_dir_path; //序列化
filesrc.flush();
filesrc.close();
}
/*
工程: ECRS_VideoPlayer
日期: 2021-02-24
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 读取配置
*/
void Widget::ReadConfig()
{
//读取配置文件
QString text;
text=QCoreApplication::applicationDirPath()+"/"+ConfigFile;
//判断文件是否存在
if(QFile::exists(text))
{
QFile filenew(text);
filenew.open(QIODevice::ReadOnly);
QDataStream in(&filenew); // 从文件读取序列化数据
in >>open_dir_path; //提取写入的数据
filenew.close();
}
}
/*
工程: ASS_SubtitleVideoPlayer
日期: 2021-06-16
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 窗口关闭事件
*/
void Widget::closeEvent(QCloseEvent *event) //窗口关闭事件
{
int ret = QMessageBox::question(this, tr("重要提示"),
tr("是否退出播放器?"),
QMessageBox::Yes | QMessageBox::No);
if(ret==QMessageBox::Yes)
{
SaveConfig();
event->accept(); //接受事件
}
else
{
event->ignore(); //清除事件
}
}
/*
工程: VLC_Core_VideoPlayer
日期: 2021-07-26
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 打开链接
*/
void Widget::on_toolButton_link_clicked()
{
bool ok;
QString text = QInputDialog::getText(this, tr("流媒体播放"),tr("请输入流媒体地址:"), QLineEdit::Normal,
tr("rtmp://58.200.131.2:1935/livetv/cctv14"),&ok);
if (ok && !text.isEmpty())
{
load_video_file(0,text);
}
}
以上是关于QT软件开发:基于libVLC内核设计视频播放器的主要内容,如果未能解决你的问题,请参考以下文章