CVB++ 15.0
Cvb/CppCompositeStreamHandler
1#include <iostream>
2#include <string>
3#include <vector>
4#include <condition_variable>
5
6#include <cvb/device_factory.hpp>
7#include <cvb/global.hpp>
8#include <cvb/driver/composite_stream.hpp>
9#include <cvb/genapi/node_map_enumerator.hpp>
10#include <cvb/async/async.hpp>
11#include <cvb/async/stream_handler_base.hpp>
12
13static const constexpr auto TIMEOUT = std::chrono::milliseconds(3000);
14static const constexpr int NUM_ELEMENTS_TO_ACQUIRE = 10; // number of elements to be acquired
15static std::map<Cvb::WaitStatus, const char *> WAIT_ERROR_STATES{{Cvb::WaitStatus::Timeout, "timeout"},
16 {Cvb::WaitStatus::Abort, "abort"}};
17
18// derives the CompositeStreamHandler class so that we can implement our own customized tasks
19// for the demonstration.
20class CustomStreamHandler final : public Cvb::Async::CompositeStreamHandler
21{
22 struct PrivateTag
23 {
24 };
25
26public:
29 {
30 return std::make_unique<CustomStreamHandler>(streams, PrivateTag{});
31 }
32
33 explicit CustomStreamHandler(const Cvb::Async::CompositeStreamHandler::StreamVectorType &streams, PrivateTag)
34 : Cvb::Async::CompositeStreamHandler(streams)
35 , numDeliverables_(0)
36 {
37 }
38
39 std::cv_status WaitUntil(std::unique_lock<std::mutex> &lock, const std::chrono::system_clock::time_point &absTime)
40 {
41 return observer_.wait_until(lock, absTime);
42 }
43
44private:
45 // asynchronously called for all registered streams.
47 {
48 // the following code is the same as the default implementation;
49 // this is just to demonstrate that you can freely override depending on your demand.
51 waitResultList.reserve(streams.size());
52 for (auto n = 0; n < streams.size(); ++n)
53 waitResultList.emplace_back(streams[n]->WaitFor(TIMEOUT));
54
55 // let it take care of the acquired deliverables.
56 HandleAsyncWaitResult(waitResultList);
57 }
58
59 // asynchronously called for all acquired deliverables.
60 void HandleAsyncWaitResult(const std::vector<Cvb::WaitResultTuple<Cvb::Composite>> &waitResultList) override
61 {
62 // the default implementation does nothing; you may add tasks by yourself.
63 std::cout << "round: #" << numDeliverables_ << "\n";
64
65 // iterate over the streams.
66 for (auto m = 0; m < waitResultList.size(); ++m)
67 {
68 // check the wait status.
69 auto waitStatus = std::get<Cvb::WaitStatus>(waitResultList[m]);
70 std::cout << "stream #" << m << "\n";
71 std::cout << "wait status: ";
72 if (waitStatus != Cvb::WaitStatus::Ok)
73 {
74 switch (waitStatus)
75 {
78 std::cout << WAIT_ERROR_STATES[waitStatus];
79 break;
80 default:
81 std::cout << "unknown";
82 }
83 std::cout << "; no deliverable is available.\n";
84 continue; // work on the next stream.
85 }
86 else
87 std::cout << "ok\n";
88
89 // pick up the delivered composite.
90 auto composite = std::get<Cvb::CompositePtr>(waitResultList[m]);
91
92 // identify the deliverable type of each item.
93 const auto numItems = composite->ItemCount();
94 std::cout << "number of items: " << numItems << "\n";
95 for (auto n = 0; n < numItems; ++n)
96 {
97 auto item = composite->ItemAt(n);
98 auto item_type = std::string("unknown");
99 if (Cvb::holds_alternative<Cvb::ImagePtr>(item))
100 item_type = "image";
101 else if (Cvb::holds_alternative<Cvb::PlanePtr>(item))
102 item_type = "plane";
103 else if (Cvb::holds_alternative<Cvb::PlaneEnumeratorPtr>(item))
104 item_type = "plane enumerator";
105 else if (Cvb::holds_alternative<Cvb::BufferPtr>(item))
106 item_type = "buffer";
107 else if (Cvb::holds_alternative<Cvb::PFNCBufferPtr>(item))
108 item_type = "pfnc buffer";
109 std::cout << "composite item #" << n << ": " << item_type << "\n";
110 }
111 }
112 std::cout << "\n";
113
114 ++numDeliverables_;
115 if (numDeliverables_ == NUM_ELEMENTS_TO_ACQUIRE)
116 observer_.notify_all();
117 }
118
119private:
120 std::condition_variable observer_;
121 int numDeliverables_;
122};
123
124int main()
125{
126 try
127 {
128 // enumerate devices.
129 auto infoList = Cvb::DeviceFactory::Discover(Cvb::DiscoverFlags::IgnoreVins);
130
131 // cannot continue the demonstration if CVMockTL is not present
132 Cvb::String accessToken;
133 for (const auto &info : infoList)
134 if (info.AccessToken().find("MockTL") != Cvb::String::npos)
135 accessToken = info.AccessToken();
136
137 if (accessToken.empty())
138 throw std::runtime_error("there is no available device for this demonstration.");
139
140 // instantiate the first device on the list; however, it is worth knowing that
141 // you can bind streams of other devices to a stream handle if needed.
142 auto device =
143 Cvb::DeviceFactory::Open<Cvb::GenICamDevice>(infoList.front().AccessToken(), Cvb::AcquisitionStack::GenTL);
144
145 // create a stream handler.
146 // IMPORTANT: this tutorial assumes that each stream is synchronized, i.e., it
147 // is running at the same acquisition frame rate; if any of them is out of sync
148 // the application will lose images. if any of the streams are not synchronized,
149 // please consider preparing a dedicated stream handler object for every single
150 // stream.
152 streams.reserve(device->StreamCount());
153 for (auto n = 0; n < device->StreamCount(); ++n)
154 streams.emplace_back(device->Stream<Cvb::CompositeStream>(n));
155 auto handler = CustomStreamHandler::Create(streams);
156
157 // start the data acquisition.
158 handler->Run();
159
160 // wait for the job is done.
161 {
162 std::mutex mutex;
164 if (std::cv_status::no_timeout != handler->WaitUntil(lock, std::chrono::system_clock::now() + TIMEOUT))
165 throw std::runtime_error("could not complete the job");
166 }
167
168 // stop the data acquisition, ignore errors.
169 handler->TryFinish();
170 }
171 catch (const std::exception &e)
172 {
173 std::cout << e.what() << std::endl;
174 }
175 return 0;
176}
Stream handler for synchronous streams.
Definition: decl_stream_handler_base.hpp:93
virtual void HandleAsyncWaitResult(const std::vector< WaitResult< typename Internal::DeliverableTraits< STREAMTYPE >::type > > &waitResultVector)
Asynchronously called for all acquired images.
Definition: detail_stream_handler_base.hpp:151
static std::unique_ptr< StreamHandlerBase > Create(const StreamVectorType &streamVector)
Create a stream handler object.
Definition: decl_stream_handler_base.hpp:130
virtual void HandleAsyncStream(const StreamVectorType &streamVector)
Asynchronously called for all registered streams.
Definition: detail_stream_handler_base.hpp:131
static std::vector< DiscoveryInformation > Discover()
Discovers available devices (not vins) with a default time span of 300ms.
Definition: decl_device_factory.hpp:221
Streams composites.
Definition: composite_stream.hpp:21
T lock(T... args)
StreamHandlerBase< CompositeStream > CompositeStreamHandler
Shorthand notation of the composite stream handler.
Definition: async.hpp:31
Root namespace for the Image Manager interface.
Definition: c_barcode.h:24
@ Abort
The acquisition has been stopped asynchronously, there is no image buffer.
@ Ok
Everything is fine, a new image arrived.
@ Timeout
A timeout occurred, no image buffer has been returned.