ViusalHMI - 视频播放
HMI系列支持MP4格式的视频播放,本例程主要通过LUA脚本API,指定播放文件。本例程演示播放SD卡目录下的视频,涉及文件遍历、视频播放等功能。
适用范围:VisualHMI - HMI&M系列&DH系列
例程下载链接:ViusalHMI - 视频播放(点击下载)
HMI支持的视频格式,如下所所示:
MP4文件
H264编码
音频流为MP3或AAC格式
视频最大分辨率<1280*768
最大帧数<30ps
最大码率<1400
1.画面配置
涉及的功能有视频列表翻页、视频上下首切换、视频播放状态(时间进度、播放状态)、音量控制等,所添加的控件地址和用途如下所示
| 控件类型 | 地址 | 用途 |
|---|---|---|
| 字状态按钮 | LW1000→设置0 | 视频列表向左翻页,LW1005=0不允许点击 |
| 字状态按钮 | LW1000→设置1 | 视频列表向右翻页LW1005=0不允许点击 |
| 字状态按钮 | LW1001→设置0 | 上一首LW1005=0不允许点击 |
| 字状态按钮 | LW1001→设置1 | 下一首LW1005=0不允许点击 |
| 位状态指示灯 | LW1002 | 0-暂停,1-继续播放LW1005=0不允许点击 |
| 数值 | LW1003 | 显示视频列表当前页 |
| 数值 | LW1004 | 显示视频列表总页数 |
| 位状态指示灯 | LW1005 | 1-SD根目录有视频 |
| 文本 | LW1100~1200,128个字节 | 显示视频名称 |
| 文本 | LW1240 | 视频播放的当前时间LW1005=0隐藏 |
| 文本 | LW1250 | 视频播放的总时间LW1005=0隐藏 |
| 播放进度条 | LW1006 | 进度条,数值范围,最小值 |

2.Lua脚本
2.1.API说明
2.1.1.play_video(file,left,top,width,height)
视频播放函数,play_video 是 HMI 系统提供的嵌入式视频播放接口,用于在指定屏幕区域播放符合硬件解码能力的 MP4 视频。该功能适用于操作引导、产品演示、安全须知播放等场景,通过富媒体提升人机交互体验
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
file |
string | 视频文件路径 • 绝对路 |
left |
number | 显示区域左上角 X 坐标(像素) |
top |
number | 显示区域左上角 Y 坐标(像素) |
width |
number | 视频显示宽度(像素) |
height |
number | 视频显示高度(像素) |
⚙️ 视频格式
| 项目 | 要求说明 |
|---|---|
| 格式 | MP4(.mp4) |
| 视频编码 | H.264 |
| 音频编码 | MP3 或 AAC |
| 最大分辨率 | 1280 × 768 像素(超过将无法播放或严重卡顿) |
| 最大帧率 | 30 fps(帧/秒) |
| 最大码率 | 1400 kbps(约 1.4 Mbps) |
2.1.2.pause_video()
暂停视频播放函数,pause_video() 是 HMI 系统提供的视频播放控制接口,用于临时暂停当前正在播放的视频(由 play_video 启动),并在后续通过 resume_video() 从暂停位置继续播放。该功能适用于需要用户交互控制、临时中断演示、同步操作步骤等场景
2.1.3.resume_video()
恢复视频播放函数,resume_video() 是 HMI 系统提供的视频播放控制接口,用于恢复由 pause_video() 暂停的视频播放,从暂停时的精确帧位置继续播放。该函数必须与 pause_video() 配套使用,共同实现视频的“暂停/继续”交互逻辑,适用于操作引导、教学演示、安全确认等需要用户临时中断并恢复的场景
2.1.4.stop_video()
停止视频播放函数,stop_video() 是 HMI 系统提供的视频播放终止接口,用于立即停止当前正在播放或已暂停的视频,释放相关解码资源,并清除屏幕上的视频画面。
2.1.5.on_video_notify(msg,v1, v2)
视频播放状态回调函数,on_video_notify(msg, v1, v2) 是 HMI 系统提供的视频播放事件回调接口,用于在视频播放过程中播放状态与进度信息。
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
msg |
number | 播放状态标识 • 1:播放中(周期性通知) • 0:播放完毕(仅触发一次) |
v1 |
number | 当前已播放时长(单位:秒,s) |
v2 |
number | 视频总时长(单位:秒,s) |
2.2.程序
2.2.1.遍历MP4文件
插入SD卡,自动触发on_sd_inserted(...),调用list_dir(...)进行遍历,触发回调函数on_list_dir(...),判断是否有视频文件(mp3、wav)。若有视频文件,路径保存在video.NameTb。代码清单如下所示
--@path :文件路径
--@filename:文件名称
--@type :0 文件夹,1 文件
--@fsize :文件大小
function on_list_dir(path, filename, type, fsize)
if type == 1
then
local cur_file_type = get_extension(filename)
print('filename = '..filename)
if cur_file_type == 'mp4'
then
video.allCnt = video.allCnt + 1
video.NameTb[video.allCnt] = path..'/'..filename
end
end
end
-- 系统回调函数,插入SD卡自动回调
function on_sd_inserted(dir)
sd_dir = dir
list_dir(sd_dir)
if video.allCnt > 0
then
video.allPage = math.modf(video.allCnt / 5)
if video.allCnt % 5 > 0
then
video.allPage = video.allPage + 1
end
set_uint16(VT_LW, 0x1003, 1)
set_uint16(VT_LW, 0x1004, video.allPage)
set_uint16(VT_LW, 0x1005, 1)
set_uint16(VT_LW, 0x1006, 0)
set_string(VT_LW, 0x1240, '00:00') --显示播放的当前的时间"xx:xx"
set_string(VT_LW, 0x1250, '00:00') --显示播放的总时间"xx:xx"
updatVideoList(video.curPage)
updatVideoPlayName(0)
end
end
-- 系统回调函数,拔掉SD卡自动回调
function on_sd_removed()
--复位清除相关变量
video.NameTb = {}
video.allCnt = 0
video.curPage = 1
video.allPage = 1
video.playIndex = 0
set_uint16(VT_LW, 0x1003, 0)
set_uint16(VT_LW, 0x1004, 0)
set_uint16(VT_LW, 0x1005, 0)
for i = 1, 5
do
set_string(VT_LW, 0x1100 + (i - 1)*(0x40), '')
set_uint16(VT_LW, 0x1500 + (i - 1)*1, 0)
end
end
2.2.2.显示列表
点击列表翻页按钮,自动触发on_update(...),判断触发的是上一页还是下一页,调用updatVideoPlayName(...)刷新列表内容。代码如下所示
--刷新视频名称列表
function updatVideoPlayName(index)
if index > 0
then
local line = index % 5
if line == 0
then
line = 5
end
for i = 1, 5
do
if i == line
then
wgt_set_fcolor(page.Video, i, play.color)
else
wgt_set_fcolor(page.Video, i, play.defColor)
end
end
else
for i = 1, 5
do
wgt_set_fcolor(page.Video, i , play.defColor)
end
end
end
function on_update(slave,vtype,addr)
if VT_LW == vtype
then
if addr == 0x1000 --翻页
then
local val = get_uint16(VT_LW, 0x1000)
local cur_page = get_uint16(VT_LW, 0x1003)
local all_page = get_uint16(VT_LW, 0x1004)
if val == 0 --上一页
then
cur_page = cur_page - 1
if cur_page <= 1
then
cur_page = 1
end
set_uint16(VT_LW, 0x1003, cur_page)
updatVideoList(cur_page)
elseif val == 1 --下一页
then
cur_page = cur_page + 1
if cur_page > all_page
then
cur_page = all_page
end
set_uint16(VT_LW, 0x1003, cur_page)
updatVideoList(cur_page)
end
....
end
end
2.2.3.播放控制
历程可以触控点击上一首、下一首、列表的某一个视频播放;同时播放完可以自动播放下一个视频。点击播放触发on_update(...),上一首/下一首通过全局变量video.playIndex 自加或自减,获取video.NameTb缓存中的第几个视频;暂停/继续,通过调用pause_video()、resume_video()控制。自动播放下一个视频,播放过程自动触发on_video_notify(msg, v1, v2)函数,通过video.playIndex自加,计算下一个视频的路径。代码如下所示
function on_video_notify(msg, v1, v2)
local SysSndState = msg --获取播放状态
local SysSndPlayTime = v1 --获取当前播放的时间
local SysSndTotalTime = v2 --获取当前播放的总时间
if SysSndState == 0x01
then
set_uint16(VT_LW, 0x1006, (v1*100)//v2)
--显示播放的当前的时间"xx:xx"
set_string(VT_LW, 0x1240,
string.format('%02d', (SysSndPlayTime // 60))..':'..
(string.format('%02d', (SysSndPlayTime %60))))
--显示播放的总时间"xx:xx"
set_string(VT_LW, 0x1250,
string.format('%02d', (SysSndTotalTime // 60))..':'..
(string.format('%02d', (SysSndTotalTime %60))))
elseif SysSndState == 0x00
then
video.playIndex = video.playIndex + 1 --下一首索引+1
if video.playIndex > video.allCnt --大于歌曲总数,播放第1首
then
video.playIndex = 1
end
local cur_play_page = math.modf(video.playIndex / 5)
if video.playIndex % 5 > 0
then
cur_play_page = cur_play_page + 1
end
local cur_page = get_uint16(VT_LW, 0x1003)
if cur_play_page == cur_page
then
updatVideoPlayName(video.playIndex)
else
updatVideoPlayName(0)
end
stop_video()
play_video(video.NameTb[video.playIndex], play.x, play.y, play.w, play.h)
end
redraw()
end
function on_update(slave,vtype,addr)
if VT_LW == vtype
then
......
elseif addr == 0x1505 --点击列表播放
then
local val = get_uint16(VT_LW, 0x1505)
local cur_page = get_uint16(VT_LW, 0x1003)
local temp = video.playIndex
set_uint16(VT_LW, 0x1002, 1) --设置播放按钮
video.playIndex = (cur_page - 1) * 5 + val
if video.playIndex <= video.allCnt
then
if string.len(video.NameTb[video.playIndex]) > 0
then
print('.... video.playIndex = '..video.playIndex)
updatVideoPlayName(video.playIndex)
if video.playIndex <= video.allCnt
then
stop_video()
play_video(video.NameTb[video.playIndex], play.x,play.y, play.w, play.h)
end
end
else
video.playIndex = temp
end
elseif addr == 0x1001 --上下首翻页
then
local val = get_uint16(VT_LW, 0x1001)
set_uint16(VT_LW, 0x1002, 1) --设置播放按钮
if val == 0 --上一首
then
video.playIndex = video.playIndex - 1
if video.playIndex < 1
then
video.playIndex = video.allCnt
end
elseif val == 1 --下一首
then
video.playIndex = video.playIndex + 1
if video.playIndex > video.allCnt
then
video.playIndex = 1
end
end
--刷新当前页
local cur_play_page = math.modf(video.playIndex / 5)
if video.playIndex % 5 > 0
then
cur_play_page = cur_play_page + 1
end
set_uint16(VT_LW, 0x1003, cur_play_page)
stop_video()
play_video(video.NameTb[video.playIndex], play.x, play.y, play.w, play.h)
updatVideoList(cur_play_page)
updatVideoPlayName(video.playIndex)
elseif addr == 0x1002 --播放按钮
then
local val = get_uint16(VT_LW, 0x1002)
if val == 0
then
pause_video()
elseif val == 1
then
resume_video()
end
end
end
end
2.3.运行预览
编译下载后,在实体屏测试,在SD卡放.mp4格式视频文件,插入实体屏,进行测试