-
Notifications
You must be signed in to change notification settings - Fork 2
/
videoplayer.py
128 lines (103 loc) · 4.27 KB
/
videoplayer.py
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import sys
from gi.repository import GObject, Gtk, Gst, GstVideo
from gnotifier import GNotifier
Gst.FRAME = Gst.SECOND // 30
def getXid(window) :
if sys.platform == "win32":
if not window.ensure_native():
print("Error - video playback requires a native window")
import ctypes
ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object]
gpointer = ctypes.pythonapi.PyCapsule_GetPointer(window.__gpointer__, None)
gdkdll = ctypes.CDLL ("libgdk-3-0.dll")
return gdkdll.gdk_win32_window_get_handle(gpointer)
else:
from gi.repository import GdkX11
return window.get_xid()
class VideoPlayer(GNotifier) :
__video_duration = 0
__video_position = 0
__video_position_timeout = None
def __init__(self, **properties):
GNotifier.__init__(self, **properties)
self.playbin = Gst.ElementFactory.make('playbin', None)
if not self.playbin :
sys.stderr.write("'playbin' gstreamer plugin missing\n")
sys.exit(1)
self.pipeline = Gst.Pipeline()
self.bus = self.pipeline.get_bus()
self.bus.add_signal_watch()
self.bus.connect('message::eos', self.onEOS)
self.bus.connect('message::error', self.onVideoError)
self.bus.enable_sync_message_emission()
self.bus.connect('sync-message::element', self.onSyncMessage)
self.pipeline.add(self.playbin)
GObject.timeout_add(100, self.triggerVideoPosition)
def triggerVideoPosition(self):
self.set_property("video-position", -1)
return True
@GObject.Property(type=bool, default=False)
def video_playing(self):
for x in self.pipeline.get_state(10000) :
if type(x) is Gst.State and x == Gst.State.PLAYING :
return True
return False
@video_playing.setter
def video_playing(self, value):
self.pipeline.set_state(Gst.State.PLAYING if value else Gst.State.PAUSED)
@property
def video_duration(self):
success, duration = self.pipeline.query_duration(Gst.Format.TIME)
if success and self.__video_duration != duration :
self.__video_duration = duration
# send signal
return self.__video_duration
@GObject.Property(type=GObject.TYPE_LONG)
def video_position(self):
success, position = self.pipeline.query_position(Gst.Format.TIME)
if success and position != self.__video_position:
#print (position)
self.__video_position = position
return self.__video_position
@video_position.setter
def video_position(self, value):
if value < 0 : return
self.seek(value, Gst.Format.TIME)
def load(self, path):
self.pause()
uri = path if Gst.uri_is_valid(path) else Gst.filename_to_uri(path)
self.pipeline.set_state(Gst.State.READY)
self.playbin.set_property('uri', uri)
self.play()
self.pause()
def playpause(self, *dontcare):
self.xid = getXid(self.video_player.get_property('window'))
self.video_playing = not self.video_playing
def play(self, *dontcare):
self.xid = getXid(self.video_player.get_property('window'))
self.video_playing = True
def pause(self, *dontcare):
self.xid = getXid(self.video_player.get_property('window'))
self.video_playing = False
def relativeSeek(self, button):
offset = int(button.get_name().replace('seek:','')) * Gst.FRAME
self.video_position += offset
def seek(self, position, format = Gst.Format.TIME):
return self.pipeline.seek_simple(
format,
Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE,
position)
def onSyncMessage(self, bus, msg):
if msg.get_structure().get_name() == 'prepare-window-handle':
# print('prepare-window-handle')
msg.src.set_window_handle(self.xid)
def onEOS(self, bus, msg):
print('onEOS(): seeking to start of video')
self.pipeline.seek_simple(
Gst.Format.TIME,
Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
0
)
def onVideoError(self, bus, msg):
print('onVideoError():', msg.parse_error())