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 {
43 const char* localAddress,
const char* localService,
int bufferSize,
int maxUdpPacketSize);
47 void sendImagePairAsync(
const ImagePair& imagePair,
bool deleteData);
48 bool collectReceivedImagePair(
ImagePair& imagePair,
double timeout);
51 static constexpr
int NUM_BUFFERS = 6;
57 volatile bool terminate;
61 std::thread sendThread;
63 std::condition_variable sendCond;
64 std::condition_variable sendWaitCond;
66 std::thread receiveThread;
67 std::timed_mutex receiveMutex;
68 std::condition_variable_any receiveCond;
69 std::condition_variable_any receiveWaitCond;
73 std::vector<unsigned char, AlignedAllocator<unsigned char> > receivedData[NUM_BUFFERS];
81 std::exception_ptr receiveException;
82 std::exception_ptr sendException;
84 bool sendThreadCreated;
85 bool receiveThreadCreated;
97 const char* localAddress,
const char* localService,
int bufferSize,
int maxUdpPacketSize)
98 : pimpl(new Pimpl(mode, remoteAddress, remoteService, localAddress, localService, bufferSize, maxUdpPacketSize)) {
101 AsyncTransfer::~AsyncTransfer() {
106 pimpl->sendImagePairAsync(imagePair, deleteData);
110 return pimpl->collectReceivedImagePair(imagePair, timeout);
116 const char* localAddress,
const char* localService,
int bufferSize,
int maxUdpPacketSize)
117 : imgTrans(mode, remoteAddress, remoteService, localAddress, localService, bufferSize, maxUdpPacketSize), terminate(
false),
118 newDataReceived(
false), sendPairValid(
false), deleteSendData(
false), sendThreadCreated(
false),
119 receiveThreadCreated(
false) {
123 while(!imgTrans.tryAccept()) {
124 std::chrono::milliseconds duration(10);
125 std::this_thread::sleep_for(duration);
130 AsyncTransfer::Pimpl::~Pimpl() {
133 sendCond.notify_all();
134 receiveCond.notify_all();
135 sendWaitCond.notify_all();
136 receiveWaitCond.notify_all();
138 if(sendThreadCreated && sendThread.joinable()) {
142 if(receiveThreadCreated && receiveThread.joinable()) {
143 receiveThread.join();
146 if(sendPairValid && deleteSendData) {
147 delete[] sendImagePair.getPixelData(0);
148 delete[] sendImagePair.getPixelData(1);
152 void AsyncTransfer::Pimpl::sendImagePairAsync(
const ImagePair& imagePair,
bool deleteData) {
153 if(!sendThreadCreated) {
155 unique_lock<mutex> lock(sendMutex);
156 sendThread = thread(bind(&AsyncTransfer::Pimpl::sendLoop,
this));
157 sendThreadCreated =
true;
161 unique_lock<mutex> lock(sendMutex);
165 std::rethrow_exception(sendException);
169 sendImagePair = imagePair;
170 sendPairValid =
true;
171 deleteSendData = deleteData;
174 sendCond.notify_one();
179 sendWaitCond.wait(lock);
184 bool AsyncTransfer::Pimpl::collectReceivedImagePair(
ImagePair& imagePair,
double timeout) {
185 if(!receiveThreadCreated) {
187 unique_lock<timed_mutex> lock(receiveMutex);
188 receiveThreadCreated =
true;
189 receiveThread = thread(bind(&AsyncTransfer::Pimpl::receiveLoop,
this));
193 unique_lock<timed_mutex> lock(receiveMutex, std::defer_lock);
197 std::chrono::steady_clock::time_point lockStart =
198 std::chrono::steady_clock::now();
199 if(!lock.try_lock_for(std::chrono::microseconds(static_cast<unsigned int>(timeout*1e6)))) {
205 unsigned int lockDuration =
static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::microseconds>(
206 std::chrono::steady_clock::now() - lockStart).count());
207 timeout = std::max(0.0, timeout - lockDuration*1e-6);
211 if(receiveException) {
212 std::rethrow_exception(receiveException);
215 if(timeout == 0 && !newDataReceived) {
221 if(!newDataReceived) {
223 while(!terminate && !receiveException && !newDataReceived) {
224 receiveCond.wait(lock);
227 receiveCond.wait_for(lock, std::chrono::microseconds(static_cast<unsigned int>(timeout*1e6)));
232 if(receiveException) {
233 std::rethrow_exception(receiveException);
236 if(newDataReceived) {
238 imagePair = receivedPair;
240 newDataReceived =
false;
241 receiveWaitCond.notify_one();
249 void AsyncTransfer::Pimpl::sendLoop() {
252 unique_lock<mutex> lock(sendMutex);
256 bool deletePair =
false;
262 unique_lock<mutex> lock(sendMutex);
264 while(!terminate && !sendPairValid) {
271 pair = sendImagePair;
272 deletePair = deleteSendData;
273 sendPairValid =
false;
275 sendWaitCond.notify_one();
279 imgTrans.setTransferImagePair(pair);
280 imgTrans.transferData(
true);
292 sendException = std::current_exception();
294 sendWaitCond.notify_all();
305 void AsyncTransfer::Pimpl::receiveLoop() {
308 unique_lock<timed_mutex> lock(receiveMutex);
317 if(!imgTrans.receiveImagePair(currentPair)) {
323 for(
int i=0;i<2;i++) {
325 int newStride = currentPair.
getWidth() * bytesPerPixel;
326 int totalSize = currentPair.
getHeight() * newStride;
327 if(static_cast<int>(receivedData[i + bufferIndex].size()) < totalSize) {
328 receivedData[i + bufferIndex].resize(totalSize);
331 memcpy(&receivedData[i + bufferIndex][0], currentPair.
getPixelData(i),
334 for(
int y = 0; y<currentPair.
getHeight(); y++) {
335 memcpy(&receivedData[i + bufferIndex][y*newStride],
341 currentPair.
setPixelData(i, &receivedData[i + bufferIndex][0]);
345 unique_lock<timed_mutex> lock(receiveMutex);
348 while(newDataReceived) {
349 receiveWaitCond.wait_for(lock, std::chrono::milliseconds(100));
356 newDataReceived =
true;
357 receivedPair = currentPair;
358 receiveCond.notify_one();
362 bufferIndex = (bufferIndex + 2) % NUM_BUFFERS;
366 if(!receiveException) {
367 receiveException = std::current_exception();
369 receiveCond.notify_all();
AsyncTransfer(ImageTransfer::OperationMode mode, const char *remoteAddress, const char *remoteService, const char *localAddress, const char *localService, int bufferSize=1048576, int maxUdpPacketSize=1472)
Creates a new transfer object.
Using TCP and acting as communication server.
OperationMode
Supported transfer modes.
unsigned char * getPixelData(int imageNumber) const
Returns the pixel data for the given image.
int getWidth() const
Returns the width of each image.
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.
void setPixelData(int imageNumber, unsigned char *pixelData)
Sets the pixel data for the given image.
A set of two images, which are usually the left camera image and the disparity map.
ImageFormat getPixelFormat(int imageNumber) const
Returns the pixel format for the given image.
void sendImagePairAsync(const ImagePair &imagePair, bool deleteData)
Starts an asynchronous transmission of the given image pair.
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.