[Flac-dev] FLAC StreamInfo Parsing

Brian Willoughby brianw at sounds.wa.com
Tue Jun 22 22:15:24 PDT 2010


On Jun 22, 2010, at 21:27, Ilia Ternovich wrote:
> Thank you very much! But how to deal with endianness in the case of
> bit stream? Some blocks (for example MinBlockSize) require 16bits
> (simply swap first and second), some block (e.g.MinFrameSize) require
> 3 byte-array to be reverted.
>
> Finally totalSamples is stored in 5 bytes ( only last 4 bits from
> first one byte are used). It was a real issue to make it little-endian
> (here is how I did it:
> http://code.google.com/p/sharpflac/source/browse/trunk/SharpFlac/ 
> Blocks/StreamInfo.cs).
>
> So to make stream little endian, I can't simple get each 4 bytes of
> the stream one by one and revert them...
>
> Anyways I've managed to decode StreamInfo, VorbisComments,SeekPoints
> and Application blocks without bitStream implementation. But I'd be
> really pleased if anyone pointed me out how to deal with endianness.


Just because you've been able to hack around without a bitStream  
implementation doesn't mean you're doing it right!  :-)

I took a look at your code, and you're calling GetEndianBytes(adr,  
ofs, n); with n > 1, and that's wrong.  You cannot look ahead in a  
stream, and so your code is already doing things in a way that is not  
to spec.  You then use array indexes and bit shift operators to build  
multi-byte values.  What's worse, I see that your code is looking at  
(contentOffset - 1), which is really bad.

What you need to do is write a bitStream function.  It should only  
read each byte from the stream once and completely deal with all 8  
bits before dealing with the next byte.  You should never look ahead  
beyond the current byte.  Instead, you need a long long accumulator  
to hold the totalSamples, which is over 32 bits.  Each time you read  
a byte, add 8 to your bit count, and shift any existing bits in your  
accumulator around to make room for the new bits.  When pulling  
values out of the accumulator, you do that based upon the number of  
bits requested.

In other words, instead of:

GetEndianBytes(streamArray, streamOffset, numBytes);

... you should implement:

(long long)GetBigEndianStreamBits(streamHandle, outputAddressPointer,  
(unsigned)numBits);

The return value will have to be 64-bit to handle totalSamples.  The  
nice thing is that you won't need any indexing or bit shifting,  
because GetBigEndianStreamBits() will directly return the value you  
ask for, based upon the number of bits requested.

I mean, you can continue to try and hack things, or you can simply  
write your stream parser the way it's supposed to be implemented.   
The good news is that if you do it right, then your code is portable  
to situations where you have a real stream, such as over the  
internet.  Your code hack so far will only work with files, not with  
real streams (and it's not really working completely, anyway).

It's really not that hard.  I've written MPEG metadata parsers in  
less than a day.  Once you implement the bit function, the rest is  
super easy.  Just don't try to map the exact stream structure into a  
literal C struct.

Brian Willoughby
Sound Consulting



More information about the Flac-dev mailing list