diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..65088e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.history + diff --git a/play.lua b/play.lua index be6b8a4..e3febed 100644 --- a/play.lua +++ b/play.lua @@ -1,5 +1,5 @@ -- 简化版视频播放器 -local gpu = peripheral.wrap("tm_gpu_2") +local gpu = peripheral.wrap("tm_gpu_0") gpu.refreshSize() gpu.setSize(64) local w, h = gpu.getSize() @@ -65,7 +65,7 @@ print("task_id: " .. task_id) -- 用于记录已打印的日志数量,避免重复打印 local total_logs_printed = 0 - +speakerrun = true while true do @@ -97,9 +97,16 @@ while true do total_logs_printed = total_logs_printed + #task_info.new_logs 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 - break + if task_info.result.current_frames then + if task_info.result.current_frames >= 200 then + break + end end sleep(1) @@ -111,18 +118,23 @@ local response = http.get(status_url, {["Content-Type"] = "application/json"}) local finalResp = textutils.unserialiseJSON(response.readAll()) response.close() -videoInfo = finalResp.result.result +videoInfo = finalResp.result +videoInfo.fps = 20 --- 此时 videoInfo 包含 frame_urls, audio_dfpwm_url 等字段 -print("\nTask completed! Total frames: " .. #videoInfo.frame_urls) +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) --- server_url .. videoInfo.audio_dfpwm_url -- 音频单通道文件 URL --- server_url .. videoInfo.audio_dfpwm_right_url -- 音频右通道文件 URL --- server_url .. videoInfo.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) +-- server_url .. videoInfo.audio_urls.audio_dfpwm_url -- 音频单通道文件 URL +-- server_url .. videoInfo.audio_urls.audio_dfpwm_right_url -- 音频右通道文件 URL +-- server_url .. videoInfo.audio_urls.audio_dfpwm_left_url -- 音频左通道文件 URL + -- 下载和播放函数 frames = {} local frameCount = 0 @@ -163,92 +175,73 @@ local function unpackFramePack(data) return frames end + -- 分批下载(每批 50 帧) local BATCH_SIZE = 20 -- local totalFrames = #videoInfo.frame_urls local totalFrames = videoInfo.fps * 10 -- 仅下载前10秒以节省时间 local allFrameData = {} +-- 第一步:构建所有需要下载的批次(仅前10秒) +local initBatches = {} for startIdx = 1, totalFrames, BATCH_SIZE do local endIdx = math.min(startIdx + BATCH_SIZE - 1, totalFrames) - print("Downloading batch: " .. startIdx .. " - " .. endIdx) - - -- 构造要下载的 URL 列表(相对路径) local urls = {} for i = startIdx, endIdx do - table.insert(urls, videoInfo.frame_urls[i]) end - - -- 请求打包 - - while true do - resp1,err = http.post( - server_url .. "/api/framepack", - textutils.serializeJSON({ urls = urls }), - { ["Content-Type"] = "application/json" }, - true - ) - - if resp1 then break end - end - - - - 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) - for i = 1, #batchFrames do - allFrameData[startIdx + i - 1] = batchFrames[i] - end - - print("Loaded batch: " .. #batchFrames .. " frames") - sleep(0.1) + 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 + local resp = http.post({ + url = server_url .. "/api/framepack?" .. batch.urls[1], + headers = { ["Content-Type"] = "application/json" }, + body = textutils.serializeJSON({ urls = batch.urls }), + timeout = 3, + binary = true + }) + if resp then + local binData = resp.readAll() + resp.close() --- -- 预加载前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 batchFrames = unpackFramePack(binData) + for idx = 1, #batchFrames do + local globalIdx = batch.start + idx - 1 + allFrameData[globalIdx] = batchFrames[idx] + end - --- local success, image = pcall(function() --- return gpu.decodeImage(table.unpack(imgBin)) --- end) + print("Cached init batch: " .. batch.start .. " - " .. (batch.start + #batchFrames - 1)) + break + else + print("Retry init batch starting at " .. batch.start) + sleep(0.5) + end + end + end) +end --- if success then --- print("Loaded frame "..i .."/"..#videoInfo.frame_urls) +-- 执行并发下载 +parallel.waitForAll(table.unpack(initTasks)) --- frames[i] = image - --- frameData[i] = nil --- data = nil --- frameCount = frameCount + 1 --- else --- print(image) --- end --- end --- end +print("Initial caching completed.") -- 播放循环 local frameDelay = tonumber(string.format("%.3f",1 / videoInfo.fps)) print("Starting playback (FPS: " .. videoInfo.fps .. ")") print(frameDelay * #videoInfo.frame_urls) local starttime1 = os.clock() -sleep(1) +sleep(4) @@ -311,11 +304,6 @@ local function cacheAhead() table.insert(downloadTasks, function() print("Downloading batch: " .. batch.start .. " - " .. (batch.start + #batch.urls - 1)) 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({ url = server_url .. "/api/framepack?"..batch.urls[1], headers = { ["Content-Type"] = "application/json" }, @@ -361,15 +349,6 @@ local function cacheAhead() 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 frameIndex2 = 0