libvisiontransfer  10.6.0
imageprotocol.cpp
1 /*******************************************************************************
2  * Copyright (c) 2023 Allied Vision Technologies GmbH
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *******************************************************************************/
14 
15 #include <cstring>
16 #include <iostream>
17 #include <limits>
18 #include <vector>
19 #include <memory>
20 #include <algorithm>
21 #include "visiontransfer/imageprotocol.h"
22 #include "visiontransfer/alignedallocator.h"
23 #include "visiontransfer/datablockprotocol.h"
24 #include "visiontransfer/exceptions.h"
25 #include "visiontransfer/bitconversions.h"
26 #include "visiontransfer/internalinformation.h"
27 
28 // Network headers
29 #ifdef _WIN32
30  #ifndef NOMINMAX
31  #define NOMINMAX
32  #endif
33  #include <winsock2.h>
34 #else
35  #include <arpa/inet.h>
36 #endif
37 
38 #define LOG_DEBUG_IMPROTO(expr)
39 //#define LOG_DEBUG_IMPROTO(expr) std::cerr << "ImageProtocol: " << expr << std::endl
40 
41 using namespace std;
42 using namespace visiontransfer;
43 using namespace visiontransfer::internal;
44 
45 namespace visiontransfer {
46 
47 /*************** Pimpl class containing all private members ***********/
48 
49 class ImageProtocol::Pimpl {
50 public:
51 
52  static const int IMAGE_HEADER_OFFSET = sizeof(DataBlockProtocol::HeaderPreamble) + 10;
53 
54  Pimpl(bool server, ProtocolType protType, int maxUdpPacketSize);
55 
56  // Redeclaration of public members
57  void setTransferImageSet(const ImageSet& imageSet);
58  void setRawTransferData(const ImageSet& metaData, const std::vector<unsigned char*>& rawData,
59  int firstTileWidth = 0, int middleTilesWidth = 0, int lastTileWidth = 0);
60  void setRawValidBytes(const std::vector<int>& validBytesVec);
61  const unsigned char* getTransferMessage(int& length);
62  bool transferComplete();
63  void resetTransfer();
64  bool getReceivedImageSet(ImageSet& imageSet);
65  bool getPartiallyReceivedImageSet(ImageSet& imageSet,
66  int& validRows, bool& complete);
67  bool imagesReceived() const;
68 
69  unsigned char* getNextReceiveBuffer(int& maxLength);
70 
71  void processReceivedMessage(int length);
72  int getProspectiveMessageSize();
73  int getNumDroppedFrames() const;
74  void resetReception();
75  bool isConnected() const;
76  const unsigned char* getNextControlMessage(int& length);
77  bool newClientConnected();
78 
79  std::string statusReport();
80 
81 private:
82  unsigned short MAGIC_SEQUECE = 0x3D15;
83 
84  // Header data transferred in the first packet
85 #pragma pack(push,1)
86  struct HeaderDataLegacy {
87  unsigned short magic;
88 
89  unsigned char protocolVersion;
90  unsigned char isRawImagePair_OBSOLETE;
91 
92  unsigned short width;
93  unsigned short height;
94 
95  unsigned short firstTileWidth;
96  unsigned short lastTileWidth;
97 
98  unsigned char format0;
99  unsigned char format1;
100  unsigned short minDisparity;
101  unsigned short maxDisparity;
102  unsigned char subpixelFactor;
103 
104  unsigned int seqNum;
105  int timeSec;
106  int timeMicrosec;
107 
108  float q[16];
109 
110  unsigned short middleTilesWidth;
111  };
112  // Header data v2: extensible and forwards-compatible
113  struct HeaderDataV2: public HeaderDataLegacy {
114  unsigned short totalHeaderSize;
115  unsigned short flags;
116  unsigned char numberOfImages;
117  unsigned char format2;
118  enum FlagBits {
119  NEW_STYLE_TRANSFER = 1,
120  HEADER_V3 = 2,
121  HEADER_V4 = 4,
122  HEADER_V5 = 8,
123  // future protocol extensions should mark a new bit here
124  };
125  };
126  // Header data v3, adds arbitrary image channel assignments
127  struct HeaderDataV3: public HeaderDataV2 {
128  // HEADER_V3 bit implies that this extension is present,
129  // declaring arbitrary channel roles for each of numberOfImages active channels.
130  // If not present, is it an old sender that always sends two images
131  // (channel 0: left, channel 1: right or disparity (if active))
132  unsigned char imageTypes[8];
133  };
134  // Header data v4, adds exposure time and sync pulse
135  struct HeaderDataV4: public HeaderDataV3 {
136  int exposureTime; // exposure time in microseconds
137  int lastSyncPulseSec;
138  int lastSyncPulseMicrosec;
139  };
140  // Header data v5, adds format for 4th image
141  struct HeaderData: public HeaderDataV4{
142  unsigned char format3;
143  };
144 #pragma pack(pop)
145 
146  // Underlying protocol for data transfers
147  DataBlockProtocol dataProt;
148  ProtocolType protType;
149 
150  // Transfer related variables
151  std::vector<unsigned char> headerBuffer;
152 
153  // Reception related variables
154  std::vector<unsigned char, AlignedAllocator<unsigned char> >decodeBuffer[ImageSet::MAX_SUPPORTED_IMAGES];
155  bool receiveHeaderParsed;
156  HeaderData receiveHeader;
157  int lastReceivedPayloadBytes[ImageSet::MAX_SUPPORTED_IMAGES];
158  bool receptionDone;
159 
160  // Copies the transmission header to the given buffer
161  void copyHeaderToBuffer(const ImageSet& imageSet, int firstTileWidth,
162  int middleTilesWidth, int lastTileWidth, unsigned char* buffer);
163 
164  // Decodes header information from the received data
165  void tryDecodeHeader(const unsigned char* receivedData, int receivedBytes);
166 
167  // Decodes a received image from a non-interleaved buffer
168  unsigned char* decodeNoninterleaved(int imageNumber, int numImages, int receivedBytes,
169  unsigned char* data, int& validRows, int& rowStride);
170 
171  // Decodes a received image from an interleaved buffer
172  unsigned char* decodeInterleaved(int imageNumber, int numImages, int receivedBytes,
173  unsigned char* data, int& validRows, int& rowStride);
174 
175  int getNumTiles(int width, int firstTileWidth, int middleTilesWidth, int lastTileWidth);
176 
177  int getFrameSize(int width, int height, int firstTileWidth, int middleTilesWidth,
178  int lastTileWidth, int totalBits);
179 
180  int getFormatBits(ImageSet::ImageFormat format, bool afterDecode);
181 
182  void decodeTiledImage(int imageNumber, int lastReceivedPayloadBytes, int receivedPayloadBytes,
183  const unsigned char* data, int firstTileStride, int middleTilesStride, int lastTileStride,
184  int& validRows, ImageSet::ImageFormat format, bool dataIsInterleaved);
185 
186  void decodeRowsFromTile(int startRow, int stopRow, unsigned const char* src,
187  unsigned char* dst, int srcStride, int dstStride, int tileWidth);
188 
189  void allocateDecodeBuffer(int imageNumber);
190 };
191 
192 
193 /******************** Stubs for all public members ********************/
194 
195 ImageProtocol::ImageProtocol(bool server, ProtocolType protType, int maxUdpPacketSize)
196  : pimpl(new Pimpl(server, protType, maxUdpPacketSize)) {
197  // All initializations are done by the Pimpl class
198 }
199 
200 ImageProtocol::~ImageProtocol() {
201  delete pimpl;
202 }
203 
205  pimpl->setTransferImageSet(imageSet);
206 }
207 
208 void ImageProtocol::setRawTransferData(const ImageSet& metaData, const std::vector<unsigned char*>& imageData,
209  int firstTileWidth, int middleTilesWidth, int lastTileWidth) {
210  pimpl->setRawTransferData(metaData, imageData, firstTileWidth, middleTilesWidth, lastTileWidth);
211 }
212 
213 void ImageProtocol::setRawValidBytes(const std::vector<int>& validBytesVec) {
214  pimpl->setRawValidBytes(validBytesVec);
215 }
216 
217 const unsigned char* ImageProtocol::getTransferMessage(int& length) {
218  return pimpl->getTransferMessage(length);
219 }
220 
222  return pimpl->transferComplete();
223 }
224 
226  pimpl->resetTransfer();
227 }
228 
230  return pimpl->getReceivedImageSet(imageSet);
231 }
232 
234  ImageSet& imageSet, int& validRows, bool& complete) {
235  return pimpl->getPartiallyReceivedImageSet(imageSet, validRows, complete);
236 }
237 
239  return pimpl->imagesReceived();
240 }
241 
242 unsigned char* ImageProtocol::getNextReceiveBuffer(int& maxLength) {
243  return pimpl->getNextReceiveBuffer(maxLength);
244 }
245 
247  pimpl->processReceivedMessage(length);
248 }
249 
251  return pimpl->getNumDroppedFrames();
252 }
253 
255  pimpl->resetReception();
256 }
257 
259  return pimpl->isConnected();
260 }
261 
262 const unsigned char* ImageProtocol::getNextControlMessage(int& length) {
263  return pimpl->getNextControlMessage(length);
264 }
265 
267  return pimpl->newClientConnected();
268 }
269 
270 /******************** Implementation in pimpl class *******************/
271 
272 ImageProtocol::Pimpl::Pimpl(bool server, ProtocolType protType, int maxUdpPacketSize)
273  :dataProt(server, (DataBlockProtocol::ProtocolType)protType,
274  maxUdpPacketSize), protType(protType),
275  receiveHeaderParsed(false), lastReceivedPayloadBytes{0},
276  receptionDone(false) {
277  headerBuffer.resize(sizeof(HeaderData) + 128);
278  memset(&headerBuffer[0], 0, sizeof(headerBuffer.size()));
279  memset(&receiveHeader, 0, sizeof(receiveHeader));
280 }
281 
282 void ImageProtocol::Pimpl::setTransferImageSet(const ImageSet& imageSet) {
283  for (int i=0; i<imageSet.getNumberOfImages(); ++i) {
284  if(imageSet.getPixelData(i) == nullptr) {
285  throw ProtocolException("Image data is null pointer!");
286  }
287  }
288 
289  // Set header as first piece of data
290  copyHeaderToBuffer(imageSet, 0, 0, 0, &headerBuffer[IMAGE_HEADER_OFFSET]);
291  dataProt.resetTransfer();
292  int numTransferBlocks = imageSet.getNumberOfImages();
293  dataProt.setTransferHeader(&headerBuffer[IMAGE_HEADER_OFFSET], sizeof(HeaderData), numTransferBlocks);
294  for (int i=0; i<imageSet.getNumberOfImages(); ++i) {
295  int bits = getFormatBits(imageSet.getPixelFormat(i), false);
296  int rawDataLength = getFrameSize(imageSet.getWidth(), imageSet.getHeight(), 0, 0, 0, bits);
297  dataProt.setTransferBytes(i, rawDataLength);
298  }
299 
300  // Perform 12 bit packed encoding if necessary
301  int bits[ImageSet::MAX_SUPPORTED_IMAGES] = {0};
302  int rowSize[ImageSet::MAX_SUPPORTED_IMAGES] = {0};
303  const unsigned char* pixelData[ImageSet::MAX_SUPPORTED_IMAGES] = {nullptr};
304 
305  for(int i = 0; i<imageSet.getNumberOfImages(); i++) {
306  bits[i] = getFormatBits(imageSet.getPixelFormat(i), false);
307  rowSize[i] = imageSet.getWidth()*bits[i]/8;
308 
309  if(imageSet.getPixelFormat(i) != ImageSet::FORMAT_12_BIT_MONO) {
310  pixelData[i] = imageSet.getPixelData(i);
311  } else {
312  static std::vector<unsigned char> encodingBuffer[ImageSet::MAX_SUPPORTED_IMAGES];
313  encodingBuffer[i].resize(rowSize[i] * imageSet.getHeight());
314  BitConversions::encode12BitPacked(0, imageSet.getHeight(), imageSet.getPixelData(i),
315  &encodingBuffer[i][0], imageSet.getRowStride(i), rowSize[i], imageSet.getWidth());
316  pixelData[i] = &encodingBuffer[i][0];
317  }
318  }
319 
320  for (int i=0; i<imageSet.getNumberOfImages(); ++i) {
321  dataProt.setTransferData(i, const_cast<unsigned char*>(pixelData[i])); // these are always reserved memory or untile buffers
322  }
323 }
324 
325 void ImageProtocol::Pimpl::setRawTransferData(const ImageSet& metaData, const std::vector<unsigned char*>& rawData,
326  int firstTileWidth, int middleTilesWidth, int lastTileWidth) {
327  if(static_cast<int>(rawData.size()) != metaData.getNumberOfImages()) {
328  throw ProtocolException("Mismatch between metadata and number of image buffers!");
329  }
330 
331  // Set header as first piece of data
332  copyHeaderToBuffer(metaData, firstTileWidth, middleTilesWidth, lastTileWidth, &headerBuffer[IMAGE_HEADER_OFFSET]);
333  dataProt.resetTransfer();
334  int numTransferBlocks = metaData.getNumberOfImages();
335  dataProt.setTransferHeader(&headerBuffer[IMAGE_HEADER_OFFSET], sizeof(HeaderData), numTransferBlocks);
336  // Now set the size per channel (replaces old final size argument to setTransferHeader()
337  for (int i=0; i<metaData.getNumberOfImages(); ++i) {
338  int rawDataLength = getFrameSize(metaData.getWidth(), metaData.getHeight(),
339  firstTileWidth, middleTilesWidth, lastTileWidth, metaData.getBitsPerPixel(i));
340  dataProt.setTransferBytes(i, rawDataLength);
341  }
342 
343  for (int i=0; i<metaData.getNumberOfImages(); ++i) {
344  dataProt.setTransferData(i, rawData[i]);
345  }
346 }
347 
348 void ImageProtocol::Pimpl::setRawValidBytes(const std::vector<int>& validBytesVec) {
349  for (int i=0; i<static_cast<int>(validBytesVec.size()); ++i) {
350  dataProt.setTransferValidBytes(i, validBytesVec[i]);
351  }
352 }
353 
354 const unsigned char* ImageProtocol::Pimpl::getTransferMessage(int& length) {
355  const unsigned char* msg = dataProt.getTransferMessage(length);
356 
357  if(msg == nullptr) {
358  msg = dataProt.getTransferMessage(length);
359  }
360 
361  return msg;
362 }
363 
364 bool ImageProtocol::Pimpl::transferComplete() {
365  return dataProt.transferComplete();
366 }
367 
368 int ImageProtocol::Pimpl::getNumTiles(int width, int firstTileWidth, int middleTilesWidth, int lastTileWidth) {
369  if(lastTileWidth == 0) {
370  return 1;
371  } else if(middleTilesWidth == 0) {
372  return 2;
373  } else {
374  int tileWidth = firstTileWidth + lastTileWidth - middleTilesWidth;
375  return (width - 2*tileWidth + firstTileWidth + lastTileWidth) / (firstTileWidth + lastTileWidth - tileWidth);
376  }
377 }
378 
379 int ImageProtocol::Pimpl::getFrameSize(int width, int height, int firstTileWidth,
380  int middleTilesWidth, int lastTileWidth, int totalBits) {
381  return (width * height * totalBits) /8;
382 }
383 
384 int ImageProtocol::Pimpl::getFormatBits(ImageSet::ImageFormat format, bool afterDecode) {
385  if(afterDecode) {
386  return ImageSet::getBytesPerPixel(format)*8;
387  } else {
388  switch(format) {
389  case ImageSet::FORMAT_8_BIT_MONO: return 8;
390  case ImageSet::FORMAT_12_BIT_MONO: return 12;
391  case ImageSet::FORMAT_8_BIT_RGB: return 24;
392  default: throw ProtocolException("Illegal pixel format!");
393  }
394  }
395 }
396 
397 void ImageProtocol::Pimpl::copyHeaderToBuffer(const ImageSet& imageSet,
398  int firstTileWidth, int middleTilesWidth, int lastTileWidth, unsigned char* buffer) {
399  int timeSec = 0, timeMicrosec = 0;
400  HeaderData* transferHeader = reinterpret_cast<HeaderData*>(buffer);
401 
402  memset(transferHeader, 0, sizeof(*transferHeader));
403  transferHeader->magic = htons(MAGIC_SEQUECE);
404  transferHeader->protocolVersion = InternalInformation::CURRENT_PROTOCOL_VERSION;
405  transferHeader->isRawImagePair_OBSOLETE = 0;
406  transferHeader->width = htons(imageSet.getWidth());
407  transferHeader->height = htons(imageSet.getHeight());
408  transferHeader->firstTileWidth = htons(firstTileWidth);
409  transferHeader->lastTileWidth = htons(lastTileWidth);
410  transferHeader->middleTilesWidth = htons(middleTilesWidth);
411  transferHeader->format0 = static_cast<unsigned char>(imageSet.getPixelFormat(0));
412  transferHeader->format1 = (imageSet.getNumberOfImages() <= 1) ? 0 : static_cast<unsigned char>(imageSet.getPixelFormat(1));
413  transferHeader->seqNum = static_cast<unsigned int>(htonl(imageSet.getSequenceNumber()));
414  transferHeader->format2 = (imageSet.getNumberOfImages() <= 2) ? 0 : static_cast<unsigned char>(imageSet.getPixelFormat(2));
415  transferHeader->format3 = (imageSet.getNumberOfImages() <= 3) ? 0 : static_cast<unsigned char>(imageSet.getPixelFormat(3));
416  transferHeader->numberOfImages = static_cast<unsigned char>(imageSet.getNumberOfImages());
417  transferHeader->exposureTime = htonl(imageSet.getExposureTime());
418 
419  imageSet.getLastSyncPulse(timeSec, timeMicrosec);
420  transferHeader->lastSyncPulseSec = htonl(timeSec);
421  transferHeader->lastSyncPulseMicrosec = htonl(timeMicrosec);
422 
423  transferHeader->totalHeaderSize = htons(sizeof(HeaderData));
424  transferHeader->flags = htons(HeaderData::FlagBits::NEW_STYLE_TRANSFER | HeaderData::FlagBits::HEADER_V3
425  | HeaderData::FlagBits::HEADER_V4 | HeaderData::FlagBits::HEADER_V5);
426 
427  int minDisp = 0, maxDisp = 0;
428  imageSet.getDisparityRange(minDisp, maxDisp);
429  transferHeader->minDisparity = minDisp;
430  transferHeader->maxDisparity = maxDisp;
431 
432  transferHeader->subpixelFactor = imageSet.getSubpixelFactor();
433 
434  imageSet.getTimestamp(timeSec, timeMicrosec);
435  transferHeader->timeSec = static_cast<int>(htonl(static_cast<unsigned int>(timeSec)));
436  transferHeader->timeMicrosec = static_cast<int>(htonl(static_cast<unsigned int>(timeMicrosec)));
437 
438  int numImageChannels = 0;
439  for (int i=0; i<(int) sizeof(transferHeader->imageTypes); ++i) {
440  transferHeader->imageTypes[i] = static_cast<unsigned char>(ImageSet::ImageType::IMAGE_UNDEFINED);
441  }
442  int idx = imageSet.getIndexOf(ImageSet::ImageType::IMAGE_LEFT);
443  if (idx>=0) {
444  transferHeader->imageTypes[idx] = static_cast<unsigned char>(ImageSet::ImageType::IMAGE_LEFT);
445  numImageChannels++;
446  }
447  idx = imageSet.getIndexOf(ImageSet::ImageType::IMAGE_RIGHT);
448  if (idx>=0) {
449  transferHeader->imageTypes[idx] = static_cast<unsigned char>(ImageSet::ImageType::IMAGE_RIGHT);
450  numImageChannels++;
451  }
452  idx = imageSet.getIndexOf(ImageSet::ImageType::IMAGE_DISPARITY);
453  if (idx>=0) {
454  transferHeader->imageTypes[idx] = static_cast<unsigned char>(ImageSet::ImageType::IMAGE_DISPARITY);
455  numImageChannels++;
456  }
457  idx = imageSet.getIndexOf(ImageSet::ImageType::IMAGE_COLOR);
458  if (idx>=0) {
459  transferHeader->imageTypes[idx] = static_cast<unsigned char>(ImageSet::ImageType::IMAGE_COLOR);
460  numImageChannels++;
461  }
462  if (numImageChannels != imageSet.getNumberOfImages()) {
463  throw std::runtime_error("Mismatch between reported number of images and enabled channel selection!");
464  }
465 
466 
467  if(imageSet.getQMatrix() != nullptr) {
468  memcpy(transferHeader->q, imageSet.getQMatrix(), sizeof(float)*16);
469  }
470 }
471 
472 void ImageProtocol::Pimpl::resetTransfer() {
473  dataProt.resetTransfer();
474 }
475 
476 unsigned char* ImageProtocol::Pimpl::getNextReceiveBuffer(int& maxLength) {
477  maxLength = dataProt.getMaxReceptionSize();
478  return dataProt.getNextReceiveBuffer(maxLength);
479 }
480 
481 void ImageProtocol::Pimpl::processReceivedMessage(int length) {
482  receptionDone = false;
483 
484  // Add the received message
485  dataProt.processReceivedMessage(length, receptionDone);
486  if(!dataProt.wasHeaderReceived() && receiveHeaderParsed) {
487  // Something went wrong. We need to reset!
488  LOG_DEBUG_IMPROTO("Resetting image protocol!");
489  resetReception();
490  return;
491  }
492 
493  int receivedBytes = 0;
494  dataProt.getReceivedData(receivedBytes);
495 
496  // Immediately try to decode the header
497  if(!receiveHeaderParsed) {
498  int headerLen = 0;
499  unsigned char* headerData = dataProt.getReceivedHeader(headerLen);
500  if(headerData != nullptr) {
501  tryDecodeHeader(headerData, headerLen);
502  }
503  }
504 }
505 
506 void ImageProtocol::Pimpl::tryDecodeHeader(const
507 unsigned char* receivedData, int receivedBytes) {
508  // Extra data fields that have been added to the header. Must be
509  // removed when the protocol version number is updated
510  constexpr int optionalDataSize = sizeof(receiveHeader.middleTilesWidth);
511  constexpr int mandatoryDataSize = static_cast<int>(sizeof(HeaderDataLegacy)) - optionalDataSize;
512  constexpr int fullyExtensibleHeaderSize = static_cast<int>(sizeof(HeaderDataV2));
513  bool isCompleteHeader = false;
514 
515  if(receivedBytes >= mandatoryDataSize) {
516  if (receivedBytes < fullyExtensibleHeaderSize) {
517  *(static_cast<HeaderDataLegacy*>(&receiveHeader)) = *reinterpret_cast<const HeaderDataLegacy*>(receivedData);
518  } else {
519  memcpy(&receiveHeader, receivedData, std::min((size_t)receivedBytes, sizeof(HeaderData)));
520  receiveHeader = *reinterpret_cast<const HeaderData*>(receivedData);
521  isCompleteHeader = true;
522  }
523  if(receiveHeader.magic != htons(MAGIC_SEQUECE)) {
524  // Let's not call this an error. Perhaps it's just not a header
525  // packet
526  return;
527  }
528 
529  if(receiveHeader.protocolVersion != InternalInformation::CURRENT_PROTOCOL_VERSION) {
530  throw ProtocolException("Protocol version mismatch!");
531  }
532 
533  // Convert byte order
534  receiveHeader.width = ntohs(receiveHeader.width);
535  receiveHeader.height = ntohs(receiveHeader.height);
536  receiveHeader.firstTileWidth = ntohs(receiveHeader.firstTileWidth);
537  receiveHeader.lastTileWidth = ntohs(receiveHeader.lastTileWidth);
538 
539  receiveHeader.timeSec = static_cast<int>(
540  ntohl(static_cast<unsigned int>(receiveHeader.timeSec)));
541  receiveHeader.timeMicrosec = static_cast<int>(
542  ntohl(static_cast<unsigned int>(receiveHeader.timeMicrosec)));
543  receiveHeader.seqNum = ntohl(receiveHeader.seqNum);
544 
545  // Optional data items
546  if(receivedBytes >= mandatoryDataSize + optionalDataSize) {
547  receiveHeader.middleTilesWidth = ntohs(receiveHeader.middleTilesWidth);
548  } else {
549  receiveHeader.middleTilesWidth = 0;
550  }
551  if (isCompleteHeader) {
552  // This is a header of v2 or above, which self-reports its extension level in the flags field
553  receiveHeader.totalHeaderSize = ntohs(receiveHeader.totalHeaderSize);
554  receiveHeader.flags = ntohs(receiveHeader.flags);
555  receiveHeader.exposureTime = ntohl(receiveHeader.exposureTime);
556  receiveHeader.lastSyncPulseSec = htonl(receiveHeader.lastSyncPulseSec);
557  receiveHeader.lastSyncPulseMicrosec = htonl(receiveHeader.lastSyncPulseMicrosec);
558  } else {
559  // Infer missing fields for legacy compatibility transfers
560  receiveHeader.totalHeaderSize = (receivedBytes <= mandatoryDataSize) ? mandatoryDataSize : static_cast<int>(sizeof(HeaderDataLegacy));
561  receiveHeader.flags = 0;
562  receiveHeader.numberOfImages = 2;
563  receiveHeader.format2 = 0;
564  receiveHeader.format3 = 0;
565  receiveHeader.exposureTime = 0;
566  receiveHeader.lastSyncPulseSec = 0;
567  receiveHeader.lastSyncPulseMicrosec = 0;
568  }
569 
570  receiveHeaderParsed = true;
571  }
572 }
573 
574 bool ImageProtocol::Pimpl::imagesReceived() const {
575  return receptionDone && receiveHeaderParsed;
576 }
577 
578 bool ImageProtocol::Pimpl::getReceivedImageSet(ImageSet& imageSet) {
579  bool complete = false;
580  int validRows;
581  bool ok = getPartiallyReceivedImageSet(imageSet, validRows, complete);
582 
583  return (ok && complete);
584 }
585 
586 bool ImageProtocol::Pimpl::getPartiallyReceivedImageSet(ImageSet& imageSet, int& validRows, bool& complete) {
587  imageSet.setWidth(0);
588  imageSet.setHeight(0);
589 
590  complete = false;
591 
592  if(!receiveHeaderParsed) {
593  // We haven't even received the image header yet
594  return false;
595  } else {
596  // We received at least some pixel data
597  imageSet.setNumberOfImages(receiveHeader.numberOfImages);
598  bool flaggedDisparityPair = (receiveHeader.isRawImagePair_OBSOLETE == 0); // only meaningful in headers <=V2
599  bool isInterleaved = (receiveHeader.flags & HeaderData::FlagBits::NEW_STYLE_TRANSFER) == 0;
600  bool arbitraryChannels = (receiveHeader.flags & HeaderData::FlagBits::HEADER_V3) > 0;
601  bool hasExposureTime = (receiveHeader.flags & HeaderData::FlagBits::HEADER_V4) > 0;
602 
603  // Forward compatibility check: mask out all known flag bits and see what remains
604  unsigned short unaccountedFlags = receiveHeader.flags & ~(HeaderData::FlagBits::NEW_STYLE_TRANSFER
605  | HeaderData::FlagBits::HEADER_V3 | HeaderData::FlagBits::HEADER_V4 | HeaderData::FlagBits::HEADER_V5);
606  if (unaccountedFlags != 0) {
607  // Newer protocol (unknown flag present) - we will try to continue
608  // since connection has not been refused earlier
609  static bool warnedOnceForward = false;
610  if (!warnedOnceForward) {
611  LOG_DEBUG_IMPROTO("Warning: forward-compatible mode; will attempt to process image stream with unknown extra flags. Consider upgrading the client software.");
612  warnedOnceForward = true;
613  }
614  }
615 
616  imageSet.setWidth(receiveHeader.width);
617  imageSet.setHeight(receiveHeader.height);
618 
619  imageSet.setPixelFormat(0, static_cast<ImageSet::ImageFormat>(receiveHeader.format0));
620  if (imageSet.getNumberOfImages() > 1) imageSet.setPixelFormat(1, static_cast<ImageSet::ImageFormat>(receiveHeader.format1));
621  if (imageSet.getNumberOfImages() > 2) imageSet.setPixelFormat(2, static_cast<ImageSet::ImageFormat>(receiveHeader.format2));
622  if (imageSet.getNumberOfImages() > 3) imageSet.setPixelFormat(3, static_cast<ImageSet::ImageFormat>(receiveHeader.format3));
623 
624  int rowStrideArr[ImageSet::MAX_SUPPORTED_IMAGES] = {0};
625  int validRowsArr[ImageSet::MAX_SUPPORTED_IMAGES] = {0};
626  unsigned char* pixelArr[ImageSet::MAX_SUPPORTED_IMAGES] = {nullptr};
627 
628  if (isInterleaved) {
629  // OLD transfer (forced to interleaved 2 images mode)
630  static bool warnedOnceBackward = false;
631  if (!warnedOnceBackward) {
632  LOG_DEBUG_IMPROTO("Info: backward-compatible mode; the device is sending with a legacy protocol. Consider upgrading its firmware.");
633  warnedOnceBackward = true;
634  }
635  unsigned char* data = dataProt.getBlockReceiveBuffer(0);
636  int validBytes = dataProt.getBlockValidSize(0);
637  for (int i=0; i < 2; ++i) {
638  pixelArr[i] = decodeInterleaved(i, imageSet.getNumberOfImages(), validBytes, data, validRowsArr[i], rowStrideArr[i]);
639  }
640  // Legacy sender with mode-dependent channel selection
641  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_LEFT, 0);
642  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_RIGHT, flaggedDisparityPair ? -1 : 1);
643  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_DISPARITY, flaggedDisparityPair ? 1 : -1);
644  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_COLOR, -1);
645  } else {
646  // NEW transfer
647  try {
648  for (int i=0; i<receiveHeader.numberOfImages; ++i) {
649  unsigned char* data = dataProt.getBlockReceiveBuffer(i);
650  int validBytes = dataProt.getBlockValidSize(i);
651  pixelArr[i] = decodeNoninterleaved(i, imageSet.getNumberOfImages(), validBytes, data, validRowsArr[i], rowStrideArr[i]);
652  }
653  } catch(const ProtocolException& ex) {
654  LOG_DEBUG_IMPROTO("Protocol exception: " << ex.what());
655  resetReception();
656  return false;
657  }
658  if (arbitraryChannels) {
659  // Completely customizable channel selection
660  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_LEFT, -1);
661  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_RIGHT, -1);
662  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_DISPARITY, -1);
663  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_COLOR, -1);
664  for (int i=0; i<imageSet.getNumberOfImages(); ++i) {
665  int typ = receiveHeader.imageTypes[i];
666  ImageSet::ImageType imgtype = static_cast<ImageSet::ImageType>(typ);
667  imageSet.setIndexOf(imgtype, i);
668  }
669  } else {
670  static bool warnedOnceV2 = false;
671  if (!warnedOnceV2) {
672  LOG_DEBUG_IMPROTO("Info: received a transfer with header v2");
673  warnedOnceV2 = true;
674  }
675  // Older v2 header; accessing imageTypes is not valid
676  // Two-image sender with mode-dependent channel selection
677  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_LEFT, 0);
678  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_RIGHT, flaggedDisparityPair ? -1 : 1);
679  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_DISPARITY, flaggedDisparityPair ? 1 : -1);
680  imageSet.setIndexOf(ImageSet::ImageType::IMAGE_COLOR, -1);
681  }
682  if(hasExposureTime) {
683  imageSet.setExposureTime(receiveHeader.exposureTime);
684  imageSet.setLastSyncPulse(receiveHeader.lastSyncPulseSec, receiveHeader.lastSyncPulseMicrosec);
685  }
686  }
687 
688  for (int i=0; i<receiveHeader.numberOfImages; ++i) {
689  imageSet.setRowStride(i, rowStrideArr[i]);
690  imageSet.setPixelData(i, pixelArr[i]);
691  }
692  imageSet.setQMatrix(receiveHeader.q);
693 
694  imageSet.setSequenceNumber(receiveHeader.seqNum);
695  imageSet.setTimestamp(receiveHeader.timeSec, receiveHeader.timeMicrosec);
696  imageSet.setDisparityRange(receiveHeader.minDisparity, receiveHeader.maxDisparity);
697  imageSet.setSubpixelFactor(receiveHeader.subpixelFactor);
698 
699  validRows = validRowsArr[0];
700  for (int i=0; i<receiveHeader.numberOfImages; ++i) {
701  if (validRowsArr[i] < validRows) {
702  validRows = validRowsArr[i];
703  }
704  }
705 
706  if(validRows == receiveHeader.height || receptionDone) {
707  complete = true;
708  resetReception();
709  }
710 
711  return true;
712  }
713 }
714 
715 unsigned char* ImageProtocol::Pimpl::decodeNoninterleaved(int imageNumber, int numImages, int receivedBytes,
716  unsigned char* data, int& validRows, int& rowStride) {
717  ImageSet::ImageFormat format;
718  int bits = 8;
719  switch (imageNumber) {
720  case 0:
721  format = static_cast<ImageSet::ImageFormat>(receiveHeader.format0);
722  break;
723  case 1:
724  format = static_cast<ImageSet::ImageFormat>(receiveHeader.format1);
725  break;
726  case 2:
727  format = static_cast<ImageSet::ImageFormat>(receiveHeader.format2);
728  break;
729  case 3:
730  format = static_cast<ImageSet::ImageFormat>(receiveHeader.format3);
731  break;
732  default:
733  throw ProtocolException("Not implemented: decodeNoninterleaved with image index > 2");
734  }
735  bits = getFormatBits(static_cast<ImageSet::ImageFormat>(format), false);
736 
737  int totalBits = bits;
738  unsigned char* ret = nullptr;
739 
740  if(receiveHeader.lastTileWidth == 0) {
741  int bufferOffset0 = 0;
742  int bufferRowStride = receiveHeader.width*(totalBits) / 8;
743 
744  if(format == ImageSet::FORMAT_8_BIT_MONO || format == ImageSet::FORMAT_8_BIT_RGB) {
745  // No decoding is necessary. We can just pass through the
746  // data pointer
747  ret = &data[bufferOffset0];
748  rowStride = bufferRowStride;
749  validRows = std::min(receivedBytes / bufferRowStride, (int)receiveHeader.height);
750  } else {
751  // Perform 12-bit => 16 bit decoding
752  allocateDecodeBuffer(imageNumber);
753  validRows = std::min(receivedBytes / bufferRowStride, (int)receiveHeader.height);
754  rowStride = 2*receiveHeader.width;
755  int lastRow = std::min(lastReceivedPayloadBytes[imageNumber] / bufferRowStride, validRows);
756 
757  BitConversions::decode12BitPacked(lastRow, validRows, &data[bufferOffset0],
758  &decodeBuffer[imageNumber][0], bufferRowStride, rowStride, receiveHeader.width);
759 
760  ret = &decodeBuffer[imageNumber][0];
761  }
762  } else {
763  // Decode the tiled transfer
764  decodeTiledImage(imageNumber,
765  lastReceivedPayloadBytes[imageNumber], receivedBytes, data,
766  receiveHeader.firstTileWidth * (totalBits) / 8,
767  receiveHeader.middleTilesWidth * (totalBits) / 8,
768  receiveHeader.lastTileWidth * (totalBits) / 8,
769  validRows, format, false);
770  ret = &decodeBuffer[imageNumber][0];
771  rowStride = receiveHeader.width*getFormatBits(
772  static_cast<ImageSet::ImageFormat>(format), true)/8;
773  }
774 
775  lastReceivedPayloadBytes[imageNumber] = receivedBytes;
776  return ret;
777 }
778 
779 
780 unsigned char* ImageProtocol::Pimpl::decodeInterleaved(int imageNumber, int numImages, int receivedBytes,
781  unsigned char* data, int& validRows, int& rowStride) {
782  ImageSet::ImageFormat format = static_cast<ImageSet::ImageFormat>(
783  imageNumber == 0 ? receiveHeader.format0 : receiveHeader.format1);
784  int bits0 = getFormatBits(static_cast<ImageSet::ImageFormat>(receiveHeader.format0), false);
785  int bits1 = getFormatBits(static_cast<ImageSet::ImageFormat>(receiveHeader.format1), false);
786  int bits2 = getFormatBits(static_cast<ImageSet::ImageFormat>(receiveHeader.format2), false);
787  int bits3 = getFormatBits(static_cast<ImageSet::ImageFormat>(receiveHeader.format3), false);
788 
789  int totalBits = (numImages<3)?(bits0 + bits1):(bits0 + bits1 + bits2 + bits3);
790 
791  unsigned char* ret = nullptr;
792 
793  if(receiveHeader.lastTileWidth == 0) {
794  int bufferOffset;
795  switch (imageNumber) {
796  case 0: { bufferOffset = 0; break; }
797  case 1: { bufferOffset = receiveHeader.width * bits0/8; break; }
798  case 2: { bufferOffset = receiveHeader.width * (bits0 + bits1)/8; break; }
799  default:
800  throw ProtocolException("Not implemented: image index > 2");
801  }
802  int bufferRowStride = receiveHeader.width*(totalBits) / 8;
803 
804  if(format == ImageSet::FORMAT_8_BIT_MONO || format == ImageSet::FORMAT_8_BIT_RGB) {
805  // No decoding is necessary. We can just pass through the
806  // data pointer
807  ret = &data[bufferOffset];
808  rowStride = bufferRowStride;
809  validRows = receivedBytes / bufferRowStride;
810  } else {
811  // Perform 12-bit => 16 bit decoding
812  allocateDecodeBuffer(imageNumber);
813  validRows = std::min(receivedBytes / bufferRowStride, (int)receiveHeader.height);
814  rowStride = 2*receiveHeader.width;
815  int lastRow = lastReceivedPayloadBytes[imageNumber] / bufferRowStride;
816 
817  BitConversions::decode12BitPacked(lastRow, validRows, &data[bufferOffset],
818  &decodeBuffer[imageNumber][0], bufferRowStride, rowStride, receiveHeader.width);
819 
820  ret = &decodeBuffer[imageNumber][0];
821  }
822  } else {
823  // Decode the tiled transfer
824  decodeTiledImage(imageNumber,
825  lastReceivedPayloadBytes[imageNumber], receivedBytes, data,
826  receiveHeader.firstTileWidth * (totalBits) / 8,
827  receiveHeader.middleTilesWidth * (totalBits) / 8,
828  receiveHeader.lastTileWidth * (totalBits) / 8,
829  validRows, format, true);
830  ret = &decodeBuffer[imageNumber][0];
831  rowStride = receiveHeader.width*getFormatBits(
832  static_cast<ImageSet::ImageFormat>(format), true)/8;
833  }
834 
835  lastReceivedPayloadBytes[imageNumber] = receivedBytes;
836  return ret;
837 }
838 
839 void ImageProtocol::Pimpl::allocateDecodeBuffer(int imageNumber) {
840  ImageSet::ImageFormat format;
841  switch (imageNumber) {
842  case 0:
843  format = static_cast<ImageSet::ImageFormat>(receiveHeader.format0);
844  break;
845  case 1:
846  format = static_cast<ImageSet::ImageFormat>(receiveHeader.format1);
847  break;
848  case 2:
849  format = static_cast<ImageSet::ImageFormat>(receiveHeader.format2);
850  break;
851  case 3:
852  format = static_cast<ImageSet::ImageFormat>(receiveHeader.format3);
853  break;
854  default:
855  throw ProtocolException("Not implemented: allocateDecodeBuffer with image index > 2");
856  }
857  int bitsPerPixel = getFormatBits(format, true);
858  int bufferSize = receiveHeader.width * receiveHeader.height * bitsPerPixel / 8;
859 
860  if(decodeBuffer[imageNumber].size() != static_cast<unsigned int>(bufferSize)) {
861  decodeBuffer[imageNumber].resize(bufferSize);
862  }
863 }
864 
865 void ImageProtocol::Pimpl::decodeTiledImage(int imageNumber, int lastReceivedPayloadBytes, int receivedPayloadBytes,
866  const unsigned char* data, int firstTileStride, int middleTilesStride, int lastTileStride, int& validRows,
867  ImageSet::ImageFormat format, bool dataIsInterleaved) {
868  // Allocate a decoding buffer
869  allocateDecodeBuffer(imageNumber);
870 
871  // Get beginning and end of first tile
872  int numTiles = getNumTiles(receiveHeader.width, receiveHeader.firstTileWidth,
873  receiveHeader.middleTilesWidth, receiveHeader.lastTileWidth);
874  int payloadOffset = 0;
875  int decodeXOffset = 0;
876  int prevTileStrides = 0;
877  for(int i = 0; i < numTiles; i++) {
878  // Get relevant parameters
879  int tileWidth = 0;
880  int tileStride = 0;
881 
882  if(i == 0) {
883  tileStride = firstTileStride;
884  tileWidth = receiveHeader.firstTileWidth;
885  } else if(i == numTiles-1) {
886  tileStride = lastTileStride;
887  tileWidth = receiveHeader.lastTileWidth;
888  } else {
889  tileStride = middleTilesStride;
890  tileWidth = receiveHeader.middleTilesWidth;
891  }
892 
893  int tileStart = std::max(0, (lastReceivedPayloadBytes - payloadOffset) / tileStride);
894  int tileStop = std::min(std::max(0, (receivedPayloadBytes - payloadOffset) / tileStride), (int)receiveHeader.height);
895  int tileOffset;
896  if (dataIsInterleaved) {
897  switch (imageNumber) {
898  case 0: { tileOffset = 0; break; }
899  case 1: { tileOffset = tileWidth * (
900  getFormatBits(static_cast<ImageSet::ImageFormat>(receiveHeader.format0), false)
901  )/8; break; }
902  case 2: { tileOffset = tileWidth * (
903  getFormatBits(static_cast<ImageSet::ImageFormat>(receiveHeader.format0), false)
904  + getFormatBits(static_cast<ImageSet::ImageFormat>(receiveHeader.format1), false)
905  )/8; break; }
906  default:
907  throw ProtocolException("Not implemented: image index > 2");
908  }
909  } else {
910  tileOffset = 0;
911  }
912  if(i > 0) {
913  tileOffset += receiveHeader.height * prevTileStrides;
914  }
915 
916  // Decode
917  int bytesPixel;
918  if(format == ImageSet::FORMAT_12_BIT_MONO) {
919  bytesPixel = 2;
920  BitConversions::decode12BitPacked(tileStart, tileStop, &data[tileOffset],
921  &decodeBuffer[imageNumber][decodeXOffset], tileStride, 2*receiveHeader.width, tileWidth);
922  } else {
923  bytesPixel = (format == ImageSet::FORMAT_8_BIT_RGB ? 3 : 1);
924  decodeRowsFromTile(tileStart, tileStop, &data[tileOffset],
925  &decodeBuffer[imageNumber][decodeXOffset], tileStride,
926  receiveHeader.width*bytesPixel, tileWidth*bytesPixel);
927  }
928 
929  payloadOffset += receiveHeader.height * tileStride;
930  decodeXOffset += tileWidth * bytesPixel;
931  prevTileStrides += tileStride;
932  if(i == numTiles-1) {
933  validRows = tileStop;
934  }
935  }
936 }
937 
938 void ImageProtocol::Pimpl::decodeRowsFromTile(int startRow, int stopRow, unsigned const char* src,
939  unsigned char* dst, int srcStride, int dstStride, int tileWidth) {
940  for(int y = startRow; y < stopRow; y++) {
941  memcpy(&dst[y*dstStride], &src[y*srcStride], tileWidth);
942  }
943 }
944 
945 void ImageProtocol::Pimpl::resetReception() {
946  receiveHeaderParsed = false;
947  for (int i=0; i<ImageSet::MAX_SUPPORTED_IMAGES; ++i) {
948  lastReceivedPayloadBytes[i] = 0;
949  }
950  dataProt.resetReception(false);
951  receptionDone = false;
952 }
953 
954 bool ImageProtocol::Pimpl::isConnected() const {
955  return dataProt.isConnected();
956 }
957 
958 const unsigned char* ImageProtocol::Pimpl::getNextControlMessage(int& length) {
959  return dataProt.getNextControlMessage(length);
960 }
961 
962 bool ImageProtocol::Pimpl::newClientConnected() {
963  return dataProt.newClientConnected();
964 }
965 
966 int ImageProtocol::Pimpl::getNumDroppedFrames() const {
967  return dataProt.getDroppedReceptions();
968 }
969 
970 std::string ImageProtocol::statusReport() {
971  return pimpl->statusReport();
972 }
973 std::string ImageProtocol::Pimpl::statusReport() {
974  return dataProt.statusReport();
975 }
976 
977 
978 
979 } // namespace
980 
visiontransfer::ImageSet::getQMatrix
const float * getQMatrix() const
Returns a pointer to the disparity-to-depth mapping matrix q.
Definition: imageset.h:320
visiontransfer::ImageSet::setDisparityRange
void setDisparityRange(int minimum, int maximum)
Sets the value range for the disparity map contained in this image set.
Definition: imageset.h:202
visiontransfer::ImageSet::getHeight
int getHeight() const
Returns the height of each image.
Definition: imageset.h:234
visiontransfer::ImageProtocol::setRawTransferData
void setRawTransferData(const ImageSet &metaData, const std::vector< unsigned char * > &imageData, int firstTileWidth=0, int middleTilesWidth=0, int lastTileWidth=0)
Sets the already pre-formatted image data for the next transfer.
Definition: imageprotocol.cpp:208
visiontransfer::ImageSet::setQMatrix
void setQMatrix(const float *q)
Sets the pointer to the disparity-to-depth mapping matrix q.
Definition: imageset.h:172
visiontransfer::ImageSet::getWidth
int getWidth() const
Returns the width of each image.
Definition: imageset.h:229
visiontransfer::ImageSet::setIndexOf
void setIndexOf(ImageType what, int idx)
Assign an image index to a specified ImageType, -1 to disable.
Definition: imageset.cpp:240
visiontransfer::ImageSet::setExposureTime
void setExposureTime(int timeMicrosec)
Sets the exposure time that was used for capturing the image set.
Definition: imageset.h:499
visiontransfer::ImageSet::setTimestamp
void setTimestamp(int seconds, int microsec)
Sets the time at which this image set has been captured.
Definition: imageset.h:190
visiontransfer::ImageSet::getRowStride
int getRowStride(int imageNumber) const
Returns the row stride for the pixel data of one image.
Definition: imageset.h:245
visiontransfer::ImageSet::getNumberOfImages
int getNumberOfImages() const
Returns the number of images in this set.
Definition: imageset.h:431
visiontransfer::ImageSet::setPixelData
void setPixelData(int imageNumber, unsigned char *pixelData)
Sets the pixel data for the given image.
Definition: imageset.h:161
visiontransfer::ImageSet::getSubpixelFactor
int getSubpixelFactor() const
Gets the subpixel factor for this image set.
Definition: imageset.h:357
visiontransfer::internal::DataBlockProtocol::HeaderPreamble
Definition: datablockprotocol.h:100
visiontransfer::ImageSet::setSequenceNumber
void setSequenceNumber(unsigned int num)
Sets the sequence number for this image set.
Definition: imageset.h:179
visiontransfer::ImageProtocol::resetReception
void resetReception()
Aborts the reception of the current image transfer and resets the internal state.
Definition: imageprotocol.cpp:254
visiontransfer::ImageSet::getIndexOf
int getIndexOf(ImageType what, bool throwIfNotFound=false) const
Returns the index of a specific image type.
Definition: imageset.cpp:214
visiontransfer::ImageSet
A set of one to three images, but usually two (the left camera image and the disparity map)....
Definition: imageset.h:50
visiontransfer::ImageProtocol::getReceivedImageSet
bool getReceivedImageSet(ImageSet &imageSet)
Returns a received image when complete.
Definition: imageprotocol.cpp:229
visiontransfer::internal::DataBlockProtocol
A protocol for transmitting large blocks of data over a network.
Definition: datablockprotocol.h:70
visiontransfer::ImageSet::FORMAT_8_BIT_RGB
@ FORMAT_8_BIT_RGB
8-bit RGB format
Definition: imageset.h:73
visiontransfer::ImageSet::getBitsPerPixel
int getBitsPerPixel(int imageNumber) const
Returns the number of bits that are required to store one image pixel.
Definition: imageset.h:410
visiontransfer::ImageSet::getTimestamp
void getTimestamp(int &seconds, int &microsec) const
Returns the time at which this image set has been captured.
Definition: imageset.h:336
visiontransfer::ImageSet::setRowStride
void setRowStride(int imageNumber, int stride)
Sets a new row stride for the pixel data of one image.
Definition: imageset.h:131
visiontransfer::ImageProtocol::processReceivedMessage
void processReceivedMessage(int length)
Handles a received network message.
Definition: imageprotocol.cpp:246
visiontransfer::ImageProtocol::getNextControlMessage
const unsigned char * getNextControlMessage(int &length)
If a control message is pending to be transmitted then the message data will be returned by this meth...
Definition: imageprotocol.cpp:262
visiontransfer::ImageSet::getExposureTime
int getExposureTime() const
Gets the exposure time in microseconds that was used for capturing the image set.
Definition: imageset.h:509
visiontransfer::ImageProtocol::isConnected
bool isConnected() const
Returns true if a remote connection is established.
Definition: imageprotocol.cpp:258
visiontransfer::ImageSet::getBytesPerPixel
int getBytesPerPixel(int imageNumber) const
Returns the number of bytes that are required to store one image pixel.
Definition: imageset.h:399
visiontransfer::ImageSet::ImageType
ImageType
Supported image types.
Definition: imageset.h:91
visiontransfer::ImageSet::ImageFormat
ImageFormat
Image formats that can be transferred.
Definition: imageset.h:68
visiontransfer::ImageSet::getDisparityRange
void getDisparityRange(int &minimum, int &maximum) const
Gets the value range for the disparity map contained in this image set. If the image set does not con...
Definition: imageset.h:349
visiontransfer::ImageSet::setHeight
void setHeight(int h)
Sets a new width for both images.
Definition: imageset.h:122
visiontransfer::ImageProtocol::ProtocolType
ProtocolType
Supported network protocols.
Definition: imageprotocol.h:67
visiontransfer::ImageSet::setPixelFormat
void setPixelFormat(int imageNumber, ImageFormat format)
Sets the pixel format for the given image.
Definition: imageset.h:143
visiontransfer::ImageProtocol::getPartiallyReceivedImageSet
bool getPartiallyReceivedImageSet(ImageSet &imageSet, int &validRows, bool &complete)
Returns a partially received image.
Definition: imageprotocol.cpp:233
visiontransfer::ImageSet::setLastSyncPulse
void setLastSyncPulse(int seconds, int microsec)
Sets the timestamp of the last received sync pulse.
Definition: imageset.h:520
visiontransfer::ImageSet::getLastSyncPulse
void getLastSyncPulse(int &seconds, int &microsec) const
Gets the timestamp of the last received sync pulse.
Definition: imageset.h:532
visiontransfer::ImageProtocol::setTransferImageSet
void setTransferImageSet(const ImageSet &imageSet)
Sets a new image that will be transfer.
Definition: imageprotocol.cpp:204
visiontransfer::ImageProtocol::resetTransfer
void resetTransfer()
Aborts the transmission of the current transfer and performs a reset of the internal state.
Definition: imageprotocol.cpp:225
visiontransfer::ImageSet::FORMAT_12_BIT_MONO
@ FORMAT_12_BIT_MONO
Definition: imageset.h:77
visiontransfer::ImageProtocol::getNextReceiveBuffer
unsigned char * getNextReceiveBuffer(int &maxLength)
Returns the buffer for receiving the next network message.
Definition: imageprotocol.cpp:242
visiontransfer::ImageSet::FORMAT_8_BIT_MONO
@ FORMAT_8_BIT_MONO
8-bit greyscale format
Definition: imageset.h:70
visiontransfer::ImageProtocol::getNumDroppedFrames
int getNumDroppedFrames() const
Returns the number of frames that have been dropped since connecting to the current remote host.
Definition: imageprotocol.cpp:250
visiontransfer::ImageProtocol::setRawValidBytes
void setRawValidBytes(const std::vector< int > &validBytes)
Updates the number of valid bytes in a partial raw transfer.
Definition: imageprotocol.cpp:213
visiontransfer::ProtocolException
Exception class that is used for all protocol exceptions.
Definition: exceptions.h:37
visiontransfer::ImageProtocol::newClientConnected
bool newClientConnected()
Returns true if the last message has established a new connection from a client.
Definition: imageprotocol.cpp:266
visiontransfer::ImageSet::getPixelData
unsigned char * getPixelData(int imageNumber) const
Returns the pixel data for the given image.
Definition: imageset.h:299
visiontransfer::ImageSet::setSubpixelFactor
void setSubpixelFactor(int subpixFact)
Sets the subpixel factor for this image set.
Definition: imageset.h:210
visiontransfer::ImageSet::setWidth
void setWidth(int w)
Sets a new width for both images.
Definition: imageset.h:117
visiontransfer::ImageProtocol::transferComplete
bool transferComplete()
Returns true if the current transfer has been completed.
Definition: imageprotocol.cpp:221
visiontransfer::ImageProtocol::getTransferMessage
const unsigned char * getTransferMessage(int &length)
Gets the next network message for the current transfer.
Definition: imageprotocol.cpp:217
visiontransfer::ImageSet::getPixelFormat
ImageFormat getPixelFormat(int imageNumber) const
Returns the pixel format for the given image.
Definition: imageset.h:272
visiontransfer::ImageSet::setNumberOfImages
void setNumberOfImages(int number)
Sets the number of valid images in this set.
Definition: imageset.h:438
visiontransfer::ImageProtocol::imagesReceived
bool imagesReceived() const
Returns true if the images of the current transfer have been received.
Definition: imageprotocol.cpp:238
visiontransfer::ImageSet::getSequenceNumber
unsigned int getSequenceNumber() const
Returns the sequence number for this image set.
Definition: imageset.h:327
Allied Vision