Skip to content

Instantly share code, notes, and snippets.

@vizv
Last active December 13, 2019 00:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vizv/93944436425b7b7eef7f1eeaea4fc6c6 to your computer and use it in GitHub Desktop.
Save vizv/93944436425b7b7eef7f1eeaea4fc6c6 to your computer and use it in GitHub Desktop.
QR code video encoder / decoder
#!/bin/sh -e
# preflight & usage
CMD="$1"
FILE="$2"
[ -z "$CMD" ] || [ -z "$FILE" ] && {
cat >&2 <<EOF
usage: $(basename "$0") encode FILE
$(basename "$0") decode FILE
EOF
exit 1
}
# command check
case "$CMD" in
encode)
FILE_OUT="$FILE.webm"
;;
decode)
FILE_OUT="$(dirname "$FILE")/recreated-$(basename "${FILE%.*}")"
;;
*)
echo "[-] Command \"$CMD\" is invalid" >&2
exit 1
;;
esac
FILE_OUT_BASE="$(basename "$FILE_OUT")"
# set default configuration
[ -z "$CHUNK_PREFIX" ] && CHUNK_PREFIX='chunk'
[ -z "$CHUNK_SIZE" ] && CHUNK_SIZE=512
[ -z "$DOT_PIXEL" ] && DOT_PIXEL=8
# calculate chunk length
FILE_SIZE="$(stat --printf='%s' "$FILE")"
CHUNKS=$(((FILE_SIZE - 1) / CHUNK_SIZE + 1))
CHUNK_SUFFIX_LEN="${#CHUNKS}"
# create temporary for processing
TMP_DIR="$(mktemp -u)"
mkdir -p "$TMP_DIR"
# setup trap
cleanup() { echo "[+] cleaning up..." >&2; rm -rf "$TMP_DIR"; }
trap cleanup HUP INT QUIT ABRT
# encode
[ "$CMD" = 'encode' ] && {
echo "[+] Splitting file..."
split --suffix-length="$CHUNK_SUFFIX_LEN" \
--numeric-suffixes=1 \
--bytes="$CHUNK_SIZE" \
"$FILE" \
"${TMP_DIR}/${CHUNK_PREFIX}-"
echo "[+] Generating QR codes..."
for CHUNK in "${TMP_DIR}/${CHUNK_PREFIX}"-*; do
echo " [+] Generating QR code for ${CHUNK}"
qrencode --8bit \
--size="$DOT_PIXEL" \
--read-from="$CHUNK" \
--output="${CHUNK}.png"
done
echo "[+] Creating video..."
ffmpeg -loglevel 16 \
-i "${TMP_DIR}/${CHUNK_PREFIX}-%0${CHUNK_SUFFIX_LEN}d.png" \
"${TMP_DIR}/${FILE_OUT_BASE}"
# set output file as FILE chunks for decode test
ORIGINAL_FILE="$FILE"
FILE="${TMP_DIR}/${FILE_OUT_BASE}"
FILE_OUT_BASE="$(basename "$ORIGINAL_FILE")"
# clean up
rm -f "${TMP_DIR}/${CHUNK_PREFIX}"-*
}
# decode / decode test
[ "$CMD" = 'decode' ] || [ "$CMD" = 'encode' ] && {
echo "[+] Extract QR codes from the video..."
ffmpeg -loglevel 16 \
-i "$FILE" \
"${TMP_DIR}/${CHUNK_PREFIX}-%0${CHUNK_SUFFIX_LEN}d.png"
echo "[+] Scanning QR codes..."
for QRCODE in "${TMP_DIR}/${CHUNK_PREFIX}"-*.png; do
echo " [+] Scanning QR code for ${QRCODE}"
zbarimg --quiet \
--raw "$QRCODE" \
| iconv --from=UTF-8 \
--to=ISO-8859-1 \
| head --bytes="$((CHUNK_SIZE + 1))" \
| head --bytes=-1 >"${QRCODE}.bin"
done
echo "[+] Rebuilding file..."
cat "${TMP_DIR}/${CHUNK_PREFIX}"-*.png.bin > "${TMP_DIR}/${FILE_OUT_BASE}"
# clean up
rm -f "${TMP_DIR}/${CHUNK_PREFIX}"-*
# for decode, move recreated file back directly
[ "$CMD" = 'decode' ] && mv "${TMP_DIR}/${FILE_OUT_BASE}" "${FILE_OUT}"
}
# compare and save video
[ "$CMD" = 'encode' ] && {
echo "[+] Comparing outputs..."
RECREATED_FILE="${TMP_DIR}/${FILE_OUT_BASE}"
cmp "$RECREATED_FILE" "$ORIGINAL_FILE" || {
echo "[-] Error: created file and original file are different!"
exit 1
}
echo "[+] Saving video..."
mv "$FILE" "$FILE_OUT"
}
cleanup
echo "[+] Done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment