python Gstreamer write mp4 video player
To understand the use of written Gstreamer player
Use Gstreamer player has written several points:
1. The element selection:
The video format within the package and the package of video, audio encoding and decoding format selection element decapsulation required. Video, audio encoding format may be obtained from the properties of a video:
encoding video format is shown in H.264, an audio encoding format is AAC. And associated components may be used to search for gst-inspect command.
2. The connecting element
Key element connection portion connected to the queue when the liner is provided a new callback pad demuxer. Use gst-inspect command template spacer elements can be obtained, in order to distinguish between video and audio streams to generate the complete connection pad.
Command: gst-inspect-1.0 qtdemux
Easy mp4 player:
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GObject, GLib
Gst.init(None)
#设置回调函数在demuxer产生新衬垫时与队列衬垫连接
def cb_demuxer_newpad(src, pad, dst,dst2):
if pad.get_property("template").name_template == "video_%u":
vdec_pad = dst.get_static_pad("sink")
pad.link(vdec_pad)
elif pad.get_property("template").name_template == "audio_%u":
adec_pad = dst2.get_static_pad("sink")
pad.link(adec_pad)
#创建elements
pipe = Gst.Pipeline.new("test")
src = Gst.ElementFactory.make("filesrc", "src")
demuxer = Gst.ElementFactory.make("qtdemux", "demux")
#创建视频队列元件
decodebin = Gst.ElementFactory.make("avdec_h264", "decode")
queuev = Gst.ElementFactory.make("queue", "queue")
conv = Gst.ElementFactory.make("videoconvert", "conv")
sink = Gst.ElementFactory.make("xvimagesink", "sink")
#创建音频队列元件
decodebina = Gst.ElementFactory.make("faad", "decodea")
queuea = Gst.ElementFactory.make("queue", "queuea")
conva = Gst.ElementFactory.make("audioconvert", "conva")
sinka = Gst.ElementFactory.make("autoaudiosink", "sinka")
#获取播放地址(这里location表示视频和代码在同一个项目下)
src.set_property("location", "a.mp4")
demuxer.connect("pad-added", cb_demuxer_newpad, queuev,queuea)
#向管道中添加元件
pipe.add(src)
pipe.add(demuxer)
pipe.add(queuev)
pipe.add(decodebin)
pipe.add(conv)
pipe.add(sink)
pipe.add(queuea)
pipe.add(decodebina)
pipe.add(conva)
pipe.add(sinka)
#连接元件
src.link(demuxer)
queuev.link(decodebin)
decodebin.link(conv)
conv.link(sink)
queuea.link(decodebina)
decodebina.link(conva)
conva.link(sinka)
#修改状态为播放
pipe.set_state(Gst.State.PLAYING)
mainloop = GLib.MainLoop()
mainloop.run()
mp4 player with gtk interface
import os
import gi
gi.require_version('Gst', '1.0')
gi.require_version('Gtk', '3.0')
from gi.repository import Gst, GObject, Gtk
class GTK_Main(object):
def __init__(self):
window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
window.set_title("Mpeg2-Player")
window.set_default_size(500, 400)
window.connect("destroy", Gtk.main_quit, "WM destroy")
vbox = Gtk.VBox()
window.add(vbox)
hbox = Gtk.HBox()
vbox.pack_start(hbox, False, False, 0)
self.entry = Gtk.Entry()
hbox.add(self.entry)
self.button = Gtk.Button("Start")
hbox.pack_start(self.button, False, False, 0)
self.button.connect("clicked", self.start_stop)
self.movie_window = Gtk.DrawingArea()
vbox.add(self.movie_window)
window.show_all()
self.player = Gst.Pipeline.new("player")
source = Gst.ElementFactory.make("filesrc", "file-source")
demuxer = Gst.ElementFactory.make("qtdemux", "demuxer")
demuxer.connect("pad-added", self.demuxer_callback)
self.video_decoder = Gst.ElementFactory.make("avdec_h264", "video-decoder")
self.audio_decoder = Gst.ElementFactory.make("faad", "audio-decoder")
audioconv = Gst.ElementFactory.make("audioconvert", "converter")
audiosink = Gst.ElementFactory.make("autoaudiosink", "audio-output")
videosink = Gst.ElementFactory.make("xvimagesink", "video-output")
self.queuea = Gst.ElementFactory.make("queue", "queuea")
self.queuev = Gst.ElementFactory.make("queue", "queuev")
colorspace = Gst.ElementFactory.make("videoconvert", "colorspace")
#colorspace = Gst.ElementFactory.make("ffmpegcolorspace", "colorspace")
self.player.add(source)
self.player.add(demuxer)
self.player.add(self.video_decoder)
self.player.add(self.audio_decoder)
self.player.add(audioconv)
self.player.add(audiosink)
self.player.add(videosink)
self.player.add(self.queuea)
self.player.add(self.queuev)
self.player.add(colorspace)
source.link(demuxer)
self.queuev.link(self.video_decoder)
self.video_decoder.link(colorspace)
colorspace.link(videosink)
self.queuea.link(self.audio_decoder)
self.audio_decoder.link(audioconv)
audioconv.link(audiosink)
bus = self.player.get_bus()
bus.add_signal_watch()
bus.enable_sync_message_emission()
bus.connect("message", self.on_message)
bus.connect("sync-message::element", self.on_sync_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)
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:
err, debug = message.parse_error()
print ("Error: %s" % err, debug)
self.player.set_state(Gst.State.NULL)
self.button.set_label("Start")
def on_sync_message(self, bus, message):
if message.get_structure().get_name() == 'prepare-window-handle':
imagesink = message.src
imagesink.set_property("force-aspect-ratio", True)
xid = self.movie_window.get_property('window').get_xid()
imagesink.set_window_handle(xid)
def demuxer_callback(self, demuxer, pad):
if pad.get_property("template").name_template == "video_%u":
qv_pad = self.queuev.get_static_pad("sink")
pad.link(qv_pad)
elif pad.get_property("template").name_template == "audio_%u":
qa_pad = self.queuea.get_static_pad("sink")
pad.link(qa_pad)
Gst.init(None)
GTK_Main()
GObject.threads_init()
Gtk.main()