<?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>realmike.org</title>
	<atom:link href="http://realmike.org/blog/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://realmike.org/blog</link>
	<description>Python and C++ developer, GNU/Linux user, FLOSS supporter</description>
	<lastBuildDate>Sat, 27 Aug 2011 20:30:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>EuroPython 2011 Notes</title>
		<link>http://realmike.org/blog/2011/07/10/europython-2011-notes/</link>
		<comments>http://realmike.org/blog/2011/07/10/europython-2011-notes/#comments</comments>
		<pubDate>Sun, 10 Jul 2011 13:05:42 +0000</pubDate>
		<dc:creator>Michael Fötsch</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[europython]]></category>

		<guid isPermaLink="false">http://realmike.org/blog/?p=520</guid>
		<description><![CDATA[These are some of my notes from EuroPython 2011. I mostly collect projects and tools that are of immediate interest to me in my own work. If you&#8217;re interested in the complete list of talks and would like to download the slides or watch the talks on video, you can find those on the EuroPython <span style="color:#777"> . . . &#8594; <a href="http://realmike.org/blog/2011/07/10/europython-2011-notes/">Read More</a></span>]]></description>
			<content:encoded><![CDATA[<p><em>These are some of my notes from <a href="http://ep2011.europython.eu/">EuroPython 2011</a>. I mostly collect projects and tools that are of immediate interest to me in my own work</em>.<em> If you&#8217;re interested in the complete list of talks and would like to download the slides or watch the talks on video, you can find those on the <a href="http://ep2011.europython.eu/p3/schedule/ep2011/list/">EuroPython talks page</a>. Also, Julie Pichon has <a href="http://www.jpichon.net/tag/europython/">summaries of some interesting talks</a> on her site.<br />
</em></p>
<div id="attachment_532" class="wp-caption alignright" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2011/07/europython_bag.jpg"><img class="size-medium wp-image-532" title="EuroPython Bag" src="http://realmike.org/blog/wp-content/uploads/2011/07/europython_bag-300x254.jpg" alt="" width="300" height="254" /></a><p class="wp-caption-text">EuroPython Bag</p></div>
<p><strong>Python Environment</strong></p>
<p>At our company, we deploy non-interactive Python tools to our internal users. So far, we deploy these tools into the users&#8217; local Python installations. Problems arise when the package versions that our tools require are different from the versions that the user has installed, or when updates to our tools require new dependencies to be installed. To avoid such problems, the &#8220;virtualenv&#8221; package allows you to keep separate Python environments for different tools. The &#8220;pip&#8221; package can then be used to automatically install dependencies into these environments. Alex Clemesha has an article up on his blog about the <a href="http://www.clemesha.org/blog/modern-python-hacker-tools-virtualenv-fabric-pip">Tools of the Modern Python Hacker: Virtualenv, Fabric and Pip</a>.</p>
<p>Another useful addition to the Python toolbox is the &#8220;nose&#8221; unit-testing package, which extends the Python &#8220;unittest&#8221; module. It has advanced support for test fixtures, generated test cases, running test batteries, and more. More at the <a href="http://somethingaboutorange.com/mrl/projects/nose/">&#8220;nose&#8221; project homepage</a>.</p>
<p><span id="more-520"></span><strong>JavaScript</strong></p>
<p>As a language, I find JavaScript pretty&#8230;awful. But it can be used to build pretty cool stuff for the web, so it&#8217;s worth learning. That&#8217;s why I attended Jonathan Fine&#8217;s &#8220;<a href="http://ep2011.europython.eu/conference/talks/javascript-for-python-programmers">JavaScript for Python Programmers</a>&#8221; training.</p>
<p>One of the learning resources that Jonathan recommended was &#8220;<a href="http://www.youtube.com/watch?v=hQVTIJBZook">JavaScript: The Good Parts</a>&#8221; (on YouTube):</p>
<p><object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/hQVTIJBZook?version=3&amp;hl=en_US" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/hQVTIJBZook?version=3&amp;hl=en_US" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p><strong>Network Programming</strong></p>
<p>For the grid computing system at our company, we rely mostly on the standard XML-RPC modules in Python. All the high-level logic, such as message queues, failure handling, authentication, etc. are custom-built on top of that.</p>
<p>Unsurprisingly, there is a wealth of existing libraries that might make our lives easier by not having to reinvent the wheel. (While adding their own layers of complexity, I&#8217;m sure.)</p>
<ul>
<li><a href="http://django-rest-framework.org/">Django REST Framework</a>—A library for adding a <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">RESTful</a> API to a Django application.</li>
<li><a href="http://celeryproject.org/">Celery</a>—An asynchronous task queue based on distributed message passing.</li>
<li><a href="http://www.zeromq.org/">ZeroMQ</a>—A &#8220;socket library that acts as a concurrency framework.&#8221;</li>
<li><a href="http://www.rabbitmq.com/">RabbitMQ</a>—Message-oriented middleware. <a href="http://blogs.digitar.com/jjww/2009/01/rabbits-and-warrens/">Jason Williams describes</a> what it is and what it can be used for.</li>
<li><a href="http://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol">AMQP</a> (Advanced Message Queuing Protocol)—The protocol that RabbitMQ implements.</li>
<li><a href="http://www.gevent.org/">gevent</a>—&#8221;A coroutine-based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libevent event loop.&#8221; Geez, I don&#8217;t even begin to understand what this means&#8230;</li>
<li><a href="http://twistedmatrix.com/">Twisted</a>—An event-driven network engine. (<a href="http://ep2011.europython.eu/conference/talks/asynchronous-programming-with-twisted">Twisted training</a> by Orestis Markou.)</li>
</ul>
<p>Alex Clemesha&#8217;s article &#8220;<a href="http://www.clemesha.org/blog/realtime-web-apps-python-django-orbited-twisted">Real-world real-time web apps with Python equals Django + Orbited + Twisted</a>&#8221; describes how some of these fit in the big picture—and adds even more buzzwords and acronyms for good measure.</p>
<p>Some of these libraries come with implementations for the architectural patterns described in the book &#8220;<a href="http://www.cse.wustl.edu/~schmidt/POSA/POSA2/">Pattern-Oriented Software Architecture: Patterns for Concurrent and Networked Objects</a>.&#8221;</p>
<p><strong>Little Tidbits</strong></p>
<ul>
<li><a href="http://www.lag.net/paramiko/">Paramiko</a>—An SSH client/server library written in Python (using PyCrypto). Jesse Noller has an <a href="http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/">introduction</a> on his site.</li>
<li><a href="http://kivy.org/">Kivy</a>—A &#8220;library for rapid development of applications that make use of innovative user interfaces, such as multi-touch apps.&#8221; For his lightning talk, <a href="http://txzone.net/2011/06/kivy-at-europython-lightning-explanation/">Mathieu Virbel</a> used a really cool presentation tool, <a href="http://github.com/tito/presemt">PreseMT</a>, that is itself based on Kivy. (<a href="http://youtu.be/SwYnUhWx0FY">Watch on YouTube</a>)<br />
<object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/SwYnUhWx0FY?version=3&amp;hl=en_US" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/SwYnUhWx0FY?version=3&amp;hl=en_US" allowscriptaccess="always" allowfullscreen="true"></embed></object></li>
<li><a href="http://www.tarsnap.com/scrypt.html">scrypt</a> key derivation function—This can be used to calculate password hashes in a way that makes brute-force attacks way harder than using traditional MD5 or SHA hashes. <a href="http://pypi.python.org/pypi/scrypt/0.5.1">Python bindings</a> exist.</li>
<li><a href="http://tk0miya.bitbucket.org/blockdiag/build/html/index.html">blockdiag</a>—A block diagram image generator. It uses an input file format that&#8217;s similar to GraphViz.</li>
</ul>
<p><em><strong>See you at EuroPython 2012!</strong></em></p>
]]></content:encoded>
			<wfw:commentRss>http://realmike.org/blog/2011/07/10/europython-2011-notes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Continued Fractions for Representing Real Numbers</title>
		<link>http://realmike.org/blog/2011/07/09/continued-fractions-for-representing-real-numbers/</link>
		<comments>http://realmike.org/blog/2011/07/09/continued-fractions-for-representing-real-numbers/#comments</comments>
		<pubDate>Sat, 09 Jul 2011 16:36:27 +0000</pubDate>
		<dc:creator>Michael Fötsch</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[europython]]></category>

		<guid isPermaLink="false">http://realmike.org/blog/?p=507</guid>
		<description><![CDATA[This is something I learned at EuroPython 2011. I think it came up in a lightning talk by Alex Martelli, but I don&#8217;t recall exactly. Continued fractions are a representation of real numbers that allows for arbitrary-precision arithmetic. If you&#8217;ve worked with floating-point numbers in Python (or most any other programming language, for that matter), <span style="color:#777"> . . . &#8594; <a href="http://realmike.org/blog/2011/07/09/continued-fractions-for-representing-real-numbers/">Read More</a></span>]]></description>
			<content:encoded><![CDATA[<p><em>This is something I learned at EuroPython 2011. I think it came up in a lightning talk by Alex Martelli, but I don&#8217;t recall exactly.</em></p>
<p>Continued fractions are a representation of real numbers that allows for arbitrary-precision arithmetic.</p>
<p>If you&#8217;ve worked with floating-point numbers in Python (or most any other programming language, for that matter), you are aware of precision problems like this:</p>
<pre><code>x = 1.0 / 3.0
total = 0.0
for i in range(300):
    total += x
print repr(total)
print total == 100.0
</code></pre>
<p>This prints 99.99999999999966, not 100.0. The reason is that the IEEE 754 floating-point representation of 1/3 isn&#8217;t exact, and this (initially small) error accumulates 300 times.</p>
<p><span id="more-507"></span>There is a different representation for real numbers: continued fractions.</p>
<ul>
<li>Consider the number PI = <strong>3</strong>.141592653589793.</li>
<li>This can also be written as: <strong>3</strong> + 1 / <strong>7</strong>.062513305931052</li>
<li>This can be written as: <strong>3</strong> + 1 / (<strong>7</strong> + 1 / <strong>15</strong>.996594406684103)</li>
<li>This can be written as: <strong>3</strong> + 1 / (<strong>7</strong> + 1 / (<strong>15</strong> + 1 / <strong>1</strong>.0034172310150002))</li>
<li>This can be written as: <strong>3</strong> + 1 / (<strong>7</strong> + 1 / (<strong>15</strong> + 1 / (<strong>1</strong> + 1 / <strong>292</strong>.6345908750162)))</li>
<li>This can be written as: <strong>3</strong> + 1 / (<strong>7</strong> + 1 / (<strong>15</strong> + 1 / (<strong>1</strong> + 1 / (<strong>292</strong> + 1 / <strong>1</strong>.5758184357354204))))</li>
</ul>
<p>This can be stored efficiently in some form of list: PI = [3, 7, 15, 1, 292, 1, ...]. The <a href="http://sun.aei.polsl.pl/~mciura/software/cf.py">&#8220;cf&#8221; module</a> is a Python implementation of continued fractions by Marcin Ciura that uses lazy evaluation. Here&#8217;s the previous example rewritten using continued fractions:</p>
<pre><code>from cf import cf
x = cf(1.0) / cf(3.0)
total = cf(0.0)
for i in range(300):
    total += x
print repr(float(total))    # prints 100.0
print total == 100.0
</code></pre>
<p>The mathematical background is explained on <a href="http://en.wikipedia.org/wiki/Continued_fraction">Wikipedia</a> and in this <a href="http://perl.plover.com/classes/cftalk/">presentation by Mark Jason Dominus</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://realmike.org/blog/2011/07/09/continued-fractions-for-representing-real-numbers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Live Desktop Streaming via DLNA on GNU/Linux</title>
		<link>http://realmike.org/blog/2011/02/09/live-desktop-streaming-via-dlna-on-gnulinux/</link>
		<comments>http://realmike.org/blog/2011/02/09/live-desktop-streaming-via-dlna-on-gnulinux/#comments</comments>
		<pubDate>Wed, 09 Feb 2011 20:38:39 +0000</pubDate>
		<dc:creator>Michael Fötsch</dc:creator>
				<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[dlna]]></category>
		<category><![CDATA[ffmpeg]]></category>
		<category><![CDATA[fuse]]></category>
		<category><![CDATA[matroska]]></category>
		<category><![CDATA[mediatomb]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[screencasting]]></category>
		<category><![CDATA[streaming]]></category>

		<guid isPermaLink="false">http://realmike.org/blog/?p=450</guid>
		<description><![CDATA[TWiT and the Ubuntu terminal on a TV set via DLNA Many modern TVs (and set-top boxes, gaming consoles, etc.) support DLNA streaming. Suppose you have a PC that stores all your music, downloaded podcasts, video podcasts, photos, and so on. You can run some DLNA media server software on your PC and stream your <span style="color:#777"> . . . &#8594; <a href="http://realmike.org/blog/2011/02/09/live-desktop-streaming-via-dlna-on-gnulinux/">Read More</a></span>]]></description>
			<content:encoded><![CDATA[<div id="attachment_459" class="wp-caption alignright" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2011/02/twit_on_tv.jpg"><img class="size-medium wp-image-459" title="twit_on_tv" src="http://realmike.org/blog/wp-content/uploads/2011/02/twit_on_tv-300x173.jpg" alt="" width="300" height="173" /></a><p class="wp-caption-text">TWiT and the Ubuntu terminal on a TV set via DLNA</p></div>
<p>Many modern TVs (and set-top boxes, gaming consoles, etc.) support <a href="http://www.dlna.org/digital_living/getting_started/">DLNA</a> streaming. Suppose you have a PC that stores all your music, downloaded podcasts, video podcasts, photos, and so on. You can run some DLNA media server software on your PC and stream your entire media collection to your TV over your home network. No more carrying around USB sticks, it&#8217;s all in your home cloud.</p>
<p>On GNU/Linux, I am using <a href="http://mediatomb.cc/">MediaTomb</a> as my DLNA server. It&#8217;s nothing fancy (it&#8217;s a file server, after all), and it just works.</p>
<p>Okay, this takes care of media files stored on your PC. But can we do more? Is it possible to stream a live capture of your desktop to the TV?</p>
<p>Let&#8217;s say you&#8217;re watching a Flash video in your browser, and there&#8217;s no way to download the video file. Or, you&#8217;re watching a live event being streamed via Flash or whatever. It would be kinda cool to be able to stream that to your TV via DLNA. And it&#8217;s possible—not trivial, mind you, but I&#8217;ve seen it working at least once&#8230;</p>
<p><span id="more-450"></span></p>
<p>The same approach that&#8217;s taken here for live streaming might also be useful for on-the-fly transcoding (e.g., an .ogg file needs to be transcoded to .vob for the player to be able to read it).</p>
<p>(I should mention that something like this isn&#8217;t unheard of. In fact, my Philips TV came with the Windows-only(!) WiFi MediaConnect software to do desktop streaming. I have never seen it in action, because I don&#8217;t use Windows. Of course, Philips based the TV&#8217;s firmware on the Linux kernel, like so many other manufacturers do. But, also unsurprisingly, they use it because it&#8217;s &#8220;free as in beer&#8221;, not because they care about users&#8217; freedom. The fact that I could still get all this to work on GNU/Linux is thanks to the invaluable work of many free software projects: MediaTomb, <a href="http://www.ffmpeg.org/">FFmpeg</a>, <a href="http://www.matroska.org/index.html">Matroska</a>, <a href="http://fuse.sourceforge.net/">FUSE</a>, <a href="http://python.org/">Python</a>, to name just a few.)</p>
<p><strong>What you can find here</strong></p>
<p>I wrote a couple of scripts that allow you to capture your desktop and stream it to a DLNA-capable player. To use the code as-is, your player must support the Matroska (.mkv) file format.</p>
<p>I used the scripts in conjunction with MediaTomb, but other media servers should work just as well.</p>
<p>The scripts are very rough at the edges, and if you are afraid of the command line or of reading Python code, you shouldn&#8217;t attempt to use them.</p>
<p><a href="http://realmike.org/blog/wp-content/uploads/2011/02/dlna_live_streaming.zip">Download the scripts</a></p>
<p>See <a href="#usage">Usage Instructions</a> below.</p>
<p><strong>What is missing / </strong><strong>Invitation to contributors</strong></p>
<p>As I mentioned, the scripts only work with devices that can play Matroska files via DLNA right now. The basic ideas and concepts should apply equally as well to MPEG-2 and other formats. I&#8217;m not sure about MPEG-4 files, though, and I would appreciate feedback from someone more familiar with the format.</p>
<p>The scripts could definitely use better error checking, a nicer command-line interface, and lots of testing. If anyone&#8217;s interested in helping with that, please contact me.</p>
<p><a name="usage"><strong>Usage Instructions</strong></a></p>
<ul>
<li>Make <a href="#dlna_fuse_config">some changes to dlna_fuse.py</a> to specify the temporary file, control the captured display region, set the output format, etc.</li>
<li>Configure MediaTomb, as <a href="#mediatomb_config">described below</a>.</li>
<li>Mount dlna_fuse.py with &#8220;python dlna_fuse.py -s -f fuse_mnt&#8221;. This automatically starts the capture.</li>
<li>At this point, add the file &#8220;fuse_mnt/a/fuse_live.mkv&#8221; to MediaTomb&#8217;s database. (You only have to do this once.)</li>
<li>Start playback.</li>
<li>As this is more of a proof-of-concept than a polished tool, please read on below and let me know if you have any feedback.</li>
</ul>
<p><strong>The Basic Idea</strong></p>
<p>First off, how do we capture the desktop? Someone named Verb3k explains this in &#8220;<a href="http://verb3k.wordpress.com/2010/01/26/how-to-do-proper-screencasts-on-linux/">How to do Proper Screencasts on Linux Using FFmpeg</a>&#8220;. Here&#8217;s an example:</p>
<blockquote><p>ffmpeg -f alsa -ac 2 -i pulse -f x11grab -r 20 -s 1024&#215;576  -i :0.0+128,224 -acodec ac3 -ac 1 -vcodec libx264 -vpre fast -threads 0 -f matroska ~/Videos/capture.mkv</p></blockquote>
<p>This command line takes sound from PulseAudio and screen images from X11 (at 20 fps) and combines them into a Matroska file using the H.264 codec for video and AC3 for audio. It grabs a rectangular area of 1024×576 pixels, 128 pixels from the left edge of the screen and 224 pixels from the top edge of the screen.</p>
<p>Now, what happens when we have MediaTomb serve up the file capture.mkv to the player while the file is still being captured? If you are luckier than I was, it might just work, and you&#8217;re done. Maybe you can find some other combination of video codec, audio codec, and container file format that your player likes better. (Before attempting to do live streaming, you should have ffmpeg convert an existing video file, and finish the conversion before starting playback, in order to find a format that your player understands.)</p>
<p>Starting the playback while the capture was still in progress didn&#8217;t work for me. Instead, when starting playback too soon after capturing had begun, the player would simply tell me the file was unplayable. When waiting for a few minutes, the player would play up until the point where I had started playback. That is, when I started playback after having captured for five minutes, playback would stop after five minutes, even if the captured file contained 10 minutes at that point.</p>
<p>You probably have an idea already why this might have failed. Let&#8217;s take a look at what the file contents might look like while the capture is in progress.</p>
<div id="attachment_456" class="wp-caption aligncenter" style="width: 635px"><a href="http://realmike.org/blog/wp-content/uploads/2011/02/live_file_format.png"><img class="size-full wp-image-456" title="live_file_format" src="http://realmike.org/blog/wp-content/uploads/2011/02/live_file_format.png" alt="" width="625" height="401" /></a><p class="wp-caption-text">A video file after 2 minutes of capturing, after 5 minutes, after it is complete</p></div>
<p>In the figure, you can see a hypothetical file format that stores the data length and video duration in the front, then the video data, then a table containing seek information and other stuff that&#8217;s only known after encoding has finished. This particular encoder seems to update the duration field periodically while encoding is in progress. On the other hand, it leaves the data size field blank until it has finished.</p>
<p>This hypothetical case shows many things that can go wrong when playback starts in the middle of encoding (which, in the case of live streaming, basically means at any time):</p>
<ul>
<li>The player might encounter the &#8220;unknown&#8221; size field and decide that the file is broken.</li>
<li>Or, it takes the &#8220;unknown&#8221; size as an indication that it should seek to the end of the file and determine the size itself (which breaks, because the file has no end yet).</li>
<li>The player might read the duration of 2:00 min. and never look at it again—playback will simply stop after 2:00 min., no matter what happens to the file in the meantime.</li>
<li>The player might know that there&#8217;s supposed to be a seek table, a list of keyframes, a checksum, etc., at the end and fail when it tries to read it.</li>
<li>&lt;endless other complications&gt;</li>
</ul>
<p>The scripts that I wrote try to circumvent these issues in two steps:</p>
<ul>
<li>Modify the file that ffmpeg produces during the capture so that the file appears to be a regular, albeit very, very long, video. Give the player all the information that it needs right away, so that it does not try to seek (through the media server) to various places in the file, searching for the information.
<ul>
<li>For Matroska files, this is what &#8220;matroska_live_filter.py&#8221; does. Hopefully, it will be possible to write filters for other container file formats in the future.</li>
</ul>
</li>
<li>Intercept calls to the filesystem, so that when the player (through the media server) tries to access parts of the file that don&#8217;t exist yet, we can wait for ffmpeg to produce them (if it&#8217;s just video data for 5 seconds in the future, for example), or come up with fake data.
<ul>
<li>This is what &#8220;dlna_fuse.py&#8221; does. This is a virtual (FUSE) filesystem that simply waits for ffmpeg to produce more data when the media server tries to prefetch more data than is available in the file.</li>
</ul>
</li>
</ul>
<p>Matroska is a container format that lends itself well to this kind of interception. Matroska has <a href="http://www.matroska.org/technical/streaming/index.html">streaming support</a> (i.e., it defines what should go into the headers so that players know it&#8217;s a live stream), but unfortunately, my particular player didn&#8217;t care much.</p>
<p>There are other container formats where I&#8217;m not sure that such a thing is possible. In MP4, for example, there are atoms like &#8220;stsz&#8221; (&#8220;sample table sizes&#8221;) and &#8220;stss&#8221; (&#8220;sample table sync samples&#8221;) that seem to go <em>before</em> the video stream and that contain information about the encoded sizes of frames—I&#8217;m not sure there&#8217;s a way to fake this data without waiting for the encoding to finish. If you are familiar with the MP4 or QuickTime formats and have an idea, please leave a comment!</p>
<p><strong>Filtering Matroska for Live Streaming</strong></p>
<p>The <a href="http://www.matroska.org/technical/streaming/index.html">Matroska specification</a> points out that a live stream is designated by setting the &#8220;Segment&#8221; size to &#8220;unknown&#8221;. ffmpeg does this, but it didn&#8217;t convince my TV to treat the file as a live stream. Instead, I ended up simply setting the size to a very large value and setting the duration of the video to 100 hours.</p>
<p>In addition, I suppress &#8220;SeekHead&#8221; elements (pointers to other sections of the file) and &#8220;Cues&#8221; elements (pointers to keyframes for fast-forwarding). This isn&#8217;t strictly necessary; ffmpeg only produces these elements when encoding finishes (which it never does with a live capture). However, this functionality was quite handy when testing out the DLNA streaming with existing .mkv files.</p>
<p>As a final hack, I output 128 KB of &#8220;Void&#8221; data after each &#8220;Cluster&#8221; (which appears to be a block of ~5 seconds of audio/video data). The &#8220;Void&#8221; data doesn&#8217;t serve any purpose other than being able to send data to the player when it requests some. The player pre-fetches data. Without the &#8220;Void&#8221; blocks, there is sometimes not as much data as it requests, because ffmpeg hasn&#8217;t produced it yet. If the requested data can&#8217;t be delivered fast enough, though, the player appears to give up. By producing the &#8220;Void&#8221; data, there is always enough data to satisfy the player, even though the data doesn&#8217;t contain anything useful.—At least, that&#8217;s what I think is happening&#8230;</p>
<p>All this is done in the Python script &#8220;matroska_live_filter.py&#8221;.</p>
<p>Usage:</p>
<ul>
<li><code>python matroska_live_filter.py &lt;mkv-filename&gt;</code> : Output a pretty-printed tree of the Matroska file structure. (Similar to the mkvinfo tool from the <a href="http://www.bunkus.org/videotools/mkvtoolnix/">mkvtoolnix</a> package.)</li>
<li><code>python matroska_live_filter.py -</code> : Read a Matroska file from stdin (maybe the output of ffmpeg writing to stdout). Writes the modified Matroska file to stdout on-the-fly, i.e., it writes data as soon as it becomes available and doesn&#8217;t wait for the input to end.</li>
</ul>
<p>As an example, to filter an ffmpeg-produced live stream, write this:</p>
<blockquote><p>ffmpeg -f alsa -ac 2 -i pulse -f x11grab -r 30 -s 1024&#215;768 -i :0.0 -acodec pcm_s16le -vcodec libx264 -vpre fast -threads 0 &#8211; | python matroska_live_filter.py &#8211; &gt;~/Videos/filtered_live.mkv</p></blockquote>
<p>(I tried to use <a href="http://www.matroska.org/downloads/linux.html">libebml and libmatroska</a> in C++ first. However, documentation was hard to come by, and the code wasn&#8217;t quite self-explanatory. I found a Matroska tag reader written in Python by Johannes Sasongko and built the filter based on that.)</p>
<p><strong>FUSE Filesystem to Fool the Media Server</strong></p>
<p>When you&#8217;re using GNOME, chances are you&#8217;re using FUSE filesystems already. When you use &#8220;Places&#8221;→&#8221;Connect to Server&#8221; to connect to an FTP server, for example, the remote server appears as a local folder in ~/.gvfs. This is a virtual filesystem that uses FUSE.</p>
<p>For the DLNA streaming, I decided to write a FUSE filesystem in Python. This filesystem would appear to MediaTomb as a regular directory containing a Matroska video file. Whenever MediaTomb would access the file or read parts of it, my Python code could intercept these calls and do its magic.</p>
<p>When the filesystem is mounted (i.e., when the Python script is started), the desktop capture is started and redirected to a temporary file. When MediaTomb (or any other program) requests some part of the file, the script can check whether there&#8217;s enough data in the file. If yes, it simply returns the data. If not, it blocks briefly until ffmpeg has written enough data. If the player tries to read too far ahead, this might indicate that the file isn&#8217;t suitable for live streaming yet, and the script will log an error. (This shouldn&#8217;t happen for Matroska files anymore, but it will be useful when trying to add support for more container formats later.)</p>
<p><a name="dlna_fuse_config">The FUSE filesystem is in &#8220;dlna_fuse.py&#8221;. It requires the Python bindings for FUSE (package &#8220;python-fuse&#8221; on Ubuntu).</a></p>
<p>You should make a few changes to the file to adapt it to your needs:</p>
<ul>
<li>Change the variable TEMP_FILE. While ffmpeg captures the desktop, the resulting video is not kept in memory but written to this file. This means, you need some free memory on your hard disk while watching live streams. Of course, the whole purpose of the FUSE filesystem is that the file doesn&#8217;t need to exist physically. At a later point, I will change the FUSE script to keep only a part of the ffmpeg output in memory, and discard older parts once the player has read them. For now, the temporary file is used as a buffer.</li>
<li>Change the ffmpeg command line. The current command corresponds roughly to this:
<ul>
<li><code>MONITOR=$(pactl list | grep -A2 '^Source #' | grep 'Name: .*\.monitor$' | awk '{print $NF}' | tail -n1)</code><br />
<code>parec -d "$MONITOR" | ffmpeg -f s16le -ac 2 -ar 44100 -i - -f x11grab -r 20 -s 1024x576  -i :0.0+128,224 -acodec ac3 -ac 1 -vcodec libx264 -vpre medium -threads 0 -f matroska - | python matroska_live_filter - &gt; ~/Videos/live.mkv</code></li>
</ul>
</li>
<li>Instead of using &#8220;ffmpeg -f alsa -i pulse&#8221;, which produced crackling noises every now and then, I use &#8220;parec&#8221; (PulseAudio recorder) to capture the audio. The part &#8220;-f s16le -ac 2 -ar 44100&#8243; is the format that parec produces (at least for me): 44 kHz, 16-bit stereo. &#8220;-r 20&#8243; instructs ffmpeg to capture at 20 fps. I chose &#8220;-s 1024&#215;576 -i :0.0+128,224&#8243; to capture a 1024-pixel-wide rectangle with an aspect ratio of 16:9 at the center of my screen, which is 1280×1024. You can change this to whatever suits you (as long as your computer can encode it fast enough). &#8220;-acodec ac3 -ac1&#8243; converts the audio to the AC3 codec in mono (the TV had problems with stereo AC3 streams). &#8220;-vcodec libx264 -vpre medium&#8221; uses the &#8220;medium&#8221; profile for the H.264 encoding. &#8220;-vpre&#8221; can also be &#8220;fast&#8221;, &#8220;ultrafast&#8221;, &#8220;lossless_ultrafast&#8221; and lots of others—you need to experiment to find an encoding profile that provides good quality, yet doesn&#8217;t overwhelm your CPU or network.</li>
<li><strong>Note:</strong> If &#8220;parec&#8221; doesn&#8217;t record anything, open the &#8220;PulseAudio Volume Control&#8221; (installed with &#8220;sudo apt-get install pavucontrol&#8221;) and make sure that on the &#8220;Input Devices&#8221; tab, the device named &#8220;Monitor of Internal Audio Analog Stereo&#8221; isn&#8217;t muted.</li>
<li>Make a directory for the mount point and mount the filesystem:
<ul>
<li><code>mkdir fuse_mnt<br />
python dlna_fuse.py -s -f fuse_mnt</code></li>
<li>&#8220;-s&#8221; means single-threaded (just in case my implementation isn&#8217;t entirely thread-safe), &#8220;-f&#8221; means foreground (so that you can see log output on stdout).</li>
</ul>
</li>
<li>To test it, you can point Nautilus (assuming you use GNOME) at the fuse_mnt directory and play the file fuse_live.mkv that you find in there using a player of your choice.</li>
<li>Add the file &#8220;fuse_mnt/a/fuse_live.mkv&#8221; to MediaTomb&#8217;s database.</li>
<li><strong>Note: </strong>I start &#8220;mediatomb&#8221; manually from a terminal, which works just fine. The MediaTomb service that&#8217;s started automatically during boot, on the other hand, can&#8217;t see the file &#8220;fuse_live.mkv&#8221; due to permission problems&#8211;I&#8217;m not sure why.</li>
<li>To stop the FUSE filesystem, run &#8220;sudo umount fuse_mnt&#8221;. If this doesn&#8217;t work, you can also kill the dlna_fuse.py process:
<ul>
<li><code>ps aux | grep dlna_fuse.py<br />
kill -9 &lt;pid&gt;</code></li>
</ul>
</li>
<li>If starting dlna_fuse.py fails with &#8220;bad mount point: Transport endpoint is not connected&#8221;, make sure the process has been killed and run &#8220;sudo umount fuse_mnt&#8221; again.</li>
</ul>
<p><a name="mediatomb_config"><strong>Configuring MediaTomb</strong></a></p>
<div id="attachment_457" class="wp-caption alignright" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2011/02/mediatomb_add.png"><img class="size-medium wp-image-457" title="mediatomb_add" src="http://realmike.org/blog/wp-content/uploads/2011/02/mediatomb_add-300x175.png" alt="" width="300" height="175" /></a><p class="wp-caption-text">MediaTomb web UI: Ugly but functional. And ugly.</p></div>
<p>Install MediaTomb via your package manager (package &#8220;mediatomb&#8221; in Ubuntu). In Ubuntu, MediaTomb is started automatically as a service. The configuration file is in /etc/mediatomb/config.xml.</p>
<p>I prefer to start mediatomb manually whenever I need it and place the configuration file in ~/.mediatomb/config.xml.</p>
<p>Provided that the config.xml contains &#8220;&lt;ui enabled=&#8221;yes&#8221;&gt;&#8221;, you can open the MediaTomb GUI in a web browser at http://localhost:49152/ (or a subsequent port number). Once the FUSE filesystem is up and running, add the file fuse_mnt/a/fuse_live.mkv to the database. At this point, you should be able to find it and play it back on your DLNA player. (Of course, it can&#8217;t hurt to try a regular file first to check whether it works at all.)</p>
<p><strong>How well does it work?</strong></p>
<p>The image quality is astonishing, even with the &#8220;fast&#8221; encoding profile that I am using. The fonts and window details are very crisp. You have to look very closely to see the typical MPEG compression artifacts, if you can see them at all.</p>
<p>I am not trying to watch HD movies this way. I mostly use this for the <a href="http://live.twit.tv/">TWiT live stream</a> and similar talking-heads programs, so the 20 fps that my PC can deliver are good enough.</p>
<p>The latency is currently whatever it takes me to start the FUSE filesystem (which automatically starts the capture), walk over to the TV, and start playback there. I think if I would delay the capture until the file is actually accessed, I could reduce latency to just a few seconds (although I do think it&#8217;s a good idea to give the encoder a head start). Maybe it will be possible at some point to reduce the latency far enough to be able to remote-control the PC and get feedback almost instantly. We&#8217;ll see.</p>
<p>If the video hangs, try the obvious things: Reduce the frame rate, make the captured screen area smaller, lower the bitrate, etc.</p>
<p><strong>Tested Hardware and Software</strong></p>
<p>I tried all this on Ubuntu 10.10 (Maverick) with MediaTomb 0.12.1, FFmpeg 0.6, and Python 2.6.</p>
<p>The TV is a Philips PFL 7605H/12 with firmware 000.140.025.000. (As far as I can tell, models 8605 and 9705 use the same firmware, so they might work as well.)</p>
<p>If any of you can successfully replicate this on other player models and brands (or even if you can&#8217;t), please leave a comment.</p>
<p><strong>Request for Comments</strong></p>
<p>Again, this is a proof-of-concept. I hope to expand and improve the scripts in the future. If you have any questions, suggestions, or comments, please leave a comment, contact me via <a href="http://identi.ca/mfoetsch">identi.ca/mfoetsch</a>, <a href="http://twitter.com/mfoetsch">twitter.com/mfoetsch</a>, or e-mail.</p>
<p style="text-align: right;"><a href="http://realmike.org/blog/wp-content/uploads/2011/02/live_file_format.odg">Figure source</a></p>
]]></content:encoded>
			<wfw:commentRss>http://realmike.org/blog/2011/02/09/live-desktop-streaming-via-dlna-on-gnulinux/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>Quick Review: &#8220;The Master Switch: The Rise and Fall of Information Empires&#8221;</title>
		<link>http://realmike.org/blog/2011/01/11/the-master-switch-the-rise-and-fall-of-information-empires/</link>
		<comments>http://realmike.org/blog/2011/01/11/the-master-switch-the-rise-and-fall-of-information-empires/#comments</comments>
		<pubDate>Tue, 11 Jan 2011 18:02:47 +0000</pubDate>
		<dc:creator>Michael Fötsch</dc:creator>
				<category><![CDATA[Meta]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[books]]></category>
		<category><![CDATA[internet]]></category>
		<category><![CDATA[master switch]]></category>
		<category><![CDATA[net neutrality]]></category>
		<category><![CDATA[review]]></category>
		<category><![CDATA[timothy wu]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://realmike.org/blog/?p=441</guid>
		<description><![CDATA[I finished reading &#8220;The Master Switch: The Rise and Fall of Information Empires&#8221; by Timothy Wu. Here&#8217;s my short review in more than 140 characters. Timothy Wu describes how, historically, information industries have tended to cycle from the freedom and openness that follows a disruptive invention to monopoly. About two thirds of the book are <span style="color:#777"> . . . &#8594; <a href="http://realmike.org/blog/2011/01/11/the-master-switch-the-rise-and-fall-of-information-empires/">Read More</a></span>]]></description>
			<content:encoded><![CDATA[<p>I finished reading &#8220;The Master Switch: The Rise and Fall of Information Empires&#8221; by <a href="http://timwu.org/">Timothy Wu</a>. Here&#8217;s my short review in more than 140 characters. <img src='http://realmike.org/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Timothy Wu describes how, historically, information industries have tended to cycle from the freedom and openness that follows a disruptive invention to monopoly. About two thirds of the book are devoted to retelling the history of four such industries: Telephone, radio, movies, television. These are intriguing and eye-opening stories: How Hollywood started out as a bunch of &#8220;IP pirates&#8221;; how the FCC came about and what they were up to; how the Bell System delayed technologies like magnetic storage media and the answering machine for decades; etc.</p>
<p><span id="more-441"></span></p>
<p>Then he continues with the Internet, from its decentralized beginnings as ARPANET, to the AOL era, all the way to Apple, Google, and <a href="http://timwu.org/network_neutrality.html">Net Neutrality</a> (and why it is that the iPad fits the monopolistic agenda so well).<br />
Having learned about the monopolistic powers of the Bell System (AT&amp;T and Verizon rising from the ashes), of cable companies, and of media conglomerates, it&#8217;s hard to see a bright future for freedom and openness on the Internet.</p>
<p>Wu makes the case for Net Neutrality, and with all the context that the book provides, it is a compelling argument.</p>
<p>Borrowing from <a href="http://www.harpers.org/archive/2007/02/0081387">what Jonathan Lethem said about Larry Lessig</a>: Timothy Wu is &#8220;the best source if you want to get radicalized in a hurry.&#8221;</p>
<p><a href="http://www.salon.com/books/laura_miller/2010/12/12/master_switch">Longer review at Salon.com</a> (by Laura Miller)</p>
]]></content:encoded>
			<wfw:commentRss>http://realmike.org/blog/2011/01/11/the-master-switch-the-rise-and-fall-of-information-empires/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SSL Certificate Error With Gwibber And identi.ca on Ubuntu</title>
		<link>http://realmike.org/blog/2011/01/02/ssl-certificate-error-with-gwibber-and-identi-ca-on-ubuntu/</link>
		<comments>http://realmike.org/blog/2011/01/02/ssl-certificate-error-with-gwibber-and-identi-ca-on-ubuntu/#comments</comments>
		<pubDate>Sun, 02 Jan 2011 20:19:19 +0000</pubDate>
		<dc:creator>Michael Fötsch</dc:creator>
				<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[certificates]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[gnu]]></category>
		<category><![CDATA[gwibber]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[ssl]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://realmike.org/blog/?p=431</guid>
		<description><![CDATA[UPDATE: The problem has been fixed on identi.ca&#8217;s side. Maybe the workaround will be useful to others in some other context at some other time. I will also remove the certificate mentioned below from my system. It won&#8217;t be needed any longer, and who knows what nasty side effects it might have going forward&#8230; I <span style="color:#777"> . . . &#8594; <a href="http://realmike.org/blog/2011/01/02/ssl-certificate-error-with-gwibber-and-identi-ca-on-ubuntu/">Read More</a></span>]]></description>
			<content:encoded><![CDATA[<p><strong>UPDATE:</strong> The problem has been <a href="http://identi.ca/conversation/60798556">fixed on identi.ca&#8217;s side</a>. Maybe the workaround will be useful to others in some other context at some other time. I will also remove the certificate mentioned below from my system. It won&#8217;t be needed any longer, and who knows what nasty side effects it might have going forward&#8230;</p>
<p>I ran into this problem today where <a href="http://gwibber.com/">Gwibber</a> (the micro-blogging client) on Ubuntu would not work with <a href="https://identi.ca/">identi.ca</a> anymore. The <a href="https://bugs.launchpad.net/ubuntu/+source/gwibber/+bug/696445">bug report</a> referred to the log file <code>~/.xsession-errors</code>, which contained this message:</p>
<blockquote><p>Traceback (most recent call last):<br />
File &#8220;/usr/lib/python2.6/dist-packages/gwibber/microblog/network.py&#8221;, line 53, in __init__<br />
self.curl.perform()<br />
error: (60, &#8216;server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none&#8217;)</p></blockquote>
<p><span id="more-431"></span></p>
<p>This is actually a <a href="http://curl.haxx.se/">cURL</a> error, so I tried to reproduce the issue directly with curl on the command line:</p>
<blockquote><p>$ curl https://identi.ca/api/statuses/friends_timeline.json?count=200&amp;since_id=61361942<br />
curl: (60) SSL certificate problem, verify that the CA cert is OK. Details:<br />
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed<br />
More details here: http://curl.haxx.se/docs/sslcerts.html</p>
<p>curl performs SSL certificate verification by default, using a &#8220;bundle&#8221;<br />
of Certificate Authority (CA) public keys (CA certs). If the default<br />
bundle file isn&#8217;t adequate, you can specify an alternate file<br />
using the &#8211;cacert option.<br />
If this HTTPS server uses a certificate signed by a CA represented in<br />
the bundle, the certificate verification probably failed due to a<br />
problem with the certificate (it might be expired, or the name might<br />
not match the domain name in the URL).<br />
If you&#8217;d like to turn off curl&#8217;s verification of the certificate, use<br />
the -k (or &#8211;insecure) option.</p></blockquote>
<p>After searching for this error on the web, I found a <a href="http://curl.haxx.se/docs/sslcerts.html">cURL page about SSL certificates</a>. This page talks about importing SSL certificates for cURL to use. After some trial and error, I came up with these steps to import the certificate and solve the issue:</p>
<p>1. I went to https://identi.ca/ in Firefox and inspected the certificate. This pointed to the certificate download URL: <a href="http://crt.comodoca.com/COMODOHigh-AssuranceSecureServerCA.crt">http://crt.comodoca.com/COMODOHigh-AssuranceSecureServerCA.crt</a></p>
<p>2. I downloaded the .crt file from that URL.</p>
<p>3. The downloaded file is in some binary format. I converted the .crt file using this openssl command:</p>
<blockquote><p>$ openssl x509 -inform DER -in COMODOHigh-AssuranceSecureServerCA.crt        -out outcert.crt -text</p></blockquote>
<p>4. I copied the resulting file, outcert.crt, to <code>/usr/share/ca-certificates/COMODO_High_Assurance_Secure_Server_CA.crt</code>.</p>
<p>5. From there, the new certificate can be installed system-wide by running dpkg-reconfigure:</p>
<blockquote><p>$ sudo dpkg-reconfigure ca-certificates</p></blockquote>
<p>This last step updates the files <code>/etc/ca-certificates.conf</code> and the directory <code>/etc/ssl/certs</code>.</p>
<p>The same curl command that didn&#8217;t work initially should work now (at least, it won&#8217;t complain about incorrect certificates.)</p>
<p>I&#8217;m sure there will be an &#8220;official&#8221; fix soon, but at least this provided for some geeky evening entertainment tonight. (Did I mention <a href="http://identi.ca/conversation/60780420">my TV is broken</a>&#8230; <img src='http://realmike.org/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  )</p>
]]></content:encoded>
			<wfw:commentRss>http://realmike.org/blog/2011/01/02/ssl-certificate-error-with-gwibber-and-identi-ca-on-ubuntu/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Tutorial: Scaling Processing for Android Apps to Different Screens</title>
		<link>http://realmike.org/blog/2010/12/23/tutorial-scaling-processing-for-android-apps-to-different-screens/</link>
		<comments>http://realmike.org/blog/2010/12/23/tutorial-scaling-processing-for-android-apps-to-different-screens/#comments</comments>
		<pubDate>Thu, 23 Dec 2010 13:13:07 +0000</pubDate>
		<dc:creator>Michael Fötsch</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://realmike.org/blog/?p=414</guid>
		<description><![CDATA[In my previous article, I gave an introduction to the built-in features of the Android platform for supporting screens of various sizes and densities. In this article, I am going to expand on this and show you actual code for achieving screen-independence in an app. My example will be a Processing app (as that&#8217;s my <span style="color:#777"> . . . &#8594; <a href="http://realmike.org/blog/2010/12/23/tutorial-scaling-processing-for-android-apps-to-different-screens/">Read More</a></span>]]></description>
			<content:encoded><![CDATA[<p>In my previous article, I gave an introduction to the built-in features of the Android platform for <a href="http://realmike.org/blog/2010/12/21/multiple-screen-sizes-with-processing-for-android/">supporting screens of various sizes and densities</a>. In this article, I am going to expand on this and show you actual code for achieving screen-independence in an app. My example will be a Processing app (as that&#8217;s my own primary use case), but the ideas should apply equally well to any game or graphics-centric app.</p>
<div id="attachment_418" class="wp-caption aligncenter" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/chimpzilla_center.png"><img class="size-medium wp-image-418 " title="chimpzilla_center" src="http://realmike.org/blog/wp-content/uploads/2010/12/chimpzilla_center-300x150.png" alt="" width="300" height="150" /></a><p class="wp-caption-text">&quot;Chimpzilla Attacks!&quot; mockup (no, I&#39;m not serious)</p></div>
<p>Let&#8217;s use the game &#8220;Chimpzilla Attacks!&#8221; as an example. I made up this game specifically for the purpose of this tutorial—and already spent way too much time on the mockup. I have no idea what the game mechanics are, but judging from the cheesy graphics, it&#8217;s got to be some kind of &#8220;Punch The Monkey&#8221; knock-off. Anyway, back to the tutorial&#8230;</p>
<p><span id="more-414"></span></p>
<p>The skyline backdrop has a resolution of 800×600 pixels. In the following image, you can see its size and aspect ratio relative to various common screen sizes, from a QVGA screen to a 1024×600 screen.</p>
<p style="text-align: center;">
<div id="attachment_419" class="wp-caption aligncenter" style="width: 624px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/aspect_ratio.png"><img class="size-large wp-image-419 " title="aspect_ratio" src="http://realmike.org/blog/wp-content/uploads/2010/12/aspect_ratio-1024x626.png" alt="" width="614" height="376" /></a><p class="wp-caption-text">Background image relative to various screen sizes and aspect ratios</p></div>
<p>The goal here is to scale the game screen so that its width fits the display. In the following image, you can see what the scaled image will look like on various screens.</p>
<div id="attachment_420" class="wp-caption aligncenter" style="width: 585px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/aspect_ratio_2.png"><img class="size-full wp-image-420    " title="aspect_ratio_2" src="http://realmike.org/blog/wp-content/uploads/2010/12/aspect_ratio_2.png" alt="" width="575" height="515" /></a><p class="wp-caption-text">Background image relative to various aspect ratios</p></div>
<p>On a 320×240 screen, all of the backdrop is visible (at 40% of the size, of course). This is because both have an aspect ratio of 4:3 (or 1.33). Most of the common screen sizes are wider, though. For example, a 1024×600 screen is 5:3 (or 1.66). The wider the screen, the higher the aspect ratio. On any screen with an aspect ratio higher than 1.33, we&#8217;ll have to cut off some of the backdrop&#8217;s height, but those parts are not used for the gameplay anyway.</p>
<p>Having to cut off some of the backdrop on wide screens sounds like the game isn&#8217;t designed for wide screens. It&#8217;s quite the opposite, though. The part of the game screen that&#8217;s used for actual gameplay is 800×400, with an aspect ratio of 2 (which is not quite Cinemascope, but close). With such a wide picture, we&#8217;d have to display black bars above and below the picture on all screens. Instead of black bars, I can just as well show more of the photo as a filler.</p>
<p>There are still aspect ratios where we have to pad the screen with black bars, namely ratios smaller than 1.33 and higher than 2, as shown in the following image.</p>
<p style="text-align: center;">
<div id="attachment_421" class="wp-caption aligncenter" style="width: 624px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/aspect_ratio_3.png"><img class="size-large wp-image-421 " title="aspect_ratio_3" src="http://realmike.org/blog/wp-content/uploads/2010/12/aspect_ratio_3-1024x635.png" alt="" width="614" height="381" /></a><p class="wp-caption-text">Image relative to extremely narrow and extremely wide screens</p></div>
<p>The 800×640 screen has an aspect ratio of 1.25. There, we&#8217;ll display black bars above and below the picture. The second screen is a hypothetical 800×340 Cinemascope (2.35:1) screen. While it is wide enough to show the entire game screen, it is not high enough. We&#8217;ll have to scale the game screen down to 680×340 so that it fits the height of the display. At that scale, we&#8217;ll have to display black bars (or whatever) to the left and to the right.</p>
<p>Okay, let&#8217;s create a &#8220;Hello, Chimpzilla!&#8221; app that demonstrates all of this.</p>
<p>(I will explain the steps based on the Eclipse Android plug-in. If you haven&#8217;t set it up yet, see my <a href="http://realmike.org/blog/2010/10/28/first-steps-with-processing-for-android/">first-steps article</a>. If you prefer to work without Eclipse, <a href="http://realmike.org/blog/2010/10/31/android-development-without-eclipse/">there&#8217;s also an article for that</a>.)</p>
<div id="attachment_422" class="wp-caption alignright" style="width: 206px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/new_project_wizard.png"><img class="size-medium wp-image-422 " title="new_project_wizard" src="http://realmike.org/blog/wp-content/uploads/2010/12/new_project_wizard-196x300.png" alt="" width="196" height="300" /></a><p class="wp-caption-text">New Android Project wizard</p></div>
<p>1. In Eclipse, click &#8220;File&#8221; → &#8220;New&#8221; → &#8220;Project&#8230;&#8221; and select &#8220;Android Project&#8221;. Specify the project name, location, package name, etc. As the Build Target, select at least API Level 7 (Android 2.1), and specify 7 as the Min SDK Version. Click Finish.</p>
<p>2. Place the file &#8220;<a href="http://wiki.processing.org/w/Android">processing-core.jar</a>&#8221; in the <code>libs/</code> sub-folder of the project folder. Press F5 in the Package Explorer. The file should now be visible in your project tree.</p>
<p>3. Add a reference to &#8220;processing-core.jar&#8221; to the project: Click &#8220;Project&#8221; →  &#8220;Properties&#8221;, select &#8220;Java Build Path&#8221; and go to the &#8220;Libraries&#8221; tab.  Click the &#8220;Add JARs&#8230;&#8221; button and select the file  &#8220;libs/processing-core.jar&#8221; from your project.</p>
<p>4. Double-click the file AndroidManifest.xml. On the Manifest tab, set the &#8220;Target SDK version&#8221; of the &#8220;Uses Sdk&#8221; element to 7 or higher. On the Application tab, set &#8220;Debuggable&#8221; to &#8220;true&#8221; (needed to debug the app on a physical device).</p>
<p>When you edit the file AndroidManifest.xml directly, it should look something like this:</p>
<pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="org.realmike.chimpzilla"
 android:versionCode="1"
 android:versionName="1.0"&gt;
 &lt;application android:icon="@drawable/icon" android:label="@string/app_name"
     android:debuggable="true"&gt;
   &lt;activity android:name=".HelloChimpzilla" android:label="@string/app_name"&gt;
     &lt;intent-filter&gt;
       &lt;action android:name="android.intent.action.MAIN" /&gt;
       &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
     &lt;/intent-filter&gt;
   &lt;/activity&gt;
 &lt;/application&gt;
 &lt;uses-sdk android:minSdkVersion="7" android:targetSdkVersion="7"/&gt;
&lt;/manifest&gt;
</code></pre>
<p>5. Place the file &#8220;<a href="http://realmike.org/blog/wp-content/uploads/2010/12/chimpzilla.png">chimpzilla.png</a>&#8221; in the <code>assets/</code> sub-folder.</p>
<p>6. Replace the code in HelloChimpzilla.java with this:</p>
<pre><code>package org.realmike.chimpzilla;

import processing.core.*;

public class HelloChimpzilla extends PApplet
{
    PImage backdropImage;

    public void setup()
    {
    	orientation(LANDSCAPE);
    	background(39, 70, 134);
        backdropImage = loadImage("chimpzilla.png");
    }

    public void draw()
    {
        image(backdropImage, 0, 0);
    }

    public static void main(String[] args)
    {
        PApplet.main(new String[] { "HelloChimpzilla" });
    }
}
</code></pre>
<p>7. To debug the app, click the &#8220;Debug As&#8230;&#8221; button and select &#8220;Android Application&#8221; as the target. If this doesn&#8217;t appear, go to &#8220;Run&#8221; → &#8220;Debug Configurations&#8230;&#8221; instead and create a new launch configuration below &#8220;Android Application&#8221;. Click Debug. </p>
<p><strong>Note:</strong> If the debugger stops because of a NullPointerException, the app probably can&#8217;t load the image file. Note that Eclipse does not rebuild the app package automatically when you change the files in the <code>assets/</code> folder. If you placed the file chimpzilla.png in there after you edited the source code, the file might not be in the package yet. Make another source code change and save the file, and Eclipse should rebuild the app package the next time you start debugging.</p>
<p>8. Let&#8217;s add the code to scale the image:</p>
<pre><code>    public void draw()
    {
        int newWidth = screenWidth;
        float scaleFactor = (float)screenWidth / (float)backdropImage.width;
        int newHeight = (int)(backdropImage.height * scaleFactor);
        int destX = (width - newWidth) / 2;
        int destY = (height - newHeight) / 2;
        image(backdropImage, destX, destY, newWidth, newHeight);
    }
</code></pre>
<p>Basically, we always scale the image to fill the width of the screen and draw it centered. This also works on aspect ratios smaller than 1.33 (where the background color will be visible above and below the scaled image). But we still have to add an &#8220;if&#8221; for extremely wide screens. On those screens, we will scale the image so that the height of the playfield (400 pixels) fits the height of the screen.</p>
<pre><code>    public void draw()
    {
        float scaleFactor;
        float screenAspect = (float)screenWidth / (float)screenHeight;
        if (screenAspect &lt;= 2)
        {
            scaleFactor = (float)screenWidth / (float)backdropImage.width;
        }
        else
        {
            final int PLAYFIELD_HEIGHT = 400;
            scaleFactor = (float)screenHeight / (float)PLAYFIELD_HEIGHT;
        }
        int newWidth = (int)(backdropImage.width * scaleFactor);
        int newHeight = (int)(backdropImage.height * scaleFactor);
        int destX = (width - newWidth) / 2;
        int destY = (height - newHeight) / 2;
        image(backdropImage, destX, destY, newWidth, newHeight);
    }
</code></pre>
<p>That&#8217;s it.</p>
<p>You might have noticed that we didn&#8217;t take Android&#8217;s screen classification (&#8220;small&#8221;, &#8220;normal&#8221;, etc.) or the screen density (&#8220;ldpi&#8221;, &#8220;mdpi&#8221;, etc.) into account when scaling the graphics. It simply wasn&#8217;t necessary to use different resources or a different formula based on this information. Once we add UI elements to the screen, we&#8217;ll have to take this into account. For example, when loading graphics for touch buttons, we might want to scale them according to the density, so that they end up in a touch-friendly size on the screen. (See my previous article for <a href="http://realmike.org/blog/2010/12/21/multiple-screen-sizes-with-processing-for-android/">more about size classifications and densities</a>.)</p>
<p>You can download a <a href='http://realmike.org/blog/wp-content/uploads/2010/12/HelloChimpzilla.zip'>ZIP file</a> containing the source code and the graphics.</p>
<p><small>Photo of the <a href="http://www.flickr.com/photos/rene-germany/1594828030/">Boston Skyline</a> is © 2007 Rene Schwietzke, licensed under a <a href="http://creativecommons.org/licenses/by/2.0/deed.en">Creative Commons Attribution 2.0 Generic</a> license. <a href="http://www.openclipart.org/detail/10441">Boat</a> and <a href="http://www.openclipart.org/detail/15076">Chimpzilla</a> graphics are from <a href="http://openclipart.org/">openclipart.org</a> and have been dedicated to the <a href="http://creativecommons.org/publicdomain/zero/1.0/">public domain</a>.</small></p>
]]></content:encoded>
			<wfw:commentRss>http://realmike.org/blog/2010/12/23/tutorial-scaling-processing-for-android-apps-to-different-screens/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress Database Errors</title>
		<link>http://realmike.org/blog/2010/12/21/wordpress-database-errors/</link>
		<comments>http://realmike.org/blog/2010/12/21/wordpress-database-errors/#comments</comments>
		<pubDate>Tue, 21 Dec 2010 15:35:04 +0000</pubDate>
		<dc:creator>Michael Fötsch</dc:creator>
				<category><![CDATA[Meta]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[phpMyAdmin]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[yahoo]]></category>

		<guid isPermaLink="false">http://realmike.org/blog/?p=407</guid>
		<description><![CDATA[Some combination of adding and deleting images too fast broke it... While editing my previous post, my WordPress installation suddenly started acting up on me. The problems had to do with uploading and deleting images using the post editor. I think what I did was upload an image, then click the &#8220;Delete&#8221; link right in <span style="color:#777"> . . . &#8594; <a href="http://realmike.org/blog/2010/12/21/wordpress-database-errors/">Read More</a></span>]]></description>
			<content:encoded><![CDATA[<div id="attachment_409" class="wp-caption alignright" style="width: 306px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/add_image_dialog.png"><img class="size-medium wp-image-409" title="add_image_dialog" src="http://realmike.org/blog/wp-content/uploads/2010/12/add_image_dialog-296x300.png" alt="" width="296" height="300" /></a><p class="wp-caption-text">Some combination of adding and deleting images too fast broke it...</p></div>
<p>While editing my previous post, my WordPress installation suddenly started acting up on me. The problems had to do with uploading and deleting images using the post editor. I think what I did was upload an image, then click the &#8220;Delete&#8221; link right in the upload dialog—probably while WordPress was still updating the tables or something.</p>
<p>Anyway, suddenly the Media Library would not show any items anymore, and soon after that, the Posts were gone as well (both in the Admin interface and on the real site).</p>
<p>I checked the server logs* and found a number of relevant error messages:</p>
<p>*) I&#8217;m on Yahoo hosting. The relevant file was scripts.log in the logs directory of my site, accessible either through FTP or at http://yourdomain/logs.</p>
<blockquote><p>[21-Dec-2010 11:26:48] WordPress database error Duplicate entry &#8217;289&#8242; for key 1 for query INSERT INTO `wp_postmeta` &#8230;<br />
[21-Dec-2010 11:35:34] WordPress database error Incorrect key file for table &#8216;wp_posts&#8217;; try to repair it for query UPDATE `wp_posts` &#8230;<br />
[21-Dec-2010 11:42:30] WordPress database error Can&#8217;t open file: &#8216;wp_posts.MYI&#8217; (errno: 145) for query SELECT post_modified_gmt FROM wp_posts &#8230;</p></blockquote>
<p><span id="more-407"></span></p>
<p>I did a Google search, which lead me to believe it was most likely some kind of database corruption. I logged into phpMyAdmin* and executed the following SQL command:</p>
<p>*) phpMyAdmin is a MySQL admin interface. It can be easily <a href="http://help.yahoo.com/l/us/yahoo/smallbusiness/webhosting/mysql/mysql-18.html">installed on Yahoo hosting</a>.</p>
<blockquote><p><code>CHECK TABLE wp_postmeta;</code></p></blockquote>
<p>The check revealed that the table was broken in some way:</p>
<blockquote><p>Table     Op     Msg_type     Msg_text<br />
blog.wp_postmeta     check     warning     Table is marked as crashed<br />
blog.wp_postmeta     check     warning     Size of datafile is: 53116       Should be: 51228<br />
blog.wp_postmeta     check     error     Record at pos: 43796 is not remove-marked<br />
blog.wp_postmeta     check     error     record delete-link-chain corrupted<br />
blog.wp_postmeta     check     error     Corrupt</p></blockquote>
<p>To fix the problem, I repaired the tables via SQL:</p>
<blockquote><p><code>REPAIR TABLE wp_postmeta;<br />
REPAIR TABLE wp_posts;</code></p></blockquote>
<p>Repairing the tables apparently worked:</p>
<blockquote><p>Table     Op     Msg_type     Msg_text<br />
blog.wp_posts     repair     info     Wrong bytesec: 225- 36- 46 at 1431684; Skipped<br />
blog.wp_posts     repair     info     Found block that points outside data file at 14317&#8230;<br />
blog.wp_posts     repair     info     Wrong bytesec: 111-115-115 at 1451636; Skipped<br />
blog.wp_posts     repair     info     Found block that points outside data file at 14516&#8230;<br />
blog.wp_posts     repair     info     Found block that points outside data file at 14525&#8230;<br />
blog.wp_posts     repair     warning     Number of rows changed from 286 to 288<br />
blog.wp_posts     repair     status     OK</p></blockquote>
<p>The blog appears to work again. All posts are back and the Media Library works as well. This was the first real WordPress issue I had—let&#8217;s hope it will remain the last one for a while.</p>
]]></content:encoded>
			<wfw:commentRss>http://realmike.org/blog/2010/12/21/wordpress-database-errors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Multiple Screen Sizes With Processing for Android</title>
		<link>http://realmike.org/blog/2010/12/21/multiple-screen-sizes-with-processing-for-android/</link>
		<comments>http://realmike.org/blog/2010/12/21/multiple-screen-sizes-with-processing-for-android/#comments</comments>
		<pubDate>Tue, 21 Dec 2010 14:12:09 +0000</pubDate>
		<dc:creator>Michael Fötsch</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[processing]]></category>

		<guid isPermaLink="false">http://realmike.org/blog/?p=376</guid>
		<description><![CDATA[Samsung Galaxy Tab (Android Virtual Device) In my ongoing effort to port a desktop Processing application to Android, I am now trying to add support for multiple screen sizes. The goal is that the same .apk works on, say, a 3.7&#8243; Milestone equally well as on a 7&#8243; Galaxy Tab and on a multitude of <span style="color:#777"> . . . &#8594; <a href="http://realmike.org/blog/2010/12/21/multiple-screen-sizes-with-processing-for-android/">Read More</a></span>]]></description>
			<content:encoded><![CDATA[<div id="attachment_395" class="wp-caption alignright" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/galaxy_tab_avd.png"><img class="size-medium wp-image-395" title="galaxy_tab_avd" src="http://realmike.org/blog/wp-content/uploads/2010/12/galaxy_tab_avd-300x193.png" alt="" width="300" height="193" /></a><p class="wp-caption-text">Samsung Galaxy Tab (Android Virtual Device)</p></div>
<p>In <a href="http://realmike.org/blog/tag/processing/">my ongoing effort</a> to port a desktop <a href="http://processing.org/">Processing</a> application to Android, I am now trying to add support for multiple screen sizes. The goal is that the same .apk works on, say, a 3.7&#8243; Milestone equally well as on a 7&#8243; Galaxy Tab and on a multitude of other screens. The Android Dev Guide has a comprehensive page that explains the <a href="http://developer.android.com/guide/practices/screens_support.html">platform features for supporting different screens</a>. I did my own tests and experiments to better understand the concepts. This article explains my findings and hopefully saves you some time and work.</p>
<p><span id="more-376"></span></p>
<p><em>Note: Android 3.2 introduces &#8220;<a href="http://android-developers.blogspot.com/2011/07/new-tools-for-managing-screen-sizes.html">numeric selectors</a>&#8221; to manage different screen sizes, which I don&#8217;t explain here.</em></p>
<p>Android abstracts different screens into 4 generalized sizes and 4 generalized densities (as of version 2.3 of the SDK):</p>
<blockquote><p><strong>Screen sizes:</strong> <em>small,</em> <em>normal,</em> <em>large,</em> <em>xlarge</em></p>
<p><strong>Densities:</strong> <em>ldpi</em> (120 dpi), <em>mdpi</em> (160 dpi), <em>hdpi</em> (240 dpi), <em>xhdpi</em> (320 dpi)</p></blockquote>
<p>Apps can provide layouts and resources for all the 16 different combinations (one set for &#8220;normal-hdpi&#8221; screens, one set for &#8220;large-ldpi&#8221; sreens, etc.). If the app does not provide resources for a specific combination, the platform will scale images automatically and employ other tricks to make the app still work. We&#8217;ll take a look at this later.</p>
<p>The pixel resolution, as in &#8220;800×400&#8243;, is not that important to supporting different screens. In fact, the Dev Guide notes that &#8220;in Android, applications do not work directly with resolution.&#8221; Apps do have access to the actual width and height in pixels of the screen. For normal Android GUI apps, however, the widget classes are going to handle the resolution transparently.</p>
<p><strong>So, what exactly are size and density and how do they correlate to the resolution in pixels?</strong></p>
<p>The density is a function of the screen size and the resolution. A 3.7-inch screen with a resolution of 854×480 pixels has a density of 265 dots per inch (dpi).</p>
<div id="attachment_400" class="wp-caption alignleft" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/wvga854.png"><img class="size-medium wp-image-400" title="wvga854" src="http://realmike.org/blog/wp-content/uploads/2010/12/wvga854-300x181.png" alt="" width="300" height="181" /></a><p class="wp-caption-text">Size of a 854×480 screen at 240 dpi</p></div>
<p>Android collapses all physical densities into the four predefined categories. A density of 265 dpi will be reported as 240 dpi (&#8220;hdpi&#8221;).</p>
<p>The density tells you how large a bitmap with a specific resolution will appear on the screen. For example, on an &#8220;ldpi&#8221; screen (120 dpi), a 120×120 bitmap occupies a 1-inch square. (This is only a rough estimate, as Android does not report the exact physical density.)</p>
<p>In your app, you can provide different versions of images for various densities. For example, you can provide a 100×100-pixel bitmap for an &#8220;mpdi&#8221; screen and a 150×150-pixel bitmap for an &#8220;hdpi&#8221; screen, which has 1.5 times the density. Both images will appear in roughly the same physical size on the two screens. So, a higher density allows you to provide images that contain more detail.</p>
<p>A higher density does not necessarily mean that you can cram more widgets or more lines of text onto the screen. A 3&#8243; screen is still a 3&#8243; screen, whether it has 160 dpi or 240 dpi. On the &#8220;hdpi&#8221; screen, you might simply want to scale all images and widgets by a factor of 1.5, so that they are still readable and easily touchable.</p>
<p>To provide density- or size-specific resources, you add a suffix to the sub-folders of your project&#8217;s <code>res/</code> folder. The right resources will automatically be loaded by the Android platform.</p>
<pre>res/
    drawable-mdpi/
        icon.png
    drawable-hdpi/
        icon.png
    values/
        strings.xml
    values-large-hdpi/
        strings.xml</pre>
<p>If you don&#8217;t provide resources for a specific size or density, the platform will load the default resources, which are assumed to be for a &#8220;normal-mdpi&#8221; screen. If, on an &#8220;hdpi&#8221; screen, the platform can only find &#8220;mdpi&#8221; images, it will scale them up for you. This is all transparent to the app.</p>
<p>The Dev Guide describes the rules of <a href="http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources">loading alternative resources</a> in detail.</p>
<div id="attachment_397" class="wp-caption alignleft" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/froyo_1024x600_160dpi.png"><img class="size-medium wp-image-397" title="froyo_1024x600_160dpi" src="http://realmike.org/blog/wp-content/uploads/2010/12/froyo_1024x600_160dpi-300x175.png" alt="" width="300" height="175" /></a><p class="wp-caption-text">FroYo on a 1024×600 160-dpi screen</p></div>
<div id="attachment_398" class="wp-caption alignleft" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/froyo_1024x600_240dpi.png"><img class="size-medium wp-image-398" title="froyo_1024x600_240dpi" src="http://realmike.org/blog/wp-content/uploads/2010/12/froyo_1024x600_240dpi-300x175.png" alt="" width="300" height="175" /></a><p class="wp-caption-text">FroYo on a 1024×600 240-dpi screen</p></div>
<p>As an example, let&#8217;s take a look at two hypothetical 1024×600 screens. One is a 7.4&#8243; screen, so it has a density of 160 dpi. The other one is a 4.9&#8243; screen with a density of 240 dpi. For the first device, the platform uses the 48×48-pixel &#8220;mdpi&#8221; versions of the app icons, which are .3&#8243; wide on the screen. For the second device, the 72×72-pixel &#8220;hdpi&#8221; versions are used (exactly 1.5 times as large), which is also .3&#8243; on the screen. (In the screenshots, you can clearly see that the Alarm Clock icon is a different resource.)</p>
<p>Both screens have the same resolution, and the icons appear at the same physical size. But as the first screen uses smaller bitmaps, there is much more empty space between the icons. One could argue that the layout of the second screen looks prettier.</p>
<p>Apparently, that&#8217;s also <a href="http://android-developers.blogspot.com/2010/09/screen-geometry-fun.html">what Samsung found when they made the Galaxy Tab</a>. The Galaxy Tab has a 7&#8243;, 1024×600 screen with 170 dpi. Yet, the Tab does not report its density as &#8220;mdpi&#8221; but as &#8220;hdpi&#8221;, so the layout looks exactly as in the second screenshot. If they used &#8220;mdpi&#8221;, the icons would be .28&#8243; wide, with &#8220;hdpi&#8221;, they are .42&#8243; wide—not a big deal, and I must admit, the layout does look prettier this way.</p>
<p>(Talking about the Galaxy Tab, Samsung offers an <a href="http://innovator.samsungmobile.com/galaxyTab.do">add-on for the Android SDK</a> that contains a virtual device skin that you can use for testing your app.)</p>
<p><strong>Okay, how does all this apply to Processing apps?</strong></p>
<p>First and foremost, make sure that your AndroidManifest.xml specifies the correct target SDK. For example, if you are developing for Android 2.2, the target SDK level is 8. As Processing requires at least level 7 to run at all, you&#8217;d specify 7 as the minimum SDK level:</p>
<blockquote><p>&lt;uses-sdk android:minSdkVersion=&#8221;7&#8243; android:targetSdkVersion=&#8221;8&#8243;&gt;&lt;/uses-sdk&gt;</p></blockquote>
<div id="attachment_401" class="wp-caption alignleft" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/resolution_target_sdk.png"><img class="size-medium wp-image-401 " title="resolution_target_sdk" src="http://realmike.org/blog/wp-content/uploads/2010/12/resolution_target_sdk-300x134.png" alt="" width="300" height="134" /></a><p class="wp-caption-text">The same Processing app without the &lt;uses-sdk&gt; element (left) and with targetSdkVersion=</p></div>
<p>If you don&#8217;t have a &lt;uses-sdk&gt; element at all, the platform assumes that your app was written for Android 1.5, for a &#8220;normal-mdpi&#8221; screen. When your app actually runs on an &#8220;hdpi&#8221; screen, the platform will scale all loaded images by the factor 1.5, and the width() and height() Processing functions will return the resolution divided by 1.5. For example, on a Milestone with its 854×480 screen, width() and height() would  return 569×320. To avoid this, add the &lt;uses-sdk&gt; element.</p>
<p>A Processing app doesn&#8217;t use regular widgets or any of the Android layout managers. Therefore, you&#8217;ll have to calculate your own layout based on the reported resolution and density. To query the resolution and density, use the DisplayMetrics class:</p>
<pre>DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);</pre>
<p>For a WVGA854, &#8220;normal-hdpi&#8221; screen, the values of the DisplayMetrics object are as follows:</p>
<blockquote><p>DisplayMetrics{density=1.5, width=854, height=480, scaledDensity=1.5, xdpi=240.0, ydpi=240.0}</p></blockquote>
<p>If your graphics were designed with a medium-density screen in mind, you can scale all graphics by the factor given in the &#8220;density&#8221; field to match the current screen—if you want to retain the same physical size, that is.</p>
<p>If you need the size classification—&#8221;small&#8221;, &#8220;normal&#8221;, &#8220;large&#8221;, &#8220;xlarge&#8221;—use the Configuration class:</p>
<pre>Configuration config = getResources().getConfiguration();
int size = config.screenLayout &amp; config.SCREENLAYOUT_SIZE_MASK;
if (size == config.SCREENLAYOUT_SIZE_SMALL)
{
    // use special layout for small screens
}</pre>
<p>In my Processing app, I store all graphics in the <code>assets/</code> directory. The screen-specific suffixes do not work there in the same way they do in the <code>res/</code> directory. Apart from that, for reasons specific to my app, I do not want to access the graphics by the auto-generated constants like &#8220;R.drawable.my_image&#8221; (if that&#8217;s even an option using Processing). Therefore, I just do my own scaling, just like I would for a desktop application where the user can resize the window.</p>
<p>Talking about the auto-generated constants: There is a field &#8220;R&#8221; in the interface processing.core.PConstants, which conflicts with the namespace for the resource constants. When accessing any Android resources through these constants, you get an error like this:</p>
<blockquote><p>The primitive type int of R does not have a field string<br />
The primitive type int of R does not have a field drawable<br />
The primitive type int of R does not have a field layout<br />
The primitive type int of R does not have a field id</p></blockquote>
<p>The solution is to qualify &#8220;R&#8221; with the package namespace when accessing the resource constants:</p>
<pre>String someText = (String) getResources().getText(org.realmike.helloandroid.R.string.someText);</pre>
<p><strong>Conclusion</strong></p>
<p>When scaling a desktop application according to the client size of the window, there&#8217;s usually no need to worry about the physical size that the UI elements will end up at. It&#8217;s all different on a touch screen device, where you want to keep UI elements legible even on small screens, and you want users to interact with the app in a comfortable way. Thinking in terms of densities and screen sizes is a useful abstraction in this scenario.</p>
<p>For multimedia apps (say, games with pre-rendered graphics), there are unique challenges to supporting multiple resolutions and aspect ratios (I haven&#8217;t talked about aspect ratios at all). These challenges are not unique to Android, and you can apply the same techniques as to a desktop application.</p>
<p>If Angry Birds looks great on a multitude of devices, screen-independence should be possible for the rest of us to achieve as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://realmike.org/blog/2010/12/21/multiple-screen-sizes-with-processing-for-android/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Sound Playback in Processing for Android</title>
		<link>http://realmike.org/blog/2010/12/11/sound-playback-in-processing-for-android/</link>
		<comments>http://realmike.org/blog/2010/12/11/sound-playback-in-processing-for-android/#comments</comments>
		<pubDate>Sat, 11 Dec 2010 15:10:28 +0000</pubDate>
		<dc:creator>Michael Fötsch</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[minim]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[processing]]></category>
		<category><![CDATA[sound]]></category>

		<guid isPermaLink="false">http://realmike.org/blog/?p=351</guid>
		<description><![CDATA[I added sound playback to the Processing app that I&#8217;m currently porting to Android. On the desktop, I used the Minim sound library, which is not supported on Android (although there is some discussion about alternatives and a possible port). All I really need from a sound library is a way to play several .ogg <span style="color:#777"> . . . &#8594; <a href="http://realmike.org/blog/2010/12/11/sound-playback-in-processing-for-android/">Read More</a></span>]]></description>
			<content:encoded><![CDATA[<p>I added sound playback to the <a href="http://processing.org/">Processing</a> app that I&#8217;m currently porting to Android. On the desktop, I used the <a href="http://code.compartmental.net/tools/minim/">Minim sound library</a>, which is not supported on Android (although there is some discussion about <a href="http://forum.processing.org/topic/sound-libraries">alternatives and a possible port</a>). All I really need from a sound library is a way to play several .ogg (or .mp3 or .wav) files simultaneously and asynchronously, query their playback durations, maybe set the playback volume of individual sounds, and stop playing sounds at any time.</p>
<p>The <a href="http://developer.android.com/reference/android/media/MediaPlayer.html">android.media.MediaPlayer</a> class is just fine for that.</p>
<p>In general, a sound can be played using the following code:</p>
<blockquote><p><code>snd = new MediaPlayer();<br />
snd.setDataSource(path_or_url_of_sound_to_play);<br />
snd.prepare();<br />
snd.start()</code></p></blockquote>
<p>My own app is a game that contains only a handful of .ogg files. I keep a HashMap of the MediaPlayer instances for all sounds in the game, with prepare() already called on them. Then I simply call start() whenever an event triggers the sound in the game.</p>
<p><span id="more-351"></span></p>
<p><a href="http://realmike.org/blog/wp-content/uploads/2010/12/eclair_2009.gif"><img class="aligncenter size-full wp-image-367" title="eclair_2009" src="http://realmike.org/blog/wp-content/uploads/2010/12/eclair_2009.gif" alt="" width="200" height="150" /></a>I store all sounds in the <code>assets/</code> sub-folder of the project, so that they are automatically included in the app package. However, this does not mean that these files will exist in the current working directory when the app is run.</p>
<p>Loading the files as if they existed in the current working directory does not work:</p>
<blockquote><p><code>snd = new MediaPlayer();<br />
snd.setDataSource("./Sounds/win.ogg");<br />
snd.prepare();  // &lt;- raises an exception because the file does not exist</code></p></blockquote>
<p>This results in an error similar to this:</p>
<blockquote><p>PlayerDriver: Command PLAYER_SET_DATA_SOURCE completed with an error<br />
or info PVMFErrNotSupported<br />
MediaPlayer:  error (1, -4)<br />
SoundTest:    Error! java.io.IOException: Prepare failed.: status=0&#215;1<br />
at android.media.MediaPlayer.prepare(Native Method)
</p></blockquote>
<p>In Processing, you can normally use the createInput() method to open a file in the assets folder. This method returns an InputStream, but there is no way to initialize a MediaPlayer from an InputStream.</p>
<p>I did try to use the dataPath() method of the sketch to retrieve the absolute path to the file, but as we&#8217;ll see, this doesn&#8217;t work either:</p>
<blockquote><p><code>snd = new MediaPlayer();<br />
snd.setDataSource(theSketch.dataPath("Sounds/win.ogg"));<br />
snd.prepare();  // &lt;- raises an exception because the file does not exist</code></p></blockquote>
<p>The dataPath() method returns a path like &#8220;/data/data/org.realmike.myapp/files/data/Sounds/win.ogg&#8221;, but no such file exists. All files in the <code>assets/</code> sub-folder are actually <em>inside</em> the .apk (which I suppose is some kind of .jar file). They do not exist as separate files in the filesystem.</p>
<p>So, to load sound files stored in the assets folder, you should retrieve the AssetManager instance from the sketch and initialize the MediaPlayer with a file descriptor:</p>
<blockquote><p><code>snd = new MediaPlayer();<br />
AssetManager assets = theSketch.getAssets();<br />
AssetFileDescriptor fd = assets.openFd("Sounds/win.ogg");<br />
snd.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());<br />
snd.prepare();</code></p></blockquote>
<p>Make sure to pass <code>fd.getStartOffset()</code> and <code>fd.getLength()</code> to setDataSource(). The file descriptor returned by <code>fd.getFileDescriptor()</code> refers to the entire app package. Without the offset and the length, the MediaPlayer will try to interpret the .apk file as a sound file—and fail.</p>
<p>There is a different way to load sounds: As <a href="http://developer.android.com/guide/topics/media/index.html">described in the Android Dev Guide</a>, you can also store sounds in the <code>res/raw/</code> folder of the project and use MediaPlayer.create() to load them:</p>
<blockquote><p><code>MediaPlayer mp = MediaPlayer.create(context, R.raw.sound_file_1);<br />
mp.start();</code></p></blockquote>
<p>As far as I can tell, this approach requires you to hard-code the integer constants that refer to the sounds (&#8220;R.raw.sound_file_1&#8243;) in the source code*. As these constants are auto-generated during the build, I did not find a way to store these constants in a data file that my app could read, so that I could associate in-game events with sounds at runtime.</p>
<p>*) I don&#8217;t know enough about Java introspection to turn a string such as &#8220;sound_file_1&#8243; into the corresponding constant from <code>R.raw</code>.</p>
<p><small>Portions of this page are reproduced from work created and <a href="http://code.google.com/policies.html">shared by Google</a> and used according to terms described in the <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons   3.0 Attribution License</a>.</small></p>
]]></content:encoded>
			<wfw:commentRss>http://realmike.org/blog/2010/12/11/sound-playback-in-processing-for-android/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Operating System Usage Statistics</title>
		<link>http://realmike.org/blog/2010/12/11/operating-system-usage-statistics/</link>
		<comments>http://realmike.org/blog/2010/12/11/operating-system-usage-statistics/#comments</comments>
		<pubDate>Sat, 11 Dec 2010 12:58:40 +0000</pubDate>
		<dc:creator>Michael Fötsch</dc:creator>
				<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[statistics]]></category>
		<category><![CDATA[w3schools]]></category>

		<guid isPermaLink="false">http://realmike.org/blog/?p=354</guid>
		<description><![CDATA[Graziano Sorbaioli pointed out a link to the w3schools.com OS Platform Statistics. The data from their web server access logs shows which operating systems visitors to w3schools.com use. I wanted to look at the data graphically, so I created two OpenOffice.org charts. Operating System Shares OS Platform Statistics - Yearly averages Not surprisingly, around 90% <span style="color:#777"> . . . &#8594; <a href="http://realmike.org/blog/2010/12/11/operating-system-usage-statistics/">Read More</a></span>]]></description>
			<content:encoded><![CDATA[<p><a href="https://identi.ca/notice/60228003">Graziano Sorbaioli</a> pointed out a link to the w3schools.com <a href="http://www.w3schools.com/browsers/browsers_os.asp">OS Platform Statistics</a>. The data from their web server access logs shows which operating systems visitors to w3schools.com use.</p>
<p>I wanted to look at the data graphically, so I created two OpenOffice.org charts.</p>
<div id="attachment_355" class="wp-caption alignleft" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/os-share.png"><img class="size-medium wp-image-355" title="os-share" src="http://realmike.org/blog/wp-content/uploads/2010/12/os-share-300x152.png" alt="OS Platform Statistics" width="300" height="152" /></a><p class="wp-caption-text">Operating System Shares</p></div>
<div id="attachment_356" class="wp-caption alignright" style="width: 310px"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/os-share-avg.png"><img class="size-medium wp-image-356" title="os-share-avg" src="http://realmike.org/blog/wp-content/uploads/2010/12/os-share-avg-300x158.png" alt="OS Platform Statistics - Yearly Averages" width="300" height="158" /></a><p class="wp-caption-text">OS Platform Statistics - Yearly averages</p></div>
<p>Not surprisingly, around 90% of visitors run Windows. But Windows usage is declining slowly, from 93% in 2003 down to 88% in 2010. Mac and Linux* are both growing slowly but steadily (Mac faster than Linux). All other operating systems account for only 0.67%.</p>
<p><span id="more-354"></span></p>
<p>*) I assume most of the Linux usage is from GNU/Linux, i.e., your average desktop Linux.</p>
<p>The w3schools.com statistics are obviously biased towards tech-savvy users (who else would read w3schools.com?). It almost certainly doesn&#8217;t mean that GNU/Linux runs on 5% of computers worldwide. The Wikipedia page on <a href="http://en.wikipedia.org/wiki/Usage_share_of_operating_systems">operating system usage share</a> comes up with much lower numbers for desktop GNU/Linux.</p>
<p>My personal (biased) interpretation is this: The more serious the computing gets that you are doing, the more likely you are to encounter Linux and GNU, from 2% in the general public, to 5% among web developers, to 43% on servers, to 92% on supercomputers<a href="http://en.wikipedia.org/wiki/Usage_share_of_operating_systems">*</a>.</p>
<p style="text-align: right;"><a href="http://realmike.org/blog/wp-content/uploads/2010/12/os-usage.ods">Chart source</a> (OpenOffice.org spreadsheet)</p>
]]></content:encoded>
			<wfw:commentRss>http://realmike.org/blog/2010/12/11/operating-system-usage-statistics/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 11.703 seconds -->
<!-- Cached page served by WP-Cache -->

