JZ2440 数码相框项目 扩展项目(四) 加快显示速度

链接

  1. JZ2440 数码相框项目 扩展项目介绍
  2. JZ2440 数码相框项目 扩展项目(一) 多文件图标 (二) 显示png
  3. JZ2440 数码相框项目 扩展项目(三) 支持鼠标
  4. JZ2440 实现截图 保存为png格式
  5. JZ2440 数码相框项目 扩展项目 1-4 源码下载

扩展项目四

1.目标

"manual页面"里,点击"上一张"或"下一张"时所要显示的图片比较大, 速度有点慢: 改进它

2.分析

在打开当前图片后,就新建线程开始读取下一幅图片,若点击“下一张”按钮,获取之前线程读取的图片数据,就可以立马显示出来。

3.实现

在 manual_page.c 中包含头文件 <pthread.h>
使用 <pthread_create> <pthread_exit> <pthread_join> 这几个函数就可以实现功能
关于 pthread_create 的第二个参数

#include <pthread.h>
extern int pthread_create (         // 创建进程 创建成功返回 0
           pthread_t *__restrict __newthread,                   // 参数1: 返回新建线程号
	       __const pthread_attr_t *__restrict __attr,           // 参数2: 参考上面链接,一般填 NULL
	       void *(*__start_routine) (void *),                   // 参数3: 线程执行的函数
	       void *__restrict __arg) __THROW __nonnull ((1, 3));  // 参数4: 传递给线程函数的参数

extern void pthread_exit (  // 新建线程退出,并返回值
            void *__retval) __attribute__ ((__noreturn__)); // 参数为线程执行完后的返回值
extern int pthread_join (   // 获取新建线程的返回结果,该函数会阻塞(非阻塞:pthread_detach)
           pthread_t __th,  // 要获取返回结果的线程号
           void **__thread_return); // pthread_exit 中的返回值

先设计预读图片的线程函数:

static void* StartNextPicture(void* filename) // 传递进来参数类型为 char *
{
    PT_PixelDatas picture_data = malloc(sizeof(T_PixelDatas)); // 要返回的图片数据
    if (!picture_data) {
        DBG_PRINTF("StartNextPicture picture_data malloc error!\n");
        pthread_exit(NULL);  // 失败返回空
    }
    DBG_PRINTF(" <Start Parse> %s!\n", filename);
    if(GetPixelDatasFrmFile(filename, picture_data)) {  // 读取图片数据,该函数可重入
        DBG_PRINTF("<fault> can't open %s!\n", filename);
        free(picture_data);
        pthread_exit(NULL);  // 失败返回空
    }
    DBG_PRINTF(" <Parse OK> %s!\n", filename);
    pthread_exit(picture_data); // 成功返回图片数据
}

然后在主线程中创建该线程,然后等待返回结果就可以了,
只给出关键部分:

static void ManualPageRun(PT_PageParams ptParentPageParams)
{
    pthread_t next_pthread_t; // 预读线程线程号
    PT_PixelDatas next_picture_data; // 保存预读线程的返回结果
    ... // 其他声明
    /* 显示菜单和图片文件 */   // 后面介绍第三个参数
    ShowManualPage(&g_tManualPageMenuIconsLayout, strFullPathName, NULL);
    findNextFile(strFullPathName); // 在该路径下循环找下一幅图片
    pthread_create(&next_pthread_t, NULL, StartNextPicture, strFullPathName); // 创建预读线程
    while (1) {
        /* 先确定是否触摸了菜单图标 */  // 获取输入事件
        iIndex = ManualPageGetInputEvent(&g_tManualPageMenuIconsLayout, &tInputEvent);
        if (iIndex == NEXT_PICTURE) { // 如果点击了 “下一张” 按钮
            // 获取预读线程返回结果,如果线程还没有执行完,会在此处阻塞
            if(pthread_join(next_pthread_t, (void**)&next_picture_data)) {
                DBG_PRINTF("pthread_join error\n");
                break; // 失败退出
            }
            if (next_picture_data) // 返回的值非空显示图片
                ShowPictureInManualPage(ptDevVideoMem, NULL, next_picture_data);
            findNextFile(strFullPathName); // 在该路径下循环找下一幅图片
            pthread_create(&next_pthread_t, NULL, StartNextPicture, strFullPathName); // 创建预读线程
        }
        else { ... // 其他事件处理 }
    }
}

由于原有程序中并没有能把预读出来的数据直接显示出来的函数,为了改动尽量的小,所以给该函数添加了第三个参数(包括调用该函数的函数,该函数调用的函数),如果第三个参数传入非空,直接使用第三个参数来显示,第二个参数不起作用。

static int ShowPictureInManualPage(PT_VideoMem ptVideoMem, char *strFileName);
改为
static int ShowPictureInManualPage(PT_VideoMem ptVideoMem, char *strFileName, 
                                   PT_PixelDatas pic_data);

串口显示 < Parse OK > 后,再点击 “下一张” 按钮就可以瞬间显示出来,当然如果在线程还没有完成前就点击仍然会阻塞在 pthread_join 函数。

< Start Parse > //xhr/app/7_pngtest/lenna.jpg!
GetPixelDatasFrmFile 7 jpg //xhr/app/7_pngtest/lenna.jpg
< Parse OK > //xhr/app/7_pngtest/lenna.jpg!

说明

程序中,我只实现了 “下一张” 的预读,如果想要实现 “上一张” 的功能如法炮制即可,不过要注意线程中分配的内存释放问题,防止内存泄漏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值