libvisiontransfer  6.0.0
imageprotocol.cpp
1 /*******************************************************************************
2  * Copyright (c) 2018 Nerian Vision 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 using namespace std;
39 
40 /*************** Pimpl class containing all private members ***********/
41 
42 class ImageProtocol::Pimpl {
43 public:
44  Pimpl(bool server, ProtocolType protType, int maxUdpPacketSize);
45 
46  // Redeclaration of public members
47  void setTransferImagePair(const ImagePair& imagePair);
48  void setRawTransferData(const ImagePair& metaData, unsigned char* rawData,
49  int firstTileWidth = 0, int secondTileWidth = 0, int validBytes = 0x7FFFFFFF);
50  void setRawValidBytes(int validBytes);
51  const unsigned char* getTransferMessage(int& length);
52  bool transferComplete();
53  void resetTransfer();
54  bool getReceivedImagePair(ImagePair& imagePair);
55  bool getPartiallyReceivedImagePair(ImagePair& imagePair,
56  int& validRows, bool& complete);
57  bool imagesReceived() const;
58 
59  unsigned char* getNextReceiveBuffer(int& maxLength);
60 
61  void processReceivedMessage(int length);
62  int getProspectiveMessageSize();
63  int getNumDroppedFrames() const;
64  void resetReception();
65  bool isConnected() const;
66  const unsigned char* getNextControlMessage(int& length);
67  bool newClientConnected();
68 
69 private:
70  unsigned short MAGIC_SEQUECE = 0x3D15;
71 
72  // Header data transferred in the first packet
73 #pragma pack(push,1)
74  struct HeaderData{
75  unsigned short magic;
76 
77  unsigned char protocolVersion;
78  unsigned char isRawImagePair;
79 
80  unsigned short width;
81  unsigned short height;
82 
83  unsigned short firstTileWidth;
84  unsigned short secondTileWidth;
85 
86  unsigned char format0;
87  unsigned char format1;
88  unsigned char minDisparity;
89  unsigned char maxDisparity;
90 
91  unsigned int seqNum;
92  int timeSec;
93  int timeMicrosec;
94 
95  float q[16];
96  };
97 #pragma pack(pop)
98 
99  // Underlying protocol for data transfers
100  DataBlockProtocol dataProt;
101  ProtocolType protType;
102 
103  // Transfer related variables
104  std::vector<unsigned char> headerBuffer;
105  std::vector<unsigned char> rawBuffer;
106  unsigned char* rawData;
107 
108  // Reception related variables
109  std::vector<unsigned char, AlignedAllocator<unsigned char> >decodeBuffer[2];
110  bool receiveHeaderParsed;
111  HeaderData receiveHeader;
112  int lastReceivedPayloadBytes[2];
113  bool receptionDone;
114 
115  // Copies the transmission header to the given buffer
116  void copyHeaderToBuffer(const ImagePair& imagePair, int firstTileWidth,
117  int secondTileWidth, unsigned char* buffer);
118 
119  // Decodes header information from the received data
120  void tryDecodeHeader(const unsigned char* receivedData, int receivedBytes);
121 
122  // Decodes a received image from an interleaved buffer
123  unsigned char* decodeInterleaved(int imageNumber, int receivedBytes,
124  unsigned char* data, int& validRows, int& rowStride);
125 
126  int getFrameSize(int width, int height, int firstTileWidth, int secondTileWidth,
128 
129  int getFormatBits(ImagePair::ImageFormat format, bool afterDecode);
130 
131  void decodeTiledImage(int imageNumber, int lastReceivedPayloadBytes, int receivedPayloadBytes,
132  const unsigned char* data, int firstTileStride, int secondTileStride, int& validRows,
133  ImagePair::ImageFormat format);
134 
135  void decodeRowsFromTile(int startRow, int stopRow, unsigned const char* src,
136  unsigned char* dst, int srcStride, int dstStride, int tileWidth);
137 
138  void allocateDecodeBuffer(int imageNumber);
139 };
140 
141 
142 /******************** Stubs for all public members ********************/
143 
144 ImageProtocol::ImageProtocol(bool server, ProtocolType protType, int maxUdpPacketSize)
145  : pimpl(new Pimpl(server, protType, maxUdpPacketSize)) {
146  // All initializations are done by the Pimpl class
147 }
148 
149 ImageProtocol::~ImageProtocol() {
150  delete pimpl;
151 }
152 
154  pimpl->setTransferImagePair(imagePair);
155 }
156 
158  unsigned char* imageData, int firstTileWidth, int secondTileWidth, int validBytes) {
159  pimpl->setRawTransferData(metaData, imageData, firstTileWidth, secondTileWidth, validBytes);
160 }
161 
162 void ImageProtocol::setRawValidBytes(int validBytes) {
163  pimpl->setRawValidBytes(validBytes);
164 }
165 
166 const unsigned char* ImageProtocol::getTransferMessage(int& length) {
167  return pimpl->getTransferMessage(length);
168 }
169 
171  return pimpl->transferComplete();
172 }
173 
175  pimpl->resetTransfer();
176 }
177 
179  return pimpl->getReceivedImagePair(imagePair);
180 }
181 
183  ImagePair& imagePair, int& validRows, bool& complete) {
184  return pimpl->getPartiallyReceivedImagePair(imagePair, validRows, complete);
185 }
186 
188  return pimpl->imagesReceived();
189 }
190 
191 unsigned char* ImageProtocol::getNextReceiveBuffer(int& maxLength) {
192  return pimpl->getNextReceiveBuffer(maxLength);
193 }
194 
196  pimpl->processReceivedMessage(length);
197 }
198 
200  return pimpl->getNumDroppedFrames();
201 }
202 
204  pimpl->resetReception();
205 }
206 
208  return pimpl->isConnected();
209 }
210 
211 const unsigned char* ImageProtocol::getNextControlMessage(int& length) {
212  return pimpl->getNextControlMessage(length);
213 }
214 
216  return pimpl->newClientConnected();
217 }
218 
219 /******************** Implementation in pimpl class *******************/
220 
221 ImageProtocol::Pimpl::Pimpl(bool server, ProtocolType protType, int maxUdpPacketSize)
222  :dataProt(server, (DataBlockProtocol::ProtocolType)protType,
223  maxUdpPacketSize), protType(protType), rawData(nullptr),
224  receiveHeaderParsed(false), lastReceivedPayloadBytes{0, 0},
225  receptionDone(false) {
226  headerBuffer.resize(sizeof(HeaderData) + 32);
227  memset(&headerBuffer[0], 0, sizeof(headerBuffer.size()));
228  memset(&receiveHeader, 0, sizeof(receiveHeader));
229 }
230 
231 void ImageProtocol::Pimpl::setTransferImagePair(const ImagePair& imagePair) {
232  if(imagePair.getPixelData(0) == nullptr || imagePair.getPixelData(1) == nullptr) {
233  throw ProtocolException("Image data is null pointer!");
234  }
235 
236  // Determine the size of a frame
237  int rawDataLength = getFrameSize(imagePair.getWidth(), imagePair.getHeight(), 0, 0,
238  imagePair.getPixelFormat(0), imagePair.getPixelFormat(1));
239 
240  // Set header as first piece of data
241  copyHeaderToBuffer(imagePair, 0, 0, &headerBuffer[16]);
242  dataProt.resetTransfer();
243  dataProt.setTransferHeader(&headerBuffer[16], sizeof(HeaderData), rawDataLength);
244 
245  // Perform 12 bit packed encoding if necessary
246  int bits[2] = {0, 0};
247  int rowSize[2] = {0, 0};
248  int rowStride[2] = {0, 0};
249  const unsigned char* pixelData[2] = {nullptr, nullptr};
250  std::vector<unsigned char> encodingBuffer[2];
251 
252  for(int i = 0; i<2; i++) {
253  bits[i] = getFormatBits(imagePair.getPixelFormat(i), false);
254  rowSize[i] = imagePair.getWidth()*bits[i]/8;
255 
256  if(imagePair.getPixelFormat(i) != ImagePair::FORMAT_12_BIT_MONO) {
257  pixelData[i] = imagePair.getPixelData(i);
258  rowStride[i] = imagePair.getRowStride(i);
259  } else {
260  encodingBuffer[i].resize(rowSize[i] * imagePair.getHeight());
261  BitConversions::encode12BitPacked(0, imagePair.getHeight(), imagePair.getPixelData(i),
262  &encodingBuffer[i][0], imagePair.getRowStride(i), rowSize[i], imagePair.getWidth());
263  pixelData[i] = &encodingBuffer[i][0];
264  rowStride[i] = rowSize[i];
265  }
266  }
267 
268  // Make a interleaved copy
269  rawBuffer.resize(imagePair.getWidth()*imagePair.getHeight()*(bits[0] + bits[1])/8 + sizeof(int));
270  int bufferOffset = 0;
271 
272  for(int y = 0; y<imagePair.getHeight(); y++) {
273  memcpy(&rawBuffer[bufferOffset], &pixelData[0][y*rowStride[0]], rowSize[0]);
274  bufferOffset += rowSize[0];
275 
276  memcpy(&rawBuffer[bufferOffset], &pixelData[1][y*rowStride[1]], rowSize[1]);
277  bufferOffset += rowSize[1];
278  }
279 
280  rawData = &rawBuffer[0];
281  int rawValidBytes = static_cast<int>(rawBuffer.size() - sizeof(int));
282 
283  dataProt.setTransferData(rawData, rawValidBytes);
284 }
285 
286 void ImageProtocol::Pimpl::setRawTransferData(const ImagePair& metaData, unsigned char* rawData,
287  int firstTileWidth, int secondTileWidth, int validBytes) {
288  if(rawData == nullptr) {
289  throw ProtocolException("Image data is null pointer!");
290  }
291 
292  // Determine the size of a frame
293  int rawDataLength = getFrameSize(metaData.getWidth(), metaData.getHeight(),
294  firstTileWidth, secondTileWidth, metaData.getPixelFormat(0),
295  metaData.getPixelFormat(1));
296 
297  // Set header as first piece of data
298  copyHeaderToBuffer(metaData, firstTileWidth, secondTileWidth, &headerBuffer[16]);
299  dataProt.resetTransfer();
300  dataProt.setTransferHeader(&headerBuffer[16], sizeof(HeaderData), rawDataLength);
301 
302  this->rawData = rawData;
303 
304  dataProt.setTransferData(rawData, validBytes);
305 }
306 
307 void ImageProtocol::Pimpl::setRawValidBytes(int validBytes) {
308  dataProt.setTransferValidBytes(validBytes);
309 }
310 
311 const unsigned char* ImageProtocol::Pimpl::getTransferMessage(int& length) {
312  const unsigned char* msg = dataProt.getTransferMessage(length);
313 
314  if(msg == nullptr) {
315  msg = dataProt.getTransferMessage(length);
316  }
317 
318  return msg;
319 }
320 
321 bool ImageProtocol::Pimpl::transferComplete() {
322  return dataProt.transferComplete();
323 }
324 
325 int ImageProtocol::Pimpl::getFrameSize(int width, int height, int firstTileWidth,
326  int secondTileWidth, ImagePair::ImageFormat format0,
327  ImagePair::ImageFormat format1) {
328 
329  int bits0 = getFormatBits(format0, false);
330  int bits1 = getFormatBits(format1, false);
331 
332  int effectiveWidth = firstTileWidth > 0 ? firstTileWidth + secondTileWidth : width;
333 
334  return (effectiveWidth * height * (bits0 + bits1)) /8;
335 }
336 
337 int ImageProtocol::Pimpl::getFormatBits(ImagePair::ImageFormat format, bool afterDecode) {
338  if(afterDecode) {
339  return ImagePair::getBytesPerPixel(format)*8;
340  } else {
341  switch(format) {
342  case ImagePair::FORMAT_8_BIT_MONO: return 8;
343  case ImagePair::FORMAT_12_BIT_MONO: return 12;
344  case ImagePair::FORMAT_8_BIT_RGB: return 24;
345  default: throw ProtocolException("Illegal pixel format!");
346  }
347  }
348 }
349 
350 void ImageProtocol::Pimpl::copyHeaderToBuffer(const ImagePair& imagePair,
351  int firstTileWidth, int secondTileWidth, unsigned char* buffer) {
352  HeaderData* transferHeader = reinterpret_cast<HeaderData*>(buffer);
353  memset(transferHeader, 0, sizeof(*transferHeader));
354  transferHeader->magic = htons(MAGIC_SEQUECE);
355  transferHeader->protocolVersion = InternalInformation::CURRENT_PROTOCOL_VERSION;
356  transferHeader->isRawImagePair = imagePair.isImageDisparityPair() ? 0 : 1;
357  transferHeader->width = htons(imagePair.getWidth());
358  transferHeader->height = htons(imagePair.getHeight());
359  transferHeader->firstTileWidth = htons(firstTileWidth);
360  transferHeader->secondTileWidth = htons(secondTileWidth);
361  transferHeader->format0 = static_cast<unsigned char>(imagePair.getPixelFormat(0));
362  transferHeader->format1 = static_cast<unsigned char>(imagePair.getPixelFormat(1));
363  transferHeader->seqNum = static_cast<unsigned int>(htonl(imagePair.getSequenceNumber()));
364 
365  int minDisp = 0, maxDisp = 0;
366  imagePair.getDisparityRange(minDisp, maxDisp);
367  transferHeader->minDisparity = minDisp;
368  transferHeader->maxDisparity = maxDisp;
369 
370  int timeSec = 0, timeMicrosec = 0;
371  imagePair.getTimestamp(timeSec, timeMicrosec);
372  transferHeader->timeSec = static_cast<int>(htonl(static_cast<unsigned int>(timeSec)));
373  transferHeader->timeMicrosec = static_cast<int>(htonl(static_cast<unsigned int>(timeMicrosec)));
374 
375  if(imagePair.getQMatrix() != nullptr) {
376  memcpy(transferHeader->q, imagePair.getQMatrix(), sizeof(float)*16);
377  }
378 }
379 
380 void ImageProtocol::Pimpl::resetTransfer() {
381  dataProt.resetTransfer();
382 }
383 
384 unsigned char* ImageProtocol::Pimpl::getNextReceiveBuffer(int& maxLength) {
385  maxLength = dataProt.getMaxReceptionSize();
386  return dataProt.getNextReceiveBuffer(maxLength);
387 }
388 
389 void ImageProtocol::Pimpl::processReceivedMessage(int length) {
390  receptionDone = false;
391 
392  // Add the received message
393  dataProt.processReceivedMessage(length, receptionDone);
394 
395  int receivedBytes = 0;
396  dataProt.getReceivedData(receivedBytes);
397 
398  // Immediately try to decode the header
399  if(!receiveHeaderParsed) {
400  int headerLen = 0;
401  unsigned char* headerData = dataProt.getReceivedHeader(headerLen);
402  if(headerData != nullptr) {
403  tryDecodeHeader(headerData, headerLen);
404  }
405  }
406 }
407 
408 void ImageProtocol::Pimpl::tryDecodeHeader(const
409 unsigned char* receivedData, int receivedBytes) {
410  if(receivedBytes >= static_cast<int>(sizeof(HeaderData))) {
411  receiveHeader = *reinterpret_cast<const HeaderData*>(receivedData);
412  if(receiveHeader.magic != htons(MAGIC_SEQUECE)) {
413  // Let's not call this an error. Perhaps it's just not a header
414  // packet
415  return;
416  }
417 
418  if(receiveHeader.protocolVersion > InternalInformation::CURRENT_PROTOCOL_VERSION ||
419  receiveHeader.protocolVersion < 4) {
420  throw ProtocolException("Protocol version mismatch!");
421  }
422 
423  // Convert byte order
424  receiveHeader.width = ntohs(receiveHeader.width);
425  receiveHeader.height = ntohs(receiveHeader.height);
426  receiveHeader.firstTileWidth = ntohs(receiveHeader.firstTileWidth);
427  receiveHeader.secondTileWidth = ntohs(receiveHeader.secondTileWidth);
428  receiveHeader.timeSec = static_cast<int>(
429  htonl(static_cast<unsigned int>(receiveHeader.timeSec)));
430  receiveHeader.timeMicrosec = static_cast<int>(
431  htonl(static_cast<unsigned int>(receiveHeader.timeMicrosec)));
432  receiveHeader.seqNum = htonl(receiveHeader.seqNum);
433 
434  receiveHeaderParsed = true;
435  }
436 }
437 
438 bool ImageProtocol::Pimpl::imagesReceived() const {
439  return receptionDone && receiveHeaderParsed;
440 }
441 
442 bool ImageProtocol::Pimpl::getReceivedImagePair(ImagePair& imagePair) {
443  bool complete = false;
444  int validRows;
445  bool ok = getPartiallyReceivedImagePair(imagePair, validRows, complete);
446 
447  return (ok && complete);
448 }
449 
450 bool ImageProtocol::Pimpl::getPartiallyReceivedImagePair(ImagePair& imagePair, int& validRows, bool& complete) {
451  imagePair.setWidth(0);
452  imagePair.setHeight(0);
453 
454  complete = false;
455 
456  if(!receiveHeaderParsed) {
457  // We haven't even received the image header yet
458  return false;
459  } else {
460  // We received at least some pixel data
461  int receivedBytes = 0;
462  unsigned char* data = dataProt.getReceivedData(receivedBytes);
463  imagePair.setImageDisparityPair(receiveHeader.isRawImagePair == 0);
464 
465  validRows = 0;
466  imagePair.setWidth(receiveHeader.width);
467  imagePair.setHeight(receiveHeader.height);
468  imagePair.setPixelFormat(0, static_cast<ImagePair::ImageFormat>(receiveHeader.format0));
469  imagePair.setPixelFormat(1, static_cast<ImagePair::ImageFormat>(receiveHeader.format1));
470 
471  int rowStride0 = 0, rowStride1 = 0;
472  int validRows0 = 0, validRows1 = 0;
473  unsigned char* pixel0 = decodeInterleaved(0, receivedBytes, data, validRows0, rowStride0);
474  unsigned char* pixel1 = decodeInterleaved(1, receivedBytes, data, validRows1, rowStride1);
475 
476  imagePair.setRowStride(0, rowStride0);
477  imagePair.setRowStride(1, rowStride1);
478  imagePair.setPixelData(0, pixel0);
479  imagePair.setPixelData(1, pixel1);
480  imagePair.setQMatrix(receiveHeader.q);
481 
482  imagePair.setSequenceNumber(receiveHeader.seqNum);
483  imagePair.setTimestamp(receiveHeader.timeSec, receiveHeader.timeMicrosec);
484  imagePair.setDisparityRange(receiveHeader.minDisparity, receiveHeader.maxDisparity);
485 
486  validRows = min(validRows0, validRows1);
487 
488  if(validRows == receiveHeader.height || receptionDone) {
489  complete = true;
490  resetReception();
491  }
492 
493  return true;
494  }
495 }
496 
497 unsigned char* ImageProtocol::Pimpl::decodeInterleaved(int imageNumber, int receivedBytes,
498  unsigned char* data, int& validRows, int& rowStride) {
499  ImagePair::ImageFormat format = static_cast<ImagePair::ImageFormat>(
500  imageNumber == 0 ? receiveHeader.format0 : receiveHeader.format1);
501  int bits0 = getFormatBits(static_cast<ImagePair::ImageFormat>(receiveHeader.format0), false);
502  int bits1 = getFormatBits(static_cast<ImagePair::ImageFormat>(receiveHeader.format1), false);
503 
504  unsigned char* ret = nullptr;
505 
506  if(receiveHeader.secondTileWidth == 0) {
507  int bufferOffset = imageNumber*receiveHeader.width * bits0/8;
508  int bufferRowStride = receiveHeader.width*(bits0 + bits1) / 8;
509 
510  if(format == ImagePair::FORMAT_8_BIT_MONO || format == ImagePair::FORMAT_8_BIT_RGB) {
511  // No decoding is necessary. We can just pass through the
512  // data pointer
513  ret = &data[bufferOffset];
514  rowStride = bufferRowStride;
515  validRows = receivedBytes / bufferRowStride;
516  } else {
517  // Perform 12-bit => 16 bit decoding
518  allocateDecodeBuffer(imageNumber);
519  validRows = receivedBytes / bufferRowStride;
520  rowStride = 2*receiveHeader.width;
521  int lastRow = lastReceivedPayloadBytes[imageNumber] / bufferRowStride;
522 
523  BitConversions::decode12BitPacked(lastRow, validRows, &data[bufferOffset],
524  &decodeBuffer[imageNumber][0], bufferRowStride, rowStride, receiveHeader.width);
525 
526  ret = &decodeBuffer[imageNumber][0];
527  }
528  } else {
529  // Decode the tiled transfer
530  decodeTiledImage(imageNumber,
531  lastReceivedPayloadBytes[imageNumber], receivedBytes,
532  data, receiveHeader.firstTileWidth * (bits0 + bits1) / 8,
533  receiveHeader.secondTileWidth * (bits0 + bits1) / 8,
534  validRows, format);
535  ret = &decodeBuffer[imageNumber][0];
536  rowStride = receiveHeader.width*getFormatBits(
537  static_cast<ImagePair::ImageFormat>(format), true)/8;
538  }
539 
540  lastReceivedPayloadBytes[imageNumber] = receivedBytes;
541  return ret;
542 }
543 
544 void ImageProtocol::Pimpl::allocateDecodeBuffer(int imageNumber) {
545  ImagePair::ImageFormat format = static_cast<ImagePair::ImageFormat>(
546  imageNumber == 0 ? receiveHeader.format0 : receiveHeader.format1);
547  int bytesPerPixel = getFormatBits(format, true);
548  int bufferSize = receiveHeader.width * receiveHeader.height * bytesPerPixel;
549 
550  if(decodeBuffer[imageNumber].size() != static_cast<unsigned int>(bufferSize)) {
551  decodeBuffer[imageNumber].resize(bufferSize);
552  }
553 }
554 
555 void ImageProtocol::Pimpl::decodeTiledImage(int imageNumber, int lastReceivedPayloadBytes, int receivedPayloadBytes,
556  const unsigned char* data, int firstTileStride, int secondTileStride, int& validRows,
557  ImagePair::ImageFormat format) {
558 
559  // Allocate a decoding buffer
560  allocateDecodeBuffer(imageNumber);
561 
562  // Get beginning and end of first tile
563  int startFirstTile = lastReceivedPayloadBytes / firstTileStride;
564  int stopFirstTile = std::min(receivedPayloadBytes / firstTileStride,
565  static_cast<int>(receiveHeader.height));
566 
567  // Get beginning and end of second tile
568  int secondTileBytes = receivedPayloadBytes - (receiveHeader.height*firstTileStride);
569  int lastSecondTileBytes = lastReceivedPayloadBytes - (receiveHeader.height*firstTileStride);
570  int startSecondTile = std::max(0, lastSecondTileBytes / secondTileStride);
571  int stopSecondTile = std::max(0, secondTileBytes / secondTileStride);
572  int firstTileOffset = imageNumber * getFormatBits(
573  static_cast<ImagePair::ImageFormat>(receiveHeader.format0), false) * receiveHeader.firstTileWidth / 8;
574 
575  // Decode first tile
576  if(format == ImagePair::FORMAT_12_BIT_MONO) {
577  BitConversions::decode12BitPacked(startFirstTile, stopFirstTile, &data[firstTileOffset], &decodeBuffer[imageNumber][0],
578  firstTileStride, 2*receiveHeader.width, receiveHeader.firstTileWidth);
579  } else {
580  decodeRowsFromTile(startFirstTile, stopFirstTile, &data[firstTileOffset],
581  &decodeBuffer[imageNumber][0], firstTileStride, receiveHeader.width,
582  receiveHeader.firstTileWidth);
583  }
584 
585  // Decode second tile
586  int secondTileOffset = receiveHeader.height*firstTileStride +
587  imageNumber * getFormatBits(static_cast<ImagePair::ImageFormat>(receiveHeader.format0), false) * receiveHeader.secondTileWidth / 8;
588 
589  if(format == ImagePair::FORMAT_12_BIT_MONO) {
590  BitConversions::decode12BitPacked(startSecondTile, stopSecondTile,
591  &data[secondTileOffset], &decodeBuffer[imageNumber][2*receiveHeader.firstTileWidth],
592  secondTileStride, 2*receiveHeader.width, receiveHeader.secondTileWidth);
593  } else {
594  decodeRowsFromTile(startSecondTile, stopSecondTile, &data[secondTileOffset],
595  &decodeBuffer[imageNumber][receiveHeader.firstTileWidth],
596  secondTileStride, receiveHeader.width, receiveHeader.secondTileWidth);
597  }
598 
599  validRows = stopSecondTile;
600 }
601 
602 void ImageProtocol::Pimpl::decodeRowsFromTile(int startRow, int stopRow, unsigned const char* src,
603  unsigned char* dst, int srcStride, int dstStride, int tileWidth) {
604  for(int y = startRow; y < stopRow; y++) {
605  memcpy(&dst[y*dstStride], &src[y*srcStride], tileWidth);
606  }
607 }
608 
609 void ImageProtocol::Pimpl::resetReception() {
610  receiveHeaderParsed = false;
611  lastReceivedPayloadBytes[0] = 0;
612  lastReceivedPayloadBytes[1] = 0;
613  dataProt.resetReception(false);
614  receptionDone = false;
615 }
616 
617 bool ImageProtocol::Pimpl::isConnected() const {
618  return dataProt.isConnected();
619 }
620 
621 const unsigned char* ImageProtocol::Pimpl::getNextControlMessage(int& length) {
622  return dataProt.getNextControlMessage(length);
623 }
624 
625 bool ImageProtocol::Pimpl::newClientConnected() {
626  return dataProt.newClientConnected();
627 }
628 
629 int ImageProtocol::Pimpl::getNumDroppedFrames() const {
630  return dataProt.getDroppedReceptions();
631 }
bool isImageDisparityPair() const
Returns true if this is a left camera image and disparity map pair.
Definition: imagepair.h:262
void setTimestamp(int seconds, int microsec)
Sets the time at which this image pair has been captured.
Definition: imagepair.h:145
void setHeight(int h)
Sets a new width for both images.
Definition: imagepair.h:77
Exception class that is used for all protocol exceptions.
Definition: exceptions.h:23
8-bit greyscale format
Definition: imagepair.h:38
unsigned char * getNextReceiveBuffer(int &maxLength)
Returns the buffer for receiving the next network message.
void setSequenceNumber(unsigned int num)
Sets the sequence number for this image pair.
Definition: imagepair.h:134
void setPixelFormat(int imageNumber, ImageFormat format)
Sets the pixel format for the given image.
Definition: imagepair.h:98
bool getReceivedImagePair(ImagePair &imagePair)
Returns a received image when complete.
void resetTransfer()
Aborts the transmission of the current transfer and performs a reset of the internal state...
int getNumDroppedFrames() const
Returns the number of frames that have been dropped since connecting to the current remote host...
unsigned char * getPixelData(int imageNumber) const
Returns the pixel data for the given image.
Definition: imagepair.h:208
bool transferComplete()
Returns true if the current transfer has been completed.
ImageProtocol(bool server, ProtocolType protType, int maxUdpPacketSize=1472)
Creates a new instance for decoding / encoding network messages for the given network protocol...
A protocol for transmitting large blocks of data over a network.
bool newClientConnected()
Returns true if the last message has established a new connection from a client.
const float * getQMatrix() const
Returns a pointer to the disparity-to-depth mapping matrix q.
Definition: imagepair.h:216
int getWidth() const
Returns the width of each image.
Definition: imagepair.h:173
bool isConnected() const
Returns true if a remote connection is established.
void setDisparityRange(int minimum, int maximum)
Sets the value range for the disparity map contained in this image pair.
Definition: imagepair.h:157
void setWidth(int w)
Sets a new width for both images.
Definition: imagepair.h:72
int getBytesPerPixel(int imageNumber) const
Returns the number of bytes that are required to store one image pixel.
Definition: imagepair.h:275
void setQMatrix(const float *q)
Sets the pointer to the disparity-to-depth mapping matrix q.
Definition: imagepair.h:127
void setRowStride(int imageNumber, int stride)
Sets a new row stride for the pixel data of one image.
Definition: imagepair.h:86
8-bit RGB format
Definition: imagepair.h:41
void setTransferImagePair(const ImagePair &imagePair)
Sets a new image that will be transfer.
void setRawValidBytes(int validBytes)
Updates the number of valid bytes in a partial raw transfer.
void getTimestamp(int &seconds, int &microsec) const
Returns the time at which this image pair has been captured.
Definition: imagepair.h:232
void setPixelData(int imageNumber, unsigned char *pixelData)
Sets the pixel data for the given image.
Definition: imagepair.h:116
void getDisparityRange(int &minimum, int &maximum) const
Gets the value range for the disparity map contained in this image pair. If the image pair does not c...
Definition: imagepair.h:245
ProtocolType
Supported network protocols.
Definition: imageprotocol.h:39
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...
void processReceivedMessage(int length)
Handles a received network message.
void resetReception()
Aborts the reception of the current image transfer and resets the internal state. ...
A set of two images, which are usually the left camera image and the disparity map.
Definition: imagepair.h:31
ImageFormat getPixelFormat(int imageNumber) const
Returns the pixel format for the given image.
Definition: imagepair.h:197
const unsigned char * getTransferMessage(int &length)
Gets the next network message for the current transfer.
void setRawTransferData(const ImagePair &metaData, unsigned char *rawData, int firstTileWidth=0, int secondTileWidth=0, int validBytes=0x7FFFFFFF)
Sets the already pre-formatted image data for the next transfer.
int getHeight() const
Returns the height of each image.
Definition: imagepair.h:178
unsigned int getSequenceNumber() const
Returns the sequence number for this image pair.
Definition: imagepair.h:223
int getRowStride(int imageNumber) const
Returns the row stride for the pixel data of one image.
Definition: imagepair.h:186
void setImageDisparityPair(bool dispPair)
Sets whether this is a left camera image and disparity map pair, or two raw camera images...
Definition: imagepair.h:166
ImageFormat
Image formats that can be transferred.
Definition: imagepair.h:36
bool imagesReceived() const
Returns true if the images of the current transfer have been received.
bool getPartiallyReceivedImagePair(ImagePair &imagePair, int &validRows, bool &complete)
Returns a partially received image.
Nerian Vision Technologies