ZBar源码分析——Window模块解析(一) | 2021SC@SDUSC

2021SC@SDUSC

目录

一、Window模块

二、代码分析

window数据结构解析

Window线程的上锁与解锁

窗口固定

窗口渲染

三、总结


一、Window模块

 要使用ZBar进行条码识别的时候,输入的可以是视频流也可以是图像流。

在采用视频流进行输入的情况下,我们往往采取的方式是打开摄像头窗口进行扫码识别。在摄像头捕获到的视频信息中,ZBar需要对视频信息进行一系列的采集和处理,如逐帧捕获等等。Window模块会将处理后的信息交给其他模块进行解码等处理。

采用图像输入时,也需要Window模块的参与,这会在后续代码分析中提到。

这部分功能的实现并不是由Video模块实现,而是在ZBar打开窗口时,由Window模块进行实现的。这样的模块分离,使得整个项目的结构更加清晰,各模块之间的分工更加明确。

除此之外,根据ZBar的项目流程,可以看到,Window模块还有一个核心功能为将图像显示到用户指定的特定于平台的输出窗口。

ZBar项目的核心代码大部分都在zbar文件夹下,而zbar文件夹下的window.h和window.c则负责了这一模块的核心功能实现,而具体的调用实现则是在Processor处理模块以及其他api中完成。

本次代码分析将从window.h和window.c中展开。


二、代码分析

window数据结构解析

根据代码中的注释,给出数据结构中每个属性的补充说明。

struct zbar_window_s {
    errinfo_t err;              /* 报错信息 */
    zbar_image_t *image;        /* 上一张显示的图像 */
                                /* 该图像信息的访问权限必须上锁 */

    unsigned overlay;           /* 用户设定的覆盖等级 */

    uint32_t format;            /* 输出格式 */
    unsigned width, height;     /* 当前输出尺寸 */
    unsigned max_width, max_height;

    uint32_t src_format;        /* 当前输入格式 */
    unsigned src_width;         /* 上一张显示图像的尺寸 */
    unsigned src_height;

    unsigned dst_width;         /* 转换目标的图像尺寸 */
    unsigned dst_height;

    unsigned scale_num;         /* 输出缩放尺度 */
    unsigned scale_den;

    point_t scaled_offset;      /* 输出位置和大小 */
    point_t scaled_size;

    uint32_t *formats;          /* 支持的格式(必须以0结尾) */

    zbar_mutex_t imglock;       /* 锁定当前显示的图像 */

    void *display;
    unsigned long xwin;
    unsigned long time;         /* 以毫秒为单位显示图像 */
    unsigned long time_avg;     /* 帧间时间的平均值 */

    window_state_t *state;      /* 接口特定状态 */

    /* 依赖接口的方法 */
    int (*init)(zbar_window_t*, zbar_image_t*, int);
    int (*draw_image)(zbar_window_t*, zbar_image_t*);
    int (*cleanup)(zbar_window_t*);
};

Window线程的上锁与解锁

在代码注释中提到,在渲染窗口时,必须保证渲染函数window.draw是线程安全的。ZBar对于线程安全方面的处理都是采用互斥锁和信号量实现。

static inline int window_lock (zbar_window_t *w)
{
    int rc = 0;
    if((rc = _zbar_mutex_lock(&w->imglock))) {
        err_capture(w, SEV_FATAL, ZBAR_ERR_LOCKING, __func__,
                    "unable to acquire lock");
        w->err.errnum = rc;
        return(-1);
    }
    return(0);
}

static inline int window_unlock (zbar_window_t *w)
{
    int rc = 0;
    if((rc = _zbar_mutex_unlock(&w->imglock))) {
        err_capture(w, SEV_FATAL, ZBAR_ERR_LOCKING, __func__,
                    "unable to release lock");
        w->err.errnum = rc;
        return(-1);
    }
    return(0);
}

当有渲染窗口的线程获得了互斥锁,其他线程则必须等待,直到其释放锁。

而关于互斥锁的具体实现,则在mutex.c中体现,后续有机会再进行解析。

zbar_window_t *zbar_window_create ()
{
    zbar_window_t *w = calloc(1, sizeof(zbar_window_t));
    if(!w)
        return(NULL);
    err_init(&w->err, ZBAR_MOD_WINDOW);
    w->overlay = 1;
    (void)_zbar_mutex_init(&w->imglock);
    return(w);
}

void zbar_window_destroy (zbar_window_t *w)
{
    /* detach */
    zbar_window_attach(w, NULL, 0);
    err_cleanup(&w->err);
    _zbar_mutex_destroy(&w->imglock);
    free(w);
}

ZBar在创建一个窗口和销毁一个窗口时,同时新建和释放互斥锁。

在创建窗口时,首先为窗口申请内存,并为当前窗口新建互斥锁,当要渲染形成窗口界面时,则通过互斥锁实现线程互斥。

窗口固定

int zbar_window_attach (zbar_window_t *w,
                        void *display,
                        unsigned long drawable)
{
    /* release image */
    zbar_window_draw(w, NULL);
    if(w->cleanup) {
        w->cleanup(w);
        w->cleanup = NULL;
        w->draw_image = NULL;
    }
    if(w->formats) {
        free(w->formats);
        w->formats = NULL;
    }
    w->src_format = 0;
    w->src_width = w->src_height = 0;
    w->scaled_size.x = w->scaled_size.y = 0;
    w->dst_width = w->dst_height = 0;
    w->max_width = w->max_height = 1 << 15;
    w->scale_num = w->scale_den = 1;
    return(_zbar_window_attach(w, display, drawable));
}

该函数实现了窗口在平台上的关联和固定。

这里对外界平台做一下说明:平台可以是 X Windows 的任何“可绘制”窗口 或 Windows 的“HWND”。

在形式参数中传递 NULL 空值 指定从资源中分离,将显示进一步的输入。

ZBar对窗口销毁时,除了释放了互斥锁,同时还需要对窗口中的当前图像进行释放,并对属性进行重置,并设定为不可渲染。

窗口渲染

int zbar_window_draw (zbar_window_t *w,
                      zbar_image_t *img)
{
    if(window_lock(w))
        return(-1);
    if(!w->draw_image)
        img = NULL;
    if(img) {
        _zbar_image_refcnt(img, 1);
        if(img->width != w->src_width ||
           img->height != w->src_height)
            w->dst_width = 0;
    }
    if(w->image)
        _zbar_image_refcnt(w->image, -1);
    w->image = img;
    return(window_unlock(w));
}

该函数实现了将图像输出到特定窗口。

可以看到,如果执行该函数时,互斥锁已被占用,则不允许执行后续程序。

在将图像输出时,如果出现图像尺寸与窗口尺寸不一致的情况,ZBar会将输出的目标图像的宽置为0,从而实现强制适应。


三、总结

本次代码分析对Window模块的几个函数进行了简单说明,关于窗口重渲染以及图层的覆盖处理将在下次分析中给出。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mai゛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值