forked from hkc/cc-stuff
Compare commits
6 Commits
Author | SHA1 | Date |
---|---|---|
Casey | a06361ad4a | |
Casey | c4740b8bfd | |
Casey | 989daae8e8 | |
Casey | bed20ee4d3 | |
Casey | 703a1744b5 | |
Casey | 92eb5b325c |
15
cc-pic.py
15
cc-pic.py
|
@ -74,13 +74,14 @@ class Converter:
|
|||
|
||||
MAX_DIFF = 3 * 255
|
||||
|
||||
def __init__(self, image: Image.Image, palette: list[int] | int = PALETTE_ADAPTIVE):
|
||||
def __init__(self, image: Image.Image, palette: list[int] | int = PALETTE_ADAPTIVE, dither: bool = True):
|
||||
dither_mode = Image.Dither.FLOYDSTEINBERG if dither else Image.Dither.NONE
|
||||
if isinstance(palette, list):
|
||||
img_pal = Image.new("P", (1, 1))
|
||||
img_pal.putpalette(palette)
|
||||
self._img = image.quantize(len(palette) // 3, palette=img_pal)
|
||||
self._img = image.quantize(len(palette) // 3, palette=img_pal, dither=dither_mode)
|
||||
else:
|
||||
self._img = image.convert("P", palette=palette, colors=16)
|
||||
self._img = image.convert("P", palette=palette, colors=16, dither=dither_mode)
|
||||
|
||||
self._imgdata = self._img.load()
|
||||
self._palette: list[int] = self._img.getpalette() or []
|
||||
|
@ -221,6 +222,12 @@ def main():
|
|||
action="store_true",
|
||||
help="Output a Lua script instead of binary image",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-D",
|
||||
dest="nodither",
|
||||
action="store_true",
|
||||
help="Disable dithering"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-W",
|
||||
dest="width",
|
||||
|
@ -391,7 +398,7 @@ def main():
|
|||
else:
|
||||
raise ValueError(f"invalid palette identifier: {args.palette!r}")
|
||||
|
||||
converter = Converter(canv, palette)
|
||||
converter = Converter(canv, palette, dither=not args.nodither)
|
||||
converter._img.save("/tmp/_ccpictmp.png")
|
||||
if args.textmode:
|
||||
with open(args.output_path, "w") as fp:
|
||||
|
|
|
@ -10,8 +10,8 @@ cleanup() {
|
|||
trap cleanup EXIT
|
||||
|
||||
|
||||
export URL="$1";
|
||||
export NAME="$2";
|
||||
export INPUT="$1";
|
||||
export OUTPUT="$(realpath "$2")";
|
||||
export BASE_URL="$3"
|
||||
|
||||
if [ -z "${BASE_URL}" ]; then
|
||||
|
@ -19,24 +19,21 @@ if [ -z "${BASE_URL}" ]; then
|
|||
fi
|
||||
|
||||
|
||||
mkdir -p "${NAME}"
|
||||
mkdir -p "${OUTPUT}"
|
||||
|
||||
export ORIG="$(pwd)";
|
||||
|
||||
cd "${TMP_DIR}"
|
||||
|
||||
yt-dlp "${URL}" -S "+height:720" -f "b" -o "${NAME}"
|
||||
ffmpeg -i "${INPUT}" -filter_complex "[0:a]channelsplit=channel_layout=stereo[left][right]" -map '[left]' -f s8 -ac 1 -ar 48k "${OUTPUT}/left.s8" -map '[right]' -f s8 -ac 1 -ar 48k "${OUTPUT}/right.s8"
|
||||
ffmpeg -i "${INPUT}" -vf fps=20 frame%04d.png
|
||||
|
||||
ffmpeg -i $2* -filter_complex "[0:a]channelsplit=channel_layout=stereo[left][right]" -map '[left]' -f s8 -ac 1 -ar 48k "${ORIG}/${NAME}/left.s8" -map '[right]' -f s8 -ac 1 -ar 48k "${ORIG}/${NAME}/right.s8"
|
||||
|
||||
ffmpeg -i $2* -vf fps=20 frame%04d.png
|
||||
rm $2*
|
||||
ls frame*.png | parallel 'echo {}; python3 ${ORIG}/cc-pic.py -W 164 -H 81 -p full {} ${ORIG}/${NAME}/{.}.cpi'
|
||||
ls frame*.png | parallel 'echo {}; python3 ${ORIG}/cc-pic.py -W 164 -H 81 -p cover {} ${OUTPUT}/{.}.cpi'
|
||||
rm frame*.png
|
||||
|
||||
cd "${ORIG}"
|
||||
|
||||
export FRAME_COUNT="$(ls ${NAME}/*.cpi | wc -l)";
|
||||
export FRAME_COUNT="$(ls ${OUTPUT}/*.cpi | wc -l)";
|
||||
|
||||
printf '{"frame_time": 0.05, "frame_count": %d, "video": "%s", "audio": {"l": "%s", "r": "%s"}}\n' "${FRAME_COUNT}" "${BASE_URL}/frame%04d.cpi" "${BASE_URL}/left.s8" "${BASE_URL}/right.s8" > "${OUTPUT}/info.json"
|
||||
|
||||
#'{"frame_time": 0.05,"frame_count": ${FRAME_COUNT},"video": "${BASE_URL}/${NAME}/frame%04d.cpi","audio": {"l": "${BASE_URL}/${NAME}/left.s8", "r": "${BASE_URL}/${NAME}/right.s8"}}' > "${NAME}/${NAME}.json"
|
||||
printf '{"frame_time": 0.05, "frame_count": %d, "video": "%s", "audio": {"l": "%s", "r": "%s"}}\n' "${FRAME_COUNT}" "${BASE_URL}/${NAME}/frame%04d.cpi" "${BASE_URL}/${NAME}/left.s8" "${BASE_URL}/${NAME}/right.s8" > "${NAME}/${NAME}.json"
|
||||
|
|
31
video.lua
31
video.lua
|
@ -2,6 +2,8 @@ local args = { ... }
|
|||
local dfpwm = require("cc.audio.dfpwm")
|
||||
local ccpi = require("ccpi")
|
||||
|
||||
local EV_NONCE = math.floor(0xFFFFFFFF * math.random())
|
||||
|
||||
settings.define("video.speaker.left", {
|
||||
description = "Speaker ID for left audio channel",
|
||||
default = peripheral.getName(peripheral.find("speaker")),
|
||||
|
@ -86,7 +88,8 @@ if not n_frames and not video_url and not audio_url_l then
|
|||
end
|
||||
end
|
||||
|
||||
print(string.format("Using monitor %s", peripheral.getName(monitor)))
|
||||
local mon_w, mon_h = monitor.getSize()
|
||||
print(string.format("Using monitor %s (%dx%d)", peripheral.getName(monitor), mon_w, mon_h))
|
||||
if speakers.r then
|
||||
print(string.format("Stereo sound: L=%s R=%s", peripheral.getName(speakers.l), peripheral.getName(speakers.r)))
|
||||
else
|
||||
|
@ -183,11 +186,11 @@ for i = 1, loading_concurrency do
|
|||
end
|
||||
|
||||
table.insert(subthreads, function()
|
||||
while #frames ~= n_frames or #audio_frames.l < n_audio_samples do
|
||||
repeat
|
||||
draw_bar(ty - 3, colors.blue, colors.gray, #frames / n_frames, "Loading video [%5d / %5d]", #frames, n_frames)
|
||||
draw_bar(ty - 2, colors.red, colors.gray, #audio_frames.l / n_audio_samples, "Loading audio [%5d / %5d]", #audio_frames.l, n_audio_samples)
|
||||
os.sleep(0.25)
|
||||
end
|
||||
until #frames >= n_frames and #audio_frames.l >= n_audio_samples
|
||||
print()
|
||||
end)
|
||||
|
||||
|
@ -208,14 +211,16 @@ table.insert(subthreads, function()
|
|||
break
|
||||
end
|
||||
end
|
||||
os.queueEvent("playback_ready")
|
||||
os.queueEvent("playback_ready", EV_NONCE)
|
||||
end)
|
||||
|
||||
table.insert(subthreads, function()
|
||||
local is_dfpwm = ({ audio_url_l:find("%.dfpwm") })[2] == #audio_url_l
|
||||
local decode = use_dfpwm and dfpwm.make_decoder() or decode_s8
|
||||
|
||||
os.pullEvent("playback_ready")
|
||||
repeat
|
||||
local _, nonce = os.pullEvent("playback_ready")
|
||||
until nonce == EV_NONCE
|
||||
|
||||
for i = 1, n_audio_samples do
|
||||
local buffer = decode(audio_frames.l[i])
|
||||
|
@ -232,7 +237,9 @@ table.insert(subthreads, function()
|
|||
local is_dfpwm = ({ audio_url_r:find("%.dfpwm") })[2] == #audio_url_r
|
||||
local decode = use_dfpwm and dfpwm.make_decoder() or decode_s8
|
||||
|
||||
os.pullEvent("playback_ready")
|
||||
repeat
|
||||
local _, nonce = os.pullEvent("playback_ready")
|
||||
until nonce == EV_NONCE
|
||||
|
||||
for i = 1, n_audio_samples do
|
||||
local buffer = decode(audio_frames.r[i])
|
||||
|
@ -244,8 +251,9 @@ table.insert(subthreads, function()
|
|||
end)
|
||||
|
||||
table.insert(subthreads, function()
|
||||
os.pullEvent("playback_ready")
|
||||
|
||||
repeat
|
||||
local _, nonce = os.pullEvent("playback_ready")
|
||||
until nonce == EV_NONCE
|
||||
local start_t = os.clock()
|
||||
while not playback_done do
|
||||
local frame = math.floor((os.clock() - start_t) / math.max(0.05, delay))
|
||||
|
@ -253,8 +261,11 @@ table.insert(subthreads, function()
|
|||
term.setBackgroundColor(frame >= #frames and colors.red or colors.gray)
|
||||
term.clearLine()
|
||||
term.write(string.format("Playing frame: %d/%d", frame + 1, #frames))
|
||||
if frames[frame + 1] then
|
||||
ccpi.draw(frames[frame + 1], 1, 1, monitor)
|
||||
local img = frames[frame + 1]
|
||||
if img ~= nil then
|
||||
local x = math.max(math.floor((mon_w - img.w) / 2), 1)
|
||||
local y = math.max(math.floor((mon_h - img.h) / 2), 1)
|
||||
ccpi.draw(img, x, y, monitor)
|
||||
end
|
||||
os.sleep(delay)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue