Skip to content

Instantly share code, notes, and snippets.

@Trumeet
Created January 16, 2021 03:03
Show Gist options
  • Save Trumeet/fd4e93d69d78dc4ac14d5cac42dfff7e to your computer and use it in GitHub Desktop.
Save Trumeet/fd4e93d69d78dc4ac14d5cac42dfff7e to your computer and use it in GitHub Desktop.
Linux Terminal has the capability of displaying 8-bit colour, so why not play something on it?
import org.jcodec.api.FrameGrab;
import org.jcodec.common.io.NIOUtils;
import org.jcodec.common.model.Picture;
import org.jcodec.scale.AWTUtil;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
/**
* Linux Terminal has the capability of displaying 8-bit colour, so why not play something on it?
*
* Libraries:
* <pre>
* implementation 'org.jcodec:jcodec:0.2.5'
* implementation 'org.jcodec:jcodec-javase:0.2.5'
* </pre>
*
* Pre-scaled video required. Separate wav audio required. Scale the video so that the size will not exceed $COLUMNS pixels in width by $LINES pixels in height.
* $COLUMNS and $LINES variables required.
* WTFPL
*
* https://gist.github.com/Trumeet
*
* @author YuutaW
*/
public class JPlayer {
public static void main(String... args) throws Throwable {
final int mspf = 1000 / 30;
final int columns = Integer.parseInt(System.getenv("COLUMNS"));
final int lines = Integer.parseInt(System.getenv("LINES"));
final FrameGrab grab = FrameGrab.createFrameGrab(NIOUtils.readableChannel(new File(args[0])));
int[][] framebuffer = new int[columns][lines];
AudioInputStream audioIn = AudioSystem.getAudioInputStream(new File(args[1]));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
System.out.print("\033[2J");
System.out.print("Press any key to start...");
System.in.read();
System.out.print("\033[?25l");
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.print("\033[?25h\u001B[0m");
}));
final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out),
2 ^ 32);
clip.start();
while(true) {
final long start = System.currentTimeMillis();
final Picture picture = grab.getNativeFrame();
if(picture == null) break;
final BufferedImage image = AWTUtil.toBufferedImage(picture);
for (int row = 0; row < image.getHeight(); row ++) {
for (int column = 0; column < image.getWidth(); column ++) {
final int gray = image.getRGB(column, row) & 0xFF;
if(framebuffer[column][row] != gray) {
render(gray, row, column, writer);
}
framebuffer[column][row] = gray;
}
}
writer.flush();
final long took = System.currentTimeMillis() - start;
if(took <= mspf) {
Thread.sleep(mspf - took);
}
}
}
private static void render(final int gray, final int line, final int column,
Writer writer) throws IOException {
int foregroundColorCode;
int backgroundColorCode;
if(gray <= 63) {
// Black.
foregroundColorCode = 30;
backgroundColorCode = 40;
} else if(gray <= 126) {
// Dark Gray
foregroundColorCode = 90;
backgroundColorCode = 100;
} else if(gray <= 189) {
// Light Gray
foregroundColorCode = 37;
backgroundColorCode = 47;
} else {
// White
foregroundColorCode = 97;
backgroundColorCode = 107;
}
// We don't use format here, since it's slow.
// '[%d;%dH[%dm[%dm '
final StringBuilder stringBuilder = new StringBuilder()
.append("\033[")
.append(line)
.append(";")
.append(column)
.append("H\u001B[")
.append(foregroundColorCode)
.append("m\u001b[")
.append(backgroundColorCode)
.append("m ");
writer.write(stringBuilder.toString());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment