GStreamer系列之概览

playbin是一个高级别的,自动化的音视频播放器,一般来说,它会播放发送给他的任何 支持的多媒体数据。

playbin的内部看起来是这个样子的:

                                    playbin
        ____________________________________________________________________
       |                            ________________     _______________    |
       |                           |                |   |               |   |
       |                        ->-| optional stuff |->-| autoaudiosink |->-|->- Audio Output
       |    ________________   |   |________________|   |_______________|   |
       |   |                |--                                             |
uri ->-|->-|  uridecodebin  |                                               |
       |   |________________|--     ________________     _______________    |
       |                       |   |                |   |               |   |
       |                        ->-| optional stuff |->-| autovideosink |->-|->- Video Output
       |                           |________________|   |_______________|   |
       |____________________________________________________________________|

“uri” 属性可以使用任何GStreamer插件支持的协议。playbin支持你将sink换成其他的,就 像我们在下面的例子中做的。一般来说,playbin总是会自动设置好你所要的一切,因此你 不要指定那些playbin没有实现的特性,开箱即用就不错的。

Example 1:播放起来

 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
import sys, os
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst, Gtk, GObject
GObject.threads_init()
Gst.init(None)

class PlayBin(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title='Audio Player')
        self.set_default_size(300, -1)
        self.connect('delete-event', Gtk.main_quit)

        vbox = Gtk.VBox()
        self.add(vbox)

        self.entry = Gtk.Entry()
        vbox.pack_start(self.entry, False, True, 0)
        self.button = Gtk.ToggleButton('Start')
        self.button.connect('clicked', self.start_stop)
        vbox.add(self.button)
        self.show_all()

        # build a palyer
        self.player = Gst.ElementFactory.make('playbin', 'player')
        # we don't need video output
        #fakesink = Gst.ElementFactory.make('fakesink', 'fakesink')
        #self.player.set_property('video-sink', fakesink)
        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.connect('message', self.on_message)

    def start_stop(self, widget):
        if self.button.get_active():
            filepath = self.entry.get_text()
            if os.path.isfile(filepath):
                self.button.set_label('Stop')
                self.player.set_property('uri', 'file://'+filepath)
                self.player.set_state(Gst.State.PLAYING)
        else:
            self.player.set_state(Gst.State.NULL)
            self.button.set_label('Start')

    def on_message(self, bus, message):
        t = message.type
        if t == Gst.MessageType.EOS:
            self.player.set_state(Gst.State.NULL)
            self.button.set_label('Start')
        elif t == Gst.MessageType.ERROR:
            self.player.set_state(Gst.State.NULL)
            err, debug = message.parse_error()
            print('Error: %s' %err, debug)
            self.button.set_label('Start')

win = PlayBin()
Gtk.main()

由于playbin插件总是会自动播放音视频流,因此我们将视频重定向至 fakesink ,这 相当于Gstreamer中的 /dev/null 。你如果想要播放视频流,只需要注释掉这两行代码

        #fakesink = Gst.ElementFactory.make('fakesink', 'fakesink')
        #self.player.set_property('video-sink', fakesink)

Example 2:控制视频的显示

当然上面的例子在播放视频时总是会打开一个新的窗口,如果你想要在指定的窗口播放则 需要使用 enable_sync_message_emission() 方法。

 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
import sys, os
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst, Gtk, GObject

# important!!! needed by window.get_xid(), xvimagesink.set_window_handle.
from gi.repository import GdkX11, GstVideo

GObject.threads_init()
Gst.init(None)

class PlayBin(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title='Audio Player')
        self.set_default_size(500, 400)
        self.connect('delete-event', Gtk.main_quit)

        vbox = Gtk.VBox()
        self.add(vbox)

        hbox = Gtk.HBox()
        vbox.pack_start(hbox, False, False, 0)
        self.entry = Gtk.Entry()
        hbox.pack_start(self.entry, True, True, 0)
        self.button = Gtk.ToggleButton('Start')
        self.button.connect('clicked', self.start_stop)
        hbox.add(self.button)
        self.movie = Gtk.DrawingArea()
        vbox.add(self.movie)
        # build a palyer
        self.player = Gst.ElementFactory.make('playbin', 'player2')
        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.connect('message', self.on_message)
        bus.enable_sync_message_emission()
        bus.connect('sync-message::element', self.on_sync_message)

        self.show_all()
        self.xid = self.movie.get_property('window').get_xid()

    def start_stop(self, widget):
        if self.button.get_active():
            filepath = self.entry.get_text()
            if os.path.isfile(filepath):
                self.button.set_label('Stop')
                self.player.set_property('uri', 'file://'+filepath)
                self.player.set_state(Gst.State.PLAYING)
        else:
            self.player.set_state(Gst.State.NULL)
            self.button.set_label('Start')

    def on_message(self, bus, message):
        t = message.type
        if t == Gst.MessageType.EOS:
            self.player.set_state(Gst.State.NULL)
            self.button.set_label('Start')
        elif t == Gst.MessageType.ERROR:
            self.player.set_state(Gst.State.NULL)
            err, debug = message.parse_error()
            print('Error: %s' %err, debug)
            self.button.set_label('Start')

    def on_sync_message(self, bus, message):
        if message.get_structure().get_name() == 'prepare-window-handle':
            message.src.set_window_handle(self.xid)

win = PlayBin()
Gtk.main()

Example 3:添加时间显示

我们可以让事情变的更有趣,我们将playbin的 videosink 切换为我们自己的GHostPad, 并在上面增加了一个时间显示的小元素。

 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
import sys, os
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst, Gtk, GObject

# important!!! needed by window.get_xid(), xvimagesink.set_window_handle.
from gi.repository import GdkX11, GstVideo

GObject.threads_init()
Gst.init(None)

class PlayBin(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title='Audio Player')
        self.set_default_size(500, 400)
        self.connect('delete-event', Gtk.main_quit)

        vbox = Gtk.VBox()
        self.add(vbox)

        hbox = Gtk.HBox()
        vbox.pack_start(hbox, False, False, 0)
        self.entry = Gtk.Entry()
        hbox.pack_start(self.entry, True, True, 0)
        self.button = Gtk.ToggleButton('Start')
        self.button.connect('clicked', self.start_stop)
        hbox.add(self.button)
        self.movie = Gtk.DrawingArea()
        vbox.add(self.movie)
        # build a palyer
        self.player = Gst.ElementFactory.make('playbin', 'player2')

        mybin = Gst.Bin()
        timeoverlay = Gst.ElementFactory.make('timeoverlay', 'timeoverlay')
        mybin.add(timeoverlay)
        pad = timeoverlay.get_static_pad('video_sink')
        ghostpad = Gst.GhostPad.new('sink', pad)
        mybin.add_pad(ghostpad)
        videosink = Gst.ElementFactory.make('autovideosink', 'autovideosin')
        mybin.add(videosink)
        timeoverlay.link(videosink)
        self.player.set_property('video-sink', mybin)

        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.connect('message', self.on_message)
        bus.enable_sync_message_emission()
        bus.connect('sync-message::element', self.on_sync_message)

        self.show_all()
        self.xid = self.movie.get_property('window').get_xid()

    def start_stop(self, widget):
        if self.button.get_active():
            filepath = self.entry.get_text()
            if os.path.isfile(filepath):
                self.button.set_label('Stop')
                self.player.set_property('uri', 'file://'+filepath)
                self.player.set_state(Gst.State.PLAYING)
        else:
            self.player.set_state(Gst.State.NULL)
            self.button.set_label('Start')

    def on_message(self, bus, message):
        t = message.type
        if t == Gst.MessageType.EOS:
            self.player.set_state(Gst.State.NULL)
            self.button.set_label('Start')
        elif t == Gst.MessageType.ERROR:
            self.player.set_state(Gst.State.NULL)
            err, debug = message.parse_error()
            print('Error: %s' %err, debug)
            self.button.set_label('Start')

    def on_sync_message(self, bus, message):
        if message.get_structure().get_name() == 'prepare-window-handle':
            message.src.set_window_handle(self.xid)

win = PlayBin()
Gtk.main()