GStreamer and Android

One project we have been working on for some time at Collabora Multimedia is making it easy to use GStreamer with Android. There has been some code available to do this for some time, but it was incomplete and not easy to use. Thanks to a project we did with ST Ericsson we got that code much improved and ST Ericsson kindly released that code afterwards. We then took that code and updated it to run with latest Gingerbread release of Android and also generalized it to make it easy to run with any chipset.

We have also now imported this code into the main GStreamer repositories, so that when you visit the GStreamer Git repository you find the code there along with all the other GStreamer modules. And we have also set up a GStreamer-android mailing list alongside the other GStreamer lists.

Edward Hervey sent out an email today with some the technical details of this project and how it works. But in general the goal here is to offer a transparent integration of GStreamer into Android. We also got a wiki page with full build instructions.

I recommend anyone interested to try it out to join the mailing list and engage with us on moving this code forward. Hopefully we can use it to enable a lot of cool Android devices coming out in the future using advanced GStreamer features such as video editing, Rygel DLNA support, Telepathy video conferencing and collaboration support, DVB support and more.

So a big thank you to Alessandro Decina, Reynaldo Verdejo, Thibault Saunier and Derek Foreman for the great effort they put into this and getting the code ready for release.

Novell patent sale

I guess a lot of you have seen the story about how Microsoft, EMC, Oracle and Apple are buying a bunch of Novell patents. The main worry from a lot of people seems to be that these patents ends up being used against open source, which is a risk, but it seems the latest changes to the deal makes the patents mostly defensive. That said, the problem still persists as it means there is another seat of patents no longer keeping these companies in check. The problems with software patents are well known, like their low quality and the crazy cost of fighting patents in court. The reason they haven’t killed the software industry completely is because of the patent nuclear deterrent, meaning how at least in the case of big companies they have enough patents themselves to usually scare of any patent lawsuits from the competitors. However this is a unstable situation and I can’t say that I like seeing this pool of patents no longer being available to deter patent suits from the 4 companies in question.

Google Summer of Code deadline

Just want to remind everyone that the deadline for students to apply for the Google Summer of Code 2011. So if you want to do a GStreamer or any other kind of project this is when you need to act.

So get your application filed ASAP as 12pm today in US Pacific time the door closes for this year.

Remember the the website you need to sign up through, our ideas list and finally our application guidelines.

So get cracking on those applications!

GStreamer and Google Summer of Code 2011

So it is once again Google Summer of Code time, when students from all over the world have a chance to earn some good money from Google for working on an open source project of their choice. The great news that the best choice, also known as GStreamer, is available also this year :)

As always we have a page with some projects ideas, but we are always open to students wanting to pursue their own ideas as long as we are able to find a suitable mentor.

Before submitting an application be sure to read our GSoC application guidelines and once you done that and have figured out what project you want to apply for, go to the Google Summer of Code 2011 website and submit.

We look forward to seeing your proposals!

Bye bye Sourceforge

GStreamer was originally hosted on Sourceforge when the project started up 10 years ago. As time went by we migrated most of our stuff over to freedesktop.org, except our bugzilla which ended up on gnome.org.

The one thing that stayed on Sourceforge was our mailing lists, until today that is. Thanks to the hard work of Tim-Philipp Müller all our lists are now migrated to freedesktop.org. There are a few advantages we see with this move, one being getting nicer archives, another being not needing to maintain an administrator list on SF anymore and finally I guess it makes the mailing lists feel a bit more authentic that they are on freedesktop.org, just like the website.

All this of course means that in the coming Months the 10 year old SF project will get gradually shut down, and maybe we end up deleting it completely. So a thanks to SF for the last 10 years of hosting :) Feels strangely nostalgic for some reason :)

And if anyone wonders if we will move bugzilla too, I don’t think that is in the cards anytime soon. Many of the most popular GStreamer applications, like Totem, Banshee, PiTiVi and so on use the GNOME bugzilla and the option to easily re-assign GStreamer bugs to GStreamer is atm more valuable than what we perceive the value of having everything on freedesktop.

Fixing the US patent system

Just saw the White House putting out this page asking for input on innovation. I recommend every US citizen reading this making sure to fill out the form explaining how the current US patent regime is not helping innovation, but hindering it. How the patent system, due to the volume and low quality of patents granted, and the unbalanced and painful process of getting them revoked, has turned the patent system into a mafia style protection racket where it costs more to fight the extortion than to just pay up. There is a great article on techdirt on this.

encodebin and python

So I went down to FOSDEM this weekend. One of the things I was able to do while there was sit down with Edward Hervey and figure out how to use the new encodebin element with Transmageddon. The goal of the new encodebin element is to make encoding a much easier task with GStreamer, where you basically pass it a GStreamer caps value for your container format and audio and video streams, and encodebin figures out which elements it needs to create output with those caps. I have a minimal example below:

import sys
import os
import gobject; gobject.threads_init()
import gst
import pygst
import glib
import gst.pbutils
import gtk

class Transcoder:
   def __init__(self):
       # create GStreamer pipeline object
       self.pipeline = gst.Pipeline("TranscodingPipeline")
       self.pipeline.set_state(gst.STATE_PAUSED)

       self.uridecoder = gst.element_factory_make("uridecodebin", "uridecoder") 
       self.uridecoder.set_property("uri", "file:///home/cschalle/Videos/gravity.mpg")
       self.uridecoder.connect("pad-added", self.OnDynamicPad)
       self.pipeline.add(self.uridecoder)

       self.containerprofile = gst.pbutils.EncodingContainerProfile ("ogg", None , gst.Caps("application/ogg"), None)
       self.videoprofile = gst.pbutils.EncodingVideoProfile (gst.Caps("video/x-dirac"), None, gst.caps_new_any(), 0)
       self.audioprofile = gst.pbutils.EncodingAudioProfile (gst.Caps("audio/x-vorbis"), None, gst.caps_new_any(), 0)
       self.containerprofile.add_profile(self.videoprofile)
       self.containerprofile.add_profile(self.audioprofile)

       self.ebin = gst.element_factory_make ("encodebin", None)
       self.ebin.set_property("profile", self.containerprofile)
       self.pipeline.add(self.ebin)

       print "self.ebin is " + str(self.ebin)
       self.ebin.set_state(gst.STATE_PAUSED)
       self.uridecoder.set_state(gst.STATE_PAUSED)
       self.filesink = gst.element_factory_make("filesink", None)
       self.filesink.set_property("location", "/tmp/test.ogg")
       self.pipeline.add(self.filesink)
       self.filesink.set_state(gst.STATE_PAUSED)
       self.ebin.link(self.filesink)

       self.pipeline.set_state(gst.STATE_PLAYING)

   def OnDynamicPad(self, uridecodebin, src_pad):
       c = src_pad.get_caps().to_string()
       print c
       sinkpad = self.ebin.emit("request-pad", src_pad.get_caps())
       print "action signal returned", sinkpad
       src_pad.link(sinkpad)

if __name__ == "__main__":
	hwg = Transcoder()
	gtk.main()

The most important thing to notice about this code is the creation of the profiles, the adding of the audio and video profile to the container profile and then finally the setting of that profile onto the encodebin element. In my example I have extremely simple caps statements, basically just the codecs names, but you could add further things here like video height and width, framerate, audio bitrate, audio channels and so on, and encodebin would be able to give you the correct output.

We did find a couple of Python binding bugs though, which Edward fixed promptly, so if you want to try this code now, you need to grab gstreamer-python from git master.

New look for Transmageddon

Screenshot of git snapshot of Transmageddon

Screenshot of git snapshot of Transmageddon

Been preparing Transmageddon for adding a slew of new features, biggest visible change so far is replacing the radiobuttons with drop down lists. People suggested I do that from day one, but with the new features planned it has become a necessity, should also make Transmageddon nicer to use on small screens, like netbooks.

Transmageddon website offline

Just thought I let people know that my personal domain, linuxrising.org is offline atm,. due to a mess up when transferring the domain to a new registrar. This means my gnome.org email is out of comission atm, and that the Transmageddon website is down. Hope to get the situation sorted within a few days.

Back on Transmageddon and new GStreamer features

Been working on Transmageddon again this weekend as the work Edward has been doing on GES has been making its way into GStreamer-plugins-base and gst-python. The most import change for now is the new discoverer service. For those who used gst-python you might know the old version of it, which is basically an API for getting information about a multimedia file. Unfortunately the old Python version had some shortcomings, but thanks to the work that has been done for GES and Rygel we now have a new C based on in plugins-base which works a lot better. So those who had problems with Transmageddon in the past not recognizing files and thus not operating properly should now have more luck. Also the new discoverer process will tell me if a file is interlaced so I can easily now add support for deinterlacing in Transmageddon.

Anyway, I thought I share my half-done implementation of gst-discover in Python. You find a better version in C in gst-plugins-base/tools or a nice Vala version at live.gnome.org. But if you are familiar with Python the code below should at least give you an inkling on how to use the API from Python. Or check out the code of transmageddon for how to use the asynch version of the API.

#!/usr/bin/env python
# gst-python

import os
import sys

import pygtk
pygtk.require('2.0')
import gobject
gobject.threads_init()
import pygst
pygst.require('0.10')
import gst
import gst.pbutils

class discover:
    def __init__(self):
	self.audiostreams=[]
    def set_file(self,file):
        self.file_uri=("file://"+filepath)
	newitem = gst.pbutils.Discoverer(50000000000)
	self.info = newitem.discover_uri(self.file_uri)

	self.streaminfo=self.info.get_stream_info()
	self.duration= (self.info.get_duration()/1000000000.0)
	self.container = self.streaminfo.get_caps()
	seekbool = self.info.get_seekable()
	if seekbool is True:
		self.seekable="Yes"
	else:
		self.seekable="No"
	audiostreamcounter=-1

	for i in self.info.get_stream_list():
		audiostreamcounter=audiostreamcounter+1
		if isinstance(i, gst.pbutils.DiscovererAudioInfo):
			audiocaps=i.get_caps()
			self.audiostreams.append(gst.pbutils.get_codec_description(audiocaps))
			self.audiotags=i.get_tags()	

		if isinstance(i, gst.pbutils.DiscovererVideoInfo):
			self.videocaps=i.get_caps()
			self.videotags=i.get_tags()
			interlacedbool = i.is_interlaced()
			if interlacedbool is True:
				self.interlaced ="Yes"
			else:
				self.interlaced="No"
			self.videoheight=i.get_height()
			self.videowidth=i.get_width()


    def create_report(self): # Create properties report
		print "Analyzing " + str(self.file_uri)
		print "Topology:"
		print "  container: " + gst.pbutils.get_codec_description(self.container)
		beancounter=0
		for item in self.audiostreams:
			beancounter=beancounter+1
			print "    audio stream " +str(beancounter) + ": " + self.audiostreams[beancounter-1]

		print "    video stream: " + gst.pbutils.get_codec_description(self.videocaps)
		print " "
		print "Properties:"
		print "  Duration: " + str(self.duration)
		print "  Seekable: " + str(self.seekable)
		print "  Video interlaced: " + str(self.interlaced)
		print "  Video height: " + str(self.videoheight)
		print "  Video width: " + str(self.videowidth)
		print "  Audio Tags: " 
		audiofile_tags = {}
		for akey in self.audiotags.keys():
			audiofile_tags[akey] = self.audiotags[akey]
			print "      " + akey, '\t', self.audiotags[akey]
		print "  Video Tags: "
		videofile_tags = {}
		for vkey in self.videotags.keys():
			videofile_tags[vkey] = self.videotags[vkey]
			print "      " + vkey, '\t', self.videotags[vkey]

if __name__=="__main__":
    if len(sys.argv)>1:
        file = sys.argv[1]
        pwd = os.getcwd()
        filepath = os.path.join(pwd,file)
        discovering = discover()
	discovering.set_file(file)
        discovering.create_report()
    else:
        print "select an audio file"



This program should give you an output like this one:

python newdiscoverer.py /home/cschalle/Videos/diracpromo.vob 
Analyzing file:///home/cschalle/Videos/diracpromo.vob
Topology:
  container: MPEG-2 System Stream
    audio stream 1: MPEG-1 Layer 2 (MP2)
    video stream: MPEG-2 Video
 
Properties:
  Duration: 735.672
  Seekable: Yes
  Video interlaced: No
  Video height: 576
  Video width: 720
  Audio Tags: 
      audio-codec 	MPEG 1 Audio, Layer 2
      bitrate 	384000
      has-crc 	True
      channel-mode 	stereo
  Video Tags: 
      bitrate 	8000000