Video2NAND – 滥用视频编码器以获取强大的计算能力
Video2NAND – Abusing video codecs for great computational power

原始链接: https://sharedobject.blog/posts/vp8-combinatorial-logic/

本文探讨了如何利用 VP8 视频编码器的预测机制来模拟组合逻辑电路。通过操纵编码器在 8x8 像素块内的预测方式,作者展示了视频帧可以被重新用作计算载体。 该系统将逻辑“真”和“假”表示为白色(255)和黑色(0)的像素块。通过利用编码器的水平和垂直预测模式,“导线”得以在帧内传递数值。功能完备的逻辑门(特别是 NOT 和 AND 门)是通过“真运动”(TM_PRED)预测构建的,该预测会对相邻像素块进行算术运算。通过巧妙设置这些 TM_PRED 块的输入,作者创建了能够执行复杂真值表所需运算的组件。 这种方法有效地将视频文件转化为了可编程逻辑电路。作者提出,这一概念有望扩展为一种合成工具,将 Verilog 代码编译为 VP8 帧,甚至可以通过帧间预测来探索时序逻辑。

```Hacker News 最新 | 过往 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 Video2NAND – 滥用视频编解码器以获得强大算力 (sharedobject.blog) 8 分,由 firer 发布于 1 小时前 | 隐藏 | 过往 | 收藏 | 讨论 | 帮助 考虑申请 YC 2026 年秋季批次!申请截止日期为 7 月 27 日。 准则 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:```
相关文章

原文

Much has been written about turning NAND gates into computers, yet knowledge of how to build these NAND gates is not as common. You may think that it’s in the realm of transistors and electrical engineering, but we’ll explore a much more exotic substrate: the video codec.

Specifically, we’ll talk about the VP8 video codec and how to abuse its prediction mechanisms to simulate combinatorial logic. Our goal is to build up a set of composable “gadgets” which can construct arbitrary logic circuits.

A Tiny Bit About Video Codecs

Video codecs are standards which describe a method of encoding a video (a series of images) into some bitstream, and how to decode that bitstream back into the original video. Instead of prescribing exactly how to encode a video, they usually define a general structure and some set of primitives which can be used to encode the video. As such, different video encoder implementations (or even the same encoder with different settings) may encode the same video differently, but all decoders are expected to be able to reconstruct the video regardless.

We will not explain the whole inner-workings of VP8, our video codec of choice, and instead focus on a subset relevant to our purposes. Furthermore, the following explanations are not entirely accurate, in an attempt to simplify the prerequisite knowledge to its essence. If you are interested in learning more about video codecs, I’d recommend reading the Theora spec, which is surprisingly readable.

You can also read this follow-up post which describes some glossed over details.

In a sense, a video is just a series of images. In video codec jargon, these images are called “frames” where each frame is grid of pixels. Frames are generally divided into to two kinds: key-frames and inter-frames.

A frame divided into 8x8 blocks of pixels

Key-frames are frames which are encoded independently of other frames. All data required to reconstruct the image is contained within the representing frame. The pixel data may be encoded directly into the frame, or predicate using intra-frame prediction. Intra-frame prediction allows the encoder to state that a certain block of the image can be predicted from another nearby block.

Since VP8 decodes these blocks row-by-row, from the top-left down to the bottom-right, the intra-frame prediction primitives it offers allow predicting a block using the row above it, the column to the left of it, and the top-left pixel between them.

top left

top[0]

top[1]

top[2]

top[3]

left[0]

left[1]

left[2]

left[3]

A block and the pixels it uses for prediction

Inter-frames are frames which exploit the fact that subsequent frames don’t change much, and allow predicting blocks of pixels based on previously decoded frames. They offer the same encoding primitives as key-frames, as well as allowing inter-frame prediction: describing a block by referencing a block from a previous frame.

We will build our combinatorial circuits purely using key-frames. Partly because the semantics of combinatorial-vs-sequential logic map well to key-frames-vs-inter-frames, and partly because the extra challenge of a limited toolkit is more interesting.

Wires and Gates

Combinatorial circuits are built up out of inputs, outputs, wires and gates. In our case, instead of electrical current representing True and False, each block in the frame will either be completely white (all pixel values set to 255) or completely black (all pixels values set to 0), respectively.

And we’ll model wires going right or down using H_PRED and V_PRED prediction modes. H_PRED stands for “horizontal prediction”, and means that every pixel value in the block is predicted by copying the value of the pixel to the left of it. Similarly, V_PRED stands for “vertical prediction”, and copies the value from above instead.

Drawing the frame as a grid of blocks:

Inputs will be represented as non-predicted blocks, set to a constant value of either completely white or completely black. Outputs are simply labeled wire blocks:

At this point, only logic gates are left. In order for our system to be functionally complete, meaning it can describe any truth-table, it is enough to construct two gates: NOT and AND. We could have chosen a different functionally complete set of gates, such as just a NAND, but as we’ll see these gates are trivial to construct.

Both gates will gate constructions will use the TM_PRED prediction mode. It stands for “True Motion prediction”, and is only slightly more complex than the prediction modes we’ve seen so far. In a TM_PRED block, the value of each pixel is computed as the sum of the corresponding pixel in the above row and the corresponding pixel in the left column, minus the value of the top-left pixel. So for a pixel with row i and column j, the value will be left[i] + top[j] - top_left.

top left

top[0]

top[1]

top[2]

top[3]

left[0]

left[1]

left[1]
+ top[2]
- top_left

left[2]

left[3]

TM prediction calculation at block cell (2,1)

All of our blocks are homogeneous - either completely black or white. This means that top[0] = top[1] = top[2] = ... and likewise left[0] = left[1] = left[2] = .... Leading to a simplified calculation of a TM_PRED block: left + top - top_left:

top left

top

left

left
+ top
- top_left

Simplified TM prediction

Since pixel values are clamped between 0 and 255, a NOT gate is equivalent to the formula 255 - INPUT (verify for yourself by substituting INPUT with either 0 or 255). We can represent this formula using a TM_PRED block. Assume the input is the top_left pixel, set the top row to all 255, and the left column to all 0 (or vice-versa). The output of the gate is the right and bottom of the TM_PRED block, which can be propagated further using the wire blocks we’ve described above.

Similarly, we can construct an AND gate by setting top_left to 255, the first input to the top row and the second input to the left column. A TM_PRED block in such a setup will represent the formula A + B - 255. Plugging in all the possible input values of A and B, we can see that the output is exactly an AND gate:

Now that we’ve constructed all the basic gadgets, we can combine them to create various other gates and circuits, including the venerable NAND:

Wrapping Up

Hopefully you’ve enjoyed this cross-domain journey, and learned something about video codecs, combinatorial logic or weird machines. We’ve only just scratched the surface, there are still a lot of open questions and directions we can take this in. Could we optimize the gadgets to be smaller? What about integrating these ideas into a synthesis tool, possibly enabling synthesis of Verilog down to VP8 frames? Or maybe, explore sequential logic and how we could implement it using inter-frames?

联系我们 contact @ memedata.com