You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Zbar库双摄像头扫码异常:首个摄像头激活后读取被锁定

ZBar双摄像头二维码扫描:第一个摄像头锁定问题的解决

我尝试用ZBar库通过两个网络摄像头扫描二维码,编写了如下C语言代码,但调用zbar_processor_set_active(proc, 1);后,读取操作似乎被锁定在第一个激活的摄像头,尽管两个摄像头的指示灯都亮着(说明都在工作),请问该如何解决?

原代码

void *scanning_f(void *ptr)
{
    const char *first_cam = "/dev/video0";
    const char *second_cam = "/dev/video2";

    zbar_processor_t *proc = zbar_processor_create(1);
    zbar_processor_set_config(proc, 0, ZBAR_CFG_ENABLE, 1);
    zbar_processor_request_size(proc, 1024,  860);
    zbar_processor_init(proc, first_cam, 0);
    zbar_processor_set_data_handler(proc, handling, NULL);
    zbar_processor_set_visible(proc, 0);
    zbar_processor_set_active(proc, 1);
    
    zbar_processor_t *proc2 = zbar_processor_create(1);
    zbar_processor_set_config(proc2, 0, ZBAR_CFG_ENABLE, 1);
    zbar_processor_request_size(proc2, 1024,  860);
    zbar_processor_init(proc2, second_cam, 0);
    zbar_processor_set_data_handler(proc2, handling, NULL);
    zbar_processor_set_visible(proc2, 0);
    zbar_processor_set_active(proc2, 1);
    
    while(1)
    {
        zbar_process_one(proc, 1000);
        zbar_process_one(proc2, 1000);
    }
}

问题原因

  1. 资源竞争与线程冲突:zbar_processor_set_active()会启动ZBar内部的帧捕获线程,在同一个主线程中先后启动两个processor的捕获线程后,内部视频设备处理上下文会出现资源竞争,导致第二个processor的处理被第一个抢占。
  2. 串行调用阻塞:zbar_process_one()是同步处理单帧的函数,在同一个循环里串行调用会让两个摄像头的处理互相等待,进一步加剧资源锁定问题。

解决方案

核心思路

为每个摄像头分配独立线程,让每个ZBar processor在专属线程中运行,彻底避免资源竞争;同时选择自动捕获线程或手动帧处理其中一种模式,不要混合使用。

修改后的代码示例

#include <pthread.h>
#include <stdlib.h>

// 线程参数结构体,传递摄像头设备路径
typedef struct {
    const char* dev_path;
} CamThreadArgs;

// 单个摄像头的扫描线程函数
void* cam_scan_thread(void* args) {
    CamThreadArgs* cam_args = (CamThreadArgs*)args;
    const char* cam_path = cam_args->dev_path;

    // 初始化ZBar processor
    zbar_processor_t* proc = zbar_processor_create(1);
    zbar_processor_set_config(proc, 0, ZBAR_CFG_ENABLE, 1);
    zbar_processor_request_size(proc, 1024, 860);
    zbar_processor_init(proc, cam_path, 0);
    zbar_processor_set_data_handler(proc, handling, NULL);
    zbar_processor_set_visible(proc, 0);

    // 模式1:手动处理帧(无需调用set_active)
    while(1) {
        zbar_process_one(proc, 1000);
    }

    // 模式2:启动自动捕获线程(注释掉上面的手动循环,启用下面两行)
    // zbar_processor_set_active(proc, 1);
    // pthread_exit(NULL);

    // 清理资源(实际中需配合退出逻辑触发)
    zbar_processor_destroy(proc);
    free(cam_args);
    return NULL;
}

void *scanning_f(void *ptr)
{
    // 启动第一个摄像头线程
    CamThreadArgs* args1 = malloc(sizeof(CamThreadArgs));
    args1->dev_path = "/dev/video0";
    pthread_t thread1;
    pthread_create(&thread1, NULL, cam_scan_thread, args1);

    // 启动第二个摄像头线程
    CamThreadArgs* args2 = malloc(sizeof(CamThreadArgs));
    args2->dev_path = "/dev/video2";
    pthread_t thread2;
    pthread_create(&thread2, NULL, cam_scan_thread, args2);

    // 等待线程结束(可根据实际需求调整,比如监听退出信号)
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    return NULL;
}

关键说明

  • 每个线程独立管理自己的ZBar processor,两个摄像头的扫描任务完全并行,不会互相抢占资源。
  • 两种处理模式二选一:
    • 手动模式:通过zbar_process_one()循环处理单帧,适合需要自定义帧处理逻辑的场景。
    • 自动模式:调用zbar_processor_set_active()启动内部捕获线程,ZBar会自动处理帧并触发handling回调,无需手动循环。
  • 注意在程序退出时添加资源清理逻辑,避免内存泄漏和设备资源未释放。

内容的提问来源于stack exchange,提问作者user3742046

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 15:16:05