summaryrefslogtreecommitdiff
path: root/blc/audio/ffplay.py
blob: 306351abc4d928bbf14397c5d1f866631e3140da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""Module for FFPlay-based audio player."""

import atexit
import subprocess as subp
import time

from .interface import AudioPlayer
from .util import ttoti, titot

class FFPlayer(AudioPlayer):
    """Audio player using ffplay.
    
    Note that this is incredibly bad: the current position is guessed based on the start time of
    the subprocess (meaning startup time of the ffplay process is counted in the current 
    position), no preloading of files is done, seeking is inaccurate and requires killing and 
    restarting the ffplay process, volume is ignored, and more. This is due to the fact that you 
    can't provide input to ffplay because it uses SDL exclusively for input (even though it can 
    be run without SDL?) so any change requires restarting the process. Use MPVPlayer if
    possible.
    """
    def play(self, start=-1):
        if self.playing:
            raise ValueError("Already playing")

        if start != -1:
            self.start = titot(start)
            if self.start <= 0.1:
                self.start = 0
        self.player = subp.Popen(["ffplay", "-nodisp", "-autoexit", "-ss", str(self.start), *self.args, self.fname],
                                 stdin=subp.DEVNULL, stdout=subp.DEVNULL, stderr=subp.DEVNULL)
        atexit.register(self.stop)
        self.start_time = time.monotonic()

    def stop(self):
        if not self.playing:
            return
        self.player.terminate()
        atexit.unregister(self.stop)
        self.player = None
        self.start = 0

    def seek(self, t):
        if self.playing:
            self.stop()
            self.start = titot(t)
            self.play()
        else:
            self.start = titot(t)

    def pause(self):
        if not self.playing:
            return
        self.stop()
        self.start = self.start + time.monotonic()

    @property
    def position(self):
        if not self.playing:
            return self.start
        return ttoti(self.start + time.monotonic() - self.start_time)

    @property
    def volume(self):
        return 100

    @volume.setter
    def volume(self, vol):
        return

    @property
    def playing(self):
        if self.player is not None:
            if self.player.poll() is not None:
                self.player = None

        return self.player is not None

    def __init__(self, fname, args=()):
        super().__init__(fname, args=args)
        
        self.player = None
        self.start = 0
        self.start_time = 0