这篇文章主要介绍了python gstreamer 实现视频快进/快退/循环播放功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
Gstreamer到底是个啥?
GStreamer 是一个 基于pipeline的多媒体框架,基于GObject,以C语言写成。
应用GStreamer这个这个多媒体框架,你可以写出任意一种流媒体的应用来如:meidaplayer、音视频编辑器、VOIP、流媒体服务器、音视频编码等等。
关于视频快进/快退/循环播放的知识总结:
1.本地视频时长获取:
Gst.Pad.query_duration官方函数介绍:
1
2
3
4
5
6
7
8
9
10
11
12
def Gst.Pad.query_duration (self, format):
#python wrapper for 'gst_pad_query_duration'
Queries a pad for the total stream duration.
Parameters:
pad ( Gst.Pad ) –a Gst.Pad to invoke the duration query on.
format ( Gst.Format ) –the Gst.Format requested
Returns a tuple made of:
( gboolean ) –TRUE (not introspectable) if the query could be performed.
duration ( gint64 ) –TRUE (not introspectable) if the query could be performed.
使用如下:
pipeline.query_duration(Gst.Format.TIME)[1]
其中pipeline为播放本地视频的管道,query_duration()函数返回一个元组,元组的形式为[Ture,duration:******],******为以ns为单位的视频时长。
2.视频播放当前位置获取:
Gst.Pad.query_position官方函数介绍:
1
2
3
4
5
6
7
8
9
10
11
12
def Gst.Pad.query_position (self, format):
#python wrapper for 'gst_pad_query_position'
Queries a pad for the stream position.
Parameters:
pad ( Gst.Pad ) –a Gst.Pad to invoke the position query on.
format ( Gst.Format ) –the Gst.Format requested
Returns a tuple made of:
( gboolean ) –TRUE (not introspectable) if the query could be performed.
cur ( gint64 ) –TRUE (not introspectable) if the query could be performed.
使用方法与时长获取函数query_duration()相同。
3.播放跳转函数:
Gst.Element.seek_simple官方函数介绍:
1
2
3
4
5
6
7
8
9
10
11
def Gst.Element.seek_simple (self,format, seek_flags, seek_pos):
#python wrapper for 'gst_element_seek_simple'
Parameters:
element ( Gst.Element ) –a Gst.Element to seek on
format ( Gst.Format ) –a Gst.Format to execute the seekin, such as Gst.Format.TIME
seek_flags ( Gst.SeekFlags ) –seek options; playback applications will usually want
to use GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT here
seek_pos ( gint64 ) –position to seek to (relative to the start);if you are doing
a seekin Gst.Format.TIME this valueis in nanoseconds- multiply with Gst.SECOND to
convert seconds to nanosecondsor with Gst.MSECOND to convert milliseconds to nanoseconds.
Returns ( gboolean ) :
TRUE (not introspectable)if the seek operation succeeded. Flushing seeks will
trigger a preroll, which will emit Gst.MessageType.ASYNC_DONE.
函数使用样例:
pipeline.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, time)
其中time的单位为nanoseconds。
有视频快进/快退/循环播放功能的小播放器.
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
import os, _thread, time
import gi
gi.require_version("Gst","1.0")
gi.require_version('Gtk','3.0')
from gi.repositoryimport Gst, GObject, Gtk, Gdk
class GTK_Main:
def __init__(self):
window= Gtk.Window(Gtk.WindowType.TOPLEVEL)
window.set_title("Vorbis-Player")
window.set_default_size(500,-1)
window.connect("destroy", Gtk.main_quit,"WM destroy")
vbox= Gtk.VBox()
window.add(vbox)
self.entry= Gtk.Entry()
vbox.pack_start(self.entry,False,False,0)
hbox= Gtk.HBox()
vbox.add(hbox)
buttonbox= Gtk.HButtonBox()
hbox.pack_start(buttonbox,False,False,0)
rewind_button= Gtk.Button("Rewind")
rewind_button.connect("clicked",self.rewind_callback)
buttonbox.add(rewind_button)
self.button= Gtk.Button("Start")
self.button.connect("clicked",self.start_stop)
buttonbox.add(self.button)
forward_button= Gtk.Button("Forward")
forward_button.connect("clicked",self.forward_callback)
buttonbox.add(forward_button)
self.time_label= Gtk.Label()
self.time_label.set_text("00:00 / 00:00")
hbox.add(self.time_label)
window.show_all()
self.player= Gst.Pipeline.new("player")
source= Gst.ElementFactory.make("filesrc","file-source")
demuxer= Gst.ElementFactory.make("decodebin","demuxer")
videoconv= Gst.ElementFactory.make("videoconvert","converter")
videosink= Gst.ElementFactory.make("xvimagesink","video-output")
demuxer.connect("pad-added",self.demuxer_callback, videoconv)
for elein [source, demuxer, videoconv, videosink]:
self.player.add(ele)
source.link(demuxer)
videoconv.link(videosink)
bus= self.player.get_bus()
bus.add_signal_watch()
bus.connect("message",self.on_message)
def start_stop(self, w):
if self.button.get_label()== "Start":
filepath= self.entry.get_text().strip()
if os.path.isfile(filepath):
filepath= os.path.realpath(filepath)
self.button.set_label("Stop")
self.player.get_by_name("file-source").set_property("location", filepath)
self.player.set_state(Gst.State.PLAYING)
self.play_thread_id= _thread.start_new_thread(self.play_thread, ())
else:
self.play_thread_id= None
self.player.set_state(Gst.State.NULL)
self.button.set_label("Start")
self.time_label.set_text("00:00 / 00:00")
def play_thread(self):
play_thread_id= self.play_thread_id
Gdk.threads_enter()
self.time_label.set_text("00:00 / 00:00")
Gdk.threads_leave()
print(play_thread_id)
print(self.play_thread_id)
while play_thread_id== self.play_thread_id:
time.sleep(0.2)
dur_int= self.player.query_duration(Gst.Format.TIME)[1]
if dur_int== -1:
continue
dur_str= self.convert_ns(dur_int)
Gdk.threads_enter()
self.time_label.set_text("00:00 / " + dur_str)
Gdk.threads_leave()
break
time.sleep(0.2)
while play_thread_id== self.play_thread_id:
pos_int= self.player.query_position(Gst.Format.TIME)[1]
pos_str= self.convert_ns(pos_int)
if play_thread_id== self.play_thread_id:
Gdk.threads_enter()
self.time_label.set_text(pos_str+ " / " + dur_str)
Gdk.threads_leave()
time.sleep(1)
def on_message(self, bus, message):
t= message.type
if t== Gst.MessageType.EOS:
self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH,0000000000)
elif t== Gst.MessageType.ERROR:
err, debug= message.parse_error()
print ("Error: %s" % err, debug)
self.play_thread_id= None
self.player.set_state(Gst.State.NULL)
self.button.set_label("Start")
self.time_label.set_text("00:00 / 00:00")
def demuxer_callback(self, demuxer, pad, dst):
caps= Gst.Pad.get_current_caps(pad)
structure_name= caps.to_string()
if structure_name.startswith("video"):
videorate_pad= dst.get_static_pad("sink")
pad.link(videorate_pad)
def rewind_callback(self, w):
rc, pos_int= self.player.query_position(Gst.Format.TIME)
seek_ns= pos_int- 10 * 1000000000
if seek_ns <0:
seek_ns= 0
print ('Backward: %d ns -> %d ns' % (pos_int, seek_ns))
self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, seek_ns)
def forward_callback(self, w):
rc, pos_int= self.player.query_position(Gst.Format.TIME)
seek_ns= pos_int+ 10 * 1000000000
print ('Forward: %d ns -> %d ns' % (pos_int, seek_ns))
self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, seek_ns)
def convert_ns(self, t):
s,ns= divmod(t,1000000000)
m,s= divmod(s,60)
if m <60:
return "%02i:%02i" %(m,s)
else:
h,m= divmod(m,60)
return "%i:%02i:%02i" %(h,m,s)
GObject.threads_init()
Gst.init(None)
GTK_Main()
Gtk.main()
总结
到此这篇关于python gstreamer 实现视频快进/快退/循环播放功能的文章就介绍到这了