Kindle Video Playback Hack
Prerequsite
- The Kindle needs to be jailbroken.
- Terimnal access on Kindle (Kterm or SSH)
- Generate a directory to store all temporary files on Kindle, using
/mnt/us/demo/for example in this tutorial.
- Generate a directory to store all temporary files on Kindle, using
- FFmpeg
Slice Video Frames
i=INPUT.mp4; w=1236; h=1648;
# Adjust resolution accordingly:
# - Kindle Paperwhite (11th gen.): 1236x1648
# - Kindle Paperwhite (12th gen.): 1264×1680
# - Kindle Colorsoft: 1264×1680
mkdir -p ./frames && ffmpeg -i "$i" \
-vf "transpose=1,\
scale=$w:$h:force_original_aspect_ratio=decrease,\
pad=$w:$h:(ow-iw)/2:(oh-ih)/2,\
format=gray" \
-r 5 ./frames/frames_%04d.png
Copy all PNG images (the frames folder) to Kindle, put under /mnt/us/demo/.
Transcode Audio
Export raw PCM audio (Signed 16-bit Little-Endian, 44100 Hz, Stereo):
i=INPUT.mp4;
ffmpeg -i "$i" -f s16le -acodec pcm_s16le -ar 44100 -ac 2 audio.raw
Copy the PCM file audio.raw to Kindle, put under /mnt/us/demo/.
E-Ink Refreshing Control
FBInk
-
Download FBInk source code from https://github.com/NiLuJe/FBInk/releases.
-
(For macOS) Install cross-compiling tools via HomeBrew:
brew tap messense/macos-cross-toolchains brew install messense/macos-cross-toolchains/armv7-unknown-linux-gnueabihf -
Compile FBink for Kindle: change directory to the root directory of FBInk source code, and run the code snippet to start compiling.
make clean make KINDLE=1 \ CROSS_COMPILE=armv7-unknown-linux-gnueabihf- \ CC=armv7-unknown-linux-gnueabihf-gcc \ STATIC=1 \ STB_IMAGE=1 \ static -
Copy and paste the binary file
fbinkof FBink under the folder./Release/to Kindle, put under/mnt/us/demo/.
eips
No extra installation needed, since eips (Electronic Ink Printing System) is a built-in CLI tool on Kindle to control the E-ink refreshing.
On older devices (Paperwhite 11th gen. and earlier), eips (v1) is quite limited compared with FBink.
On newer devices (Paperwhite 12th gen. and later), Amazon upgraded it to eips_v2 which supports more features than v1 but still limited compared to FBInk.
Shell Script
Run on kindle to orchestrate the “video” playback, put under /mnt/us/demo/.
Shell Script Template:
#!/bin/sh
# 1. Pause Kindle UI
stop framework 2>/dev/null
# 2. Force refreshing e-ink (gc16: Grayscale Clear 16-level Waveform)
/mnt/us/demo/fbink -q -c -f -W GC16
# Alternative: eips_v2 clear -f -m gc16 -W
# 3. Play audio
# Legacy GStreamer 0.10 (Older Kindle firmware, including Kindle Paperwhite 11th gen. and older models)
gst-launch-0.10 -q filesrc location=/mnt/us/demo/audio.raw ! \
"audio/x-raw-int,endianness=(int)1234,signed=(boolean)true,width=(int)16,depth=(int)16,rate=(int)44100,channels=(int)2" ! \
mixersink &
# Alernative: GStreamer 1.0 (Modern firmware, including Kindle Colorsoft, Paperwhite 12th gen. and newer models)
# gst-launch-1.0 -q filesrc location=/mnt/us/demo/audio.raw ! \
# "audio/x-raw,format=S16LE,layout=interleaved,rate=44100,channels=2" ! \
# mixersink &
AUDIO_PID=$!
# 4. Play frames
get_time_ms() {
awk '{printf "%d\n", $1 * 1000}' /proc/uptime
}
# Based on the frame rate, using 5fps (200ms) for example here
FRAME_INTERVAL=200
# Compensation for hardware refreshing latency, adjust based on the device, using 80ms for example here
LATENCY_OFFSET=80
START_TIME=$(get_time_ms)
FRAME_INDEX=0
for img in /mnt/us/demo/frames/*.png; do
TARGET_TIME=$(( START_TIME + (FRAME_INDEX * FRAME_INTERVAL) - LATENCY_OFFSET ))
CURRENT_TIME=$(get_time_ms)
if [ $(( CURRENT_TIME - TARGET_TIME )) -gt $FRAME_INTERVAL ]; then
FRAME_INDEX=$((FRAME_INDEX + 1))
continue
fi
if [ $CURRENT_TIME -lt $TARGET_TIME ]; then
usleep $(( (TARGET_TIME - CURRENT_TIME) * 1000 ))
fi
/mnt/us/demo/fbink -q -f -W A2 -g file="$img"
# Alternative: eips_v2 png "$img" -g -m a2 -W
FRAME_INDEX=$((FRAME_INDEX + 1))
done
kill -9 $AUDIO_PID 2>/dev/null
# 5. Resotre Kindle UI
start framework
To start the “video” playback, simply connect the Kindle to a Bluetooth audio device, and run the shell script, named as play_demo for example in this tutoial.
/mnt/us/demo/play_demo.sh
Demo
- Bilibili: https://www.bilibili.com/video/BV1Rqhw6CEaz/
- YouTube: