pyQT 视频播放器(三) 实现视频截图、获取每一帧数据

  • 背景
  • 方法调研
    • 详细代码说明
    • 最终效果
      • 总结:
      • 参考资料

背景

在 “PyQt5 实现视频播放器(二) ,详细版本 ,适合新手入门“
中已经想写的介绍了如何使用pyQT 自带的一些控件,实现简单的视频播放功能(例如播放、暂停、进度条跳转、声音控制、全屏播放等),通过评论区的交流,发现大家除了这些简单功能外,还有一个比较强烈的需求就是视频截图,所以下面就来实现一下视频截图功能

方法调研

在方法调研的前分享一下自己在遇到一个新问题的时候的“搜索方法”,希望能够起到抛砖引玉的作用。(有了正确的搜索方式,对于开发能少走弯路,提高效率)

  1. 问题定义:这一步也容易也难,特别是工作之后会有更加深刻的体验,简单来说就是如何将你的需求/问题与实际程序实现逻辑进行对应,比如说想实现视频进度条展示,那么对应到具体的pyqt的开发中可能就是,如何使用qt的slider来展示qmediaplayer 播放的媒体进度。这就要求你能对需求/问题进行分解、对使用的程序逻辑/程序组件功能有充分的了解。有点啰嗦了,回归正题,问题定义为:
    qt实现视频截图”、如何获取qt视频播放中的每一帧数据、“qt mediaplayer 截图 ”,
    会用英文更好: get frame data using QMediaPlayer
  2. 搜索: pyQT作为QT的一个python版本接口使用方式,整体的资料虽然不如QT的多,但是QT的使用方式都能够在pyQT上使用,因此我在搜索的时候基本上都是不区分pyqt和QT的,比如这次搜索的时候就是查询qt 如何获取,参考的代码也都是QT的源码,改成python的时候只需要注意import 的位置、以及c++写法到python写法的切换即可。
  3. 筛选:搜索到的方案比较多,大致可以归纳为如下几种:
    (1)使用“截屏”的方式来完成截图,我稍微尝试了一下发现对于qmediaplayer输出的widget无法截取到画面图像,另外即使截取到了也只是UI界面上大小原始原始图像的大小,因此放弃这个方案
    (2)qt + ffmpeg或qt + vlc或qt+ opencv 等进行视频解码播放,功能强大,能够比较方便的进行功能较复杂的图像处理需求,例如使用opencv可以对图像进行复杂的操作(识别、检测、画框)
    (3)QMediaPlayer + QAbstractVideoSurface,比较方便,转换的是QImage,可以获取每一帧数据。
    方案筛选上,由于我们只需要完成截图功能,而且之前用的就是Qmediaplayer,选方案二,能够最快速的实现这个功能。

详细代码说明

采用 QMediaPlayer + QAbstractVideoSurface 这个方案重点需要了解一下QAbstractVideoSurface 这个类,结合查询到的资料以及Assistant中的说明:QAbstractVideoSurface class is a base class for video presentation surfaces.
其中 [pure virtual] 的有两个函数:
(1)supportedPixelFormats() # 支持的视频解码后的数据格式
(2)present(const QVideoFrame &frame) # 获取视频解码的数据frame,进行展示
因此我们只需要新写一个类,继承这个抽象的QAbstractVideoSurface 类,然后重写里面的这个两个纯虚函方法,就能从present 输入的Frame中获取每一帧的数据。
如下:

from PyQt5.QtMultimedia import QAbstractVideoSurface, QVideoFrame, QAbstractVideoBuffer
from PyQt5.QtCore import pyqtSignal, QDateTime
from PyQt5.QtGui import QImage
class myVideoSurface(QAbstractVideoSurface):FinishGrab = pyqtSignal()  # 截图完成信号def __init__(self, parent=None):super(QAbstractVideoSurface, self).__init__(parent)def supportedPixelFormats(self, type=None):support_format = [QVideoFrame.Format_ARGB32,QVideoFrame.Format_ARGB32_Premultiplied,QVideoFrame.Format_ARGB8565_Premultiplied,QVideoFrame.Format_AYUV444,QVideoFrame.Format_AYUV444_Premultiplied,QVideoFrame.Format_BGR24,QVideoFrame.Format_BGR32,QVideoFrame.Format_BGR555,QVideoFrame.Format_BGR565,QVideoFrame.Format_BGRA32,QVideoFrame.Format_BGRA32_Premultiplied,QVideoFrame.Format_BGRA5658_Premultiplied,QVideoFrame.Format_CameraRaw,QVideoFrame.Format_IMC1,QVideoFrame.Format_IMC2,QVideoFrame.Format_IMC3,QVideoFrame.Format_IMC4,QVideoFrame.Format_Jpeg,QVideoFrame.Format_NV12,QVideoFrame.Format_NV21,QVideoFrame.Format_RGB24,QVideoFrame.Format_RGB32,QVideoFrame.Format_RGB555,QVideoFrame.Format_RGB565,QVideoFrame.Format_User,QVideoFrame.Format_UYVY,QVideoFrame.Format_Y16,QVideoFrame.Format_Y8 ,QVideoFrame.Format_YUV420P,QVideoFrame.Format_YUV444,QVideoFrame.Format_YUYV,QVideoFrame.Format_YV12,]return support_formatdef present(self, frame: 'QVideoFrame'):print("width:{},heigth:{},format:{},start_time:{},endtime{}".format(frame.width(), frame.height(), frame.pixelFormat(), frame.startTime(), frame.endTime()))if frame.isValid():frame.map(QAbstractVideoBuffer.ReadOnly)img = QImage(frame.bits(), frame.width(), frame.height(),QVideoFrame.imageFormatFromPixelFormat(frame .pixelFormat()))grab_jpg = './'+QDateTime.currentDateTime().toString("yyyy-MM-dd hh-mm-ss-zzz")+'.jpg'save_state = img.save(grab_jpg)print("截图状态:"+str(save_state))frame.unmap()self.FinishGrab.emit()return Trueelse:return False

其中 supportedPixelFormats 中的支持的格式只要后面present中能够支持即可,由于我们并不是真的展示,在present中只是转成了QImage,然后完成截图。在这里有两种方案:
(1)使用present中每一帧数据进行展示(这里已经转成QImage图像数据了,接着想怎么画图都可以,然后图像展示就可以),这个方案的话就是图像转换比较耗时,可能会影响到播放的流畅度,如果不是每一帧图像都需要处理的话,不建议用这种方式
(2)播放然后采用“PyQt5 实现视频播放器(二) ,详细版本 ,适合新手入门“
中介绍的widget进行播放,只有需要截图的将player的输出切换到videosurface进行截图,截完图在切换回去,这种方式播放就是在截图的时候由于切换了player的输出因此会导致截图的时候视频界面会就“黑“一下(此时没有输出),
这里考虑到截图功能不是每一帧都需要截(由界面上得按钮触发),因此采用了方案(2)

最终效果

首先在原先 “PyQt5 实现视频播放器(二) ,详细版本 ,适合新手入门“中的界面基础上增加了一个截图按钮:

在视频播放的时候,点击截图按钮,会自动截取当前时刻的图片,由于只是demo(抛砖引玉的作用),因此图片会保存到demo所在的当前目录下面(保存的代码在present函数中):

某张具体的截图如下:(获取到720x480的原始尺寸大小)

总结:

(1)基本完成视频截图的功能,如果需要复杂的功能可以在这个上面继续扩展(例如截图的列表展示、截图的帧号等)
(2)截图的时候已经能够获取每一帧的数据,那么对应的“画框”、图像检测、分类等等都可以在这个上面进行扩展
(3)完整的演示demo 已经打包上传到csdn上:
[https://download.csdn.net/download/u012552296/84553765](demo中有视频和解码器,可以完整运行完整个demo,windows10 环境验证正常)(https://download.csdn.net/download/u012552296/84553765)
[https://download.csdn.net/download/u012552296/16184221] (https://download.csdn.net/download/u012552296/16184221)

参考资料

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
[1]How to save a frame using QMediaPlayer?
https://stackoverflow.com/questions/37724602/how-to-save-a-frame-using-qmediaplayer
[1]原来Qt从视频中获取每一帧数据如此简单: https://blog.csdn.net/jxbinwd/article/details/81034339

pyQT 视频播放器(三) 实现视频截图、获取每一帧数据相关推荐

  1. Qt从视频中获取每一帧数据

    参考了以下文章:https://blog.csdn.net/jxbinwd/article/details/81034339 我按照上面文章的描述写程序,解析出来的图像保存成图片.保存的图片有很多乱码 ...

  2. Android FFmpeg视频播放器三 音频封装格式解码播放

    Android FFmpeg视频播放器一解封装 Android Android FFmpeg视频播放器二 视频封装格式解码播放 视频解封装之后就会得到音频流和视频流,解封状得到的数据是AVPackag ...

  3. 安卓开发本地视频播放器——扫描本地视频文件显示在gridview上,然后点击播放。

    本文将引导大家做一个本地视频播放器,希望能帮到有需要的朋友. 直接上代码: 下面这是获取扫描视频的代码. package com.mediaplayer.utils;import java.util. ...

  4. android电商评论,三步教你获取电商评论数据

    现在的电商平台的商品琳琅满目,咱们足不出户就可以淘到性价比很好的尖货.但是东西多了大家不免要比较一番,这个时候看看商品粉丝的评论就尤其重要. 接下来一步步给大家介绍怎样获取评论的数据来供我们分析,以天 ...

  5. H.264裸流文件中获取每一帧数据

    测试解码器性能时,最常用的无非是向解码器中推送码流. 之前封装了一个avc的解码器,想做一个测试,读取H.264裸流文件将码流定期定时推送到解码器. 测试其实很简单: 1.了解H.264裸流文件的构成 ...

  6. android videoview截屏,如何进行网络视频截图/获取视频的缩略图

    小编导读:获取视频的缩略图,截图正在播放的视频某一帧,是在音视频开发中,常遇到的问题.本文是主要用于点播中截图视频,同时还可以获取点播视频的缩略图进行显示,留下一个问题,如下图所示,如果要获取直播中节 ...

  7. C++ Qt高仿QQ影音视频播放器 (三)

      本篇介绍中间视频播放控件的实现.   主要涉及到3个控件:打开文件按钮.右侧打开文件列表按钮.播放时间进度条按钮.播放效果如下:   正常播放时,时间进度条只有在鼠标悬浮到视频区域时才显示. 打开 ...

  8. vue 视频截图获取第一帧或者某一帧

    id:传入的video容器id,imgType:截图文件的类型. const screenshot = (id, imgType)=>{const video = document.getEle ...

  9. android 暂停函数,Android万能视频播放器06-添加视频暂停、播放和Seek功能

    1.Seek函数: avformat_seek_file(pFormatCtx, -1, INT64_MIN, relsecds, INT64_MAX, 0); relsecds单位: int64_t ...

最新文章

  1. 用户操作拦截并作日志记录--自定义注解+AOP拦截
  2. 年结 利润分配-未分配利润年结
  3. KDD2021 放榜,6 篇论文带你了解阿里妈妈AI技术
  4. 用9种办法解决 JS 闭包经典面试题之 for 循环取 i
  5. SQLi LABS Less-22
  6. php array_diff 用法
  7. window版GitHub使用
  8. matlab位图矢量化,matlab图形矢量化解决方案
  9. SpringBoot整合定时任务(在线Cron表达式生成器)
  10. 西门子G120变频器常用参数(自己总结的)
  11. 怎么利用企业微信营销 企业微信如何营销 企业微信如何维护好友 企业微信如何开通
  12. 让你嘿嘿嘿!最新windows7升级win10方法!
  13. 百度paddlepaddle入门讲解第一周内容
  14. 铝电解电容器在电路设计时的使用注意事项
  15. matlab 实验七 低层绘图操作,matlab实验内容答案
  16. 【Web动画】CSS3 3D 行星运转 浏览器渲染原理
  17. python骚操作!WiFi密码还能这样获取?用户扫一扫连接,无需输入密码
  18. 全球与中国车载称重系统市场现状及未来发展趋势
  19. C++围棋小游戏1.2.2
  20. 教你一招,能解决90%的机房问题

热门文章

  1. 信用卡商户mcc代码
  2. python 小学数学_python解越南逆天小学数学题
  3. 2019广州编程挑战赛_中学组
  4. ARM SWI软中断
  5. Windows下并发地画圆和画方
  6. 《没想到吧》杨迪模仿TFBOYS三小只 池子成“快乐喷泉”
  7. 1-3-06:甲流疫情死亡率
  8. 从零认识dB和dBm以及dBi、dBd、dBc和dBV
  9. 圣诞海报设计背景,开始准备
  10. 写给1987—1990年出生的同学,生活在80后和90后夹缝中的一代