2005年5月20日

Python with Last-Modified-Time

Doing web programing sometime need to parse/create the Last-Modified-Time, Last-Modified-Since, or Date... values in the RFC2822 format. And I always forget the format string. Here we go:




>>> import time
>>> time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
'Fri, 20 May 2005 11:08:40 GMT'
>>> t = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(time.time()))
>>> t
'Fri, 20 May 2005 11:22:20 GMT'
>>> time.strptime(t, "%a, %d %b %Y %H:%M:%S GMT")
(2005, 5, 20, 11, 22, 20, 4, 140, -1)


So what these tell us? Well, the format string is:
"%a, %d %b %Y %H:%M:%S GMT"


That's it. Yes, it is GMT time, no timezone there.

2005年5月17日

Scale Gstreamer Video with GTK+

改变 Gstreamer 视频在 gtk drawingarea 的大小,比例。



Spent days on how to let a gstreamer video sink know that the video window size was changed. Finally, I realized that I missed a line of code in totem that just did this.



In order to have the video in gstreamer respect the aspect ratio of a video, you have to put the video window (normally a gtk drawingarea) inside a gtk aspectframe. However, after the aspectframe is resized to follow the video aspect ratio, you have to call video_sink.expose() in order for the video sink to resize itself. I am using gstreamer python binding, of course. So many 'have to's that are not documented!



The expose() method is an method of interface GstXOverlay. So any video sink that implements the interface should have a expose() method (gstream name is gst_x_overlay_expose(xid). Sucks, huh?)

Debian: Find programs? 寻找程序包?

Since I'm talking about Debian tricks, here is one more trick on dealing with debian packages:

Looking for program:


Sometime, people tell you to use a command to solve your problem, but you don't have this command on your system, what you do you?


You can install apt-file and run:


user$ apt-file update
user$ apt-file search command_name

"update" will download/update package lists from the apt servers. "search" will search a filename from all the packages on the apt servers, even for the files that you did not installed on your system.



想知道一个命令或者一个文件在哪个程序包里吗?比如别人让你跑一个程序,但是你发现你的系统里没有这个程序,怎么办?你可以安装 apt-file这个程序,然后跑下面的命令:


user$ apt-file update
user$ apt-file search command_name


"update" 让 apt-file 从网上下载和更新所有程序包的内容,"search"让它在程序包里搜索一个文件名,这个文件名所在的程序包有没有安装无所谓。当然这个功能其他的几个 deb/apt 应用程序也可能有,不过我几年前开始用这个,用着顺手,就没有发掘新的程序了。



当然,如果你装了 synaptic ,可能什么窍门都不用了,它全包了。

Debian: Changelog before install? 升级前看看更新记录?

Before update a package on Debian, you might want to find out what have been changed in that package. Here is how I always do:



在 Debian 里升级一个程序包的时候,你可能会想知道这个包的最新的更新记录,看看它值不值得升级。有时候只是修改说明文件里的笔误,升级没意思。我一般这么做:



reportbug package:


user$ aptitude changelog reportbug


Yes, it is simple, but you might not know before I told you. And apt-listchanges is more powerful but it is an extra package to install.



虽然简单,我不说你却未必知道。apt-listchanges 更强大些,不过它得另装一个包。

2005年5月11日

Python with Gstreamer

OK, so what if we use python and the playbin of gstreamer? Well, that can be done in a few lines:

player.py



#!/usr/bin/python
import sys, os.path
import pygtk; pygtk.require('2.0')
import gtk
import gst, gst.interfaces

def cb_eos(kele, data):
gtk.main_quit()
def cb_error(*args):
print args, args[2]

class Control:
def __init__(self, playbin, vsink,da):
self.fullscreen = False
self.play = playbin
self.vsink = vsink
self.da = da
def key_release(self, widget, event, *args):
if event.string in ['p', ' ']:
if self.play.get_state() == gst.STATE_PLAYING:
ret = self.play.set_state(gst.STATE_PAUSED)
else:
self.vsink.set_xwindow_id(self.da.window.xid)
ret = self.play.set_state(gst.STATE_PLAYING)
elif event.string == 's':
ret = self.play.set_state(gst.STATE_NULL)
elif event.string == 'q':
self.quit()
elif event.string == 'f':
if self.fullscreen:
widget.unfullscreen()
else:
widget.fullscreen()
self.fullscreen = not self.fullscreen
def quit(self, *args):
ret = self.play.set_state(gst.STATE_NULL)
gtk.main_quit()


def main():
fname = sys.argv[1]
absfname = os.path.abspath(fname)
uri = 'file://%s' % absfname

# Setup video/audio sink and playbin
vsink = gst.element_factory_make('xvimagesink')
asink = gst.element_factory_make('esdsink', 'asink')
playbin = gst.element_factory_make('playbin', 'playbin')
playbin.set_property('video-sink', vsink)
playbin.set_property('audio-sink', asink)
playbin.set_property('uri', uri)

playbin.connect('eos', cb_eos)
playbin.connect('error', cb_error)

win = gtk.Window(gtk.WINDOW_TOPLEVEL)
da = gtk.DrawingArea()
ctr = Control(playbin, vsink, da)
win.add(da)
win.connect('key-release-event', ctr.key_release)
win.connect('delete-event', ctr.quit)
win.show_all()
gtk.main()
playbin.set_state(gst.STATE_NULL)

if __name__ == '__main__':
main()
# vim:ts=8:sw=4:expandtab



You can just type


player.py test.avi


The key bindings are:





p or spacePlay/pause the movie
sStop the movie
fFullscreen/un-fullscreen
qQuit the program.



Note:



  • You have to import gst.interfaces for many methods to exist, e.g. xvimagesink.set_xwindow_id().

  • It seems that the binding between gstreamer video window and gtk+ window have to happens later. That's why we set_xwindow_id() before starting to play the movie.

  • You need to use a gtk.AspectFrame for keeping the aspect ratio of the movie.

2005年5月10日

gstreamer lauch video!

OK, here after installed the gstreamer-ffmpeg on my Debian box from deb http://debian.ressukka.net/ unstable/ , I have to test it.



I use this gst-launch command for my test. First for this clip I have, I use mplayer to find out what the codecs were used. Well, it is a .avi with msmpeg4v2 video codec and mp3/mp2 mad audio codec. Since my mplayer already installed w32codecs, I'm all set. Now we are ready, here is the command I used to play the clip with gst-launch:



  • gst-launch filesrc location=test.avi ! ffdemux_avi name=demuxer ! { queue ! ffdec_msmpeg4v2 ! ffcolorspace ! xvimagesink } { demuxer. ! queue ! mad ! esdsink }



Some notes:

  • The elements used are:









    filesrc: load video file from source.
    ffdemux_avi: demux avi into streams, from the gstreamer-ffmpeg plugin.
    queue: Since we want to play both video and audio, need to use threads for video and audio playing at the same time. queue is used to bridge a thread to other threads.
    ffdec_msmpeg4v2: well, we want to play a msmpeg4v2 video.
    ffcolorspace: convert the decoded video stream into something our video display can understand.
    xvimagesink: we use xv as our video output devicde. Other options: sdlvideosink, ximagesink. Somehow, autovideosink don't work for me.
    mad: this element handle mp3 audio codec.
    esdsink: I use esd as audio output device. Of cause alsasink should work too, if it is not used by someone else.

  • There are 2 threads as denoted by the curly bracket {...}. Since we want to play the video and audio at the sametime, we put them together using the blocks.



    To make sure our audio links from the demuxer ffdemux_avi, we assign a name to that demuxer instant, "demux". At audio thread, we link it using the name "demux." to link with our audio decoder.



    Notice the Dot->. after the "demux". Because this "demux" is not a real element, it is a ghost element, so we tell gst-lauch about this by putting a dot(.) after "demux".




Wow, what a mess! How about make it simpler? We all know gstreamer can autodetect all those codecs. OK, the element that do the autodect is decodebin. So here we go:



  • gst-launch filesrc location=test.avi ! decodebin name=debin ! { queue ! xvimagesink } { debin. ! queue ! esdsink }



That's it! We don't even need to know all the codecs things. The element "playbin" does not work for me because its video-sink/audio-sink properties only take element objects as paramenters. Cannot do that with gst-launch.



Gstreamer with gstreamer-ffmpeg and w32codecs are fun.

2005年5月9日

Compile python code? 编译蟒蛇程序?

You cannot but there are ways to hide your python code by compiling part of your program. How about a C program with a main() and use python's C API? Well,
pyrex
can do that.



All you have to do for a stand alone C program in Pyrex are:



cdef extern from "Python.h":
void Py_Initialize()
void Py_Finalize()
void PySys_SetArgv(int argc, char *argv[])

# Declare extension init function as a C function.
cdef public void initdemo()

# Define main() and declare it as "public"
cdef public int main(int argc, char *argv[]):
Py_Initialize() # Init Python environment
PySys_SetArgv(argc, argv) # Fill in sys.argv
initdemo() # Init our Pyrex generated main module.
# Do something here...
Py_Finalize() # When done, clean up Python env.





The following is a real example which actually do something. We use the re module to demostrate the power of python here:



demo.pyx:


cdef extern from "Python.h":
void Py_Initialize()
void Py_Finalize()
void PySys_SetArgv(int argc, char *argv[])

cdef extern from "stdio.h":
int printf(char *format, ...)

cdef public void initdemo()

def regex(msg):
import re
a = re.findall(r'as\w*', msg)
return a

cdef public int main(int argc, char *argv[]):
Py_Initialize()
PySys_SetArgv(argc, argv)
initdemo()
msg = 'Jump it as high as an ass, asshole!'
print 'Searching "as" from "%s"' % msg
m = regex(msg)
for i in m:
print 'Match:', i

cdef int count
count = len(m)
printf("Total: %d\n", count)
Py_Finalize()

# vim:ts=8:sw=4:expandtab



Makefile: Link with libpython.

all: demo

demo: demo.c
gcc -g -O2 -I/usr/include/python2.3 -lpython2.3 -o demo demo.c

demo.c: demo.pyx
pyrexc demo.pyx

.PHONY:
all



Run ./demo now will show you how things go. We hide everything in demo.pyx now!



As you can see, every C function that is used inside .pyx need to be explicitly declared in a cdef extern from "cheader.h": block. Other than that, Pyrex also cannot do list comprehension and generator. So do your generator or comprehension in a .py module and import to the .pyx.



And of cause if you don't write pure C inside .pyx, the resulting program will not be faster than a pure .py program.