开源相机管理库Aravis例程学习(三)——注册回调multiple-acquisition-callback

开源相机管理库Aravis例程学习(三)------回调multiple-acquisition-callback

简介

本文针对官方例程中的:02-multiple-acquisition-callback做简单的讲解。

aravis版本:0.8.31

操作系统:ubuntu-20.04

gcc版本:9.4.0

例程代码

这段代码使用Aravis的API,控制相机连续采集,并异步地在回调函数中获取10个有效图像,主要操作步骤如下:

  • 连接相机
  • 设置采集模式为连续采集
  • 创建流对象(同时注册回调),并向流对象的buffer池中添加buffer
  • 开始采集
  • 获取10张有效图像后停止采集
  • 释放资源

连续采集multiple-acquisition-main-thread不同的是,本例中图像获取过程以及停止采集条件的改变都是异步进行的(在回调函数中)。

cpp 复制代码
/* SPDX-License-Identifier:Unlicense */

/* Aravis header */
#include <arv.h>
/* Standard headers */
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include "LogManager.h"

//用于回调函数中传递和储存流的状态和计数器
typedef struct {
	ArvStream *stream;
	int counter;
	gboolean done;
} ArvStreamCallbackData;

//回调函数
//根据不同的回调类型处理视频流事件
static void stream_callback (void *user_data, ArvStreamCallbackType type, ArvBuffer *buffer)
{
	ArvStreamCallbackData *callback_data = (ArvStreamCallbackData *) user_data;

	/* 回调函数内尽量不做非必要的耗时操作 */
	switch (type) {
		case ARV_STREAM_CALLBACK_TYPE_INIT:
			PAW_INFO("ARV_STREAM_CALLBACK_TYPE_INIT");
			break;
		case ARV_STREAM_CALLBACK_TYPE_START_BUFFER:
			PAW_INFO("ARV_STREAM_CALLBACK_TYPE_START_BUFFER");
			break;
		case ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE:
			PAW_INFO("ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE");
			//从buffer池中取出buffer
			g_assert (buffer == arv_stream_pop_buffer(callback_data->stream));
			g_assert (buffer != NULL);

			//检索10个有效buffer
			if (callback_data->counter < 10) {
				if (arv_buffer_get_status(buffer) == ARV_BUFFER_STATUS_SUCCESS)
					PAW_INFO("Acquired"<<arv_buffer_get_image_width(buffer)<<"x"<<arv_buffer_get_image_height(buffer)<< " buffer");
				arv_stream_push_buffer(callback_data->stream, buffer);
				callback_data->counter++;
			} else {
				callback_data->done = TRUE;
			}

			break;
		case ARV_STREAM_CALLBACK_TYPE_EXIT:
			PAW_INFO("ARV_STREAM_CALLBACK_TYPE_EXIT");
			/* Stream thread ended */
			break;
	}
}

/*
 * Connect to the first available camera, then acquire 10 buffers.
 */
int main (int argc, char **argv)
{
	CLogManager& p_log_instance = CLogManager::GetInstance();

	ArvCamera *camera;
	GError *error = NULL;

	//连接相机
	camera = arv_camera_new ("192.168.6.63", &error);

	if (ARV_IS_CAMERA (camera)) {
		ArvStreamCallbackData callback_data;

		printf ("Found camera '%s'\n", arv_camera_get_model_name (camera, NULL));
		//设置相机采集模式为连续采集
		arv_camera_set_acquisition_mode (camera, ARV_ACQUISITION_MODE_CONTINUOUS, &error);

        //初始化回调数据
		callback_data.counter = 0;
		callback_data.done = FALSE;
		callback_data.stream = NULL;

		if (error == NULL) {
			//创建流对象,注册回调
			PAW_INFO("create stream");
			callback_data.stream = arv_camera_create_stream (camera, stream_callback, &callback_data, &error);
			PAW_INFO("create stream end");
		}
			
		if (ARV_IS_STREAM (callback_data.stream)) {
			int i;
			size_t payload;

			/* Retrieve the payload size for buffer creation */
			//从相机对象中获取图像负载大小(每个图像的字节大小)
			payload = arv_camera_get_payload (camera, &error);
			PAW_INFO("payload:" << payload);
			if (error == NULL) {
				/* Insert some buffers in the stream buffer pool */
				//双缓冲
				for (i = 0; i < 2; i++)
					arv_stream_push_buffer (callback_data.stream, arv_buffer_new (payload, NULL));
			}

			if (error == NULL)
				/* Start the acquisition */
				arv_camera_start_acquisition (camera, &error);

			if (error == NULL) {
				while (!callback_data.done) {
					usleep (1000);
				}
			}


			if (error == NULL)
				/* Stop the acquisition */
				arv_camera_stop_acquisition (camera, &error);

			/* Destroy the stream object */
			g_clear_object (&callback_data.stream);
		}

		/* Destroy the camera instance */
		PAW_INFO("destroy stream");
		g_clear_object (&camera);
		PAW_INFO("destroy stream end");
	}

	if (error != NULL) {
		/* En error happened, display the correspdonding message */
		printf ("Error: %s\n", error->message);
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

注:PAW_INFO是我自定义的用于打印日志的宏

运行结果:

其中<>之间的是线程号。

arv_camera_create_stream

连续采集multiple-acquisition-main-thread中我们简单介绍了arv_camera_create_stream函数,在那个例子中callbackuser_data都被设置为NULL,表示不注册回调。而在本例中callback注册了一个我们自定义的函数stream_callback。至于stream_callback中为什么为switch结构我们在后面的讨论中会给出回答。

cpp 复制代码
static void stream_callback (void *user_data, ArvStreamCallbackType type, ArvBuffer *buffer)
{
	ArvStreamCallbackData *callback_data = (ArvStreamCallbackData *) user_data;

	switch (type) {
		case ARV_STREAM_CALLBACK_TYPE_INIT:
			...
			break;
		case ARV_STREAM_CALLBACK_TYPE_START_BUFFER:
			...
			break;
		case ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE:
			...
			break;
		case ARV_STREAM_CALLBACK_TYPE_EXIT:
			...
			break;
	}
}

ArvStreamCallbackType

简介:一个枚举类,描述了流回调函数被调用的时间点。

cpp 复制代码
typedef enum {
	ARV_STREAM_CALLBACK_TYPE_INIT,
	ARV_STREAM_CALLBACK_TYPE_EXIT,
	ARV_STREAM_CALLBACK_TYPE_START_BUFFER,
	ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE
} ArvStreamCallbackType;

ArvStreamCallback

简介:ArvStreamCallback是一个函数指针类型,用于在实例化流对象时注册回调函数。

cpp 复制代码
typedef void(* ArvStreamCallback) (
  void* user_data,
  ArvStreamCallbackType type,
  ArvBuffer* buffer
)

它在四种情况下会被调用:

①流接收线程的初始化时(只会被调用一次,对应type为ARV_STREAM_CALLBACK_TYPE_INIT

②流接收线程的终止时(只会被调用一次,对应type为ARV_STREAM_CALLBACK_TYPE_EXIT

③每一个buffer从缓冲队列被开始取出时(对应type为ARV_STREAM_CALLBACK_TYPE_START_BUFFER

④每一个buffer从缓冲队列中取出完毕时(无论成功与否,对应type为ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE

现在回答关于stream_callback中的switch结构的问题:

在调用arv_camera_create_stream 注册回调完成后,会立即开启一个流接收线程,用于数据接收。

cpp 复制代码
arv_camera_create_stream (camera, stream_callback, &callback_data, &error);

在这个流线程初始化时,会调用stream_callback并向type传入ARV_STREAM_CALLBACK_TYPE_INIT。然后是在开启采集之后,会对每一帧满足上述情况③和情况④的图像,再调用stream_callback,并分别向type传入ARV_STREAM_CALLBACK_TYPE_START_BUFFERARV_STREAM_CALLBACK_TYPE_BUFFER_DONE。最后在线程退出时最后调用一次stream_callback,并向type传入ARV_STREAM_CALLBACK_TYPE_EXIT

回调函数中使用switch结构是为了根据不同的type参数值执行不同的操作,以实现在流线程的不同时间点完成用户自定义的相关操作。

相关推荐
修己xj9 小时前
GoTab:打造属于你自己的个性化浏览器新标签页
开源
蝎子莱莱爱打怪15 小时前
XZLL-IM干货系列 03|消息 ID 设计:一个 UUID 搞不定的事,我用两个 ID 解决了
后端·面试·开源
冬奇Lab17 小时前
每日一个开源项目(第137篇):Penpot - 真正开源的设计协作工具,SVG 原生格式消灭设计-开发鸿沟
前端·开源·设计
冬奇Lab2 天前
每日一个开源项目(第135篇):codebase-memory-mcp - 给 AI Agent 一张代码库的知识图谱
人工智能·开源·llm
uniquejing3 天前
《每次 API 调用前扔掉 43% Token,我开源了一个 AI 提示词瘦身工具》
开源
文心快码BaiduComate4 天前
Comate 搭载GLM-5.2:百万上下文,稳定支撑长程任务
前端·程序员·开源
冬奇Lab4 天前
每日一个开源项目(第133篇):EchoBird - 把 AI 工具的安装和部署做成傻瓜操作
人工智能·开源·资讯
通信小呆呆5 天前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人
H__Rick5 天前
自动对焦学习-3
人工智能·学习·计算机视觉
Daisy Lee5 天前
量化学习-第1章-什么是量化金融
学习·金融·datawhale