<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Bluish Coder: ogg</title>
 <link href="http://bluishcoder.co.nz/tag/ogg/atom.xml" rel="self"/>
 <link href="http://bluishcoder.co.nz/"/>
 <updated>2018-01-10T15:35:12+13:00</updated>
 <id>http://bluishcoder.co.nz/</id>
 <author>
   <name>Bluishcoder</name>
   <email>admin@bluishcoder.co.nz</email>
 </author>

 
 <entry>
   <title>Vorbis Player implemented in Pure</title>
   <link href="http://bluishcoder.co.nz/2010/02/25/vorbis-player-written-in-pure.html"/>
   <updated>2010-02-25T14:00:00+13:00</updated>
   <id>http://bluishcoder.co.nz/2010/02/25/vorbis-player-written-in-pure</id>
   <content type="html">&lt;p&gt;After writing the &lt;a href=&quot;http://bluishcoder.co.nz/2010/02/20/pure-preforking-echo-server-example.html&quot;&gt;preforking echo server example&lt;/a&gt; in &lt;a href=&quot;http://code.google.com/p/pure-lang/&quot;&gt;Pure&lt;/a&gt; I wanted to try something a bit more complex. I&#39;ve written Ogg players in various languages before so I decided to do one in Pure to compare. Here&#39;s some of the ones I&#39;ve written in the past:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://bluishcoder.co.nz/2009/03/oggplayer-simple-ogg-player-using.html&quot;&gt;oggplayer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://bluishcoder.co.nz/2009/06/26/decoding-vorbis-files-with-libvorbis.html&quot;&gt;plogg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://tech.groups.yahoo.com/group/iolanguage/message/11610&quot;&gt;Io Language Addons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://bluishcoder.co.nz/2007/05/ogg-theora-support-for-factor.html&quot;&gt;Factor Ogg Player&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;An unreleased Haskell Vorbis player&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I wrapped the libogg and libvorbis libraries using the Pure FFI. A program &#39;pure-gen&#39; is included with Pure that will generate FFI wrappers given a C include file. I ran this against libogg and libvorbis. The generated Pure wrappers look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;extern int ogg_page_version(ogg_page*);
extern int ogg_page_continued(ogg_page*);
extern int ogg_page_bos(ogg_page*);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see Pure FFI definitions look very much like the C definitions.&lt;/p&gt;

&lt;p&gt;I decided to model an Ogg file as a list of physical pages. This is esentially a list containing elements of the libogg ogg_page object. I have a Pure function that will take this list of pages and return a list of packets for each logical bitstream in the file. For vorbis playback I take this list of packets for the vorbis bitstream and produce a list of decoded PCM data.&lt;/p&gt;

&lt;p&gt;Pure is a strict language by default but provides an &#39;&amp;amp;&#39; special form to perform lazy evaluation. I use this to make sure all the returned lists mentioned above are lazy. Playing the lazy list of decoded PCM data never loads the entire file in memory. The file is read, converted into packets and decoded as each element of the PCM data list is requested.&lt;/p&gt;

&lt;p&gt;For audio playback I use &lt;a href=&quot;http://connect.creativelabs.com/openal/default.aspx&quot;&gt;OpenAL&lt;/a&gt;. I queue the PCM data to an OpenAL source up to a limit of 50 queued items, removing them as they get processed and adding new ones when room becomes available.&lt;/p&gt;

&lt;p&gt;Here&#39;s what some of the API to process the Ogg files looks like in Pure. First load the player code. This will also load the Ogg, Vorbis and OpenAL wrappers:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ pure -i player.pure
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From the Pure REPL, play a vorbis file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; play_vorbis (sources!0) &quot;test.ogg&quot;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Load an Ogg file getting a lazy list of all pages in the file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; using namespace ogg;
&amp;gt; let p = file_pages &quot;test.ogg&quot;;
&amp;gt; p;
ogg_page (#&amp;lt;pointer 0x9e61cc8&amp;gt;,[...]):#&amp;lt;thunk 0xb7259b38&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Get a list of all packets and the serial number of the first logical bitstream in the list of pages:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; let (stream1,serialno) = packets p;
&amp;gt; serialno;
1426627898
&amp;gt; stream1;
ogg_packet (#&amp;lt;pointer 0x9dd98f0&amp;gt;,[...]):#&amp;lt;thunk 0xb725bce0&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Get the next logical bitstream:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; let p2 = filter (\x-&amp;gt;ogg_page_serialno x ~= serialno) p;
&amp;gt; p2;
#&amp;lt;thunk 0xb725dc30&amp;gt;
&amp;gt; let (stream2,serialno2) = packets p2;
&amp;gt; serialno2;
629367739
&amp;gt; stream2;
ogg_packet (#&amp;lt;pointer 0x9cfcf08&amp;gt;,[...]):#&amp;lt;thunk 0xb725c988&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that all these results are lazily evaluated so the entire
file is not loaded into memory. If we look at the original list
of pages you&#39;ll see what has been read so far (two pages):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; p;
ogg_page (...):ogg_page (...):#&amp;lt;thunk 0xb725dd98&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Get all the streams in the file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; let s = all_streams p;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Get all the vorbis streams:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; let v = vorbis_streams s;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Get the first vorbis stream. I ignore the serial number here (this is what the _ does):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; let (v1, _) = v!0;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Decode the vorbis header packets and intialize a vorbis decoder
for the first vorbis stream:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; let decoder = vorbis_header v1;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Get a lazy list of all the decoded PCM data from the vorbis stream:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; let pcm = pcm_data decoder;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The mechanics of getting the decoding floating point data from libvorbis into Pure and then back to the OpenAL C API is made easier due to it being possible to easily convert to and from raw C pointers and Pure matrix objects.&lt;/p&gt;

&lt;p&gt;For example, the data returned from the vorbis call to decode the data is an array of pointers pointing to an array of floats. To convert this to a Pure matrix with dimensions (c,n) where &#39;c&#39; is the number of channels and &#39;n&#39; is the number of samples:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;vorbis_synthesis_read dsp samples $$ matrix m
when
  f0 = get_pointer data;
  floats = [get_pointer (f0+(x*4))|x=0..(channels-1)];
  m = map (float_matrix samples) floats;
end;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code uses a list comprehension to return a list of &#39;pointer to array of floats&#39;. One pointer for each channel in the audio data. It then maps over this list producing a new list containing a matrix of float&#39;s. This is list of matrices each of which contains the audio data for a channel. The &#39;matrix m&#39; call converts this to a single matrix of dimensions (c,n).&lt;/p&gt;

&lt;p&gt;OpenAL expects the data as a pointer to a contiguous matrix of floats with dimensions (n,c) so when writing to OpenAL the matrix needs to be transposed:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;play_pcm source rate pcm@(x:xs) =
  ....
  queue_sample source rate (transpose x) $$
  play source $$
  play_pcm source rate xs;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This transposed matrix is later converted from floats to 16 bit integers and &#39;packed&#39; so it is contiguous in memory, and a pointer to the raw memory passed to OpenAL:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;buffer16 s = pack (map clamp s);  
...
data = buffer16 ...pcmdata...;
alBufferData ... (cooked (short_pointer NULL data)) ((#data) * (sizeof sshort_t)) ...;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &#39;cooked&#39; call means the C memory has &#39;free&#39; called on it when nothing in Pure is holding onto it anymore.&lt;/p&gt;

&lt;p&gt;One downside with lazy lists is it can be easy to accidently read the entire file and decode everything before playing. This will cause issues with large Ogg files. I managed to avoid that and files play in constant memory. An &lt;a href=&quot;http://okmij.org/ftp/Streams.html&quot;&gt;iteratee&lt;/a&gt; style approach might be interesting to try as an alternative to lazy lists. I&#39;d like to try decoding Theora files and doing a/v sync in Pure at some point as well.&lt;/p&gt;

&lt;p&gt;I haven&#39;t used Pure much but it seemed to be fairly simple to put this together. I&#39;d be interested in feedback on the approach (using lazy lists) and Pure style issues in the code.&lt;/p&gt;

&lt;p&gt;The code for this is at &lt;a href=&quot;http://github.com/doublec/pure-ogg-player&quot;&gt;http://github.com/doublec/pure-ogg-player&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Playing Ogg files with audio and video in sync</title>
   <link href="http://bluishcoder.co.nz/2009/06/27/playing-ogg-files-with-audio-and-video.html"/>
   <updated>2009-06-27T22:07:00+12:00</updated>
   <id>http://bluishcoder.co.nz/2009/06/27/playing-ogg-files-with-audio-and-video</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://bluishcoder.co.nz/2009/06/26/decoding-vorbis-files-with-libvorbis.html&quot;&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&#39;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&#39;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=&quot;http://theora.org/doc/libtheora-1.0/group__decfuncs.html#g31c814bf09b2232aff69c57ae20f04eb&quot;&gt;th_decode_packetin&lt;/a&gt;. The last parameter is a pointer to hold the &#39;granulepos&#39; 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&#39;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=&quot;http://theora.org/doc/libtheora-1.0/group__basefuncs.html#g707e1e281de788af0df39ef00f3fb432&quot;&gt;th_granule_time&lt;/a&gt; converts a &#39;granulepos&#39; to an absolute time in seconds. So decoding a frame gives us &#39;granulepos&#39;. 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&#39;s a breakdown of the steps:
* Read the headers from the Ogg file. Stop when we hit the first data packet.
* Read packets from the audio stream in the Ogg file. For each audio packet:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Decode the audio data and write it to the audio hardware.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Get the current playback position of the audio and convert it to an absolute time value.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Convert the last granulepos read (defaulting to zero if none have been read) to an absolute time value using the libtheora API.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;If the audio time is greater than the video time:   
    &amp;lt;ol&amp;gt;
      &amp;lt;li&amp;gt;Read a packet from the Theora stream.&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;Decode that packet and display it&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;Store the granulepos from that decoded frame so we know when to display the next frame.&amp;lt;/li&amp;gt;
    &amp;lt;/ol&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&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&#39;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 &#39;&lt;a href=&quot;http://github.com/doublec/plogg/tree/part4_avsync&quot;&gt;part4_avsync&lt;/a&gt;&#39; branch on github.&lt;/p&gt;

&lt;p&gt;This example takes a slightly different approach to reading headers. I use &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_stream_packetpeek.html&quot;&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&#39;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;&lt;code&gt;// Process all available header packets in the stream. When we hit
// the first data stream we don&#39;t decode it, instead we
// return. The caller can then choose to process whatever data
// streams it wants to deal with.
ogg_packet packet;
while (!headersDone &amp;amp;&amp;amp;
       (ret = ogg_stream_packetpeek(&amp;amp;stream-&amp;gt;mState, &amp;amp;packet)) != 0) {
assert(ret == 1);

// A packet is available. If it is not a header packet we exit.
// If it is a header packet, process it as normal.
headersDone = headersDone || handle_theora_header(stream, &amp;amp;packet);
headersDone = headersDone || handle_vorbis_header(stream, &amp;amp;packet);
if (!headersDone) {
  // Consume the packet
  ret = ogg_stream_packetout(&amp;amp;stream-&amp;gt;mState, &amp;amp;packet);
  assert(ret == 1);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To read packets for a particular stream I use a &#39;read_packet&#39; function that operates on a stream passed as a parameter:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;bool OggDecoder::read_packet(istream&amp;amp; is, 
                             ogg_sync_state* state, 
                             OggStream* stream, 
                             ogg_packet* packet) {
  int ret = 0;
  while ((ret = ogg_stream_packetout(&amp;amp;stream-&amp;gt;mState, packet)) != 1) {
    ogg_page page;
    if (!read_page(is, state, &amp;amp;page))
      return false;

    int serial = ogg_page_serialno(&amp;amp;page);
    assert(mStreams.find(serial) != mStreams.end());
    OggStream* pageStream = mStreams[serial];

    // Drop data for streams we&#39;re not interested in.
    if (stream-&amp;gt;mActive) {
      ret = ogg_stream_pagein(&amp;amp;pageStream-&amp;gt;mState, &amp;amp;page);
      assert(ret == 0);
    }
  }
  return true;
}
&lt;/code&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&#39;ve added an &#39;active&#39; flag to the streams so we can ignore streams that we aren&#39;t intersted in. We don&#39;t want to continuously buffer data for alternative audio tracks we aren&#39;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&#39;s time to display a frame is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// At this point we&#39;ve written some audio data to the sound
// system. Now we check to see if it&#39;s time to display a video
// frame.
//
// The granule position of a video frame represents the time
// that that frame should be displayed up to. So we get the
// current time, compare it to the last granule position read.
// If the time is greater than that it&#39;s time to display a new
// video frame.
//
// The time is obtained from the audio system - this represents
// the time of the audio data that the user is currently
// listening to. In this way the video frame should be synced up
// to the audio the user is hearing.
//
ogg_int64_t position = 0;
int ret = sa_stream_get_position(mAudio, SA_POSITION_WRITE_SOFTWARE, &amp;amp;position);
assert(ret == SA_SUCCESS);
float audio_time = 
  float(position) /
  float(audio-&amp;gt;mVorbis.mInfo.rate) /
  float(audio-&amp;gt;mVorbis.mInfo.channels) /
  sizeof(short);

float video_time = th_granule_time(video-&amp;gt;mTheora.mCtx, mGranulepos);
if (audio_time &amp;gt; video_time) {
  // Decode one frame and display it. If no frame is available we
  // don&#39;t do anything.
  ogg_packet packet;
  if (read_packet(is, &amp;amp;state, video, &amp;amp;packet)) {
    handle_theora_data(video, &amp;amp;packet); 
    video_time = th_granule_time(video-&amp;gt;mTheora.mCtx, mGranulepos);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The code for decoding and display the Theora video is similar to the &lt;a href=&quot;http://bluishcoder.co.nz/2009/06/26-decoding-theora-files-using-libtheora.html&quot;&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 &#39;plogg&#39; should play Ogg files with a Theora and Vorbis track in sync. It does not play Theora files with no audio track - we can&#39;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 and the audio and video will skip (depending on the speed of your hardware). This isn&#39;t a pleasant experience. Because of the blocking audio writes we can&#39;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&#39;t too complex and I&#39;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&#39;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=&quot;http://www.bigbuckbunny.org/index.php/download/&quot;&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&#39;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&#39;s on the PC.&lt;/p&gt;

&lt;p&gt;After the followup article on improving the a/v sync I&#39;ll look at covering seeking.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Decoding Vorbis files with libvorbis</title>
   <link href="http://bluishcoder.co.nz/2009/06/26/decoding-vorbis-files-with-libvorbis.html"/>
   <updated>2009-06-26T14:08:00+12:00</updated>
   <id>http://bluishcoder.co.nz/2009/06/26/decoding-vorbis-files-with-libvorbis</id>
   <content type="html">&lt;p&gt;Decoding Vorbis streams require a very similar approach to that used when &lt;a href=&quot;http://bluishcoder.co.nz/2009/06/25/decoding-theora-files-using-libtheora.html&quot;&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=&quot;http://www.xiph.org/vorbis/doc/&quot;&gt;libvorbis documentation&lt;/a&gt; doesn&#39;t contain an API reference that I could find so I&#39;m following the approached used by the example programs.&lt;/p&gt;

&lt;p&gt;Assuming we have already obtained an &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_packet.html&quot;&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&#39;t return a value to see that it&#39;s a Vorbis data packet. To check for this you need to check if the stream is a Vorbis stream (by knowing you&#39;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&#39;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=&quot;http://github.com/doublec/plogg/tree/master&quot;&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=&quot;http://bluishcoder.co.nz/2009/06/25/decoding-theora-files-using-libtheora.html&quot;&gt;Theora post&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class VorbisDecode {
  ...
  vorbis_info mInfo;
  vorbis_comment mComment;
  vorbis_dsp_state mDsp;
  vorbis_block mBlock;
  ...
      VorbisDecode()
  {
    vorbis_info_init(&amp;amp;mInfo);
    vorbis_comment_init(&amp;amp;mComment);    
  }
};
&lt;/code&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;&lt;code&gt;  int ret = vorbis_synthesis_headerin(&amp;amp;stream-&amp;gt;mVorbis.mInfo,
                      &amp;amp;stream-&amp;gt;mVorbis.mComment,
                      packet);
  if (stream-&amp;gt;mType == TYPE_VORBIS &amp;amp;&amp;amp; ret == OV_ENOTVORBIS) {
    // First data packet
    ret = vorbis_synthesis_init(&amp;amp;stream-&amp;gt;mVorbis.mDsp, &amp;amp;stream-&amp;gt;mVorbis.mInfo);
    assert(ret == 0);
    ret = vorbis_block_init(&amp;amp;stream-&amp;gt;mVorbis.mDsp, &amp;amp;stream-&amp;gt;mVorbis.mBlock);
    assert(ret == 0);
    stream-&amp;gt;mHeadersRead = true;
    handle_vorbis_data(stream, packet);
  }
  else if (ret == 0) {
    stream-&amp;gt;mType = TYPE_VORBIS;
  }
}
&lt;/code&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;&lt;code&gt;  int ret = 0;

  if (vorbis_synthesis(&amp;amp;stream-&amp;gt;mVorbis.mBlock, packet) == 0) {
    ret = vorbis_synthesis_blockin(&amp;amp;stream-&amp;gt;mVorbis.mDsp, &amp;amp;stream-&amp;gt;mVorbis.mBlock);
    assert(ret == 0);
  }
  float** pcm = 0;
  int samples = 0;
  while ((samples = vorbis_synthesis_pcmout(&amp;amp;stream-&amp;gt;mVorbis.mDsp, &amp;amp;pcm)) &amp;gt; 0) {
    if (!mAudio) {
      ret = sa_stream_create_pcm(&amp;amp;mAudio,
                 NULL,
                 SA_MODE_WRONLY,
                 SA_PCM_FORMAT_S16_NE,
                 stream-&amp;gt;mVorbis.mInfo.rate,
                 stream-&amp;gt;mVorbis.mInfo.channels);
      assert(ret == SA_SUCCESS);

      ret = sa_stream_open(mAudio);
      assert(ret == SA_SUCCESS);
    }

    if (mAudio) {
      short buffer[samples * stream-&amp;gt;mVorbis.mInfo.channels];
      short* p = buffer;
      for (int i=0;i &amp;lt; samples; ++i) {
        for(int j=0; j &amp;lt; stream-&amp;gt;mVorbis.mInfo.channels; ++j) {
          int v = static_cast&amp;lt;int&amp;gt;(floorf(0.5 + pcm[j][i]*32767.0));
          if (v &amp;gt; 32767) v = 32767;
          if (v &amp;lt;-32768) v = -32768;
          *p++ = v;
        }
      }

      ret = sa_stream_write(mAudio, buffer, sizeof(buffer));
      assert(ret == SA_SUCCESS);
    }

    ret = vorbis_synthesis_read(&amp;amp;stream-&amp;gt;mVorbis.mDsp, samples);
    assert(ret == 0);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A couple of minor changes were also made to the example program:
1. Continue processing pages and packets when the &#39;end of file&#39; is reached. Otherwise a few packets that are buffered after we&#39;ve reached the end of the file will be missed.
2. After reading a page don&#39;t just try to read one packet, call &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_stream_packetout.html&quot;&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;/p&gt;

&lt;p&gt;The code for this example is in the &#39;part3_vorbis&#39; 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;
</content>
 </entry>
 
 <entry>
   <title>Decoding Theora files using libtheora</title>
   <link href="http://bluishcoder.co.nz/2009/06/25/decoding-theora-files-using-libtheora.html"/>
   <updated>2009-06-25T20:33:00+12:00</updated>
   <id>http://bluishcoder.co.nz/2009/06/25/decoding-theora-files-using-libtheora</id>
   <content type="html">&lt;p&gt;My last post covered &lt;a href=&quot;http://bluishcoder.co.nz/2009/06/24/reading-ogg-files-using-libogg.html&quot;&gt;read Ogg files using libogg&lt;/a&gt;. The resulting program didn&#39;t do much but it covered the basic steps needed to get an &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_packet.html&quot;&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=&quot;http://theora.org/doc/libtheora-1.0/&quot;&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;&lt;code&gt;class TheoraDecode { 
  ...
  th_info mInfo;
  th_comment mComment;
  th_setup_info *mSetup;
  th_dec_ctx* mCtx;
  ...
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;http://theora.org/doc/libtheora-1.0/structth__info.html&quot;&gt;th_info&lt;/a&gt;, &lt;a href=&quot;http://theora.org/doc/libtheora-1.0/structth__comment.html&quot;&gt;th_comment&lt;/a&gt; and &lt;a href=&quot;http://theora.org/doc/libtheora-1.0/theoradec_8h.html#b71cd2657455cc27d6c0127c66a89f28&quot;&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=&quot;http://theora.org/doc/libtheora-1.0/theoradec_8h.html#843d70bb02563885a8d54b9c1a781729&quot;&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=&quot;http://theora.org/doc/libtheora-1.0/group__basefuncs.html#g430d9c605816a6ca0bdce3a0b965b926&quot;&gt;th_info_init&lt;/a&gt; and &lt;a href=&quot;http://theora.org/doc/libtheora-1.0/group__basefuncs.html#g6c8ab25988e7ea9d7b1e31a54cf58f09&quot;&gt;th_comment_init&lt;/a&gt;. Notice that th_setup_info is a pointer. This needs to be free&#39;d when we&#39;re finished with it using &lt;a href=&quot;http://theora.org/doc/libtheora-1.0/group__decfuncs.html#gdef55431b68aaa59d0d7b32b2f118f27&quot;&gt;th_setup_free&lt;/a&gt;. The decoder context object also needs to be free&#39;d. Use &lt;a href=&quot;http://theora.org/doc/libtheora-1.0/group__decfuncs.html#gfb6684ad8ba507b71112bc9de148e7d0&quot;&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;&lt;code&gt;class TheoraDecode {
  ...
  TheoraDecode() :
    mSetup(0),
    mCtx(0)
  {
    th_info_init(&amp;amp;mInfo);
    th_comment_init(&amp;amp;mComment);
  }

  ~TheoraDecode() {
    th_setup_free(mSetup);
    th_decode_free(mCtx);
  }   
  ...
&lt;/code&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;&lt;code&gt;class OggStream
{
  ...
  int mSerial;
  ogg_stream_state mState;
  StreamType mType;
  bool mHeadersRead;
  TheoraDecode mTheora;
  ...
};
&lt;/code&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&#39;m using to do this is to attempt to extract a Theora header from it. If this succeeds, it&#39;s a Theora stream. &lt;a href=&quot;http://theora.org/doc/libtheora-1.0/group__decfuncs.html#g006d01d36fbe64768c571e6a12b7fc50&quot;&gt;th_decode_headerin&lt;/a&gt; will attempt to decode a header packet. A return value of &#39;0&#39; 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;&lt;code&gt;ogg_packet* packet = ...got this previously...;
int ret = th_decode_headerin(&amp;amp;stream-&amp;gt;mTheora.mInfo,
                             &amp;amp;stream-&amp;gt;mTheora.mComment,
                             &amp;amp;stream-&amp;gt;mTheora.mSetup,
                             packet);
if (ret == TH_ENOTFORMAT)
  return; // Not a theora header

if (ret &amp;gt; 0) {
  // This is a theora header packet
  stream-&amp;gt;mType = TYPE_THEORA;
  return;
}

assert(ret == 0);
// This is not a header packet. It is the first 
// video data packet.
stream-&amp;gt;mTheora.mCtx = 
  th_decode_alloc(&amp;amp;stream-&amp;gt;mTheora.mInfo, 
                  stream-&amp;gt;mTheora.mSetup);
assert(stream-&amp;gt;mTheora.mCtx != NULL);
stream-&amp;gt;mHeadersRead = true;
...decode data packet...
&lt;/code&gt;&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=&quot;http://theora.org/doc/libtheora-1.0/group__decfuncs.html#g0ef07a9a97849054aa606c595a2d807e&quot;&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=&quot;http://theora.org/doc/libtheora-1.0/group__decfuncs.html#g31c814bf09b2232aff69c57ae20f04eb&quot;&gt;th_decode_packetin&lt;/a&gt;. This adds the packet to the decoder. A return value of &#39;0&#39; means we can get a decoded frame as a result of adding the packet. A call to &lt;a href=&quot;http://theora.org/doc/libtheora-1.0/group__decfuncs.html#ga9cc8af63fa8540e0fc95572f259cdcb&quot;&gt;th_decode_ycbcr_out&lt;/a&gt; gets the decoded YUV data, stored in a &lt;a href=&quot;http://theora.org/doc/libtheora-1.0/codec_8h.html#343f7cfabad179cc4fe527cf06873f45&quot;&gt;th_ycbcr_buffer&lt;/a&gt; object. This is basically an array of the YUV data.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ogg_int64_t granulepos = -1;
int ret = th_decode_packetin(stream-&amp;gt;mTheora.mCtx,
                             packet,
                             &amp;amp;granulepos);
assert(ret == 0);

th_ycbcr_buffer buffer;
ret = th_decode_ycbcr_out(stream-&amp;gt;mTheora.mCtx, buffer);
assert(ret == 0);
...copy yuv data to SDL YUV overlay...
...display overlay...
...sleep for 1 frame...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &#39;granulepos&#39; 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&#39;ll write more about this in a future post when I cover synchronising the audio and video. For now it&#39;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&#39;t copy the code for this since it&#39;s not particularly relevant to using the libtheora API - you can see it in the &lt;a href=&quot;http://github.com/doublec/plogg/&quot;&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;&lt;code&gt;float framerate = 
  float(stream-&amp;gt;mTheora.mInfo.fps_numerator) / 
  float(stream-&amp;gt;mTheora.mInfo.fps_denominator);
SDL_Delay((1.0/framerate)*1000);
&lt;/code&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&#39;ll cover these topics in a later post.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Reading Ogg files using libogg</title>
   <link href="http://bluishcoder.co.nz/2009/06/24/reading-ogg-files-using-libogg.html"/>
   <updated>2009-06-24T23:49:00+12:00</updated>
   <id>http://bluishcoder.co.nz/2009/06/24/reading-ogg-files-using-libogg</id>
   <content type="html">&lt;p&gt;Reading data from an Ogg file is relatively simple. The file format is well documented in &lt;a href=&quot;http://www.ietf.org/rfc/rfc3533.txt&quot;&gt;RFC 3533&lt;/a&gt;. I showed how to read the format using JavaScript &lt;a href=&quot;http://bluishcoder.co.nz/2009/06/05/reading-ogg-files-with-javascript.html&quot;&gt;in a previous post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For C and C++ programs it&#39;s easier to use the &lt;a href=&quot;http://xiph.org&quot;&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&#39;m prototyping some approaches to improve the performance of the Firefox Ogg video playback and while I&#39;m at it I&#39;ll write some posts on using these libraries to decode/play Ogg files. Hopefully it&#39;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=&quot;http://github.com/doublec/plogg/tree&quot;&gt;plogg&lt;/a&gt; git repository on github. The &#39;master&#39; branch contains the work in progress player that I&#39;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=&quot;http://www.xiph.org/ogg/doc/libogg/&quot;&gt;libogg documentation&lt;/a&gt; describes the API that I&#39;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&#39;t decode the data or do anything really useful. That&#39;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=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_sync_state.html&quot;&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=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_sync_init.html&quot;&gt;ogg_sync_init&lt;/a&gt; and later cleaned up with &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_sync_clear.html&quot;&gt;ogg_sync_clear&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ifstream file(&quot;foo.ogg&quot;, ios::in | ios::binary);
ogg_sync_state state;
int ret = ogg_sync_init(&amp;amp;state);
assert(ret==0);
...look for page...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that the libogg functions return an error code which should be checked, A result of &#39;0&#39; generally indicates success. We want to obtain a complete page of Ogg data. This is held in an &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_page.html&quot;&gt;ogg_page&lt;/a&gt; structure. The process of obtaining this structure is to do the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_sync_pageout.html&quot;&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=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_sync_buffer.html&quot;&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=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_sync_wrote.html&quot;&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 &#39;1&#39; if a full page of data is available.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Here&#39;s the code to do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ogg_page page;
while(ogg_sync_pageout(&amp;amp;state, &amp;amp;page) != 1) {
  char* buffer = ogg_sync_buffer(oy, 4096);
  assert(buffer);

  file.read(buffer, 4096);
  int bytes = stream.gcount();
  if (bytes == 0) {
    // End of file
    break;
  }

  int ret = ogg_sync_wrote(&amp;amp;state, bytes);
  assert(ret == 0);
}
&lt;/code&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;&lt;code&gt;class OggStream
{
  ...
  int mSerial;
  ogg_stream_state mState;
  int mPacketCount;
  ...
};

typedef map&amp;lt;int, OggStream*&amp;gt; StreamMap; 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each stream has an &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_stream_state.html&quot;&gt;ogg_stream_state&lt;/a&gt; object that is used to keep track of the data read that belongs to the stream. We&#39;re storing this in the OggStream object that we associated with the stream serial number. Once we&#39;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;&lt;code&gt;StreamMap streams;
ogg_page page = ...obtained previously...;
int serial = ogg_page_serialno(&amp;amp;page);
OggStream* stream = 0;
if (ogg_page_bos(&amp;amp;page) {
  stream = new OggStream(serial);
  int ret = ogg_stream_init(&amp;amp;stream-&amp;gt;mState, serial);
  assert(ret == 0);
  streams[serial] = stream;
}
else
  stream = streams[serial];

int ret = ogg_stream_pagein(&amp;amp;stream-&amp;gt;mState, &amp;amp;page);
assert(ret == 0);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code uses &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_page_serialno.html&quot;&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=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_page_bos.html&quot;&gt;ogg_page_bos&lt;/a&gt;) then we create a new OggStream object, initialize the stream&#39;s state with &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_stream_init.html&quot;&gt;ogg_stream_init&lt;/a&gt;, and store it in out streams map. If it&#39;s not the beginning of the stream we just get our existing entry in the map. The final call to &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_stream_pagein.html&quot;&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=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_stream_packetout.html&quot;&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&#39;s data is stored in an &lt;a href=&quot;http://www.xiph.org/ogg/doc/libogg/ogg_packet.html&quot;&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&#39;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;p&gt;The code for this is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;while (..read a page...) {
  ...put page in stream...  
  ogg_packet packet;
  int ret = ogg_stream_packetout(&amp;amp;stream-&amp;gt;mState, &amp;amp;packet);    
  if (ret == 0) {
    // Need more data to be able to complete the packet
    continue;
  }
  else if (ret == -1) {
    // We are out of sync and there is a gap in the data.
    // We lost a page somewhere.
    break;
  }

  // A packet is available, this is what we pass to the vorbis or
  // theora libraries to decode.
  stream-&amp;gt;mPacketCount++;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&#39;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&#39;t require reading from a file. You can use these routines with any data you&#39;ve obtained. From a socket, from memory, etc.&lt;/p&gt;

&lt;p&gt;In the next post about reading Ogg files I&#39;ll go through using libtheora to decode the video data and display it.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Reading Ogg files with JavaScript</title>
   <link href="http://bluishcoder.co.nz/2009/06/05/reading-ogg-files-with-javascript.html"/>
   <updated>2009-06-05T15:09:00+12:00</updated>
   <id>http://bluishcoder.co.nz/2009/06/05/reading-ogg-files-with-javascript</id>
   <content type="html">&lt;p&gt;On &lt;a href=&quot;http://tinyvid.tv&quot;&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;/p&gt;

&lt;p&gt;The format of the Ogg container is defined in &lt;a href=&quot;http://www.ietf.org/rfc/rfc3533.txt&quot;&gt;RFC 3533&lt;/a&gt;. The difficulty comes in reading binary data from JavaScript. The &lt;a href=&quot;https://developer.mozilla.org/en/XMLHttpRequest&quot;&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;/p&gt;

&lt;p&gt;One way of handling binary data is described in &lt;a href=&quot;https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data&quot;&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;/p&gt;

&lt;p&gt;Ideally I don&#39;t want to download the entire file. It might be a large video. I thought by handling the &#39;progress&#39; event or ready state 3 (data received) I&#39;d be able to look at the data currently retrieved. This does work but on each call to the &#39;responseText&#39; 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;/p&gt;

&lt;p&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&#39;d like to be able to process the file in chunks using an &lt;a href=&quot;http://okmij.org/ftp/Streams.html#random-bin-IO&quot;&gt;Iteratee&lt;/a&gt; style approach.&lt;/p&gt;

&lt;p&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 &#39;Go&#39; button in the &lt;a href=&quot;http://www.double.co.nz/video_test/oggparse.html&quot;&gt;demo page&lt;/a&gt;. This will load &lt;a href=&quot;http://www.double.co.nz/video_test/transformers320.ogg&quot;&gt;transformers320.ogg&lt;/a&gt; and display the contents of the first Ogg physical page.&lt;/p&gt;

&lt;p&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 &#39;Next&#39; will move on to the Next page. This is a Vorbis header with the rate and channel information. Clicking &#39;Next&#39; 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 &#39;Next&#39; 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;/p&gt;

&lt;p&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;/p&gt;

&lt;p&gt;The main issues with doing this from JavaScript seem to be:&lt;/p&gt;

&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=&quot;http://tinyvid.tv&quot;&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&#39;t be added. As a result even tinyvid itself can&#39;t use XMLHttpRequest to read these files.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>New &lt;video&gt; enabled experimental Firefox builds</title>
   <link href="http://bluishcoder.co.nz/2007/12/08/new-enabled-experimental-firefox-builds.html"/>
   <updated>2007-12-08T01:21:00+13:00</updated>
   <id>http://bluishcoder.co.nz/2007/12/08/new-enabled-experimental-firefox-builds</id>
   <content type="html">&lt;p&gt;I&#39;ve uploaded new builds of Firefox with experimental support for the WHATWG &amp;lt;video&amp;gt; element. They are (compiled from &lt;a href=&quot;http://www.double.co.nz/cgi-bin/gitweb.cgi?p=video.git;a=commit;h=3444c2cfe1e192edab5fd07eb0044f1f1f1a2196&quot;&gt;this git commit&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.double.co.nz/video_test/firefox-3.0b2pre-video.en-US.mac.dmg&quot;&gt;Intel Mac OS X 10.4.x&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.double.co.nz/video_test/firefox-3.0b2pre-video.en-US.win32.zip&quot;&gt;Windows XP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.double.co.nz/video_test/firefox-3.0b2pre-video.en-US.linux-i686.tar.bz2&quot;&gt;Ubuntu Linux x86&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The &lt;a href=&quot;http://www.double.co.nz/cgi-bin/gitweb.cgi?p=video.git;a=summary&quot;&gt;git repository&lt;/a&gt; has been updated with the code for this build.&lt;/p&gt;

&lt;p&gt;Note that the code in these builds, and the git repository, is advanced from that in the patch attached to the &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=382267&quot;&gt;video element bugzilla entry&lt;/a&gt;. That code can be accessed from git via the &lt;a href=&quot;http://www.double.co.nz/cgi-bin/gitweb.cgi?p=video.git;a=commit;h=946b0f3444def5591aed8bbcf713241d7b4f4695&quot;&gt;patch11&lt;/a&gt; tag.&lt;/p&gt;

&lt;p&gt;The usual disclaimer with the builds I provide applies.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Be aware that these are builds from a random point in the Mozilla CVS tree,
with the Video patch applied. I don&#39;t guarantee they&#39;ll work for much more
than demonstrating video support and it&#39;s very likely to contain bugs. That
said, I run these builds often.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Two main additions with this build. The first is fixing the annoying bug whereby leaving a page that is playing video would leave the sound running in the background. This was due to the &#39;bfcache&#39; keeping the page around in case the user hits the back or forward buttons. The video is effectively paused now when the page is in the bfcache.&lt;/p&gt;

&lt;p&gt;The second is preliminary support for the &lt;a href=&quot;http://www.whatwg.org/specs/web-apps/current-work/#source&quot;&gt;&amp;lt;source&amp;gt; element&lt;/a&gt;, which can be used to provide a list of media resources, with mime types, and the browser &lt;a href=&quot;http://www.whatwg.org/specs/web-apps/current-work/#pick-a&quot;&gt;selects out of the list the media resource to play based on what it supports&lt;/a&gt;. This initial implementation only supports a &#39;type&#39; attribute set to &#39;video/ogg&#39;. What this will let you do though, is add a source element for an MP4 encoding, and one for an Ogg encoding. When played on Firefox the Ogg version will play, and a browser that currently doesn&#39;t support Ogg but supports MP4 can choose to play that instead.&lt;/p&gt;

&lt;p&gt;Issues I have partial fixes for but haven&#39;t yet made it into the main branch of the git repository, and not in these builds are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sound support on Linux is patchy. I&#39;m using sydney audio&#39;s OSS support which has issues when multiple devices open /dev/dsp. This can occasionally affect synchronisation of the video.&lt;/li&gt;
&lt;li&gt;There is no buffering for network loads. The video plays immediately so on a slow pipe or large video the playback will stutter. You can pause the video to let the download catch up but there is no progress indication yet. This can make performance look worse than it is in bandwidth constrained environments.&lt;/li&gt;
&lt;li&gt;Seeking forward and back in the stream. There is some support, but it&#39;s a work in progress and quite broken.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;You might notice that full page zoom works in this build. And it works with videos. You can zoom a page and any videos on the page are zoomed. You can test this with Ctrl+ (Apple-+ on the Mac).&lt;/p&gt;

&lt;p&gt;Test videos are available at &lt;a href=&quot;http://www.double.co.nz/video_test/&quot;&gt;my test page&lt;/a&gt;, or &lt;a href=&quot;http://dev.opera.com/articles/view/a-call-for-video-on-the-web-opera-vid/&quot;&gt;Opera&#39;s page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are sites using the &amp;lt;video&amp;gt; right now.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://metavid.ucsc.edu/&quot;&gt;Metavid&lt;/a&gt; project has support for the &amp;lt;video&amp;gt; element. If you look at the videos in a &amp;lt;video&amp;gt; enabled browser, the player is the interface provided with the &#39;controls&#39; attribute set. For example, &lt;a href=&quot;http://metavid.ucsc.edu/overlay/video_player/webview?stream_name=senate_proceeding_11-16-07&amp;amp;t=00:00:00/00:01:00&quot;&gt;Senate Proceeding 11-16-07&lt;/a&gt;. Nice job, Metavid, and thanks for using &amp;lt;video&amp;gt;!&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://commons.wikimedia.org/wiki/Category:Video&quot;&gt;Wikimedia video&#39;s&lt;/a&gt; seems to have experimental support for it. Unfortunately the test to see if the video element is supported appears to be done last, so usually the Java applet, etc is found first. You can get around this by setting a cookie. When the &lt;a href=&quot;http://commons.wikimedia.org/wiki/Category:Video&quot;&gt;Wikimedia video page&lt;/a&gt; open, enter this in the URL bar:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;javascript:wgOggPlayer.setCookie(&#39;ogg_player&#39;, &#39;videoElement&#39;, 7*86400*1000, false, false, false, false)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remove it by deleting the &#39;commons.wikimedia.org&#39; cookie if you want to go back to the default ordering of selections.&lt;/p&gt;

&lt;p&gt;You&#39;ll notice some issues, which is probably why it&#39;s currently right at the end of the chain. Clicking on the video picture and pressing play works fine. But clicking the play button on the main page listing all the videos does not correctly display the video. I&#39;ll look into what&#39;s causing this.&lt;/p&gt;

&lt;p&gt;If you know of any other &amp;lt;video&amp;gt; supported sites, please let me know in the comments.&lt;/p&gt;

&lt;p&gt;I&#39;ll be attending the &lt;a href=&quot;http://www.w3.org/2007/08/video/&quot;&gt;W3C Video on the Web Workshop&lt;/a&gt; in San Jose on the 12th and 13th of December. I fly out from Auckland on the 9th and leave San Francisco on the 16th. If you&#39;re in the area and want to catch up, &lt;a href=&quot;mailto:chris.double@double.co.nz&quot;&gt;let me know&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Opera has a new Video enabled build</title>
   <link href="http://bluishcoder.co.nz/2007/11/09/opera-has-new-video-enabled-build.html"/>
   <updated>2007-11-09T00:03:00+13:00</updated>
   <id>http://bluishcoder.co.nz/2007/11/09/opera-has-new-video-enabled-build</id>
   <content type="html">&lt;p&gt;Opera is making a &lt;a href=&quot;http://dev.opera.com/articles/view/a-call-for-video-on-the-web-opera-vid/&quot;&gt;call for video on the web&lt;/a&gt;, releasing an experimental build with video support modelled on the latest &lt;a href=&quot;http://www.whatwg.org/specs/web-apps/current-work/#video0&quot;&gt;WHATWG specification&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Their post has some examples to try out and instructions on how to use the &amp;lt;video&gt; element.&lt;/p&gt;

&lt;p&gt;Their examples work quite well in the latest video enabled build of Firefox too. Thanks to help from &lt;a href=&quot;http://weblogs.mozillazine.org/roc/&quot;&gt;Robert O&#39;Callahan&lt;/a&gt; it now has support for the &#39;controls&#39; attribute. There&#39;s no more need for JavaScript buttons to activate video. I&#39;ve also implemented some of the events. This code is in the &lt;a href=&quot;http://www.double.co.nz/cgi-bin/gitweb.cgi&quot;&gt;git repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some very experimental binary builds if you want to try things out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.double.co.nz/video_test/firefox-3.0a9pre_controls.en-US.win32.zip&quot;&gt;Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.double.co.nz/video_test/firefox-3.0a9pre_controls.en-US.mac.dmg&quot;&gt;Mac OS X 10.4 (Intel)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Linux coming soon&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Be aware that these are builds from a random point in the Mozilla CVS tree, with the Video patch applied. I don&#39;t guarantee they&#39;ll work for much more than demonstrating video support and it&#39;s very likely to contain bugs. That said, I run these builds often.&lt;/p&gt;

&lt;p&gt;Try out the &lt;a href=&quot;http://dev.opera.com/articles/view/a-call-for-video-on-the-web-opera-vid/&quot;&gt;demo&#39;s that Opera have done&lt;/a&gt;, or the one&#39;s on my &lt;a href=&quot;http://www.double.co.nz/video_test&quot;&gt;test page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It&#39;s very cool to see video support using patent free formats running on more than one browser, with simple HTML that can be embedded by anyone. Thanks Opera!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Theora needs an MSVC compatible inline assembler expert</title>
   <link href="http://bluishcoder.co.nz/2007/10/03/theora-needs-msvc-compatible-inline.html"/>
   <updated>2007-10-03T13:06:00+13:00</updated>
   <id>http://bluishcoder.co.nz/2007/10/03/theora-needs-msvc-compatible-inline</id>
   <content type="html">&lt;p&gt;The &lt;a href=&quot;http://blog.hartwork.org/?p=86&quot;&gt;Theora project needs someone&lt;/a&gt; knowledgeable in the inline assembler syntax used in the Microsoft Visual C++ toolset.&lt;/p&gt;

&lt;p&gt;Theora has some assembler portions written using the GNU assembler syntax. Some way of having these same optimizations working when building the library with the Microsoft toolset would be very useful.&lt;/p&gt;
</content>
 </entry>
 
 
</feed>
