[video output=day455 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Decoding PNG Huffman Tables" vod_platform=youtube id=fuPhHEBTShI annotator=Miblo]
[0:00][Recap and set the stage for the day decoding Huffman][:compression :speech]
[0:48][Bring us up to speed with ParsePNG()][:compression :research]
[2:09][Return to the PNG[ref
    site=W3C
    page="Portable Network Graphics (PNG) Specification (Second Edition)"
    url=https://w3.org/TR/2003/REC-PNG-20031110/] and DEFLATE[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt] specifications with a few words on compressor creation][:compression :research]
[6:17][Set up to handle DEFLATE's use of Huffman coding[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :research]
[10:24][Slightly organise handmade_png.h and let ComputeHuffman() process the entire HCLENSwizzle table][:compression]
[15:37][Stupid Huffman Decoder][:blackboard :compression]
[21:09][LUT+Shift Algorithm, Patent Pending 2018®™][:blackboard :compression]
[23:01][Consult the DEFLATE spec for the maximum code length[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :research]
[28:10][Consider the feasibility of building a 32k lookup table][:compression :memory :speech]
[29:46][Introduce AllocateHuffman() and png_huffman_entry struct][:compression :memory]
[36:40][Determine to implement HuffmanDecode()][:compression :speech]
[37:56][Encoding symbols: "Numerical" vs "Bit"][:blackboard]
[39:22][Relieve png_huffman_entry of containing SymbolLength][:compression]
[40:08][Introduce PeekBits(), the same as ConsumeBits() just without shifting the bits, and DiscardBits()][:parsing]
[46:13][Implement HuffmanDecode(), augmenting png_huffman with MaxCodeLengthInBits][:compression]
[49:30][Dive into implementing ComputeHuffman()][:compression]
[53:25][Determining symbol code locations][:blackboard :compression]
[55:16][Enable ComputeHuffman() to correctly place symbol codes in the table][:compression]
[59:20][Start to enable ComputeHuffman() to build those Huffman codes, in conjunction with the DEFLATE specification[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression]
[1:03:12][Come to understand DEFLATE's use of Huffman coding[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt] specifications with a few words on compressor creation][:compression :research]
[1:08:27][Enable ComputeHuffman() to find the numerical value of the smallest code for each code length, and assign numerical values to all the codes][:compression]
[1:15:13][Consider ourselves done with that part of it][:compression :speech]
[1:15:46][Make ParsePNG() allocate our Huffman tables][:compression :memory]
[1:18:54][Determine to go over the LitLenDistTable construction routine and implement the filters][:compression :speech]
[1:19:58][Step through ParsePNG() and inspect our data, in conjunction with the DEFLATE specification[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :run]
[1:25:15][Fix AllocateHuffman() to set the MaxCodeLengthInBits][:compression]
[1:25:40][Continue to step through ComputeHuffman() and consider the use of MaxCodeLengthInBits in the ArbitraryBits computation][:compression :run]
[1:29:35][Change AllocateHuffman() to set the MaxCodeLengthInBits according to the length of that length it was passed in, i.e. 2^Length][:compression]
[1:31:30][:Run it and hit our assertion in AllocateHuffman()][:compression]
[1:31:44][Revert AllocateHuffman() and instead make ParsePNG() pass 8 to it for the DictHuffman allocation][:compression]
[1:32:16][Continue to step through ComputeHuffman() and inspect our data][:compression :run]
[1:33:38][Assert in HuffmanDecode() that BitsUsed != 0][:compression]
[1:34:20][Continue to step through ParsePNG(), hit our assertion in HuffmanDecode() and investigate why][:compression :run]
[1:35:26][Carefully read 3.1.1 Packing into bytes[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt] to discover that Huffman codes are packed in the opposite direction to everything else][:compression :research]
[1:45:30][Make ComputeHuffman() flip the bits of Huffman codes][:compression]
[1:48:12][Step through ComputeHuffman() to watch our bits flip][:compression :run]
[1:49:07][Fix ComputeHuffman() to flip all our bits correctly][:compression]
[1:50:13][Step through ComputeHuffman() to see our correctly flipping bits][:compression :run]
[1:51:17][Consider packing the Huffman codes backwards][:compression :speech]
[1:53:12][Step through HuffmanDecode() until we assert][:compression :run]
[1:55:57][Make ParsePNG() increment LitLenCount in the LitLenDistTable construction routine][:compression]
[1:56:50][:Run until we crash in HuffmanDecode()][:compression]
[1:57:09][Temporarily prevent ComputeHuffman() from flipping the Huffman bits][:compression]
[1:57:26][:Run it and crash earlier][:compression]
[1:58:05][Q&A][:speech]
[1:58:17][Fix typo in the LitLenDistTable construction in ParsePNG()[ref
    site=GitHub
    page="HandmadeHero / cpp/Issues / Wrong value in LitLenDistTable for value of 17"
    url=https://github.com/HandmadeHero/cpp/issues/74]][:compression]
[1:59:30][Close that issue[ref
    site=GitHub
    page="HandmadeHero / cpp/Issues / Wrong value in LitLenDistTable for value of 17"
    url=https://github.com/HandmadeHero/cpp/issues/74]][:admin :compression]
[2:00:15][@ratchetfreak][Q: Don't the bits when reading the table need to be reversed as well?][:compression]
[2:00:53][@spensasaurusrex][Q: How many hours long is this series now? I've dabbled in the first dozen or so episodes, but trying to catch up on so much content is discouraging]
[2:01:12][@mmozeiko][Q: You said multiple times that PNG spec does not allow fixed Huffman codes, but this is not true: PNG spec explicitly says that both fixed and dynamic Huffmans are allowed (section 10.1)][:compression]
[2:01:28][@somebody_took_my_name][Q: In AllocateHuffman() you use the sizeof the huffman table not the entries to malloc data][:memory]
[2:01:38][Fix typo in AllocateHuffman()][:memory]
[2:02:11][Read 10.1 :Compression method 0[ref
    site=W3C
    page="Portable Network Graphics (PNG) Specification (Second Edition)"
    url=https://w3.org/TR/2003/REC-PNG-20031110/]][:compression :research]
[2:03:04][@ratchetfreak][Q: When reading the 3 bit lengths you'd read, e.g. 0b011, but I believe it should be 0b110[ref
    site=IETF
    page="DEFLATE Compressed Data Format Specification version 1.3"
    url=https://www.ietf.org/rfc/rfc1951.txt]][:compression]
[2:05:51][@ratchetfreak][Q: Yeah, you are correct][:compression]
[2:08:29][@ratchetfreak][Q: Only Huffman codes are bit-reversed when looking at the bit from first byte to last, and most significant bit to least significant][:compression]
[2:09:37][Close down the stream][:speech]
[/video]
