一、运行环境
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_())
三、运行效果
