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