LVGL笔记(1)-使用《avilib》库播放avi视频(lvgl在windows模拟运行)


在github找到一个 avilib库,可以方便的读写avi文件。这里主要用到读取图片帧的功能。avi文件必须是MJPG编码,这样读取出来就是一张张的jpg图片,直接使用lvgl的第三方库《sjpg》解码。
如何生成MJPG编码的avi文件,请参考《 AVI视频封装格式(阅读笔记)》。
在windows仿真的视频:

lvgl播放avi视频

1.函数简介

这里只介绍读取avi用到的部分函数。

1.1 avi_t *AVI_open_input_file(const char *filename, int getIndex)

传入文件名,打开avi文件;返回avi_t指针,后面的操作都要用到这个指针。

1.2 long AVI_video_frames(avi_t *AVI)

获取avi文件的总帧数(有多少张jpg图片)。由视频的时长可以估算,一般是一秒20-30帧,以30帧算,如果视频是10秒长,那么总帧数是300张。

1.3 double AVI_frame_rate(avi_t *AVI)

这个函数直接返回 AVI->fps,每秒的帧数。更新图片的速度由这个参数决定。

1.4 int AVI_set_video_position(avi_t *AVI, long frame)

设置AVI->pos.
传入参数frame是帧索引,范围在0-总帧数之间。
返回值:0表示正常,非0表示出错。

1.5 long AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe)

读取AVI->pos对应的图片,把数据存放到vidbuf,如果是关键帧,keyframe = 1,否则keyframe = 0.
返回值:本帧数据大小,单位是字节。

1.6 AVI_close((avi_t *) avi)

关闭avi文件。

2.操作流程

Created with Raphaël 2.3.0 打开视频文件:AVI_open_input_file 读取总帧数:AVI_video_frames 设置视频开始读取位置:AVI_set_video_position 读取帧数据:AVI_read_frame lvgl显示图片:lv_img_set_src 延时 确认帧数达到最大:pos==(frames-1)? 关闭视频文件:AVI_close yes no

3.源代码

这里有一个疑问,如果一开始设置帧索引为0,会闪退出;设置到10开始就正常。不知道为什么。注意下面的代码第56行。

static lv_img_dsc_t IMG1 = {
    .header.cf = LV_IMG_CF_RAW,
    .header.always_zero = 0,
    .header.reserved = 0,
    .header.w = 0,
    .header.h = 0,
    .data_size = 0,
    .data = NULL,
};
lv_obj_t * objpg;
//const	unsigned char JFIF_INFO[18]=
//{0XFF ,0XE0 ,0X00 ,0X10 ,0X4A ,0X46 ,0X49 ,0X46 ,0X00 ,0X01 ,0X01 ,0X01 ,0X00 ,0X60 ,0X00 ,0X60 ,0X00 ,0X00};

lv_obj_t * g_scr;
int avi_file_is_opened=0;
char frameBuffer[20*1024];
int frameSize = 0;      //单帧的字节数
int keyFrame = 0;       //是否关键帧
int pos;                //帧索引
int frames;             //帧总数

avi_t * avi;
static void pic_timer(void)
{
    //lv_obj_t* bg = timer->user_data;
    if(avi_file_is_opened){
        pos++;
        if(pos<frames){
            //  avi->pos  会自动增加,不用下面的函数
            //AVI_set_video_position((avi_t *) avi,pos);
            frameSize = AVI_read_frame((avi_t *) avi, frameBuffer, &keyFrame);
            //  图片的尺寸不能大于分配的空间
            if(frameSize > sizeof(frameBuffer))     return;
            printf("pos:%d,frameSize: %d",pos, frameSize);

            IMG1.data_size = frameSize;
            memcpy(frameBuffer+2,JFIF_INFO,sizeof(JFIF_INFO));
            IMG1.data = (const uint8_t *)frameBuffer;

            lv_img_set_src(g_scr,&IMG1);
        }else{
            printf("avi file close.");
            avi_file_is_opened = 0;
            AVI_close((avi_t *) avi);
        }
    }
}
void lv_100ask_demo_course_4_1_1(void)
{
    char *ff="./avi/hanfu03.avi";
    avi = AVI_open_input_file(ff, 1);
    if(avi != NULL){
        avi_file_is_opened = 1;
        printf("W: %d,H: %d", (int)(avi->width),(int)(avi->height));
        //将avi帧byte读取到bitmap中
        pos = 10;
        frames=AVI_video_frames(avi);

        AVI_set_video_position((avi_t *) avi,pos);
            frameSize = AVI_read_frame((avi_t *) avi, frameBuffer, &keyFrame);
        printf("pos:%d,frameSize: %d",pos, frameSize);


    }else{
        printf("open avi fail.");
        AVI_close((avi_t *) avi);
        return;
    }

        IMG1.data_size = frameSize;
        //memcpy(frameBuffer+2,JFIF_INFO,sizeof(JFIF_INFO));
        IMG1.data = (const uint8_t *)frameBuffer;


        g_scr =  lv_img_create(lv_scr_act());
        lv_img_set_src(g_scr,&IMG1);

    lv_timer_t * timer = lv_timer_create(pic_timer, 35,  g_scr);
    lv_timer_set_repeat_count(timer, frames+1);
}

4.整个工程源码

测试代码工程】是在韦东山老师的开源工程上改动的。本例子在工程中的位置:
在这里插入图片描述
测试时,在main函数中调用该函数即可:
在这里插入图片描述
本文只是记录学习过程,并非教程。

posted @ 2022-10-12 11:02  汉塘阿德  阅读(377)  评论(0编辑  收藏  举报  来源