Sunday, February 26, 2012

Python Video Player Part Duex

After too many hours I gave up on MLT. Their documentation is pretty bad. I could not get "multi" working. Back to gstreamer.

Initially I was reluctant to use the gstreamer command line; get-launch. But I was not making headway in gstreamer in python, so I thought it would be good to get python out of the way for now.

My ultimate goal is to figure out how to use "tee". But I could not find good documentation on the, so switched to getting mux to work, since it has one input and 2 outputs, like tee.

I still could not get things to work. I could run the gst-launcher but it would PAUSE and I could not figure out how to get it to START. It seemed like it had something to do with putting queues on the mux output. Then all was revealed in this post. For the mpegdemux, the queues need to go after the decoders... frustrating. Here is code that works (just put your path to your mpg file):
#!/bin/bash
gst-launch-0.10 -v --gst-debug-level=1 \
mpegdemux name=demuxer \
demuxer. ! mpeg2dec ! queue ! ffmpegcolorspace ! xvimagesink \
demuxer. ! mad ! queue ! audioconvert ! pulsesink \
filesrc location="PATH TO .mpg FILE" ! demuxer.
Now to tee the video. OMG - this worked! Two identical video windows (note: they are positioned on top of each other).
#!/bin/bash
gst-launch-0.10 -v --gst-debug-level=1 \
mpegdemux name=demuxer \
demuxer. ! mpeg2dec ! queue ! ffmpegcolorspace ! tee name=my_tee \
my_tee. ! queue ! xvimagesink \
my_tee. ! queue ! xvimagesink \
demuxer. ! mad ! queue ! audioconvert ! pulsesink \
filesrc location="/home/chuck/Desktop/test.mpg" ! demuxer.
Life is good. Here it's working in python:
import sys, os
import pygtk, gtk, gobject
import pygst
pygst.require("0.10")
import gst

FILEPATH='MY FILE PATH.mpg'

class GTK_Main:
def __init__(self):
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_title("Mpeg2-Player")
#window.set_default_size(200, 100)
window.connect("destroy", gtk.main_quit, "WM destroy")
vbox = gtk.VBox()
window.add(vbox)
hbox = gtk.HBox()
vbox.pack_start(hbox, False)
self.button = gtk.Button("Start")
hbox.pack_start(self.button, False)
self.button.connect("clicked", self.start_stop)
window.show_all()

self.player = gst.Pipeline("player")
source = gst.element_factory_make("filesrc", "file-source")
source.set_property("location", FILEPATH)

demuxer = gst.element_factory_make("mpegdemux", "demuxer")
demuxer.connect("pad-added", self.demuxer_callback) # evidently demux needs to be setup dynamically

self.video_decoder = gst.element_factory_make("mpeg2dec", "video-decoder")
self.colorspace = gst.element_factory_make("ffmpegcolorspace", "colorspace")
self.audio_decoder = gst.element_factory_make("mad", "audio-decoder")
audioconv = gst.element_factory_make("audioconvert", "converter")
audiosink = gst.element_factory_make("pulsesink", "audio-output")
videosink1 = gst.element_factory_make("xvimagesink", "video-output1")
videosink1.set_property("name", "vid1")
videosink2 = gst.element_factory_make("xvimagesink", "video-output2")
videosink2.set_property("name", "vid2")
self.tee=gst.element_factory_make("tee","my_tee")

self.queuea = gst.element_factory_make("queue", "queuea")
self.queuev = gst.element_factory_make("queue", "queuev")
self.queuet1 = gst.element_factory_make("queue", "queuet")
self.queuet2 = gst.element_factory_make("queue", "queuet2")

self.player.add(source, demuxer, self.video_decoder, self.audio_decoder, audioconv,
audiosink, videosink1, videosink2, self.queuea, self.queuev,self.queuet1,
self.queuet2, self.colorspace,self.tee)
gst.element_link_many(source, demuxer)
gst.element_link_many(self.video_decoder,self.queuev, self.colorspace, self.tee )
gst.element_link_many(self.audio_decoder,self.queuea, audioconv, audiosink)
gst.element_link_many(self.tee, self.queuet1, videosink1)
gst.element_link_many(self.tee, self.queuet2, videosink2)

bus = self.player.get_bus()
bus.add_signal_watch()
bus.enable_sync_message_emission()
bus.connect("message", self.on_message)

def start_stop(self, w):
if self.button.get_label() == "Start":
self.button.set_label("Stop")
self.player.set_state(gst.STATE_PLAYING) # tells mux it needs to connect to something, then starts
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.MESSAGE_EOS:
self.player.set_state(gst.STATE_NULL)
self.button.set_label("Start")
elif t == gst.MESSAGE_ERROR:
err, debug = message.parse_error()
print "Error: %s" % err, debug
self.player.set_state(gst.STATE_NULL)
self.button.set_label("Start")

def demuxer_callback(self, demuxer, pad):
if pad.get_property("template").name_template == "video_%02d":
qv_pad = self.video_decoder.get_pad("sink")
pad.link(qv_pad)
elif pad.get_property("template").name_template == "audio_%02d":
qa_pad = self.audio_decoder.get_pad("sink")
pad.link(qa_pad)

GTK_Main()
gtk.gdk.threads_init()
gtk.main()

No comments:

Post a Comment