开源相机管理库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不同的是,本例中图像获取过程以及停止采集条件的改变都是异步进行的(在回调函数中)。
/* 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
函数,在那个例子中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
参数值执行不同的操作,以实现在流线程的不同时间点完成用户自定义的相关操作。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架