python - 话题成员“分享”
问题描述
背景和问题:
我正在尝试创建一个自定义程序来编辑视频上的“事物”。为此,我希望能够使用时间滑块在视频中导航。从 Internet 上的大量资源中获得灵感,我编写了下面的代码,它非常适合简单阅读。但是当我使用滑块更改视频当前时间时,有时它会崩溃。
研究与测试:
我知道它来自线程中的视频读取处理程序,主读取进程(run()函数)和我的自定义函数同时使用它来更改视频时间位置。我尝试了不同的方法,例如添加自动将视频设置为“暂停”状态、添加“is_reading 位”或“正在阅读时等待”,但它永远不会结束,或者仍然崩溃
这是一个工作(并且崩溃!)的简化代码示例
有没有比我有更多线程经验的人可以引导我使用线程来解决我的并发/不共享成员问题?
#!/usr/bin/python
# coding: utf-8
import cv2
import sys
from PyQt5.QtWidgets import QWidget, QLabel, QApplication, QPushButton, QSlider, QHBoxLayout, QVBoxLayout
from PyQt5.QtCore import QThread, Qt, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QImage, QPixmap
import time
class Thread(QThread):
changePixmap = pyqtSignal(QImage)
# reading lock bit
is_reading_handler = False
# Play / pause status bit
is_pause = False
# vidéo frame rate
fps = 50.0
# current frame video index
current_frame_index = 0
# screen time by image
image_duration_ns = 1000000000.0/50.0
# method to change the play/pause status
def swapPlayPause(self):
if self.is_pause:
self.is_pause = False
print("Play")
else:
self.is_pause = True
print("Pause")
# method to change de current time video position
def changeVideoPosition(self, value):
# self.is_pause = True # <- test
self.current_frame_index = int(self.frames_count*value*0.001)
self.video_handler.set(cv2.CAP_PROP_POS_FRAMES, self.current_frame_index)
# self.read()
def run(self):
# Open video handler
self.video_handler = cv2.VideoCapture("video_source/GOPR0483.MP4")
# GET VIDEO INFORMATIONS
# Find OpenCV version
(major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')
if int(major_ver) < 3 :
fps = self.video_handler.get(cv2.cv.CV_CAP_PROP_FPS)
print("Frames per second using video.get(cv2.cv.CV_CAP_PROP_FPS): {0}".format(fps))
else :
fps = self.video_handler.get(cv2.CAP_PROP_FPS)
print("Frames per second using video.get(cv2.CAP_PROP_FPS) : {0}".format(fps))
width = self.video_handler.get(cv2.CAP_PROP_FRAME_WIDTH)
height = self.video_handler.get(cv2.CAP_PROP_FRAME_HEIGHT)
self.width = 640
self.height = 480
self.frames_count = self.video_handler.get(cv2.CAP_PROP_FRAME_COUNT)
print("frames count = {0}".format(self.frames_count))
duration = self.frames_count / fps
print("duration in s {0}".format(duration))
# "Read" video
time_last = 0
# image screen time
self.image_duration_ns = 1000000000/fps
while True:
if not self.is_pause:
# new image if the current one is expired
time_cur = time.time_ns()
if time_cur-time_last > self.image_duration_ns:
# read the new image
self.read()
time_last = time_cur
def read(self):
# if the reading handler is already used, wait a litle bit before to read
if self.is_reading_handler:
time.sleep(0.01)
# This "while" does not work because the self.is_reading_heandler does not seems to be share with the run() member !?
# while self.is_reading_handler:
# time.sleep(0.01)
# lock the reading handler
self.is_reading_handler = True
# read the image
ret, frame = self.video_handler.read()
if ret:
# https://stackoverflow.com/a/55468544/6622587
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = rgbImage.shape
bytesPerLine = ch * w
convertToQtFormat = QImage(rgbImage.data, w, h, bytesPerLine, QImage.Format_RGB888)
p = convertToQtFormat.scaled(self.width, self.height, Qt.KeepAspectRatio)
self.changePixmap.emit(p)
self.current_frame_index += 1
# release read handler
self.is_reading_handler = False
class App(QWidget):
def __init__(self):
super().__init__()
self.title = "test"
self.initUI()
@pyqtSlot(QImage)
def setImage(self, image):
self.video.setPixmap(QPixmap.fromImage(image))
def initUI(self):
self.setWindowTitle(self.title)
# QT object for the video
self.video = QLabel(self)
self.video.resize(self.width(), self.height())
# video read thread
self.th = Thread(self)
self.th.changePixmap.connect(self.setImage)
# BT play pause
self.bt_pp = QPushButton('P/P', self)
self.bt_pp.clicked.connect(self.th.swapPlayPause)
# video time slider
self.sl_time = QSlider(Qt.Horizontal, self)
self.sl_time.setGeometry(10, 100, 400, 40)
self.sl_time.setMinimum(0)
self.sl_time.setMaximum(1000)
self.time_slide_value = 0
self.sl_time.setValue(self.time_slide_value)
self.sl_time.valueChanged.connect(self.th.changeVideoPosition)
# simple vert layout
self.ly_all = QVBoxLayout()
self.ly_all.addWidget(self.video)
self.ly_all.addWidget(self.sl_time)
self.ly_all.addWidget(self.bt_pp)
self.setLayout(self.ly_all)
# here we go !
self.th.start()
self.show()
# instanciation
app = QApplication(sys.argv)
window = App()
app.exec_()
解决方案
推荐阅读
- python - Azure Pipelines - 在 Python 脚本中使用 System.AccessToken
- java - 在没有合适的 MacOS 机器的情况下针对 MacOS Big Sur 进行测试
- reactjs - Django + ReactJS。Httponly cookie 没有保存在 React 端的浏览器中。我还在两边都给了 {withcredentials : true}
- ios - 拒绝来电推送后无法处理取消VOIP推送
- node.js - 无法加载源的服务索引:UrlBlockedExtended
- firebase - 我如何复合 postUid 和 Userid
- html - Fullcalendar v5 粘性标题与 Bootstrap 固定顶部导航相结合
- swift - SwiftLint“排除”不适用于一个文件夹
- angular - Angular & Jest:为什么订阅块在 ngOnInit 中运行?
- python-3.x - 删除字符串末尾的逗号