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" 40 class AsyncTransfer::Pimpl {
42 Pimpl(
const char* address,
const char* service,
44 int bufferSize,
int maxUdpPacketSize);
48 void sendImagePairAsync(
const ImagePair& imagePair,
bool deleteData);
49 bool collectReceivedImagePair(
ImagePair& imagePair,
double timeout);
50 int getNumDroppedFrames()
const;
51 bool isConnected()
const;
53 std::string getRemoteAddress()
const;
57 static constexpr
int NUM_BUFFERS = 6;
58 static constexpr
int SEND_THREAD_SHORT_WAIT_MS = 1;
59 static constexpr
int SEND_THREAD_LONG_WAIT_MS = 10;
65 volatile bool terminate;
69 std::thread sendThread;
71 std::condition_variable sendCond;
72 std::condition_variable sendWaitCond;
74 std::thread receiveThread;
75 std::timed_mutex receiveMutex;
76 std::condition_variable_any receiveCond;
77 std::condition_variable_any receiveWaitCond;
81 std::vector<unsigned char, AlignedAllocator<unsigned char> > receivedData[NUM_BUFFERS];
89 std::exception_ptr receiveException;
90 std::exception_ptr sendException;
92 bool sendThreadCreated;
93 bool receiveThreadCreated;
101 void createSendThread();
108 int bufferSize,
int maxUdpPacketSize)
109 : pimpl(new Pimpl(address, service, protType, server, bufferSize, maxUdpPacketSize)) {
113 : pimpl(new Pimpl(device.getIpAddress().c_str(),
"7681", static_cast<
ImageProtocol::ProtocolType>(device.getNetworkProtocol()),
114 false, bufferSize, maxUdpPacketSize)) {
117 AsyncTransfer::~AsyncTransfer() {
122 pimpl->sendImagePairAsync(imagePair, deleteData);
126 return pimpl->collectReceivedImagePair(imagePair, timeout);
130 return pimpl->getNumDroppedFrames();
134 return pimpl->isConnected();
138 return pimpl->disconnect();
142 return pimpl->getRemoteAddress();
146 return pimpl->tryAccept();
151 AsyncTransfer::Pimpl::Pimpl(
const char* address,
const char* service,
153 int bufferSize,
int maxUdpPacketSize)
154 : imgTrans(address, service, protType, server, bufferSize, maxUdpPacketSize),
155 terminate(
false), newDataReceived(
false), sendPairValid(
false),
156 deleteSendData(
false), sendThreadCreated(
false),
157 receiveThreadCreated(
false) {
164 AsyncTransfer::Pimpl::~Pimpl() {
167 sendCond.notify_all();
168 receiveCond.notify_all();
169 sendWaitCond.notify_all();
170 receiveWaitCond.notify_all();
172 if(sendThreadCreated && sendThread.joinable()) {
176 if(receiveThreadCreated && receiveThread.joinable()) {
177 receiveThread.join();
180 if(sendPairValid && deleteSendData) {
181 delete[] sendImagePair.getPixelData(0);
182 delete[] sendImagePair.getPixelData(1);
186 void AsyncTransfer::Pimpl::createSendThread() {
187 if(!sendThreadCreated) {
189 unique_lock<mutex> lock(sendMutex);
190 sendThread = thread(bind(&AsyncTransfer::Pimpl::sendLoop,
this));
191 sendThreadCreated =
true;
195 void AsyncTransfer::Pimpl::sendImagePairAsync(
const ImagePair& imagePair,
bool deleteData) {
199 unique_lock<mutex> lock(sendMutex);
203 std::rethrow_exception(sendException);
207 sendImagePair = imagePair;
208 sendPairValid =
true;
209 deleteSendData = deleteData;
212 sendCond.notify_one();
217 sendWaitCond.wait(lock);
222 bool AsyncTransfer::Pimpl::collectReceivedImagePair(
ImagePair& imagePair,
double timeout) {
223 if(!receiveThreadCreated) {
225 unique_lock<timed_mutex> lock(receiveMutex);
226 receiveThreadCreated =
true;
227 receiveThread = thread(bind(&AsyncTransfer::Pimpl::receiveLoop,
this));
231 unique_lock<timed_mutex> lock(receiveMutex, std::defer_lock);
235 std::chrono::steady_clock::time_point lockStart =
236 std::chrono::steady_clock::now();
237 if(!lock.try_lock_for(std::chrono::microseconds(static_cast<unsigned int>(timeout*1e6)))) {
243 unsigned int lockDuration =
static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::microseconds>(
244 std::chrono::steady_clock::now() - lockStart).count());
245 timeout = std::max(0.0, timeout - lockDuration*1e-6);
249 if(receiveException) {
250 std::rethrow_exception(receiveException);
253 if(timeout == 0 && !newDataReceived) {
259 if(!newDataReceived) {
261 while(!terminate && !receiveException && !newDataReceived) {
262 receiveCond.wait(lock);
265 receiveCond.wait_for(lock, std::chrono::microseconds(static_cast<unsigned int>(timeout*1e6)));
270 if(receiveException) {
271 std::rethrow_exception(receiveException);
274 if(newDataReceived) {
276 imagePair = receivedPair;
278 newDataReceived =
false;
279 receiveWaitCond.notify_one();
287 void AsyncTransfer::Pimpl::sendLoop() {
290 unique_lock<mutex> lock(sendMutex);
294 bool deletePair =
false;
300 unique_lock<mutex> lock(sendMutex);
302 bool firstWait =
true;
303 while(!terminate && !sendPairValid) {
304 imgTrans.transferData();
305 sendCond.wait_for(lock, std::chrono::milliseconds(
306 firstWait ? SEND_THREAD_SHORT_WAIT_MS : SEND_THREAD_LONG_WAIT_MS));
313 pair = sendImagePair;
314 deletePair = deleteSendData;
315 sendPairValid =
false;
317 sendWaitCond.notify_one();
321 imgTrans.setTransferImagePair(pair);
322 imgTrans.transferData();
334 sendException = std::current_exception();
336 sendWaitCond.notify_all();
347 void AsyncTransfer::Pimpl::receiveLoop() {
350 unique_lock<timed_mutex> lock(receiveMutex);
359 if(!imgTrans.receiveImagePair(currentPair)) {
365 for(
int i=0;i<2;i++) {
367 int newStride = currentPair.
getWidth() * bytesPerPixel;
368 int totalSize = currentPair.
getHeight() * newStride;
369 if(static_cast<int>(receivedData[i + bufferIndex].size()) < totalSize) {
370 receivedData[i + bufferIndex].resize(totalSize);
373 memcpy(&receivedData[i + bufferIndex][0], currentPair.
getPixelData(i),
376 for(
int y = 0; y<currentPair.
getHeight(); y++) {
377 memcpy(&receivedData[i + bufferIndex][y*newStride],
383 currentPair.
setPixelData(i, &receivedData[i + bufferIndex][0]);
387 unique_lock<timed_mutex> lock(receiveMutex);
390 while(newDataReceived) {
391 receiveWaitCond.wait_for(lock, std::chrono::milliseconds(100));
398 newDataReceived =
true;
399 receivedPair = currentPair;
400 receiveCond.notify_one();
404 bufferIndex = (bufferIndex + 2) % NUM_BUFFERS;
408 if(!receiveException) {
409 receiveException = std::current_exception();
411 receiveCond.notify_all();
415 bool AsyncTransfer::Pimpl::isConnected()
const {
416 return imgTrans.isConnected();
419 void AsyncTransfer::Pimpl::disconnect() {
420 imgTrans.disconnect();
423 std::string AsyncTransfer::Pimpl::getRemoteAddress()
const {
424 return imgTrans.getRemoteAddress();
427 int AsyncTransfer::Pimpl::getNumDroppedFrames()
const {
428 return imgTrans.getNumDroppedFrames();
431 bool AsyncTransfer::Pimpl::tryAccept() {
432 return imgTrans.tryAccept();
void disconnect()
Terminates the current connection.
A lightweight protocol for transferring image pairs.
bool tryAccept()
Tries to accept a client connection.
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.
unsigned char * getPixelData(int imageNumber) const
Returns the pixel data for the given image.
int getWidth() const
Returns the width of each image.
int getNumDroppedFrames() const
Returns the number of frames that have been dropped since connecting to the current remote host...
bool isConnected() const
Returns true if a remote connection is established.
void sendImagePairAsync(const ImagePair &imagePair, bool deleteData=false)
Starts an asynchronous transmission of the given image pair.
int getBytesPerPixel(int imageNumber) const
Returns the number of bytes that are required to store one image pixel.
void setRowStride(int imageNumber, int stride)
Sets a new row stride for the pixel data of one image.
Class for synchronous transfer of image pairs.
std::string getRemoteAddress() const
Returns the address of the remote host.
void setPixelData(int imageNumber, unsigned char *pixelData)
Sets the pixel data for the given image.
ProtocolType
Supported network protocols.
A set of two images, which are usually the left camera image and the disparity map.
Aggregates information about a discovered device.
int getHeight() const
Returns the height of each image.
int getRowStride(int imageNumber) const
Returns the row stride for the pixel data of one image.
bool collectReceivedImagePair(ImagePair &imagePair, double timeout=-1)
Collects the asynchronously received image.