PyQt QMediaPlayer setPosition membulatkan nilai posisi

Saya memiliki aplikasi yang dirancang untuk membantu menyinkronkan video eksperimen dan sinyal data. Aplikasi ini memiliki widget video dan penggeser yang dapat mengatur posisi temporal video. Namun, QMediaPlayer hanya akan mengatur posisi pada interval 500mSec/1000mSec (di aplikasi saya 500mSec/di aplikasi yang dibuat 1000mSec) sementara video diambil pada 50fps yang menyiratkan interval 20mSec. Ini membuat sinkronisasi menjadi tidak berguna. Saya telah menambahkan output posisi sebelum dan sesudah perubahan posisi.

Bantuan apa pun akan dihargai.

Berikut output saat mengganti slider:

New slider position 326
Media player updated position 0
New slider position 816
Media player updated position 0
New slider position 1306
Media player updated position 0
New slider position 1632
Media player updated position 1000
New slider position 1959
Media player updated position 1000
New slider position 2449
Media player updated position 2000
New slider position 2938
Media player updated position 2000
New slider position 3428
Media player updated position 2000
New slider position 3755
Media player updated position 3000
New slider position 4081
Media player updated position 3000
New slider position 4571
Media player updated position 4000
New slider position 4897
Media player updated position 4000
New slider position 5224
Media player updated position 4000
New slider position 5550
Media player updated position 5000
New slider position 5714
Media player updated position 5000
New slider position 6040
Media player updated position 5000
New slider position 6203
Media player updated position 6000
New slider position 6530

Saya juga mencoba mengatur posisi tertentu yang saya ambil dari mediaPlayer.position() tetapi tidak berhasil.

Berikut adalah aplikasi yang dibikin:

import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QSize, Qt, QUrl
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import QMainWindow, QLabel, QWidget, QSlider
from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout

#
# Reference https://pythonprogramminglanguage.com/pyqt5-video-widget/
#
class MainWindow (QMainWindow):
    def __init__ (self, parent=None):
        super (QMainWindow, self).__init__ (parent)

        #
        # Set the filename here
        #
        filename = '/Users/yuval/src/lab/S4560001.MP4'

        self.setMinimumSize (QSize (640, 480))
        self.setWindowTitle ('Video & Data Viewer and Annotator')

        self.mediaPlayer = QMediaPlayer (None, QMediaPlayer.VideoSurface)
        videoWidget = QVideoWidget ()
        videoWidget.setMinimumSize (640,200)

        #
        # Position Slider
        #
        self.positionSlider = QSlider (Qt.Horizontal)
        self.positionSlider.setRange (0, 0)
        self.positionSlider.sliderMoved.connect (self.setPosition)

        #
        # Position Label
        #
        self.positionLabel = QLabel ('00:00:000')

        centralWidget = QWidget (self)
        self.setCentralWidget (centralWidget)

        #
        # Layout the Control Widgets
        #
        ctlLayout = QHBoxLayout ()
        ctlLayout.setContentsMargins (0, 0, 0, 0)
        ctlLayout.addWidget (self.positionSlider)
        ctlLayout.addWidget (self.positionLabel)

        #
        # Layout the Window
        #
        layout = QVBoxLayout ()
        layout.addWidget (videoWidget)
        layout.addLayout (ctlLayout)

        centralWidget.setLayout (layout)

        self.mediaPlayer.setVideoOutput (videoWidget)
        self.mediaPlayer.positionChanged.connect (self.positionChanged)
        self.mediaPlayer.durationChanged.connect (self.durationChanged)
        self.mediaPlayer.error.connect (self.handleError)
        self.mediaPlayer.setNotifyInterval (100)
        self.mediaPlayer.setMuted (True)

        print (filename)

        if filename != '':
            self.mediaPlayer.setMedia (
                QMediaContent (QUrl.fromLocalFile (filename)))

    def positionChanged (self, position):
        self.positionSlider.setValue (position)

    def durationChanged (self, duration):
        self.positionSlider.setRange (0, duration)

    def setPosition (self, position):
        print (f'New slider position {position}')
        self.mediaPlayer.setPosition (position)
        print (f'Media player updated position {self.mediaPlayer.position ()}')

    def handleError (self):
        print ('Error: ' + self.mediaPlayer.errorString ())

if __name__ == '__main__':
    app = QtWidgets.QApplication (sys.argv)
    mainWin = MainWindow ()
    mainWin.show ()
    sys.exit (app.exec_ ())

Saya menjalankan MacOS 10.14.16 (Mojave).

Python 3.7.4

Paket Python: PyQt5==5.13.0 PyQt5-sip==4.19.18

Paket port: py37-pyqt5 @5.12.2_0 (aktif) qt5 @5.12.4_0 (aktif)


person YuvGM    schedule 11.09.2019    source sumber


Jawaban (1)


Menemukan jawabannya. Masalahnya ada di Qt5 dan mereka "mengklaim" itu bukan bug, dan sepertinya tidak ada rencana untuk memperbaikinya. Ini khusus untuk MacOS dan berfungsi dengan baik di Windows (dan saya curiga Linux). Soalnya Qt5 menggunakan API MacOS yang memiliki toleransi waktu. Secara default, ini hanya akan menggunakan "keyframe" sementara toleransinya dapat dibatasi. Qt5 tidak menentukan toleransi sehingga menyesuaikan waktu dengan keyframe.

Jika ada orang di tim pengembangan MacOS Qt5, alangkah baiknya jika Anda bisa memperbaikinya. Dan ya, jika saya memiliki lingkungan pengembangan, saya akan memperbaikinya sendiri (tetapi saya mungkin akan ditolak).

Lihat (dari 2015) https://bugreports.qt.io/browse/QTBUG-49609?jql=project%20%3D%20QTBUG%20AND%20solving%20%3D%20Unresolved%20AND%20text%20~%20%22qmediaplayer%22%20ORDER%20BY%20priority%20DESC%2C%20updated%20DESC

API MacOS/AVFoundation adalah https://developer.apple.com/documentation/avfoundation/avplayeritem/1387418-seek

person YuvGM    schedule 16.09.2019
comment
Anda dapat mengatasinya dengan menyandikan video dengan lebih sedikit B-frame dan P-frame. Yaitu, gunakan lebih banyak I-frame. Terutama tidak jelas jika Anda tidak bisa mencari B-frame. Jauh lebih mudah untuk mencari P-frame; memorinya juga lebih sedikit untuk pemutaran tetapi ukuran file bertambah. - person artless noise; 29.03.2020