ffmpeg+pyqt5简单实现一个抽帧可视化小工具

一、运行环境

        python3.6,linux18.04,pyqt5

二、主体代码

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file '/home/SENSETIME/wangwenjun1.vendor/PycharmProjects/pyqt/frame.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import os
import shutil
import time
from subprocess import PIPE, Popen
from uuid import uuid4
from multiprocessing import Queue


class Ui_MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super(Ui_MainWindow, self).__init__()
        self.setupUi(self)
        self.retranslateUi(self)

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(90, 20, 80, 23))
        self.pushButton.setObjectName("pushButton")
        self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
        self.progressBar.setGeometry(QtCore.QRect(530, 280, 221, 23))
        self.progressBar.setProperty("value", 0)
        self.progressBar.setObjectName("progressBar")
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(530, 240, 80, 23))
        self.pushButton_2.setObjectName("pushButton_2")
        self.listView_2 = QtWidgets.QListView(self.centralwidget)
        self.listView_2.setGeometry(QtCore.QRect(80, 80, 441, 201))
        self.listView_2.setObjectName("listView_2")
        self.listView = QtWidgets.QListView(self.centralwidget)
        self.listView.setGeometry(QtCore.QRect(80, 310, 441, 211))
        self.listView.setObjectName("listView")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(80, 60, 121, 16))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(80, 290, 211, 16))
        self.label_2.setObjectName("label_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 20))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.pushButton_2.clicked.connect(self.onStart)
        self.timer = QBasicTimer()
        self.step = 0
        self.failed_file = Queue()
        self.mp4_files = []
        self.target_folder = 'picture'
        self.finish_file = Queue()

        self.pushButton.clicked.connect(self.openfile)

        # 实例化列表模型,添加数据
        self.slm = QStringListModel()
        self.failed_slm = QStringListModel()

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "视频抽帧小工具"))
        self.pushButton.setText(_translate("MainWindow", "打开"))
        self.pushButton_2.setText(_translate("MainWindow", "开始"))
        self.label.setText(_translate("MainWindow", "总量"))
        self.label_2.setText(_translate("MainWindow", "失败: 0"))

    def openfile(self):
        openfile_name = QFileDialog.getOpenFileNames(self, '选择文件', '', 'Excel files(*.mp4)')
        self.mp4_files = list(self._filter_file(openfile_name[0]))
        self.target_folder = os.path.join(os.path.split(self.mp4_files[0])[0], self.target_folder)
        QMessageBox.warning(self, '保存路径', f'本次图片保存在{self.target_folder}, 默认会清理该路径,请及时转移文件!')
        try:
            shutil.rmtree(self.target_folder)
        except:
            pass
        print(f'total: {len(self.mp4_files)}')
        self.label.setText(f"总量: {len(self.mp4_files)}")
        # 设置模型列表视图,加载数据列表
        self.slm.setStringList(self.mp4_files)

        # 设置列表视图的模型
        self.listView_2.setModel(self.slm)

    def _filter_file(self, mp4_files):
        t_set = set()
        for filename in mp4_files:
            if os.path.isfile(filename):
                new_f = filename.replace(' ', '').replace('(', '').replace(')', '').strip()
                try:
                    os.rename(filename, new_f)
                except shutil.SameFileError:
                    print('no copy!')
                except:
                    import traceback
                    print(traceback.format_exc())
                if new_f in t_set:
                    continue
                t_set.add(new_f)
        return t_set

    def timerEvent(self, event):
        self.progressBar.setValue(self.finish_file.qsize() * 100 / len(self.mp4_files))
        self.label_2.setText(f"失败: {self.failed_file.qsize()}")
        # 设置模型列表视图,加载数据列表
        _t = []
        while not self.failed_file.empty():
            _t.append(self.failed_file.get())
        self.failed_slm.setStringList(_t)
        # 设置列表视图的模型
        self.listView.setModel(self.failed_slm)
        if self.finish_file.qsize() >= len(self.mp4_files):
            print(self.finish_file.qsize())
            self.timer.stop()
            self.pushButton_2.setText('Start')
            QMessageBox.information(self, '抽帧完成提醒', f'本次图片保存在{self.target_folder}')
            self.finish_file = Queue()
            self.failed_file = Queue()
            return

    def onStart(self):
        self.label.setText(f"总量: {len(self.mp4_files)}")
        if not len(self.mp4_files):
            QMessageBox.critical(self, '抽帧视频数错误', '总量数为0不可执行抽帧操作!')
            return
        if self.timer.isActive():
            self.proc.terminate()
            self.proc.join()
            self.timer.stop()
            self.mp4_files.clear()
            self.progressBar.setValue(0)
            self.label.setText(f"总量: {len(self.mp4_files)}")
            self.listView_2.setModel(self.slm.setStringList([]))
            self.listView.setModel(self.slm.setStringList([]))
            self.pushButton_2.setText('Start')
            self.finish_file = Queue()
            self.failed_file = Queue()
        else:
            self.timer.start(0, self)
            from multiprocessing import Process
            self.proc = Process(target=self.extract_frame_files, args=(self.mp4_files, self.finish_file, self.failed_file))
            self.proc.start()
            self.pushButton_2.setText('End')

    def extract_frame_files(self, files, finish_q, failed_q):
        for file in files:
            self.extract_frame(file, finish_q, failed_q)

    def extract_frame(self, file,  finish_q, failed_q):
        picture_id = str(uuid4())
        os.makedirs(self.target_folder, exist_ok=True)
        command = f"ffmpeg -i {file} -vf fps=2 {self.target_folder}/frame{picture_id}_xxx.png"
        command = command.replace('xxx', '%d')
        proc = Popen(command, shell=True,
                     stdout=PIPE,
                     stderr=PIPE)
        return_code = None
        while return_code is None:
            return_code = proc.poll()
            time.sleep(0.01)
        out, err = proc.communicate()
        proc.kill()
        finish_q.put(1)
        if return_code == 0:
            pass
        else:
            failed_q.put(1)
            print(f'[{file}]出错结束')
            print(f"err: \n{err}")


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

三、运行效果

        

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以使用PythonPyQt5来创建一个基于FFmpeg的视频播放器。下面是一个简单的示例代码: ```python import sys from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton from PyQt5.QtGui import QIcon from PyQt5.QtCore import Qt import subprocess class VideoPlayer(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle("Video Player") self.setGeometry(100, 100, 800, 600) # 创建一个垂直布局 layout = QVBoxLayout() # 创建一个播放按钮 play_button = QPushButton("Play") play_button.clicked.connect(self.playVideo) layout.addWidget(play_button) # 将布局设置为窗口的主布局 self.setLayout(layout) def playVideo(self): # 使用FFmpeg命令行播放视频 video_path = "path_to_video_file" # 替换为您自己的视频路径 command = ["ffmpeg", "-i", video_path, "-an", "-window_title", "Video Player", "-f", "sdl", "Video Player"] subprocess.call(command) if __name__ == "__main__": app = QApplication(sys.argv) player = VideoPlayer() player.show() sys.exit(app.exec_()) ``` 请将上述代码中的`"path_to_video_file"`替换为您自己的视频文件路径。运行代码后,将显示一个窗口,其中包含一个播放按钮。单击播放按钮将使用FFmpeg播放视频文件。 请注意,您需要安装FFmpeg并将其添加到系统路径中。此外,还需要安装PyQt5库。您可以使用以下命令来安装PyQt5: ``` pip install PyQt5 ``` 希望这可以帮助您开始创建一个基于FFmpeg的视频播放器!如有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值