跳转至

videoplayer 视频播放

一、概述

videoplayer 是 LuatOS 的视频播放核心库,负责把视频文件里的 MJPG(MJPEG)帧解码成 RGB565 像素,再送到屏幕显示,或者交给脚本自己处理。它只做“读帧 + 解码 + 送屏”,不涉及音频与播放列表。

要点:

1、模块名是 videoplayer,先 videoplayer.open(path) 拿到播放器对象,再循环调用 draw_frame 显示或 read_frame 取帧;

2、draw_frame 内部走显示抽象层:优先用 display 库,未启用时回退 lcd;两者都不可用会返回错误信息 no display;

3、read_frame 返回的 data 是 RGB565 原始像素的 Lua 字符串,长度 = width × height × 2。它已经拷贝到 Lua 侧,取帧后可以安全长期持有该字符串;

4、真正能放的格式只有 MJPG 裸流与 HZV(MJPEG + 音频)容器。FMT_AVI_MJPG 是预留枚举、FMT_MP4_H264 已不再解码,这两个常量只是数值占位,不要拿它们判断“能不能播”;

5、解码分软件与硬件两种模式:软件解码基于 tjpgd,通用但吃 CPU;硬件解码依赖平台实现,切换失败会返回 false。

⚠️ 该库需要固件在编译时打开 LUAT_USE_VIDEOPLAYER。如果脚本里 videoplayer 为 nil,说明当前固件没有包含该库,需要向对接 FAE 确认固件版本。

二、核心示例

-- 打开视频文件
local player, err = videoplayer.open("/sdcard/video.mjpg")
if not player then
    log.error("videoplayer", "打开失败", err)
    return
end

-- 先看视频参数
local info = videoplayer.info(player)
if info then
    log.info("videoplayer", "分辨率", info.width, info.height,
             "格式", info.format, "解码模式", info.decode_mode)
end

-- 逐帧播放到屏幕左上角
while true do
    local ok, e = videoplayer.draw_frame(player, 0, 0)
    if e == "eof" then
        log.info("videoplayer", "播放结束")
        break
    elseif not ok then
        log.error("videoplayer", "解码失败", e)
        break
    end
    sys.wait(33)    -- 约 30fps
end

videoplayer.close(player)
player = nil

三、常量详解

3.1 解码模式常量

常量 值 含义
videoplayer.DECODE_SW 0 软件解码(tjpgd),通用,CPU 占用较高
videoplayer.DECODE_HW 1 硬件解码,可用性取决于平台

3.2 视频格式常量

常量 值 含义 现状
videoplayer.FMT_MJPG 0 裸 MJPG 流 支持
videoplayer.FMT_AVI_MJPG 1 AVI 容器 + MJPG 预留,未实现
videoplayer.FMT_MP4_H264 2 MP4 容器 + H.264 已不再解码,仅保留数值避免枚举错位
videoplayer.FMT_HZV 3 HZV 容器(MJPEG + 音频) 支持,本库只取视频轨

这两组常量同时也是 videoplayer.info() 返回的 format 与 decode_mode 字段的取值。

四、函数详解

videoplayer.open(path)

打开视频文件并创建播放器对象。

参数:

参数 类型 说明
path string 视频文件路径,如 /sdcard/video.mjpg、/sdcard/video.hzv,支持 MJPG 与 HZV

返回值:成功返回播放器对象(userdata);失败返回 nil 和错误信息字符串。

local player, err = videoplayer.open("/sdcard/video.hzv")
if not player then
    log.error("videoplayer", "打开失败", err)
    return
end

注意事项:

1、必须在文件系统挂载成功之后再调用(fatfs 或 io 先挂好 SD 卡),否则路径解析不到会直接失败;

2、文件扩展名不决定格式,真正识别的是文件内容;把 H264 的 mp4 改名成 mjpg 依然打不开。

videoplayer.close(player)

关闭播放器并释放全部资源。

参数:

参数 类型 说明
player userdata videoplayer.open() 返回的播放器对象

返回值:无。

videoplayer.close(player)
player = nil

注意事项:

1、重复调用是安全的,对象内部的上下文置空后直接返回;

2、对象被 Lua 回收时会自动再关一次,但工程上仍建议显式关闭,避免长时间占用解码缓冲区。

videoplayer.read_frame(player)

读取并解码下一帧,返回帧数据表。

参数:

参数 类型 说明
player userdata videoplayer.open() 返回的播放器对象

返回值:

  • 成功:table,字段见下表;
  • 到达文件末尾:nil 和 "eof";
  • 出错:nil 和错误信息字符串(format / nomem / io / decode / param / error);
  • 播放器已关闭:nil 和 "player closed"。
字段 类型 说明
width number 帧宽(像素)
height number 帧高(像素)
data string RGB565 原始像素,长度 = width × height × 2
pts number 显示时间戳,单位由 timescale 决定
duration number 本帧时长,单位同 timescale
timescale number 时间基,pts / timescale 即秒
while true do
    local frame, err = videoplayer.read_frame(player)
    if err == "eof" then break end
    if frame then
        -- frame.data 已经是 RGB565,可直接送 lcd / 自己的图像处理
        log.info("videoplayer", "帧", frame.width, frame.height, "#data", #frame.data)
    end
end

注意事项:

1、每帧的 data 都是一块新字符串,1024×600 一帧约 1.2MB。循环播放时不要把所有帧攒进 table,内存很快会耗尽;

2、read_frame 与 draw_frame 都会消耗一帧,二者不要对同一次播放交叉调用,否则会丢帧。

videoplayer.draw_frame(player, x, y)

读取下一帧、解码并直接绘制到默认屏幕。

参数:

参数 类型 说明
player userdata videoplayer.open() 返回的播放器对象
x int 显示起始 X 坐标
y int 显示起始 Y 坐标

返回值:成功返回 true;到达末尾返回 nil 和 "eof";失败返回 nil 和错误信息,其中没有可用显示设备时为 "no display"。

while true do
    local ok, err = videoplayer.draw_frame(player, 40, 30)
    if err == "eof" then break end
    if not ok then
        log.error("videoplayer", "绘制失败", err)
        break
    end
    sys.wait(33)
end

注意事项:

1、坐标在库内部按 int16 处理,有效范围 -32768~32767,正常按屏幕坐标从 0 开始传即可;

2、绘制目标由固件决定:启用 display 库时走 display,否则回退 lcd。屏没初始化会得到 no display,先 lcd.init 再播放;

3、单帧解码耗时随分辨率变化,帧率要靠 sys.wait 自己控,库不做定时。

videoplayer.info(player)

获取视频信息。

参数:

参数 类型 说明
player userdata videoplayer.open() 返回的播放器对象

返回值:成功返回 table(width、height、format、decode_mode);播放器无效或取信息失败返回 nil(不返回错误字符串)。

local info = videoplayer.info(player)
if info then
    log.info("videoplayer", "分辨率", info.width, info.height)
    log.info("videoplayer", "格式", info.format, "解码模式", info.decode_mode)
end

format 的取值见 3.2 节,decode_mode 见 3.1 节。

videoplayer.set_decode_mode(player, mode)

设置解码模式,播放过程中可以随时切换。

参数:

参数 类型 说明
player userdata videoplayer.open() 返回的播放器对象
mode int videoplayer.DECODE_SW 软件解码,videoplayer.DECODE_HW 硬件解码

返回值:成功返回 true,失败返回 false。

-- 先试硬件解码,失败就退回软件解码
if not videoplayer.set_decode_mode(player, videoplayer.DECODE_HW) then
    log.info("videoplayer", "本平台不支持硬件解码,使用软件解码")
    videoplayer.set_decode_mode(player, videoplayer.DECODE_SW)
end

注意事项:返回 false 的常见原因是播放器已关闭,或当前平台没有实现硬件解码。切到不支持的硬件解码后不会自动回退,要按返回值自己处理。

videoplayer.debug(on_off)

打开或关闭调试输出。

参数:

参数 类型 说明
on_off boolean true 开启,false 关闭(默认关闭)

返回值:无。

videoplayer.debug(true)     -- 打印解码过程、帧大小等信息
videoplayer.debug(false)    -- 关闭

五、产品支持说明

型号 文档中心是否有播放教程 教程入口
Air1601 / Air1602 有 /air1601/luatos/app/multimedia/ui/videoplayer/
Air1603 有 /air1603/luatos/app/multimedia/ui/videoplayer/
Air780EPM / Air780EHM 有 /air780epm/luatos/app/multimedia/ui/videoplayer/
Air780EGH 有 /air780egh/luatos/app/multimedia/ui/videoplayer/
Air780EHV 有 /air780ehv/luatos/app/multimedia/ui/videoplayer/
Air8000 有 /air8000/luatos/app/multimedia/ui/videoplayer/

上表按文档中心已有的播放教程列出,不代表所有固件都包含该库。判断依据只有一条:脚本里 videoplayer 是否为 nil,为 nil 说明固件未编译该组件。

搜索