jaseg / python-mpv

Python interface to the awesome mpv media player
https://git.jaseg.de/python-mpv.git
Other
547 stars 68 forks source link

Issues with seek command? #79

Closed sumdog closed 5 years ago

sumdog commented 5 years ago

I'm having trouble seeking in a video file. I don't see anything in the debugging output other than that -12 from mpv. Is the actual error a field of that MpvHandle object? I've tried using different data types for the seek amount (int(10), float, etc.) as well, but I still get this cryptic error.

I'm on mpv 0.29.1 / Python 3.6.5 / python-mpv 0.3.9

debug cplayer Run command: loadfile, flags=0, args=[file:///tmp/test.mp4, replace, ]
debug global config path: 'watch_later' -> '-'
info cplayer Playing: /tmp/test.mp4
v cplayer Running hook: ytdl_hook/on_load
v ytdl_hook ytdl:// hook
v ytdl_hook not a ytdl:// url
v ifo Opening /tmp/test.mp4
debug cplayer Run command: seek, flags=0, args=[10.000000, relative, unused]
v ifo_dvdnav Opening /tmp/test.mp4
Traceback (most recent call last):
  ...
  ...
    self.player.command('seek', '10')
  File "/home/cassius/.local/lib64/python3.6/site-packages/mpv.py", line 628, in command
    _mpv_command(self.handle, (c_char_p*len(args))(*args))
  File "/home/cassius/.local/lib64/python3.6/site-packages/mpv.py", line 102, in raise_for_ec
    raise ex(ec, *args)
SystemError: ('Error running mpv command', -12, (<MpvHandle object at 0x7fa17ee85bf8>, <mpv.c_char_p_Array_3 object at 0x7fa14c205620>))
fish: “python3 -m mpvbuddy” terminated by signal SIGABRT (Abort)
McSinyx commented 5 years ago

Could you provide how to reproduce the error, i.e. which method did you called? Since I see

debug cplayer Run command: loadfile, flags=0, args=[file:///tmp/test.mp4, replace, ]
...
fish: “python3 -m mpvbuddy” terminated by signal SIGABRT (Abort)

BTW have a merry Christmas or other holiday of your choice! I still go to school today though :vietnam:

sumdog commented 5 years ago

Merry Christmas. Thanks for your help. Here's a script that I can use to reproduce the problem (hard coded path to /tmp/test.mp4). I tried to dig into raise_for_ec to add some print statements around the raised error, but I can't figure out how to get a string out of c_char_p_Array_3. I tried both player.seek and player.command('seek'.. but both seemed to produce the same error. The PyQt5 version is 5.10.1, in case that matters.

#!/usr/bin/env python3
import mpv
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys

class MPVWindow(QMainWindow):

    def __init__(self):
        super().__init__(None)

        self.container = QWidget(self)
        self.setCentralWidget(self.container)
        self.container.setAttribute(Qt.WA_DontCreateNativeAncestors)
        self.container.setAttribute(Qt.WA_NativeWindow)
        self.setWindowFlags(Qt.CustomizeWindowHint | Qt.FramelessWindowHint)
        self.player = mpv.MPV(wid=str(int(self.container.winId())),
                              # vo='x11', # You may not need this
                              log_handler=print,
                              loglevel='debug',
                              input_default_bindings=False,
                              input_vo_keyboard=False)
        self.player.observe_property('time-pos', self.time_observer)
        self.player.observe_property('fullscreen', self.fullscreen_observer)
        self.player.register_key_binding('WHEEL_UP', 'osd-msg-bar add volume 2')
        self.player.register_key_binding('WHEEL_DOWN', 'osd-msg-bar add volume -2')
        self.player.register_key_binding('MBTN9', 'seek 10')
        self.player.register_key_binding('MBTN10', 'seek -10')
        self.player.register_key_binding('MBTN_MID', 'show-progress')
        self.player.register_key_binding('MBTN_LEFT_DBL', 'cycle fullscreen')
        self.player.register_key_binding('MBTN_RIGHT', 'osd-msg-bar cycle pause')
        self.player.register_key_binding('MBTN_BACK', 'script-message extpl-back')
        self.player.register_key_binding('MBTN_FORWARD', 'script-message extpl-forward')

    def play(self, video_file, seek):
        self.player.play(video_file)
        print(seek)
        self.player.command('seek', '10')
        # this doesn't work either
        #self.player.seek(10)

    def fullscreen_observer(self, _name, value):
        if value:
            self.showFullScreen()
        else:
            self.showNormal()

    def time_observer(self, name, value):
        pass

if __name__ == '__main__':
    app = QApplication(sys.argv)

    # This is necessary since PyQT stomps over the locale settings needed by libmpv.
    # This needs to happen after importing PyQT before creating the first mpv.MPV instance.
    import locale
    locale.setlocale(locale.LC_NUMERIC, 'C')

    player = MPVWindow()
    player.play('/tmp/test.mp4', 10)
    player.show()

    sys.exit(app.exec_())

and the error/trace:

debug cplayer Run command: enable-section, flags=0, args=[py_kb_0d2e4bfcd0ea6b26, allow-hide-cursor+allow-vo-dragging]
Traceback (most recent call last):
  File "bug.py", line 61, in <module>
debug cplayer Run command: define-section, flags=0, args=[py_kb_9c129fbc9ff3d595, MBTN_FORWARD script-message extpl-forward, force]
    player.play('/tmp/test.mp4', 10)
debug cplayer Run command: enable-section, flags=0, args=[py_kb_9c129fbc9ff3d595, allow-hide-cursor+allow-vo-dragging]
  File "bug.py", line 39, in play
debug cplayer Run command: loadfile, flags=0, args=[/tmp/test.mp4, replace, ]
debug global config path: 'watch_later' -> '-'
info cplayer Playing: /tmp/test.mp4
    self.player.command('seek', '10')
  File "/home/cassius/.local/lib64/python3.6/site-packages/mpv.py", line 628, in command
v cplayer Running hook: ytdl_hook/on_load
v ytdl_hook ytdl:// hook
v ytdl_hook not a ytdl:// url
v ifo Opening /tmp/test.mp4
    _mpv_command(self.handle, (c_char_p*len(args))(*args))
debug cplayer Run command: seek, flags=0, args=[10.000000, relative, unused]
  File "/home/cassius/.local/lib64/python3.6/site-packages/mpv.py", line 102, in raise_for_ec
v ifo_dvdnav Opening /tmp/test.mp4
v file Opening /tmp/test.mp4
debug file Stream opened successfully.
v demux Trying demuxers for level=normal.
    raise ex(ec, *args)
debug demux Trying demuxer: disc (force-level: normal)
SystemError: ('Error running mpv command', -12, (<MpvHandle object at 0x7f2ba5719e18>, <mpv.c_char_p_Array_3 object at 0x7f2b76dc49d8>))
Fatal Python error: could not acquire lock for <_io.BufferedWriter name='<stdout>'> at interpreter shutdown, possibly due to daemon threads

Thread 0x00007f2b15ffb700 (most recent call first):
  File "/home/cassius/.local/lib64/python3.6/site-packages/mpv.py", line 469 in _event_loop
  File "/usr/lib64/python3.6/threading.py", line 864 in run
  File "/usr/lib64/python3.6/threading.py", line 916 in _bootstrap_inner
  File "/usr/lib64/python3.6/threading.py", line 884 in _bootstrap

Current thread 0x00007f2ba5779540 (most recent call first):
fish: “python3 bug.py” terminated by signal SIGABRT (Abort)
sumdog commented 5 years ago

Here's a more basic example, so it seems unrelated to any of the GUI stuff. I was able to print out that c_char_p_Array_5 and it's just the commands/arguments in an array. I'm not sure why mpv is sending a -12 without any additional error message. Does this work on your machine? Maybe it's a change in the mpv API.

#!/usr/bin/env python3

import mpv

player = mpv.MPV()
player.play('/tmp/test.mp4')
player.seek(10)
Traceback (most recent call last):
  File "/tmp/min.py", line 7, in <module>
    player.seek(10)
  File "/home/cassius/.local/lib64/python3.6/site-packages/mpv.py", line 641, in seek
    self.command('seek', amount, reference, precision)
  File "/home/cassius/.local/lib64/python3.6/site-packages/mpv.py", line 628, in command
    _mpv_command(self.handle, (c_char_p*len(args))(*args))
  File "/home/cassius/.local/lib64/python3.6/site-packages/mpv.py", line 102, in raise_for_ec
    raise ex(ec, *args)
SystemError: ('Error running mpv command', -12, (<MpvHandle object at 0x7f8ffb393e18>, <mpv.c_char_p_Array_5 object at 0x7f8ff15d3950>))
jaseg commented 5 years ago

I haven't fully validated this yet, but I think the issue might be that you try to seek right after calling MPV.play, without waiting for the file to be loaded and playback to start. IIRC libmpv doesn't like that. The following three lines between play and seek might do the trick:

import time
while self.player.core_idle:
    time.sleep(0.05)
jaseg commented 5 years ago

The abort you get is probably due to some interaction between libmpv, qt and python. I wouldn't look into that too closely before fixing the -12 error.

The problem might be that a reference to the mpv object is leaked in the exception object, leading to the mpv object's daemon thread still lingering around after sys.exit is called, interfering with python's shutdown.

sumdog commented 5 years ago

Argg!! I ran into this exact problem years ago and saw in my old source code I waited for the file-loaded event :sweat_smile:

There's a seekable property that's probably the best thing to wait for. The following works:

player.play(video_file)
player.wait_for_property('seekable')
player.seek(seek, reference='absolute', precision='exact')

Thanks for your help.