Bad Apple on a MiniDisc Player
January 12, 2024
So... I got Bad Apple!! to play on a MiniDisc player. The process was interesting, so I'll write about what I did, but before that, check it out!!
Now that you've seen it, the basic premise behind how it works is very simple: draw bitmaps in the display buffer of the player that correspond to the frames of the video. I knew something like this had to be possible from the work Sir68k did creating MiniTris, which is a playable version of tetris on Type-S MiniDisc devices. Because I knew it was possible to write individual pixels on the display, I next had to find out how to get the compiled C code on to the device in the first place!
The method I figured out was quite impractical, but it did work. Since I couldn't figure out how to use the NetMD IDE by Asivery, I went with an alternative route. Using the Tetris upload script found in the netmd-exploits project, I replaced the compiled Tetris bytes for my firmware (V1.5) and after recompiling netmd-exploits and writing my own small NodeJS project to utilize it, I was able to load my code on to the player, and have it be executed by the exploit! I then modified the Tetris code to draw pixels from a 7 byte bitmap to the display.
static void drawFrame(const uint8_t frame[]) {
for (int y = 0; y < 6; y++) {
for (int x = 0; x < 7; x++) {
int pixel_value = (frame[y] >> x) & 1;
set_pixel((8 - x), y, !pixel_value);
}
}
}
However, I still had the task of getting the bitmaps on to the device in the first place. With its limited amount of available memory for an application and the requirements for displaying the data as a straight bitmap, I ended up processing the data in a rather unusual way. To create the bitmap array which would end up in the C code, I first used FFMPEG to convert the original Bad Apple video into a series of 8x7 bitmaps at 8fps. This left me with 1753 frames, each of which was 7 bytes long, which comes out to 12.2kB of used memory. This fit nicely into the player's 14.8kB of program memory available using the exploit. To actually put the array into the code, I opted to create a C array which I could paste into the code I already had. I accomplished this by creating a Python script which read through all the frames, extracted the colors from them as either 0s or 1s, and then created a file with a C-style array in it. Each frame looked somewhat like the following:
...
{
0b11111111,
0b11111100,
0b10111100,
0b10111101,
0b11111101,
0b11011100,
0b10011100,
},
...
After that was complete, I pasted it into the C program to be generated for the player, compiled it, uploaded the code, and the result is the video!
Please check out the awesome projects that allowed me to create this!