Cutting VCDs or How I Learned to Stop Worrying and Love GStreamer
For a few weeks, I was looking for a way to cut three VideoCD images I had sitting on my hard disk for a while (three years!?) and
write the results (with other things) to a DVD. As I'm
always short in space, decided to cash those 4.5GB this time and so started my GStreamer pilgrimage...
Normally, if it was audio, I would have done this:
freq=44100
channels=2
depth=16
bitrate=$((freq*channels*depth))
mplayer -ao pcm:nowaveheader:file=/dev/fd/10 -really-quiet "$infile" </dev/null 10>&1 &>/dev/null |
tail --bytes=+$((start*bitrate/8)) |
head --bytes=$((length*bitrate/8)) |
lame --quiet -r /dev/stdin "$outfile.mp3"
(works like a charm.) This is clean. This is what Unix is supposed to be. This shows various rules of Unix philosophy in action. For example, I don't like spending two hours to figure out how to compress using
mencoder
, so I simply use
lame
without selling the rest of my pipeline to it. But for video, it's more complex. I decided to finally go the GStreamer way instead of finding my way through
man mplayer
for the zillionth time (I suspect it may not be feasible using
mplayer
.)
Meeting: Being the good GNOME hacker that I am, I decide to try out gstreamer 0.10, although I already have 0.8 installed on my system. So I check out and build gnome-python (and lots of prereqs), gstreamer, gst-plugins-base, gst-plugins-good, and gst-plugins-bad stuff from HEAD. Multiple bugs are filed in the process and I
go mad by the sheer amount of packages spitting Werror on my face... At this point I call it a night (morning should have been more appropriate.)
Attraction: I read the gstreamer FAQ and start experimenting with
gst-launch
. Pretty excited about finding the
Pango element and wanting to try it out. So I figure what playbin is, and build a few pipelines from the FAQ to use decodebin. Apart from it crashing randomly (which turned out updating liboil fixes), it seems to be working. I figure out that
GNonLin should do what I want, i.e. reinventing
head
and
tail
. What I fail to figure out is how to use
PiTiVi. But in the end, I fail to find any video on my harddisk that it can play, and I give up.
Separation: Days later. For the first time in my involvement with Free Software, I feel what the users are possibly feeling most of the time and I'm aimless as a developer. At this point I the least I care about is the Free Software license of the code and what it allows me to do. All I see is that I just want to cut the damn clip out of the VCD image and I cannot. Decide to go back to gstreamer 0.8. At least I have an installation of it that does play my movies, out of synch though. I manage to find and compile a version of GNonLin that works with 0.8, but trying to run any useful pipeline that contains a gnlfilesource element with
gst-launch
stalls at PREROLLING and never enters PLAYING mode. Need another few days of break.
Reconciliation: From the Accounts Team work I remember bilboed, who is the author of PiTiVi and GNonLin. I find him on #gnome-hackers, and he enlightens me that the most decoders I want (MPEG, MAD, ...) are in gst-plugins-ugly, one module that I simply missed. Installing -ugly (after figuring out *why* it's not enabling each external plugin first) did it. Now I could play my videos using gst 0.10. Using Pango to show subtitles using playbin still doesn't work though. I also found out that #gstreamer on freenode is a much better place to ask questions than #gnome-hackers is. Turned out (via its author) that GNonLin needs a glib main-loop to run, and so cannot be used via
gst-launch
. I still don't understand why, but bilboed was so nice that he wrote a short Python piece to use the gnlfilesource to delay the audio track of an input movie. It actually revealed a couple bugs in GNonLin it seems and took a few days until he thought the script should work. It segfaults on most of the video files I have (segfaulting Python that is), but I could finally find a very short piece (a 600kb MPEG) that it *plays*. No video window though, only voice. Playbin refuses to play the test piece for what seems to be a playbin bug with very short files. Bilboed's experience with the test case was different: he had video but no voice. So he patched the script to *fix* the voice issue and was wondering how it worked for me :). Anyway, after boring myself with it for a few hours, sleep overcomes and I give up.
[The movie ends here, so this stage doesn't have a name]In my dreamz we were relaxing in the
Ein-stein Cafe (man, they do have the best chicken wings in T.O.) on College St. on a Friday night and walked to my place afterward, for tea and watching a few episodes of
Barareh (an Iranian TV show.) Everybody left soon after midnight and it was only me and Alireza. I dreamed I started my weekly harddisk cleanup and passed by the 4.5GB thing again and so asked Alireza whether he had any tool to cut a VCDs into clips. Hell he did. There was this tiny Windoze app in his old stuff called
vcdcut
that did that and just that. Setting up a a samba share and voila, two hours later all that was left was my the clips and no VCD images anymore. I felt something heavy hitting my head from the back and glanced at the floor that was approaching with increasing speed...
When I opened my eyes I was in a court room. There were masters McIlroy and Thompson sitting in the jury and master Kernighan too. There were the GStreamer developers standing in the defendant's place, accused of violating several laws of Unix philosophy and customer lock-down via running on a proprietary pipeline, different from that of the Unix systems. I heard Eric Raymond whispering "got to add this case to my
book."
All of a sudden I could hear a loud noise boom booming all around my head, like when xmms jumps to a song with a much higher volume level... And I wake up.
When I really woke I was frozen in between
I didn't know who I was, it was a dream inside a dream
It's all a dream
Oh what a dream
I had a dream
Epilogue:GStreamer is an exciting framework. One that opens up a lot of new possibilities in Linux multimedia. There are
a few bugs here and there, but they will hopefully by fixed by the time for
10x10.
Writing both
stdinsrc and
stdoutsink gstreamer elements should be extremely easy, and that would make it possible to use gstreamer with Unix pipelines, like the one I used for cropping audio. Same thing about writing
head and
tail elements (which is what the GNonLin elements are supposed to do, among other things.)
A notable side-effect of lack of Unix philosophy on Windoze land is that people write (non-free, fwiw) tiny applications that do one instantiation of one problem and only that. By that I mean you find an application to cut a piece out of a VCD image. You find another to cut a piece out of an MP3. You find another to convert a WMA to MP3. Another one to convert MP3 to WMA. Seriously. While that makes a Unix hacker laugh and look down his nose to the poor Windoze user, there has been moments in my pilgrimage that I wished there was a 50kb binary I could download and run that would cut that piece out of the VCD image and just that...
On the other end of the spectrum, it's a source of controversy where the modularity line should be drawn. There are various widely-used featureful tools that are both a proof for and against the
do one thing and do it well essence of the
Unix philosophy. Emacs is
one of them, a rather clean one. Mplayer and ImageMagick are two other, nasty ones. They are not extensible, feature-packed to the state of decreasing user's performance, and simply ugly. Yet they do the job no other pipeline will do. Whether GStreamer is the true way to implement what Mplayer does, we still need to figure out. But better integration with the traditional Unix practices (whatever that means) is something to be explored.
Update: Apparently GStreamer already has stdinsrc and stdoutsink. They are called fdsrc and fdsink.