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 sendImagePairAsync(
const ImagePair& imagePair,
bool deleteData);
52 bool collectReceivedImagePair(
ImagePair& imagePair,
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->sendImagePairAsync(imagePair, deleteData);
129 return pimpl->collectReceivedImagePair(imagePair, 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), sendPairValid(
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(sendPairValid && deleteSendData) {
184 delete[] sendImagePair.getPixelData(0);
185 delete[] sendImagePair.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::sendImagePairAsync(
const ImagePair& imagePair,
bool deleteData) {
202 unique_lock<mutex> lock(sendMutex);
206 std::rethrow_exception(sendException);
210 sendImagePair = imagePair;
211 sendPairValid =
true;
212 deleteSendData = deleteData;
215 sendCond.notify_one();
220 sendWaitCond.wait(lock);
225 bool AsyncTransfer::Pimpl::collectReceivedImagePair(
ImagePair& imagePair,
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 imagePair = receivedPair;
281 newDataReceived =
false;
282 receiveWaitCond.notify_one();
290 void AsyncTransfer::Pimpl::sendLoop() {
293 unique_lock<mutex> lock(sendMutex);
297 bool deletePair =
false;
303 unique_lock<mutex> lock(sendMutex);
305 bool firstWait =
true;
306 while(!terminate && !sendPairValid) {
307 imgTrans.transferData();
308 sendCond.wait_for(lock, std::chrono::milliseconds(
309 firstWait ? SEND_THREAD_SHORT_WAIT_MS : SEND_THREAD_LONG_WAIT_MS));
316 pair = sendImagePair;
317 deletePair = deleteSendData;
318 sendPairValid =
false;
320 sendWaitCond.notify_one();
324 imgTrans.setTransferImagePair(pair);
325 imgTrans.transferData();
337 sendException = std::current_exception();
339 sendWaitCond.notify_all();
350 void AsyncTransfer::Pimpl::receiveLoop() {
353 unique_lock<timed_mutex> lock(receiveMutex);
362 if(!imgTrans.receiveImagePair(currentPair)) {
368 for(
int i=0;i<2;i++) {
370 int newStride = currentPair.
getWidth() * bytesPerPixel;
371 int totalSize = currentPair.
getHeight() * newStride;
372 if(static_cast<int>(receivedData[i + bufferIndex].size()) < totalSize) {
373 receivedData[i + bufferIndex].resize(totalSize);
376 memcpy(&receivedData[i + bufferIndex][0], currentPair.
getPixelData(i),
379 for(
int y = 0; y<currentPair.
getHeight(); y++) {
380 memcpy(&receivedData[i + bufferIndex][y*newStride],
386 currentPair.
setPixelData(i, &receivedData[i + bufferIndex][0]);
390 unique_lock<timed_mutex> lock(receiveMutex);
393 while(newDataReceived) {
394 receiveWaitCond.wait_for(lock, std::chrono::milliseconds(100));
401 newDataReceived =
true;
402 receivedPair = currentPair;
403 receiveCond.notify_one();
407 bufferIndex = (bufferIndex + 2) % NUM_BUFFERS;
411 if(!receiveException) {
412 receiveException = std::current_exception();
414 receiveCond.notify_all();
418 bool AsyncTransfer::Pimpl::isConnected()
const {
419 return imgTrans.isConnected();
422 void AsyncTransfer::Pimpl::disconnect() {
423 imgTrans.disconnect();
426 std::string AsyncTransfer::Pimpl::getRemoteAddress()
const {
427 return imgTrans.getRemoteAddress();
430 int AsyncTransfer::Pimpl::getNumDroppedFrames()
const {
431 return imgTrans.getNumDroppedFrames();
434 bool AsyncTransfer::Pimpl::tryAccept() {
435 return imgTrans.tryAccept();
int getHeight() const
Returns the height of each image.
bool tryAccept()
Tries to accept a client connection.
Class for synchronous transfer of image pairs.
bool collectReceivedImagePair(ImagePair &imagePair, double timeout=-1)
Collects the asynchronously received image.
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.
A lightweight protocol for transferring image pairs.
void setPixelData(int imageNumber, unsigned char *pixelData)
Sets the pixel data for the given image.
void setRowStride(int imageNumber, int stride)
Sets a new row stride for the pixel data of one image.
bool isConnected() const
Returns true if a remote connection is established.
void disconnect()
Terminates the current connection.
int getRowStride(int imageNumber) const
Returns the row stride for the pixel data of one image.
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.
int getWidth() const
Returns the width of each image.
Aggregates information about a discovered device.
unsigned char * getPixelData(int imageNumber) const
Returns the pixel data for the given image.
void sendImagePairAsync(const ImagePair &imagePair, bool deleteData=false)
Starts an asynchronous transmission of the given image pair.
A set of two images, which are usually the left camera image and the disparity map.
int getBytesPerPixel(int imageNumber) const
Returns the number of bytes that are required to store one image pixel.