jaseg / python-mpv

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

Command Questions and Additional Documentation #140

Closed CalculusAce closed 3 years ago

CalculusAce commented 3 years ago

I just recently started using python-mpv on Windows, and I'm running to the same issues with using the default MPV key bindings with the Qt implementation as mentioned by another Windows user in the issues thread. As a result, I have been working on creating custom key bindings from within Qt to control various aspects of media playback. I have been able to successfully setup keyboard shortcuts to play media, toggle pausing playback, and seeking at a specific time interval so far.

That being said, I have been unable to figure out what the options for the reference argument are for seek for example. I've seen that the default is relative, but what if I'd like to seek back to a specific time step relative to time 0 or the end of a video rather than having it relative to whatever time I am currently at during playback for example. Rewinding is another thing I've been trying to figure out.

Toggling subtitles on and off during playback is another command I've been struggling to find (assuming the subtitle file is muxed within a mkv file or an external subtitle file). Seeking to a specific subtitle ID and controlling the start and stop times of media playback are also of interest.

Lastly, I wanted to see if there's another documentation source for this module or mpv itself that outlines how to implement some of these more nuanced commands in greater detail?

Thanks again for creating this great module!

jaseg commented 3 years ago

Hey there,

That being said, I have been unable to figure out what the options for the reference argument are for seek for example. I've seen that the default is relative, but what if I'd like to seek back to a specific time step relative to time 0 or the end of a video rather than having it relative to whatever time I am currently at during playback for example. Rewinding is another thing I've been trying to figure out.

So you want seek to "snap" to a global interval, e.g. 0s, 5s, 10s, 15s, ... into the file instead of -15s, -10s, -5s, +5s, +10s, ...?

Reading the man page it does not seem like mpv supports this right now. You can open a feature request with mpv, but since you're using python-mpv anyway you can emulate this behavior in python fairly easily:

#!/usr/bin/env python3
import sys
import math

import mpv

player = mpv.MPV(log_handler=print, loglevel='info', osd_level=2)

player.play('test.mp4')
@player.on_key_press('LEFT')
def seek_backwards():
    seek(-5)

@player.on_key_press('RIGHT')
def seek_forward():
    seek(5)

def seek(interval:'seconds', tolerance:'seconds'=1.0):
    timestamp = player.time_pos
    time_now_rounded = math.ceil(timestamp/interval) * interval
    if abs(timestamp - time_now_rounded) > tolerance:
        player.seek(time_now_rounded, reference='absolute')
        print(f'{timestamp} {time_now_rounded} {abs(timestamp - time_now_rounded)} short-circuit')

    else:
        # don't clip to player.duration as that might not always be known and precise
        player.seek(max(0, time_now_rounded + interval), reference='absolute')
        print(f'{timestamp} {time_now_rounded} {abs(timestamp - time_now_rounded)} {max(0, time_now_rounded + interval)}')

player.wait_until_playing()
player.wait_for_playback()
sys.exit(0)

Rewinding is another thing I've been trying to figure out.

Do you mean the "playing the video in reverse" effect like VCRs used to do, as opposed to the "jump to target frame" that seek does? In that case, see upstream issue #4000. Reverse playback is unsupported because it is incompatible with the way video encodings work.

Toggling subtitles on and off during playback is another command I've been struggling to find (assuming the subtitle file is muxed within a mkv file or an external subtitle file).

Subtitle visibility can be controlled using the player.sub_visibility = True | False property. A good reference here is the default input.conf. The subtitle track can be selected using the player.sid property-mapped option as described in the man page.

Playback start time can be set using the --start option: Either during construction as in MPV(..., start=...) or when loading the file using player.loadfile(..., start=...) instead of the player.play convenience method. Playback stop time should be --end I think.

You can add external subtitle files during playback using the sub_add command, see #119 for an example.

Lastly, I wanted to see if there's another documentation source for this module or mpv itself that outlines how to implement some of these more nuanced commands in greater detail?

The official upstream reference is the man page, https://mpv.io/manual/master/

Alas, not everything is documented there in detail. I have had to resort to reading mpv's source to find out details. options.c and command.c are good starting points here.

The mpv fellows are nice people, and if you find out something that is not documented in the man page I am sure they'd love a pull request against the DOCS tree on the mpv repo that the man page is generated from.

CalculusAce commented 3 years ago

@jaseg Thank you for taking the time to provide such detailed answers to my questions. That was very helpful. I have since been able to implement the majority of the commands I have been looking for using Qt hotkeys.

The only other command I am looking to implement involves trying to record and save audio as an mp3 from a stream with FFMPEG (I think stream-record may be the correct path potentially). I'd like to be able to do it as an audio clip for a specific subtitle for example so I am thinking that maybe loadfile would be more appropriate prior to recording it.

jaseg commented 3 years ago

TBH to record audio from a stream being played back, I would spawn a separate "stream recorder" process. The simplest way to do that I think would be to just fork out a separate ffmpeg instance.

mpv probably can do what you want, but I think having the "player" mpv instance also record the stream it is playing may be problematic if the user interacts with that mpv instance, e.g. seeking backwards or pausing playback.

melMass commented 3 years ago

@CalculusAce For play/pause you can use:

self.player.command("cycle","pause")