libvisiontransfer  7.1.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 middleTilesWidth = 0, int lastTileWidth = 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 lastTileWidth;
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  unsigned short middleTilesWidth;
103  };
104 #pragma pack(pop)
105 
106  // Underlying protocol for data transfers
107  DataBlockProtocol dataProt;
108  ProtocolType protType;
109 
110  // Transfer related variables
111  std::vector<unsigned char> headerBuffer;
112  std::vector<unsigned char> rawBuffer;
113  unsigned char* rawData;
114 
115  // Reception related variables
116  std::vector<unsigned char, AlignedAllocator<unsigned char> >decodeBuffer[2];
117  bool receiveHeaderParsed;
118  HeaderData receiveHeader;
119  int lastReceivedPayloadBytes[2];
120  bool receptionDone;
121 
122  // Copies the transmission header to the given buffer
123  void copyHeaderToBuffer(const ImagePair& imagePair, int firstTileWidth,
124  int middleTilesWidth, int lastTileWidth, unsigned char* buffer);
125 
126  // Decodes header information from the received data
127  void tryDecodeHeader(const unsigned char* receivedData, int receivedBytes);
128 
129  // Decodes a received image from an interleaved buffer
130  unsigned char* decodeInterleaved(int imageNumber, int receivedBytes,
131  unsigned char* data, int& validRows, int& rowStride);
132 
133  int getNumTiles(int width, int firstTileWidth, int middleTilesWidth, int lastTileWidth);
134 
135  int getFrameSize(int width, int height, int firstTileWidth, int middleTilesWidth,
136  int lastTileWidth, ImagePair::ImageFormat format0, ImagePair::ImageFormat format1);
137 
138  int getFormatBits(ImagePair::ImageFormat format, bool afterDecode);
139 
140  void decodeTiledImage(int imageNumber, int lastReceivedPayloadBytes, int receivedPayloadBytes,
141  const unsigned char* data, int firstTileStride, int middleTilesStride, int lastTileStride,
142  int& validRows, ImagePair::ImageFormat format);
143 
144  void decodeRowsFromTile(int startRow, int stopRow, unsigned const char* src,
145  unsigned char* dst, int srcStride, int dstStride, int tileWidth);
146 
147  void allocateDecodeBuffer(int imageNumber);
148 };
149 
150 
151 /******************** Stubs for all public members ********************/
152 
153 ImageProtocol::ImageProtocol(bool server, ProtocolType protType, int maxUdpPacketSize)
154  : pimpl(new Pimpl(server, protType, maxUdpPacketSize)) {
155  // All initializations are done by the Pimpl class
156 }
157 
158 ImageProtocol::~ImageProtocol() {
159  delete pimpl;
160 }
161 
163  pimpl->setTransferImagePair(imagePair);
164 }
165 
167  unsigned char* imageData, int firstTileWidth, int middleTilesWidth, int lastTileWidth, int validBytes) {
168  pimpl->setRawTransferData(metaData, imageData, firstTileWidth, middleTilesWidth, lastTileWidth, validBytes);
169 }
170 
171 void ImageProtocol::setRawValidBytes(int validBytes) {
172  pimpl->setRawValidBytes(validBytes);
173 }
174 
175 const unsigned char* ImageProtocol::getTransferMessage(int& length) {
176  return pimpl->getTransferMessage(length);
177 }
178 
180  return pimpl->transferComplete();
181 }
182 
184  pimpl->resetTransfer();
185 }
186 
188  return pimpl->getReceivedImagePair(imagePair);
189 }
190 
192  ImagePair& imagePair, int& validRows, bool& complete) {
193  return pimpl->getPartiallyReceivedImagePair(imagePair, validRows, complete);
194 }
195 
197  return pimpl->imagesReceived();
198 }
199 
200 unsigned char* ImageProtocol::getNextReceiveBuffer(int& maxLength) {
201  return pimpl->getNextReceiveBuffer(maxLength);
202 }
203 
205  pimpl->processReceivedMessage(length);
206 }
207 
209  return pimpl->getNumDroppedFrames();
210 }
211 
213  pimpl->resetReception();
214 }
215 
217  return pimpl->isConnected();
218 }
219 
220 const unsigned char* ImageProtocol::getNextControlMessage(int& length) {
221  return pimpl->getNextControlMessage(length);
222 }
223 
225  return pimpl->newClientConnected();
226 }
227 
228 /******************** Implementation in pimpl class *******************/
229 
230 ImageProtocol::Pimpl::Pimpl(bool server, ProtocolType protType, int maxUdpPacketSize)
231  :dataProt(server, (DataBlockProtocol::ProtocolType)protType,
232  maxUdpPacketSize), protType(protType), rawData(nullptr),
233  receiveHeaderParsed(false), lastReceivedPayloadBytes{0, 0},
234  receptionDone(false) {
235  headerBuffer.resize(sizeof(HeaderData) + 32);
236  memset(&headerBuffer[0], 0, sizeof(headerBuffer.size()));
237  memset(&receiveHeader, 0, sizeof(receiveHeader));
238 }
239 
240 void ImageProtocol::Pimpl::setTransferImagePair(const ImagePair& imagePair) {
241  if(imagePair.getPixelData(0) == nullptr || imagePair.getPixelData(1) == nullptr) {
242  throw ProtocolException("Image data is null pointer!");
243  }
244 
245  // Determine the size of a frame
246  int rawDataLength = getFrameSize(imagePair.getWidth(), imagePair.getHeight(), 0, 0, 0,
247  imagePair.getPixelFormat(0), imagePair.getPixelFormat(1));
248 
249  // Set header as first piece of data
250  copyHeaderToBuffer(imagePair, 0, 0, 0, &headerBuffer[16]);
251  dataProt.resetTransfer();
252  dataProt.setTransferHeader(&headerBuffer[16], sizeof(HeaderData), rawDataLength);
253 
254  // Perform 12 bit packed encoding if necessary
255  int bits[2] = {0, 0};
256  int rowSize[2] = {0, 0};
257  int rowStride[2] = {0, 0};
258  const unsigned char* pixelData[2] = {nullptr, nullptr};
259  std::vector<unsigned char> encodingBuffer[2];
260 
261  for(int i = 0; i<2; i++) {
262  bits[i] = getFormatBits(imagePair.getPixelFormat(i), false);
263  rowSize[i] = imagePair.getWidth()*bits[i]/8;
264 
265  if(imagePair.getPixelFormat(i) != ImagePair::FORMAT_12_BIT_MONO) {
266  pixelData[i] = imagePair.getPixelData(i);
267  rowStride[i] = imagePair.getRowStride(i);
268  } else {
269  encodingBuffer[i].resize(rowSize[i] * imagePair.getHeight());
270  BitConversions::encode12BitPacked(0, imagePair.getHeight(), imagePair.getPixelData(i),
271  &encodingBuffer[i][0], imagePair.getRowStride(i), rowSize[i], imagePair.getWidth());
272  pixelData[i] = &encodingBuffer[i][0];
273  rowStride[i] = rowSize[i];
274  }
275  }
276 
277  // Make a interleaved copy
278  rawBuffer.resize(imagePair.getWidth()*imagePair.getHeight()*(bits[0] + bits[1])/8 + sizeof(int));
279  int bufferOffset = 0;
280 
281  for(int y = 0; y<imagePair.getHeight(); y++) {
282  memcpy(&rawBuffer[bufferOffset], &pixelData[0][y*rowStride[0]], rowSize[0]);
283  bufferOffset += rowSize[0];
284 
285  memcpy(&rawBuffer[bufferOffset], &pixelData[1][y*rowStride[1]], rowSize[1]);
286  bufferOffset += rowSize[1];
287  }
288 
289  rawData = &rawBuffer[0];
290  int rawValidBytes = static_cast<int>(rawBuffer.size() - sizeof(int));
291 
292  dataProt.setTransferData(rawData, rawValidBytes);
293 }
294 
295 void ImageProtocol::Pimpl::setRawTransferData(const ImagePair& metaData, unsigned char* rawData,
296  int firstTileWidth, int middleTilesWidth, int lastTileWidth, int validBytes) {
297  if(rawData == nullptr) {
298  throw ProtocolException("Image data is null pointer!");
299  }
300 
301  // Determine the size of a frame
302  int rawDataLength = getFrameSize(metaData.getWidth(), metaData.getHeight(),
303  firstTileWidth, middleTilesWidth, lastTileWidth, metaData.getPixelFormat(0),
304  metaData.getPixelFormat(1));
305 
306  // Set header as first piece of data
307  copyHeaderToBuffer(metaData, firstTileWidth, middleTilesWidth, lastTileWidth, &headerBuffer[16]);
308  dataProt.resetTransfer();
309  dataProt.setTransferHeader(&headerBuffer[16], sizeof(HeaderData), rawDataLength);
310 
311  this->rawData = rawData;
312 
313  dataProt.setTransferData(rawData, validBytes);
314 }
315 
316 void ImageProtocol::Pimpl::setRawValidBytes(int validBytes) {
317  dataProt.setTransferValidBytes(validBytes);
318 }
319 
320 const unsigned char* ImageProtocol::Pimpl::getTransferMessage(int& length) {
321  const unsigned char* msg = dataProt.getTransferMessage(length);
322 
323  if(msg == nullptr) {
324  msg = dataProt.getTransferMessage(length);
325  }
326 
327  return msg;
328 }
329 
330 bool ImageProtocol::Pimpl::transferComplete() {
331  return dataProt.transferComplete();
332 }
333 
334 int ImageProtocol::Pimpl::getNumTiles(int width, int firstTileWidth, int middleTilesWidth, int lastTileWidth) {
335  if(lastTileWidth == 0) {
336  return 1;
337  } else if(middleTilesWidth == 0) {
338  return 2;
339  } else {
340  int tileWidth = firstTileWidth + lastTileWidth - middleTilesWidth;
341  return (width - 2*tileWidth + firstTileWidth + lastTileWidth) / (firstTileWidth + lastTileWidth - tileWidth);
342  }
343 }
344 
345 int ImageProtocol::Pimpl::getFrameSize(int width, int height, int firstTileWidth,
346  int middleTilesWidth, int lastTileWidth, ImagePair::ImageFormat format0,
347  ImagePair::ImageFormat format1) {
348 
349  int bits0 = getFormatBits(format0, false);
350  int bits1 = getFormatBits(format1, false);
351  return (width * height * (bits0 + bits1)) /8;
352 }
353 
354 int ImageProtocol::Pimpl::getFormatBits(ImagePair::ImageFormat format, bool afterDecode) {
355  if(afterDecode) {
356  return ImagePair::getBytesPerPixel(format)*8;
357  } else {
358  switch(format) {
359  case ImagePair::FORMAT_8_BIT_MONO: return 8;
360  case ImagePair::FORMAT_12_BIT_MONO: return 12;
361  case ImagePair::FORMAT_8_BIT_RGB: return 24;
362  default: throw ProtocolException("Illegal pixel format!");
363  }
364  }
365 }
366 
367 void ImageProtocol::Pimpl::copyHeaderToBuffer(const ImagePair& imagePair,
368  int firstTileWidth, int middleTilesWidth, int lastTileWidth, unsigned char* buffer) {
369  HeaderData* transferHeader = reinterpret_cast<HeaderData*>(buffer);
370  memset(transferHeader, 0, sizeof(*transferHeader));
371  transferHeader->magic = htons(MAGIC_SEQUECE);
372  transferHeader->protocolVersion = InternalInformation::CURRENT_PROTOCOL_VERSION;
373  transferHeader->isRawImagePair = imagePair.isImageDisparityPair() ? 0 : 1;
374  transferHeader->width = htons(imagePair.getWidth());
375  transferHeader->height = htons(imagePair.getHeight());
376  transferHeader->firstTileWidth = htons(firstTileWidth);
377  transferHeader->lastTileWidth = htons(lastTileWidth);
378  transferHeader->middleTilesWidth = htons(middleTilesWidth);
379  transferHeader->format0 = static_cast<unsigned char>(imagePair.getPixelFormat(0));
380  transferHeader->format1 = static_cast<unsigned char>(imagePair.getPixelFormat(1));
381  transferHeader->seqNum = static_cast<unsigned int>(htonl(imagePair.getSequenceNumber()));
382 
383  int minDisp = 0, maxDisp = 0;
384  imagePair.getDisparityRange(minDisp, maxDisp);
385  transferHeader->minDisparity = minDisp;
386  transferHeader->maxDisparity = maxDisp;
387 
388  transferHeader->subpixelFactor = imagePair.getSubpixelFactor();
389 
390  int timeSec = 0, timeMicrosec = 0;
391  imagePair.getTimestamp(timeSec, timeMicrosec);
392  transferHeader->timeSec = static_cast<int>(htonl(static_cast<unsigned int>(timeSec)));
393  transferHeader->timeMicrosec = static_cast<int>(htonl(static_cast<unsigned int>(timeMicrosec)));
394 
395  if(imagePair.getQMatrix() != nullptr) {
396  memcpy(transferHeader->q, imagePair.getQMatrix(), sizeof(float)*16);
397  }
398 }
399 
400 void ImageProtocol::Pimpl::resetTransfer() {
401  dataProt.resetTransfer();
402 }
403 
404 unsigned char* ImageProtocol::Pimpl::getNextReceiveBuffer(int& maxLength) {
405  maxLength = dataProt.getMaxReceptionSize();
406  return dataProt.getNextReceiveBuffer(maxLength);
407 }
408 
409 void ImageProtocol::Pimpl::processReceivedMessage(int length) {
410  receptionDone = false;
411 
412  // Add the received message
413  dataProt.processReceivedMessage(length, receptionDone);
414 
415  int receivedBytes = 0;
416  dataProt.getReceivedData(receivedBytes);
417 
418  // Immediately try to decode the header
419  if(!receiveHeaderParsed) {
420  int headerLen = 0;
421  unsigned char* headerData = dataProt.getReceivedHeader(headerLen);
422  if(headerData != nullptr) {
423  tryDecodeHeader(headerData, headerLen);
424  }
425  }
426 }
427 
428 void ImageProtocol::Pimpl::tryDecodeHeader(const
429 unsigned char* receivedData, int receivedBytes) {
430  // Extra data fields that have been added to the header. Must be
431  // removed when the protocol version number is updated
432  constexpr int optionalDataSize = sizeof(receiveHeader.middleTilesWidth);
433  constexpr int mandatoryDataSize = static_cast<int>(sizeof(HeaderData)) - optionalDataSize;
434 
435  if(receivedBytes >= mandatoryDataSize) {
436  receiveHeader = *reinterpret_cast<const HeaderData*>(receivedData);
437  if(receiveHeader.magic != htons(MAGIC_SEQUECE)) {
438  // Let's not call this an error. Perhaps it's just not a header
439  // packet
440  return;
441  }
442 
443  if(receiveHeader.protocolVersion != InternalInformation::CURRENT_PROTOCOL_VERSION) {
444  throw ProtocolException("Protocol version mismatch!");
445  }
446 
447  // Convert byte order
448  receiveHeader.width = ntohs(receiveHeader.width);
449  receiveHeader.height = ntohs(receiveHeader.height);
450  receiveHeader.firstTileWidth = ntohs(receiveHeader.firstTileWidth);
451  receiveHeader.lastTileWidth = ntohs(receiveHeader.lastTileWidth);
452 
453  receiveHeader.timeSec = static_cast<int>(
454  htonl(static_cast<unsigned int>(receiveHeader.timeSec)));
455  receiveHeader.timeMicrosec = static_cast<int>(
456  htonl(static_cast<unsigned int>(receiveHeader.timeMicrosec)));
457  receiveHeader.seqNum = htonl(receiveHeader.seqNum);
458 
459  // Optional data items
460  if(receivedBytes >= mandatoryDataSize + optionalDataSize) {
461  receiveHeader.middleTilesWidth = htons(receiveHeader.middleTilesWidth);
462  } else {
463  receiveHeader.middleTilesWidth = 0;
464  }
465 
466  receiveHeaderParsed = true;
467  }
468 }
469 
470 bool ImageProtocol::Pimpl::imagesReceived() const {
471  return receptionDone && receiveHeaderParsed;
472 }
473 
474 bool ImageProtocol::Pimpl::getReceivedImagePair(ImagePair& imagePair) {
475  bool complete = false;
476  int validRows;
477  bool ok = getPartiallyReceivedImagePair(imagePair, validRows, complete);
478 
479  return (ok && complete);
480 }
481 
482 bool ImageProtocol::Pimpl::getPartiallyReceivedImagePair(ImagePair& imagePair, int& validRows, bool& complete) {
483  imagePair.setWidth(0);
484  imagePair.setHeight(0);
485 
486  complete = false;
487 
488  if(!receiveHeaderParsed) {
489  // We haven't even received the image header yet
490  return false;
491  } else {
492  // We received at least some pixel data
493  int receivedBytes = 0;
494  unsigned char* data = dataProt.getReceivedData(receivedBytes);
495  imagePair.setImageDisparityPair(receiveHeader.isRawImagePair == 0);
496 
497  validRows = 0;
498  imagePair.setWidth(receiveHeader.width);
499  imagePair.setHeight(receiveHeader.height);
500  imagePair.setPixelFormat(0, static_cast<ImagePair::ImageFormat>(receiveHeader.format0));
501  imagePair.setPixelFormat(1, static_cast<ImagePair::ImageFormat>(receiveHeader.format1));
502 
503  int rowStride0 = 0, rowStride1 = 0;
504  int validRows0 = 0, validRows1 = 0;
505  unsigned char* pixel0 = decodeInterleaved(0, receivedBytes, data, validRows0, rowStride0);
506  unsigned char* pixel1 = decodeInterleaved(1, receivedBytes, data, validRows1, rowStride1);
507 
508  imagePair.setRowStride(0, rowStride0);
509  imagePair.setRowStride(1, rowStride1);
510  imagePair.setPixelData(0, pixel0);
511  imagePair.setPixelData(1, pixel1);
512  imagePair.setQMatrix(receiveHeader.q);
513 
514  imagePair.setSequenceNumber(receiveHeader.seqNum);
515  imagePair.setTimestamp(receiveHeader.timeSec, receiveHeader.timeMicrosec);
516  imagePair.setDisparityRange(receiveHeader.minDisparity, receiveHeader.maxDisparity);
517  imagePair.setSubpixelFactor(receiveHeader.subpixelFactor);
518 
519  validRows = min(validRows0, validRows1);
520 
521  if(validRows == receiveHeader.height || receptionDone) {
522  complete = true;
523  resetReception();
524  }
525 
526  return true;
527  }
528 }
529 
530 unsigned char* ImageProtocol::Pimpl::decodeInterleaved(int imageNumber, int receivedBytes,
531  unsigned char* data, int& validRows, int& rowStride) {
532  ImagePair::ImageFormat format = static_cast<ImagePair::ImageFormat>(
533  imageNumber == 0 ? receiveHeader.format0 : receiveHeader.format1);
534  int bits0 = getFormatBits(static_cast<ImagePair::ImageFormat>(receiveHeader.format0), false);
535  int bits1 = getFormatBits(static_cast<ImagePair::ImageFormat>(receiveHeader.format1), false);
536 
537  unsigned char* ret = nullptr;
538 
539  if(receiveHeader.lastTileWidth == 0) {
540  int bufferOffset = imageNumber*receiveHeader.width * bits0/8;
541  int bufferRowStride = receiveHeader.width*(bits0 + bits1) / 8;
542 
543  if(format == ImagePair::FORMAT_8_BIT_MONO || format == ImagePair::FORMAT_8_BIT_RGB) {
544  // No decoding is necessary. We can just pass through the
545  // data pointer
546  ret = &data[bufferOffset];
547  rowStride = bufferRowStride;
548  validRows = receivedBytes / bufferRowStride;
549  } else {
550  // Perform 12-bit => 16 bit decoding
551  allocateDecodeBuffer(imageNumber);
552  validRows = receivedBytes / bufferRowStride;
553  rowStride = 2*receiveHeader.width;
554  int lastRow = lastReceivedPayloadBytes[imageNumber] / bufferRowStride;
555 
556  BitConversions::decode12BitPacked(lastRow, validRows, &data[bufferOffset],
557  &decodeBuffer[imageNumber][0], bufferRowStride, rowStride, receiveHeader.width);
558 
559  ret = &decodeBuffer[imageNumber][0];
560  }
561  } else {
562  // Decode the tiled transfer
563  decodeTiledImage(imageNumber,
564  lastReceivedPayloadBytes[imageNumber], receivedBytes, data,
565  receiveHeader.firstTileWidth * (bits0 + bits1) / 8,
566  receiveHeader.middleTilesWidth * (bits0 + bits1) / 8,
567  receiveHeader.lastTileWidth * (bits0 + bits1) / 8,
568  validRows, format);
569  ret = &decodeBuffer[imageNumber][0];
570  rowStride = receiveHeader.width*getFormatBits(
571  static_cast<ImagePair::ImageFormat>(format), true)/8;
572  }
573 
574  lastReceivedPayloadBytes[imageNumber] = receivedBytes;
575  return ret;
576 }
577 
578 void ImageProtocol::Pimpl::allocateDecodeBuffer(int imageNumber) {
579  ImagePair::ImageFormat format = static_cast<ImagePair::ImageFormat>(
580  imageNumber == 0 ? receiveHeader.format0 : receiveHeader.format1);
581  int bytesPerPixel = getFormatBits(format, true);
582  int bufferSize = receiveHeader.width * receiveHeader.height * bytesPerPixel;
583 
584  if(decodeBuffer[imageNumber].size() != static_cast<unsigned int>(bufferSize)) {
585  decodeBuffer[imageNumber].resize(bufferSize);
586  }
587 }
588 
589 void ImageProtocol::Pimpl::decodeTiledImage(int imageNumber, int lastReceivedPayloadBytes, int receivedPayloadBytes,
590  const unsigned char* data, int firstTileStride, int middleTilesStride, int lastTileStride, int& validRows,
591  ImagePair::ImageFormat format) {
592  // Allocate a decoding buffer
593  allocateDecodeBuffer(imageNumber);
594 
595  // Get beginning and end of first tile
596  int numTiles = getNumTiles(receiveHeader.width, receiveHeader.firstTileWidth,
597  receiveHeader.middleTilesWidth, receiveHeader.lastTileWidth);
598  int payloadOffset = 0;
599  int decodeXOffset = 0;
600  int prevTileStrides = 0;
601  for(int i = 0; i < numTiles; i++) {
602  // Get relevant parameters
603  int tileWidth = 0;
604  int tileStride = 0;
605 
606  if(i == 0) {
607  tileStride = firstTileStride;
608  tileWidth = receiveHeader.firstTileWidth;
609  } else if(i == numTiles-1) {
610  tileStride = lastTileStride;
611  tileWidth = receiveHeader.lastTileWidth;
612  } else {
613  tileStride = middleTilesStride;
614  tileWidth = receiveHeader.middleTilesWidth;
615  }
616 
617  int tileStart = std::max(0, (lastReceivedPayloadBytes - payloadOffset) / tileStride);
618  int tileStop = std::min(std::max(0, (receivedPayloadBytes - payloadOffset) / tileStride), (int)receiveHeader.height);
619  int tileOffset = imageNumber * getFormatBits(static_cast<ImagePair::ImageFormat>(receiveHeader.format0), false) * tileWidth / 8;
620  if(i > 0) {
621  tileOffset += receiveHeader.height * prevTileStrides;
622  }
623 
624  // Decode
625  int bytesPixel;
626  if(format == ImagePair::FORMAT_12_BIT_MONO) {
627  bytesPixel = 2;
628  BitConversions::decode12BitPacked(tileStart, tileStop, &data[tileOffset],
629  &decodeBuffer[imageNumber][decodeXOffset], tileStride, 2*receiveHeader.width, tileWidth);
630  } else {
631  bytesPixel = (format == ImagePair::FORMAT_8_BIT_RGB ? 3 : 1);
632  decodeRowsFromTile(tileStart, tileStop, &data[tileOffset],
633  &decodeBuffer[imageNumber][decodeXOffset], tileStride,
634  receiveHeader.width*bytesPixel, tileWidth*bytesPixel);
635  }
636 
637  payloadOffset += receiveHeader.height * tileStride;
638  decodeXOffset += tileWidth * bytesPixel;
639  prevTileStrides += tileStride;
640  if(i == numTiles-1) {
641  validRows = tileStop;
642  }
643  }
644 }
645 
646 void ImageProtocol::Pimpl::decodeRowsFromTile(int startRow, int stopRow, unsigned const char* src,
647  unsigned char* dst, int srcStride, int dstStride, int tileWidth) {
648  for(int y = startRow; y < stopRow; y++) {
649  memcpy(&dst[y*dstStride], &src[y*srcStride], tileWidth);
650  }
651 }
652 
653 void ImageProtocol::Pimpl::resetReception() {
654  receiveHeaderParsed = false;
655  lastReceivedPayloadBytes[0] = 0;
656  lastReceivedPayloadBytes[1] = 0;
657  dataProt.resetReception(false);
658  receptionDone = false;
659 }
660 
661 bool ImageProtocol::Pimpl::isConnected() const {
662  return dataProt.isConnected();
663 }
664 
665 const unsigned char* ImageProtocol::Pimpl::getNextControlMessage(int& length) {
666  return dataProt.getNextControlMessage(length);
667 }
668 
669 bool ImageProtocol::Pimpl::newClientConnected() {
670  return dataProt.newClientConnected();
671 }
672 
673 int ImageProtocol::Pimpl::getNumDroppedFrames() const {
674  return dataProt.getDroppedReceptions();
675 }
676 
677 } // namespace
678 
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 setRawTransferData(const ImagePair &metaData, unsigned char *rawData, int firstTileWidth=0, int middleTilesWidth=0, int lastTileWidth=0, int validBytes=0x7FFFFFFF)
Sets the already pre-formatted image data for the next transfer.
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
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