High level API rs2::context中,核心的数据为rs2_context结构体。rs2::context中最为核心的query_devices()、query_all_sensors()等函数,均为调用了次级API(rs_xxx_xxx()一类的函数)。对这些函数来说,其输入是对应的次级结构体或类rs2_xxx。rs2_context即为这些次级结构的一员。
与rs2_context相关的次级API在rs_context.h和rs.cpp中实现。这些次级API,从本质上说,均调用了rs_context结构体中层级更低的librealsense::context类中的方法。librealsense::context类即是rs2::context对外API操作中,最低层的一级封装。
rs2_context包含了librealsense::context类的共享指针:
1 2 3 4 5 struct rs2_context { ~rs2_context () { ctx->stop (); } std::shared_ptr<librealsense::context> ctx; };
因此,rs2::context所有的具体操作,均调用了librealsense::context类中所对应的方法。
rs::context与librealsense::context之间的关系如下所示:
librealsense::context类 该类如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class context : public std::enable_shared_from_this<context>{ public : explicit context ( backend_type type ) ; void stop () { _device_watcher->stop (); } ~context (); std::vector<std::shared_ptr<device_info>> query_devices (int mask) const ; const platform::backend& get_backend () const { return *_backend; } uint64_t register_internal_device_callback (devices_changed_callback_ptr callback) ; void unregister_internal_device_callback (uint64_t cb_id) ; void set_devices_changed_callback (devices_changed_callback_ptr callback) ; std::vector<std::shared_ptr<device_info>> create_devices (platform::backend_device_group devices, const std::map<std::string, std::weak_ptr<device_info>>& playback_devices, int mask) const ; std::shared_ptr<playback_device_info> add_device (const std::string& file) ; void remove_device (const std::string& file) ; void add_software_device (std::shared_ptr<device_info> software_device) ; private : void on_device_changed (platform::backend_device_group old, platform::backend_device_group curr, const std::map<std::string, std::weak_ptr<device_info>>& old_playback_devices, const std::map<std::string, std::weak_ptr<device_info>>& new_playback_devices) ; void raise_devices_changed (const std::vector<rs2_device_info>& removed, const std::vector<rs2_device_info>& added) ; void start_device_watcher () ; std::shared_ptr<platform::backend> _backend; std::shared_ptr<platform::device_watcher> _device_watcher; std::map<std::string, std::weak_ptr<device_info>> _playback_devices; std::map<uint64_t , devices_changed_callback_ptr> _devices_changed_callbacks; devices_changed_callback_ptr _devices_changed_callback; std::map<int , std::weak_ptr<const stream_interface>> _streams; std::map<int , std::map<int , std::weak_ptr<lazy<rs2_extrinsics>>>> _extrinsics; std::mutex _streams_mutex, _devices_changed_callbacks_mtx; };
该类的有8个类变量:
1 2 3 4 5 6 7 8 9 10 std::shared_ptr<platform::backend> _backend; std::shared_ptr<platform::device_watcher> _device_watcher; std::map<std::string, std::weak_ptr<device_info>> _playback_devices; std::map<uint64_t , devices_changed_callback_ptr> _devices_changed_callbacks; devices_changed_callback_ptr _devices_changed_callback; std::map<int , std::weak_ptr<const stream_interface>> _streams; std::map<int , std::map<int , std::weak_ptr<lazy<rs2_extrinsics>>>> _extrinsics; std::mutex _streams_mutex, _devices_changed_callbacks_mtx;
该类的构造函数如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 context::context ( backend_type type ) : _devices_changed_callback(nullptr , [](rs2_devices_changed_callback*){}) { static bool version_logged=false ; if (!version_logged) { version_logged = true ; LOG_DEBUG ( "Librealsense VERSION: " << RS2_API_VERSION_STR ); } _backend = platform::create_backend (); environment::get_instance ().set_time_service (_backend->create_time_service ()); _device_watcher = _backend->create_device_watcher (); assert (_device_watcher->is_stopped ()); }
输入参数为backend_type,但该参数貌似并没有用。构造函数首先初始化类成员变量_devices_changed_callback(TODO: 搞清楚这个类到底是什么),接着调platform::create_backend()函数来为成员变量_backend赋值,然后调用类函数create_time_service()与create_device_watcher(),前者不知道在干什么(TODO: 弄清楚),后者则为设备守望类型的成员变量_device_watcher赋值。最后,检查一下_device_watcher是否处于stop状态。
类成员变量_playback_devices、_devices_changed_callbacks、_streams、_extrinsics等在初始化是并未赋值,这些变量在调用到对应的函数时才会对其进行赋值。
query_devices()与create_device()函数 query_devices()是librealsense::context中非常重要的一个函数。该函数被调用时,返回当前连接的设备信息。该函数如下所示:
1 2 3 4 5 std::vector<std::shared_ptr<device_info>> context::query_devices (int mask) const { platform::backend_device_group devices (_backend->query_uvc_devices(), _backend->query_usb_devices(), _backend->query_hid_devices()) ; return create_devices (devices, _playback_devices, mask); }
首先该函数创建了一个backend_device_group对象,将目前所有发现的设备集合起来。这些设备通过_backend对象的query_uvc/usb/hid_device()函数来获取。在得到设备的集合后,调用create_device()函数来创建对应的device_info对象。create_device()函数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 std::vector<std::shared_ptr<device_info>> context::create_devices ( platform::backend_device_group devices, const std::map<std::string, std::weak_ptr<device_info>>& playback_devices, int mask) const { std::vector<std::shared_ptr<device_info>> list; LOG_INFO ("UVC backend: " << devices.uvc_devices.size ()); LOG_INFO ("HID backend: " << devices.hid_devices.size ()); LOG_INFO ("USB backend: " << devices.usb_devices.size ()); auto t = const_cast <context*>(this ); auto ctx = t->shared_from_this (); if (mask & RS2_PRODUCT_LINE_D400) { LOG_INFO ("Create d400 device_info" ); auto d400_devices = d400_info::pick_d400_devices (ctx, devices); std::copy (begin (d400_devices), end (d400_devices), std::back_inserter (list)); } if ( mask & RS2_PRODUCT_LINE_L500 ) { LOG_INFO ("Create l500 device_info" ); auto l500_devices = l500_info::pick_l500_devices (ctx, devices); std::copy (begin (l500_devices), end (l500_devices), std::back_inserter (list)); } if (mask & RS2_PRODUCT_LINE_SR300) { LOG_INFO ("Create sr300 device_info" ); auto sr300_devices = sr300_info::pick_sr300_devices (ctx, devices.uvc_devices, devices.usb_devices); std::copy (begin (sr300_devices), end (sr300_devices), std::back_inserter (list)); } if (mask & RS2_PRODUCT_LINE_D400 || mask & RS2_PRODUCT_LINE_SR300 || mask & RS2_PRODUCT_LINE_L500) { LOG_INFO ("Create recovery devices" ); auto recovery_devices = fw_update_info::pick_recovery_devices (ctx, devices.usb_devices, mask); std::copy (begin (recovery_devices), end (recovery_devices), std::back_inserter (list)); } if (mask & RS2_PRODUCT_LINE_NON_INTEL) { LOG_INFO ("Create uvc_device_info" ); auto uvc_devices = platform_camera_info::pick_uvc_devices (ctx, devices.uvc_devices); std::copy (begin (uvc_devices), end (uvc_devices), std::back_inserter (list)); } for (auto && item : playback_devices) { if (auto dev = item.second.lock ()) list.push_back (dev); } if (list.size ()) LOG_INFO ( "Found " << list.size () << " RealSense devices (mask 0x" << std::hex << mask << ")" ); return list; }
create_device()
函数的输入参数有三个:
platform::backend_device_group
对象,创建device_info
对象时使用;
std::map<std::string, std::weak_ptr<device_info>>
类型的类内变量,即当前context对象中通过手动方式添加的设备;
int
类型变量mask
,用来判断输出哪种类型设备的device_info
列表。
create_device()
函数首先根据mask
值,判定创建哪一类型的device_info
。在rs2::context
中,通常不会指定mask
的值,当未指定时,该值会被赋为254,所有的if
都会走一变。为了防止创建出并未连接的设备,device_info
各种派生类的pick_xxxx_devices()
函数中,都会首先通过设备pid来进行筛选,符合系列pid的设备才会被创建。
连接一个D455设备时,将会返回3个device_info组成的队列。
rs2::context::query_devices()的过程 综上,rs2::context
对象轮询所有设备的过程如下所示: