9 #include <unordered_set>
20 using std::chrono::high_resolution_clock;
21 using std::chrono::milliseconds;
27 return message.c_str();
34 static Int32 handleImaqError(Int32 err) {
37 imgShowError(err, temp);
43 _ImaqGrabberImpl::_ImaqGrabberImpl(
const std::string & _deviceName,
const std::string & _deviceSource, zmq::context_t & _ctx):
44 deviceName(_deviceName),
45 deviceSource(_deviceSource),
53 handleImaqError(imgInterfaceOpen(deviceSource.c_str(), &ifid));
55 handleImaqError(imgInterfaceReset(ifid));
56 handleImaqError(imgSessionOpen(ifid, &sid));
60 _ImaqGrabberImpl::~_ImaqGrabberImpl() {
67 interfaceOpen =
false;
70 int _ImaqGrabberImpl::getInteger(uInt32 attr) {
72 handleImaqError(imgGetAttribute(sid, attr, &temp));
75 int _ImaqGrabberImpl::getWidth() {
76 return getInteger(IMG_ATTR_ROI_WIDTH);
78 int _ImaqGrabberImpl::getHeight() {
79 return getInteger(IMG_ATTR_ROI_HEIGHT);
81 int _ImaqGrabberImpl::getBytesPerPixel() {
82 return getInteger(IMG_ATTR_BYTESPERPIXEL);
85 void _ImaqGrabberImpl::startServing() {
86 enableAcquisition =
true;
87 acquisitionThread = thread(&_ImaqGrabberImpl::acquisition,
this);
91 void _ImaqGrabberImpl::stopServing() {
92 enableAcquisition =
false;
93 if(acquisitionThread.joinable()) {
94 cout <<
"wait for grabber thread to join" << endl;
95 acquisitionThread.join();
99 void _ImaqGrabberImpl::addEndpoint(
const string & _endpoint) {
100 endpoints.push_back(_endpoint);
106 #define IMAQ_BUFFER_COUNT (256)
108 void _ImaqGrabberImpl::acquisition() {
109 RocLogger logger(ctx,
"inproc://log",
"camserver",
SSTR(
"grabber.", deviceName));
111 zmq::socket_t pubSocket(ctx, ZMQ_PUB);
112 for(
const auto & ep: endpoints) {
113 pubSocket.bind(ep.c_str());
115 int width = getWidth();
116 int height = getHeight();
117 int bytesPerPixel = getBytesPerPixel();
124 bufferList[i] =
new char[width * height * bytesPerPixel];
125 assert(bufferList[i] !=
nullptr);
126 bufferUsers[i] =
new atomic<int>(0);
127 assert(bufferUsers[i] !=
nullptr);
130 handleImaqError(imgGrabSetup(sid, 0 ));
132 cout <<
"grab initialized" << endl;
135 handleImaqError(imgSessionStartAcquisition(sid));
137 int currentBuffer = 0;
138 auto t1 = chrono::high_resolution_clock::now();
139 auto t2 = chrono::high_resolution_clock::now();
141 while(enableAcquisition) {
143 int currentBufferIndex = 0;
145 while(currentBufferIndex < IMAQ_BUFFER_COUNT && *bufferUsers[currentBufferIndex] > 0) {
146 ++currentBufferIndex;
148 if(currentBufferIndex >= IMAQ_BUFFER_COUNT) {
152 cout <<
"use buffer: " << currentBufferIndex << endl;
155 res = imgGrab(sid, (
void**)&bufferList[currentBufferIndex], 1);
156 t2 = chrono::high_resolution_clock::now();
157 auto grabTime = chrono::system_clock::now();
159 milliseconds dt = chrono::duration_cast<milliseconds>(t2 - t1);
160 cout <<
"dt: " << dt.count() <<
" ms" << endl;
167 uint64_t grabHighResTime = chrono::duration_cast<chrono::microseconds>(t1.time_since_epoch()).count();
168 uint64_t grabWallTime = chrono::duration_cast<chrono::microseconds>(grabTime.time_since_epoch()).count();
170 cout <<
"current buffer: " << currentBuffer <<
" idx: " << currentBufferIndex << endl;
172 lostFrames = getInteger(IMG_ATTR_LOST_FRAMES);
173 if(lostFrames > totalLostFrames) {
174 cout <<
"buffer overrun! " << (lostFrames - totalLostFrames) <<
" lost frames!! (" << lostFrames <<
" in session)" << endl;
175 totalLostFrames = lostFrames;
177 acquireBuffer(currentBufferIndex);
179 zmq::message_t header(deviceName.length());
180 memcpy(header.data(), deviceName.c_str(), deviceName.length());
181 pubSocket.send(header, ZMQ_SNDMORE);
182 zmq::message_t dimensions(3 * 4 + 2 * 8);
188 pubSocket.send(dimensions, ZMQ_SNDMORE);
189 zmq::message_t data(bufferList[currentBufferIndex],
190 width * height * bytesPerPixel,
192 new std::function<
void()>(
193 bind(&_ImaqGrabberImpl::releaseBuffer,
197 pubSocket.send(data);
199 }
else if(res == (Int32)(IMG_ERR_TIMEOUT)) {
202 handleImaqError(res);
206 cout <<
"aquisition stopped" << endl;
209 logger.
error(
SSTR(
"grabbing service canceled! (", e.
what(),
")"));
212 while(totalBufferUsers > 0) {
214 unique_lock<mutex> lock(m);
215 bufferFreeNotifier.wait(lock);
217 handleImaqError(imgSessionStopAcquisition(sid));
219 delete[] bufferList[i];
220 delete bufferUsers[i];
223 logger.
debug(
SSTR(
"grabber worker is done"));
226 void _ImaqGrabberImpl::acquireBuffer(
int bufferId) {
228 if((*bufferUsers[bufferId])++ == 0) {
230 cout << deviceName <<
" acquired buffer " << bufferId << endl;
236 void _ImaqGrabberImpl::releaseBuffer(
int bufferId) {
237 if(--(*bufferUsers[bufferId]) == 0) {
239 cout << deviceName <<
" released buffer " << bufferId << endl;
243 bufferFreeNotifier.notify_all();
#define IMAQ_BUFFER_COUNT
Base for all Imaq related exceptions.
void insertNetworkUInt32(void *buffer, uint32_t value)
void publishBufferLoad(const int usedBuffers, const int totalBuffers)
void insertNetworkUInt64(void *buffer, uint64_t value)
void error(const std::string &_msg)
void setThreadPriority(std::thread &th, thread_priority_t prio)
void debug(const std::string &_msg)
std::string SSTR(Args &&...components)
Creates a temporary string stream for string concatenation.
ImaqException(const std::string &_message)
void cbWrapper(void *data, void *hint)
virtual const char * what() const