I recently have been playing around with gstreamer and python, seeking (and finding) a way to decode and play HD movie with 10 audio tracks on relatively cheap hardware (being, a linux system with several cheapo 5.1 soundcards).

python, gstreamer and pulseaudio proved a winning combination here;

  • gstreamer and it's commandline tools (gst-launch, gst-inspect) to explore the decoding
  • pulseaudio, being the default ubuntu sound layer with nice gui apps (pavumeter, padevchooser), and good gstreamer integration (pulsesink, setting output device)
  • python (using the great pygst gstreamer bindings & gtk) to create a little player (fullscreen + ever-forever looping)

import sys, os
import pygtk, gtk, gobject
import pygst
pygst.require("0.10")
import gst

class GTK_Main:
    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_title("Player")
        self.window.connect("destroy", gtk.main_quit, "WM destroy")
        vbox = gtk.VBox()
        self.window.add(vbox)
        self.movie_window = gtk.DrawingArea()
        vbox.add(self.movie_window)
        self.window.show_all()
        self.window.fullscreen()
        self.pipeline = gst.parse_launch("filesrc location=fball/final1.mov  ! qtdemux name=d \
interleave name=i0 !  \
pulsesink device=\"alsa_output.pci_13f6_111_0_sound_card_0_alsa_playback_0\"  sync=true \
interleave name=i1 ! \
pulsesink device=\"alsa_output.pci_13f6_111_1_sound_card_0_alsa_playback_0\"  sync=true   \
interleave name=i2 ! \
pulsesink device=\"alsa_output.pci_13f6_111_sound_card_0_alsa_playback_0\"   sync=true \
d.audio_00 !  queue !  audioresample ! audioconvert ! deinterleave name=di0 \
di0.src0 ! audioresample ! audioconvert !  queue !   i0. \
di0.src1 !  audioresample ! audioconvert !  queue !   i0. \
d.audio_01 !  audioresample ! audioconvert !  queue !  audioresample ! audioconvert ! deinterleave name=di1 \
di1.src0 ! audioresample ! audioconvert !  queue !  i0. \
di1.src1 !  audioresample ! audioconvert !  queue ! i0. \
d.audio_02 !  audioresample ! audioconvert !  queue !  audioresample ! audioconvert ! deinterleave name=di2 \
di2.src0 ! audioresample ! audioconvert !  queue !   i1. \
di2.src1 !  audioresample ! audioconvert !  queue !   i1. \
d.audio_03 !  audioresample ! audioconvert !  queue !  audioresample ! audioconvert ! deinterleave name=di3 \
di3.src0 ! audioresample ! audioconvert !  queue ! i1. \
di3.src1 !  audioresample ! audioconvert !  queue !   i1. \
d.audio_04 !  audioresample ! audioconvert !  queue !  audioresample ! audioconvert ! deinterleave name=di4 \
di4.src0 ! audioresample ! audioconvert !  queue !   i2. \
di4.src1 !  audioresample ! audioconvert !  queue !   i2. \
d.video_00 ! queue ! decodebin ! xvimagesink sync=true")

     
        self.time_format = gst.Format(gst.FORMAT_TIME)

        bus = self.pipeline.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)

        self.pipeline.set_state(gst.STATE_PLAYING)
   
    def on_message(self, bus, message):
        t = message.type
        if t == gst.MESSAGE_EOS:
            self.pipeline.set_state(gst.STATE_PAUSED)
            seek_ns = 0
            self.pipeline.seek_simple(self.time_format, gst.SEEK_FLAG_FLUSH, seek_ns)
            self.pipeline.set_state(gst.STATE_PLAYING)
        elif t == gst.MESSAGE_ERROR:
            err, debug = message.parse_error()
            print "Error: %s" % err, debug
            self.pipeline.set_state(gst.STATE_NULL)
    
    def on_sync_message(self, bus, message):
        if message.structure is None:
            return
        message_name = message.structure.get_name()
        if message_name == 'prepare-xwindow-id':
            imagesink = message.src
            imagesink.set_property('force-aspect-ratio', True)
            imagesink.set_xwindow_id(self.movie_window.window.xid)


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