<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>iXce's blog &#187; Code</title>
	<atom:link href="http://guillaume.segu.in/blog/category/code/feed/" rel="self" type="application/rss+xml" />
	<link>http://guillaume.segu.in/blog</link>
	<description>Stuff that doesn’t matter</description>
	<lastBuildDate>Mon, 28 Feb 2011 22:28:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Use git as your blog data storage backend</title>
		<link>http://guillaume.segu.in/blog/code/298/use-git-as-your-blog-data-storage-backend/</link>
		<comments>http://guillaume.segu.in/blog/code/298/use-git-as-your-blog-data-storage-backend/#comments</comments>
		<pubDate>Thu, 22 Jul 2010 00:18:37 +0000</pubDate>
		<dc:creator>iXce</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[storage]]></category>

		<guid isPermaLink="false">http://guillaume.segu.in/blog/?p=298</guid>
		<description><![CDATA[A school friend, namely p4bl0, mentioned the idea of maintaining blog posts with git and a set of hooks which would produce the blog html from the contents of the repo. I loved the idea, but thought I could push it a little further&#160;: a blog engine which would use no other storage than git, [...]]]></description>
			<content:encoded><![CDATA[<p>A school friend, namely <a href="http://pablo.rauzy.name/">p4bl0</a>, mentioned the idea of maintaining blog posts with <tt>git</tt> and a set of hooks which would produce the blog html from the contents of the repo. I loved the idea, but thought I could push it a little further&nbsp;: a blog engine which would use no other storage than <tt>git</tt>, with the post subject and contents being the commit message subject and contents. A post-commit or post-receive hook then produces the html. As simple as that&nbsp;!</p>
<p>You can find the source in <a href="http://guillaume.segu.in/cgit/blogit.git/">BloGit git repo</a>, and see an example at <a href="http://aulo.in/blogit.html">BloGit example</a>. To use the source, you first have to pack it (using the <tt>pack</tt> script), which will merge the <tt>raw_post</tt> and <tt>raw_produce</tt>, producing a single <tt>post</tt> script (which I also included at the end of this post), which you can simply put in an empty directory and run it. It will unpack the other script (<tt>produce</tt>), initialize the git repo, and set the hooks. It&#8217;ll then prompt you for your post title and then open an editor for you to set your post contents. Save the file, and you&#8217;re done with your first post&nbsp;: check the index.html file which has been produced in the same directory. You can write your own stylesheet in the <a href="http://aulo.in/blogit-style.css">blogit-style.css</a> file. Further posts can be done with the same <tt>post</tt> script.</p>
<p>Yet, the best way is probably just to use the usual git workflow. To initialize the repo and all, run <tt>post --unpack</tt>, and to post <tt>post --raw</tt> or <tt>git commit --allow-empty</tt> (when using <tt>git commit</tt>, leave a blank line between the subject line and the rest of the post). You can also amend existing commits (using <tt>git commit --amend</tt>), use the GIT_AUTHOR_* environment variables to change the author, and so on. Since merge commits are skipped by the html generator, it should work just great for multi author blogging !</p>
<p>PS&nbsp;: I know this is JUST a git log pretty printer, and that the whole thing is pretty much trivial. I also know that using versionned files to store the posts would allow a lot of extra bonuses (such as automatically adding &#8220;Updated on &#8230;&#8221; mentions based on the commit log of each single file). I just thought the idea was fun <img src='http://guillaume.segu.in/blog/wp-includes/images/smilies/tongue.png' alt=':p' class='wp-smiley' />  There are probably a lot of things to improve, or a lot of smart git features to use there that I overlooked. Feel free to leave a line <img src='http://guillaume.segu.in/blog/wp-includes/images/smilies/smile.png' alt=':)' class='wp-smiley' /> </p>
<p><span id="more-298"></span></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #483d8b;">&quot;&quot;&quot;
 bloggit
 Author : Guillaume &quot;iXce&quot; Seguin
 Email  : guillaume@segu.in (or guillaume.seguin@ens.fr)
 Copyright (C) 2010 Guillaume Seguin
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor,
 Boston, MA  02110-1301, USA.
&quot;&quot;&quot;</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">subprocess</span>, <span style="color: #dc143c;">os</span>, <span style="color: #dc143c;">sys</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">base64</span>, <span style="color: #dc143c;">bz2</span>
CONTENTS_FILE = <span style="color: #483d8b;">&quot;POST_CONTENTS&quot;</span>
repo = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">abspath</span> <span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #dc143c;">os</span>.<span style="color: black;">chdir</span> <span style="color: black;">&#40;</span>repo<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span> <span style="color: black;">&#40;</span>repo, <span style="color: #483d8b;">&quot;.git&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
    <span style="color: #dc143c;">subprocess</span>.<span style="color: black;">call</span> <span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;git&quot;</span>, <span style="color: #483d8b;">&quot;init&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
produce_path = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span> <span style="color: black;">&#40;</span>repo, <span style="color: #483d8b;">&quot;produce&quot;</span><span style="color: black;">&#41;</span>
produce_script = <span style="color: #dc143c;">bz2</span>.<span style="color: black;">decompress</span> <span style="color: black;">&#40;</span><span style="color: #dc143c;">base64</span>.<span style="color: black;">b64decode</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;&quot;&quot;
QlpoOTFBWSZTWQf3J2wAAV//gFxQAYB6b/p/f+fe7r///+pQBd42u22yaV13O6AGigNBIy
aIp7Sn6DJiSaeSeo00PykD1M1B+inpA03qQDU0AJk0mhqNPRGgAGjQaAGgADTQDQEajUYp
im2RT9U9RkGTQZAZG1DIAAAcaMmRhGIBhNBgE0GgZMmjJkMIDCRQTQmCaJtI1GjT1GmhqA
0yPUNDQbUNDQepWIWGfa4d31kD+Y5Rb4yaILtfQ2R3ruai19rArmVtHwltw/M/SKgVz+HG
mewWVLlaRGi+TgiYISYkD6/fECu/rM0N4r5GtcYW1QTuePdDZ+sPg4zb9+44SCBIOFkkg0
x55udVuK1GAeJhbulbdkEl+jz2G9vfcAh34ns8FhgJwKe1v5KFIdM2Eyyw0GMr3CL7ZNzK
RBUsFKRqwtgoNy9FHvVS66uV+heJbKHRXDHFf4J1zs3cj8oXsMfU5N+644WGdjzvLX1aap
AI6VwBnkLDzalqgjQuC2soFnZlK5GCZb80ra1gw5fh4rnD8GUmm6eUSa5mYoiFgrwmamRK
zCz9yuRcozq5UKJtbq3sBSN1gjHDQ9z2BK7Dw2KcWMHm491MdO2B62ZoUOzKwCqoREREHo
ZjLn2p0HiWYoMBQRP8YCAzIgZUc2PJZaZrY/lODrob1VQg4U9L1ZRXpNBCelwBoEqUbFCs
BJpOCKGs54vnVO1AQDU6v9X0lEnEHuE1nlsy5pNWawCEYImSZc/AdREPAKBrlp73jcCryL
OAdFJcMZqdVjjE5gIfQY4Qjju9UdOBBmuXjz6uZhpsc3LhrDg1BQGoL4GyiDRmpTkImmc9
YlDd26K11qaiVDQ4wwITIEMyxMiLi274jeFlLrj8BpnXU87qMq6z2VQs6RN74sifuXfw7d
bOOm9bexNvdsxPvZDgG0cmUYClTHvcCFAMAdL+/IndGLRmvh7w/Bni8LAUfWdAcRyR4NDu
d49goYEMqHwDJLLa4vSbQRLptFdWVLzfSggKVzGtJIX1laSjr8I2BUTyiovpeiiyNQZu5Y
xresZCItgNp6ArbjFsCdRdgrgsw9tcrCa1Djq7A7ItXvGBWWs9IP0iIEAqnJ8xcH6Do9+1
UNVwkrSI5yC/J0ACce0NqBmWdEXp0KBIBWawoxJI66zSW55iEHoFRC0m8pYQICMFCcrrbT
Lg5yvtsbQNwVvMipGYYYTGs+czVBOZBcoWGD+l1xRtlbVMDwM0OpEVa3YMa1Ax/SosYOB4
WQVhQejJLSsL7hmrQh6V/tgUDTQ1C5tNdUOZckY4G+CyuDeTOgkEyPE+YjKpYtTRnMzumS
KImpjWQIAaLK2djnoVkRq5F+Sglu77bey0552SggnVQj0jKnFwwvhT3Y6oFpO4b8hmb1t7
A3yKE74eX6aqvJ7fP5wjXYonDYwumjqnrlv3obv7WsTxFpxVYpHCErmRUKGvwPUiSRWYMn
FZIzt0eUPDxJrGAamFrkeX3WwB0CmC/Jls/DLFV7uiPSiVaMNxy1GXfqziuzlXVsk2mQw2
AeNj5+QtDUFuUCZKDGMagNGpxIx/46nKSJsbprNPXGqzJVxVcglKGV5VysJDCqgRinuNbX
ChqDzZ6JXB8Rz0VF8aK+NMxXupulQOr1U6XP19can5uVqG7fs6Sa3Kq51jGOK9jDQ6fZf4
zXLr884Wq67SW+YyPk5OB1G0WmA1s8OiKQRBccciEMujm6A2LMvcIDogVk2GRbzgYrapcB
VDXEsgM9FJCQrvwaVw3C6i0FlYbnwXoJqe3bYlAjrGTVnqOSOpUOWcFXUdVlKmeOahYuhi
mEIgcCiiFMPnz5r1hXukd6HApZVuGq1kxn8DgWUiEMcRm+5FDm1Y7cFNuOVzIkcaRHdWGj
vESnObg+IQwh5zNAYUb6CROYdEATsATAW/EnFc9IJTEQfCce8EymZ4uNSNoi3DgvNBNkxt
jAmszFZUqNLNxxkjqWcA+gkju1U2gyzjAujsieBpM9X37TNq17LCRv6ToL1MIOJeWVwUiB
6MrbOTHwIixlYyW5xO7y/+LuSKcKEgD+5O2A==
&quot;&quot;&quot;</span>.<span style="color: black;">strip</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">replace</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, <span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span> <span style="color: black;">&#40;</span>produce_path<span style="color: black;">&#41;</span>:
    <span style="color: #008000;">open</span> <span style="color: black;">&#40;</span>produce_path, <span style="color: #483d8b;">&quot;w&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">write</span> <span style="color: black;">&#40;</span>produce_script<span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">os</span>.<span style="color: black;">chmod</span> <span style="color: black;">&#40;</span>produce_path, 0755<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> hook <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;post-receive&quot;</span>, <span style="color: #483d8b;">&quot;post-commit&quot;</span><span style="color: black;">&#41;</span>:
    hook_path = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span> <span style="color: black;">&#40;</span>repo, <span style="color: #483d8b;">&quot;.git&quot;</span>, <span style="color: #483d8b;">&quot;hooks&quot;</span>, hook<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span> <span style="color: black;">&#40;</span>hook_path<span style="color: black;">&#41;</span> \
     <span style="color: #ff7700;font-weight:bold;">or</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">realpath</span> <span style="color: black;">&#40;</span>hook_path<span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= produce_path:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">lexists</span> <span style="color: black;">&#40;</span>hook_path<span style="color: black;">&#41;</span>: <span style="color: #dc143c;">os</span>.<span style="color: black;">remove</span> <span style="color: black;">&#40;</span>hook_path<span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">os</span>.<span style="color: black;">symlink</span> <span style="color: black;">&#40;</span>produce_path, hook_path<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;--unpack&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">sys</span>.<span style="color: black;">argv</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Unpack only&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">SystemExit</span>
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;--raw&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">sys</span>.<span style="color: black;">argv</span>:
    p = <span style="color: #dc143c;">subprocess</span>.<span style="color: black;">Popen</span> <span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;git&quot;</span>, <span style="color: #483d8b;">&quot;commit&quot;</span>, <span style="color: #483d8b;">&quot;--allow-empty&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
    p.<span style="color: black;">communicate</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">else</span>:
    title = <span style="color: #008000;">raw_input</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Post title ? &quot;</span><span style="color: black;">&#41;</span>
    editor = <span style="color: #483d8b;">&quot;vi&quot;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;VISUAL&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span>:
        editor = <span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;VISUAL&quot;</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">elif</span> <span style="color: #483d8b;">&quot;EDITOR&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span>:
        editor = <span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;EDITOR&quot;</span><span style="color: black;">&#93;</span>
    contents_path = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span> <span style="color: black;">&#40;</span>repo, CONTENTS_FILE<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span> <span style="color: black;">&#40;</span>contents_path<span style="color: black;">&#41;</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">remove</span> <span style="color: black;">&#40;</span>contents_path<span style="color: black;">&#41;</span>
    ret = <span style="color: #dc143c;">subprocess</span>.<span style="color: black;">call</span> <span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>editor, contents_path<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> ret == <span style="color: #ff4500;">0</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span> <span style="color: black;">&#40;</span>contents_path<span style="color: black;">&#41;</span>:
        contents = <span style="color: #008000;">open</span> <span style="color: black;">&#40;</span>contents_path<span style="color: black;">&#41;</span>.<span style="color: black;">read</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #dc143c;">os</span>.<span style="color: black;">remove</span> <span style="color: black;">&#40;</span>contents_path<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;A problem occured while editing the contents file&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">SystemExit</span>
    p = <span style="color: #dc143c;">subprocess</span>.<span style="color: black;">Popen</span> <span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;git&quot;</span>, <span style="color: #483d8b;">&quot;commit&quot;</span>, <span style="color: #483d8b;">&quot;--allow-empty&quot;</span>, <span style="color: #483d8b;">&quot;-F&quot;</span>, <span style="color: #483d8b;">&quot;-&quot;</span><span style="color: black;">&#93;</span>,
                          stdin = <span style="color: #dc143c;">subprocess</span>.<span style="color: black;">PIPE</span><span style="color: black;">&#41;</span>
    p.<span style="color: black;">communicate</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;%s<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>%s&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>title, contents<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">if</span> p.<span style="color: black;">returncode</span> == <span style="color: #ff4500;">0</span>: <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;New post successfully added&quot;</span>
<span style="color: #ff7700;font-weight:bold;">else</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">&quot;Couldn't add new post&quot;</span>
    <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://guillaume.segu.in/blog/code/298/use-git-as-your-blog-data-storage-backend/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Useful paralellism with Python</title>
		<link>http://guillaume.segu.in/blog/code/223/useful-paralellism-with-python/</link>
		<comments>http://guillaume.segu.in/blog/code/223/useful-paralellism-with-python/#comments</comments>
		<pubDate>Wed, 21 Apr 2010 19:54:41 +0000</pubDate>
		<dc:creator>iXce</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[multiprocessing]]></category>
		<category><![CDATA[parallel]]></category>

		<guid isPermaLink="false">http://guillaume.segu.in/blog/?p=223</guid>
		<description><![CDATA[After sorting out my clutter issues and finally producing a video of a clutter animation, I thought I&#8217;d use it on the initial goal, that animation I had written ages ago. What I had sadly forecast occurred, the video dumping awfully slowed down the animation. The whole problem is that, for now at least, I [...]]]></description>
			<content:encoded><![CDATA[<p>After <a href="http://guillaume.segu.in/blog/code/216/doing-videos-of-clutter-animations/">sorting out my clutter issues and finally producing a video of a clutter animation</a>, I thought I&#8217;d use it on the initial goal, that animation I had written ages ago. What I had sadly forecast occurred, the video dumping awfully slowed down the animation.</p>
<p>The whole problem is that, for now at least, I don&#8217;t think it&#8217;s possible to run the animation frame per frame rather than time based. So I thought &#8220;let&#8217;s just defer the whole video generation to after the end of the animation, and bufferize the frames meanwhile&#8221;. Well, this worked&#8230; until oomkiller jumped in and killed my process. Urgh.</p>
<p>So, I can&#8217;t bufferize the whole video, but I can&#8217;t push the frames to gstreamer in real time directly from the animation either. Well, all I need is parallelism then&nbsp;! Push frames to a queue which is consumed by another execution unit (by pushing the frames to gstreamer). And since threading pretty much sucks in Python (well, it would definitely since we need real parallelism), let&#8217;s use the new <a href="http://docs.python.org/library/multiprocessing.html">multiprocessing</a> framework from Python 2.6. Using it is pretty straightforward&nbsp;: create some parallel structures (queues, pipes), spawn a new process with it&#8217;s own main function, push to the structures from one process, read from another, and you&#8217;re done. The only thing I&#8217;m still wondering is why there is a <a href="http://docs.python.org/library/multiprocessing.html#multiprocessing.Queue.close">close()</a> function on Queues when there is no obvious way to detect from the other end that the queue has been closed (which I worked around by pushing a None message).</p>
<p>Well, now I have a smooth animation and a smooth video dump, my two cores being nicely fully used <img src='http://guillaume.segu.in/blog/wp-includes/images/smilies/smile.png' alt=':)' class='wp-smiley' /> </p>
<p>The code is available below, with the interesting parts being <tt>StageRecorder.create_pipeline</tt>, <tt>StageRecorder.dump_frame</tt>, <tt>StageRecorder.stop_recording</tt> and  <tt>StageRecorder.process_runner</tt>.</p>
<p><span id="more-223"></span></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> clutter
<span style="color: #ff7700;font-weight:bold;">import</span> gst
<span style="color: #ff7700;font-weight:bold;">import</span> gobject
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> multiprocessing <span style="color: #ff7700;font-weight:bold;">import</span> Process, <span style="color: #dc143c;">Queue</span>
&nbsp;
DEFAULT_OUTPUT = <span style="color: #483d8b;">&quot;stage.ogg&quot;</span>
DEFAULT_PIPELINE_DESC = <span style="color: #483d8b;">&quot;videorate ! theoraenc ! oggmux&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> StageRecorderSrc <span style="color: black;">&#40;</span>gst.<span style="color: black;">Element</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Gstreamer element used to push our buffers into the pipeline&quot;&quot;&quot;</span>
&nbsp;
    __gstdetails__ = <span style="color: black;">&#40;</span>
        <span style="color: #483d8b;">&quot;Clutter Stage Recorder Source plugin&quot;</span>,
        <span style="color: #483d8b;">&quot;stagerecorder.py&quot;</span>,
        <span style="color: #483d8b;">&quot;&quot;</span>,
        <span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    _src_template = gst.<span style="color: black;">PadTemplate</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;src&quot;</span>,
                                     gst.<span style="color: black;">PAD_SRC</span>,
                                     gst.<span style="color: black;">PAD_ALWAYS</span>,
                                     gst.<span style="color: black;">caps_new_any</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    __gsttemplates__ = <span style="color: black;">&#40;</span>_src_template,<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        gst.<span style="color: black;">Element</span>.<span style="color: #0000cd;">__init__</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">src_pad</span> = gst.<span style="color: black;">Pad</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._src_template<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">src_pad</span>.<span style="color: black;">use_fixed_caps</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">add_pad</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">src_pad</span><span style="color: black;">&#41;</span>
&nbsp;
gobject.<span style="color: black;">type_register</span> <span style="color: black;">&#40;</span>StageRecorderSrc<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> StageRecorder <span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Clutter stage recorder which dumps frames into a gstreamer pipeline&quot;&quot;&quot;</span>
&nbsp;
    stage = <span style="color: #008000;">None</span>
    output_filename = <span style="color: #008000;">None</span>
    pipeline_desc = <span style="color: #008000;">None</span>
    parallel = <span style="color: #008000;">False</span>
&nbsp;
    pipeline = <span style="color: #008000;">None</span>
    src = <span style="color: #008000;">None</span>
    buffer_queue = <span style="color: #008000;">None</span>
    process = <span style="color: #008000;">None</span>
&nbsp;
    stage_width = <span style="color: #ff4500;">0</span>
    stage_height = <span style="color: #ff4500;">0</span>
&nbsp;
    clock_start = -<span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,
                  stage,
                  pipeline_desc = DEFAULT_PIPELINE_DESC,
                  output_filename = DEFAULT_OUTPUT,
                  parallel = <span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">stage</span> = stage
        stage.<span style="color: black;">connect</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;destroy&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">stop_recording</span><span style="color: black;">&#41;</span>
        stage.<span style="color: black;">connect_after</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;paint&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">dump_frame</span><span style="color: black;">&#41;</span>
        stage.<span style="color: black;">connect</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;notify::width&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">update_size</span><span style="color: black;">&#41;</span>
        stage.<span style="color: black;">connect</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;notify::height&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">update_size</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline_desc</span> = pipeline_desc
        <span style="color: #008000;">self</span>.<span style="color: black;">output_filename</span> = output_filename
        <span style="color: #008000;">self</span>.<span style="color: black;">dumping</span> = <span style="color: #008000;">False</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span> = <span style="color: #008000;">None</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">src</span> = <span style="color: #008000;">None</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">parallel</span> = parallel
        <span style="color: #008000;">self</span>.<span style="color: black;">clock_start</span> = -<span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> create_pipeline <span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Create the gstreamer pipeline and run it&quot;&quot;&quot;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span> = gst.<span style="color: black;">parse_launch</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">pipeline_desc</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Couldn't create pipeline&quot;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">add_source</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">add_sink</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">set_state</span> <span style="color: black;">&#40;</span>gst.<span style="color: black;">STATE_PLAYING</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">parallel</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">buffer_queue</span> = <span style="color: #dc143c;">Queue</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">process</span> = Process <span style="color: black;">&#40;</span>target = <span style="color: #008000;">self</span>.<span style="color: black;">process_runner</span>,
                                    args = <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">buffer_queue</span>,<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">process</span>.<span style="color: black;">start</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> add_source <span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Add our data source and its filters&quot;&quot;&quot;</span>
        sink_pad = <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">find_unlinked_pad</span> <span style="color: black;">&#40;</span>gst.<span style="color: black;">PAD_SINK</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> sink_pad:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Pipeline has no unlinked sink pad&quot;</span>
&nbsp;
        src_element = StageRecorderSrc <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">add</span> <span style="color: black;">&#40;</span>src_element<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">src</span> = src_element.<span style="color: black;">get_static_pad</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;src&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># The ffmpegcolorspace element is a generic converter; it will convert</span>
        <span style="color: #808080; font-style: italic;"># our supplied fixed format data into whatever the encoder wants</span>
        ffmpegcolorspace = gst.<span style="color: black;">element_factory_make</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;ffmpegcolorspace&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> ffmpegcolorspace:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't create ffmpegcolorspace element&quot;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">add</span> <span style="color: black;">&#40;</span>ffmpegcolorspace<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># No need to verticalflip here since clutter_stage_read_pixels did</span>
&nbsp;
        src_element.<span style="color: black;">link</span> <span style="color: black;">&#40;</span>ffmpegcolorspace<span style="color: black;">&#41;</span>
&nbsp;
        src_pad = ffmpegcolorspace.<span style="color: black;">get_static_pad</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;src&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> src_pad:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't get src pad to link into pipeline&quot;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> src_pad.<span style="color: black;">link</span> <span style="color: black;">&#40;</span>sink_pad<span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= gst.<span style="color: black;">PAD_LINK_OK</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't link to sink pad&quot;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> add_sink <span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Add the final filesink&quot;&quot;&quot;</span>
        src_pad = <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">find_unlinked_pad</span> <span style="color: black;">&#40;</span>gst.<span style="color: black;">PAD_SRC</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> src_pad:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Pipeline has no unlinked src pad&quot;</span>
        filesink = gst.<span style="color: black;">parse_launch</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;filesink location=%s&quot;</span> \
                                        <span style="color: #66cc66;">%</span> <span style="color: #008000;">self</span>.<span style="color: black;">output_filename</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> filesink:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't create filesink element&quot;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">add</span> <span style="color: black;">&#40;</span>filesink<span style="color: black;">&#41;</span>
&nbsp;
        sink_pad = filesink.<span style="color: black;">get_static_pad</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;sink&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> sink_pad:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't get sink pad to link pipeline output&quot;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> src_pad.<span style="color: black;">link</span> <span style="color: black;">&#40;</span>sink_pad<span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= gst.<span style="color: black;">PAD_LINK_OK</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't link to sink pad&quot;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> dump_frame <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, stage<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Dump a frame to the gstreamer pipeline&quot;&quot;&quot;</span>
        <span style="color: #808080; font-style: italic;"># Prevent an infinite loop (clutter.Stage.read_pixels</span>
        <span style="color: #808080; font-style: italic;"># performs another paint)</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>.<span style="color: black;">dumping</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">dumping</span> = <span style="color: #008000;">True</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">create_pipeline</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            data = <span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">read_pixels</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">0</span>,
                                           <span style="color: #008000;">self</span>.<span style="color: black;">stage_width</span>,
                                           <span style="color: #008000;">self</span>.<span style="color: black;">stage_height</span><span style="color: black;">&#41;</span>
            <span style="color: #808080; font-style: italic;"># Use clutter clock</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">clock_start</span> == -<span style="color: #ff4500;">1</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">clock_start</span> = clutter.<span style="color: black;">get_timestamp</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            timestamp = clutter.<span style="color: black;">get_timestamp</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> - <span style="color: #008000;">self</span>.<span style="color: black;">clock_start</span>
            timestamp <span style="color: #66cc66;">*</span>= <span style="color: #ff4500;">1000</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">parallel</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">buffer_queue</span>.<span style="color: black;">put</span> <span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>data, timestamp<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                buffer = gst.<span style="color: black;">Buffer</span> <span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
                buffer.<span style="color: black;">timestamp</span> = timestamp
                <span style="color: #808080; font-style: italic;"># Don't forget to set the right caps on the buffer</span>
                <span style="color: #008000;">self</span>.<span style="color: black;">set_caps_on</span> <span style="color: black;">&#40;</span>buffer<span style="color: black;">&#41;</span>
                status = <span style="color: #008000;">self</span>.<span style="color: black;">src</span>.<span style="color: black;">push</span> <span style="color: black;">&#40;</span>buffer<span style="color: black;">&#41;</span>
                <span style="color: #ff7700;font-weight:bold;">if</span> status <span style="color: #66cc66;">!</span>= gst.<span style="color: black;">FLOW_OK</span>:
                    <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Error while pushing buffer : &quot;</span> + status
            <span style="color: #008000;">self</span>.<span style="color: black;">dumping</span> = <span style="color: #008000;">False</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> update_size <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, stage = <span style="color: #008000;">None</span>, param = <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Update the size of the gstreamer frames based on the stage size&quot;&quot;&quot;</span>
        x1, y1, x2, y2 = <span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">get_allocation_box</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage_width</span> = <span style="color: #008000;">int</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">0.5</span> + x2 - x1<span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage_height</span> = <span style="color: #008000;">int</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">0.5</span> + y2 - y1<span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> set_caps_on <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, dest<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Set the current frame caps on the specified object&quot;&quot;&quot;</span>
        <span style="color: #808080; font-style: italic;"># The data is always native-endian xRGB; ffmpegcolorspace</span>
        <span style="color: #808080; font-style: italic;"># doesn't support little-endian xRGB, but does support</span>
        <span style="color: #808080; font-style: italic;"># big-endian BGRx.</span>
        caps = gst.<span style="color: black;">caps_from_string</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;video/x-raw-rgb,bpp=32,depth=24,<span style="color: #000099; font-weight: bold;">\</span>
                                      red_mask=0xff000000,<span style="color: #000099; font-weight: bold;">\</span>
                                      green_mask=0x00ff0000,<span style="color: #000099; font-weight: bold;">\</span>
                                      blue_mask=0x0000ff00,<span style="color: #000099; font-weight: bold;">\</span>
                                      endianness=4321,<span style="color: #000099; font-weight: bold;">\</span>
                                      framerate=15/1,<span style="color: #000099; font-weight: bold;">\</span>
                                      width=%d,height=%d&quot;</span> \
                                        <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">stage_width</span>,
                                           <span style="color: #008000;">self</span>.<span style="color: black;">stage_height</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> dest:
            dest.<span style="color: black;">set_caps</span> <span style="color: black;">&#40;</span>caps<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> stop_recording <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, stage<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">parallel</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">buffer_queue</span>.<span style="color: black;">put</span> <span style="color: black;">&#40;</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">set_state</span> <span style="color: black;">&#40;</span>gst.<span style="color: black;">STATE_NULL</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> process_runner <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, queue<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
            message = queue.<span style="color: black;">get</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> message:
                <span style="color: #ff7700;font-weight:bold;">return</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                data, timestamp = message
                buffer = gst.<span style="color: black;">Buffer</span> <span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
                buffer.<span style="color: black;">timestamp</span> = timestamp
                <span style="color: #008000;">self</span>.<span style="color: black;">set_caps_on</span> <span style="color: black;">&#40;</span>buffer<span style="color: black;">&#41;</span>
                status = <span style="color: #008000;">self</span>.<span style="color: black;">src</span>.<span style="color: black;">push</span> <span style="color: black;">&#40;</span>buffer<span style="color: black;">&#41;</span>
                <span style="color: #ff7700;font-weight:bold;">if</span> status <span style="color: #66cc66;">!</span>= gst.<span style="color: black;">FLOW_OK</span>:
                    <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Error while pushing buffer : &quot;</span> + status</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://guillaume.segu.in/blog/code/223/useful-paralellism-with-python/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Doing videos of Clutter animations</title>
		<link>http://guillaume.segu.in/blog/code/216/doing-videos-of-clutter-animations/</link>
		<comments>http://guillaume.segu.in/blog/code/216/doing-videos-of-clutter-animations/#comments</comments>
		<pubDate>Tue, 20 Apr 2010 18:15:24 +0000</pubDate>
		<dc:creator>iXce</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[clutter]]></category>
		<category><![CDATA[gst]]></category>
		<category><![CDATA[gstreamer]]></category>
		<category><![CDATA[pyclutter]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://guillaume.segu.in/blog/?p=216</guid>
		<description><![CDATA[A while back, I used clutter (a very nice and simple animation toolkit that basically let&#8217;s you easily work in a 3D environment with 2D objects) to do a little photo slideshow with a lot of customisations, but I never even showed it to the person it was aimed at because the whole thing was [...]]]></description>
			<content:encoded><![CDATA[<p>A while back, I used <a href="http://clutter-project.org/">clutter</a> (a very nice and simple animation toolkit that basically let&#8217;s you easily work in a 3D environment with 2D objects) to do a little photo slideshow with a lot of customisations, but I never even showed it to the person it was aimed at because the whole thing was not satisfying enough (it either took ages to start or was not smooth and it was not easy to put a decent soundtrack when you can&#8217;t synchronize video &#038; audio).</p>
<p>A simple solution would have been to do the rendering once and then just do the postproduction. I had quickly looked for a way to use a direct output of the animation to <a href="http://www.gstreamer.net/">gstreamer</a> (since there is gstreamer input support for clutter, this pretty much made sense), but there was none. Another option would have been to use a capture software, like <a href="http://xvidcap.sourceforge.net/">Xvidcap</a>, but this stuff is too heavy for my poor laptop. Consequently, I just gave up back then.</p>
<p>What I had completely overlooked is that clutter uses OpenGL for the rendering, so that all I had to do was to dump each frame myself using <a href="http://www.opengl.org/sdk/docs/man/xhtml/glReadPixels.xml">glReadPixels</a> or using things like <a href="https://devel.neopsis.com/projects/yukon/">Yukon</a> to do the dirty stuff. After a quick googling, I found this <a href="http://www.mail-archive.com/clutter@o-hand.com/msg02802.html">clutter mailing list thread about capturing the clutter output to a video file</a>, which mentions the <a href="http://www.google.com/codesearch/p?hl=fr#GiXzDO4YbyM/clutter/clutter-stage.c&#038;q=clutter_stage_read_pixels&#038;sa=N&#038;cd=1&#038;ct=rc">clutter_stage_read_pixels</a> function, which does all the glReadPixels magic and even puts it in a more standard format. It also points to <a href="http://www.google.com/codesearch/p?hl=fr#ehFKkUWsZRM/src/shell-recorder.c&#038;q=gnome-shell%20recorder&#038;d=1">gnome-shell&#8217;s recorder stuff</a>, which does the glReadPixels stuff and outputs it to a gstreamer pipeline, plus some extra fancy things (since they are doing screencasts of gnome-shell features, they draw the mouse cursor on top of each frame). So all I have to do now is put things together <img src='http://guillaume.segu.in/blog/wp-includes/images/smilies/smile.png' alt=':)' class='wp-smiley' /> </p>
<p>One of the bad things I figured is that clutter_stage_read_pixels calls clutter_stage_paint, so mixing the gnome-shell recorder approach with clutter_stage_read_pixels results in a bad infinite loop if you don&#8217;t protect the whole thing. Even though this means painting things twice, I guess this is a much easier approach than having to use python-opengl or something along the line.</p>
<p>Another bad thing I encountered was that the Python bindings for clutter_stage_read_pixels are broken at the moment (pyclutter 1.0.2). The first problem is that the argument parsing part seems to be broken. Changing the PyArg_ParseTupleAndKeywords to a simple PyArg_ParseTuple gets things &#8220;working&#8221;, and gdb indicates a segfault in a PyDict_Check of the keywords argument&nbsp;:</p>
<p><code>Program received signal SIGSEGV, Segmentation fault.<br />
0x00000032d34ecd9c in _PyArg_ParseTupleAndKeywords_SizeT (args=(0, 0, 500, 200), keywords=<unknown at remote 0x7fffeffdc260>, format=<br />
    0x7ffff000d9ac "dddd:ClutterStage.read_pixels", kwlist=0x7ffff022f6c0) at Python/getargs.c:1409<br />
1409                (keywords != NULL &#038;&#038; !PyDict_Check(keywords)) ||<br />
(gdb) bt<br />
#0  0x00000032d34ecd9c in _PyArg_ParseTupleAndKeywords_SizeT (args=(0, 0, 500, 200), keywords=</unknown><unknown at remote 0x7fffeffdc260>, format=<br />
    0x7ffff000d9ac "iiii:ClutterStage.read_pixels", kwlist=0x7ffff022f6c0) at Python/getargs.c:1409<br />
</unknown></code></p>
<p>After asking on #clutter, <a href="http://blogs.gnome.org/ebassi/">ebassi</a> immediately caught the problem, <a href="http://git.clutter-project.org/cgit.cgi?url=bindings/pyclutter/commit/&#038;id=7a5b4cb27b9925b80e8d7cacedcd1277648b067f">there was a missing &#8220;kwargs&#8221; bit in the python binding override definition</a>, so that the kwargs were never actually passed to the C wrapper which was getting garbage instead.</p>
<p>The other problem was that the returned data was empty. This was simply due to the fact that the buffer returned by the C function was interpreted as a NULL-terminated string, which is wrong when you get such binary data. The fix was simply to <a href="http://git.clutter-project.org/cgit.cgi?url=bindings/pyclutter/commit/&#038;id=c05436ed9c236c060628e5a09ce8d32ade58cca2">specify the length to read to fill the string</a>.</p>
<p>Both issues are now fixed in pyclutter git, and should be available on the next stable release.</p>
<p>The remainder of the port was pretty straightforward. The only problem was that I had no experience with gstreamer, which wasted me quite a lot of time. Here are a few things I discovered&nbsp;:</p>
<ul>
<li>The <tt>--gst-debug-level</tt> command line argument is really really useful, especially on levels 3 and 4, it outputs a lot of valuable information on what&#8217;s going on and what&#8217;s not working.</li>
<li>The whole <a href="http://www.gstreamer.net/data/doc/gstreamer/head/manual/html/section-caps.html">caps</a> story is really important. After spending an hour trying to figure why my pads wouldn&#8217;t negotiate their caps, I found out that they couldn&#8217;t because I had a wrong cap (the endianness one), and after a few more hours I figured that I had to set the caps on each buffer, and that I actually only had to set caps on buffers.</li>
<li>Timestamps are not magically inferred (at least not without extra gstreamer elements) and should be set by hand using the buffer.timestamp python property (this is not quite well documented in the Python bindings documentation imho).</li>
</ul>
<p>Well, that&#8217;s pretty much it. I used a Clutter python demo from <a href="https://fedorahosted.org/fedora-tour/browser/docs/learning_refs/test.py">fedora-tour</a> and here is the result : <a href='http://guillaume.segu.in/blog/wp-content/uploads/2010/04/stage.ogg'>Clutter Stage Recorder demo</a>. The whole source is available below <img src='http://guillaume.segu.in/blog/wp-includes/images/smilies/smile.png' alt=':)' class='wp-smiley' /> </p>
<p><span id="more-216"></span></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #808080; font-style: italic;"># -*- coding: utf-8 -*-</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> clutter
<span style="color: #ff7700;font-weight:bold;">import</span> gst
<span style="color: #ff7700;font-weight:bold;">import</span> gobject
&nbsp;
DEFAULT_OUTPUT = <span style="color: #483d8b;">&quot;stage.ogg&quot;</span>
DEFAULT_PIPELINE_DESC = <span style="color: #483d8b;">&quot;videorate ! theoraenc ! oggmux&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> StageRecorderSrc <span style="color: black;">&#40;</span>gst.<span style="color: black;">Element</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Gstreamer element used to push our buffers into the pipeline&quot;&quot;&quot;</span>
&nbsp;
    __gstdetails__ = <span style="color: black;">&#40;</span>
        <span style="color: #483d8b;">&quot;Clutter Stage Recorder Source plugin&quot;</span>,
        <span style="color: #483d8b;">&quot;stagerecorder.py&quot;</span>,
        <span style="color: #483d8b;">&quot;&quot;</span>,
        <span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
    _src_template = gst.<span style="color: black;">PadTemplate</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;src&quot;</span>,
                                     gst.<span style="color: black;">PAD_SRC</span>,
                                     gst.<span style="color: black;">PAD_ALWAYS</span>,
                                     gst.<span style="color: black;">caps_new_any</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    __gsttemplates__ = <span style="color: black;">&#40;</span>_src_template,<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        gst.<span style="color: black;">Element</span>.<span style="color: #0000cd;">__init__</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">src_pad</span> = gst.<span style="color: black;">Pad</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._src_template<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">src_pad</span>.<span style="color: black;">use_fixed_caps</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">add_pad</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">src_pad</span><span style="color: black;">&#41;</span>
&nbsp;
gobject.<span style="color: black;">type_register</span> <span style="color: black;">&#40;</span>StageRecorderSrc<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> StageRecorder <span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Clutter stage recorder which dumps frames into a gstreamer pipeline&quot;&quot;&quot;</span>
&nbsp;
    stage = <span style="color: #008000;">None</span>
    output_filename = <span style="color: #008000;">None</span>
    pipeline_desc = <span style="color: #008000;">None</span>
&nbsp;
    pipeline = <span style="color: #008000;">None</span>
    src = <span style="color: #008000;">None</span>
&nbsp;
    stage_width = <span style="color: #ff4500;">0</span>
    stage_height = <span style="color: #ff4500;">0</span>
&nbsp;
    clock_start = -<span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,
                  stage,
                  pipeline_desc = DEFAULT_PIPELINE_DESC,
                  output_filename = DEFAULT_OUTPUT<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">stage</span> = stage
        stage.<span style="color: black;">connect</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;destroy&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">stop_recording</span><span style="color: black;">&#41;</span>
        stage.<span style="color: black;">connect_after</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;paint&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">dump_frame</span><span style="color: black;">&#41;</span>
        stage.<span style="color: black;">connect</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;notify::width&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">update_size</span><span style="color: black;">&#41;</span>
        stage.<span style="color: black;">connect</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;notify::height&quot;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">update_size</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline_desc</span> = pipeline_desc
        <span style="color: #008000;">self</span>.<span style="color: black;">output_filename</span> = output_filename
        <span style="color: #008000;">self</span>.<span style="color: black;">dumping</span> = <span style="color: #008000;">False</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span> = <span style="color: #008000;">None</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">src</span> = <span style="color: #008000;">None</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">clock_start</span> = -<span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> create_pipeline <span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Create the gstreamer pipeline and run it&quot;&quot;&quot;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span> = gst.<span style="color: black;">parse_launch</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">pipeline_desc</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Couldn't create pipeline&quot;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">add_source</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">add_sink</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">set_state</span> <span style="color: black;">&#40;</span>gst.<span style="color: black;">STATE_PLAYING</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> add_source <span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Add our data source and its filters&quot;&quot;&quot;</span>
        sink_pad = <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">find_unlinked_pad</span> <span style="color: black;">&#40;</span>gst.<span style="color: black;">PAD_SINK</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> sink_pad:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Pipeline has no unlinked sink pad&quot;</span>
&nbsp;
        src_element = StageRecorderSrc <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">add</span> <span style="color: black;">&#40;</span>src_element<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">src</span> = src_element.<span style="color: black;">get_static_pad</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;src&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># The ffmpegcolorspace element is a generic converter; it will convert</span>
        <span style="color: #808080; font-style: italic;"># our supplied fixed format data into whatever the encoder wants</span>
        ffmpegcolorspace = gst.<span style="color: black;">element_factory_make</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;ffmpegcolorspace&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> ffmpegcolorspace:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't create ffmpegcolorspace element&quot;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">add</span> <span style="color: black;">&#40;</span>ffmpegcolorspace<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># No need to verticalflip here since clutter_stage_read_pixels did</span>
&nbsp;
        src_element.<span style="color: black;">link</span> <span style="color: black;">&#40;</span>ffmpegcolorspace<span style="color: black;">&#41;</span>
&nbsp;
        src_pad = ffmpegcolorspace.<span style="color: black;">get_static_pad</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;src&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> src_pad:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't get src pad to link into pipeline&quot;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> src_pad.<span style="color: black;">link</span> <span style="color: black;">&#40;</span>sink_pad<span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= gst.<span style="color: black;">PAD_LINK_OK</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't link to sink pad&quot;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> add_sink <span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Add the final filesink&quot;&quot;&quot;</span>
        src_pad = <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">find_unlinked_pad</span> <span style="color: black;">&#40;</span>gst.<span style="color: black;">PAD_SRC</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> src_pad:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Pipeline has no unlinked src pad&quot;</span>
        filesink = gst.<span style="color: black;">parse_launch</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;filesink location=%s&quot;</span> \
                                        <span style="color: #66cc66;">%</span> <span style="color: #008000;">self</span>.<span style="color: black;">output_filename</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> filesink:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't create filesink element&quot;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">add</span> <span style="color: black;">&#40;</span>filesink<span style="color: black;">&#41;</span>
&nbsp;
        sink_pad = filesink.<span style="color: black;">get_static_pad</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;sink&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> sink_pad:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't get sink pad to link pipeline output&quot;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">if</span> src_pad.<span style="color: black;">link</span> <span style="color: black;">&#40;</span>sink_pad<span style="color: black;">&#41;</span> <span style="color: #66cc66;">!</span>= gst.<span style="color: black;">PAD_LINK_OK</span>:
            <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Can't link to sink pad&quot;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> dump_frame <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, stage<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Dump a frame to the gstreamer pipeline&quot;&quot;&quot;</span>
        <span style="color: #808080; font-style: italic;"># Prevent an infinite loop (clutter.Stage.read_pixels</span>
        <span style="color: #808080; font-style: italic;"># performs another paint)</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>.<span style="color: black;">dumping</span>:
            <span style="color: #008000;">self</span>.<span style="color: black;">dumping</span> = <span style="color: #008000;">True</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">create_pipeline</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            buffer = gst.<span style="color: black;">Buffer</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">read_pixels</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">0</span>,
                                                         <span style="color: #008000;">self</span>.<span style="color: black;">stage_width</span>,
                                                         <span style="color: #008000;">self</span>.<span style="color: black;">stage_height</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            <span style="color: #808080; font-style: italic;"># Use clutter clock</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">self</span>.<span style="color: black;">clock_start</span> == -<span style="color: #ff4500;">1</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">clock_start</span> = clutter.<span style="color: black;">get_timestamp</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            buffer.<span style="color: black;">timestamp</span> = clutter.<span style="color: black;">get_timestamp</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> - <span style="color: #008000;">self</span>.<span style="color: black;">clock_start</span>
            buffer.<span style="color: black;">timestamp</span> <span style="color: #66cc66;">*</span>= <span style="color: #ff4500;">1000</span>
            <span style="color: #808080; font-style: italic;"># Don't forget to set the right caps on the buffer</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">set_caps_on</span> <span style="color: black;">&#40;</span>buffer<span style="color: black;">&#41;</span>
            status = <span style="color: #008000;">self</span>.<span style="color: black;">src</span>.<span style="color: black;">push</span> <span style="color: black;">&#40;</span>buffer<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> status <span style="color: #66cc66;">!</span>= gst.<span style="color: black;">FLOW_OK</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">RuntimeError</span>, <span style="color: #483d8b;">&quot;Error while pushing buffer : &quot;</span> + status
            <span style="color: #008000;">self</span>.<span style="color: black;">dumping</span> = <span style="color: #008000;">False</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> update_size <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, stage = <span style="color: #008000;">None</span>, param = <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Update the size of the gstreamer frames based on the stage size&quot;&quot;&quot;</span>
        x1, y1, x2, y2 = <span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">get_allocation_box</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage_width</span> = <span style="color: #008000;">int</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">0.5</span> + x2 - x1<span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage_height</span> = <span style="color: #008000;">int</span> <span style="color: black;">&#40;</span><span style="color: #ff4500;">0.5</span> + y2 - y1<span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> set_caps_on <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, dest<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;&quot;Set the current frame caps on the specified object&quot;&quot;&quot;</span>
        <span style="color: #808080; font-style: italic;"># The data is always native-endian xRGB; ffmpegcolorspace</span>
        <span style="color: #808080; font-style: italic;"># doesn't support little-endian xRGB, but does support</span>
        <span style="color: #808080; font-style: italic;"># big-endian BGRx.</span>
        caps = gst.<span style="color: black;">caps_from_string</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;video/x-raw-rgb,bpp=32,depth=24,<span style="color: #000099; font-weight: bold;">\</span>
                                      red_mask=0xff000000,<span style="color: #000099; font-weight: bold;">\</span>
                                      green_mask=0x00ff0000,<span style="color: #000099; font-weight: bold;">\</span>
                                      blue_mask=0x0000ff00,<span style="color: #000099; font-weight: bold;">\</span>
                                      endianness=4321,<span style="color: #000099; font-weight: bold;">\</span>
                                      framerate=15/1,<span style="color: #000099; font-weight: bold;">\</span>
                                      width=%d,height=%d&quot;</span> \
                                        <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">stage_width</span>,
                                           <span style="color: #008000;">self</span>.<span style="color: black;">stage_height</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> dest:
            dest.<span style="color: black;">set_caps</span> <span style="color: black;">&#40;</span>caps<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> stop_recording <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, stage<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">pipeline</span>.<span style="color: black;">set_state</span> <span style="color: black;">&#40;</span>gst.<span style="color: black;">STATE_NULL</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> clutterTest:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;">#create a clutter stage</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage</span> = clutter.<span style="color: black;">Stage</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        recorder = StageRecorder <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">stage</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'destroy'</span>, clutter.<span style="color: black;">main_quit</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#set the stage size in x,y pixels</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">set_size</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">500</span>,<span style="color: #ff4500;">200</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#define some clutter colors in rgbo (red,green,blue,opacity)</span>
        color_black = clutter.<span style="color: black;">Color</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span> 
        color_green = clutter.<span style="color: black;">Color</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">255</span>,<span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span>
        color_blue = clutter.<span style="color: black;">Color</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">255</span>,<span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#set the clutter stages bg color to our black</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">set_color</span><span style="color: black;">&#40;</span>color_black<span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#create a clutter label, is there documentation for creating a clutterlabel?</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label</span> = clutter.<span style="color: black;">Text</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#set the labels font</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label</span>.<span style="color: black;">set_font_name</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Mono 32'</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#add some text to the label</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label</span>.<span style="color: black;">set_text</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Hello&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#make the label green</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label</span>.<span style="color: black;">set_color</span><span style="color: black;">&#40;</span>color_green <span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#put the label in the center of the stage</span>
        <span style="color: black;">&#40;</span>label_width, label_height<span style="color: black;">&#41;</span> = <span style="color: #008000;">self</span>.<span style="color: black;">label</span>.<span style="color: black;">get_size</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        label_x = <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">get_width</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>/<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span> - label_width/<span style="color: #ff4500;">2</span>
        label_y = <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">get_height</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>/<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span> - label_height/<span style="color: #ff4500;">2</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label</span>.<span style="color: black;">set_position</span><span style="color: black;">&#40;</span>label_x, label_y<span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#make a second label similar to the first label</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label2</span> = clutter.<span style="color: black;">Text</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label2</span>.<span style="color: black;">set_font_name</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Mono 32'</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label2</span>.<span style="color: black;">set_text</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;World!&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label2</span>.<span style="color: black;">set_color</span><span style="color: black;">&#40;</span>color_blue <span style="color: black;">&#41;</span>
        <span style="color: black;">&#40;</span>label2_width, label2_height<span style="color: black;">&#41;</span> = <span style="color: #008000;">self</span>.<span style="color: black;">label2</span>.<span style="color: black;">get_size</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        label2_x = <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">get_width</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>/<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span> - label2_width/<span style="color: #ff4500;">2</span>
        label2_y = <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">get_height</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>/<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span> - label2_height/<span style="color: #ff4500;">2</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label2</span>.<span style="color: black;">set_position</span><span style="color: black;">&#40;</span>label2_x, label2_y<span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#hide the label2 </span>
        <span style="color: #008000;">self</span>.<span style="color: black;">label2</span>.<span style="color: black;">set_opacity</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#create a timeline for the animations that are going to happen</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">timeline</span> = clutter.<span style="color: black;">Timeline</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">timeline</span>.<span style="color: black;">set_duration</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2000</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">timeline</span>.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'completed'</span>, <span style="color: #008000;">self</span>.<span style="color: black;">quit</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#how will the animation flow? ease in? ease out? or steady?</span>
        <span style="color: #808080; font-style: italic;">#ramp_inc_func will make the animation steady</span>
        labelalpha = clutter.<span style="color: black;">Alpha</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">timeline</span>,clutter.<span style="color: black;">LINEAR</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#make some opacity behaviours that we will apply to the labels</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">hideBehaviour</span> = clutter.<span style="color: black;">BehaviourOpacity</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">255</span>,0x00,labelalpha<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">showBehaviour</span> = clutter.<span style="color: black;">BehaviourOpacity</span><span style="color: black;">&#40;</span>0x00,<span style="color: #ff4500;">255</span>,labelalpha<span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#add the items to the stage</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">label2</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">add</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">label</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#show all stage items and enter the clutter main loop</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">show_all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">swapLabels</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        clutter.<span style="color: black;">main</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> quit <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">stage</span>.<span style="color: black;">destroy</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        clutter.<span style="color: black;">main_quit</span> <span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> swapLabels<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:   
        <span style="color: #808080; font-style: italic;">#which label is at full opacity?, like the highlander, there can be only one</span>
        <span style="color: #ff7700;font-weight:bold;">if</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">label</span>.<span style="color: black;">get_opacity</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">&gt;</span><span style="color: #ff4500;">1</span> <span style="color: black;">&#41;</span>:
            showing = <span style="color: #008000;">self</span>.<span style="color: black;">label</span>
            hidden = <span style="color: #008000;">self</span>.<span style="color: black;">label2</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            showing = <span style="color: #008000;">self</span>.<span style="color: black;">label2</span>
            hidden = <span style="color: #008000;">self</span>.<span style="color: black;">label</span>
        <span style="color: #808080; font-style: italic;">#detach all objects from the behaviors</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">hideBehaviour</span>.<span style="color: black;">remove_all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">showBehaviour</span>.<span style="color: black;">remove_all</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#apply the behaviors to the labels</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">hideBehaviour</span>.<span style="color: black;">apply</span><span style="color: black;">&#40;</span>showing<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">showBehaviour</span>.<span style="color: black;">apply</span><span style="color: black;">&#40;</span>hidden<span style="color: black;">&#41;</span>
        <span style="color: #808080; font-style: italic;">#behaviours do nothing if their timelines are not running</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">timeline</span>.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__==<span style="color: #483d8b;">&quot;__main__&quot;</span>:
    <span style="color: #dc143c;">test</span> = clutterTest<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://guillaume.segu.in/blog/code/216/doing-videos-of-clutter-animations/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Doing changes for usability sake based on broken assumptions</title>
		<link>http://guillaume.segu.in/blog/code/173/doing-changes-for-usability-sake-based-on-broken-assumptions/</link>
		<comments>http://guillaume.segu.in/blog/code/173/doing-changes-for-usability-sake-based-on-broken-assumptions/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 19:01:43 +0000</pubDate>
		<dc:creator>iXce</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[GNOME]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[azerty]]></category>
		<category><![CDATA[dumb]]></category>
		<category><![CDATA[keybinding]]></category>
		<category><![CDATA[metacity]]></category>
		<category><![CDATA[qwerty]]></category>

		<guid isPermaLink="false">http://guillaume.segu.in/blog/?p=173</guid>
		<description><![CDATA[Keyboard shortcuts are always a great matter of debate, and the whole problem is that most often they are chosen based on assumptions of the end user layout. For instance, take this metacity commit : Change default cycle_group keybinding to Alt-grave. This change looks perfectly harmless, right ? Well not quite. It&#8217;s most likely based [...]]]></description>
			<content:encoded><![CDATA[<p>Keyboard shortcuts are always a great matter of debate, and the whole problem is that most often they are chosen based on assumptions of the end user layout.</p>
<p>For instance, take this <a href="http://git.gnome.org/browse/metacity/commit/?id=0f805bfdfb46e6739912df042f628ca9913b433c">metacity commit : Change default cycle_group keybinding to Alt-grave</a>. This change looks perfectly harmless, right ? Well not quite. It&#8217;s most likely based on the assumption that the end users has a qwerty keyboard layout (and it makes perfectly sense there). But let&#8217;s take an azerty layout. Grave is on the é/7 key, which is even farther from alt or tab than F6 is (well, not much I agree, but it might be even worse on other layouts). Is it really worth doing such a change then ?</p>
<p>Let&#8217;s also note that this also triggers a bad bug which gets alt+7 and alt+shift+7 to trigger the binding as well, while alt+grave is actually alt+altgr+7. This has been keeping me from nicely switching to my window n°7 in irssi for months (great thing that this window holds a really low traffic channel&#8230;).</p>
<p>All in all, I guess that the real problem is not that this change was made, but rather than we might need a system to have layout-dependant keybindings, or maybe hardware-location-based keybindings (<em>i.e.</em> that the key above the Tab key would trigger this keybinding independently of the layout).</p>
<p><em>Initially published on Mar 24, 2010 @ 8:22</em></p>
<p><strong>Update :</strong> this change has been <a href="http://git.gnome.org/browse/metacity/commit/?id=7d8972f20d4a41bb9c8afbc45a2eb6a9bbf08b09">reverted for the GNOME 2.30 release</a>. Even though I&#8217;m happy that the problem is &#8220;fixed&#8221;, it&#8217;s sad that the underlying problem (Alt+Shift+7 triggering Alt+`) is still there.</p>
]]></content:encoded>
			<wfw:commentRss>http://guillaume.segu.in/blog/code/173/doing-changes-for-usability-sake-based-on-broken-assumptions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dotclear &amp; PHP 5.3</title>
		<link>http://guillaume.segu.in/blog/code/191/dotclear-php-5-3/</link>
		<comments>http://guillaume.segu.in/blog/code/191/dotclear-php-5-3/#comments</comments>
		<pubDate>Fri, 26 Mar 2010 00:28:10 +0000</pubDate>
		<dc:creator>iXce</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[dotclear]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php 5.3]]></category>

		<guid isPermaLink="false">http://guillaume.segu.in/blog/?p=191</guid>
		<description><![CDATA[After migrating a bunch of stuff from one (about to expire) server which ran lenny to a new one running squeeze, a friend&#8217;s blog, which is powered by Dotclear, appeared heavily broken. His posts appeared empty, though they were still there and the titles were right, but nothing else (no url, no author, no date, [...]]]></description>
			<content:encoded><![CDATA[<p>After migrating a bunch of stuff from one (about to expire) server which ran lenny to a new one running squeeze, a friend&#8217;s blog, which is powered by Dotclear, appeared heavily broken. His posts appeared empty, though they were still there and the titles were right, but nothing else (no url, no author, no date, no content). After a little bit of investigation, I figured that the problem was that squeeze is running PHP 5.3, and that my friend&#8217;s version of Dotclear obviously didn&#8217;t support it. Checked the Dotclear website, found out that since PHP 5.3 support is planned for the upcoming Dotclear 2.2, the latest version (Dotclear 2.1.6 &#8212; which my friend already had, actually) did not support it. Checked the PHP website to find the 5.3 release date&nbsp;: 30 June 2009. Wow.</p>
<p>Looked <a href="http://forum.dotclear.net/viewtopic.php?pid=252993">a little deeper in the Dotclear forums</a>, and I found a <a href="http://blog.famillecollet.com/public/Patches/dc216.patch">patch</a> which is actually a workaround for the problem. This workaround has been available since the 20th of July, 2009, and the Dotclear developers won&#8217;t include it even in the 2.1 branch because it&#8217;s a workaround and not a real fix&nbsp;:</p>
<blockquote><p>Le patch n&#8217;est pas appliqué parce que, tu le dis toi-même, c&#8217;est une rustine. Ça peut paraître vieux jeu, mais nous préférons garder un code propre et régler les problèmes correctement.</p></blockquote>
<p>Which translates to &#8220;The patch hasn&#8217;t been applied because it&#8217;s only a workaround. It might sound overaged, but we&#8217;d rather keep a clean code and fix the problems correctly&#8221;. Well, it sounds like a great plan, which would be fine if it did not took them ages to produce that clean code&nbsp;:) (arguably, since the patch is easily available, my point might is pretty much void, but still, it&#8217;s not official &#8212; the average user grabbing the latest official release and installing it on their hosting which provides php 5.3 might easily get confused).</p>
]]></content:encoded>
			<wfw:commentRss>http://guillaume.segu.in/blog/code/191/dotclear-php-5-3/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Debugging cvCanny on x86_64</title>
		<link>http://guillaume.segu.in/blog/code/178/debugging-cvcanny-on-x86_64/</link>
		<comments>http://guillaume.segu.in/blog/code/178/debugging-cvcanny-on-x86_64/#comments</comments>
		<pubDate>Thu, 25 Mar 2010 22:45:47 +0000</pubDate>
		<dc:creator>iXce</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[OpenCV]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[canny]]></category>
		<category><![CDATA[cast]]></category>
		<category><![CDATA[compiler]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[int]]></category>
		<category><![CDATA[long]]></category>
		<category><![CDATA[optimization]]></category>

		<guid isPermaLink="false">http://guillaume.segu.in/blog/?p=178</guid>
		<description><![CDATA[There&#8217;s an outstanding bug right now which makes that cvCanny edge detector function in OpenCV currently segfaults on x86_64 systems. This post is an open attempt to track my debugging process Bug encountered. I know it&#8217;s x86_64 specific since I ran the same code on an i686 machine a few hours ago (with a home [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s an <a href="https://code.ros.org/trac/opencv/ticket/157">outstanding bug</a> right now which makes that cvCanny edge detector function in OpenCV currently segfaults on x86_64 systems. This post is an open attempt to track my debugging process <img src='http://guillaume.segu.in/blog/wp-includes/images/smilies/smile.png' alt=':)' class='wp-smiley' /> </p>
<ul>
<li>Bug encountered. I know it&#8217;s x86_64 specific since I ran the same code on an i686 machine a few hours ago (with a home compiled OpenCV, though).</li>
<li>Googled it : found reports on both <a href="https://code.ros.org/trac/opencv/ticket/157">OpenCV</a> and <a href="https://bugzilla.redhat.com/show_bug.cgi?id=531695">RedHat</a> bugtrackers.</li>
<li>Installed debug symbols, ran under gdb : all values I may need are optimized out.</li>
<li>Fetched OpenCV source, compiled it in debug mode.</li>
<li>CvCanny works great in debug mode.</li>
<li>Recompiled in release (optimized) mode to check if it is a distro-specific bug (both reports are from Fedora users).</li>
<li>Woha, release mode compilation is so slow <img src='http://guillaume.segu.in/blog/wp-includes/images/smilies/sad.png' alt=':(' class='wp-smiley' />  But bug confirmed&nbsp;: it segfaults again. Time to instrument the code.</li>
<li>Filled cvCanny function with printfs and fflushs to track the function execution. Looks like it tries to access an element at index -514. Hugh. What&#8217;s even more frightening is that it <em>successfully</em> achieves that on another array.</li>
<li>After running the same instrumented code on my i686 machine, it appears that the indexes are right and that the same indexes are accessed without any problem in optimized mode in the i686 build.</li>
<li>Reading the code tells me that the accesses at negative indexes are legit since the array origin is shifted from the actual allocated memory blob start. Well, that&#8217;s good, since it explains why it works well in debug mode or on i686 setups, but that&#8217;s pretty bad because it&#8217;s going to be awful to narrow down.</li>
<li>Ok, doing the access by hand (i.e. doing _map[-514] instead of _map[j - mapstep]) works. This is getting crazy. Doing k = j &#8211; mapstep and accessing _map[k] segfaults as well. Huh.</li>
<li>After an hour of heavy fprintfs, I figured that long k = j &#8211; mapstep; gave me a k which wasn&#8217;t the int value (-514) but rather the unsigned int value (4294966782), while doing int k = -514; long k2 = k; printf (&#8220;%d %ld\n&#8221;, k, k2); in a very simple code gives out -514 -514, even with -O3 or -O5 and all the options used for OpenCV release build. Since we are working with 64 bits pointers (i.e. of the size of long integers), this is probably the issue&nbsp;: when accessing _map[k], it unreferences the value at _map + k, which fails since it unreferences _map + 4294966782 instead of _map &#8211; 514.</li>
<li>Doing volatile int k = j &#8211; mapstep; and accessing _map[k] works, and cvCanny runs great now. Though this isn&#8217;t a real fix, just a workaround. There&#8217;s most likely a compiler bug underneath.</li>
<li>Posted a summary of my findings and the workaround on the bug report on the OpenCV tracker.</li>
</ul>
<p>Patch against latest svn (it should apply nicely to the 2.0.0 release as well)&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="diff" style="font-family:monospace;">Index: cvcanny.cpp
===================================================================
<span style="color: #888822;">--- cvcanny.cpp	<span style="">&#40;</span>révision 2908<span style="">&#41;</span></span>
<span style="color: #888822;">+++ cvcanny.cpp	<span style="">&#40;</span>copie de travail<span style="">&#41;</span></span>
<span style="color: #440088;">@@ -239,7 +239,8 @@</span>
                 <span style="">&#123;</span>
                     if<span style="">&#40;</span> m &gt; _mag<span style="">&#91;</span>j-<span style="">1</span><span style="">&#93;</span> &amp;&amp; m &gt;= _mag<span style="">&#91;</span>j+<span style="">1</span><span style="">&#93;</span> <span style="">&#41;</span>
                     <span style="">&#123;</span>
<span style="color: #991111;">-                        if<span style="">&#40;</span> m &gt; high &amp;&amp; !prev_flag &amp;&amp; _map<span style="">&#91;</span>j-mapstep<span style="">&#93;</span> != 2 <span style="">&#41;</span></span>
<span style="color: #00b000;">+                        volatile int k = j - mapstep;</span>
<span style="color: #00b000;">+                        if<span style="">&#40;</span> m &gt; high &amp;&amp; !prev_flag &amp;&amp; _map<span style="">&#91;</span>k<span style="">&#93;</span> != 2 <span style="">&#41;</span></span>
                         <span style="">&#123;</span>
                             CANNY_PUSH<span style="">&#40;</span> _map + j <span style="">&#41;</span>;
                             prev_flag = <span style="">1</span>;
<span style="color: #440088;">@@ -253,7 +254,8 @@</span>
                 <span style="">&#123;</span>
                     if<span style="">&#40;</span> m &gt; _mag<span style="">&#91;</span>j+magstep2<span style="">&#93;</span> &amp;&amp; m &gt;= _mag<span style="">&#91;</span>j+magstep1<span style="">&#93;</span> <span style="">&#41;</span>
                     <span style="">&#123;</span>
<span style="color: #991111;">-                        if<span style="">&#40;</span> m &gt; high &amp;&amp; !prev_flag &amp;&amp; _map<span style="">&#91;</span>j-mapstep<span style="">&#93;</span> != 2 <span style="">&#41;</span></span>
<span style="color: #00b000;">+                        volatile int k = j - mapstep;</span>
<span style="color: #00b000;">+                        if<span style="">&#40;</span> m &gt; high &amp;&amp; !prev_flag &amp;&amp; _map<span style="">&#91;</span>k<span style="">&#93;</span> != 2 <span style="">&#41;</span></span>
                         <span style="">&#123;</span>
                             CANNY_PUSH<span style="">&#40;</span> _map + j <span style="">&#41;</span>;
                             prev_flag = <span style="">1</span>;
<span style="color: #440088;">@@ -268,7 +270,8 @@</span>
                     s = s &lt; <span style="">0</span> ? -<span style="">1</span> : <span style="">1</span>;
                     if<span style="">&#40;</span> m &gt; _mag<span style="">&#91;</span>j+magstep2-s<span style="">&#93;</span> &amp;&amp; m &gt; _mag<span style="">&#91;</span>j+magstep1+s<span style="">&#93;</span> <span style="">&#41;</span>
                     <span style="">&#123;</span>
<span style="color: #991111;">-                        if<span style="">&#40;</span> m &gt; high &amp;&amp; !prev_flag &amp;&amp; _map<span style="">&#91;</span>j-mapstep<span style="">&#93;</span> != 2 <span style="">&#41;</span></span>
<span style="color: #00b000;">+                        volatile int k = j - mapstep;</span>
<span style="color: #00b000;">+                        if<span style="">&#40;</span> m &gt; high &amp;&amp; !prev_flag &amp;&amp; _map<span style="">&#91;</span>k<span style="">&#93;</span> != 2 <span style="">&#41;</span></span>
                         <span style="">&#123;</span>
                             CANNY_PUSH<span style="">&#40;</span> _map + j <span style="">&#41;</span>;
                             prev_flag = <span style="">1</span>;</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://guillaume.segu.in/blog/code/178/debugging-cvcanny-on-x86_64/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rant of the day : OpenCV-python 2.0 package on Fedora 13</title>
		<link>http://guillaume.segu.in/blog/code/175/rant-of-the-day-opencv-python-2-0-package-on-fedora-13/</link>
		<comments>http://guillaume.segu.in/blog/code/175/rant-of-the-day-opencv-python-2-0-package-on-fedora-13/#comments</comments>
		<pubDate>Thu, 25 Mar 2010 00:46:08 +0000</pubDate>
		<dc:creator>iXce</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[OpenCV]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[fedora 13]]></category>
		<category><![CDATA[rant]]></category>

		<guid isPermaLink="false">http://guillaume.segu.in/blog/?p=175</guid>
		<description><![CDATA[Today I&#8217;ve been looking at opencv-python for a quick project (I&#8217;d like to practice OpenCV a little bit). Installed the opencv-python package on Fedora 13, headed to the samples directory (/usr/share/opencv/samples/python/), started running one of them and&#8230; boum, segfault. Tried another one (the inpainting one), and it worked. A third one&#8230; segfault. Most of the [...]]]></description>
			<content:encoded><![CDATA[<p>Today I&#8217;ve been looking at <a href="http://opencv.willowgarage.com/documentation/python/index.html">opencv-python</a> for a quick project (I&#8217;d like to practice OpenCV a little bit). Installed the opencv-python package on Fedora 13, headed to the samples directory (/usr/share/opencv/samples/python/), started running one of them and&#8230; boum, segfault. Tried another one (the inpainting one), and it worked. A third one&#8230; segfault. Most of the samples in there segfaulted, mostly with SWIG errors about wrong parameters, always mentioning int64 (I&#8217;m using a x86_64 kernel &#038; distribution).</p>
<p>After half an hour of failure on trying to get opencv.i686 work alongside my x86_64 python, I went back to the OpenCV website to check if there was some known heavy problems with x86_64 systems and&#8230; I discovered that&nbsp;:</p>
<blockquote><p>Starting with release 2.0, OpenCV has a new Python interface. (The previous Python interface is described in SwigPythonInterface.)</p></blockquote>
<p>Wait wait wait, you mean that during all this time I was running the OLD, pre-2.0 Python interface&nbsp;? Why the hell does the opencv-python 2.0 package provides both the new and the old interfaces&nbsp;? (well, I know the answer : backwards compatibility). Meh <img src='http://guillaume.segu.in/blog/wp-includes/images/smilies/sad.png' alt=':(' class='wp-smiley' />  Anyway, I wish the old samples would get ported to the new interface&#8230; At the moment there&#8217;s no sample using it at all&nbsp;:/</p>
]]></content:encoded>
			<wfw:commentRss>http://guillaume.segu.in/blog/code/175/rant-of-the-day-opencv-python-2-0-package-on-fedora-13/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Doing basic UML-like diagrams for Python code</title>
		<link>http://guillaume.segu.in/blog/code/160/doing-basic-uml-like-diagrams-for-python-code/</link>
		<comments>http://guillaume.segu.in/blog/code/160/doing-basic-uml-like-diagrams-for-python-code/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 00:56:15 +0000</pubDate>
		<dc:creator>iXce</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[diagram]]></category>
		<category><![CDATA[uml]]></category>

		<guid isPermaLink="false">http://guillaume.segu.in/blog/?p=160</guid>
		<description><![CDATA[For a project midterm presentation, we were asked to produce a bunch of slides explaining our project architecture and implementation choices. Apart of the obvious things (libraries in use, network protocol&#8230;), I had no real clue on what I could put in, so I thought I&#8217;d just throw some UML-like diagrams and that it would [...]]]></description>
			<content:encoded><![CDATA[<p>For a project midterm presentation, we were asked to produce a bunch of slides explaining our project architecture and implementation choices. Apart of the obvious things (libraries in use, network protocol&#8230;), I had no real clue on what I could put in, so I thought I&#8217;d just throw some UML-like diagrams and that it would be fine. The only detail was&nbsp;: how to produce these diagrams&nbsp;?</p>
<p>Since the project code was written in Python, all the inheritance relations were already held by the code and could be introspected, so that it was theoretically possible to automatically produce the inheritance diagram. And it actually is, and is implemented by things like the <a href="http://epydoc.sourceforge.net/">Epydoc</a> (a documentation generator for Python code) parser, as well as the diagram generation, which Epydoc also implements. The only thing is that I wasn&#8217;t satisfied by the Epydoc diagrams since they were limited to the inheritance relationships, while I was also willing to include usage relationships and display only the main methods and variables of my objects.</p>
<p>I thus wrote <a href="http://guillaume.segu.in/cgit/umlpy.git/">Umlpy</a>, a UML-like class diagram generator for Python code, which depends on Epydoc (for the parser) and python-graphviz (for the graph generation, it produces nicely spaced graphs and can output jpg, png or pdf files, and probably more). It handles the aforementioned requirements through docstrings parsing and introspection. Check the <a href="http://guillaume.segu.in/cgit/umlpy.git/tree/README">Umlpy README file</a> for more documentation on how to use it. It took me about 10 minutes to get to the result I was expecting (it&#8217;s basically about adding a little docstring for usage relationship, and copy-pasting a docstring on methods or variables you want to see on the diagram.</p>
<p>This wouldn&#8217;t be complete without the mandatory screenshot, and <a href="http://guillaume.segu.in/cgit/umlpy.git/tree/example.py?id=16c34deeb3340aeb470958e2b2278c6c703fc5d5">this example code</a> results into this diagram&nbsp;:<br />
<img src="http://guillaume.segu.in/blog/wp-content/uploads/2010/03/example.png" alt="Umlpy result example" title="Umlpy result example" width="384" height="320" class="aligncenter size-full wp-image-161" /></p>
]]></content:encoded>
			<wfw:commentRss>http://guillaume.segu.in/blog/code/160/doing-basic-uml-like-diagrams-for-python-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cloud Computing for home usage</title>
		<link>http://guillaume.segu.in/blog/home/149/cloud-computing-for-home-usage/</link>
		<comments>http://guillaume.segu.in/blog/home/149/cloud-computing-for-home-usage/#comments</comments>
		<pubDate>Sun, 21 Mar 2010 23:27:32 +0000</pubDate>
		<dc:creator>iXce</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[~home]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[cloudpy]]></category>
		<category><![CDATA[distributed]]></category>
		<category><![CDATA[fault-torelant]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://guillaume.segu.in/blog/?p=149</guid>
		<description><![CDATA[Last autumn I had to do some particularly cpu-time consuming but completely independant computations on thousands of pictures (namely computing SIFT keypoints on high resolution images). Using my laptop, it would have taken hundreds of hours to complete (it took about 20 minutes per image), but it could be easily done in a distributed manner [...]]]></description>
			<content:encoded><![CDATA[<p>Last autumn I had to do some particularly cpu-time consuming but completely independant computations on thousands of pictures (namely computing SIFT keypoints on high resolution images). Using my laptop, it would have taken hundreds of hours to complete (it took about 20 minutes per image), but it could be easily done in a distributed manner on dozens of machines.</p>
<p>I thus started writing a little cloud-computing alike framework to handle the distributed computations in a safe manner&nbsp;: the machines I was intending to run my computations on were public-access machines and could get rebooted at any time, so the computation (let&#8217;s call it task from now on) that was started on it would never end.</p>
<p>There&#8217;s no trick here, the user defines his tasks, an entry point which sets off the initial tasks, and that&#8217;s it. The tasks are stored in a workqueue, which is handled by a master node, which assigns tasks to the other nodes (actually, the master server is split in two, the &#8220;heartbeat&#8221; server which monitors slaves status, and a taskqueue server from which the slaves pull their tasks). If a node does not complete a task within a user-defined amount of time, the master assigns it to another node. Yet, if the initial node manages to complete the task before the second one, the task gets completed anyway (this prevents infinite task respawning in case of an unexpectedly long task).</p>
<p>The tasks may use data stored in either a file-like storage or in a database. Since the whole thing is in Python without any runtime restriction, any arbitrary code or binary can be ran through this thing, which feels like a great pro versus frameworks where only a few languages are supported. A nice feature is that each task can be associated to a file pack (holding e.g. binaries which will be ran by the task) which is automatically deployed or cleaned when the task is started on the node.</p>
<p>Let&#8217;s also mention that the slaves are automatically deployed based on a simple configuration file (through ssh/scp)&nbsp;; that applications are easy to deploy as well (the initial files, the entry points and al are defined in a single config file, form which the deploy tool automagically creates the file packs, updates the pack data to the heartbeat server and plugs the entry point into the taskqueue) and that there are only a few deps for the slaves (python and python-yaml), and not much awful ones for the various servers (mostly add sqlalchemy to the slaves deps).</p>
<p>There are still some points I&#8217;d like to improve. I&#8217;d first like to make the master node dynamic, and not static like it is now. Nodes which may elect as master (i.e. those who may directly connect to the various storages) would use a distributed protocol to actually elect the master (I&#8217;ve worked on such stuff last year during a complexity course, see my (French) summary about the subject&nbsp;: <a href="http://guillaume.segu.in/papers/calculabilitedistribuee.pdf">Calculabilité Distribuée</a>), and then broadcast to the other nodes the winner of the election. If the current master is unreachable at any time, the electable slaves would start doing the election process right away, but would still try to attempt to reach the master until the election is completed.<br />
I&#8217;d also like to add a way to handle in a nicer way mixes of 32 and 64 bits architectures (i.e. provide a way to define 32-bit/64-bit specific initial packages).<br />
Security is another matter, I guess I should probably add some chrooting to the runtime environment, and secure the transmissions between the nodes (note that there&#8217;s absolutely no notion of authentication in any part of the software at the moment).</p>
<p>The only problem is that whan I got to the point I had finished the framework, I had no time to write the little bit of script to actually test the whole thing, and a friend had thrown the pictures to his high-end quadcore computer, so I had no chance to test it on a real life scenario. I&#8217;ll try someday, though. If you want to give a try to the latest version I pushed (it lacks the database backend and documentation at the moment, though I intend to finish/test them and upload them someday soon), check the <a href="http://guillaume.segu.in/cgit/cloudpy.git/">Cloudpy git repo</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://guillaume.segu.in/blog/home/149/cloud-computing-for-home-usage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ns-3 multithreading</title>
		<link>http://guillaume.segu.in/blog/home/143/ns-3-multithreading/</link>
		<comments>http://guillaume.segu.in/blog/home/143/ns-3-multithreading/#comments</comments>
		<pubDate>Sat, 20 Mar 2010 00:40:53 +0000</pubDate>
		<dc:creator>iXce</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Internships]]></category>
		<category><![CDATA[~home]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[internship]]></category>
		<category><![CDATA[multithreading]]></category>
		<category><![CDATA[ns-3]]></category>

		<guid isPermaLink="false">http://guillaume.segu.in/blog/?p=143</guid>
		<description><![CDATA[Last summer, I went to INRIA Sophia Antipolis (INRIA is the French research institute for computer science, basically&#160;; Sophia Antipolis names a group of villages near Nice and Antibes (on the Côte d&#8217;Azur) on which are installed quite a lot of technology businesses, among which HP or Amadeus) for a 3 months internship in PLANETE [...]]]></description>
			<content:encoded><![CDATA[<p>Last summer, I went to <a href="http://www-sop.inria.fr/">INRIA Sophia Antipolis</a> (INRIA is the French research institute for computer science, basically&nbsp;; Sophia Antipolis names a group of villages near Nice and Antibes (on the Côte d&#8217;Azur) on which are installed quite a lot of technology businesses, among which HP or <a href="http://www.amadeus.net/">Amadeus</a>) for a 3 months internship in <a href="http://planete.inria.fr/">PLANETE</a> project, under the advisory of <a href="http://cutebugs.net/">Mathieu Lacage</a>, a great software engineer.</p>
<p>Before any extra details, let&#8217;s point to <a href="http://guillaume.segu.in/code/ns-3-multithreading.hg/">the code</a>, <a href="http://guillaume.segu.in/papers/ns3-multithreading.pdf">the report</a> and <a href="http://guillaume.segu.in/slides/ns3-multithreading.pdf">the slides</a>. There are also some slides somewhere in the wild which were made for a quick talk given by Mathieu at <a href="http://www.wns3.org">ns-3 workshop at SIMUtools 2010</a>.</p>
<p>The goal of the internship was to enable the <strong>seamless</strong> use of multicore parallelization in <a href="http://www.nsnam.org/">ns-3</a> network simulator to speed up simulations.<br />
The obvious idea behind this project is that with all the trends on going more and more towards highly multicore architectures even for personal computers, such a change would possibly allow large speedups without having to directly throw a lot of hardware in the balance and without requiring most likely complicated configurations from the user.</p>
<p>Our goal was to make theses changes entirely transparent for both developers (<em>i.e.</em> those working on improving the ns-3 framework &#8212; routing stuff, devices handling&#8230;) and users (<em>i.e.</em> those using ns-3 to simulate their protocols&#8230;).</p>
<p>Before going into the optimization details, let&#8217;s mention the basic idea of the algorithms that we used for the synchronisation of the execution units (the cores, in our case), algorithms which are part of the conservative synchronization algorithms class (as opposed to optimistic algorithms class).<br />
We first tried a message-passing based approach, namely the Chandy, Misra, Bryant algorithm. The whole idea in this algorithm is that each node knows how far in the future it can avance without any risk of simulation desynchronization. This is based on knowing the physical transfer delays, plus the current date of the neighboring nodes ; date which is passed through recurrent messages. This way, under certain conditions (namely that no link has a null transfer time), the simulation will safely advance.<br />
We found out that this approach would lead to no performance gain due to the amount of messages which have to be passed compared to the actual amount of stuff done per time unit.<br />
We then used a barrier-based synchronization algorithm&nbsp;: at each iteration, a global maximum date is determined, based on the current date of each node and the physical transfer delays (again). All the node are thus allowed to process events up to this date, then wait at the barrier, and then go to the next iteration when everyone has reached the barrier. The actual barrier implementation is a fun part, which is described in the report. From a trivial semaphor implementation to a fully optimized, tree-shaped implementation, performance gains of over a 100 fold can be observed.</p>
<p>One of the usual challenges when doing parallel computing is to define a proper partition of what each execution unit does. For instance, when working on a network of nodes (which are computers, routers&#8230;), which nodes should be handled by which execution unit&nbsp;? Since we don&#8217;t want to ask the user about what he thinks would be the best, and since we can&#8217;t just use topology clues to make a good partitionning (because it also depends on the actual dynamics of the network, which we can&#8217;t predict), we had to use a dumb solution and make it smart. The solution we found there was to have both dedicated and global nodes&nbsp;: a given percentage of nodes is dedicated to each execution unit, while a global pool of nodes remains undedicated. When an unit has finished processing it&#8217;s own dedicated nodes, it starts picking nodes from the global pool and process them. This way, these units won&#8217;t waste their time waiting for other units which have to handle more complicated nodes in their dedicated set, thus requiring more processing time just for the local set.</p>
<p>Now you are going to ask, why not just use a global pool and let all the units directly pick nodes to process from there&nbsp;? The whole problem is that this global list must be protected, two threads just can&#8217;t pick stuff from it at the same time &#8212; this would lead to awful memory corruptions, and probably more. Consequently, we need to use either mutexes (<em>i.e.</em> locks) or atomic operations to modify the list. Atomic operations are cheap compared to locks, and yet they are still at least 10 times slower than normal operations. This justifies the whole dedicated + global pools approach.</p>
<p>Now, there were more thread safety problems. While most of them were easily disarmed for minor performances loss (such as disabling free list or caches), there was still a major issue&nbsp;: reference counting. Indeed, in order to be as user-friendly as possible, ns-3 provides (and heavily uses) a reference counting system to ease memory handling for users. The whole problem there is that the counters might be accessed concurrently by two threads at once. What happens when a thread references an objet at microseconds before another thread unreferences it&nbsp;?<br />
An usual i++ operation is usualy done by taking i from memory to a register, adding 1 to it and putting it back to memory. Now, if the original reference count was 1, we could have the first thread taking i = 1 from memory, the second one taking i = 1 from memory, remov 1, putting i = 0 back into memory, then figuring i == 0 and trashing the objet, then the first threading adding 1 locally, and putting i = 2 back into memo&#8230; wait, this memory has been unallocated. Game over.<br />
Again, a possible solution is to use atomic operations. Oh right, they are awfully expensive. Don&#8217;t care, let&#8217;s try, there must not be that much ref/unrefs going around there. And then&#8230; ow, actually, we just catched a plain 100% runtime increase.<br />
While we fixed some of the stupidities that lead to such horrible increases, the problem was still on.<br />
We tried to use thread local storage to maintain a per-thread reference count, but this did not really solve the problem, just helped.<br />
We finally tried to use thread local buffers of Ref/Unref operations, which would be batch-ran by a single thread. This lead to nice performance improvements over the previous solutions, but if I remember correctly under certain unknown conditions the code would badly crash or eat all the memory. Urgh.</p>
<p>Still, in some conditions, I still managed to get over 20% performance improvement with 8 threads (iirc).</p>
<p>The conclusion of all this is that multithreaded programming is definitely not a trivial problem and that converting an existing software to gain from multithreading is not that easy. For more information, numeric data and all, check the report.</p>
<p>Now, I have had no time since middle September to work on the issue, but I know Mathieu has. It&#8217;d be awesome to have some news from him here&#8230; To be continued, hopefully.</p>
]]></content:encoded>
			<wfw:commentRss>http://guillaume.segu.in/blog/home/143/ns-3-multithreading/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

