边转换边播放功能

This commit is contained in:
nnwang
2026-02-07 13:32:36 +08:00
parent cf0842a34b
commit 00e13e765e
2 changed files with 66 additions and 85 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.history

141
play.lua
View File

@@ -1,5 +1,5 @@
-- 简化版视频播放器 -- 简化版视频播放器
local gpu = peripheral.wrap("tm_gpu_2") local gpu = peripheral.wrap("tm_gpu_0")
gpu.refreshSize() gpu.refreshSize()
gpu.setSize(64) gpu.setSize(64)
local w, h = gpu.getSize() local w, h = gpu.getSize()
@@ -65,7 +65,7 @@ print("task_id: " .. task_id)
-- 用于记录已打印的日志数量,避免重复打印 -- 用于记录已打印的日志数量,避免重复打印
local total_logs_printed = 0 local total_logs_printed = 0
speakerrun = true
while true do while true do
@@ -97,10 +97,17 @@ while true do
total_logs_printed = total_logs_printed + #task_info.new_logs total_logs_printed = total_logs_printed + #task_info.new_logs
end end
if task_info.result.audio_urls and speakerrun then
speakerrun = false
shell.run("bg speakerlib play ".. server_url .. task_info.result.audio_urls.audio_dfpwm_url .." ".. server_url .. task_info.result.audio_urls.audio_dfpwm_left_url .." ".. server_url .. task_info.result.audio_urls.audio_dfpwm_right_url)
end
-- 检查是否完成 -- 检查是否完成
if task_info.status == "completed" then if task_info.result.current_frames then
if task_info.result.current_frames >= 200 then
break break
end end
end
sleep(1) sleep(1)
end end
@@ -111,18 +118,23 @@ local response = http.get(status_url, {["Content-Type"] = "application/json"})
local finalResp = textutils.unserialiseJSON(response.readAll()) local finalResp = textutils.unserialiseJSON(response.readAll())
response.close() response.close()
videoInfo = finalResp.result.result videoInfo = finalResp.result
videoInfo.fps = 20
-- 此时 videoInfo 包含 frame_urls, audio_dfpwm_url 等字段 videoInfo.frame_urls = {}
print("\nTask completed! Total frames: " .. #videoInfo.frame_urls)
-- /frames/20116713/frame_000001.png
for i = 1, videoInfo.total_frames - 10 do
videoInfo.frame_urls[i] = "/frames/"..task_id.."/frame_" .. string.format("%06d", i) .. ".png"
end
-- 播放音频 单通道 -- 播放音频 单通道
--shell.run("bg speaker play", server_url .. videoInfo.audio_dfpwm_url) --shell.run("bg speaker play", server_url .. videoInfo.audio_dfpwm_url)
-- server_url .. videoInfo.audio_dfpwm_url -- 音频单通道文件 URL -- server_url .. videoInfo.audio_urls.audio_dfpwm_url -- 音频单通道文件 URL
-- server_url .. videoInfo.audio_dfpwm_right_url -- 音频右通道文件 URL -- server_url .. videoInfo.audio_urls.audio_dfpwm_right_url -- 音频右通道文件 URL
-- server_url .. videoInfo.audio_dfpwm_left_url -- 音频左通道文件 URL -- server_url .. videoInfo.audio_urls.audio_dfpwm_left_url -- 音频左通道文件 URL
shell.run("bg speakerlib play ".. server_url .. videoInfo.audio_dfpwm_url .." ".. server_url .. videoInfo.audio_dfpwm_left_url .." ".. server_url .. videoInfo.audio_dfpwm_right_url)
-- 下载和播放函数 -- 下载和播放函数
frames = {} frames = {}
local frameCount = 0 local frameCount = 0
@@ -163,92 +175,73 @@ local function unpackFramePack(data)
return frames return frames
end end
-- 分批下载(每批 50 帧) -- 分批下载(每批 50 帧)
local BATCH_SIZE = 20 local BATCH_SIZE = 20
-- local totalFrames = #videoInfo.frame_urls -- local totalFrames = #videoInfo.frame_urls
local totalFrames = videoInfo.fps * 10 -- 仅下载前10秒以节省时间 local totalFrames = videoInfo.fps * 10 -- 仅下载前10秒以节省时间
local allFrameData = {} local allFrameData = {}
-- 第一步构建所有需要下载的批次仅前10秒
local initBatches = {}
for startIdx = 1, totalFrames, BATCH_SIZE do for startIdx = 1, totalFrames, BATCH_SIZE do
local endIdx = math.min(startIdx + BATCH_SIZE - 1, totalFrames) local endIdx = math.min(startIdx + BATCH_SIZE - 1, totalFrames)
print("Downloading batch: " .. startIdx .. " - " .. endIdx)
-- 构造要下载的 URL 列表(相对路径)
local urls = {} local urls = {}
for i = startIdx, endIdx do for i = startIdx, endIdx do
table.insert(urls, videoInfo.frame_urls[i]) table.insert(urls, videoInfo.frame_urls[i])
end end
table.insert(initBatches, {
start = startIdx,
urls = urls
})
end
-- 请求打包 print("Pre-caching first " .. totalFrames .. " frames (" .. #initBatches .. " batches)...")
-- 第二步:并发下载所有初始化批次
local initTasks = {}
for _, batch in ipairs(initBatches) do
table.insert(initTasks, function()
while true do while true do
resp1,err = http.post( local resp = http.post({
server_url .. "/api/framepack", url = server_url .. "/api/framepack?" .. batch.urls[1],
textutils.serializeJSON({ urls = urls }), headers = { ["Content-Type"] = "application/json" },
{ ["Content-Type"] = "application/json" }, body = textutils.serializeJSON({ urls = batch.urls }),
true timeout = 3,
) binary = true
})
if resp1 then break end if resp then
end local binData = resp.readAll()
resp.close()
if not resp1 then error("Failed to download framepack "..err) end
local binData = resp1.readAll()
print(#binData .. " bytes received")
resp1.close()
-- 解包
local batchFrames = unpackFramePack(binData) local batchFrames = unpackFramePack(binData)
for i = 1, #batchFrames do for idx = 1, #batchFrames do
allFrameData[startIdx + i - 1] = batchFrames[i] local globalIdx = batch.start + idx - 1
allFrameData[globalIdx] = batchFrames[idx]
end end
print("Loaded batch: " .. #batchFrames .. " frames") print("Cached init batch: " .. batch.start .. " - " .. (batch.start + #batchFrames - 1))
sleep(0.1) break
else
print("Retry init batch starting at " .. batch.start)
sleep(0.5)
end
end
end)
end end
-- 执行并发下载
parallel.waitForAll(table.unpack(initTasks))
print("Initial caching completed.")
-- -- 预加载前N帧
-- for i = 1, math.min(videoInfo.fps, #videoInfo.frame_urls) do
-- if frameData[i] then
-- local data = frameData[i]
-- local imgBin = {}
-- for j = 1, #data do
-- imgBin[#imgBin + 1] = data:byte(j)
-- end
-- local success, image = pcall(function()
-- return gpu.decodeImage(table.unpack(imgBin))
-- end)
-- if success then
-- print("Loaded frame "..i .."/"..#videoInfo.frame_urls)
-- frames[i] = image
-- frameData[i] = nil
-- data = nil
-- frameCount = frameCount + 1
-- else
-- print(image)
-- end
-- end
-- end
-- 播放循环 -- 播放循环
local frameDelay = tonumber(string.format("%.3f",1 / videoInfo.fps)) local frameDelay = tonumber(string.format("%.3f",1 / videoInfo.fps))
print("Starting playback (FPS: " .. videoInfo.fps .. ")") print("Starting playback (FPS: " .. videoInfo.fps .. ")")
print(frameDelay * #videoInfo.frame_urls) print(frameDelay * #videoInfo.frame_urls)
local starttime1 = os.clock() local starttime1 = os.clock()
sleep(1) sleep(4)
@@ -311,11 +304,6 @@ local function cacheAhead()
table.insert(downloadTasks, function() table.insert(downloadTasks, function()
print("Downloading batch: " .. batch.start .. " - " .. (batch.start + #batch.urls - 1)) print("Downloading batch: " .. batch.start .. " - " .. (batch.start + #batch.urls - 1))
while true do while true do
-- local resp = http.post(
-- server_url .. "/api/framepack?"..batch.urls[1],
-- textutils.serializeJSON({ urls = batch.urls }),
-- { ["Content-Type"] = "application/json" }
-- )
local resp = http.post({ local resp = http.post({
url = server_url .. "/api/framepack?"..batch.urls[1], url = server_url .. "/api/framepack?"..batch.urls[1],
headers = { ["Content-Type"] = "application/json" }, headers = { ["Content-Type"] = "application/json" },
@@ -361,15 +349,6 @@ local function cacheAhead()
end end
end end
-- -- 音频播放协程
-- local function playAudio()
-- os.queueEvent("audio_start") -- 触发同步
-- shell.run("bg speakerlib play " ..
-- server_url .. videoInfo.audio_dfpwm_url .. " " ..
-- server_url .. videoInfo.audio_dfpwm_left_url .. " " ..
-- server_url .. videoInfo.audio_dfpwm_right_url)
-- end
-- 视频渲染协程 -- 视频渲染协程
local function renderVideo() local function renderVideo()
local frameIndex2 = 0 local frameIndex2 = 0