<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' version='2.0'><channel><atom:id>tag:blogger.com,1999:blog-18561009</atom:id><lastBuildDate>Sat, 13 Feb 2010 06:20:24 +0000</lastBuildDate><title>Bluish Coder</title><description>Programming Languages, Martial Arts and Computers. The Weblog of Chris Double.</description><link>http://www.bluishcoder.co.nz/</link><managingEditor>noreply@blogger.com (Chris Double)</managingEditor><generator>Blogger</generator><openSearch:totalResults>342</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-6244093721949054389</guid><pubDate>Sat, 13 Feb 2010 06:10:00 +0000</pubDate><atom:updated>2010-02-13T19:20:24.798+13:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Moving away from blogger</title><description>Blogger are &lt;a href="http://blogger-ftp.blogspot.com/"&gt;deprecating their ftp publishing&lt;/a&gt; support and are recommending users to switch to their custom domain feature where they host the blog files for you. I prefer to keep my posts on my own server so will be switching weblog systems in the near future.&lt;br /&gt;&lt;br /&gt;This will break existing links to Atom feeds for specific labels (eg. the feed for Mozilla specific posts) as they are on a blogger controlled domain. So if you're reading this through one of those Atom feeds and want to continue with it then you might want to switch to:&lt;pre&gt;http://bluishcoder.co.nz/tags/[tagname]/atom.xml&lt;/pre&gt;For example, the Mozilla specific posts will be in &lt;code&gt;&lt;a href="http://bluishcoder.co.nz/tags/mozilla/atom.xml"&gt;http://bluishcoder.co.nz/tags/mozilla/atom.xml&lt;/a&gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;My existing posts will remain at their current URL's.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-6244093721949054389?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2010/02/moving-away-from-blogger.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-3162683446128871648</guid><pubDate>Fri, 27 Nov 2009 22:19:00 +0000</pubDate><atom:updated>2009-11-28T11:24:21.807+13:00</atom:updated><title>Using the Wasp Lisp Secure Remote Injection Framework (MOSREF)</title><description>&lt;p&gt;MOSREF is a secure remote injection framework written in &lt;a href="http://waspvm.blogspot.com/"&gt;Wasp Lisp&lt;/a&gt; (which I previously wrote about &lt;a href="http://www.bluishcoder.co.nz/2009/11/wasp-lisp-small-scheme-like-lisp.html"&gt;here&lt;/a&gt;). With MOSREF you have a 'console' program running which can create dones applications that are run on a target system.&lt;/p&gt;&lt;p&gt;The console and drones can communicate with each other, executing shell commands or Wasp Lisp code. Drones can create other drones to 'bridge' bridge communications so the console can send commands to drones it is not directly connected too.&lt;/p&gt;&lt;p&gt;Lisp code can be compiled and sent to drones to execute. One of the 'built in' capabilities is a Socks proxy server. This can be run on a drone and data is tunneled to the console which the controller can use as a socks proxy.&lt;/p&gt;&lt;p&gt;MOSREF isn't built by default with Wasp. To build it you need to run 'waspc' to compile and create an executable (example assumes you are in the root of the Wasp source directory):&lt;/p&gt;&lt;pre&gt;$ &lt;strong&gt;cd mod&lt;/strong&gt;&lt;br /&gt;$ &lt;strong&gt;waspc -exe ../mosref bin/mosref&lt;/strong&gt;&lt;br /&gt;BUILD: bin/mosref&lt;br /&gt;BUILD: core/macro&lt;br /&gt;BUILD: core/config&lt;br /&gt;BUILD: site/config&lt;br /&gt;...&lt;br /&gt;BUILD: mosref/cmd/with&lt;br /&gt;BUILD: mosref/cmds&lt;br /&gt;BUILD: bin/mosref&lt;br /&gt;$ &lt;strong&gt;chmod +x ../mosref&lt;/strong&gt;&lt;br /&gt;$ &lt;strong&gt;rlwrap ../moseref&lt;/strong&gt;&lt;br /&gt;console&gt; &lt;strong&gt;help&lt;/strong&gt;&lt;br /&gt;Commands: clear &amp;lt;key&gt; ...&lt;br /&gt;          cp &amp;lt;src-file&gt; &amp;lt;dst-file&gt;&lt;br /&gt;          do &amp;lt;lisp-expr&gt;&lt;br /&gt;          drone &amp;lt;file&gt; &amp;lt;id&gt; &amp;lt;platform&gt;&lt;br /&gt;          exit&lt;br /&gt;          help [&amp;lt;command&gt;]&lt;br /&gt;          load &amp;lt;path&gt;&lt;br /&gt;          nodes&lt;br /&gt;          on &amp;lt;node-id&gt; [&amp;lt;command&gt;]&lt;br /&gt;          proxy [&amp;lt;portno&gt; [&amp;lt;secret&gt;]]&lt;br /&gt;          recover &amp;lt;id&gt;&lt;br /&gt;          set [&amp;lt;key&gt;[=&amp;lt;value&gt;] [&amp;lt;command&gt;]]&lt;br /&gt;          sh &amp;lt;cmd&gt;&lt;br /&gt;          with &amp;lt;key&gt;[=&amp;lt;value&gt;] [&amp;lt;command&gt;]&lt;/pre&gt;&lt;p&gt;The first thing you need to do on the running console is set the IP address and the port it will listen on (Replacing xx.xx.xx.xx with the IP address):&lt;/p&gt;&lt;pre&gt;console&gt; &lt;strong&gt;set addr=xx.xx.xx.xx&lt;/strong&gt;&lt;br /&gt;Set.&lt;br /&gt;console&gt; &lt;strong&gt;set port=10000&lt;/strong&gt;&lt;br /&gt;Set.&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Now you need to create a drone executable to be run on the target system:&lt;p&gt;&lt;pre&gt;console&gt; &lt;strong&gt;drone drone1 foo linux-x86&lt;/strong&gt;&lt;br /&gt;Drone executable created.&lt;br /&gt;Listening for drone on 10000...&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This creates an executable for Linux systems called 'drone1'. It is given the name node name 'foo'. It will show in the list of nodes available from the console:&lt;/p&gt;&lt;pre&gt;console&gt; &lt;strong&gt;nodes&lt;/strong&gt;&lt;br /&gt;NODES: console online address: xx.xx.xx.xx port: 10000&lt;br /&gt;       foo offline&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;When the 'drone1' executable is run on a target system it will connect to the console using an encrypted connection. You will need to find a way to copy and run the executable onto the target. The following shows it being run on the target:&lt;/p&gt;&lt;pre&gt;target$ ./drone1&lt;br /&gt;  DRONE: Preparing keys...&lt;br /&gt;  DRONE: Sending Drone Public Key...&lt;br /&gt;  DRONE: Sending Drone IV...&lt;br /&gt;  DRONE: Reading Console IV...&lt;br /&gt;  DRONE: CONSOLE IV CT is ...&lt;br /&gt;  DRONE: CONSOLE IV PT is ...&lt;br /&gt;  DRONE: Confirming Console IV...&lt;br /&gt;  DRONE: Waiting for Console to confirm Drone IV...&lt;br /&gt;  DRONE: Affiliation complete....&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The connection will show on the console:&lt;/p&gt;&lt;pre&gt;console&gt; &lt;strong&gt;nodes&lt;/strong&gt;&lt;br /&gt;NODES: console online address: xx.xx.xx.xx port: 10000&lt;br /&gt;       foo online&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Notice it shows 'foo' is now online. It's now possible to execute commands on the target machine by sending them to the drone. Using 'sh' you can execute shell commands. From the console:&lt;/p&gt;&lt;pre&gt;console&gt; &lt;strong&gt;on foo sh ifconfig&lt;/strong&gt;&lt;br /&gt;eth0      Link encap:Ethernet  HWaddr ...&lt;br /&gt;          inet addr:yy.yy.yy.yy  &lt;br /&gt;...&lt;br /&gt;          RX bytes:2458924520 (2.2 GB)  TX bytes:2458924520 (2.2 GB)&lt;br /&gt;console&gt; &lt;strong&gt;on foo set addr=yy.yy.yy.yy&lt;/strong&gt;&lt;br /&gt;Set.&lt;br /&gt;console&gt; &lt;strong&gt;on foo set port=10000&lt;/strong&gt;&lt;br /&gt;Set.&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Here we execute 'ifconfig' on the target so we can find out the IP address. The output of 'ifconfig' is sent back to the console. Using this information the addr and port is set on the drone. This can be used to have the target create new drones on internal machines that only it can access. It will then act as a bridge between the console and the internal machine.&lt;/p&gt;&lt;p&gt;As well as running shell commands you can run Wasp Lisp code:&lt;/p&gt;&lt;pre&gt;console&gt; &lt;strong&gt;on foo do (+ 1 2)&lt;/strong&gt;&lt;br /&gt;:: 3&lt;br /&gt;console&gt; &lt;strong&gt;on foo load lib/http-file-server.ms&lt;/strong&gt;&lt;br /&gt;:: spawn-http-file-server&lt;br /&gt;console&gt; &lt;strong&gt;on foo do (offer-http-file 2080 "/test" "text/plain" "Hello world!")&lt;/strong&gt;&lt;br /&gt;:: [queue 824A098]&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Using 'on foo do' we compile a Lisp expression and send it to 'foo' to be run. In this case a simple addition. 'on foo load' will load a Lisp file located on the console, compile it, and send the byte code to be run on 'foo'. Then we 'on foo do' to run a function contained in that file on the 'foo' machine. In this case, it runs a simple webserver. Any Lisp code can be sent and run.&lt;/p&gt;&lt;p&gt;It's possible to copy files between nodes too. In this next example we create another drone that will be run on a machine internal to the network that the target is on. Note that the build is performed on the console so we need to copy the executable from there to the target.&lt;/p&gt;&lt;pre&gt;console&gt; &lt;strong&gt;on foo drone drone2 bar linux-x86&lt;/strong&gt;&lt;br /&gt;Drone executable created.&lt;br /&gt;Listening for drone on 10000...&lt;br /&gt;console&gt; &lt;strong&gt;cp console:/home/console/waspvm/mod/drone2 foo:/tmp/drone2&lt;/strong&gt;&lt;br /&gt;Copy from console:/home/console/waspvm/mod/drone2 to foo:/tmp/drone2&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Using some magic means (an exploit, copying file using shell commands on the target drone, etc) we get 'drone2' running on another machine available internally on the target network:&lt;/p&gt;&lt;pre&gt;target2$ &lt;strong&gt;./drone2&lt;/strong&gt;&lt;br /&gt;  DRONE: Preparing keys...&lt;br /&gt;  DRONE: Sending Drone Public Key...&lt;br /&gt;  DRONE: Sending Drone IV...&lt;br /&gt;  DRONE: Reading Console IV...&lt;br /&gt;  DRONE: CONSOLE IV CT is ...&lt;br /&gt;  DRONE: CONSOLE IV PT is ...&lt;br /&gt;  DRONE: Confirming Console IV...&lt;br /&gt;  DRONE: Waiting for Console to confirm Drone IV...&lt;br /&gt;  DRONE: Affiliation complete....&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;From the console we now see the 'bar' node:&lt;/p&gt;&lt;pre&gt;console&gt; &lt;strong&gt;nodes&lt;/strong&gt;&lt;br /&gt;NODES: bar online&lt;br /&gt;       console online address: xx.xx.xx.xx port: 10000&lt;br /&gt;foo online address: yy.yy.yy.yy port: 10000&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;MOSREF has a 'proxy' command that lets you set up a Socks 4 proxy on the console that tunnels traffic to and from a target node. Here we set up a proxy to the 'bar' node:&lt;/p&gt;&lt;pre&gt;console&gt; &lt;strong&gt;on bar proxy 5000&lt;/strong&gt;&lt;br /&gt;SOCKS Proxy created, listening on port 5000.&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This will result in the 'console' machine having a Socks 4 proxy running on port 5000. If you configure Firefox to use this proxy you can access local webservers available from the internal network that 'bar' can see. Note that 'console' can't see 'bar' directly. It is tunnelling traffic to 'foo', from there to 'bar', then back from 'bar' to 'foo' and to 'console.&lt;/p&gt;&lt;p&gt;The source for MOSREF is in the Wasp Lisp distribution and makes for a good body of Wasp Lisp code for learning.&lt;/p&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/waspvm" rel="tag"&gt;waspvm&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-3162683446128871648?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/11/using-wasp-lisp-secure-remote-injection.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-6241425985699327211</guid><pubDate>Fri, 27 Nov 2009 08:28:00 +0000</pubDate><atom:updated>2009-11-27T21:35:02.217+13:00</atom:updated><title>Wasp Lisp - a Small Scheme-like Lisp</title><description>&lt;p&gt;&lt;a href="http://waspvm.blogspot.com/"&gt;Wasp Lisp&lt;/a&gt; is a small Scheme-like Lisp implementation developed by Scott Dunlop. It features a lightweight concurrency model (with similarities to &lt;a href="http://www.erlang.org"&gt;Erlang&lt;/a&gt; and &lt;a href="http://code.google.com/p/termite/"&gt;Termite&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;Wasp Lisp was originally derived from &lt;a href="http://bc.tech.coop/blog/061119.html"&gt;MOSREF&lt;/a&gt; - the Mosquito Secure Remote Execution Framework. It includes an implementation of MOSREF so can do similar things that the original was built for.&lt;/p&gt;&lt;p&gt;Wasp feels a lot like Scheme. It has a REPL which you can use to try Lisp interactively. You can spawn lightweight threads and use channels to communicate between threads. Here's a simple example with a thread that loops forever, waits for data to be sent to a channel and then prints that out. From the REPL strings are interactively sent to the channel:&lt;/p&gt;&lt;pre&gt;$ &lt;strong&gt;rlwrap ../wasp&lt;/strong&gt;&lt;br /&gt;&gt;&gt; &lt;strong&gt;(define channel (make-queue))&lt;/strong&gt;&lt;br /&gt;:: [queue 98154C0]&lt;br /&gt;&gt;&gt; &lt;strong&gt;(define (looper channel)&lt;/strong&gt;&lt;br /&gt;..   &lt;strong&gt;(forever&lt;/strong&gt;&lt;br /&gt;..     &lt;strong&gt;(define data (wait channel))&lt;/strong&gt;&lt;br /&gt;..     &lt;strong&gt;(print data)))&lt;/strong&gt;&lt;br /&gt;:: looper&lt;br /&gt;&gt;&gt; &lt;strong&gt;(spawn looper channel)&lt;/strong&gt;&lt;br /&gt;:: [process looper]&lt;br /&gt;&gt;&gt; &lt;strong&gt;(send "hello\n" channel)&lt;/strong&gt;&lt;br /&gt;hello&lt;br /&gt;:: [queue-output 9815500]&lt;br /&gt;&gt;&gt; &lt;strong&gt;(send "world\n" channel)&lt;/strong&gt;&lt;br /&gt;world&lt;br /&gt;:: [queue-output 9815500] &lt;/pre&gt;&lt;p&gt;Threads are co-operative in Wasp. You need to manually yield to switch from a thread. The following example doesn't manually yield and will constantly print 'a' to the terminal:&lt;/p&gt;&lt;pre&gt;(begin &lt;br /&gt;  (spawn &lt;br /&gt;    (lambda () &lt;br /&gt;      (forever (print "a\n")))) &lt;br /&gt;  (spawn &lt;br /&gt;    (lambda () &lt;br /&gt;      (forever (print "b\n")))))&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;To yield you use the 'pause' function. Adding this to the 'forever' loop in the example above will switch between the two threads:&lt;/p&gt;&lt;pre&gt;(begin &lt;br /&gt;  (spawn &lt;br /&gt;    (lambda () &lt;br /&gt;      (forever &lt;br /&gt;        (pause)&lt;br /&gt;        (print "a\n")))) &lt;br /&gt;  (spawn &lt;br /&gt;    (lambda () &lt;br /&gt;      (forever &lt;br /&gt;        (pause)&lt;br /&gt;        (print "b\n")))))&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Wasp Lisp code can get compiled to a compact bytecode format using the 'waspc' command. This can produce a binary executable for the platform:&lt;/p&gt;&lt;pre&gt;$ &lt;strong&gt;cat &gt;test.ms&lt;br /&gt;(define (main)&lt;br /&gt;  (print "hello world!\n"))&lt;/strong&gt;&lt;br /&gt;$ &lt;strong&gt;waspc -exe hello test.ms&lt;/strong&gt;&lt;br /&gt;BUILD: test&lt;br /&gt;BUILD: core/macro&lt;br /&gt;BUILD: core/config&lt;br /&gt;BUILD: site/config&lt;br /&gt;BUILD: core/file&lt;br /&gt;BUILD: core/module&lt;br /&gt;BUILD: core/io&lt;br /&gt;BUILD: core/macro&lt;br /&gt;BUILD: core/config&lt;br /&gt;BUILD: site/config&lt;br /&gt;BUILD: core/file&lt;br /&gt;BUILD: core/module&lt;br /&gt;BUILD: core/io&lt;br /&gt;BUILD: test&lt;br /&gt;$ &lt;strong&gt;chmod +x hello&lt;/strong&gt;&lt;br /&gt;$ &lt;strong&gt;./hello&lt;/strong&gt;&lt;br /&gt;hello world!&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;There is quite a bit of example code, including a simple HTTP server:&lt;/p&gt;&lt;pre&gt;$ &lt;strong&gt;rlwrap ../wasp&lt;/strong&gt;&lt;br /&gt;&gt;&gt; &lt;strong&gt;(import "lib/http-file-server")&lt;/strong&gt;&lt;br /&gt;:: #t&lt;br /&gt;&gt;&gt; &lt;strong&gt;(offer-http-file 2080 "/test" "text/plain" "Hello world!")&lt;/strong&gt;&lt;br /&gt;:: [queue 985A1F0]&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This serves the text 'Hello world!' when http://localhost:2080/test is requested. The Wasp VM site has an informal &lt;a href="http://waspvm.googlepages.com/dragracingagainstthttpdusingsiege"&gt;speed test of serving data&lt;/a&gt; comparing against THTTPD.&lt;/p&gt;&lt;p&gt;Wasp builds and runs on Linux, Mac OS X and Windows. Instructions for building and links to other information are &lt;a href="http://waspvm.googlepages.com/"&gt;here&lt;/a&gt;. The source is available on &lt;a href="https://launchpad.net/waspvm"&gt;launchpad&lt;/a&gt;. &lt;a href="http://www.monkey.org/~provos/libevent/"&gt;libevent&lt;/a&gt; is needed to build.&lt;/p&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/waspvm" rel="tag"&gt;waspvm&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-6241425985699327211?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/11/wasp-lisp-small-scheme-like-lisp.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-7506329736191504343</guid><pubDate>Mon, 27 Jul 2009 11:30:00 +0000</pubDate><atom:updated>2009-07-27T23:32:08.134+12:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>self</category><title>Displaying images with Self</title><description>&lt;p&gt;The &lt;a href='http://www.selflanguage.org'&gt;Self&lt;/a&gt; source code has some example programs, one of which is a web browser. This was developed quite a long time ago and is unable to nicely display most pages on the modern web but it does a reasonable job of basic pages. On the Linux port there were some problems with displaying images however. I tracked this down to two issues:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;It only natively decoded image formats that aren't really used on the web (Sun Raster format for example). The GIF and JPG handling code spawned external programs, which I didn't have on my Linux install, to convert to a format it could handle before displaying.&lt;/li&gt;&lt;li&gt;There was a bug in the color management code on X11 for displays greater than 8 bit.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The first was a quick fix by changing the programs that it used to do the conversion to one readily available on Linux. I changed it to use the &lt;a href="http://www.imagemagick.org/"&gt;Image Magick&lt;/a&gt; '&lt;a href="http://www.imagemagick.org/script/convert.php"&gt;convert&lt;/a&gt;' program. This enabled displaying code in an imageMorph by setting the image for the morph:&lt;/p&gt;&lt;pre&gt;setImage: ui2Image copyFromGIFFile: 'test.gif'&lt;/pre&gt;&lt;p&gt;I tracked the second issue down to code that was sending a message to an object that didn't understand that message (Static typing fans can say 'I told you so' here). Self has a 'paintManager' which handles color mapping for displays that can't display a large number of colors. On 8 bit displays this is a 'paintManager'. On displays with more colors it's a 'unmappedPaintManager'. The latter doesn't have some of the slots of the former and there was code trying to do this. I changed this to check if the paintManager instance can do color mapping before sending the messages.&lt;/p&gt;&lt;p&gt;With that change the web browser could display images. An example page that works with the browser (one of the few...), and code to display it:&lt;/p&gt;&lt;pre&gt;'http://www.bluishcoder.co.nz/self/imagetest.html' asURL getPageForUser&lt;/pre&gt;&lt;p&gt;The patches with these fixes is available from the &lt;a href="http://github.com/doublec/self/tree/webbrowser"&gt;webbrowser branch&lt;/a&gt; of my fork of the Self git repostory on github. The fixes were only a few lines of code.&lt;/p&gt;&lt;p&gt;I did a &lt;a href="http://www.bluishcoder.co.nz/self/selfimage.ogg"&gt;short screencast&lt;/a&gt; showing loading image morph's and displaying the web page in the browser. And before you say, "wow, that GUI looks so 90's", don't forget - it was.&lt;/p&gt;&lt;video src='http://www.bluishcoder.co.nz/self/selfimage.ogg' controls='controls'&gt;&lt;/video&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/self" rel="tag"&gt;self&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-7506329736191504343?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/07/displaying-images-with-self.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-6138669222816188430</guid><pubDate>Sun, 26 Jul 2009 05:51:00 +0000</pubDate><atom:updated>2009-07-27T00:02:55.797+12:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>self</category><title>Building and using Self on Linux</title><description>&lt;p&gt;The original implementation of the &lt;a href="http://selflanguage.org/"&gt;Self programming language&lt;/a&gt; is easy to build from source. Russell Allen maintains a &lt;a href="http://github.com/russellallen/self/tree/master"&gt;git repository on github&lt;/a&gt; containing the source.&lt;/p&gt;&lt;p&gt;I use &lt;a href="http://www.archlinux.org/"&gt;Arch Linux&lt;/a&gt; with 'flex' and 'tcsh' packages installed for various parts of the build process. To build a Self binary:&lt;/p&gt;&lt;pre&gt;$ &lt;strong&gt;git clone git://github.com/russellallen/self.git&lt;/strong&gt;&lt;br /&gt;$ &lt;strong&gt;cd self/release&lt;/strong&gt;&lt;br /&gt;$ &lt;strong&gt;sh buildLinuxVM&lt;/strong&gt;&lt;br /&gt;$ &lt;strong&gt;cd ..&lt;/strong&gt;&lt;br /&gt;$ &lt;strong&gt;./Self&lt;/strong&gt;&lt;/pre&gt;&lt;p&gt;The build takes about 30 minutes on my laptop. There will be many compilation warnings but these can be safely ignored. The result of the build is a 'Self' executable in the root directory of the cloned source. The executable can be run but most of the Self library is not loaded. You need to create an image to run or use an existing one. About the only thing you can do with the Self VM without an image is use primitives.&lt;/p&gt;&lt;p&gt;The 'objects' directory contains the source for the core Self library, the User Inteface, as well as other applications and interesting stuff. These can be used to build an image to run Self. The file 'all2.self' can be used to create an image including the graphical user interface. 'small.self' can be used to build an image without the user interface. The primitive '_RunScript' is used to load these files. Once loaded you can save a 'snapshot' (this is the term Self uses for images) which can be resumed in later sessions.&lt;/p&gt;&lt;pre&gt;$ &lt;strong&gt;cd objects&lt;/strong&gt;&lt;br /&gt;$ &lt;strong&gt;../Self&lt;/strong&gt;&lt;br /&gt;Self Virtual Machine Version 4.1.13, Sun 26 Jul 09 16:59:28 Linux&lt;br /&gt;Copyright 1989-2003: The Self Group (type _Credits for credits)&lt;br /&gt;&lt;br /&gt;for I386:  LogVMMessages = true&lt;br /&gt;for I386:  PrintScriptName  = true&lt;br /&gt;for I386:  Inline = true&lt;br /&gt;for I386:  SICDeferUncommonBranches = false (not implemented)&lt;br /&gt;for I386:  SICReplaceOnStack = false (not implemented)&lt;br /&gt;for I386:  SaveOutgoingArgumentsOfPatchedFrames = true&lt;br /&gt;VM # &lt;strong&gt;'all2.self' _RunScript&lt;/strong&gt;&lt;br /&gt;reading all2.self...&lt;br /&gt;reading ./core/init.self...&lt;br /&gt;reading ./core/allCore.self...&lt;br /&gt;reading ./core/systemStructure.self...&lt;br /&gt;reading ./core/defaultBehavior.self...&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;reading ./ui2/outliner/profileSliceGrpMod.self...&lt;br /&gt;reading ./ui2/outliner/profileSelfSlotMdl.self...&lt;br /&gt;reading ./ui2/outliner/powerOperations.self...&lt;br /&gt;verifying newgen: eden from to oldgen: old0 old1 z p r S v O m N M i  done&lt;br /&gt;Starting: Collecting Garbage...&lt;br /&gt;Finished: Collecting Garbage&lt;br /&gt;Starting: Refilling module cache...&lt;br /&gt;Finished: Refilling module cache&lt;br /&gt;"Self 0" &lt;strong&gt;saveAs: 'ui.snap'&lt;/strong&gt;&lt;br /&gt;Starting: Writing snapshot to ui.snap...&lt;br /&gt;Finished: Writing snapshot to ui.snap&lt;br /&gt;shell&lt;br /&gt;"Self 1" &lt;strong&gt;quit&lt;/strong&gt;&lt;br /&gt;Save to ui.snap before quitting? &lt;br /&gt;  y =&gt; save, then quit&lt;br /&gt;  n =&gt; quit without saving&lt;br /&gt;  RET =&gt; cancel&lt;br /&gt;Response: &lt;strong&gt;n&lt;/strong&gt;&lt;/pre&gt;&lt;p&gt;Notice the call to 'saveAs:' to save the image snapshot. 'quit' is used to exit the running Self session. This image can now be resumed using the '-s' argument to 'Self' whenever you want to run Self:&lt;/p&gt;&lt;pre&gt;$ &lt;strong&gt;cd objects&lt;/strong&gt;&lt;br /&gt;$ &lt;strong&gt;../Self -s ui.snap&lt;/strong&gt;&lt;br /&gt;for I386:  LogVMMessages = true&lt;br /&gt;for I386:  PrintScriptName  = true&lt;br /&gt;for I386:  Inline = true&lt;br /&gt;for I386:  SICDeferUncommonBranches = false (not implemented)&lt;br /&gt;for I386:  SICReplaceOnStack = false (not implemented)&lt;br /&gt;for I386:  SaveOutgoingArgumentsOfPatchedFrames = true&lt;br /&gt;&lt;br /&gt; Welcome to the Self system!  (Version 4.4)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Copyright 1992-2009 AUTHORS, Sun Microsystems, Inc. and Stanford University.&lt;br /&gt;See the LICENSE file for license information.&lt;br /&gt;&lt;br /&gt;Type _Credits for full credits.&lt;br /&gt;&lt;br /&gt;VM version: 4.1.13&lt;br /&gt;&lt;br /&gt;  "Self 1" &lt;/pre&gt;&lt;p&gt;At this point you can now use any Self expressions. All code is run in the contents of an object called 'shell'. You can start the graphical user interface by passing the 'open' message to the 'desktop' object:&lt;/p&gt;&lt;pre&gt;"Self 1" &lt;strong&gt;desktop open&lt;/strong&gt;&lt;/pre&gt;&lt;p&gt;The desktop will appear with a 'trash can' object and an outliner for the 'shell' object. Left clicking on the middle button labelled 'E' in the group of three buttons on the right of the shell will open an expression evaluator allowing you to enter Self expressions. Middle click on objects to get an object specific menu. On the desktop this provides a menu item to quit when you want to leave the session.&lt;/p&gt;&lt;p&gt;There are some interesting applications in the 'objects' directory. For example, there is a Smalltalk implementation written in Self. This can be loaded at the shell with the command:&lt;/p&gt;&lt;pre&gt;"Self 1" &lt;strong&gt;bootstrap read: 'smalltalk' From: 'applications/smalltalk'&lt;/strong&gt;&lt;/pre&gt;&lt;p&gt;When it completes loading you can find a 'smalltalk' item on the desktop's right click menu. Choosing that provides a menu to load a standard Smalltalk browser, workspace and inspector, allowing you to write Smalltalk code. There's a document that &lt;a href="http://selflanguage.org/_static/manuals/smalltalk.ps.gz"&gt;describes the Smalltalk emulator&lt;/a&gt; for more information about it. There are other interesting applications in the objects directory including a web browser, Java emulator, a C preprocessor, &lt;a href="http://www.cs.washington.edu/research/projects/cecil/"&gt;Cecil&lt;/a&gt; implementation and a parser/lexer generator. Most of this code is old and in various states of usability but it provides some interesting examples of Self code to look at and play with.&lt;/p&gt;&lt;p&gt;The &lt;a href="http://selflanguage.org/_static/tutorial/Tutorial/index.html"&gt;Self tutorial&lt;/a&gt; provides a good introduction to using the Self user interface.&lt;/p&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/self" rel="tag"&gt;self&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-6138669222816188430?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/07/building-and-using-self-on-linux.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-6365521314596965711</guid><pubDate>Thu, 16 Jul 2009 08:08:00 +0000</pubDate><atom:updated>2009-07-16T20:13:11.614+12:00</atom:updated><title>Prototype Based Programming Languages</title><description>&lt;p&gt;I've been reading up on &lt;a href="http://en.wikipedia.org/wiki/Prototype-based_programming"&gt;protoype based&lt;/a&gt; programming languages recently. Mainly using the &lt;a href="http://iolanguage.com/"&gt;Io Programming Language&lt;/a&gt; and &lt;a href="http://selflanguage.org/"&gt;Self&lt;/a&gt; but also looking at &lt;a href="http://www.ccs.neu.edu/home/ivan/moo/lm_toc.html"&gt;LambdaMOO&lt;/a&gt; and similar languages. A good overview of using the prototype based approach to building programs is &lt;a href="http://research.sun.com/self/papers/organizing-programs.html"&gt;Organizing Programs without Classes&lt;/a&gt;. This post is based on examples from that paper and from &lt;a href="http://crpit.com/abstracts/CRPITV13Noble.html"&gt;Attack of the Clones&lt;/a&gt; which covers design patterns using Self.&lt;/p&gt;&lt;h2&gt;Self&lt;/h2&gt;&lt;p&gt;In the Self programming language objects are created using a literal object syntax. This syntax defines code and slots within the &lt;code&gt;(|&lt;/code&gt; and &lt;code&gt;|)&lt;/code&gt; delimiters. An example object looks like:&lt;/p&gt;&lt;pre&gt;point = (|&lt;br /&gt;  parent* = traits point.&lt;br /&gt;  x.&lt;br /&gt;  y.&lt;br /&gt;|)&lt;/pre&gt;&lt;p&gt;This creates an object with 3 slots. The slots are 'parent', 'x' and 'y'. The 'parent' slot is assigned an inital value of 'traits point' which is the traits object for points (more on what this is later). The '*' that is suffixed to the 'parent' slot means it is a prototype slot and used in the prototype slot lookup chain.&lt;/p&gt;&lt;p&gt;This means when a message is sent to the 'point' object the lookup starts with the 'point' object. If a slot with the messages name is not found in that object then each prototype slot (those suffixed with '*') are searched looking for a slot with that name.&lt;/p&gt;&lt;p&gt;So in the 'point' case, looking for 'x' will find it immediately in the point object. Looking for 'print' will not so it will look for it in the 'traits point' object. If it's not there it will look in that objects prototype slots and so on until it is found or the search is exhausted.&lt;/p&gt;&lt;p&gt;The idiom in Self (and other prototype based languages) is to create global objects like these and use 'clone' to create copies of it. So creating two different points would look like:&lt;/p&gt;&lt;pre&gt;a = point clone.&lt;br /&gt;b = point clone.&lt;/pre&gt;&lt;p&gt;Notice that 'point' has no method slots. Only the 'x' and 'y' which contain data. The methods are defined in the 'traits point' object. The definition of that could look something like:&lt;/p&gt;&lt;pre&gt;traits point = (|&lt;br /&gt;  parent* = traits clonable.&lt;br /&gt;  print = x println y println.&lt;br /&gt;|)&lt;/pre&gt;&lt;p&gt;This provides a method to print the 'x' and 'y' values of the object and another parent that provides other basic functionality lie the ability to clone. The 'traits point' object doesn't define any data slots. It defines only methods. However it uses 'x' and 'y' messages that aren't defined. It expects to be used in a prototype slot of another object that defines the 'x' and 'y' slots (like ur 'point' example earlier.&lt;/p&gt;&lt;p&gt;Separating the code out into data objects and trait objects allows the trait object to be reused in other objects. For example, an object that computes the 'x' and 'y' values rather than storing them can re-use the traits object:&lt;/p&gt;&lt;pre&gt;computed_point = (|&lt;br /&gt;  parent* = traits point.&lt;br /&gt;  x = ..compute x..&lt;br /&gt;  y = ..compute y..&lt;br /&gt;|)&lt;/pre&gt;&lt;p&gt;This 'computed_point' can be used anywhere a point is expected. The traits object sends the 'x' and 'y' messages when it needs their value and it doesn't matter if there stored as data as in the 'point' object, or as methods that calculate the value as in the 'computed_point' object. Each 'point' and 'computed_point' object shares a single trait object instance. This avoids the need to have multiple copies of the methods in each point object instance.&lt;/p&gt;&lt;p&gt;The prototype slots of an object effectively form an inheritance relationship. The way to subclass objects in Self is to create a new object and set a prototype slot to an instance of the parent object. Usually it's the trait objects that map the subclass relationship since it is those objects that contain the object behaviour (ie. the methods and no data). An example follows in Self of how a 'polygon' and 'filled_polygon' object can be modelled (this is from the 'Organizing Programs without Classes' paper):&lt;/p&gt;&lt;pre&gt;polygon_traits = (|&lt;br /&gt;  draw = ...draw using 'vertices' slot to get points...&lt;br /&gt;|)&lt;br /&gt;&lt;br /&gt;polygon = (|&lt;br /&gt;  parent* = polygon_traits.&lt;br /&gt;  vertices.&lt;br /&gt;|)&lt;br /&gt;&lt;br /&gt;filled_polygon_traits = (|&lt;br /&gt;  parent* = polygon_traits.&lt;br /&gt;  draw = ...draw using 'vertices' and 'fillPattern'...&lt;br /&gt;|)&lt;br /&gt;&lt;br /&gt;filled_polygon = (|&lt;br /&gt;  parent* = filled_polygon_traits.&lt;br /&gt;  vertices.&lt;br /&gt;  fillPattern;&lt;br /&gt;|)&lt;/pre&gt;&lt;p&gt;Cloning the 'polygon' object and sending the 'draw' message will draw the polygon using the list of points held in the 'vertices' slot. Cloning the 'filled_polygon' object and sending the 'draw' message will draw using the specialized 'draw' method that also uses the 'fillPattern' slot to fill the polygon when drawing. This can re-use the 'draw' method in the 'polygon_traits' object if needed.&lt;/p&gt;&lt;p&gt;The new 'filled_polygon' object did require defining a new 'vertices' slot. Self allows multiple prototype slots, each of which is involved in the lookup for slot names. We can share the 'vertices' from the 'polygon' object by making that an additional prototype slot in 'filled_polygon'. This is often termed a 'data parent':&lt;/p&gt;&lt;pre&gt;filled_polygon = (|&lt;br /&gt;  parent* = filled_polygon_traits.&lt;br /&gt;  dataParent* = polygon clone.&lt;br /&gt;  fillPattern;&lt;br /&gt;|)&lt;/pre&gt;&lt;p&gt;Notice the 'dataParent' slot is a prototype slot (suffixed with a '*'). This means it participates in the slot lookup process. The data parent approach has an advantage over the previous example in that if we change the representation of the 'polygon' object then all new 'filled_polygon' instances will get this new representation. We don't need to edit the 'filled_polygon' definition for the modified or additional slots.&lt;/p&gt;&lt;p&gt;In the 'filled_polygon' example we re-used the 'vertices' slot from 'polygon'. We can also define subclasses that implement 'vertices' differently than 'polygon'. For example, a rectangle that stores the four corners and computes the vertices from this. Due to the seperation of state and behaviour this can be modelled easily:&lt;/p&gt;&lt;pre&gt;rectangle_traits = (|&lt;br /&gt;  parent* = polygon_traits.&lt;br /&gt;  draw = ...draw rectangle using left, right, top, bottom...&lt;br /&gt;  vertices = ...compute vertices list using left, right, etc...&lt;br /&gt;|)&lt;br /&gt;&lt;br /&gt;rectangle = (|&lt;br /&gt;  parent* = rectangle_traits.&lt;br /&gt;  left.&lt;br /&gt;  right.&lt;br /&gt;  top.&lt;br /&gt;  bottom.&lt;br /&gt;|)&lt;/pre&gt;&lt;p&gt;Inheritance in Self can be dynamic if the prototype slots are made assignable. This means, at runtime, we can change the value of the slot used during message lookup, resulting in different behaviour. This can be used for objects that can be in different states.&lt;/p&gt;&lt;p&gt;An example is a 'file' object. It can be opened or closed. Some methods in 'file' can only be used when the file is open, and some only when it is closed. This could be managed by conditional checks in each method. Or the parent of the object could be changed to a different traits object depending on the state - this avoids the need for each method to check if the file is in the open or closed state:&lt;/p&gt;&lt;pre&gt;open_file_traits = (|&lt;br /&gt;  read = ...&lt;br /&gt;  close = setParent: close_file_traits.&lt;br /&gt;|)&lt;br /&gt;&lt;br /&gt;closed_file_traits = (|&lt;br /&gt;  open = setParent: open_file_traits.&lt;br /&gt;|)&lt;br /&gt;&lt;br /&gt;file = (|&lt;br /&gt;  parent* = closed_file_traits.&lt;br /&gt;|)&lt;/pre&gt;&lt;p&gt;Methods like 'open' are only available on closed files. 'read' can only be called on opened files. This is basically the &lt;a href="http://en.wikipedia.org/wiki/Strategy_pattern"&gt;Strategy pattern&lt;/a&gt; made easy using Self's dynamic inheritance.&lt;/p&gt;&lt;h2&gt;Io&lt;/h2&gt;&lt;p&gt;Whereas Self defines the prototype lookup chain to be that of the prototype slots in an object, Io instead has a slot called 'protos' which is a list of all objects in the prototype chain. Instead of creating slots with a name suffixed with '*' you append to the existing 'protos' list.&lt;/p&gt;&lt;p&gt;The 'protos' list is initially populated when you clone an object with the object that you cloned. This is unlike Self where copying an object does a shallow copy of all the slots of that object. In Io you get a 'differential inheritance' model where your newly created object has no slots, just a 'protos' field that contains the original object that was cloned. The Self 'point' example I used earlier looks like:&lt;/p&gt;&lt;pre&gt;Point := Object clone do(&lt;br /&gt;  x := 0&lt;br /&gt;  y := 0&lt;br /&gt;)&lt;/pre&gt;&lt;p&gt;Calling 'clone' on this new 'Point' object results in a new object that does not contain it's own 'x' and 'y' values. Instead its 'protos' field points to the 'Point' object which contains the values. When you set the 'x' value on the clone it will then create its own 'x' slot rather than changing the prototypes. In this way clones of big objects where relatively few slots are changed will save some memory:&lt;/p&gt;&lt;pre&gt;a := Point clone&lt;br /&gt;b := Point clone&lt;br /&gt;a x = 5&lt;br /&gt;a x println&lt;br /&gt; =&gt; 5&lt;br /&gt;b x println&lt;br /&gt; =&gt; 0&lt;br /&gt;a protos first == Point&lt;br /&gt; =&gt; true&lt;br /&gt;b protos first == Point&lt;br /&gt; =&gt; true&lt;/pre&gt;&lt;p&gt;This does have an interesting side effect in that if you clone a clone then you can end up with a longish prototype chain for the method lookup:&lt;/p&gt;&lt;pre&gt;a := Point clone&lt;br /&gt;b := a clone&lt;br /&gt;c := b clone&lt;br /&gt;c protos first == b&lt;br /&gt; =&gt; true&lt;br /&gt;c protos first protos first == a&lt;br /&gt; =&gt; true&lt;br /&gt;c protos first protos first protos first == Point&lt;br /&gt; =&gt; true&lt;/pre&gt;&lt;p&gt;Inheritance is handled in much the same manner as Self but you need to manipulate the 'protos' slot instead of having multiple prototype slots. The filled polygon example looks like:&lt;/p&gt;&lt;pre&gt;PolygonTraits = Object clone do(&lt;br /&gt;  draw := method(vertices foreach(v, v println))&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;Polygon := PolygonTraits clone do(&lt;br /&gt;  vertices := list(1,2,3,4)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;FilledPolygonTraits := PolygonTraits clone do(&lt;br /&gt;  draw := method(resend; fillPattern println)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;FilledPolygon := FilledPolygonTraits clone do(&lt;br /&gt;  appendProto(Polygon clone)&lt;br /&gt;  fillPattern := "solid"&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;Polygon clone draw&lt;br /&gt;  =&gt; 1&lt;br /&gt;     2&lt;br /&gt;     3&lt;br /&gt;FilledPolygon clone draw&lt;br /&gt;  =&gt; 1&lt;br /&gt;     2&lt;br /&gt;     3&lt;br /&gt;     "solid"&lt;/pre&gt;&lt;p&gt;'appendProto' appends an object to the prototype chain which is initially 'FilledPolygonTraits' in this examples as that was the initial object we cloned. The dynamic inheritance example can also be done in Io:&lt;/p&gt;&lt;pre&gt;OpenFileTraits := Object clone do(&lt;br /&gt;  read := method(n, "Reading #{n} bytes" interpolate println)&lt;br /&gt;  close := method(&lt;br /&gt;    self removeProto(OpenFileTraits)&lt;br /&gt;    self appendProto(ClosedFileTraits)&lt;br /&gt;  )&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;ClosedFileTraits := Object clone do(&lt;br /&gt;  open := method(&lt;br /&gt;    self removeProto(ClosedFileTraits)&lt;br /&gt;    self appendProto(OpenFileTraits)&lt;br /&gt;  )&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;File := Object clone do(&lt;br /&gt;  init := method(self appendProto(ClosedFileTraits))&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;f := File clone&lt;br /&gt;f read(255)&lt;br /&gt;  =&gt; Exception: File does not respond to 'read'&lt;br /&gt;f open&lt;br /&gt;f read(255)&lt;br /&gt;  =&gt; reading 255 bytes&lt;br /&gt;f open&lt;br /&gt;  =&gt; Exception: File does not respond to 'open'&lt;br /&gt;f close&lt;/pre&gt;&lt;p&gt;It's a bit more work than in Self to manually manage the prototype chain but does work.&lt;/p&gt;&lt;h2&gt;JavaScript&lt;/h2&gt;&lt;p&gt;JavaScript is also a prototype based programming language. Unlike Self or Io it only allows one object to be used as the prototype in any given object. This is stored in a hidden '__proto__' member and cannot be updated once set on construction (some implementations allow changing it however). Objects are created by using the 'new' keyword on a constructor function that initializes the object. For now I'll leave it as an exercise for the reader to implement the examples above in JavaScript. I'd be interested in the approaches people take.&lt;/p&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/self" rel="tag"&gt;self&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/io" rel="tag"&gt;io&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/javascript" rel="tag"&gt;javascript&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-6365521314596965711?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/07/prototype-based-programming-languages.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-6897339688065370851</guid><pubDate>Sat, 27 Jun 2009 10:06:00 +0000</pubDate><atom:updated>2009-06-27T22:07:53.489+12:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Playing Ogg files with audio and video in sync</title><description>&lt;p&gt;&lt;a href="http://www.bluishcoder.co.nz/2009/06/decoding-vorbis-files-with-libvorbis.html"&gt;My last post in this series&lt;/a&gt; had Vorbis audio playing but with Theora video out of sync. This post will go through an approach to keeping the video in sync with the audio.&lt;/p&gt;&lt;p&gt;To get video in sync with the audio we need a timer incrementing from when we start playback. We can't use the system clock for this as it is not necessarily keeping the same time as the audio or video being played. The system clock can drift slightly and over time this audio and video to get out of sync.&lt;/p&gt; &lt;p&gt;The audio library I'm using, libsydneyaudio, has an API call that allows getting the playback position of the sound sample being played by the audio system. This is a value in bytes. Since we know the sample rate and number of channels of the audio stream we can compute a time value from this. Synchronisation becomes a matter of continuously feeding the audio to libsydneybackend, querying the current position, converting it to a time value, and displaying the frame for that time.&lt;/p&gt;&lt;p&gt;The time for a particular frame is returned by the call to &lt;a href="http://theora.org/doc/libtheora-1.0/group__decfuncs.html#g31c814bf09b2232aff69c57ae20f04eb"&gt;th_decode_packetin&lt;/a&gt;. The last parameter is a pointer to hold the 'granulepos' of the decoded frame. The Theora spec explains that the granulepos can be used to compute the time that this frame should be displayed up to. That is, when this time is exceeded this frame should no longer be displayed. It also enables computing the location of the keyframe that this frame depends on - I'll cover what this means when I write about how to do seeking.&lt;/p&gt;&lt;p&gt;The libtheora API &lt;a href="http://theora.org/doc/libtheora-1.0/group__basefuncs.html#g707e1e281de788af0df39ef00f3fb432"&gt;th_granule_time&lt;/a&gt; converts a 'granulepos' to an absolute time in seconds. So decoding a frame gives us 'granulepos'. We store this so we know when to stop displaying the frame. We track the audio position, convert it to a time. If it exceeds this value we decode the next frame and display that. Here's a breakdown of the steps:&lt;/p&gt;&lt;ol&gt;  &lt;li&gt;Read the headers from the Ogg file. Stop when we hit the first data packet.&lt;/li&gt;  &lt;li&gt;Read packets from the audio stream in the Ogg file. For each audio packet:    &lt;ol&gt;      &lt;li&gt;Decode the audio data and write it to the audio hardware.&lt;/li&gt;      &lt;li&gt;Get the current playback position of the audio and convert it to an absolute time value.&lt;/li&gt;      &lt;li&gt;Convert the last granulepos read (defaulting to zero if none have been read) to an absolute time value using the libtheora API.&lt;/li&gt;      &lt;li&gt;If the audio time is greater than the video time:    &lt;ol&gt;      &lt;li&gt;Read a packet from the Theora stream.&lt;/li&gt;      &lt;li&gt;Decode that packet and display it&lt;/li&gt;      &lt;li&gt;Store the granulepos from that decoded frame so we know when to display the next frame.&lt;/li&gt;    &lt;/ol&gt;      &lt;/li&gt;    &lt;/ol&gt;  &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Notice that the structure of the program is different to the last few articles. We no longer read all packets from the stream, processing them as we get them. Instead we specifically process the audio packets and only handle the video when it's time to display them. Since we are driving our a/v sync off the audio clock we must continously feed the audio data. I think it tends to be a better user experience to have flawless audio with video frame skipping rather than skipping audio but smooth video. Worse is to have both skipping of course.&lt;/p&gt;&lt;p&gt;The example code for this article is in the '&lt;a href="http://github.com/doublec/plogg/tree/part4_avsync"&gt;part4_avsync&lt;/a&gt;' branch on github.&lt;/p&gt;&lt;p&gt;This example takes a slightly different approach to reading headers. I use &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_stream_packetpeek.html"&gt;ogg_stream_packetpeek&lt;/a&gt; to peek ahead in the bitstream for a packet and do the header processing on the peeked packet. If it is a header I then consume the packet. This is done so I don't consume the first data packet when reading the headers. I want the data packets to be consumed in a particular order (audio, followed by video when needed).&lt;/p&gt;&lt;pre&gt;// Process all available header packets in the stream. When we hit&lt;br /&gt;// the first data stream we don't decode it, instead we&lt;br /&gt;// return. The caller can then choose to process whatever data&lt;br /&gt;// streams it wants to deal with.&lt;br /&gt;ogg_packet packet;&lt;br /&gt;while (!headersDone &amp;amp;&amp;amp;&lt;br /&gt;       (ret = ogg_stream_packetpeek(&amp;amp;stream-&gt;mState, &amp;amp;packet)) != 0) {&lt;br /&gt;assert(ret == 1);&lt;br /&gt;&lt;br /&gt;// A packet is available. If it is not a header packet we exit.&lt;br /&gt;// If it is a header packet, process it as normal.&lt;br /&gt;headersDone = headersDone || handle_theora_header(stream, &amp;amp;packet);&lt;br /&gt;headersDone = headersDone || handle_vorbis_header(stream, &amp;amp;packet);&lt;br /&gt;if (!headersDone) {&lt;br /&gt;  // Consume the packet&lt;br /&gt;  ret = ogg_stream_packetout(&amp;amp;stream-&gt;mState, &amp;amp;packet);&lt;br /&gt;  assert(ret == 1);&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;To read packets for a particular stream I use a 'read_packet' function that operates on a stream passed as a parameter:&lt;/p&gt;&lt;pre&gt;bool OggDecoder::read_packet(istream&amp;amp; is, &lt;br /&gt;                             ogg_sync_state* state, &lt;br /&gt;                             OggStream* stream, &lt;br /&gt;                             ogg_packet* packet) {&lt;br /&gt;  int ret = 0;&lt;br /&gt;&lt;br /&gt;  while ((ret = ogg_stream_packetout(&amp;amp;stream-&gt;mState, packet)) != 1) {&lt;br /&gt;    ogg_page page;&lt;br /&gt;    if (!read_page(is, state, &amp;amp;page))&lt;br /&gt;      return false;&lt;br /&gt;&lt;br /&gt;    int serial = ogg_page_serialno(&amp;amp;page);&lt;br /&gt;    assert(mStreams.find(serial) != mStreams.end());&lt;br /&gt;    OggStream* pageStream = mStreams[serial];&lt;br /&gt;    &lt;br /&gt;    // Drop data for streams we're not interested in.&lt;br /&gt;    if (stream-&gt;mActive) {&lt;br /&gt;      ret = ogg_stream_pagein(&amp;amp;pageStream-&gt;mState, &amp;amp;page);&lt;br /&gt;      assert(ret == 0);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  return true;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;If we need to read a new page (to be able to get more packets) we check the stream for the read page and if it is not for the stream we want we store the packet in the bitstream for that page so it can be retrieved later. I've added an 'active' flag to the streams so we can ignore streams that we aren't intersted in. We don't want to continuously buffer data for alternative audio tracks we aren't playing for example. The streams are marked inactive when the headers are finished reading.&lt;/p&gt;&lt;p&gt;The code that does the checking to see if it's time to display a frame is:&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;// At this point we've written some audio data to the sound&lt;br /&gt;// system. Now we check to see if it's time to display a video&lt;br /&gt;// frame.&lt;br /&gt;//&lt;br /&gt;// The granule position of a video frame represents the time&lt;br /&gt;// that that frame should be displayed up to. So we get the&lt;br /&gt;// current time, compare it to the last granule position read.&lt;br /&gt;// If the time is greater than that it's time to display a new&lt;br /&gt;// video frame.&lt;br /&gt;//&lt;br /&gt;// The time is obtained from the audio system - this represents&lt;br /&gt;// the time of the audio data that the user is currently&lt;br /&gt;// listening to. In this way the video frame should be synced up&lt;br /&gt;// to the audio the user is hearing.&lt;br /&gt;//&lt;br /&gt;ogg_int64_t position = 0;&lt;br /&gt;int ret = sa_stream_get_position(mAudio, SA_POSITION_WRITE_SOFTWARE, &amp;amp;position);&lt;br /&gt;assert(ret == SA_SUCCESS);&lt;br /&gt;float audio_time = &lt;br /&gt;  float(position) /&lt;br /&gt;  float(audio-&gt;mVorbis.mInfo.rate) /&lt;br /&gt;  float(audio-&gt;mVorbis.mInfo.channels) /&lt;br /&gt;  sizeof(short);&lt;br /&gt;&lt;br /&gt;float video_time = th_granule_time(video-&gt;mTheora.mCtx, mGranulepos);&lt;br /&gt;if (audio_time &gt; video_time) {&lt;br /&gt;  // Decode one frame and display it. If no frame is available we&lt;br /&gt;  // don't do anything.&lt;br /&gt;  ogg_packet packet;&lt;br /&gt;  if (read_packet(is, &amp;amp;state, video, &amp;amp;packet)) {&lt;br /&gt;    handle_theora_data(video, &amp;amp;packet); &lt;br /&gt;    video_time = th_granule_time(video-&gt;mTheora.mCtx, mGranulepos);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The code for decoding and display the Theora video is similar to the &lt;a href="http://www.bluishcoder.co.nz/2009/06/decoding-theora-files-using-libtheora.html"&gt;Theora decoding article&lt;/a&gt;. The main difference is we store the granulepos in mGranulepos so we know when to stop displaying the frame.&lt;/p&gt;&lt;p&gt;This version of 'plogg' should play Ogg files with a Theora and Vorbis track in sync. You can test it on &lt;a href="http://www.double.co.nz/video_test/transformers320.ogg"&gt;the transformers trailer&lt;/a&gt; for example. It does not play Theora files with no audio track - we can't synchronise to the audio clock if there is no audio. This can be worked around by falling back to delaying for the required framerate as the previous Theora example did.&lt;/p&gt;&lt;p&gt;The a/v sync is not perfect however. If the video is large and decoding keyframes takes a while then we can fall behind in displaying the video and go out of sync. This is because we only play one frame when we check the time. One approach to fixing this is to decode, but not display, all frames up until the audio time rather than just the next time.&lt;/p&gt;&lt;p&gt;The other issue is that the API call we are using to write to the audio hardware is blocking. This is using up valuable time that we could be using to decode a frame. When the write to the sound hardware returns we have very little time to decode a frame before glitches start appearing in the audio due to buffer underruns. Try playing a larger video (like &lt;a href="http://tinyvid.tv/file/ah2ebubqurvy.ogg"&gt;the Ghostbusters HD Trailer&lt;/a&gt; and the audio and video will skip (depending on the speed of your hardware). This isn't a pleasant experience. Because of the blocking audio writes we can't skip more than one frame due to the frame decoding time taking too long causing audio skip.&lt;/p&gt;&lt;p&gt;The fixes for these aren't too complex and I'll go through it in my next article. The basic approach is to move to an asynchronous method of writing the audio, skip displaying frames when needed (to reduce the cost of the YUV decoding), skip decoding frames if possible (depending on location of keyframes we can do this), and to check how much audio data we have queued before decoding to always ensure we won't drop audio while decoding.&lt;/p&gt;&lt;p&gt;With these fixes in place I can play the 1080p Ogg version of &lt;a href="http://www.bigbuckbunny.org/index.php/download/"&gt;Big Buck Bunny&lt;/a&gt; on a Macbook laptop (running Arch Linux) with no audio interruption  and with a/v syncing correctly. There is a fair amount of frame skipping however but it's a lot more watchable than if you try playing it without these modifications in place. And better than watching with the video lagging further and further behind the longer you watch it. Further improvements can be made to reduce the frame skipping by utilising threads to take advantage of extra core's on the PC.&lt;/p&gt;&lt;p&gt;After the followup article on improving the a/v sync I'll look at covering seeking.&lt;/p&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/ogg" rel="tag"&gt;ogg&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/theora" rel="tag"&gt;theora&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/vorbis" rel="tag"&gt;vorbis&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-6897339688065370851?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/06/playing-ogg-files-with-audio-and-video.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-7137821059910630367</guid><pubDate>Thu, 25 Jun 2009 03:52:00 +0000</pubDate><atom:updated>2009-06-25T20:33:07.566+12:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Decoding Vorbis files with libvorbis</title><description>&lt;p&gt;Decoding Vorbis streams require a very similar approach to that used when &lt;a href="http://www.bluishcoder.co.nz/2009/06/decoding-theora-files-using-libtheora.html"&gt;decoding Theora streams&lt;/a&gt;. The public interface to the libvorbis library is very similar to that used by libtheora. Unfortunately the &lt;a href="http://www.xiph.org/vorbis/doc/"&gt;libvorbis documentation&lt;/a&gt; doesn't contain an API reference that I could find so I'm following the approached used by the example programs.&lt;/p&gt;&lt;p&gt;Assuming we have already obtained an &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_packet.html"&gt;ogg_packet&lt;/a&gt;, the general steps to follow to decode and play Vorbis streams are:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Call vorbis_synthesis_headerin to see if the packet is a Vorbis header packet. This is passed a vorbis_info and vorbis_comment object to hold the information read from those header packets. The return value of this function is zero if the packet is a Vorbis header packet. Unfortunately it doesn't return a value to see that it's a Vorbis data packet. To check for this you need to check if the stream is a Vorbis stream (by knowing you've previously read Vorbis headers from it) and the return value is OV_ENOTVORBIS.&lt;/li&gt;&lt;li&gt;Once all the header packets are read create a vorbis_dsp_state and vorbis_block object. Initialize these with vorbis_synthesis_init and vorbis_block_init respectively. These objects hold the state of the Vorbis decoding. vorbis_synthesis_init is passed the vorbis_info object that was filled in during the reading of the header packets.&lt;/li&gt;&lt;li&gt;For each data packet:&lt;ol&gt;&lt;li&gt;Call vorbis_synthesis passing it the vorbis_block created above and the ogg_packet containing the packet data. If this succeeds (by returning zero), call vorbis_synthesis_blockin passing it the vorbis_dsp_state and vorbis_block objects. This call copies the data from the packet into the Vorbis objects ready for decoding.&lt;/li&gt;&lt;li&gt;Call vorbis_synthesis_pcmout to get an pointer to an array of floating point values for the sound samples. This will return the number of samples in the array. The array is indexed by channel number, followed by sample number. Once obtained this sound data can be sent to the sound hardware to play the audio.&lt;/li&gt;&lt;li&gt;Call vorbis_synthesis_read, passing it the vorbis_dsp_state object and the number of sound samples consumed. This allows you to consume less data than vorbis_synthesis_pcmout returned. This is useful if you can't write all the data to the sound hardware without blocking.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;In the example code in the &lt;a href="http://github.com/doublec/plogg/tree/master"&gt;github repository&lt;/a&gt; I create a VorbisDecode object that holds the objects needed for decoding. This is similar to the TheoraDecode object mentioned in my &lt;a href="http://www.bluishcoder.co.nz/2009/06/decoding-theora-files-using-libtheora.html"&gt;Theora post&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;class VorbisDecode {&lt;br /&gt;  ...&lt;br /&gt;  vorbis_info mInfo;&lt;br /&gt;  vorbis_comment mComment;&lt;br /&gt;  vorbis_dsp_state mDsp;&lt;br /&gt;  vorbis_block mBlock;&lt;br /&gt;  ...&lt;br /&gt;&lt;br /&gt;  VorbisDecode()&lt;br /&gt;  {&lt;br /&gt;    vorbis_info_init(&amp;amp;mInfo);&lt;br /&gt;    vorbis_comment_init(&amp;amp;mComment);    &lt;br /&gt;  }&lt;br /&gt;};&lt;/pre&gt;    &lt;p&gt;I added a TYPE_VORBIS value to the StreamType enum and the stream is set to this type when a Vorbis header is successfully decoded:&lt;/p&gt;&lt;pre&gt;  int ret = vorbis_synthesis_headerin(&amp;amp;stream-&gt;mVorbis.mInfo,&lt;br /&gt;                      &amp;amp;stream-&gt;mVorbis.mComment,&lt;br /&gt;                      packet);&lt;br /&gt;  if (stream-&gt;mType == TYPE_VORBIS &amp;amp;&amp;amp; ret == OV_ENOTVORBIS) {&lt;br /&gt;    // First data packet&lt;br /&gt;    ret = vorbis_synthesis_init(&amp;amp;stream-&gt;mVorbis.mDsp, &amp;amp;stream-&gt;mVorbis.mInfo);&lt;br /&gt;    assert(ret == 0);&lt;br /&gt;    ret = vorbis_block_init(&amp;amp;stream-&gt;mVorbis.mDsp, &amp;amp;stream-&gt;mVorbis.mBlock);&lt;br /&gt;    assert(ret == 0);&lt;br /&gt;    stream-&gt;mHeadersRead = true;&lt;br /&gt;    handle_vorbis_data(stream, packet);&lt;br /&gt;  }&lt;br /&gt;  else if (ret == 0) {&lt;br /&gt;    stream-&gt;mType = TYPE_VORBIS;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The example program uses libsydneyaudio for audio output. This requires sound samples to be written as signed short values. When I get the floating point data from Vorbis I convert this to signed short and send it to libsydneyaudio:&lt;/p&gt;&lt;pre&gt;  int ret = 0;&lt;br /&gt;    &lt;br /&gt;  if (vorbis_synthesis(&amp;amp;stream-&gt;mVorbis.mBlock, packet) == 0) {&lt;br /&gt;    ret = vorbis_synthesis_blockin(&amp;amp;stream-&gt;mVorbis.mDsp, &amp;amp;stream-&gt;mVorbis.mBlock);&lt;br /&gt;    assert(ret == 0);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  float** pcm = 0;&lt;br /&gt;  int samples = 0;&lt;br /&gt;  while ((samples = vorbis_synthesis_pcmout(&amp;amp;stream-&gt;mVorbis.mDsp, &amp;amp;pcm)) &gt; 0) {&lt;br /&gt;    if (!mAudio) {&lt;br /&gt;      ret = sa_stream_create_pcm(&amp;amp;mAudio,&lt;br /&gt;                 NULL,&lt;br /&gt;                 SA_MODE_WRONLY,&lt;br /&gt;                 SA_PCM_FORMAT_S16_NE,&lt;br /&gt;                 stream-&gt;mVorbis.mInfo.rate,&lt;br /&gt;                 stream-&gt;mVorbis.mInfo.channels);&lt;br /&gt;      assert(ret == SA_SUCCESS);&lt;br /&gt;&lt;br /&gt;      ret = sa_stream_open(mAudio);&lt;br /&gt;      assert(ret == SA_SUCCESS);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (mAudio) {&lt;br /&gt;      short buffer[samples * stream-&gt;mVorbis.mInfo.channels];&lt;br /&gt;      short* p = buffer;&lt;br /&gt;      for (int i=0;i &amp;lt; samples; ++i) {&lt;br /&gt;    for(int j=0; j &amp;lt; stream-&gt;mVorbis.mInfo.channels; ++j) {&lt;br /&gt;      int v = static_cast&amp;lt;int&amp;lt;(floorf(0.5 + pcm[j][i]*32767.0));&lt;br /&gt;      if (v &gt; 32767) v = 32767;&lt;br /&gt;      if (v &amp;lt;-32768) v = -32768;&lt;br /&gt;      *p++ = v;&lt;br /&gt;    }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      ret = sa_stream_write(mAudio, buffer, sizeof(buffer));&lt;br /&gt;      assert(ret == SA_SUCCESS);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    ret = vorbis_synthesis_read(&amp;amp;stream-&gt;mVorbis.mDsp, samples);&lt;br /&gt;    assert(ret == 0);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;A couple of minor changes were also made to the example program:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Continue processing pages and packets when the 'end of file' is reached. Otherwise a few packets that are buffered after we've reached the end of the file will be missed.&lt;/li&gt;&lt;li&gt;After reading a page don't just try to read one packet, call &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_stream_packetout.html"&gt;ogg_stream_packetout&lt;/a&gt; until it returns a result saying there are no more packets. This means we process all the packets from the page immediately and prevents a build up of buffered data.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The code for this example is in the 'part3_vorbis' branch of the github repository. This also includes the Theora code but does not do any a/v synchronisation.  Files containing Theora streams will show the video data but it will not play smoothly and will not be synchronised with the audio. Fixing that is the topic of the next post in this series.&lt;/p&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/ogg" rel="tag"&gt;ogg&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/theora" rel="tag"&gt;theora&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/vorbis" rel="tag"&gt;vorbis&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-7137821059910630367?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/06/decoding-vorbis-files-with-libvorbis.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-793270184265149370</guid><pubDate>Wed, 24 Jun 2009 13:14:00 +0000</pubDate><atom:updated>2009-06-26T14:08:59.935+12:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Decoding Theora files using libtheora</title><description>&lt;p&gt;My last post covered &lt;a href="http://www.bluishcoder.co.nz/2009/06/reading-ogg-files-using-libogg.html"&gt;read Ogg files using libogg&lt;/a&gt;. The resulting program didn't do much but it covered the basic steps needed to get an &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_packet.html"&gt;ogg_packet&lt;/a&gt; which we need to decode the data in the stream. The thing step I want to cover is decoding Theora streams using &lt;a href="http://theora.org/doc/libtheora-1.0/"&gt;libtheora&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In the previous post I stored a count of the number of packets in the OggStream object. For theora decoding we need a number of different objects to be stored. I encapsulate this in a TheoraDecode structure:&lt;/p&gt;&lt;pre&gt;class TheoraDecode { &lt;br /&gt;  ...&lt;br /&gt;  th_info mInfo;&lt;br /&gt;  th_comment mComment;&lt;br /&gt;  th_setup_info *mSetup;&lt;br /&gt;  th_dec_ctx* mCtx;&lt;br /&gt;  ...&lt;br /&gt;};&lt;/pre&gt;&lt;p&gt;&lt;a href="http://theora.org/doc/libtheora-1.0/structth__info.html"&gt;th_info&lt;/a&gt;, &lt;a href="http://theora.org/doc/libtheora-1.0/structth__comment.html"&gt;th_comment&lt;/a&gt; and &lt;a href="http://theora.org/doc/libtheora-1.0/theoradec_8h.html#b71cd2657455cc27d6c0127c66a89f28"&gt;th_setup_info&lt;/a&gt; contain data read from the Theora headers. The Theora stream contains three headers packets. These are the info, comment and setup headers. There is one object for holding each of these as we read the headers. The &lt;a href="http://theora.org/doc/libtheora-1.0/theoradec_8h.html#843d70bb02563885a8d54b9c1a781729"&gt;th_dec_ctx&lt;/a&gt; object holds information that the decoder requires to keep track of the decoding process.&lt;/p&gt;&lt;p&gt;th_info and th_comment need to be initialized using &lt;a href="http://theora.org/doc/libtheora-1.0/group__basefuncs.html#g430d9c605816a6ca0bdce3a0b965b926"&gt;th_info_init&lt;/a&gt; and &lt;a href="http://theora.org/doc/libtheora-1.0/group__basefuncs.html#g6c8ab25988e7ea9d7b1e31a54cf58f09"&gt;th_comment_init&lt;/a&gt;. Notice that th_setup_info is a pointer. This needs to be free'd when we're finished with it using &lt;a href="http://theora.org/doc/libtheora-1.0/group__decfuncs.html#gdef55431b68aaa59d0d7b32b2f118f27"&gt;th_setup_free&lt;/a&gt;. The decoder context object also needs to be free'd. Use &lt;a href="http://theora.org/doc/libtheora-1.0/group__decfuncs.html#gfb6684ad8ba507b71112bc9de148e7d0"&gt;th_decode_free&lt;/a&gt;. A convenient place to do this is in the TheoraDecode constructor and destructor:&lt;/p&gt;&lt;pre&gt;class TheoraDecode {&lt;br /&gt;  ...&lt;br /&gt;  TheoraDecode() :&lt;br /&gt;    mSetup(0),&lt;br /&gt;    mCtx(0)&lt;br /&gt;  {&lt;br /&gt;    th_info_init(&amp;amp;mInfo);&lt;br /&gt;    th_comment_init(&amp;amp;mComment);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  ~TheoraDecode() {&lt;br /&gt;    th_setup_free(mSetup);&lt;br /&gt;    th_decode_free(mCtx);&lt;br /&gt;  }   &lt;br /&gt;  ...&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The TheoraDecode object is stored in the OggStream structure. The OggStream stucture also gets a field holding the type of the stream (Theora, Vorbis, Unknown, etc) and a boolean indicating whether the headers have been read:&lt;/p&gt;&lt;pre&gt;class OggStream&lt;br /&gt;{&lt;br /&gt;  ...&lt;br /&gt;  int mSerial;&lt;br /&gt;  ogg_stream_state mState;&lt;br /&gt;  StreamType mType;&lt;br /&gt;  bool mHeadersRead;&lt;br /&gt;  TheoraDecode mTheora;&lt;br /&gt;  ...&lt;br /&gt;};&lt;/pre&gt;&lt;p&gt;Once we get the ogg_packet from an Ogg stream we need to find out if it is a Theora stream. The approach I'm using to do this is to attempt to extract a Theora header from it. If this succeeds, it's a Theora stream. &lt;a href="http://theora.org/doc/libtheora-1.0/group__decfuncs.html#g006d01d36fbe64768c571e6a12b7fc50"&gt;th_decode_headerin&lt;/a&gt; will attempt to decode a header packet. A return value of '0' indicates that we got a Theora data packet (presumably the headers have been read already). This function gets passed the info, comment, and setup objects and it will populate them with data as it reads the headers:&lt;/p&gt;&lt;pre&gt;ogg_packet* packet = ...got this previously...;&lt;br /&gt;int ret = th_decode_headerin(&amp;amp;stream-&gt;mTheora.mInfo,&lt;br /&gt;                             &amp;amp;stream-&gt;mTheora.mComment,&lt;br /&gt;                             &amp;amp;stream-&gt;mTheora.mSetup,&lt;br /&gt;                             packet);&lt;br /&gt;if (ret == TH_ENOTFORMAT)&lt;br /&gt;  return; // Not a theora header&lt;br /&gt;&lt;br /&gt;if (ret &gt; 0) {&lt;br /&gt;  // This is a theora header packet&lt;br /&gt;  stream-&gt;mType = TYPE_THEORA;&lt;br /&gt;  return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;assert(ret == 0);&lt;br /&gt;// This is not a header packet. It is the first &lt;br /&gt;// video data packet.&lt;br /&gt;stream-&gt;mTheora.mCtx = &lt;br /&gt;  th_decode_alloc(&amp;amp;stream-&gt;mTheora.mInfo, &lt;br /&gt;                  stream-&gt;mTheora.mSetup);&lt;br /&gt;assert(stream-&gt;mTheora.mCtx != NULL);&lt;br /&gt;stream-&gt;mHeadersRead = true;&lt;br /&gt;...decode data packet...&lt;/pre&gt;&lt;p&gt;In this example code we attempt to decode the header. If it fails it bails out, possibly to try decoding the packet using libvorbis or some other means. If it succeeds the stream is marked as type TYPE_THEORA so we can handle it specially later.&lt;/p&gt;&lt;p&gt;If all headers packets are read and we got the first data packet then we call &lt;a href="http://theora.org/doc/libtheora-1.0/group__decfuncs.html#g0ef07a9a97849054aa606c595a2d807e"&gt;th_decode_alloc&lt;/a&gt; to get a decode context to decode the data.&lt;/p&gt;&lt;p&gt;Once the headers are all read, the next step is to decode each Theora data packet. To do this we first call &lt;a href="http://theora.org/doc/libtheora-1.0/group__decfuncs.html#g31c814bf09b2232aff69c57ae20f04eb"&gt;th_decode_packetin&lt;/a&gt;. This adds the packet to the decoder. A return value of '0' means we can get a decoded frame as a result of adding the packet. A call to &lt;a href="http://theora.org/doc/libtheora-1.0/group__decfuncs.html#ga9cc8af63fa8540e0fc95572f259cdcb"&gt;th_decode_ycbcr_out&lt;/a&gt; gets the decoded YUV data, stored in a &lt;a href="http://theora.org/doc/libtheora-1.0/codec_8h.html#343f7cfabad179cc4fe527cf06873f45"&gt;th_ycbcr_buffer&lt;/a&gt; object. This is basically an array of the YUV data.&lt;/p&gt;&lt;pre&gt;ogg_int64_t granulepos = -1;&lt;br /&gt;int ret = th_decode_packetin(stream-&gt;mTheora.mCtx,&lt;br /&gt;                             packet,&lt;br /&gt;                             &amp;amp;granulepos);&lt;br /&gt;assert(ret == 0);&lt;br /&gt;&lt;br /&gt;th_ycbcr_buffer buffer;&lt;br /&gt;ret = th_decode_ycbcr_out(stream-&gt;mTheora.mCtx, buffer);&lt;br /&gt;assert(ret == 0);&lt;br /&gt;...copy yuv data to SDL YUV overlay...&lt;br /&gt;...display overlay...&lt;br /&gt;...sleep for 1 frame...&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The 'granulepos' returned by the th_decode_packetin call holds information regarding the presentation time of this frame, and what frame contains the keyframe that is needed for this frame if it is not a keyframe. I'll write more about this in a future post when I cover synchronising the audio and video. For now it's going to be ignored.&lt;/p&gt;&lt;p&gt;Once we have the YUV data I use SDL to create a surface, and a YUV overlay. This allows SDL to do the YUV to RGB conversion for me. I won't copy the code for this since it's not particularly relevant to using the libtheora API - you can see it in the &lt;a href="http://github.com/doublec/plogg/"&gt;github repository&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Once the YUV data is blit to the screen the final step is to sleep for the period of one frame so the video can playback at approximately the right framerate. The framerate of the video is stored in the th_info object that we got from the headers. It is represented as the fraction of two numbers:&lt;/p&gt;&lt;pre&gt;float framerate = &lt;br /&gt;  float(stream-&gt;mTheora.mInfo.fps_numerator) / &lt;br /&gt;  float(stream-&gt;mTheora.mInfo.fps_denominator);&lt;br /&gt;SDL_Delay((1.0/framerate)*1000);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;With all that in place, running the program with an Ogg file containing a Theora stream should play the video at the right framerate. Adding Vorbis playback is almost as easy - the main difficulty is synchronising the audio and video. I'll cover these topics in a later post.&lt;/p&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/theora" rel="tag"&gt;theora&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/ogg" rel="tag"&gt;ogg&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-793270184265149370?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/06/decoding-theora-files-using-libtheora.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>11</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-3906412136752836119</guid><pubDate>Wed, 24 Jun 2009 11:37:00 +0000</pubDate><atom:updated>2009-06-24T23:49:44.180+12:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Reading Ogg files using libogg</title><description>&lt;p&gt;Reading data from an Ogg file is relatively simple. The file format is well documented in &lt;a href="http://www.ietf.org/rfc/rfc3533.txt"&gt;RFC 3533&lt;/a&gt;. I showed how to read the format using JavaScript &lt;a href="http://www.bluishcoder.co.nz/2009/06/reading-ogg-files-with-javascript.html"&gt;in a previous post&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;For C and C++ programs it's easier to use the &lt;a href="http://xiph.org"&gt;xiph.org&lt;/a&gt; libraries. There are libraries for decoding specific formats (libvorbis, libtheora) and there is a library for reading data from Ogg files (libogg).&lt;/p&gt;&lt;p&gt;I'm prototyping some approaches to improve the performance of the Firefox Ogg video playback and while I'm at it I'll write some posts on using these libraries to decode/play Ogg files. Hopefully it'll prove useful to others using them and I can get some feedback on usage.&lt;/p&gt;&lt;p&gt;All the code for this is in the &lt;a href="http://github.com/doublec/plogg/tree"&gt;plogg&lt;/a&gt; git repository on github. The 'master' branch contains the work in progress player that I'll describe in a series of posts, and there are branches specific to the examples in each post.&lt;/p&gt;&lt;p&gt;The &lt;a href="http://www.xiph.org/ogg/doc/libogg/"&gt;libogg documentation&lt;/a&gt; describes the API that I'll be using in this post. All that this example will do is read an Ogg file, read each stream in the file and count the number of packets for that stream. It prints the number of packets. It doesn't decode the data or do anything really useful. That'll come later.&lt;/p&gt;&lt;p&gt;You can think of an Ogg file as containing logical streams of data. Each stream has a serial number that is unique within the file to identify it. A file containing Vorbis and Theora data will have two streams. A Vorbis stream and a Theora stream.&lt;/p&gt;&lt;p&gt;Each stream is split up into packets. The packets contain the raw data for the stream. The process of decoding a stream involves getting a packet from it, decoding that data, doing something with it, and repeating.&lt;/p&gt;&lt;p&gt;That describes the logical format. The physical format of the Ogg file is split into pages of data. Each physical page contains some part of the data for one stream. &lt;/p&gt;&lt;p&gt;The process of reading and decoding an Ogg file is to read pages from the file, associating them with the streams they belong to. At some point we then go through the pages held in the stream and obtain the packets from it. This is the process the code in this example follows.&lt;/p&gt;&lt;p&gt;The first thing we need to do when reading an Ogg file is find the first page of data. We use a &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_sync_state.html"&gt;ogg_sync_state&lt;/a&gt; structure to keep track of search for the page data. This needs to be initialized with &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_sync_init.html"&gt;ogg_sync_init&lt;/a&gt; and later cleaned up with &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_sync_clear.html"&gt;ogg_sync_clear&lt;/a&gt;:&lt;pre&gt;ifstream file("foo.ogg", ios::in | ios::binary);&lt;br /&gt;ogg_sync_state state;&lt;br /&gt;int ret = ogg_sync_init(&amp;state);&lt;br /&gt;assert(ret==0);&lt;br /&gt;...look for page...&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Note that the libogg functions return an error code which should be checked, A result of '0' generally indicates success. We want to obtain a complete page of Ogg data. This is held in an &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_page.html"&gt;ogg_page&lt;/a&gt; structure. The process of obtaining this structure is to do the following steps:&lt;ol&gt;&lt;li&gt;Call &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_sync_pageout.html"&gt;ogg_sync_pageout&lt;/a&gt;. This will take any data current stored in the ogg_sync_state object and store it in the ogg_page. It will return a result indicating when the entire pages data has been read and the ogg_page can be used. It needs to be called first to initialize buffers. It gets called repeatedly as we read data from the file.&lt;/li&gt;&lt;li&gt;Call &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_sync_buffer.html"&gt;ogg_sync_buffer&lt;/a&gt; to obtain an area of memory we can reading data from the file into. We pass the size of the buffer. This buffer is reused on each call and will be resized if needed if a larger buffer size is asked for later.&lt;/li&gt;&lt;li&gt;Read data from the file into the buffer obtained above.&lt;/li&gt;&lt;li&gt;Call &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_sync_wrote.html"&gt;ogg_sync_wrote&lt;/a&gt; to tell libogg how much data we copied into the buffer.&lt;/li&gt;&lt;li&gt;Resume from the first step, calling ogg_sync_buffer. This will copy the data from the buffer into the page, and return '1' if a full page of data is available.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Here's the code to do this:&lt;/p&gt;&lt;pre&gt;ogg_page page;&lt;br /&gt;while(ogg_sync_pageout(&amp;amp;state, &amp;amp;page) != 1) {&lt;br /&gt;  char* buffer = ogg_sync_buffer(oy, 4096);&lt;br /&gt;  assert(buffer);&lt;br /&gt;&lt;br /&gt;  file.read(buffer, 4096);&lt;br /&gt;  int bytes = stream.gcount();&lt;br /&gt;  if (bytes == 0) {&lt;br /&gt;    // End of file&lt;br /&gt;    break;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  int ret = ogg_sync_wrote(&amp;state, bytes);&lt;br /&gt;  assert(ret == 0);&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;We need to keep track of the logical streams within the file. These are identified by serial number and this number is obtained from the page. I create a C++ map to associate the serial number with an OggStream object which holds information I want associated with the stream. In later examples this will hold data needed for the Theora and Vorbis decoding process.&lt;/p&gt;&lt;pre&gt;class OggStream&lt;br /&gt;{&lt;br /&gt;  ...&lt;br /&gt;  int mSerial;&lt;br /&gt;  ogg_stream_state mState;&lt;br /&gt;  int mPacketCount;&lt;br /&gt;  ...&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;typedef map&lt;int, OggStream*&gt; StreamMap; &lt;/pre&gt;&lt;p&gt;Each stream has an &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_stream_state.html"&gt;ogg_stream_state&lt;/a&gt; object that is used to keep track of the data read that belongs to the stream. We're storing this in the OggStream object that we associated with the stream serial number. Once we've read a page as described above we need to tell libogg to add this page of data to the stream.&lt;/p&gt;&lt;pre&gt;StreamMap streams;&lt;br /&gt;ogg_page page = ...obtained previously...;&lt;br /&gt;int serial = ogg_page_serialno(&amp;page);&lt;br /&gt;OggStream* stream = 0;&lt;br /&gt;if (ogg_page_bos(&amp;page) {&lt;br /&gt;  stream = new OggStream(serial);&lt;br /&gt;  int ret = ogg_stream_init(&amp;stream-&gt;mState, serial);&lt;br /&gt;  assert(ret == 0);&lt;br /&gt;  streams[serial] = stream;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;  stream = streams[serial];&lt;br /&gt;&lt;br /&gt;int ret = ogg_stream_pagein(&amp;stream-&gt;mState, &amp;page);&lt;br /&gt;assert(ret == 0);&lt;/pre&gt;&lt;p&gt;This code uses &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_page_serialno.html"&gt;ogg_page_serialno&lt;/a&gt;to get the serial number of the page we just read. If it is the beginning of the stream (&lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_page_bos.html"&gt;ogg_page_bos&lt;/a&gt;) then we create a new OggStream object, initialize the stream's state with &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_stream_init.html"&gt;ogg_stream_init&lt;/a&gt;, and store it in out streams map. If it's not the beginning of the stream we just get our existing entry in the map. The final call to &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_stream_pagein.html"&gt;ogg_stream_pagein&lt;/a&gt; inserts the page of data into the streams state object. Once this is done we can start looking for completed packets of data and decode them.&lt;/p&gt;&lt;p&gt;To decode the data from a stream we need to retrieve a packet from it. The steps for doing this are:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Call &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_stream_packetout.html"&gt;ogg_stream_packetout&lt;/a&gt;. This will return a value indicating if a packet of data is available in the stream. If it is not then we need to read another page (following the same steps previously) and add it to the stream, calling ogg_stream_packetout again until it tells us a packet is available. The packet's data is stored in an &lt;a href="http://www.xiph.org/ogg/doc/libogg/ogg_packet.html"&gt;ogg_packet&lt;/a&gt; object.&lt;/li&gt;&lt;li&gt;Do something with the packet data. This usually involves calling libvorbis or libtheora routines to decode the data. In this example we're just counting the packets.&lt;/li&gt;&lt;li&gt;Repeat until all packets in all streams are consumed.&lt;/li&gt;&lt;/ol&gt;&lt;pre&gt;while (..read a page...) {&lt;br /&gt;  ...put page in stream...  &lt;br /&gt;  ogg_packet packet;&lt;br /&gt;  int ret = ogg_stream_packetout(&amp;stream-&gt;mState, &amp;packet);    &lt;br /&gt;  if (ret == 0) {&lt;br /&gt;    // Need more data to be able to complete the packet&lt;br /&gt;    continue;&lt;br /&gt;  }&lt;br /&gt;  else if (ret == -1) {&lt;br /&gt;    // We are out of sync and there is a gap in the data.&lt;br /&gt;    // We lost a page somewhere.&lt;br /&gt;    break;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // A packet is available, this is what we pass to the vorbis or&lt;br /&gt;  // theora libraries to decode.&lt;br /&gt;  stream-&gt;mPacketCount++;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;That's all there is to reading an Ogg file. There are more libogg functions to get data out of the stream, identify end of stream, and various other useful functions but this covers the basics. Try out the example program in the github repository for more information.&lt;/p&gt;&lt;p&gt;Note that the libogg functions don't require reading from a file. You can use these routines with any data you've obtained. From a socket, from memory, etc.&lt;/p&gt;&lt;p&gt;In the next post about reading Ogg files I'll go through using libtheora to decode the video data and display it.&lt;/p&gt; &lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/theora" rel="tag"&gt;theora&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/ogg" rel="tag"&gt;ogg&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-3906412136752836119?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/06/reading-ogg-files-using-libogg.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-4911395605634628980</guid><pubDate>Fri, 05 Jun 2009 00:51:00 +0000</pubDate><atom:updated>2009-06-05T15:09:25.891+12:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Reading Ogg files with JavaScript</title><description>On &lt;a href="http://tinyvid.tv"&gt;tinyvid.tv&lt;/a&gt; I do quite a bit of server side reading of Ogg files to get things like duration and bitrate information when serving information about the media. I wondered if it would be possible to do this sort of thing using JavaScript running in the browser.&lt;br /&gt;&lt;br /&gt;The format of the Ogg container is defined in &lt;a href="http://www.ietf.org/rfc/rfc3533.txt"&gt;RFC 3533&lt;/a&gt;. The difficulty comes in reading binary data from JavaScript. The &lt;a href="https://developer.mozilla.org/en/XMLHttpRequest"&gt;XMLHttpRequest&lt;/a&gt; object can be used to retrieve data via a URL from JavaScript in a page but processing the binary data in the Ogg file is problematic. The response returned by XMLHttpRequest assumes text or XML (in Firefox at least).&lt;br /&gt;&lt;br /&gt;One way of handling binary data is described in &lt;a href="https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data"&gt;this Mozilla Developer article&lt;/a&gt;. Trying this method out works in Firefox and I can download and read the data in the Ogg file.&lt;br /&gt;&lt;br /&gt;Ideally I don't want to download the entire file. It might be a large video. I thought by handling the 'progress' event or ready state 3 (data received) I'd be able to look at the data currently retrieved. This does work but on each call to the 'responseText' attribute in these events Firefox copies its internal copy of the downloaded data into a JavaScript array. Doing this every time a portion of the file is downloaded results in major memory use and slow downs proving impractical for even small files.&lt;br /&gt;&lt;br /&gt;I think the only reliable way to process the file in chunks is to use byte range requests and do multiple requests. Is there a more reliable way to do binary file reading via JavaScript using XMLHttpRequest? I'd like to be able to process the file in chunks using an &lt;a href="http://okmij.org/ftp/Streams.html#random-bin-IO"&gt;Iteratee&lt;/a&gt; style approach.&lt;br /&gt;&lt;br /&gt;I put up a rough quick demo of loading the first 100Kb of a video and displaying information from each Ogg packet. This probably works in Firefox only due to the workaround needed to read binary data. Click on the 'Go' button in the &lt;a href="http://www.double.co.nz/video_test/oggparse.html"&gt;demo page&lt;/a&gt;. This will load &lt;a href="http://www.double.co.nz/video_test/transformers320.ogg"&gt;transformers320.ogg&lt;/a&gt; and display the contents of the first Ogg physical page.&lt;br /&gt;&lt;br /&gt;I decode the header packets for Theora and Vorbis. So the first page shown will show it is for a Theora stream with a given size and framerate. Clicking 'Next' will move on to the Next page. This is a Vorbis header with the rate and channel information. Clicking 'Next' again gets the comment header for the Theora stream. The demo reads the comments and displays them. The same for the Vorbis comment records. As you 'Next' through the file it displays the meaning of the granulepos for each page. It shows whether the Theora data is for a keyframe, what time position it is, etc.&lt;br /&gt;&lt;br /&gt;Something like this could be used to read metadata from Ogg files, read subtitle information, show duration, etc. More interesting would be to implement a Theora and/or Vorbis decoder in JavaScript and see how it performs.&lt;br /&gt;&lt;br /&gt;The main issues with doing this from JavaScript seem to be:&lt;ul&gt;&lt;li&gt;Handling binary data using XMLHttpRequest in a cross browser manner&lt;/li&gt;&lt;li&gt;Processing the file in chunks so the entire file does not need to be kept in memory&lt;/li&gt;&lt;li&gt;Files need to be hosted on the same domain as the page. &lt;a href="http://tinyvid.tv"&gt;tinyvid.tv&lt;/a&gt; adds the W3C Access Control headers so they can be accessed cross domain but it also hosts some files on Amazon S3 where these headers can't be added. As a result even tinyvid itself can't use XMLHttpRequest to read these files.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/tinyvid" rel="tag"&gt;tinyvid&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/javascript" rel="tag"&gt;javascript&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/theora" rel="tag"&gt;theora&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-4911395605634628980?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/06/reading-ogg-files-with-javascript.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>9</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-1665228612307107866</guid><pubDate>Tue, 02 Jun 2009 00:46:00 +0000</pubDate><atom:updated>2009-06-02T12:55:28.521+12:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Video for Everybody - HTML 5 video fallback</title><description>Kroc Camen has made available &lt;a href="http://camendesign.com/code/video_for_everybody"&gt;Video for Everybody&lt;/a&gt;, an HTML snippet that uses HTML 5 video if it's available in the browser, otherwise falling back to different video playback options.&lt;br /&gt;&lt;br /&gt;What's interesting about 'Video for Everybody' is it doesn't use scripting at all. It uses the fallback mechanism built into HTML. The video playback mechanism used, in order of availability in the browser, is:&lt;ol&gt;&lt;li&gt;HTML 5 &amp;lt;video&amp;gt;&lt;/li&gt;&lt;li&gt;Adobe Flash&lt;/li&gt;&lt;li&gt;Quicktime&lt;/li&gt;&lt;li&gt;Windows Media Player&lt;/li&gt;&lt;li&gt;Text explaining how to get video support if none of the above is available&lt;/li&gt;&lt;/ol&gt;The fallback options work across multiple browsers and even works on the iPhone. The 'Video For Everybody' page also goes through how to encode videos in Ogg and MP4 format.&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/video" rel="tag"&gt;video&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-1665228612307107866?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/06/video-for-everybody-html-5-video.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>13</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-6302339428723436012</guid><pubDate>Sat, 16 May 2009 06:53:00 +0000</pubDate><atom:updated>2009-05-16T19:24:05.755+12:00</atom:updated><title>Third Party Comment Engines</title><description>I've been playing around with different commenting engines on &lt;a href="http://tinyvid.tv"&gt;tinyvid&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Currently I use &lt;a href="http://intensedebate.com/"&gt;Intense Debate&lt;/a&gt;. An example of a video using this comment system is &lt;a href="http://tinyvid.tv/show/yka5q2v7221y"&gt;here&lt;/a&gt;. I like this service a lot. You can sign on with &lt;a href="http://openid.net/"&gt;OpenId&lt;/a&gt;, the moderation tools are good and it seems to be generally reliable.&lt;br /&gt;&lt;br /&gt;Intense Debate has support for plugins that anyone can write. Potentially I could write a video plugin that allowed embedding &amp;lt;video&gt; into comments for example.&lt;br /&gt;&lt;br /&gt;But it does have some issues. Sometimes comments don't seem to appear in the right order. I'll get an email that a comment was left, visit the page, and it's nowhere. Somehow it gets buried amongst other older comments. This started happening when I switched the ordering of the comments to have the most recent comment at the top.&lt;br /&gt;&lt;br /&gt;Sometimes, depending on the content of your comment, the engine gets confused and the comment is scrambled. This seems to happen if I edit a comment that has a URL in it. It converts the URL to an HTML &amp;lt;a href/&gt; and when editing and saving seems to reconvert, or do some weirdness with it. I've lost comments through this. Long comments can get silently truncated or trashed.&lt;br /&gt;&lt;br /&gt;I set up tinyvid so I can easily add different comment engines and switch them on and off for individual videos for testing. I recently tried &lt;a href="http://js-kit.com/"&gt;js-kit&lt;/a&gt;. An example of video with js-kit comments for testing is &lt;a href="http://tinyvid.tv/show/1odneot3p3d2a"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I like js-kit too. I'm using their 'rating' widget and that seems to work nicely. The comments are ok too. You can sign in with OpenId. But there is some weirdness there. If I sign in using OpenId, leave a comment, then revisit the page later, then the comments don't appear. I have to delete the js-kit cookie to have them appear again.&lt;br /&gt;&lt;br /&gt;There is a limit to the size of the comments, similar in size to Intense Debate's, of 3,000 characters. I suspect this limit isn't a problem in practice however.&lt;br /&gt;&lt;br /&gt;There's a lot to like about js-kit, apart from the OpenId issue, but I need to try it out a bit more to see what other issues it has.&lt;br /&gt;&lt;br /&gt;The last one I tried was &lt;a href="http://disqus.com/home/"&gt;Disqus&lt;/a&gt;. Example &lt;a href="http://tinyvid.tv/show/2pmbfowazuyds"&gt;here&lt;/a&gt;. The Disqus site lets you register using OpenId. However you can't login to leave a comment using OpenId. You must login using a Disqus Id that gets assigned to you when you've registered.&lt;br /&gt;&lt;br /&gt;When I registered using OpenId, then tried to login to leave a comment it requested a password. I had to go back to the Disqus site, change my profile to add a password. This seems sub-optimal since the point of me using OpenId is to avoid multiple passwords and accounts.&lt;br /&gt;&lt;br /&gt;Disqus requires anonymous posters to leave a valid email address. I couldn't find a way to turn this option off. I'm sure this will just result in people leaving bogus email addresses.&lt;br /&gt;&lt;br /&gt;One step of the Disqus setup requires adding a script block to the page that does document.write. This won't work on XHTML sites. And I dislike document.write usage in general. Thankfully this step appears optional. It's for converting marked up items in the page to a comment count.&lt;br /&gt;&lt;br /&gt;After leaving a comment Disqus does a full page refresh. This unfortunately results in the video on the page restarting and reloading.&lt;br /&gt;&lt;br /&gt;Apart from those issues Disqus seemed quite nice. Simple to set up and configurable.&lt;br /&gt;&lt;br /&gt;So the end result is I'm not sure which is best. I'll play around with them for a bit more and get feedback. Are there any other's worth trying?&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/tinyvid" rel="tag"&gt;tinyvid&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-6302339428723436012?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/05/third-party-comment-engines.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-8458561468372847962</guid><pubDate>Mon, 11 May 2009 11:45:00 +0000</pubDate><atom:updated>2009-05-12T11:10:50.778+12:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Simple Nanojit Example</title><description>I've been playing around with &lt;a href="https://developer.mozilla.org/En/Nanojit"&gt;Nanojit&lt;/a&gt;, thinking about using it in a &lt;a href="https://github.com/doublec/cf/tree"&gt;toy project of mine&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Nanojit is a library for generating machine code with backends for x86 and ARM. It's used by &lt;a href="http://en.wikipedia.org/wiki/Tamarin_(JIT)"&gt;Tamarin&lt;/a&gt; and &lt;a href="https://wiki.mozilla.org/JavaScript:TraceMonkey"&gt;TraceMonkey&lt;/a&gt; for their just in time compilers.&lt;br /&gt;&lt;br /&gt;The Mozilla documentation contains some documentation which gives an overview of what's there:&lt;ul&gt;&lt;li&gt;&lt;a href="https://developer.mozilla.org/En/Nanojit"&gt;Nanojit overview&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://developer.mozilla.org/En/Nanojit/LIR"&gt;LIR Instructions&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Currently Nanojit seems to be directly included in both the Tamarin and Mozilla repositories. To make it easy to reuse in my various test projects I split out the nanojit code and put it in a &lt;a href="http://github.com/doublec/nanojit/tree/master"&gt;github repository&lt;/a&gt;. The build is a simple makefile and is only setup for x86 since that's that platform I'm trying it on for now.&lt;br /&gt;&lt;br /&gt;In the 'example' directory of the nanojit github repository is the example from the &lt;a href="https://developer.mozilla.org/En/Nanojit"&gt;Mozilla documentation&lt;/a&gt;. This is what I'm basing my usage of it from.&lt;br /&gt;&lt;br /&gt;As a simple test of using it I wrote an expression evaluator. You enter simple mathematical expressions using addition, subtraction, multiplication and division at the command line and it compiles the expression into machine code using nanojit and calls it to get the result.&lt;br /&gt;&lt;br /&gt;I started with an interpreter first and added the compiling once that was working. To parse the expressions I used &lt;a href="http://piumarta.com/software/peg/"&gt;Ian Piumarta's Parsing Expression Grammar library&lt;/a&gt;. I tweaked it a bit to be able to use it from C++. The grammar is simple and produces a basic Abstract Syntax tree:&lt;pre&gt;Expr      = lhs:Product (  "+" rhs:Product  { lhs = new Add(lhs, rhs); }&lt;br /&gt;                         | "-" rhs:Product  { lhs = new Subtract(lhs, rhs); }&lt;br /&gt;                        )*                  { $$ = lhs }&lt;br /&gt;Product   = lhs:Value   (  "*" rhs:Value    { lhs = new Multiply(lhs, rhs); }&lt;br /&gt;                         | "/" rhs:Value    { lhs = new Divide(lhs, rhs); }&lt;br /&gt;                        )* _                { $$ =lhs }&lt;br /&gt;Value     = Number _&lt;br /&gt;Number    = &lt; [0-9]+ ('.' [0-9]+)?&gt;     { $$ = new Number(atof(yytext)); }&lt;/pre&gt;Running this through the 'leg' program produces C code that can be included in the project to compile the expression entered by the user. The interpreter just walks over the AST, calling an 'eval' method, to produce the result. Code looks like:&lt;pre&gt;float Number::eval()  { return value; }&lt;br /&gt;float Add:eval()      { return lhs-&gt;eval() + rhs-&gt;eval(); }&lt;br /&gt;float Subtract:eval() { return lhs-&gt;eval() - rhs-&gt;eval(); }&lt;br /&gt;float Multiply:eval() { return lhs-&gt;eval() * rhs-&gt;eval(); }&lt;br /&gt;float Divide:eval()   { return lhs-&gt;eval() / rhs-&gt;eval(); }&lt;br /&gt;int main() {&lt;br /&gt;  Object* result = parse();&lt;br /&gt;  cout &amp;lt;&amp;lt; "Result: " &amp;lt;&amp;lt; result-&gt;eval() &amp;lt;&amp;lt; endl;  &lt;br /&gt;  return 0;&lt;br /&gt;}&lt;/pre&gt;Converting this to generate machine code and call it is pretty easy. Instead of an 'eval' method I created a 'compile' method. 'compile' takes an object as an argument that I call methods on to generate Nanojit intermediate representation (LIR). It returns the resulting generated LIR instruction. The code for the Number AST object looks like:&lt;pre&gt;LIns* Number::compile(LirWriter* writer) {&lt;br /&gt;  return writer-&gt;insImmf(value);&lt;br /&gt;}&lt;/pre&gt;The LirWriter object contains methods to generate LIR code. For Number we generate an immediate float value and return a pointer to the generated instruction.&lt;br /&gt;&lt;br /&gt;The operators are implemented in a similar manner. I'll just show the code for Add:&lt;pre&gt;LIns* Add::compile(LirWriter* writer)&lt;br /&gt;{&lt;br /&gt;  LIns* a = lhs-&gt;compile(writer);&lt;br /&gt;  LIns* b = rhs-&gt;compile(writer);&lt;br /&gt;  return writer-&gt;ins2(LIR_fadd, a, b);&lt;br /&gt;}&lt;/pre&gt;Here we compile the left and right hand sides of the expression, saving pointers to the generated instructions. Then we generate a 'float add' LIR instruction. This is passed the instructions that were generated for the left and right parts of the expression. By calling compile on the topmost AST object we end up generating the code for the entire expression.&lt;br /&gt;&lt;br /&gt;The code required to set up Nanojit and create the LirWriter is a bit more complicated. Most of what I did was copy and pasted from the example code. Basically I create a Fragmento object and a LirBuffer. Then each time an expression is entered I create a Fragment object which will contain the final generated code and a LirBufferWriter which is the base LirWriter object used by the 'compile' methods. &lt;br /&gt;&lt;br /&gt;LirWriter's can be added to a LirBufferWriter to form a pipeline that instructions go through to do different things like optimisation or output debugging code before ending up in the LirBuffer. After this I generate a 'start' instruction, call the 'compile' method to do the rest, and generate a required epilogue instruction:&lt;pre&gt;Fragmento *fragmento = new (gc) Fragmento(&amp;core, 20);&lt;br /&gt;LirBuffer *buf = new (gc) LirBuffer(fragmento, NULL);&lt;br /&gt;...&lt;br /&gt;Object* result = parse();&lt;br /&gt;...&lt;br /&gt;Fragment *f = new (gc) Fragment(NULL);&lt;br /&gt;LirBufWriter writer(buf);&lt;br /&gt;...&lt;br /&gt;writer.ins0(LIR_start);&lt;br /&gt;writer.ins1(LIR_fret, result-&gt;compile(&amp;writer));&lt;br /&gt;...&lt;br /&gt;f-&gt;lastIns = writer.insGuard(LIR_loop, writer.insImm(1), rec_ins);&lt;br /&gt;&lt;br /&gt;// Compile the fragment.&lt;br /&gt;compile(fragmento-&gt;assm(), f);&lt;br /&gt;&lt;br /&gt;// Call the compiled function.&lt;br /&gt;typedef JS_FASTCALL float (*ExprFunction)();&lt;br /&gt;ExprFunction fn = reinterpret_cast&lt;ExprFunction&gt;(f-&gt;code());&lt;br /&gt;cout &amp;lt;&amp;lt; "Result: " &amp;lt;&amp;lt; fn() &amp;lt;&amp;lt; endl;&lt;/pre&gt;The expression evaluator interpreter and compiler example can be downloaded and played with by cloning my '&lt;a href="http://github.com/doublec/play/tree/master"&gt;play&lt;/a&gt;' repository on github. Once cloned you'll need to initialize and update the submodules to pull in the nanojit and peg third party libraries that it uses:&lt;pre&gt;$ git clone git://github.com/doublec/play.git&lt;br /&gt;$ cd play&lt;br /&gt;$ git submodule init&lt;br /&gt;$ git submodule clone&lt;/pre&gt;Run 'make' in the 'expr-interpreter' and 'expr-compiler' directories and run the 'expr' program that results. If you compile both nanojit and expr-compiler with DEBUG defined you get some debug output. It show's the LIR and the assembler code generated. For example, the LIR for: 2+3+4*2 is:&lt;pre&gt;start&lt;br /&gt;#40000000:0 /* 2 */&lt;br /&gt;#40080000:0 /* 3 */&lt;br /&gt;fadd1 = fadd #0x40000000:0, #0x40080000:0&lt;br /&gt;#40100000:0 /* 4 */&lt;br /&gt;#40000000:0 /* 2 */&lt;br /&gt;fmul1 = fmul #0x40100000:0, #0x40000000:0&lt;br /&gt;fadd2 = fadd fadd1, fmul1&lt;br /&gt;ret fadd2&lt;/pre&gt;The assembly code generated for this is:&lt;pre&gt;mov -8(ebp),0                  &lt;br /&gt;mov -4(ebp),1073741824         &lt;br /&gt;mov -16(ebp),0                 &lt;br /&gt;mov -12(ebp),1074266112        &lt;br /&gt;fldq -16(ebp)                  &lt;br /&gt;fadd -8(ebp)                    f0(#0x40080000:0)&lt;br /&gt;fstpq -8(ebp)                   f0(fadd1)&lt;br /&gt;mov -16(ebp),0                 &lt;br /&gt;mov -12(ebp),1074790400        &lt;br /&gt;mov -24(ebp),0                 &lt;br /&gt;mov -20(ebp),1073741824        &lt;br /&gt;fldq -24(ebp)                  &lt;br /&gt;fmul -16(ebp)                   f0(#0x40000000:0)&lt;br /&gt;fadd -8(ebp)                    f0(fmul1)&lt;/pre&gt;It's easy to change the code to use integer math instead of floating point. Use LIR_ret instead of LIR_fret for the return, and use LIR_add, LIR_sub, etc. This is the assembly code generated for '2+3+4*2' using integer math:&lt;pre&gt;mov eax,2                      &lt;br /&gt;add eax,3                       eax(2)&lt;br /&gt;mov ebx,4                       eax(add1)&lt;br /&gt;mov ecx,2                       eax(add1) ebx(4)&lt;br /&gt;mul ebx,ecx                     eax(add1) ecx(2) ebx(4)&lt;br /&gt;add eax,ebx                     eax(add1) ebx(mul1)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/nanojit" rel="tag"&gt;nanojit&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-8458561468372847962?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/05/simple-nanojit-example.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-386945934960422898</guid><pubDate>Fri, 08 May 2009 00:17:00 +0000</pubDate><atom:updated>2009-05-08T12:26:03.178+12:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Theora encoder improvements</title><description>A lot of work has been going on improving the Theora video encoder. Given a better encoder we end up with better quality Theora videos without the need to change the decoder in existing players. The project name for the Theora encoder improvements is 'Thusnelda'. &lt;br /&gt;&lt;br /&gt;Periodic updates have been released by &lt;a href="http://xiph.org"&gt;Xiph&lt;/a&gt; showing the progress of the new encoder. The &lt;a href="http://web.mit.edu/xiphmont/Public/theora/demo7.html"&gt;latest update&lt;/a&gt; makes interesting reading and show's graphs comparing it against other Theora builds, and against x264 (an H.264 encoder).&lt;br /&gt;&lt;br /&gt;The update show's that some great improvements have been made, and in some cases is comparible to the results from the x264 encoder. Greg Maxwell gives some more information &lt;a href="http://www.reddit.com/r/programming/comments/8iphn/theora_encoder_improvments_comparable_to_h264/c09evak"&gt;in this reddit comment&lt;/a&gt; about the results.&lt;br /&gt;&lt;br /&gt;Remember that the intent of this is not to compare Theora vs x264, or to say one is better than the other in the general case. It's to show the improvement of Theora vs older Theora versions. The fact that it compares favourably against x264 in this one case, using one particular test of quality, is a good result though.&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/video" rel="tag"&gt;video&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-386945934960422898?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/05/theora-encoder-improvements.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>8</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-6667063496812202891</guid><pubDate>Thu, 09 Apr 2009 13:30:00 +0000</pubDate><atom:updated>2009-04-10T04:05:27.560+12:00</atom:updated><title>Another tinyvid.tv update</title><description>I've made some more changes and fixes to &lt;a href="http://tinyvid.tv"&gt;tinyvid.tv&lt;/a&gt; since my &lt;a href="http://www.bluishcoder.co.nz/2009/03/tinyvidtv-updates.html"&gt;last update&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;I've updated to the latest &lt;a href="http://factorcode.org"&gt;Factor&lt;/a&gt; version, picking up some bug fixes and improvements to the libraries that I use.&lt;br /&gt;&lt;br /&gt;The look and feel of the site has a new logo and banner thanks to &lt;a href="http://www.tapper-ware.net/"&gt;Hans Schmucker&lt;/a&gt;. There have been some great contributions and bug reports in the &lt;a href="http://tinyvid.tv/feedback"&gt;feedback&lt;/a&gt; part of the site from Hans and others.&lt;br /&gt;&lt;br /&gt;Support for converting &lt;a href="http://www.dailymotion.com"&gt;Daily Motion&lt;/a&gt; videos is now in place. This gives three sites that can be converted from now. The other two being &lt;a href="http://youtube.com"&gt;YouTube&lt;/a&gt; and &lt;a href="http://vimeo.com"&gt;Vimeo&lt;/a&gt;. In all cases it tries to convert the highest quality video available from the site.&lt;br /&gt;&lt;br /&gt;A number of bugs in the &lt;a href="http://tinyvid.tv/upload"&gt;file uploads&lt;/a&gt; have been fixed. There still are a few annoyances in this area, mainly to do with not very good error reporting when an upload fails. I'm still playing around with this area.&lt;br /&gt;&lt;br /&gt;Previously logging in was done with &lt;a href="http://www.bluishcoder.co.nz/2009/02/testing-facebook-connect-locally.html"&gt;Facebook Connect&lt;/a&gt;. Now I've added support for &lt;a href="http://openid.net/"&gt;Open ID&lt;/a&gt; as well as Facebook and others. &lt;br /&gt;&lt;br /&gt;This support was easily added using the great service from &lt;a href="https://rpxnow.com/"&gt;RPX Now&lt;/a&gt;. I implemented server support in &lt;a href="http://factorcode.org"&gt;Factor&lt;/a&gt; very easily and it gives a nice authentication login interface. If you don't want to associate an existing account with your tinyvid.tv videos you can use a service like &lt;a href="http://myopenid.com/"&gt;myopenid.com&lt;/a&gt; to get an Open ID login and use that to authenticate with tinyvid.&lt;br /&gt;&lt;br /&gt;I'm trialing the &lt;a href="http://www.bluishcoder.co.nz/2009/03/replacing-controls-using-bookmarklet.html"&gt;bookmarklet written by Hans Schmucker&lt;/a&gt; as the main player on the site. It provides visibility of the controls outside the video area so you can always see them without obscuring the video, has a volume control, and allows resizing the video. If you want to try the browser's standard controls you can click on the 'download' link on the video page to do that. I may switch between this player and the native controls based on feedback or if problems are found.&lt;br /&gt;&lt;br /&gt;I added an 'embed snippet' on the video page so you can copy/paste it into your own pages to have the video embedded.&lt;br /&gt;&lt;br /&gt;If you have any ideas for things to add or improve let me know.&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/video" rel="tag"&gt;video&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/tinyvid" rel="tag"&gt;tinyvid&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-6667063496812202891?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/04/another-tinyvidtv-update.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-7445861216291445493</guid><pubDate>Thu, 02 Apr 2009 20:43:00 +0000</pubDate><atom:updated>2009-04-03T09:47:46.677+13:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>The Linux Link Tech Show on HTML 5 Audio and Video</title><description>Yesterday I was a guest on &lt;a href="http://www.tllts.org/"&gt;The Linux Link Tech Show&lt;/a&gt; talking about Firefox and HTML 5 audio/video support. It was a great show with lots of interesting questions and discussions about video in the browser, the choice of Theora for the video codec, and different ways video can be used on the web. &lt;br /&gt;&lt;br /&gt;The show is archived and you can download and listen to &lt;a href="http://www.tllts.org/"&gt;episode 292&lt;/a&gt; recorded on the 1st April 2009. Vorbis and MP3 versions are available.&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/video" rel="tag"&gt;video&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-7445861216291445493?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/04/linux-link-tech-show-on-html-5-audio.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-7512876399827185028</guid><pubDate>Wed, 25 Mar 2009 11:21:00 +0000</pubDate><atom:updated>2009-03-26T00:40:11.178+13:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>oggplayer: A simple Ogg player using liboggplay</title><description>To help track down performance issues, and fix some a/v synchronisation bugs, I wrote a simple Ogg player in C++ using the same libraries and a similar approach to what I use in the Firefox video implementation.&lt;br /&gt;&lt;br /&gt;The source to '&lt;a href="http://github.com/doublec/oggplayer/tree/master"&gt;oggplayer&lt;/a&gt;' is &lt;a href="http://github.com/doublec/oggplayer/tree/master"&gt;available on github&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;I've setup the repository to facilitate my experimenting with different approaches and different library versions. What this means is I've taken the, probably unusual, approach of having a 'thirdparty' directory containing git &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"&gt;submodules&lt;/a&gt; for each of the Ogg based libraries I'm using. I configure and build these and link statically to them. This lets me use experimental versions of the Ogg libraries without dealing with 'shared library hell'.&lt;br /&gt;&lt;br /&gt;This is all explained in the README, but just quickly these are the steps to clone oggplayer, and get the third party libraries from git:&lt;pre&gt;$ git clone git://github.com/doublec/oggplayer.git&lt;br /&gt;$ cd oggplayer&lt;br /&gt;$ git submodules init&lt;br /&gt;$ git submodules update&lt;/pre&gt;Once that's done you need to build the third party libraries:&lt;pre&gt;$ cd thirdparty&lt;br /&gt;$ sh build.sh&lt;/pre&gt;Run 'make' to build oggplayer itself. The third party libraries are built and installed in a 'local' subdirectory.&lt;br /&gt;&lt;br /&gt;You'll notice the unix-centric leaning of these commands. I've only built on Linux. I'm using cross platform libraries so it should build with minor changes on Mac OS X. Mainly changing the audio library to link against in the Makefile. For Windows you'll probably need to use Cygwin or MSYS.&lt;br /&gt;&lt;br /&gt;To run, just pass the filename on the command line:&lt;pre&gt;$ ./oggplayer foo.ogg&lt;/pre&gt;Press ESC to exit the playback, and space bar to toggle full screen on supported platforms (those that &lt;a href="http://www.libsdl.org"&gt;SDL&lt;/a&gt; supports full screen).&lt;br /&gt;&lt;br /&gt;These are the third party libraries I use, and include as submodules:&lt;ul&gt;&lt;li&gt;libogg&lt;/li&gt;&lt;li&gt;libvorbis&lt;/li&gt;&lt;li&gt;libtheora&lt;/li&gt;&lt;li&gt;liboggz&lt;/li&gt;&lt;li&gt;libfishsound&lt;/li&gt;&lt;li&gt;liboggplay&lt;/li&gt;&lt;li&gt;libsydneyaudio&lt;/li&gt;&lt;/ul&gt;You'll need the following system libraries to build:&lt;ul&gt;&lt;li&gt;Boost C++ libraries&lt;/li&gt;&lt;li&gt;SDL&lt;/li&gt;&lt;/ul&gt;There's not much error checking, I mostly use 'assert' to bail on an error. I don't want to spend time creating an awesome player, rather something I can use to try test out the way I'm using the third party libraries.&lt;br /&gt;&lt;br /&gt;Interestingly with this example player I can play back the &lt;a href="http://www.bluishcoder.co.nz/2009/01/liboggplay-playback-performance.html"&gt;problematic HD video&lt;/a&gt; I mentioned previously. Part of this is the newer YUV conversion routines in liboggplay and the more lower level optimized SDL libraries for blitting the video data. I'm also not seeing audio buffer underruns which I see with some videos in Firefox. Time to do some investigating!&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/video" rel="tag"&gt;video&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-7512876399827185028?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/03/oggplayer-simple-ogg-player-using.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>8</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-3733859471062121535</guid><pubDate>Mon, 23 Mar 2009 01:57:00 +0000</pubDate><atom:updated>2009-03-23T15:01:25.319+13:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Very nice web technology demo</title><description>This '&lt;a href="http://www.w3.org/2009/03/web-demo.xhtml"&gt;glimpse of future web technologies&lt;/a&gt;', all in one document is pretty nifty. Lots of different web stuff in there, including rotated videos, fancy CSS, and DFXP captions for videos.&lt;br /&gt;&lt;br /&gt;Thanks to &lt;a href="http://intertwingly.net/blog/2009/03/22/Several-Web-technologies"&gt;Sam Ruby&lt;/a&gt; for pointing to &lt;a href="http://www.w3.org/People/LeHegaret/"&gt;Philippe Le Hegaret's&lt;/a&gt; work.&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-3733859471062121535?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/03/very-nice-web-technology-demo.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-8916135418781537741</guid><pubDate>Fri, 13 Mar 2009 01:39:00 +0000</pubDate><atom:updated>2009-03-17T11:31:45.907+13:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Replacing &lt;video&gt; controls using a bookmarklet</title><description>[Update: Chris Blizzard has a neat &lt;a href="http://www.0xdeadbeef.com/weblog/?p=1173"&gt;screencast&lt;/a&gt; showing the bookmarklet and player replacement in action.]&lt;br /&gt;&lt;br /&gt;There's been some interesting demo's of &amp;lt;video&amp;gt; usage and manipulation discussed in the &lt;a href="http://tinyvid.tv/feedback"&gt;TinyVid Feedback&lt;/a&gt; comments section.&lt;br /&gt;&lt;br /&gt;One user, &lt;a href="http://www.intensedebate.com/people/hansschmucker"&gt;hansschmucker&lt;/a&gt;, has done some nice demonstrations of what &amp;lt;video&amp;gt; can offer. &lt;br /&gt;&lt;br /&gt;For example, &lt;a href="http://www.tapper-ware.net/devel/js/JS.TinyVidPlayer/v002/bookmarklet/index.html"&gt;this bookmarklet&lt;/a&gt; can take a &lt;a href="http://tinyvid.tv"&gt;TinyVid&lt;/a&gt; video and replace the player using the built in controls with one written in JavaScript provided by the bookmarklet. The new interface includes seeking, play, pause and volume control. It looks very nice.&lt;br /&gt;&lt;br /&gt;To use the bookmarket, visit the &lt;a href="http://www.tapper-ware.net/devel/js/JS.TinyVidPlayer/v002/bookmarklet/index.html"&gt;bookmarklet page&lt;/a&gt;, click on the button that appears there and bookmark the resulting page. Next visit a &lt;a href="http://tinyvid.tv/show/yka5q2v7221y"&gt;TinyVid video&lt;/a&gt; and visit the bookmarklet. The built in player will be replaced by the new one. This will also work on many pages that use video using the built in controls, for example &lt;a href="http://transparencycamp.org/videos/"&gt;this transparency camp video&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This example show's it's possible for users to create and customize their own video players and use it on sites of their choice which is pretty nice.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.intensedebate.com/people/hansschmucker"&gt;hansschmucker&lt;/a&gt; also provided some demo's of using &amp;lt;video&amp;gt; with &amp;lt;canvas&amp;gt; that allow you to view a video in 3D using red/cyan glasses. I've copied his comment from the feedback page below:&lt;blockquote&gt;=== Using VIDEO as data source for 3D ===&lt;br /&gt;I just wrote a little demo to demonstrate how powerful VIDEO elements can be as data source: This little script (it's 20 lines for god's sake) uses a video (which was also produced via JS by the way, thanks to Radiohead's choice of using simple CSV for the data, the power of Canvas and a bit of base64 decoding) to offset pixels in a randomly generated noise map, saving the original map as red and the altered image as red/blue.&lt;br /&gt;&lt;br /&gt;You just have to get out your red/cyan glasses and you'll be able to enjoy the video in 3D. Lots more could be done with proper optimization (in fact, the whole thing may be done as a set of SVG filters) and just a little more attention to detail (random noise is possibly the worst thing you can use for a map), but it's still amazing how easily you can create something amazong with VIDEO.&lt;br /&gt;...&lt;br /&gt;Two more variants: &lt;a href="http://www.tapper-ware.net/devel/js/JS.StereoVideo/index3.xhtml"&gt;uses a prerendered noise (looks much better)&lt;/a&gt;  and &lt;a href="http://www.tapper-ware.net/devel/js/JS.StereoVideo/index2.xhtml"&gt; warps the source image itself&lt;/a&gt; which probably makes most sense here.&lt;/blockquote&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/tinyvid" rel="tag"&gt;tinyvid&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/video" rel="tag"&gt;video&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-8916135418781537741?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/03/replacing-controls-using-bookmarklet.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-9094017595919383583</guid><pubDate>Sat, 07 Mar 2009 02:16:00 +0000</pubDate><atom:updated>2009-03-07T15:35:08.458+13:00</atom:updated><title>tinyvid.tv updates</title><description>I did some updates to &lt;a href="http://www.tinyvid.tv"&gt;tinyvid.tv&lt;/a&gt;, my test site for using the HTML 5 video element, over the last week or so.&lt;br /&gt;&lt;br /&gt;I mentioned the first in a previous post, &lt;a href="http://www.bluishcoder.co.nz/2009/02/testing-facebook-connect-locally.html"&gt;using Facebook Connect for authentication&lt;/a&gt;. All user accounts have an internal identifier which is associated with the Facebook account when the user chooses to authorize TinyVid. This means all activities that require user authentication require a Facebook account. Eventually I'll probably add other methods (OpenId, etc).&lt;br /&gt;&lt;br /&gt;The main feature addition was &lt;a href="http://tinyvid.tv/upload"&gt;uploads&lt;/a&gt;. If you are authenticated you can upload files. They are initially set to private visibility. You can edit that to make them public. &lt;br /&gt;&lt;br /&gt;There are two ways of doing uploads. The first is via the standard HTML file input element. This requires the uploaded file to be in Ogg format already. I check this when the upload is complete and fail the upload if it is not valid. &lt;br /&gt;&lt;br /&gt;The second is using the &lt;a href="http://firefogg.org"&gt;firefogg&lt;/a&gt; Firefox extension. This lets you upload a file in almost any video format. It transcodes the video to Ogg format before uploading. It provides a progress bar for the transcode, and the upload progress, providing a slightly better user experience than the first method.&lt;br /&gt;&lt;br /&gt;File uploads are still in testing and I'll be enabling/disabling it as I find problems and fix them.&lt;br /&gt;&lt;br /&gt;I changed the &lt;a href="http://www.bluishcoder.co.nz/2009/02/fallback-options-for-html5-video.html"&gt;fallback mechanism&lt;/a&gt; so that browsers that don't have native video support will immediately use the Cortado Java applet instead of requiring a click through.&lt;br /&gt;&lt;br /&gt;I added a &lt;a href="http://tinyvid.tv/popular"&gt;page showing popular videos&lt;/a&gt;. It shows videos with the most views over the last 24 hours, and for all time (since I enabled this feature which is only a few days ago).&lt;br /&gt;&lt;br /&gt;There is an &lt;a href="http://tinyvid.tv/account"&gt;account management&lt;/a&gt; feature that lists all the videos you've uploaded or converted. You can edit the metadata for these videos (title, description, private/public visibility) or delete them. These requires being authenticated.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://tinyvid.tv/search"&gt;Search&lt;/a&gt; was added. Currently it searches through the titles. I'll add searching through the description field later. &lt;br /&gt;&lt;br /&gt;I fixed an issue that prevented Safari from playing some of the videos due to a bug in the &lt;a href="http://www.factorcode.org"&gt;Factor&lt;/a&gt; webserver. Safari users will need to &lt;a href="http://weblogs.mozillazine.org/asa/archives/2009/03/open_video_in_s.html"&gt;install the XiphQT plugin&lt;/a&gt; to get Ogg support however.&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/tinyvid" rel="tag"&gt;tinyvid&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/video" rel="tag"&gt;video&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-9094017595919383583?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/03/tinyvidtv-updates.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-4006518593731468041</guid><pubDate>Fri, 27 Feb 2009 00:20:00 +0000</pubDate><atom:updated>2009-02-27T13:30:30.558+13:00</atom:updated><title>User Authentication - OpenID and Facebook</title><description>I'm still looking at the different options for &lt;a href="http://tinyvid.tv"&gt;tinyid&lt;/a&gt; to handle registration and authentication of users. My recent change added logging in using your Facebook account using &lt;a href="http://developers.facebook.com/connect.php"&gt;Facebook Connect&lt;/a&gt;. Another option I'm considering is &lt;a href="http://openid.net/"&gt;OpenID&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There's a good blog post comparing the &lt;a href="http://www.sociallipstick.com/2008/11/21/an-open-stack-glossary-for-facebook-developers/"&gt;Facebook vs the OpenID stack&lt;/a&gt;. The same weblog has a post on using &lt;a href="http://www.sociallipstick.com/2009/02/04/how-to-accept-openid-in-a-popup-without-leaving-the-page/"&gt;OpenID in a popup&lt;/a&gt; without leaving the page, similar to how Facebook Connect does its magic. You can see a &lt;a href="http://openid-demo.appspot.com/"&gt;demo of this concept in action&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/facebook" rel="tag"&gt;facebook&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/openid" rel="tag"&gt;openid&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/tinyvid" rel="tag"&gt;tinyvid&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-4006518593731468041?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/02/user-authentication-openid-and-facebook.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-5484027582120651533</guid><pubDate>Wed, 25 Feb 2009 22:24:00 +0000</pubDate><atom:updated>2009-02-26T15:30:32.138+13:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Fallback options for HTML5 video</title><description>The HTML5 &amp;lt;video&amp;gt; element only works on a few, often bleeding edge, browsers. For &lt;a href="http://tinyvid.tv"&gt;tinyvid&lt;/a&gt; I've been only supporting this subset of browsers. Recently I put in support for a simple fallback option for other browsers.&lt;br /&gt;&lt;br /&gt;In browsers that don't support &amp;lt;video&amp;gt; the element is ignored. The contents of the element are still processed however. This means any HTML elements within &amp;lt;video&amp;gt;...&amp;lt;/video&amp;gt; will display to the user on those browsers. The most basic fallback option is to tell the user that their browser doesn't support video:&lt;pre&gt;&amp;lt;video&amp;gt;&lt;br /&gt;  &amp;lt;p&amp;gt;pSorry, your browser doesn't support the video element&amp;lt;p&amp;gt;&lt;br /&gt;&amp;lt;/video&amp;gt;&lt;/pre&gt;In my blog in the past I've used the video element to display the Theora video, and fallback to a YouTube hosted video if the browser doesn't support it. This was done with code like:&lt;pre&gt;&amp;lt;video src="/video_bling.ogg" controls&amp;gt;&lt;br /&gt;  &amp;lt;object width="425" height="350"&amp;gt;&lt;br /&gt;    &amp;lt;param name="movie" &lt;br /&gt;              value="http://www.youtube.com/v/vvtdkxCIKC8"&amp;gt;&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;embed src="http://www.youtube.com/v/vvtdkxCIKC8" &lt;br /&gt;              type="application/x-shockwave-flash" &lt;br /&gt;              width="425"&lt;br /&gt;              height="350"&amp;gt; &amp;lt;/embed&amp;gt; &lt;br /&gt;  &amp;lt;/object&amp;gt;&amp;gt;/video&amp;gt;&lt;/pre&gt;On &amp;lt;video&amp;gt; enabled browsers this uses built in support. On others it uses the Flash player to play the YouTube video.&lt;br /&gt;&lt;br /&gt;It's possible to play Theora videos using a Java Applet called &lt;a href="http://maikmerten.livejournal.com/2256.html"&gt;Cortado&lt;/a&gt;. This can be used as a fallback for users that have Java support but no HTML5 video support:&lt;pre&gt;&amp;lt;video src="test.ogg" controls&amp;gt;&lt;br /&gt;  &amp;lt;applet code="com.fluendo.player.Cortado.class" &lt;br /&gt;             archive="cortado.jar" &lt;br /&gt;             width="320"&lt;br /&gt;             height="240"&amp;gt;&lt;br /&gt;    &amp;lt;param name="url" value="test.ogg"&amp;gt;&amp;lt;/param&amp;gt;&lt;br /&gt;    &amp;lt;param name="duration" value="229.015"&amp;gt;&amp;lt;/param&amp;gt;            &lt;br /&gt;  &amp;lt;/applet&amp;gt;&lt;br /&gt;&amp;lt;/video&amp;gt;&lt;/pre&gt;The Cortado applet cannot be used for video's hosted on another domain however. They must be on the same domain as that serving the cortado applet.&lt;br /&gt;&lt;br /&gt;These fallback options don't allow creating your own controls with JavaScript and using the nice HTML5 media API. They work best when you only want a single fallback option and use the built-in controls.&lt;br /&gt;&lt;br /&gt;There are JavaScript libraries that can be used to emulate the HTML5 media API. Or you can write a simple wrapper to do this yourself. The basic approach is to use &amp;lt;video&amp;gt; in your page and insert a JavaScript file at the top. When loaded this fill searches the document for usages of &amp;lt;video&amp;gt;. It detects what capabilities the browser has (native video support, Flash, Cortado, mplayer/vlc plugin, etc) and replaces the &amp;lt;video&amp;gt; element with the correct HTML code to instantiate the fallback. The JavaScript can then create a wrapper object that emulates the HTML5 API and calls the underlying plugin methods, etc if possible.&lt;br /&gt;&lt;br /&gt;Examples of this type of library can be seen in use:&lt;ul&gt;&lt;li&gt;&lt;a href="http://metavid.org/w/index.php/Mv_embed"&gt;mv_embed&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.celt-codec.org/presentations/"&gt;Xiph.org presentations&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://footage.stealthisfilm.com/browse"&gt;Steal This Footage&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;I've added very simple fallback to tinyvid using the Cortado applet. If the browser doesn't support &amp;lt;video&amp;gt; it displays a link the user can click to go to a page that uses the applet. The server decides whether to use native video or the applet depending on a URL parameter. Here's a link to a native video player, and the applet version:&lt;ul&gt;&lt;li&gt;&lt;a href="http://tinyvid.tv/show/t5v1inpguy9t"&gt;Native Video&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tinyvid.tv/show/t5v1inpguy9t?player=applet"&gt;Cortado Applet&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;For the applet version the server queries the Ogg file for the width, height and duration of the video so it can embed that data in the applet parameters. In some cases I can't get the width and height. This is due to some of the videos being stored on backup storage (via Amazon S3) and I can't locally analyze it to get the data. In that case the applet dimensions are set to 320x240.&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/video" rel="tag"&gt;video&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-5484027582120651533?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/02/fallback-options-for-html5-video.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-4882440039079440758</guid><pubDate>Wed, 25 Feb 2009 22:14:00 +0000</pubDate><atom:updated>2009-02-26T11:24:10.189+13:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>facebook</category><title>Testing Facebook Connect Locally</title><description>I've been experimenting with integrating features from the social networking site Facebook into &lt;a href="http://www.tinyvid.tv"&gt;tinyvid&lt;/a&gt;. To do this I'm using the '&lt;a href="http://developers.facebook.com/connect.php"&gt;Facebook Connect&lt;/a&gt;' API.&lt;br /&gt;&lt;br /&gt;When you register a Facebook application you need to provide URL's to your application's site so Facebook knows where to send the user on redirects from logging in, and handle messaging between Facebook and your application.&lt;br /&gt;&lt;br /&gt;To handle the case of being able to develop and test on a local server, and deploying to the live server. This is the 'Callback URL' setting in the application setup. This can contain an IP address and port number so for testing locally you can set it to a local IP address. For example, http://127.0.0.1:9000.&lt;br /&gt;&lt;br /&gt;Facebook doesn't try to contact this directly, it redirects the browser to it, so this works fine when testing the application locally. You can create two applications, one with the testing Callback URL, and one with the production one, and make this a parameter in your application.&lt;br /&gt;&lt;br /&gt;Another option that worked for me was to set the Callback URL to the production domain (in this case, tinyvid.tv) and locally set my hosts file so that tinyvid.tv resolved to localhost. The web server needs to run in port 80 locally for this to work.&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/facebook" rel="tag"&gt;facebook&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-4882440039079440758?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/02/testing-facebook-connect-locally.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></item><item><guid isPermaLink='false'>tag:blogger.com,1999:blog-18561009.post-5661283598945654190</guid><pubDate>Wed, 28 Jan 2009 01:06:00 +0000</pubDate><atom:updated>2009-01-28T14:17:48.853+13:00</atom:updated><category domain='http://www.blogger.com/atom/ns#'>mozilla</category><title>Daily Motion, OLPC and Theora</title><description>A while back it was &lt;a href="http://www.readwriteweb.com/archives/olpc_daily_motion_partner_on_o.php"&gt;announced that Daily Motion&lt;/a&gt;, an online video site, had opened an OLPC channel for sharing videos encoded using Theora for playback on OLPC's.&lt;br /&gt;&lt;br /&gt;The channel, &lt;a href="http://olpc.dailymotion.com/"&gt;http://olpc.dailymotion.com&lt;/a&gt;, contains theora videos aimed at the OLPC audience. What's nice is that the videos playback in Firefox 3.1 using the native Theora support and don't require a plugin, for example &lt;a href="http://olpc.dailymotion.com/popular/video/x43efw_une-vision-de-lunivers-simulation_tech"&gt;this video&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Looking at the Daily Motion page it seems they use the &amp;lt;object&gt; element to playback the Ogg Theora file, which uses the internal decoder and player user interface. This is a nice result from the adding of support for &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=448603"&gt;direct loading of Ogg files&lt;/a&gt; that &lt;a href="http://weblogs.mozillazine.org/roc/"&gt;Robert&lt;/a&gt; worked on.&lt;br /&gt;&lt;br /&gt;&lt;span class="technoratitag"&gt;Categories: &lt;a href="http://del.icio.us/bluishcoder/firefox" rel="tag"&gt;firefox&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/theora" rel="tag"&gt;theora&lt;/a&gt;, &lt;a href="http://del.icio.us/bluishcoder/video" rel="tag"&gt;video&lt;/a&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18561009-5661283598945654190?l=www.bluishcoder.co.nz%2Findex.html' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bluishcoder.co.nz/2009/01/daily-motion-olpc-and-theora.html</link><author>noreply@blogger.com (Chris Double)</author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></item></channel></rss>