71 lines
6.1 KiB
Plaintext
71 lines
6.1 KiB
Plaintext
[video member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Implementing PNG Reconstruction Filters" vod_platform=youtube id=M27KjGYbWvs annotator=Miblo]
|
|
[0:00][Recap and set the stage for the day continuing with our PNG reader][:compression :parsing :speech]
|
|
[2:44][Our understanding of the DEFLATE encoding][:compression :parsing :speech]
|
|
[6:00][Pull up our piece of structured :art][:drawing]
|
|
[7:43][Create a simpler piece of structured :art][:drawing]
|
|
[11:33][A few thoughts on structured :art][:speech]
|
|
[12:33][Add a BYTE == 1 case in ParsePNG() by advice of @mmozeiko][:compression :parsing]
|
|
[13:51][:Run our PNG reader on gimp_8x8_compression0.png to see which :compression case we hit in ParsePNG()][:parsing]
|
|
[16:19][Prevent ParsePNG() from performing integral promotion on the LEN != NLEN comparison][:parsing]
|
|
[16:43][Continue to step through ParsePNG()][:compression :parsing :run]
|
|
[18:32][Prevent ParsePNG() from calling EndianSwap() on the LEN][:memory :parsing]
|
|
[18:53][Continue to step through ParsePNG() to completion, and inspect the DecompressedPixels][:compression :parsing :run]
|
|
[24:57][Deduce that the DecompressedPixels contain row transform filter indicators that we have not yet learnt][:compression :parsing :run]
|
|
[26:56][Rename DecompressedPixels to FinalPixels, initialising it before the :parsing loop in ParsePNG()]
|
|
[27:59][Crash ~4coder and step into it to see what's going on][:admin]
|
|
[30:10][Continue setting up ParsePNG() to apply the filters to the FinalPixels][:parsing]
|
|
[33:27][4.3 Reference image to PNG image transformation[ref
|
|
site=W3C
|
|
page="Portable Network Graphics (PNG) Specification (Second Edition)"
|
|
url=https://w3.org/TR/2003/REC-PNG-20031110/]][:parsing :research]
|
|
[40:27][9 Filtering (PNG)[ref
|
|
site=W3C
|
|
page="Portable Network Graphics (PNG) Specification (Second Edition)"
|
|
url=https://w3.org/TR/2003/REC-PNG-20031110/]][:parsing :research]
|
|
[49:05][Finish setting up ParsePNG() to apply the filters to our parsed pixels, noting that it seems tailor-made for SIMD[ref
|
|
site=W3C
|
|
page="Portable Network Graphics (PNG) Specification (Second Edition)"
|
|
url=https://w3.org/TR/2003/REC-PNG-20031110/]][:parsing :performance]
|
|
[1:08:10][Introduce our PNGFilter*() functions[ref
|
|
site=W3C
|
|
page="Portable Network Graphics (PNG) Specification (Second Edition)"
|
|
url=https://w3.org/TR/2003/REC-PNG-20031110/]][:parsing]
|
|
[1:22:16][Introduce PNGFilterReconstruct() to perform the filtering part of ParsePNG()][:parsing]
|
|
[1:26:03][Step through PNGFilterReconstruct() to see what we end up with][:parsing :run]
|
|
[1:29:32][Add assertions in the untested Average and Paeth filter cases in PNGFilterReconstruct()][:parsing]
|
|
[1:30:55][:Run the program on the compressed gimp_8x8.png to see that it looks right][:compression :parsing]
|
|
[1:39:16][Draw a more complicated image][:art :drawing]
|
|
[1:41:00][:Run it on our more complicated, uncompressed image and hit the Paeth filter]
|
|
[1:42:40][Remove that assertion from the Paeth filter case in PNGFilterReconstruct()][:parsing]
|
|
[1:42:53][Step through PNGFilterReconstruct() into PNGFilter4() (Paeth) to see that it looks reasonable][:parsing :run]
|
|
[1:46:21][:Run it on our compressed complex image, to see that it look good too][:parsing]
|
|
[1:46:57][:Run it on our fully complex gimp_test.png and crash in ParsePNG()][:parsing]
|
|
[1:48:41][Step through ConsumeSize() to realise that the crash occurs even in the first IDAT chunk, so the bug must be in the Huffman decode][:parsing]
|
|
[1:53:53][Perform coverage checking on every EncodedLen case in ParsePNG() to find that the 16-long (0x10) case is never used in the successfully parsed file][:parsing :run]
|
|
[1:58:56][3.2.7 Compression with dynamic Huffman codes BTYE=10[ref
|
|
site=IETF
|
|
page="DEFLATE Compressed Data Format Specification version 1.3"
|
|
url=https://www.ietf.org/rfc/rfc1951.txt]][:compression :research]
|
|
[2:01:44][Step through the BTYPE=10 case in ParsePNG() to see that the LitLenDistTable seems to be built correctly][:compression :parsing :run]
|
|
[2:02:40][Consider our current situation and ways to proceed][:parsing :speech]
|
|
[2:03:18][Q&A][:speech]
|
|
[2:03:38][@ratchetfreak][Q: The LEN, NLEN is so the decompressor can resync with a compressor if a block got corrupted (and the compressor emitted an empty block) by looking for the bytes 0000FFFF, mostly handy for byte streams][:compression]
|
|
[2:04:09][@rooctag][Q: C is up and left[ref
|
|
site=W3C
|
|
page="Portable Network Graphics (PNG) Specification (Second Edition)"
|
|
url=https://w3.org/TR/2003/REC-PNG-20031110/]][:parsing]
|
|
[2:05:26][Fix PNGFilterReconstruct() to correctly filter Paeth][:parsing]
|
|
[2:06:24][@geekengale][Q: Did I see for(;;) in your code? What's that for / how does it work?][:language]
|
|
[2:07:56][@john_diresta][Q: In the :memory window when you were writing the "decoded" pixel (non-compressed 8x8) you were writing to some memory that you have not allocated, accordingly to the ASCII representation, there were some strings about a path in windows]
|
|
[2:09:16][@Brian][Q: In Day 055 when you create the hash table, you added your TODO on getting a better hash. Other than for educational purposes investigating better hashes, what kinds of problems would you start to see if the hash was not good enough? Like would it pop-up when you are profiling or something? Would you get any errors?][:"data structure"]
|
|
[2:11:09][@sharlock93][Q: There is a VS plugin that lets you see images in memory. It's called Image Watch. Was pretty useful when I did the PNG decoding][:parsing]
|
|
[2:11:38][@john_diresta][Q: Oh okay, it's that it looked strange. Usually it's filled with 0xDD of 0xCD if I remember correctly, or maybe it's just for stack :memory?]
|
|
[2:13:22][@uplinkcoder][Q: Try a big empty image which compresses very well]
|
|
[2:14:49][@quickshift_][Q: So on Linux, would you have to use calloc() instead of VirtualAlloc() or is there an alternative?[ref
|
|
site="Linux Programmer's Manual"
|
|
page="mmap(2)"
|
|
url=http://man7.org/linux/man-pages/man2/mmap.2.html]][:memory]
|
|
[2:15:32][@sgtrumbi][Q: Will you integrate the decoder directly into the game or into the simple_preprocessor?]
|
|
[2:16:04][Close it up with a glimpse into the future][:speech]
|
|
[/video]
|