Qt 视频播放画面闪烁问题解决办法

问题

窗口伸缩时,有其他窗口元素与视频窗口交叉显示时,焦点切换时,视频出现闪烁现象。

播放软件实现了多窗口同时播放多路视频。在切换不同的视频窗口时出现背景图片刷新闪屏

播放软件主窗口重新实现函数changeEvent,解决最小化之后界面不刷新问题。

void CSSAWidget::paintEvent(QPaintEvent *)
{
    由于继承了QWidget,必须重载paintevent才能绘制背景
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
    p.drawPixmap(0, 0, width(), height(), m_pixMapBG);//绘制背景
}

播放视频的widget类派生自QWidget,重新实现paintEvent函数,绘制背景图片。

void CSSAWidget::paintEvent(QPaintEvent *)
{
    由于继承了QWidget,必须重载paintevent才能绘制背景
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
    p.drawPixmap(0, 0, width(), height(), m_pixMapBG);//绘制背景
}


问题是在视频播放过程中,当播放软件重绘的时候(比如调用update、repaint等函数时),会重绘widget背景,导致播放视频闪烁。

结合网上查找方案和Qt官方文档之后,设置widget属性setAttribute(Qt::WA_OpaquePaintEvent); 之后,在软件上进行其他窗口切换的时候不再刷新背景。
Qt官方文档解释如下:To rapidly update custom widgets that constantly paint over their entire areas with opaque content, e.g., video streaming widgets, it is better to set the widget’s Qt::WA_OpaquePaintEvent, avoiding any unnecessary overhead associated with repainting the widget’s background.

快速刷新需要在整个窗口区域持续绘制不透明内容自定义widget,比如视频流widget,最好设置Qt::WA_OpaquePaintEvent属性来避免任何不必要的过度重绘背景。

Qt::WA_OpaquePaintEvent属性的解释如下:Indicates that the widget paints all its pixels when it receives a paint event. Thus, it is not required for operations like updating, resizing, scrolling and focus changes to erase the widget before generating paint events. The use of WA_OpaquePaintEvent provides a small optimization by helping to reduce flicker on systems that do not support double buffering and avoiding computational cycles necessary to erase the background prior to painting. Note: Unlike WA_NoSystemBackground, WA_OpaquePaintEvent makes an effort to avoid transparent window backgrounds. This flag is set or cleared by the widget’s author.

虽然使用上述方法,当操作一直在软件上时不再出现重绘背景的问题。但是当软件失去焦点,再重新获取焦点时,依旧会出现重绘背景。

解决办法

  1. 播放视频的 QWidget 设置, widget->setAttribute(Qt::WA_OpaquePaintEvent);
    避免任何不必要的过度重绘背景;
  2. 视频播放时调用 widget->setUpdatesEnabled(false),设置Widget不刷新。
  3. 播放结束之后调用 widget->setUpdatesEnabled(true),设置Widget刷新。
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用Qt和OpenCV库来实现视频播放功能。首先,确保你已经正确安装了Qt和OpenCV,并在Qt项目中将OpenCV库链接到你的项目中。 接下来,创建一个Qt窗口应用程序,并添加一个QWidget或QLabel作为视频显示区域。在窗口类的头文件中,包含OpenCV库的头文件: ```cpp #include <opencv2/opencv.hpp> ``` 然后,在窗口类的源文件中,添加以下代码来实现视频播放功能: ```cpp // 1. 创建一个CvCapture对象来打开视频文件 cv::VideoCapture video("path/to/video/file"); // 2. 检查视频是否成功打开 if (!video.isOpened()) { // 处理打开失败的情况 return; } // 3. 创建一个定时器来定时获取视频QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, [=]() { // 4. 从视频中读取一帧 cv::Mat frame; video >> frame; // 5. 将帧转换为Qt图像格式 QImage image(frame.data, frame.cols, frame.rows, QImage::Format_RGB888); image = image.rgbSwapped(); // 颜色通道顺序转换 // 6. 在QWidget或QLabel上显示图像 // 如果使用QLabel,将图像设置为标签的图像 // label->setPixmap(QPixmap::fromImage(image)); // 如果使用QWidget,绘制图像到QWidget上 // 重写QWidget的paintEvent函数,类似下面的代码: /* void MyWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.drawImage(0, 0, image); } */ // 7. 检查视频是否播放完毕 if (frame.empty()) { // 处理视频结束的情况 timer->stop(); return; } }); // 8. 设置定时器的间隔时间(单位为毫秒) timer->start(33); // 每秒大约30帧 // 可以根据需要调整定时器的间隔时间,以平衡实时性和性能。 ``` 这是一个基本的Qt应用程序示例,用于打开并显示视频文件。你可以根据自己的需求进行进一步的定制和处理,比如添加控制按钮或处理视频帧的其他操作。记得将代码中的"path/to/video/file"替换为你要播放视频文件的路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值