开源相机管理库Aravis例程学习(三)——回调multiple-acquisition-callback
- 简介
- 例程代码
- arv_camera_create_stream
- ArvStreamCallbackType
- ArvStreamCallback
简介
本文针对官方例程中的: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不同的是,本例中图像获取过程以及停止采集条件的改变都是异步进行的(在回调函数中)。
/* 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池中取出bufferg_assert (buffer == arv_stream_pop_buffer(callback_data->stream));g_assert (buffer != NULL);//检索10个有效bufferif (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
函数,在那个例子中callback
和user_data
都被设置为NULL,表示不注册回调。而在本例中callback注册了一个我们自定义的函数stream_callback
。至于stream_callback
中为什么为switch结构我们在后面的讨论中会给出回答。
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
简介:一个枚举类,描述了流回调函数被调用的时间点。
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
是一个函数指针类型,用于在实例化流对象时注册回调函数。
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
注册回调完成后,会立即开启一个流接收线程,用于数据接收。
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_BUFFER
和ARV_STREAM_CALLBACK_TYPE_BUFFER_DONE
。最后在线程退出时最后调用一次stream_callback
,并向type
传入ARV_STREAM_CALLBACK_TYPE_EXIT
。
回调函数中使用switch结构是为了根据不同的type
参数值执行不同的操作,以实现在流线程的不同时间点完成用户自定义的相关操作。