Monday, March 23, 2009

FLAC parsing

Let me start by saying that I very much dislike the raw FLAC format! After a lot of failed attempts I finally got a parser working. Part of the frustration was due to FLAC, and the other part was the way FFmpeg's parsing works.

First issue: reliable frame detection
  • Using only the 16-bit frame header gives many many false positive frame start matches.
  • Using the frame header + frame CRC-16 gives a handful of false positives.
  • The only reliable way seems to be a full frame header validation including the header CRC-8, along with checking the CRC-16 for the whole frame.
Second issue: using FFmpeg's parser to combine pieces of frames from chunks of data
  • Frame headers are variable-sized from 6 bytes to 16 bytes.
  • The whole frame can be as small as 11 bytes, and silent frames are often less than 16 bytes.
  • ff_combine_frame() only keeps up to 8 bytes of state information
So, the way I finally ended up with a working parser was to basically use the same strategy as the buffering that's done currently in the FLAC decoder, but do it with ff_combine_frame().
  1. read first header to get starting point for block size/channels/bps
  2. estimate maximum frame size
  3. buffer enough data for maximum frame
  4. detect next header
  5. update maximum frame size with header info
  6. update buffer
  7. return frame start and size
  8. goto 3
There are special cases for when there is no more data to read and for checking up to 11 bytes from the end of the buffer to make sure there isn't a small frame that's not being detected due to the 16-byte state size.

No comments: