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 进度条,数值范围,最小值

image-20260121092309719

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格式视频文件,插入实体屏,进行测试

Copyright ©Dacai all right reserved,powered by Gitbook该文件修订时间: 2026-02-05 16:02:04

results matching ""

    No results matching ""