libvisiontransfer  5.2.0
imageprotocol.cpp
1 /*******************************************************************************
2  * Copyright (c) 2018 Nerian Vision Technologies
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 
27 // Network headers
28 #ifdef _WIN32
29  #ifndef NOMINMAX
30  #define NOMINMAX
31  #endif
32  #include <winsock2.h>
33 #else
34  #include <arpa/inet.h>
35 #endif
36 
37 using namespace std;
38 
39 /*************** Pimpl class containing all private members ***********/
40 
41 class ImageProtocol::Pimpl {
42 public:
43  Pimpl(ProtocolType protType, int maxUdpPacketSize);
44 
45  // Redeclaration of public members
46  void setTransferImagePair(const ImagePair& imagePair);
47  void setRawTransferData(const ImagePair& metaData, unsigned char* rawData,
48  int firstTileWidth = 0, int secondTileWidth = 0, int validBytes = 0x7FFFFFFF);
49  void setRawValidBytes(int validBytes);
50  const unsigned char* getTransferMessage(int& length);
51  bool transferComplete();
52  void resetTransfer();
53  bool getReceivedImagePair(ImagePair& imagePair);
54  bool getPartiallyReceivedImagePair(ImagePair& imagePair,
55  int& validRows, bool& complete);
56  bool imagesReceived() const;
57 
58  unsigned char* getNextReceiveBuffer(int& maxLength);
59 
60  bool processReceivedMessage(int length);
61  int getProspectiveMessageSize();
62  void resetReception();
63 
64 private:
65  enum HeaderPixelFormat {
66  HDR_FMT_8_BIT,
67  HDR_FMT_12_BIT_SPLIT, // For backwards compatibility
68  HDR_FMT_12_BIT_PACKED,
69  };
70 
71  // Header data transferred in the first packet
72 #pragma pack(push,1)
73  struct HeaderData{
74  unsigned char protocolVersion;
75  unsigned char isRawImagePair;
76 
77  unsigned short width;
78  unsigned short height;
79 
80  unsigned short firstTileWidth;
81  unsigned short secondTileWidth;
82 
83  unsigned char format0;
84  unsigned char format1;
85  unsigned char minDisparity;
86  unsigned char maxDisparity;
87 
88  unsigned int seqNum;
89  int timeSec;
90  int timeMicrosec;
91 
92  float q[16];
93 
94  unsigned char padding1[6]; // Pad to 32 bytes
95  };
96 #pragma pack(pop)
97 
98  static const unsigned char CURRENT_VERSION = 0x04;
99 
100  // Underlying protocol for data transfers
101  DataBlockProtocol dataProt;
102  ProtocolType protType;
103 
104  // Transfer related variables
105  bool headerTransferred;
106  std::vector<unsigned char> headerBuffer;
107  std::vector<unsigned char> rawBuffer;
108  unsigned char* rawData;
109  int rawValidBytes;
110  int rawDataLength;
111 
112  // Reception related variables
113  std::vector<unsigned char, AlignedAllocator<unsigned char> >decodeBuffer[2];
114  bool receiveHeaderParsed;
115  HeaderData receiveHeader;
116  int lastReceivedPayloadBytes[2];
117  int receiveTotalSize;
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,
132  ImagePair::ImageFormat format0, ImagePair::ImageFormat format1, int headerSize);
133 
134  int getFormatNibbles(HeaderPixelFormat format);
135 
136  void decodeTiledImage(int imageNumber, int lastReceivedPayloadBytes, int receivedPayloadBytes,
137  const unsigned char* data, int firstTileStride, int secondTileStride, int& validRows,
138  HeaderPixelFormat 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(ProtocolType protType, int maxUdpPacketSize)
150  : pimpl(new Pimpl(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  return pimpl->processReceivedMessage(length);
202 }
203 
205  pimpl->resetReception();
206 }
207 
208 /******************** Implementation in pimpl class *******************/
209 
210 ImageProtocol::Pimpl::Pimpl(ProtocolType protType, int maxUdpPacketSize)
211  :dataProt(static_cast<DataBlockProtocol::ProtocolType>(protType), maxUdpPacketSize),
212  protType(protType), headerTransferred(false),
213  rawData(nullptr), rawValidBytes(0), rawDataLength(0), receiveHeaderParsed(false),
214  lastReceivedPayloadBytes{0, 0}, receiveTotalSize(0), receptionDone(false) {
215  headerBuffer.resize(sizeof(HeaderData) + sizeof(unsigned short));
216  memset(&headerBuffer[0], 0, sizeof(headerBuffer.size()));
217  memset(&receiveHeader, 0, sizeof(receiveHeader));
218 
219  // Just after start-up we don't yet know the expected data size. So lets
220  // just allocate enough memory for one UDP packet
221  dataProt.setReceiveDataSize(maxUdpPacketSize);
222 }
223 
224 void ImageProtocol::Pimpl::setTransferImagePair(const ImagePair& imagePair) {
225  if(imagePair.getPixelData(0) == nullptr || imagePair.getPixelData(1) == nullptr) {
226  throw ProtocolException("Image data is null pointer!");
227  }
228 
229  headerTransferred = false;
230 
231  // Set header as first piece of data
232  copyHeaderToBuffer(imagePair, 0, 0, &headerBuffer[0]);
233  dataProt.startTransfer();
234  dataProt.setTransferData(&headerBuffer[0], sizeof(HeaderData));
235 
236  // Perform 12 bit packed encoding if neccessary
237  int nibbles[2] = {0, 0};
238  int rowSize[2] = {0, 0};
239  int rowStride[2] = {0, 0};
240  const unsigned char* pixelData[2] = {nullptr, nullptr};
241  std::vector<unsigned char> encodingBuffer[2];
242 
243  for(int i = 0; i<2; i++) {
244  nibbles[i] = imagePair.getPixelFormat(i) == ImagePair::FORMAT_8_BIT ? 2 : 3;
245  rowSize[i] = imagePair.getWidth()*nibbles[i]/2;
246 
247  if(imagePair.getPixelFormat(i) == ImagePair::FORMAT_8_BIT) {
248  pixelData[i] = imagePair.getPixelData(i);
249  rowStride[i] = imagePair.getRowStride(i);
250  } else {
251  encodingBuffer[i].resize(rowSize[i] * imagePair.getHeight());
252  BitConversions::encode12BitPacked(0, imagePair.getHeight(), imagePair.getPixelData(i),
253  &encodingBuffer[i][0], imagePair.getRowStride(i), rowSize[i], imagePair.getWidth());
254  pixelData[i] = &encodingBuffer[i][0];
255  rowStride[i] = rowSize[i];
256  }
257  }
258 
259  // Make a interleaved copy
260  rawBuffer.resize(imagePair.getWidth()*imagePair.getHeight()*(nibbles[0] + nibbles[1])/2 + sizeof(short));
261  int bufferOffset = 0;
262 
263  for(int y = 0; y<imagePair.getHeight(); y++) {
264  memcpy(&rawBuffer[bufferOffset], &pixelData[0][y*rowStride[0]], rowSize[0]);
265  bufferOffset += rowSize[0];
266 
267  memcpy(&rawBuffer[bufferOffset], &pixelData[1][y*rowStride[1]], rowSize[1]);
268  bufferOffset += rowSize[1];
269  }
270 
271  rawData = &rawBuffer[0];
272  rawValidBytes = static_cast<int>(rawBuffer.size() - sizeof(short));
273 
274  rawDataLength = getFrameSize(imagePair.getWidth(), imagePair.getHeight(), 0, 0,
275  imagePair.getPixelFormat(0), imagePair.getPixelFormat(1), 0);
276 }
277 
278 void ImageProtocol::Pimpl::setRawTransferData(const ImagePair& metaData, unsigned char* rawData,
279  int firstTileWidth, int secondTileWidth, int validBytes) {
280  if(rawData == nullptr) {
281  throw ProtocolException("Image data is null pointer!");
282  }
283 
284  headerTransferred = false;
285 
286  // Set header as first piece of data
287  copyHeaderToBuffer(metaData, firstTileWidth, secondTileWidth, &headerBuffer[0]);
288  dataProt.startTransfer();
289  dataProt.setTransferData(&headerBuffer[0], sizeof(HeaderData));
290 
291  this->rawData = rawData;
292  rawValidBytes = validBytes;
293 
294  rawDataLength = getFrameSize(metaData.getWidth(), metaData.getHeight(),
295  firstTileWidth, secondTileWidth, metaData.getPixelFormat(0),
296  metaData.getPixelFormat(1), 0);
297 }
298 
299 void ImageProtocol::Pimpl::setRawValidBytes(int validBytes) {
300  rawValidBytes = validBytes;
301  if(headerTransferred) {
302  dataProt.setTransferValidBytes(validBytes);
303  }
304 }
305 
306 const unsigned char* ImageProtocol::Pimpl::getTransferMessage(int& length) {
307  const unsigned char* msg = dataProt.getTransferMessage(length);
308 
309  if(msg == nullptr && !headerTransferred && rawValidBytes > 0) {
310  // Transmitting the header is complete. Lets transfer the actual
311  // payload.
312  headerTransferred = true;
313  dataProt.setTransferData(rawData, rawDataLength, rawValidBytes);
314  msg = dataProt.getTransferMessage(length);
315  }
316 
317  return msg;
318 }
319 
320 bool ImageProtocol::Pimpl::transferComplete() {
321  return dataProt.transferComplete() && headerTransferred;
322 }
323 
324 int ImageProtocol::Pimpl::getFrameSize(int width, int height, int firstTileWidth,
325  int secondTileWidth, ImagePair::ImageFormat format0,
326  ImagePair::ImageFormat format1, int headerSize) {
327  int nibbles0 = format0 == ImagePair::FORMAT_8_BIT ? 2 : 3;
328  int nibbles1 = format1 == ImagePair::FORMAT_8_BIT ? 2 : 3;
329 
330  int effectiveWidth = firstTileWidth > 0 ? firstTileWidth + secondTileWidth : width;
331 
332  return (effectiveWidth * height * (nibbles0 + nibbles1)) /2 + headerSize;
333 }
334 
335 int ImageProtocol::Pimpl::getFormatNibbles(HeaderPixelFormat format) {
336  // A nibble is 4 bits
337  if(format == HDR_FMT_12_BIT_SPLIT || format == HDR_FMT_12_BIT_PACKED) {
338  return 3;
339  } else {
340  return 2;
341  }
342 }
343 
344 void ImageProtocol::Pimpl::copyHeaderToBuffer(const ImagePair& imagePair,
345  int firstTileWidth, int secondTileWidth, unsigned char* buffer) {
346  HeaderData* transferHeader = reinterpret_cast<HeaderData*>(buffer);
347  memset(transferHeader, 0, sizeof(*transferHeader));
348  transferHeader->protocolVersion = CURRENT_VERSION;
349  transferHeader->isRawImagePair = imagePair.isImageDisparityPair() ? 0 : 1;
350  transferHeader->width = htons(imagePair.getWidth());
351  transferHeader->height = htons(imagePair.getHeight());
352  transferHeader->firstTileWidth = htons(firstTileWidth);
353  transferHeader->secondTileWidth = htons(secondTileWidth);
354  transferHeader->format0 = imagePair.getPixelFormat(0) == ImagePair::FORMAT_8_BIT ? HDR_FMT_8_BIT : HDR_FMT_12_BIT_PACKED;
355  transferHeader->format1 = imagePair.getPixelFormat(1) == ImagePair::FORMAT_8_BIT ? HDR_FMT_8_BIT : HDR_FMT_12_BIT_PACKED;
356  transferHeader->seqNum = static_cast<unsigned int>(htonl(imagePair.getSequenceNumber()));
357 
358  int minDisp = 0, maxDisp = 0;
359  imagePair.getDisparityRange(minDisp, maxDisp);
360  transferHeader->minDisparity = minDisp;
361  transferHeader->maxDisparity = maxDisp;
362 
363  int timeSec = 0, timeMicrosec = 0;
364  imagePair.getTimestamp(timeSec, timeMicrosec);
365  transferHeader->timeSec = static_cast<int>(htonl(static_cast<unsigned int>(timeSec)));
366  transferHeader->timeMicrosec = static_cast<int>(htonl(static_cast<unsigned int>(timeMicrosec)));
367 
368  if(imagePair.getQMatrix() != nullptr) {
369  memcpy(transferHeader->q, imagePair.getQMatrix(), sizeof(float)*16);
370  }
371 }
372 
373 void ImageProtocol::Pimpl::resetTransfer() {
374  dataProt.resetTransfer();
375 }
376 
377 unsigned char* ImageProtocol::Pimpl::getNextReceiveBuffer(int& maxLength) {
378  maxLength = dataProt.getMaxReceptionSize();
379  return dataProt.getNextReceiveBuffer(maxLength);
380 }
381 
382 bool ImageProtocol::Pimpl::processReceivedMessage(int length) {
383  receptionDone = false;
384 
385  // Add the received message
386  if(!dataProt.processReceivedMessage(length)) {
387  resetReception();
388  return false;
389  }
390 
391  int receivedBytes = 0;
392  const unsigned char* receivedData = dataProt.getReceivedData(receivedBytes);
393 
394  // Immediately try to decode the header
395  if(!receiveHeaderParsed && receivedBytes > 0) {
396  tryDecodeHeader(receivedData, receivedBytes);
397  }
398 
399  // Check if we have received a complete frame
400  if(receivedBytes == receiveTotalSize) {
401  receptionDone = true;
402  dataProt.finishReception();
403  } else if(receivedBytes > receiveTotalSize) {
404  // This is a corrupted frame
405  dataProt.resetReception();
406  return false;
407  }
408 
409  return true;
410 }
411 
412 void ImageProtocol::Pimpl::tryDecodeHeader(const
413 unsigned char* receivedData, int receivedBytes) {
414  if(receivedBytes >= static_cast<int>(sizeof(HeaderData))) {
415  receiveHeader = *reinterpret_cast<const HeaderData*>(receivedData);
416 
417  if(receiveHeader.protocolVersion > CURRENT_VERSION ||
418  receiveHeader.protocolVersion < 4) {
419  throw ProtocolException("Protocol version mismatch!");
420  }
421 
422  // Convert byte order
423  receiveHeader.width = ntohs(receiveHeader.width);
424  receiveHeader.height = ntohs(receiveHeader.height);
425  receiveHeader.firstTileWidth = ntohs(receiveHeader.firstTileWidth);
426  receiveHeader.secondTileWidth = ntohs(receiveHeader.secondTileWidth);
427  receiveHeader.timeSec = static_cast<int>(
428  htonl(static_cast<unsigned int>(receiveHeader.timeSec)));
429  receiveHeader.timeMicrosec = static_cast<int>(
430  htonl(static_cast<unsigned int>(receiveHeader.timeMicrosec)));
431  receiveHeader.seqNum = htonl(receiveHeader.seqNum);
432 
433  // Make sure that the receive buffer is large enough
434  receiveTotalSize = getFrameSize(
435  receiveHeader.width,
436  receiveHeader.height,
437  receiveHeader.firstTileWidth,
438  receiveHeader.secondTileWidth,
439  receiveHeader.format0 == HDR_FMT_8_BIT ? ImagePair::FORMAT_8_BIT : ImagePair::FORMAT_12_BIT,
440  receiveHeader.format1 == HDR_FMT_8_BIT ? ImagePair::FORMAT_8_BIT : ImagePair::FORMAT_12_BIT,
441  sizeof(HeaderData));
442 
443  dataProt.setReceiveDataSize(receiveTotalSize);
444  receiveHeaderParsed = true;
445  }
446 }
447 
448 bool ImageProtocol::Pimpl::imagesReceived() const {
449  return receptionDone && receiveHeaderParsed;
450 }
451 
452 bool ImageProtocol::Pimpl::getReceivedImagePair(ImagePair& imagePair) {
453  bool complete = false;
454  int validRows;
455  bool ok = getPartiallyReceivedImagePair(imagePair, validRows, complete);
456 
457  return (ok && complete);
458 }
459 
460 bool ImageProtocol::Pimpl::getPartiallyReceivedImagePair(ImagePair& imagePair, int& validRows, bool& complete) {
461  imagePair.setWidth(0);
462  imagePair.setHeight(0);
463 
464  complete = false;
465 
466  if(!receiveHeaderParsed) {
467  // We haven't even received the image header yet
468  return false;
469  } else {
470  // We received at least some pixel data
471  int receivedBytes = 0;
472  unsigned char* data = dataProt.getReceivedData(receivedBytes);
473  if(receivedBytes == receiveTotalSize) {
474  // Receiving this frame has completed
475  dataProt.finishReception();
476  }
477 
478  imagePair.setImageDisparityPair(receiveHeader.isRawImagePair == 0);
479 
480  validRows = 0;
481  imagePair.setWidth(receiveHeader.width);
482  imagePair.setHeight(receiveHeader.height);
483  imagePair.setPixelFormat(0, receiveHeader.format0 == HDR_FMT_8_BIT ? ImagePair::FORMAT_8_BIT : ImagePair::FORMAT_12_BIT);
484  imagePair.setPixelFormat(1, receiveHeader.format1 == HDR_FMT_8_BIT ? ImagePair::FORMAT_8_BIT : ImagePair::FORMAT_12_BIT);
485 
486  int rowStride0 = 0, rowStride1 = 0;
487  int validRows0 = 0, validRows1 = 0;
488  unsigned char* pixel0 = decodeInterleaved(0, receivedBytes, data, validRows0, rowStride0);
489  unsigned char* pixel1 = decodeInterleaved(1, receivedBytes, data, validRows1, rowStride1);
490 
491  imagePair.setRowStride(0, rowStride0);
492  imagePair.setRowStride(1, rowStride1);
493  imagePair.setPixelData(0, pixel0);
494  imagePair.setPixelData(1, pixel1);
495  imagePair.setQMatrix(receiveHeader.q);
496 
497  imagePair.setSequenceNumber(receiveHeader.seqNum);
498  imagePair.setTimestamp(receiveHeader.timeSec, receiveHeader.timeMicrosec);
499  imagePair.setDisparityRange(receiveHeader.minDisparity, receiveHeader.maxDisparity);
500 
501  validRows = min(validRows0, validRows1);
502 
503  if(validRows == receiveHeader.height) {
504  complete = true;
505  }
506 
507  if(receptionDone) {
508  // Reset everything for receiving the next image
509  resetReception();
510  }
511 
512  return true;
513  }
514 }
515 
516 unsigned char* ImageProtocol::Pimpl::decodeInterleaved(int imageNumber, int receivedBytes,
517  unsigned char* data, int& validRows, int& rowStride) {
518  if(receivedBytes <= static_cast<int>(sizeof(HeaderData))) {
519  // We haven't yet received any data for the requested image
520  return nullptr;
521  }
522 
523  HeaderPixelFormat format = static_cast<HeaderPixelFormat>(
524  imageNumber == 0 ? receiveHeader.format0 : receiveHeader.format1);
525  int nibbles0 = getFormatNibbles(static_cast<HeaderPixelFormat>(receiveHeader.format0));
526  int nibbles1 = getFormatNibbles(static_cast<HeaderPixelFormat>(receiveHeader.format1));
527 
528  unsigned char* ret = nullptr;
529  int payloadBytes = receivedBytes - sizeof(HeaderData);
530 
531  if(receiveHeader.secondTileWidth == 0) {
532  int bufferOffset = sizeof(HeaderData) + imageNumber*receiveHeader.width * nibbles0/2;
533  int bufferRowStride = receiveHeader.width*(nibbles0 + nibbles1) / 2;
534 
535  if(format == HDR_FMT_8_BIT) {
536  // No decoding is neccessary. We can just pass through the
537  // data pointer
538  ret = &data[bufferOffset];
539  rowStride = bufferRowStride;
540  validRows = payloadBytes / bufferRowStride;
541  } else {
542  // Perform 12-bit => 16 bit decoding
543  allocateDecodeBuffer(imageNumber);
544  validRows = payloadBytes / bufferRowStride;
545  rowStride = 2*receiveHeader.width;
546  int lastRow = lastReceivedPayloadBytes[imageNumber] / bufferRowStride;
547 
548  if(format == HDR_FMT_12_BIT_SPLIT) {
549  BitConversions::decode12BitSplit(lastRow, validRows, &data[bufferOffset],
550  &decodeBuffer[imageNumber][0], bufferRowStride, rowStride, receiveHeader.width);
551  } else {
552  BitConversions::decode12BitPacked(lastRow, validRows, &data[bufferOffset],
553  &decodeBuffer[imageNumber][0], bufferRowStride, rowStride, receiveHeader.width);
554  }
555 
556  ret = &decodeBuffer[imageNumber][0];
557  }
558  } else {
559  // Decode the tiled transfer
560  decodeTiledImage(imageNumber,
561  lastReceivedPayloadBytes[imageNumber], payloadBytes,
562  data, receiveHeader.firstTileWidth * (nibbles0 + nibbles1) / 2,
563  receiveHeader.secondTileWidth * (nibbles0 + nibbles1) / 2,
564  validRows, format);
565  ret = &decodeBuffer[imageNumber][0];
566 
567  if(format == HDR_FMT_8_BIT) {
568  rowStride = receiveHeader.width;
569  } else {
570  rowStride = 2*receiveHeader.width;
571  }
572  }
573 
574  lastReceivedPayloadBytes[imageNumber] = payloadBytes;
575  return ret;
576 }
577 
578 void ImageProtocol::Pimpl::allocateDecodeBuffer(int imageNumber) {
579  HeaderPixelFormat format = static_cast<HeaderPixelFormat>(
580  imageNumber == 0 ? receiveHeader.format0 : receiveHeader.format1);
581  int bytesPerPixel = (format == HDR_FMT_8_BIT ? 1 : 2);
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 secondTileStride, int& validRows,
591  HeaderPixelFormat format) {
592 
593  // Allocate a decoding buffer
594  allocateDecodeBuffer(imageNumber);
595 
596  // Get beginning and end of first tile
597  int startFirstTile = lastReceivedPayloadBytes / firstTileStride;
598  int stopFirstTile = std::min(receivedPayloadBytes / firstTileStride,
599  static_cast<int>(receiveHeader.height));
600 
601  // Get beginning and end of second tile
602  int secondTileBytes = receivedPayloadBytes - (receiveHeader.height*firstTileStride);
603  int lastSecondTileBytes = lastReceivedPayloadBytes - (receiveHeader.height*firstTileStride);
604  int startSecondTile = std::max(0, lastSecondTileBytes / secondTileStride);
605  int stopSecondTile = std::max(0, secondTileBytes / secondTileStride);
606  int firstTileOffset = sizeof(HeaderData) + imageNumber * getFormatNibbles(
607  static_cast<HeaderPixelFormat>(receiveHeader.format0)) * receiveHeader.firstTileWidth / 2;
608 
609  // Decode first tile
610  if(format == HDR_FMT_12_BIT_SPLIT) {
611  BitConversions::decode12BitSplit(startFirstTile, stopFirstTile, &data[firstTileOffset], &decodeBuffer[imageNumber][0],
612  firstTileStride, 2*receiveHeader.width, receiveHeader.firstTileWidth);
613  } else if(format == HDR_FMT_12_BIT_PACKED) {
614  BitConversions::decode12BitPacked(startFirstTile, stopFirstTile, &data[firstTileOffset], &decodeBuffer[imageNumber][0],
615  firstTileStride, 2*receiveHeader.width, receiveHeader.firstTileWidth);
616  } else {
617  decodeRowsFromTile(startFirstTile, stopFirstTile, &data[firstTileOffset],
618  &decodeBuffer[imageNumber][0], firstTileStride, receiveHeader.width,
619  receiveHeader.firstTileWidth);
620  }
621 
622  // Decode second tile
623  int secondTileOffset = sizeof(HeaderData) + receiveHeader.height*firstTileStride +
624  imageNumber * getFormatNibbles(static_cast<HeaderPixelFormat>(receiveHeader.format0)) * receiveHeader.secondTileWidth / 2;
625 
626  if(format == HDR_FMT_12_BIT_SPLIT) {
627  BitConversions::decode12BitSplit(startSecondTile, stopSecondTile,
628  &data[secondTileOffset], &decodeBuffer[imageNumber][2*receiveHeader.firstTileWidth],
629  secondTileStride, 2*receiveHeader.width, receiveHeader.secondTileWidth);
630  } else if(format == HDR_FMT_12_BIT_PACKED) {
631  BitConversions::decode12BitPacked(startSecondTile, stopSecondTile,
632  &data[secondTileOffset], &decodeBuffer[imageNumber][2*receiveHeader.firstTileWidth],
633  secondTileStride, 2*receiveHeader.width, receiveHeader.secondTileWidth);
634  } else {
635  decodeRowsFromTile(startSecondTile, stopSecondTile, &data[secondTileOffset],
636  &decodeBuffer[imageNumber][receiveHeader.firstTileWidth],
637  secondTileStride, receiveHeader.width, receiveHeader.secondTileWidth);
638  }
639 
640  validRows = stopSecondTile;
641 }
642 
643 void ImageProtocol::Pimpl::decodeRowsFromTile(int startRow, int stopRow, unsigned const char* src,
644  unsigned char* dst, int srcStride, int dstStride, int tileWidth) {
645  for(int y = startRow; y < stopRow; y++) {
646  memcpy(&dst[y*dstStride], &src[y*srcStride], tileWidth);
647  }
648 }
649 
650 void ImageProtocol::Pimpl::resetReception() {
651  receiveHeaderParsed = false;
652  lastReceivedPayloadBytes[0] = 0;
653  lastReceivedPayloadBytes[1] = 0;
654  receiveTotalSize = 0;
655  dataProt.resetReception();
656  receptionDone = false;
657 }
bool isImageDisparityPair() const
Returns true if this is a left camera image and disparity map pair.
Definition: imagepair.h:244
void setTimestamp(int seconds, int microsec)
Sets the time at which this image pair has been captured.
Definition: imagepair.h:127
void setHeight(int h)
Sets a new width for both images.
Definition: imagepair.h:65
Exception class that is used for all protocol exceptions.
Definition: exceptions.h:23
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:116
void setPixelFormat(int imageNumber, ImageFormat format)
Sets the pixel format for the given image.
Definition: imagepair.h:86
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...
unsigned char * getPixelData(int imageNumber) const
Returns the pixel data for the given image.
Definition: imagepair.h:190
bool transferComplete()
Returns true if the current transfer has been completed.
A protocol for transmitting large blocks of data over a network.
const float * getQMatrix() const
Returns a pointer to the disparity-to-depth mapping matrix q.
Definition: imagepair.h:198
int getWidth() const
Returns the width of each image.
Definition: imagepair.h:155
void setDisparityRange(int minimum, int maximum)
Sets the value range for the disparity map contained in this image pair.
Definition: imagepair.h:139
void setWidth(int w)
Sets a new width for both images.
Definition: imagepair.h:60
void setQMatrix(const float *q)
Sets the pointer to the disparity-to-depth mapping matrix q.
Definition: imagepair.h:109
void setRowStride(int imageNumber, int stride)
Sets a new row stride for the pixel data of one image.
Definition: imagepair.h:74
ImageProtocol(ProtocolType protType, int maxUdpPacketSize=1472)
Creates a new instance for decoding / encoding network messages for the given network protocol...
void setTransferImagePair(const ImagePair &imagePair)
Sets a new image that will be transfer.
bool processReceivedMessage(int length)
Handles a received network message.
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:214
void setPixelData(int imageNumber, unsigned char *pixelData)
Sets the pixel data for the given image.
Definition: imagepair.h:98
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:227
ProtocolType
Supported network protocols.
Definition: imageprotocol.h:39
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:30
ImageFormat getPixelFormat(int imageNumber) const
Returns the pixel format for the given image.
Definition: imagepair.h:179
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.
8-bit greyscale format
Definition: imagepair.h:37
int getHeight() const
Returns the height of each image.
Definition: imagepair.h:160
unsigned int getSequenceNumber() const
Returns the sequence number for this image pair.
Definition: imagepair.h:205
int getRowStride(int imageNumber) const
Returns the row stride for the pixel data of one image.
Definition: imagepair.h:168
void setImageDisparityPair(bool dispPair)
Sets whether this is a left camera image and disparity map pair, or two raw camera images...
Definition: imagepair.h:148
ImageFormat
Image formats that can be transferred.
Definition: imagepair.h:35
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