Ubuntu Opportunistic Developers Week March 2010 - Building multimedia into your app with GStreamer - Laszlo Pandy - Mar 2 2010

(03:01:51 PM) laszlok: Alright I guess that's me
(03:02:02 PM) laszlok: I'm going to be talking about GStreamer
(03:02:35 PM) laszlok: I'm not sure how much you guys know already, so if you have any questions or I missed something, please ask in #ubuntu-classroom-chat
(03:02:47 PM) laszlok: [SLIDE 1]
(03:03:18 PM) laszlok: Seems the schedule in lernid isn't working
(03:04:13 PM) laszlok: I'll get a link for those who aren't using lernid as well
(03:05:08 PM) laszlok: For those that do still see the gwibber slides, is the schedule list loaded? On my lernid neither is there
(03:05:42 PM) laszlok: Lets do it manually then:
(03:07:11 PM) laszlok: Thanks for reporting guys, it must be a server issue
(03:08:01 PM) laszlok: I'm gonna start now and you can follow along manually from the link above
(03:08:10 PM) laszlok: First slide!
(03:08:41 PM) laszlok: So I'm talking about adding gstreamer support to your app
(03:08:51 PM) laszlok: This means multimedia stuff
(03:08:58 PM) laszlok: audio and video all that cool jazz
(03:09:25 PM) laszlok: GStreamer can do pictures too, but most apps use separate libraries for images because of performance
(03:09:39 PM) laszlok: However I am not talking about playing event sounds like an alert
(03:10:02 PM) laszlok: those sounds which are really short and you just play, never pause, seek, etc
(03:11:01 PM) laszlok: GStreamer is overkill for that, and there are better libraries for that (which could be covered in another talk)
(03:11:14 PM) laszlok: Second slide!
(03:12:08 PM) laszlok: GStreamer is a framework for putting decoders, filters, encoders, file readers, etc. together
(03:12:35 PM) laszlok: if you are writing a decoder to integrate with ubuntu you are going to want to know about the framework aspects
(03:12:47 PM) laszlok: [SLIDE 2]
(03:13:51 PM) laszlok: but for us, in most cases we only care about GStreamer as a library
(03:14:16 PM) laszlok: and GStreamer is a very good library, it takes very little code to achieve a great deal in your application
(03:14:36 PM) laszlok: Slide three!
(03:15:57 PM) laszlok: GStreamer can automatically detect which plugin to use depending on the protocol (file://, http://, etc) the media container, codec
(03:16:14 PM) laszlok: you just have to tell it where to get the data and it works like magic
(03:17:13 PM) laszlok: another important aspect is that it spawns its own threads for each stream and provides a nice interface so we don't have to deal with it
(03:17:58 PM) laszlok: when you are playing video there is a thread for audio and one for video, but all the signals come in to your main thread like gtk callbacks; nice and clean
(03:18:09 PM) laszlok: QUESTION: How portable is it? Can I make gstreamer apps for Win/Mac?
(03:18:17 PM) laszlok: yes you can
(03:18:24 PM) laszlok: its supports many platforms
(03:19:05 PM) laszlok: I am part of the Jokosher project which uses GStreamer for an audio multitracker
(03:19:16 PM) laszlok: and we have been doing windows releases for more than a year i think
(03:20:04 PM) laszlok: the official releases don't have builds for any platform, but like the GStreamer PPA for ubuntu there is a win-builds which has all the latest releases for windows
(03:20:25 PM) laszlok: I don't have any experience using it on the Mac, but I know it is supported
(03:20:40 PM) laszlok: [SLIDE 4]
(03:20:48 PM) laszlok: okay now we get into the real stuff
(03:21:08 PM) laszlok: today's talk is mostly a high level usage of gstreamer, but i think it is important to understand a few concepts
(03:21:42 PM) laszlok: QUESTION: This is a really specific one, and may want to wait, but can I seek into a movie and display a still thumbnail?
(03:22:00 PM) laszlok: yes, remind me about that at the end and I will tell you specifically how to do it
(03:22:30 PM) laszlok: So Gstreamer is concerned with moving data
(03:22:50 PM) laszlok: data flow happens inside a pipeline
(03:23:03 PM) laszlok: there are a bunch of elements all linked together
(03:23:28 PM) laszlok: the source(s) provide data to the pipeline, and the sink(s) take it out and put it somewhere
(03:24:29 PM) laszlok: an example pipeline would start with a file source, move it through a decoder, pass it to audioconvert (which makes sure it is in the right format) and that would pass it to the Pulseaudio sink
(03:25:04 PM) laszlok: A bin is another important concept. It is just a collection of elements within a pipeline
(03:25:14 PM) laszlok: you can think of it as a pipeline inside a pipeline
(03:25:38 PM) laszlok: [SLIDE 5]
(03:26:03 PM) laszlok: here are some example sources
(03:26:12 PM) laszlok: gstreamer has lots
(03:26:49 PM) laszlok: giosrc is important because it provides all the protocols of the gnome virtual file system
(03:27:21 PM) laszlok: if you run the debugging tool gst-inspect-0.10 with no arguments in the terminal it will tell you alll the plugins you have installed
(03:27:24 PM) w1nGNUtz_ is now known as w1nGNUtz
(03:27:54 PM) laszlok: gst-inspect-0.10 pulsesrc will give you all the info about the pulse audio source
(03:28:30 PM) laszlok: [SLIDE 6]
(03:28:35 PM) laszlok: same deal with sinks
(03:30:12 PM) laszlok: QUESTION: how does changing framerates fit into the pipline?
(03:31:05 PM) laszlok: since its been brought up i will quickly cover another topic
(03:31:23 PM) laszlok: the link between each element has a thing called caps (short for capabilities)
(03:31:41 PM) laszlok: it specifies what kind of data is allowed to be sent from one element to another
(03:32:08 PM) laszlok: for example pulsesink does not want to receive ogg vorbis data, it wants raw audio
(03:32:26 PM) laszlok: so we have to feed it through the ogg vorbis decoder first
(03:33:05 PM) laszlok: it is possible to manually specify the caps of each link, so you can say you want this audio converted to 44100Hz before sending to pulsesink
(03:33:21 PM) laszlok: in the same way you can force the framerate of a video stream
(03:33:52 PM) laszlok: but if you get the caps wrong, the elements will complain that they can't link
(03:34:05 PM) laszlok: so its a bit more advanced, we won't be doing caps today
(03:34:18 PM) laszlok: [SLIDE 7]
(03:34:33 PM) laszlok: so here is an example pipeline
(03:34:49 PM) laszlok: the gstreamer language syntax has the ! meaning link to
(03:35:11 PM) laszlok: there is a debugging tool which uses this syntax, and you can test out all sorts of cool pipelines
(03:35:20 PM) laszlok: every can try:
(03:35:45 PM) laszlok: gst-launch-0.10 audiotestsrc wave=ticks ! pulsesink
(03:36:15 PM) laszlok: gst-inspect-0.10 audiotestsrc will tell you near the bottom what other types of waves you can use
(03:36:43 PM) laszlok: [SLIDE 8]
(03:37:10 PM) laszlok: as I have mentioned there is all sorts of complicated stuff going on in gstreamer
(03:37:39 PM) laszlok: but playback is a pretty simple use case, so they invented playbin2
(03:38:01 PM) laszlok: it is used by totem and many gstreamer apps who just want to play audio and video
(03:38:27 PM) laszlok: it internally manages almost everything for us
(03:39:05 PM) laszlok: reading from the right protocol, finding decoders, it even handles subtitles and can do gapless playback
(03:39:22 PM) laszlok: [SLIDE 9]
(03:39:34 PM) laszlok: so lets try a really simple playbin example using some python
(03:39:52 PM) laszlok:
(03:40:28 PM) laszlok: as you can see in the code, we have to import gst and create a new playbin2 object
(03:41:03 PM) laszlok: all gstreamer plugins are dynamically loaded, so you have to use the factory to create it
(03:41:30 PM) laszlok: gst.element_factory_make('playbin2') will fail if the plugin 'playbin2' is not installed
(03:41:51 PM) laszlok: the next step we set the URI
(03:42:11 PM) laszlok: then we get the bus, which allows us to monitor the pipeline through signals, just like in GTK
(03:42:35 PM) laszlok: we can attach a callback to the "message::eos" signal (EOS is end of stream)
(03:42:52 PM) laszlok: then we set the playbin to the playing state
(03:43:11 PM) laszlok: there are four states in gstreamer: NULL, READY, PAUSED and PLAYING
(03:43:32 PM) laszlok: NULL is for when you want to free the resources and destroy the object
(03:44:14 PM) laszlok: after we set the state we start the mainloop so we get receeve signals
(03:44:21 PM) laszlok: *receive
(03:44:34 PM) laszlok: any questions about this code?
(03:44:53 PM) laszlok: [SLIDE 10]
(03:45:13 PM) laszlok: QUESTION: what if it's a file not a url?
(03:45:29 PM) laszlok: do it like file:///home/laszlo/... (it has to be an absolute path)
(03:45:50 PM) laszlok: QUESTION: can you elaborate on states? what state a pipeline should have if we don't want to destroy it, but rather play next source?
(03:46:03 PM) laszlok: you can have it in whichever you like
(03:46:16 PM) laszlok: gstreamer allows the pipeline to be changed while its playing
(03:46:42 PM) laszlok: though its probably best to move it to paused, switch the uri, and put it back to playing
(03:47:08 PM) laszlok: QUESTION: what other proteries can we set with playbin.set_property()? And sourcefile is it allway an uri?
(03:47:16 PM) laszlok: gst-inspect-0.10 playbin2
(03:47:21 PM) laszlok: that will tell you about the properties
(03:47:43 PM) laszlok: playbin2 only deals with URIs, but those can be file:/// ones too
(03:47:52 PM) laszlok: QUESTION: and if we want to stop playing and restart it from beginning?
(03:48:31 PM) laszlok: you should set it to PAUSED and seek to the start (seeking is slide 17 if we get there)
(03:48:58 PM) laszlok: to clarify PAUSED means the same thing as PLAYING except that the data is not moving
(03:49:09 PM) laszlok: the data is there on the edge, but the damn is closed
(03:49:18 PM) laszlok: if you have a video in PAUSED you will see the first frame
(03:49:59 PM) laszlok: QUESTION: does using playbin also handle installing packages for missing codecs like with mp3's? Or that's something that should still be manually programmed?
(03:50:21 PM) laszlok: i dont think playbin does this itself
(03:50:40 PM) laszlok: GStreamer will send an error on the pipeline ("missing codec!")
(03:51:01 PM) laszlok: and you can catch the error and use another module (import gst.pbutils) to launch the codec install window
(03:51:30 PM) laszlok: okay everyone got that code from slide 10?
(03:51:44 PM) laszlok: its a GTK window, pretty simpel
(03:51:51 PM) laszlok: its needs some gstreamer love
(03:51:58 PM) laszlok: [SLIDE 11]
(03:52:34 PM) laszlok:
(03:52:48 PM) laszlok: [SLIDE 12]
(03:53:35 PM) laszlok:
(03:53:46 PM) laszlok: and back to the code
(03:54:19 PM) laszlok: so we are gonna take the playbin2 example and put it into the GUI class
(03:54:58 PM) laszlok: just make sure all code in __init__() is before the call to self.main_window.show_all()
(03:55:03 PM) laszlok: [SLIDE 13]
(03:55:35 PM) laszlok: on_finish becomes a class method, and we update the GUI when it is called
(03:55:47 PM) laszlok: whoever was asking about to restart from the beginning, this is it
(03:56:02 PM) laszlok: seek_simple, FORMAT_TIME, to position 0
(03:56:19 PM) laszlok: [SLIDE 14]
(03:56:37 PM) laszlok: this is straightforward
(03:56:56 PM) laszlok: in the button handler we either set the state to PLAYING or PAUSED
(03:57:26 PM) laszlok: right before we do gtk.main_quit() we should set the state to NULL otherwise gstreamer will print an error on the console about resources not being cleaned up properly
(03:57:34 PM) laszlok: [SLIDE 15]
(03:57:54 PM) laszlok: if you guys are building this code, it should sorta work now
(03:58:08 PM) laszlok: QUESTION: the uris in playbin need to be absolute, or I can write them like relative paths for files?
(03:58:23 PM) laszlok: I have not figured out a way to make file:/// work without absolute paths
(03:58:46 PM) laszlok: you should get the current working durectory using the os.path.abspath('.') command in python
(03:59:06 PM) laszlok: [SLIDE 16]
(03:59:28 PM) laszlok: heres the tricky part, we have to attach the video to our GTK window
(03:59:56 PM) laszlok: playbin2 has a video-sink property which allows us to switch where it sends the video
(04:00:31 PM) laszlok: we should wait until the widget is realized before connecting it, cause it might not be on the screen and video_area.window will be None
(04:00:54 PM) laszlok: then we just set the xwindow id
(04:01:14 PM) laszlok: and we're done
(04:01:22 PM) laszlok: [SLIDE 17]
(04:01:44 PM) laszlok: heres how to seek from the value on the slider
(04:01:50 PM) laszlok: [SLIDE 18]
(04:02:14 PM) laszlok: if there any questions about that, ask me
(04:02:20 PM) laszlok: [SLIDE 19]
(04:02:43 PM) laszlok:  QUESTION: How do I seek into a movie and display a still thumbnail?
(04:02:52 PM) laszlok: thanks for reminding me
(04:03:18 PM) laszlok: you should keep the state in PAUSED so that the first frame shows
(04:03:24 PM) laszlok: and then seek with FLUSH and KEY
(04:03:43 PM) laszlok: this is important because if it is plaused, there is data in the pipeline thats not moving
(04:04:03 PM) laszlok: FLUSH will tell the elements to throw out the old data and only use the data from the new position
(04:04:27 PM) laszlok: KEY_UNIT will tell the decoder to seek to a key frame, so you don't get a partially decoded blocky frame from the video
(04:04:50 PM) laszlok: QUESTION: what do that seek flags mean?
(04:05:05 PM) laszlok: is it clear from what i said on slide 18?
(04:05:17 PM) laszlok: [SLIDE 18]
(04:05:50 PM) laszlok: [SLIDE 19]
(04:06:32 PM) laszlok: if you have not seen gobject.timeout_add() before, it will call your function at the time interval given as long as the mainloop is still running
(04:06:52 PM) laszlok: 100 means 100 milliseconds, or 10 times per second
(04:07:20 PM) laszlok: if you have some other intensive operation which is blocking the mainloop it will be called much less often and your GUI will be unresponsive
(04:07:41 PM) laszlok: so every 100ms we query the position and update the slider, make sense?
(04:07:45 PM) laszlok: [SLIDE 20]
(04:08:16 PM) laszlok: here I am querying both the position and duration, because sometimes the duration changes
(04:08:34 PM) laszlok: for many audio types like mp3, the duration is an estimate
(04:09:10 PM) laszlok: there is no way to know the exact length without playing the file to the end and saving the result
(04:09:29 PM) laszlok: QUESTION: Why would the duration change? for streaming files?
(04:09:48 PM) laszlok: often with streaming files you don't know how long it is, the duration query will fail
(04:10:26 PM) laszlok: other files like mp3 i mentioned the duration is estimated by calculating it form the size of the file and the bitrate
(04:10:47 PM) laszlok: if the file is a poorly encoded variable bitrate file, the duration estimate may change
(04:11:08 PM) laszlok: gstreamer requires you specify the format you want
(04:11:21 PM) laszlok: but almost always we want TIME (which comes back in nanoseconds)
(04:11:36 PM) laszlok: you can call query bytes or percent for example
(04:11:52 PM) laszlok: [SLIDE 21]
(04:12:08 PM) laszlok: so once we have the values from the query here is how we update the slider
(04:12:26 PM) laszlok: make sure you block the on_slider_change function or that will be called with you do set_value()
(04:12:38 PM) laszlok: [SLIDE 22]
(04:12:54 PM) laszlok:
(04:12:59 PM) laszlok: heres the completed code
(04:13:31 PM) laszlok: I added a little thing there to always read the file from the current directory
(04:13:50 PM) laszlok: 120 lines and you can do the basics of what totem does
(04:14:14 PM) laszlok: thanks guys, i'm just gonna answer questions now
(04:14:22 PM) laszlok: QUESTION: possible to extract/record a slice of audio/video from a file to a file ? faster than real-time ? (yes/no answer is enough)
(04:14:31 PM) laszlok: yes it is possible
(04:15:01 PM) laszlok: if you don't have an element which requires real time (like going from files to files) gstreamer will go as fast as possible
(04:15:47 PM) laszlok: to extract slices of audio/video files the elements you want are in the gnonlin package
(04:15:54 PM) laszlok: they are used by pitivi for example
(04:16:18 PM) laszlok: QUESTION: is it possible to seek to/display a still of a non-keyframe?
(04:16:36 PM) laszlok: yes, i believe this is what happens when you leave out the KEY_UNIT
(04:16:55 PM) laszlok: it will take longer to seek, because the decoder has to find a key frame and decode everything after that to get the full frame
(04:17:09 PM) laszlok: but this is what totem does for its frame-by-frame step feature
(04:17:48 PM) laszlok: QUESTION: Can you help me to find "wmap" codec for .wmv files?
(04:17:56 PM) laszlok: find me later in #jokosher and i'll see
(04:18:03 PM) laszlok: QUESTION: If I have a video in HD and only want to display it as a thumbnail, is this simple, and does gstreamer do clever stuff to provide low memory usage?
(04:18:38 PM) laszlok: gstreamer is fairly good with memory usage
(04:19:08 PM) laszlok: i believe the nautilus thumbnailer which gets those pictures of your videos uses gstreamer and just sets it to paused to extract a single frame
(04:19:24 PM) laszlok: sometimes it does use a lot of IO though
(04:20:14 PM) laszlok: okay so if the movie is playing, and you want a smaller copy of it
(04:20:41 PM) laszlok: this is just the same as when you scale down the totem window
(04:21:14 PM) laszlok: there is an element called tee to make copies of streams
(04:21:25 PM) laszlok: so you can have one small copy and one large playing at the same time even
(04:21:44 PM) laszlok: but for an HD video it sill have to decode the entire thing, then scale it down which will require a lot of cpu
(04:22:31 PM) laszlok: however the gstreamer magicians have some more tricks which are currently only prototype and use cairo to draw the scaled video directly instead of copying the HD video around
(04:22:55 PM) laszlok: you may have seen it on the planet, it sounds pretty much like what mattmole is looking for

MeetingLogs/OpWeek1003/Gstreamer (last edited 2010-03-02 22:28:32 by pool-71-182-100-128)