As I said in the previous post, I wanted to add ZMBV support to NihAV
, mostly because it is rather simple codec (which means I can write a decoder and an encoder for it without spending too much time), it’s lossless and supports various bit-depths too (which means I can encode various content into it preserving the original format).
I still had to improve my deflate
support (both decompressing and compressing) a bit to support the way the data is stored there. At least now I mostly understand what various flags are for.
First of all, by itself deflate
format specifies just a bitstream split into blocks of data that may contain any amount of coded data. And these blocks start at the next bit after the previous block has ended, no byte aligning except by chance or after a copy block (which aligns bitstream before storing length and block contents).
Then, there is raw format used in various formats (like Zip or gzip) and there’s zlib
format used for most cases data is stored as part of some other format (that means you have two initial bytes like 0x78 0x5E
and 2×2 bytes of checksum in the end).
So, ZMBV uses unterminated stream format: first frame contains zlib
header plus one or several blocks of data padded with an empty copy block to the byte limit, next frame contains continuation of that stream (also one or more blocks padded to the byte boundary) and so on. This is obviously done so you can decode frames one after another and still exploit the redundancy from the previously coded frame data if you’re lucky.
Normally you would start decoding data and keep decoding it until the final block (there’s a flag in block header for that) has been decoded—or error out earlier for insufficient data. In this case though we need to decode data block, check if we are at the end of input data and then return the decoded data. Similarly during data compression we need to encode all current data and pad output stream to the byte boundary if needed.
This is not hard or particularly tricky but it demonstrates that deflated data can be stored in different ways. At least now I really understand what that Z_SYNC_FLUSH
flag is for.