21 #include "visiontransfer/imageprotocol.h"
22 #include "visiontransfer/exceptions.h"
23 #include "visiontransfer/internal/alignedallocator.h"
24 #include "visiontransfer/internal/datablockprotocol.h"
25 #include "visiontransfer/internal/bitconversions.h"
26 #include "visiontransfer/internal/internalinformation.h"
35 #include <arpa/inet.h>
38 #define LOG_DEBUG_IMPROTO(expr)
42 using namespace visiontransfer;
43 using namespace visiontransfer::internal;
45 namespace visiontransfer {
49 class ImageProtocol::Pimpl {
54 Pimpl(
bool server, ProtocolType protType,
int maxUdpPacketSize);
57 void setTransferImageSet(
const ImageSet& imageSet);
58 void setRawTransferData(
const ImageSet& metaData,
const std::vector<unsigned char*>& rawData,
59 int firstTileWidth = 0,
int middleTilesWidth = 0,
int lastTileWidth = 0);
60 void setRawValidBytes(
const std::vector<int>& validBytesVec);
61 const unsigned char* getTransferMessage(
int& length);
62 bool transferComplete();
64 bool getReceivedImageSet(
ImageSet& imageSet);
65 bool getPartiallyReceivedImageSet(
ImageSet& imageSet,
66 int& validRows,
bool& complete);
67 bool imagesReceived()
const;
69 unsigned char* getNextReceiveBuffer(
int& maxLength);
71 void processReceivedMessage(
int length);
72 int getProspectiveMessageSize();
73 int getNumDroppedFrames()
const;
74 void resetReception();
75 bool isConnected()
const;
76 const unsigned char* getNextControlMessage(
int& length);
77 bool newClientConnected();
79 std::string statusReport();
81 bool supportsExtendedConnectionStateProtocol()
const;
84 unsigned short MAGIC_SEQUECE = 0x3D15;
88 struct HeaderDataLegacy {
91 unsigned char protocolVersion;
92 unsigned char isRawImagePair_OBSOLETE;
95 unsigned short height;
97 unsigned short firstTileWidth;
98 unsigned short lastTileWidth;
100 unsigned char format0;
101 unsigned char format1;
102 unsigned short minDisparity;
103 unsigned short maxDisparity;
104 unsigned char subpixelFactor;
112 unsigned short middleTilesWidth;
115 struct HeaderDataV2:
public HeaderDataLegacy {
116 unsigned short totalHeaderSize;
117 unsigned short flags;
118 unsigned char numberOfImages;
119 unsigned char format2;
121 NEW_STYLE_TRANSFER = 1,
129 struct HeaderDataV3:
public HeaderDataV2 {
134 unsigned char imageTypes[8];
137 struct HeaderDataV4:
public HeaderDataV3 {
139 int lastSyncPulseSec;
140 int lastSyncPulseMicrosec;
143 struct HeaderData:
public HeaderDataV4{
144 unsigned char format3;
150 ProtocolType protType;
153 std::vector<unsigned char> headerBuffer;
156 std::vector<unsigned char, AlignedAllocator<unsigned char> >decodeBuffer[ImageSet::MAX_SUPPORTED_IMAGES];
157 bool receiveHeaderParsed;
158 HeaderData receiveHeader;
159 int lastReceivedPayloadBytes[ImageSet::MAX_SUPPORTED_IMAGES];
163 void copyHeaderToBuffer(
const ImageSet& imageSet,
int firstTileWidth,
164 int middleTilesWidth,
int lastTileWidth,
unsigned char* buffer);
167 void tryDecodeHeader(
const unsigned char* receivedData,
int receivedBytes);
170 unsigned char* decodeNoninterleaved(
int imageNumber,
int numImages,
int receivedBytes,
171 unsigned char* data,
int& validRows,
int& rowStride);
174 unsigned char* decodeInterleaved(
int imageNumber,
int numImages,
int receivedBytes,
175 unsigned char* data,
int& validRows,
int& rowStride);
177 int getNumTiles(
int width,
int firstTileWidth,
int middleTilesWidth,
int lastTileWidth);
179 int getFrameSize(
int width,
int height,
int firstTileWidth,
int middleTilesWidth,
180 int lastTileWidth,
int totalBits);
184 void decodeTiledImage(
int imageNumber,
int lastReceivedPayloadBytes,
int receivedPayloadBytes,
185 const unsigned char* data,
int firstTileStride,
int middleTilesStride,
int lastTileStride,
188 void decodeRowsFromTile(
int startRow,
int stopRow,
unsigned const char* src,
189 unsigned char* dst,
int srcStride,
int dstStride,
int tileWidth);
191 void allocateDecodeBuffer(
int imageNumber);
197 ImageProtocol::ImageProtocol(
bool server,
ProtocolType protType,
int maxUdpPacketSize)
198 : pimpl(new Pimpl(server, protType, maxUdpPacketSize)) {
202 ImageProtocol::~ImageProtocol() {
207 pimpl->setTransferImageSet(imageSet);
211 int firstTileWidth,
int middleTilesWidth,
int lastTileWidth) {
212 pimpl->setRawTransferData(metaData, imageData, firstTileWidth, middleTilesWidth, lastTileWidth);
216 pimpl->setRawValidBytes(validBytesVec);
220 return pimpl->getTransferMessage(length);
224 return pimpl->transferComplete();
228 pimpl->resetTransfer();
232 return pimpl->getReceivedImageSet(imageSet);
236 ImageSet& imageSet,
int& validRows,
bool& complete) {
237 return pimpl->getPartiallyReceivedImageSet(imageSet, validRows, complete);
241 return pimpl->imagesReceived();
245 return pimpl->getNextReceiveBuffer(maxLength);
249 pimpl->processReceivedMessage(length);
253 return pimpl->getNumDroppedFrames();
257 pimpl->resetReception();
261 return pimpl->isConnected();
265 return pimpl->getNextControlMessage(length);
269 return pimpl->newClientConnected();
273 return pimpl->supportsExtendedConnectionStateProtocol();
278 ImageProtocol::Pimpl::Pimpl(
bool server, ProtocolType protType,
int maxUdpPacketSize)
280 maxUdpPacketSize), protType(protType),
281 receiveHeaderParsed(false), lastReceivedPayloadBytes{0},
282 receptionDone(
false) {
283 headerBuffer.resize(
sizeof(HeaderData) + 128);
284 memset(&headerBuffer[0], 0,
sizeof(headerBuffer.size()));
285 memset(&receiveHeader, 0,
sizeof(receiveHeader));
288 void ImageProtocol::Pimpl::setTransferImageSet(
const ImageSet& imageSet) {
296 copyHeaderToBuffer(imageSet, 0, 0, 0, &headerBuffer[IMAGE_HEADER_OFFSET]);
297 dataProt.resetTransfer();
299 dataProt.setTransferHeader(&headerBuffer[IMAGE_HEADER_OFFSET],
sizeof(HeaderData), numTransferBlocks);
302 int rawDataLength = getFrameSize(imageSet.
getWidth(), imageSet.
getHeight(), 0, 0, 0, bits);
303 dataProt.setTransferBytes(i, rawDataLength);
307 int bits[ImageSet::MAX_SUPPORTED_IMAGES] = {0};
308 int rowSize[ImageSet::MAX_SUPPORTED_IMAGES] = {0};
309 const unsigned char* pixelData[ImageSet::MAX_SUPPORTED_IMAGES] = {
nullptr};
313 rowSize[i] = imageSet.
getWidth()*bits[i]/8;
318 static std::vector<unsigned char> encodingBuffer[ImageSet::MAX_SUPPORTED_IMAGES];
319 encodingBuffer[i].resize(rowSize[i] * imageSet.
getHeight());
322 pixelData[i] = &encodingBuffer[i][0];
327 dataProt.setTransferData(i,
const_cast<unsigned char*
>(pixelData[i]));
331 void ImageProtocol::Pimpl::setRawTransferData(
const ImageSet& metaData,
const std::vector<unsigned char*>& rawData,
332 int firstTileWidth,
int middleTilesWidth,
int lastTileWidth) {
334 throw ProtocolException(
"Mismatch between metadata and number of image buffers!");
338 copyHeaderToBuffer(metaData, firstTileWidth, middleTilesWidth, lastTileWidth, &headerBuffer[IMAGE_HEADER_OFFSET]);
339 dataProt.resetTransfer();
341 dataProt.setTransferHeader(&headerBuffer[IMAGE_HEADER_OFFSET],
sizeof(HeaderData), numTransferBlocks);
345 firstTileWidth, middleTilesWidth, lastTileWidth, metaData.
getBitsPerPixel(i));
346 dataProt.setTransferBytes(i, rawDataLength);
350 dataProt.setTransferData(i, rawData[i]);
354 void ImageProtocol::Pimpl::setRawValidBytes(
const std::vector<int>& validBytesVec) {
355 for (
int i=0; i<static_cast<int>(validBytesVec.size()); ++i) {
356 dataProt.setTransferValidBytes(i, validBytesVec[i]);
360 const unsigned char* ImageProtocol::Pimpl::getTransferMessage(
int& length) {
361 const unsigned char* msg = dataProt.getTransferMessage(length);
364 msg = dataProt.getTransferMessage(length);
370 bool ImageProtocol::Pimpl::transferComplete() {
371 return dataProt.transferComplete();
374 int ImageProtocol::Pimpl::getNumTiles(
int width,
int firstTileWidth,
int middleTilesWidth,
int lastTileWidth) {
375 if(lastTileWidth == 0) {
377 }
else if(middleTilesWidth == 0) {
380 int tileWidth = firstTileWidth + lastTileWidth - middleTilesWidth;
381 return (width - 2*tileWidth + firstTileWidth + lastTileWidth) / (firstTileWidth + lastTileWidth - tileWidth);
385 int ImageProtocol::Pimpl::getFrameSize(
int width,
int height,
int firstTileWidth,
386 int middleTilesWidth,
int lastTileWidth,
int totalBits) {
387 return (width * height * totalBits) /8;
403 void ImageProtocol::Pimpl::copyHeaderToBuffer(
const ImageSet& imageSet,
404 int firstTileWidth,
int middleTilesWidth,
int lastTileWidth,
unsigned char* buffer) {
405 int timeSec = 0, timeMicrosec = 0;
406 HeaderData* transferHeader =
reinterpret_cast<HeaderData*
>(buffer);
408 memset(transferHeader, 0,
sizeof(*transferHeader));
409 transferHeader->magic = htons(MAGIC_SEQUECE);
410 transferHeader->protocolVersion = InternalInformation::CURRENT_PROTOCOL_VERSION;
411 transferHeader->isRawImagePair_OBSOLETE = 0;
412 transferHeader->width = htons(imageSet.
getWidth());
413 transferHeader->height = htons(imageSet.
getHeight());
414 transferHeader->firstTileWidth = htons(firstTileWidth);
415 transferHeader->lastTileWidth = htons(lastTileWidth);
416 transferHeader->middleTilesWidth = htons(middleTilesWidth);
417 transferHeader->format0 =
static_cast<unsigned char>(imageSet.
getPixelFormat(0));
419 transferHeader->seqNum =
static_cast<unsigned int>(htonl(imageSet.
getSequenceNumber()));
422 transferHeader->numberOfImages =
static_cast<unsigned char>(imageSet.
getNumberOfImages());
426 transferHeader->lastSyncPulseSec = htonl(timeSec);
427 transferHeader->lastSyncPulseMicrosec = htonl(timeMicrosec);
429 transferHeader->totalHeaderSize = htons(
sizeof(HeaderData));
430 transferHeader->flags = htons(HeaderData::FlagBits::NEW_STYLE_TRANSFER | HeaderData::FlagBits::HEADER_V3
431 | HeaderData::FlagBits::HEADER_V4 | HeaderData::FlagBits::HEADER_V5);
433 int minDisp = 0, maxDisp = 0;
435 transferHeader->minDisparity = minDisp;
436 transferHeader->maxDisparity = maxDisp;
441 transferHeader->timeSec =
static_cast<int>(htonl(
static_cast<unsigned int>(timeSec)));
442 transferHeader->timeMicrosec =
static_cast<int>(htonl(
static_cast<unsigned int>(timeMicrosec)));
444 int numImageChannels = 0;
445 for (
int i=0; i<(int)
sizeof(transferHeader->imageTypes); ++i) {
446 transferHeader->imageTypes[i] =
static_cast<unsigned char>(ImageSet::ImageType::IMAGE_UNDEFINED);
448 int idx = imageSet.
getIndexOf(ImageSet::ImageType::IMAGE_LEFT);
450 transferHeader->imageTypes[idx] =
static_cast<unsigned char>(ImageSet::ImageType::IMAGE_LEFT);
453 idx = imageSet.
getIndexOf(ImageSet::ImageType::IMAGE_RIGHT);
455 transferHeader->imageTypes[idx] =
static_cast<unsigned char>(ImageSet::ImageType::IMAGE_RIGHT);
458 idx = imageSet.
getIndexOf(ImageSet::ImageType::IMAGE_DISPARITY);
460 transferHeader->imageTypes[idx] =
static_cast<unsigned char>(ImageSet::ImageType::IMAGE_DISPARITY);
463 idx = imageSet.
getIndexOf(ImageSet::ImageType::IMAGE_COLOR);
465 transferHeader->imageTypes[idx] =
static_cast<unsigned char>(ImageSet::ImageType::IMAGE_COLOR);
469 throw std::runtime_error(
"Mismatch between reported number of images and enabled channel selection!");
474 memcpy(transferHeader->q, imageSet.
getQMatrix(),
sizeof(
float)*16);
478 void ImageProtocol::Pimpl::resetTransfer() {
479 dataProt.resetTransfer();
482 unsigned char* ImageProtocol::Pimpl::getNextReceiveBuffer(
int& maxLength) {
483 maxLength = dataProt.getMaxReceptionSize();
484 return dataProt.getNextReceiveBuffer(maxLength);
487 void ImageProtocol::Pimpl::processReceivedMessage(
int length) {
488 receptionDone =
false;
491 dataProt.processReceivedMessage(length, receptionDone);
492 if(!dataProt.wasHeaderReceived() && receiveHeaderParsed) {
494 LOG_DEBUG_IMPROTO(
"Resetting image protocol!");
499 int receivedBytes = 0;
500 dataProt.getReceivedData(receivedBytes);
503 if(!receiveHeaderParsed) {
505 unsigned char* headerData = dataProt.getReceivedHeader(headerLen);
506 if(headerData !=
nullptr) {
507 tryDecodeHeader(headerData, headerLen);
512 void ImageProtocol::Pimpl::tryDecodeHeader(
const
513 unsigned char* receivedData,
int receivedBytes) {
516 constexpr
int optionalDataSize =
sizeof(receiveHeader.middleTilesWidth);
517 constexpr
int mandatoryDataSize =
static_cast<int>(
sizeof(HeaderDataLegacy)) - optionalDataSize;
518 constexpr
int fullyExtensibleHeaderSize =
static_cast<int>(
sizeof(HeaderDataV2));
519 bool isCompleteHeader =
false;
521 if(receivedBytes >= mandatoryDataSize) {
522 if (receivedBytes < fullyExtensibleHeaderSize) {
523 *(
static_cast<HeaderDataLegacy*
>(&receiveHeader)) = *
reinterpret_cast<const HeaderDataLegacy*
>(receivedData);
525 memcpy(&receiveHeader, receivedData, std::min((
size_t)receivedBytes,
sizeof(HeaderData)));
526 receiveHeader = *
reinterpret_cast<const HeaderData*
>(receivedData);
527 isCompleteHeader =
true;
529 if(receiveHeader.magic != htons(MAGIC_SEQUECE)) {
535 if(receiveHeader.protocolVersion != InternalInformation::CURRENT_PROTOCOL_VERSION) {
540 receiveHeader.width = ntohs(receiveHeader.width);
541 receiveHeader.height = ntohs(receiveHeader.height);
542 receiveHeader.firstTileWidth = ntohs(receiveHeader.firstTileWidth);
543 receiveHeader.lastTileWidth = ntohs(receiveHeader.lastTileWidth);
545 receiveHeader.timeSec =
static_cast<int>(
546 ntohl(
static_cast<unsigned int>(receiveHeader.timeSec)));
547 receiveHeader.timeMicrosec =
static_cast<int>(
548 ntohl(
static_cast<unsigned int>(receiveHeader.timeMicrosec)));
549 receiveHeader.seqNum = ntohl(receiveHeader.seqNum);
552 if(receivedBytes >= mandatoryDataSize + optionalDataSize) {
553 receiveHeader.middleTilesWidth = ntohs(receiveHeader.middleTilesWidth);
555 receiveHeader.middleTilesWidth = 0;
557 if (isCompleteHeader) {
559 receiveHeader.totalHeaderSize = ntohs(receiveHeader.totalHeaderSize);
560 receiveHeader.flags = ntohs(receiveHeader.flags);
561 receiveHeader.exposureTime = ntohl(receiveHeader.exposureTime);
562 receiveHeader.lastSyncPulseSec = htonl(receiveHeader.lastSyncPulseSec);
563 receiveHeader.lastSyncPulseMicrosec = htonl(receiveHeader.lastSyncPulseMicrosec);
566 receiveHeader.totalHeaderSize = (receivedBytes <= mandatoryDataSize) ? mandatoryDataSize : static_cast<int>(
sizeof(HeaderDataLegacy));
567 receiveHeader.flags = 0;
568 receiveHeader.numberOfImages = 2;
569 receiveHeader.format2 = 0;
570 receiveHeader.format3 = 0;
571 receiveHeader.exposureTime = 0;
572 receiveHeader.lastSyncPulseSec = 0;
573 receiveHeader.lastSyncPulseMicrosec = 0;
576 receiveHeaderParsed =
true;
580 bool ImageProtocol::Pimpl::imagesReceived()
const {
581 return receptionDone && receiveHeaderParsed;
584 bool ImageProtocol::Pimpl::getReceivedImageSet(
ImageSet& imageSet) {
585 bool complete =
false;
587 bool ok = getPartiallyReceivedImageSet(imageSet, validRows, complete);
589 return (ok && complete);
592 bool ImageProtocol::Pimpl::getPartiallyReceivedImageSet(
ImageSet& imageSet,
int& validRows,
bool& complete) {
598 if(!receiveHeaderParsed) {
604 bool flaggedDisparityPair = (receiveHeader.isRawImagePair_OBSOLETE == 0);
605 bool isInterleaved = (receiveHeader.flags & HeaderData::FlagBits::NEW_STYLE_TRANSFER) == 0;
606 bool arbitraryChannels = (receiveHeader.flags & HeaderData::FlagBits::HEADER_V3) > 0;
607 bool hasExposureTime = (receiveHeader.flags & HeaderData::FlagBits::HEADER_V4) > 0;
610 unsigned short unaccountedFlags = receiveHeader.flags & ~(HeaderData::FlagBits::NEW_STYLE_TRANSFER
611 | HeaderData::FlagBits::HEADER_V3 | HeaderData::FlagBits::HEADER_V4 | HeaderData::FlagBits::HEADER_V5);
612 if (unaccountedFlags != 0) {
615 static bool warnedOnceForward =
false;
616 if (!warnedOnceForward) {
617 LOG_DEBUG_IMPROTO(
"Warning: forward-compatible mode; will attempt to process image stream with unknown extra flags. Consider upgrading the client software.");
618 warnedOnceForward =
true;
622 imageSet.
setWidth(receiveHeader.width);
623 imageSet.
setHeight(receiveHeader.height);
630 int rowStrideArr[ImageSet::MAX_SUPPORTED_IMAGES] = {0};
631 int validRowsArr[ImageSet::MAX_SUPPORTED_IMAGES] = {0};
632 unsigned char* pixelArr[ImageSet::MAX_SUPPORTED_IMAGES] = {
nullptr};
636 static bool warnedOnceBackward =
false;
637 if (!warnedOnceBackward) {
638 LOG_DEBUG_IMPROTO(
"Info: backward-compatible mode; the device is sending with a legacy protocol. Consider upgrading its firmware.");
639 warnedOnceBackward =
true;
641 unsigned char* data = dataProt.getBlockReceiveBuffer(0);
642 int validBytes = dataProt.getBlockValidSize(0);
643 for (
int i=0; i < 2; ++i) {
644 pixelArr[i] = decodeInterleaved(i, imageSet.
getNumberOfImages(), validBytes, data, validRowsArr[i], rowStrideArr[i]);
647 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_LEFT, 0);
648 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_RIGHT, flaggedDisparityPair ? -1 : 1);
649 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_DISPARITY, flaggedDisparityPair ? 1 : -1);
650 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_COLOR, -1);
654 for (
int i=0; i<receiveHeader.numberOfImages; ++i) {
655 unsigned char* data = dataProt.getBlockReceiveBuffer(i);
656 int validBytes = dataProt.getBlockValidSize(i);
657 pixelArr[i] = decodeNoninterleaved(i, imageSet.
getNumberOfImages(), validBytes, data, validRowsArr[i], rowStrideArr[i]);
660 LOG_DEBUG_IMPROTO(
"Protocol exception: " << ex.what());
665 if (arbitraryChannels) {
667 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_LEFT, -1);
668 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_RIGHT, -1);
669 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_DISPARITY, -1);
670 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_COLOR, -1);
672 int typ = receiveHeader.imageTypes[i];
677 static bool warnedOnceV2 =
false;
679 LOG_DEBUG_IMPROTO(
"Info: received a transfer with header v2");
684 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_LEFT, 0);
685 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_RIGHT, flaggedDisparityPair ? -1 : 1);
686 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_DISPARITY, flaggedDisparityPair ? 1 : -1);
687 imageSet.
setIndexOf(ImageSet::ImageType::IMAGE_COLOR, -1);
689 if(hasExposureTime) {
691 imageSet.
setLastSyncPulse(receiveHeader.lastSyncPulseSec, receiveHeader.lastSyncPulseMicrosec);
695 for (
int i=0; i<receiveHeader.numberOfImages; ++i) {
702 imageSet.
setTimestamp(receiveHeader.timeSec, receiveHeader.timeMicrosec);
703 imageSet.
setDisparityRange(receiveHeader.minDisparity, receiveHeader.maxDisparity);
706 validRows = validRowsArr[0];
707 for (
int i=0; i<receiveHeader.numberOfImages; ++i) {
708 if (validRowsArr[i] < validRows) {
709 validRows = validRowsArr[i];
713 if(validRows == receiveHeader.height || receptionDone) {
722 unsigned char* ImageProtocol::Pimpl::decodeNoninterleaved(
int imageNumber,
int numImages,
int receivedBytes,
723 unsigned char* data,
int& validRows,
int& rowStride) {
726 switch (imageNumber) {
740 throw ProtocolException(
"Not implemented: decodeNoninterleaved with image index > 2");
744 int totalBits = bits;
745 unsigned char* ret =
nullptr;
747 if(receiveHeader.lastTileWidth == 0) {
748 int bufferOffset0 = 0;
749 int bufferRowStride = receiveHeader.width*(totalBits) / 8;
754 ret = &data[bufferOffset0];
755 rowStride = bufferRowStride;
756 validRows = std::min(receivedBytes / bufferRowStride, (
int)receiveHeader.height);
759 allocateDecodeBuffer(imageNumber);
760 validRows = std::min(receivedBytes / bufferRowStride, (
int)receiveHeader.height);
761 rowStride = 2*receiveHeader.width;
762 int lastRow = std::min(lastReceivedPayloadBytes[imageNumber] / bufferRowStride, validRows);
764 BitConversions::decode12BitPacked(lastRow, validRows, &data[bufferOffset0],
765 &decodeBuffer[imageNumber][0], bufferRowStride, rowStride, receiveHeader.width);
767 ret = &decodeBuffer[imageNumber][0];
771 decodeTiledImage(imageNumber,
772 lastReceivedPayloadBytes[imageNumber], receivedBytes, data,
773 receiveHeader.firstTileWidth * (totalBits) / 8,
774 receiveHeader.middleTilesWidth * (totalBits) / 8,
775 receiveHeader.lastTileWidth * (totalBits) / 8,
776 validRows, format,
false);
777 ret = &decodeBuffer[imageNumber][0];
778 rowStride = receiveHeader.width*getFormatBits(
782 lastReceivedPayloadBytes[imageNumber] = receivedBytes;
787 unsigned char* ImageProtocol::Pimpl::decodeInterleaved(
int imageNumber,
int numImages,
int receivedBytes,
788 unsigned char* data,
int& validRows,
int& rowStride) {
790 imageNumber == 0 ? receiveHeader.format0 : receiveHeader.format1);
796 int totalBits = (numImages<3)?(bits0 + bits1):(bits0 + bits1 + bits2 + bits3);
798 unsigned char* ret =
nullptr;
800 if(receiveHeader.lastTileWidth == 0) {
802 switch (imageNumber) {
803 case 0: { bufferOffset = 0;
break; }
804 case 1: { bufferOffset = receiveHeader.width * bits0/8;
break; }
805 case 2: { bufferOffset = receiveHeader.width * (bits0 + bits1)/8;
break; }
809 int bufferRowStride = receiveHeader.width*(totalBits) / 8;
814 ret = &data[bufferOffset];
815 rowStride = bufferRowStride;
816 validRows = receivedBytes / bufferRowStride;
819 allocateDecodeBuffer(imageNumber);
820 validRows = std::min(receivedBytes / bufferRowStride, (
int)receiveHeader.height);
821 rowStride = 2*receiveHeader.width;
822 int lastRow = lastReceivedPayloadBytes[imageNumber] / bufferRowStride;
824 BitConversions::decode12BitPacked(lastRow, validRows, &data[bufferOffset],
825 &decodeBuffer[imageNumber][0], bufferRowStride, rowStride, receiveHeader.width);
827 ret = &decodeBuffer[imageNumber][0];
831 decodeTiledImage(imageNumber,
832 lastReceivedPayloadBytes[imageNumber], receivedBytes, data,
833 receiveHeader.firstTileWidth * (totalBits) / 8,
834 receiveHeader.middleTilesWidth * (totalBits) / 8,
835 receiveHeader.lastTileWidth * (totalBits) / 8,
836 validRows, format,
true);
837 ret = &decodeBuffer[imageNumber][0];
838 rowStride = receiveHeader.width*getFormatBits(
842 lastReceivedPayloadBytes[imageNumber] = receivedBytes;
846 void ImageProtocol::Pimpl::allocateDecodeBuffer(
int imageNumber) {
848 switch (imageNumber) {
862 throw ProtocolException(
"Not implemented: allocateDecodeBuffer with image index > 2");
864 int bitsPerPixel = getFormatBits(format,
true);
865 int bufferSize = receiveHeader.width * receiveHeader.height * bitsPerPixel / 8;
867 if(decodeBuffer[imageNumber].size() !=
static_cast<unsigned int>(bufferSize)) {
868 decodeBuffer[imageNumber].resize(bufferSize);
872 void ImageProtocol::Pimpl::decodeTiledImage(
int imageNumber,
int lastReceivedPayloadBytes,
int receivedPayloadBytes,
873 const unsigned char* data,
int firstTileStride,
int middleTilesStride,
int lastTileStride,
int& validRows,
876 allocateDecodeBuffer(imageNumber);
879 int numTiles = getNumTiles(receiveHeader.width, receiveHeader.firstTileWidth,
880 receiveHeader.middleTilesWidth, receiveHeader.lastTileWidth);
881 int payloadOffset = 0;
882 int decodeXOffset = 0;
883 int prevTileStrides = 0;
884 for(
int i = 0; i < numTiles; i++) {
890 tileStride = firstTileStride;
891 tileWidth = receiveHeader.firstTileWidth;
892 }
else if(i == numTiles-1) {
893 tileStride = lastTileStride;
894 tileWidth = receiveHeader.lastTileWidth;
896 tileStride = middleTilesStride;
897 tileWidth = receiveHeader.middleTilesWidth;
900 int tileStart = std::max(0, (lastReceivedPayloadBytes - payloadOffset) / tileStride);
901 int tileStop = std::min(std::max(0, (receivedPayloadBytes - payloadOffset) / tileStride), (
int)receiveHeader.height);
903 if (dataIsInterleaved) {
904 switch (imageNumber) {
905 case 0: { tileOffset = 0;
break; }
906 case 1: { tileOffset = tileWidth * (
909 case 2: { tileOffset = tileWidth * (
920 tileOffset += receiveHeader.height * prevTileStrides;
927 BitConversions::decode12BitPacked(tileStart, tileStop, &data[tileOffset],
928 &decodeBuffer[imageNumber][decodeXOffset], tileStride, 2*receiveHeader.width, tileWidth);
931 decodeRowsFromTile(tileStart, tileStop, &data[tileOffset],
932 &decodeBuffer[imageNumber][decodeXOffset], tileStride,
933 receiveHeader.width*bytesPixel, tileWidth*bytesPixel);
936 payloadOffset += receiveHeader.height * tileStride;
937 decodeXOffset += tileWidth * bytesPixel;
938 prevTileStrides += tileStride;
939 if(i == numTiles-1) {
940 validRows = tileStop;
945 void ImageProtocol::Pimpl::decodeRowsFromTile(
int startRow,
int stopRow,
unsigned const char* src,
946 unsigned char* dst,
int srcStride,
int dstStride,
int tileWidth) {
947 for(
int y = startRow; y < stopRow; y++) {
948 memcpy(&dst[y*dstStride], &src[y*srcStride], tileWidth);
952 void ImageProtocol::Pimpl::resetReception() {
953 receiveHeaderParsed =
false;
954 for (
int i=0; i<ImageSet::MAX_SUPPORTED_IMAGES; ++i) {
955 lastReceivedPayloadBytes[i] = 0;
957 dataProt.resetReception(
false);
958 receptionDone =
false;
961 bool ImageProtocol::Pimpl::isConnected()
const {
962 return dataProt.isConnected();
965 const unsigned char* ImageProtocol::Pimpl::getNextControlMessage(
int& length) {
966 return dataProt.getNextControlMessage(length);
969 bool ImageProtocol::Pimpl::newClientConnected() {
970 return dataProt.newClientConnected();
973 int ImageProtocol::Pimpl::getNumDroppedFrames()
const {
974 return dataProt.getDroppedReceptions();
977 std::string ImageProtocol::statusReport() {
978 return pimpl->statusReport();
980 std::string ImageProtocol::Pimpl::statusReport() {
981 return dataProt.statusReport();
984 bool ImageProtocol::Pimpl::supportsExtendedConnectionStateProtocol()
const {
985 return dataProt.supportsExtendedConnectionStateProtocol();