com.hdcookbook.grin.util
Class BitStreamIO

java.lang.Object
  extended by com.hdcookbook.grin.util.BitStreamIO

public class BitStreamIO
extends java.lang.Object

This contains utility methods to help read and write bit streams. This can be handy, for example, to read and write things like the BDJO data structure (part 3-2 section 10.2.1.2) or the index.bdmv structure (part 3-2 section 5.2.3.2). For example, a structure like this:

      isFirst                    1 uimsbf
      isPretty           1 uimsbf
        randomFlags              3 uimsbf
        reserved_for_word_align 11 bslbf
      someNameLength             8 uimsbf
      for (i = 0; i < someNameLength; i++) {
          someNameByte   8 uimsbf
      }

  where someName is encoded in UTF8
 
Could be read with:
    DataInputStream dis = ...;
    BitStreamIO bio = new BitStreamIO();

    boolean isFirst = (bio.readBits(dis, 1)) != 0;
    boolean isPretty = (bio.readBits(dis, 1)) != 0;
    int someBits = bio.readBits(dis, 3);        // 0 <= someBits < 8
    bio.readBits(dis, 11);
    if (Debug.ASSERT) {
        bio.assertByteAligned(1);
    }
    byte[] buf = new byte[bio.readBits(dis, 8)];
    dis.read(buf);
    String someName = new String(buf, "UTF-8");
 
And it could be written with:
    DataOutputStream dos= ...;
    BitStreamIO bio = new BitStreamIO();

    bio.writeBits(dos, 1, (isFirst ? 1 : 0));
    bio.writeBits(dos, 1, (isPretty ? 1 : 0));
    bio.writeBits(dos, 3, someBits);
    bio.writeBits(dos, 11, 0);
    if (Debug.ASSERT) {
        bio.assertByteAligned(1);
    }
    byte[] buf = someName.getBytes("UTF-8");
    bio.writeBits(dos, 8, buf.length);
    dos.write(buf);
 
Note how you use the underlying data stream directly when reading and writing byte quantities, and only use the bio helper when dealing with bits. A more elegant and OO design would have been to make a BitStreamReader and BitStreamWriter class that extended DataInputStream and DataOutputStream, but that would have been bigger and slower to classload. On Blu-ray players, there's a substantial penalty (on the order of 30ms) per class loaded, so it's good for performance to minimize the number of classes.

This code is probably a bit slower than hand-written shifts and masks, but it's simpler, and perfectly adequate for the small binary data structures that are typical of Blu-ray and many other environments.

Author:
Bill Foote (http://jovial.com)

Constructor Summary
BitStreamIO()
          Create a new BitStreamIO helper.
 
Method Summary
 void assertByteAligned(int numBytes)
          Generate an assertion failure if the BitStreamIO helper isn't aligned ot the given number of bytes.
 int getBitsProcessed()
          Get the number of bits processed by this helper.
 int readBits(java.io.DataInputStream dis, int numBits)
          Read the given number of bits from dis.
 long readBitsLong(java.io.DataInputStream dis, int numBits)
          Read the given number of bits from dis.
 void writeBits(java.io.DataOutputStream dos, int numBits, int value)
          Write the given bits to dos.
 void writeBitsLong(java.io.DataOutputStream dos, int numBits, long value)
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

BitStreamIO

public BitStreamIO()
Create a new BitStreamIO helper. A given helper should be used for either reading or writing, but not both.

Method Detail

readBits

public int readBits(java.io.DataInputStream dis,
                    int numBits)
             throws java.io.IOException
Read the given number of bits from dis. No locking is performed; it is assumed a BitStreamIO object is only used by one thread at a time. Some bits will be stored in the helper if the read isn't byte-aligned after this call.

Parameters:
dis - The stream to read from.
numBits - The number of bits to read, 0 <= numBits <= 32
Throws:
java.io.IOException

readBitsLong

public long readBitsLong(java.io.DataInputStream dis,
                         int numBits)
                  throws java.io.IOException
Read the given number of bits from dis. No locking is performed; it is assumed a BitStreamIO object is only used by one thread at a time. Some bits will be stored in the helper if the read isn't byte-aligned after this call.

Parameters:
dis - The stream to read from.
numBits - The number of bits to read, 0 <= numBits <= 64
Throws:
java.io.IOException

writeBits

public void writeBits(java.io.DataOutputStream dos,
                      int numBits,
                      int value)
               throws java.io.IOException
Write the given bits to dos. No locking is performed; it is assumed a BitStreamIO object is only used by one thread at a time. Some bits will be stored in the helper if the result isn't byte-aligned at the end of this write.

Parameters:
dos - The stream to write to
numBits - The number of bits, 0 <= numBits <= 32
value - The value to read (in the lower-order bits)
Throws:
java.io.IOException

writeBitsLong

public void writeBitsLong(java.io.DataOutputStream dos,
                          int numBits,
                          long value)
                   throws java.io.IOException
Throws:
java.io.IOException

assertByteAligned

public void assertByteAligned(int numBytes)
Generate an assertion failure if the BitStreamIO helper isn't aligned ot the given number of bytes. assertByteAligned(1) asserts it's byte aligned, assertByteAligned(4) asserts its word-aligned, etc.


getBitsProcessed

public int getBitsProcessed()
Get the number of bits processed by this helper. This can be useful for checking consisgtency, or for padding on byte or word boundaries.