libvisiontransfer  5.1.0
imageprotocol.cpp
1 /*******************************************************************************
2  * Copyright (c) 2017 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  // Make an interleaved copy of both images
237  int bytes0 = imagePair.getPixelFormat(0) == ImagePair::FORMAT_8_BIT ? 1 : 2;
238  int bytes1 = imagePair.getPixelFormat(1) == ImagePair::FORMAT_8_BIT ? 1 : 2;
239 
240  rawBuffer.resize(imagePair.getWidth()*imagePair.getHeight()*(bytes0 + bytes1) + sizeof(short));
241 
242  int bufferOffset = 0;
243  int row0Size = imagePair.getWidth()*bytes0;
244  int row1Size = imagePair.getWidth()*bytes1;
245  for(int y = 0; y<imagePair.getHeight(); y++) {
246  memcpy(&rawBuffer[bufferOffset], &imagePair.getPixelData(0)[y*imagePair.getRowStride(0)], row0Size);
247  bufferOffset += row0Size;
248 
249  memcpy(&rawBuffer[bufferOffset], &imagePair.getPixelData(1)[y*imagePair.getRowStride(1)], row1Size);
250  bufferOffset += row1Size;
251  }
252 
253  rawData = &rawBuffer[0];
254  rawValidBytes = static_cast<int>(rawBuffer.size() - sizeof(short));
255 
256  rawDataLength = getFrameSize(imagePair.getWidth(), imagePair.getHeight(), 0, 0,
257  imagePair.getPixelFormat(0), imagePair.getPixelFormat(1), 0);
258 }
259 
260 void ImageProtocol::Pimpl::setRawTransferData(const ImagePair& metaData, unsigned char* rawData,
261  int firstTileWidth, int secondTileWidth, int validBytes) {
262  if(rawData == nullptr) {
263  throw ProtocolException("Image data is null pointer!");
264  }
265 
266  headerTransferred = false;
267 
268  // Set header as first piece of data
269  copyHeaderToBuffer(metaData, firstTileWidth, secondTileWidth, &headerBuffer[0]);
270  dataProt.startTransfer();
271  dataProt.setTransferData(&headerBuffer[0], sizeof(HeaderData));
272 
273  this->rawData = rawData;
274  rawValidBytes = validBytes;
275 
276  rawDataLength = getFrameSize(metaData.getWidth(), metaData.getHeight(),
277  firstTileWidth, secondTileWidth, metaData.getPixelFormat(0),
278  metaData.getPixelFormat(1), 0);
279 }
280 
281 void ImageProtocol::Pimpl::setRawValidBytes(int validBytes) {
282  rawValidBytes = validBytes;
283  if(headerTransferred) {
284  dataProt.setTransferValidBytes(validBytes);
285  }
286 }
287 
288 const unsigned char* ImageProtocol::Pimpl::getTransferMessage(int& length) {
289  const unsigned char* msg = dataProt.getTransferMessage(length);
290 
291  if(msg == nullptr && !headerTransferred && rawValidBytes > 0) {
292  // Transmitting the header is complete. Lets transfer the actual
293  // payload.
294  headerTransferred = true;
295  dataProt.setTransferData(rawData, rawDataLength, rawValidBytes);
296  msg = dataProt.getTransferMessage(length);
297  }
298 
299  return msg;
300 }
301 
302 bool ImageProtocol::Pimpl::transferComplete() {
303  return dataProt.transferComplete() && headerTransferred;
304 }
305 
306 int ImageProtocol::Pimpl::getFrameSize(int width, int height, int firstTileWidth,
307  int secondTileWidth, ImagePair::ImageFormat format0,
308  ImagePair::ImageFormat format1, int headerSize) {
309  int nibbles0 = format0 == ImagePair::FORMAT_8_BIT ? 2 : 3;
310  int nibbles1 = format1 == ImagePair::FORMAT_8_BIT ? 2 : 3;
311 
312  int effectiveWidth = firstTileWidth > 0 ? firstTileWidth + secondTileWidth : width;
313 
314  return (effectiveWidth * height * (nibbles0 + nibbles1)) /2 + headerSize;
315 }
316 
317 int ImageProtocol::Pimpl::getFormatNibbles(HeaderPixelFormat format) {
318  // A nibble is 4 bits
319  if(format == HDR_FMT_12_BIT_SPLIT || format == HDR_FMT_12_BIT_PACKED) {
320  return 3;
321  } else {
322  return 2;
323  }
324 }
325 
326 void ImageProtocol::Pimpl::copyHeaderToBuffer(const ImagePair& imagePair,
327  int firstTileWidth, int secondTileWidth, unsigned char* buffer) {
328  HeaderData* transferHeader = reinterpret_cast<HeaderData*>(buffer);
329  memset(transferHeader, 0, sizeof(*transferHeader));
330  transferHeader->protocolVersion = CURRENT_VERSION;
331  transferHeader->isRawImagePair = imagePair.isImageDisparityPair() ? 0 : 1;
332  transferHeader->width = htons(imagePair.getWidth());
333  transferHeader->height = htons(imagePair.getHeight());
334  transferHeader->firstTileWidth = htons(firstTileWidth);
335  transferHeader->secondTileWidth = htons(secondTileWidth);
336  transferHeader->format0 = imagePair.getPixelFormat(0) == ImagePair::FORMAT_8_BIT ? HDR_FMT_8_BIT : HDR_FMT_12_BIT_PACKED;
337  transferHeader->format1 = imagePair.getPixelFormat(1) == ImagePair::FORMAT_8_BIT ? HDR_FMT_8_BIT : HDR_FMT_12_BIT_PACKED;
338  transferHeader->seqNum = static_cast<unsigned int>(htonl(imagePair.getSequenceNumber()));
339 
340  int minDisp = 0, maxDisp = 0;
341  imagePair.getDisparityRange(minDisp, maxDisp);
342  transferHeader->minDisparity = minDisp;
343  transferHeader->maxDisparity = maxDisp;
344 
345  int timeSec = 0, timeMicrosec = 0;
346  imagePair.getTimestamp(timeSec, timeMicrosec);
347  transferHeader->timeSec = static_cast<int>(htonl(static_cast<unsigned int>(timeSec)));
348  transferHeader->timeMicrosec = static_cast<int>(htonl(static_cast<unsigned int>(timeMicrosec)));
349 
350  if(imagePair.getQMatrix() != nullptr) {
351  memcpy(transferHeader->q, imagePair.getQMatrix(), sizeof(float)*16);
352  }
353 }
354 
355 void ImageProtocol::Pimpl::resetTransfer() {
356  dataProt.resetTransfer();
357 }
358 
359 unsigned char* ImageProtocol::Pimpl::getNextReceiveBuffer(int& maxLength) {
360  maxLength = dataProt.getMaxReceptionSize();
361  return dataProt.getNextReceiveBuffer(maxLength);
362 }
363 
364 bool ImageProtocol::Pimpl::processReceivedMessage(int length) {
365  receptionDone = false;
366 
367  // Add the received message
368  if(!dataProt.processReceivedMessage(length)) {
369  resetReception();
370  return false;
371  }
372 
373  int receivedBytes = 0;
374  const unsigned char* receivedData = dataProt.getReceivedData(receivedBytes);
375 
376  // Immediately try to decode the header
377  if(!receiveHeaderParsed && receivedBytes > 0) {
378  tryDecodeHeader(receivedData, receivedBytes);
379  }
380 
381  // Check if we have received a complete frame
382  if(receivedBytes == receiveTotalSize) {
383  receptionDone = true;
384  dataProt.finishReception();
385  } else if(receivedBytes > receiveTotalSize) {
386  // This is a corrupted frame
387  dataProt.resetReception();
388  return false;
389  }
390 
391  return true;
392 }
393 
394 void ImageProtocol::Pimpl::tryDecodeHeader(const
395 unsigned char* receivedData, int receivedBytes) {
396  if(receivedBytes >= static_cast<int>(sizeof(HeaderData))) {
397  receiveHeader = *reinterpret_cast<const HeaderData*>(receivedData);
398 
399  if(receiveHeader.protocolVersion > CURRENT_VERSION ||
400  receiveHeader.protocolVersion < 4) {
401  throw ProtocolException("Protocol version mismatch!");
402  }
403 
404  // Convert byte order
405  receiveHeader.width = ntohs(receiveHeader.width);
406  receiveHeader.height = ntohs(receiveHeader.height);
407  receiveHeader.firstTileWidth = ntohs(receiveHeader.firstTileWidth);
408  receiveHeader.secondTileWidth = ntohs(receiveHeader.secondTileWidth);
409  receiveHeader.timeSec = static_cast<int>(
410  htonl(static_cast<unsigned int>(receiveHeader.timeSec)));
411  receiveHeader.timeMicrosec = static_cast<int>(
412  htonl(static_cast<unsigned int>(receiveHeader.timeMicrosec)));
413  receiveHeader.seqNum = htonl(receiveHeader.seqNum);
414 
415  // Make sure that the receive buffer is large enough
416  receiveTotalSize = getFrameSize(
417  receiveHeader.width,
418  receiveHeader.height,
419  receiveHeader.firstTileWidth,
420  receiveHeader.secondTileWidth,
421  receiveHeader.format0 == HDR_FMT_8_BIT ? ImagePair::FORMAT_8_BIT : ImagePair::FORMAT_12_BIT,
422  receiveHeader.format1 == HDR_FMT_8_BIT ? ImagePair::FORMAT_8_BIT : ImagePair::FORMAT_12_BIT,
423  sizeof(HeaderData));
424 
425  dataProt.setReceiveDataSize(receiveTotalSize);
426  receiveHeaderParsed = true;
427  }
428 }
429 
430 bool ImageProtocol::Pimpl::imagesReceived() const {
431  return receptionDone && receiveHeaderParsed;
432 }
433 
434 bool ImageProtocol::Pimpl::getReceivedImagePair(ImagePair& imagePair) {
435  bool complete = false;
436  int validRows;
437  bool ok = getPartiallyReceivedImagePair(imagePair, validRows, complete);
438 
439  return (ok && complete);
440 }
441 
442 bool ImageProtocol::Pimpl::getPartiallyReceivedImagePair(ImagePair& imagePair, int& validRows, bool& complete) {
443  imagePair.setWidth(0);
444  imagePair.setHeight(0);
445 
446  complete = false;
447 
448  if(!receiveHeaderParsed) {
449  // We haven't even received the image header yet
450  return false;
451  } else {
452  // We received at least some pixel data
453  int receivedBytes = 0;
454  unsigned char* data = dataProt.getReceivedData(receivedBytes);
455  if(receivedBytes == receiveTotalSize) {
456  // Receiving this frame has completed
457  dataProt.finishReception();
458  }
459 
460  imagePair.setImageDisparityPair(receiveHeader.isRawImagePair == 0);
461 
462  validRows = 0;
463  imagePair.setWidth(receiveHeader.width);
464  imagePair.setHeight(receiveHeader.height);
465  imagePair.setPixelFormat(0, receiveHeader.format0 == HDR_FMT_8_BIT ? ImagePair::FORMAT_8_BIT : ImagePair::FORMAT_12_BIT);
466  imagePair.setPixelFormat(1, receiveHeader.format1 == HDR_FMT_8_BIT ? ImagePair::FORMAT_8_BIT : ImagePair::FORMAT_12_BIT);
467 
468  int rowStride0 = 0, rowStride1 = 0;
469  int validRows0 = 0, validRows1 = 0;
470  unsigned char* pixel0 = decodeInterleaved(0, receivedBytes, data, validRows0, rowStride0);
471  unsigned char* pixel1 = decodeInterleaved(1, receivedBytes, data, validRows1, rowStride1);
472 
473  imagePair.setRowStride(0, rowStride0);
474  imagePair.setRowStride(1, rowStride1);
475  imagePair.setPixelData(0, pixel0);
476  imagePair.setPixelData(1, pixel1);
477  imagePair.setQMatrix(receiveHeader.q);
478 
479  imagePair.setSequenceNumber(receiveHeader.seqNum);
480  imagePair.setTimestamp(receiveHeader.timeSec, receiveHeader.timeMicrosec);
481  imagePair.setDisparityRange(receiveHeader.minDisparity, receiveHeader.maxDisparity);
482 
483  validRows = min(validRows0, validRows1);
484 
485  if(validRows == receiveHeader.height) {
486  complete = true;
487  }
488 
489  if(receptionDone) {
490  // Reset everything for receiving the next image
491  resetReception();
492  }
493 
494  return true;
495  }
496 }
497 
498 unsigned char* ImageProtocol::Pimpl::decodeInterleaved(int imageNumber, int receivedBytes,
499  unsigned char* data, int& validRows, int& rowStride) {
500  if(receivedBytes <= static_cast<int>(sizeof(HeaderData))) {
501  // We haven't yet received any data for the requested image
502  return nullptr;
503  }
504 
505  HeaderPixelFormat format = static_cast<HeaderPixelFormat>(
506  imageNumber == 0 ? receiveHeader.format0 : receiveHeader.format1);
507  int nibbles0 = getFormatNibbles(static_cast<HeaderPixelFormat>(receiveHeader.format0));
508  int nibbles1 = getFormatNibbles(static_cast<HeaderPixelFormat>(receiveHeader.format1));
509 
510  unsigned char* ret = nullptr;
511  int payloadBytes = receivedBytes - sizeof(HeaderData);
512 
513  if(receiveHeader.secondTileWidth == 0) {
514  int bufferOffset = sizeof(HeaderData) + imageNumber*receiveHeader.width * nibbles0/2;
515  int bufferRowStride = receiveHeader.width*(nibbles0 + nibbles1) / 2;
516 
517  if(format == HDR_FMT_8_BIT) {
518  // No decoding is neccessary. We can just pass through the
519  // data pointer
520  ret = &data[bufferOffset];
521  rowStride = bufferRowStride;
522  validRows = payloadBytes / bufferRowStride;
523  } else {
524  // Perform 12-bit => 16 bit decoding
525  allocateDecodeBuffer(imageNumber);
526  validRows = payloadBytes / bufferRowStride;
527  rowStride = 2*receiveHeader.width;
528  int lastRow = lastReceivedPayloadBytes[imageNumber] / bufferRowStride;
529 
530  if(format == HDR_FMT_12_BIT_SPLIT) {
531  BitConversions::decode12BitSplit(lastRow, validRows, &data[bufferOffset],
532  &decodeBuffer[imageNumber][0], bufferRowStride, rowStride, receiveHeader.width);
533  } else {
534  BitConversions::decode12BitPacked(lastRow, validRows, &data[bufferOffset],
535  &decodeBuffer[imageNumber][0], bufferRowStride, rowStride, receiveHeader.width);
536  }
537 
538  ret = &decodeBuffer[imageNumber][0];
539  }
540  } else {
541  // Decode the tiled transfer
542  decodeTiledImage(imageNumber,
543  lastReceivedPayloadBytes[imageNumber], payloadBytes,
544  data, receiveHeader.firstTileWidth * (nibbles0 + nibbles1) / 2,
545  receiveHeader.secondTileWidth * (nibbles0 + nibbles1) / 2,
546  validRows, format);
547  ret = &decodeBuffer[imageNumber][0];
548 
549  if(format == HDR_FMT_8_BIT) {
550  rowStride = receiveHeader.width;
551  } else {
552  rowStride = 2*receiveHeader.width;
553  }
554  }
555 
556  lastReceivedPayloadBytes[imageNumber] = payloadBytes;
557  return ret;
558 }
559 
560 void ImageProtocol::Pimpl::allocateDecodeBuffer(int imageNumber) {
561  HeaderPixelFormat format = static_cast<HeaderPixelFormat>(
562  imageNumber == 0 ? receiveHeader.format0 : receiveHeader.format1);
563  int bytesPerPixel = (format == HDR_FMT_8_BIT ? 1 : 2);
564  int bufferSize = receiveHeader.width * receiveHeader.height * bytesPerPixel;
565 
566  if(decodeBuffer[imageNumber].size() != static_cast<unsigned int>(bufferSize)) {
567  decodeBuffer[imageNumber].resize(bufferSize);
568  }
569 }
570 
571 void ImageProtocol::Pimpl::decodeTiledImage(int imageNumber, int lastReceivedPayloadBytes, int receivedPayloadBytes,
572  const unsigned char* data, int firstTileStride, int secondTileStride, int& validRows,
573  HeaderPixelFormat format) {
574 
575  // Allocate a decoding buffer
576  allocateDecodeBuffer(imageNumber);
577 
578  // Get beginning and end of first tile
579  int startFirstTile = lastReceivedPayloadBytes / firstTileStride;
580  int stopFirstTile = std::min(receivedPayloadBytes / firstTileStride,
581  static_cast<int>(receiveHeader.height));
582 
583  // Get beginning and end of second tile
584  int secondTileBytes = receivedPayloadBytes - (receiveHeader.height*firstTileStride);
585  int lastSecondTileBytes = lastReceivedPayloadBytes - (receiveHeader.height*firstTileStride);
586  int startSecondTile = std::max(0, lastSecondTileBytes / secondTileStride);
587  int stopSecondTile = std::max(0, secondTileBytes / secondTileStride);
588  int firstTileOffset = sizeof(HeaderData) + imageNumber * getFormatNibbles(
589  static_cast<HeaderPixelFormat>(receiveHeader.format0)) * receiveHeader.firstTileWidth / 2;
590 
591  // Decode first tile
592  if(format == HDR_FMT_12_BIT_SPLIT) {
593  BitConversions::decode12BitSplit(startFirstTile, stopFirstTile, &data[firstTileOffset], &decodeBuffer[imageNumber][0],
594  firstTileStride, 2*receiveHeader.width, receiveHeader.firstTileWidth);
595  } else if(format == HDR_FMT_12_BIT_PACKED) {
596  BitConversions::decode12BitPacked(startFirstTile, stopFirstTile, &data[firstTileOffset], &decodeBuffer[imageNumber][0],
597  firstTileStride, 2*receiveHeader.width, receiveHeader.firstTileWidth);
598  } else {
599  decodeRowsFromTile(startFirstTile, stopFirstTile, &data[firstTileOffset],
600  &decodeBuffer[imageNumber][0], firstTileStride, receiveHeader.width,
601  receiveHeader.firstTileWidth);
602  }
603 
604  // Decode second tile
605  int secondTileOffset = sizeof(HeaderData) + receiveHeader.height*firstTileStride +
606  imageNumber * getFormatNibbles(static_cast<HeaderPixelFormat>(receiveHeader.format0)) * receiveHeader.secondTileWidth / 2;
607 
608  if(format == HDR_FMT_12_BIT_SPLIT) {
609  BitConversions::decode12BitSplit(startSecondTile, stopSecondTile,
610  &data[secondTileOffset], &decodeBuffer[imageNumber][2*receiveHeader.firstTileWidth],
611  secondTileStride, 2*receiveHeader.width, receiveHeader.secondTileWidth);
612  } else if(format == HDR_FMT_12_BIT_PACKED) {
613  BitConversions::decode12BitPacked(startSecondTile, stopSecondTile,
614  &data[secondTileOffset], &decodeBuffer[imageNumber][2*receiveHeader.firstTileWidth],
615  secondTileStride, 2*receiveHeader.width, receiveHeader.secondTileWidth);
616  } else {
617  decodeRowsFromTile(startSecondTile, stopSecondTile, &data[secondTileOffset],
618  &decodeBuffer[imageNumber][receiveHeader.firstTileWidth],
619  secondTileStride, receiveHeader.width, receiveHeader.secondTileWidth);
620  }
621 
622  validRows = stopSecondTile;
623 }
624 
625 void ImageProtocol::Pimpl::decodeRowsFromTile(int startRow, int stopRow, unsigned const char* src,
626  unsigned char* dst, int srcStride, int dstStride, int tileWidth) {
627  for(int y = startRow; y < stopRow; y++) {
628  memcpy(&dst[y*dstStride], &src[y*srcStride], tileWidth);
629  }
630 }
631 
632 void ImageProtocol::Pimpl::resetReception() {
633  receiveHeaderParsed = false;
634  lastReceivedPayloadBytes[0] = 0;
635  lastReceivedPayloadBytes[1] = 0;
636  receiveTotalSize = 0;
637  dataProt.resetReception();
638  receptionDone = false;
639 }
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