15 #if __GNUC__ == 4 && __GNUC_MINOR__ < 9 18 #include <bits/c++config.h> 19 #undef _GLIBCXX_USE_CLOCK_MONOTONIC 26 #include <condition_variable> 32 #include "visiontransfer/asynctransfer.h" 33 #include "visiontransfer/alignedallocator.h" 43 class AsyncTransfer::Pimpl {
45 Pimpl(
const char* address,
const char* service,
47 int bufferSize,
int maxUdpPacketSize);
51 void sendImageSetAsync(
const ImageSet& imageSet,
bool deleteData);
52 bool collectReceivedImageSet(
ImageSet& imageSet,
double timeout);
53 int getNumDroppedFrames()
const;
54 bool isConnected()
const;
56 std::string getRemoteAddress()
const;
60 static constexpr
int NUM_BUFFERS = 6;
61 static constexpr
int SEND_THREAD_SHORT_WAIT_MS = 1;
62 static constexpr
int SEND_THREAD_LONG_WAIT_MS = 10;
68 volatile bool terminate;
72 std::thread sendThread;
74 std::condition_variable sendCond;
75 std::condition_variable sendWaitCond;
77 std::thread receiveThread;
78 std::timed_mutex receiveMutex;
79 std::condition_variable_any receiveCond;
80 std::condition_variable_any receiveWaitCond;
84 std::vector<unsigned char, AlignedAllocator<unsigned char> > receivedData[NUM_BUFFERS];
92 std::exception_ptr receiveException;
93 std::exception_ptr sendException;
95 bool sendThreadCreated;
96 bool receiveThreadCreated;
104 void createSendThread();
109 AsyncTransfer::AsyncTransfer(
const char* address,
const char* service,
111 int bufferSize,
int maxUdpPacketSize)
112 : pimpl(new Pimpl(address, service, protType, server, bufferSize, maxUdpPacketSize)) {
116 : pimpl(new Pimpl(device.getIpAddress().c_str(),
"7681", static_cast<
ImageProtocol::ProtocolType>(device.getNetworkProtocol()),
117 false, bufferSize, maxUdpPacketSize)) {
120 AsyncTransfer::~AsyncTransfer() {
125 pimpl->sendImageSetAsync(imageSet, deleteData);
129 return pimpl->collectReceivedImageSet(imageSet, timeout);
133 return pimpl->getNumDroppedFrames();
137 return pimpl->isConnected();
141 return pimpl->disconnect();
145 return pimpl->getRemoteAddress();
149 return pimpl->tryAccept();
154 AsyncTransfer::Pimpl::Pimpl(
const char* address,
const char* service,
156 int bufferSize,
int maxUdpPacketSize)
157 : imgTrans(address, service, protType, server, bufferSize, maxUdpPacketSize),
158 terminate(
false), newDataReceived(
false), sendSetValid(
false),
159 deleteSendData(
false), sendThreadCreated(
false),
160 receiveThreadCreated(
false) {
167 AsyncTransfer::Pimpl::~Pimpl() {
170 sendCond.notify_all();
171 receiveCond.notify_all();
172 sendWaitCond.notify_all();
173 receiveWaitCond.notify_all();
175 if(sendThreadCreated && sendThread.joinable()) {
179 if(receiveThreadCreated && receiveThread.joinable()) {
180 receiveThread.join();
183 if(sendSetValid && deleteSendData) {
184 delete[] sendImageSet.getPixelData(0);
185 delete[] sendImageSet.getPixelData(1);
189 void AsyncTransfer::Pimpl::createSendThread() {
190 if(!sendThreadCreated) {
192 unique_lock<mutex> lock(sendMutex);
193 sendThread = thread(bind(&AsyncTransfer::Pimpl::sendLoop,
this));
194 sendThreadCreated =
true;
198 void AsyncTransfer::Pimpl::sendImageSetAsync(
const ImageSet& imageSet,
bool deleteData) {
202 unique_lock<mutex> lock(sendMutex);
206 std::rethrow_exception(sendException);
210 sendImageSet = imageSet;
212 deleteSendData = deleteData;
215 sendCond.notify_one();
220 sendWaitCond.wait(lock);
225 bool AsyncTransfer::Pimpl::collectReceivedImageSet(
ImageSet& imageSet,
double timeout) {
226 if(!receiveThreadCreated) {
228 unique_lock<timed_mutex> lock(receiveMutex);
229 receiveThreadCreated =
true;
230 receiveThread = thread(bind(&AsyncTransfer::Pimpl::receiveLoop,
this));
234 unique_lock<timed_mutex> lock(receiveMutex, std::defer_lock);
238 std::chrono::steady_clock::time_point lockStart =
239 std::chrono::steady_clock::now();
240 if(!lock.try_lock_for(std::chrono::microseconds(static_cast<unsigned int>(timeout*1e6)))) {
246 unsigned int lockDuration =
static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::microseconds>(
247 std::chrono::steady_clock::now() - lockStart).count());
248 timeout = std::max(0.0, timeout - lockDuration*1e-6);
252 if(receiveException) {
253 std::rethrow_exception(receiveException);
256 if(timeout == 0 && !newDataReceived) {
262 if(!newDataReceived) {
264 while(!terminate && !receiveException && !newDataReceived) {
265 receiveCond.wait(lock);
268 receiveCond.wait_for(lock, std::chrono::microseconds(static_cast<unsigned int>(timeout*1e6)));
273 if(receiveException) {
274 std::rethrow_exception(receiveException);
277 if(newDataReceived) {
279 imageSet = receivedSet;
281 newDataReceived =
false;
282 receiveWaitCond.notify_one();
290 void AsyncTransfer::Pimpl::sendLoop() {
293 unique_lock<mutex> lock(sendMutex);
297 bool deleteSet =
false;
303 unique_lock<mutex> lock(sendMutex);
305 bool firstWait =
true;
306 while(!terminate && !sendSetValid) {
307 imgTrans.transferData();
308 sendCond.wait_for(lock, std::chrono::milliseconds(
309 firstWait ? SEND_THREAD_SHORT_WAIT_MS : SEND_THREAD_LONG_WAIT_MS));
316 imgSet = sendImageSet;
317 deleteSet = deleteSendData;
318 sendSetValid =
false;
320 sendWaitCond.notify_one();
324 imgTrans.setTransferImageSet(imgSet);
325 imgTrans.transferData();
338 sendException = std::current_exception();
340 sendWaitCond.notify_all();
352 void AsyncTransfer::Pimpl::receiveLoop() {
355 unique_lock<timed_mutex> lock(receiveMutex);
364 if(!imgTrans.receiveImageSet(currentSet)) {
372 int newStride = currentSet.
getWidth() * bytesPerPixel;
373 int totalSize = currentSet.
getHeight() * newStride;
374 if(static_cast<int>(receivedData[i + bufferIndex].size()) < totalSize) {
375 receivedData[i + bufferIndex].resize(totalSize);
378 memcpy(&receivedData[i + bufferIndex][0], currentSet.
getPixelData(i),
381 for(
int y = 0; y<currentSet.
getHeight(); y++) {
382 memcpy(&receivedData[i + bufferIndex][y*newStride],
388 currentSet.
setPixelData(i, &receivedData[i + bufferIndex][0]);
392 unique_lock<timed_mutex> lock(receiveMutex);
395 while(newDataReceived) {
396 receiveWaitCond.wait_for(lock, std::chrono::milliseconds(100));
403 newDataReceived =
true;
404 receivedSet = currentSet;
405 receiveCond.notify_one();
413 if(!receiveException) {
414 receiveException = std::current_exception();
416 receiveCond.notify_all();
420 bool AsyncTransfer::Pimpl::isConnected()
const {
421 return imgTrans.isConnected();
424 void AsyncTransfer::Pimpl::disconnect() {
425 imgTrans.disconnect();
428 std::string AsyncTransfer::Pimpl::getRemoteAddress()
const {
429 return imgTrans.getRemoteAddress();
432 int AsyncTransfer::Pimpl::getNumDroppedFrames()
const {
433 return imgTrans.getNumDroppedFrames();
436 bool AsyncTransfer::Pimpl::tryAccept() {
437 return imgTrans.tryAccept();
int getRowStride(int imageNumber) const
Returns the row stride for the pixel data of one image.
void setPixelData(int imageNumber, unsigned char *pixelData)
Sets the pixel data for the given image.
bool tryAccept()
Tries to accept a client connection.
int getNumberOfImages() const
Returns the number of images in this set.
Class for synchronous transfer of image sets.
AsyncTransfer(const char *address, const char *service="7681", ImageProtocol::ProtocolType protType=ImageProtocol::PROTOCOL_UDP, bool server=false, int bufferSize=1048576, int maxUdpPacketSize=1472)
Creates a new transfer object.
int getHeight() const
Returns the height of each image.
A lightweight protocol for transferring image sets.
bool isConnected() const
Returns true if a remote connection is established.
void disconnect()
Terminates the current connection.
int getBytesPerPixel(int imageNumber) const
Returns the number of bytes that are required to store one image pixel.
int getNumDroppedFrames() const
Returns the number of frames that have been dropped since connecting to the current remote host...
ProtocolType
Supported network protocols.
std::string getRemoteAddress() const
Returns the address of the remote host.
void setRowStride(int imageNumber, int stride)
Sets a new row stride for the pixel data of one image.
Aggregates information about a discovered device.
unsigned char * getPixelData(int imageNumber) const
Returns the pixel data for the given image.
A set of one to three images, but usually two (the left camera image and the disparity map)...
int getWidth() const
Returns the width of each image.
bool collectReceivedImageSet(ImageSet &imageSet, double timeout=-1)
Collects the asynchronously received image.
void sendImageSetAsync(const ImageSet &imageSet, bool deleteData=false)
Starts an asynchronous transmission of the given image set.