Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <tile_map/image_cache.h>
00031
00032 #include <boost/make_shared.hpp>
00033
00034 #include <QtAlgorithms>
00035 #include <QByteArray>
00036 #include <QList>
00037 #include <QNetworkAccessManager>
00038 #include <QNetworkDiskCache>
00039 #include <QUrl>
00040
00041 #include <ros/ros.h>
00042
00043 namespace tile_map
00044 {
00045 bool ComparePriority(const ImagePtr left, const ImagePtr right)
00046 {
00047 return left->Priority() > right->Priority();
00048 }
00049
00050 const int Image::MAXIMUM_FAILURES = 5;
00051
00052 Image::Image(const QString& uri, size_t uri_hash, uint64_t priority) :
00053 uri_(uri),
00054 uri_hash_(uri_hash),
00055 loading_(false),
00056 failures_(0),
00057 failed_(false),
00058 priority_(priority)
00059 {
00060 }
00061
00062 Image::~Image()
00063 {
00064 }
00065
00066 void Image::InitializeImage()
00067 {
00068 image_ = boost::make_shared<QImage>();
00069 }
00070
00071 void Image::ClearImage()
00072 {
00073 image_.reset();
00074 }
00075
00076 void Image::AddFailure()
00077 {
00078 failures_++;
00079 failed_ = failures_ > MAXIMUM_FAILURES;
00080 }
00081
00082 const int ImageCache::MAXIMUM_NETWORK_REQUESTS = 6;
00083
00084 ImageCache::ImageCache(const QString& cache_dir, size_t size) :
00085 network_manager_(this),
00086 cache_dir_(cache_dir),
00087 cache_(size),
00088 exit_(false),
00089 tick_(0),
00090 cache_thread_(new CacheThread(this)),
00091 network_request_semaphore_(MAXIMUM_NETWORK_REQUESTS)
00092 {
00093 QNetworkDiskCache* disk_cache = new QNetworkDiskCache(this);
00094 disk_cache->setCacheDirectory(cache_dir_);
00095 network_manager_.setCache(disk_cache);
00096
00097 connect(&network_manager_, SIGNAL(finished(QNetworkReply*)), this, SLOT(ProcessReply(QNetworkReply*)));
00098 connect(cache_thread_, SIGNAL(RequestImage(QString)), this, SLOT(ProcessRequest(QString)));
00099
00100 cache_thread_->start();
00101 cache_thread_->setPriority(QThread::NormalPriority);
00102 }
00103
00104 ImageCache::~ImageCache()
00105 {
00106
00107
00108 exit_ = true;
00109 cache_thread_->notify();
00110 network_request_semaphore_.release(MAXIMUM_NETWORK_REQUESTS);
00111 cache_thread_->wait();
00112 delete cache_thread_;
00113 }
00114
00115 void ImageCache::Clear()
00116 {
00117 cache_.clear();
00118 network_manager_.cache()->clear();
00119 }
00120
00121 ImagePtr ImageCache::GetImage(size_t uri_hash, const QString& uri, int32_t priority)
00122 {
00123 ImagePtr image;
00124
00125
00126 cache_mutex_.lock();
00127 ImagePtr* image_ptr = cache_.take(uri_hash);
00128 if (!image_ptr)
00129 {
00130
00131 image_ptr = new ImagePtr(boost::make_shared<Image>(uri, uri_hash, priority));
00132 image = *image_ptr;
00133 if (!cache_.insert(uri_hash, image_ptr))
00134 {
00135 ROS_ERROR("FAILED TO CREATE HANDLE: %s", uri.toStdString().c_str());
00136 image_ptr = 0;
00137 }
00138 }
00139 else
00140 {
00141 image = *image_ptr;
00142
00143
00144 cache_.insert(uri_hash, image_ptr);
00145 }
00146
00147 cache_mutex_.unlock();
00148
00149 unprocessed_mutex_.lock();
00150 if (image && !image->GetImage())
00151 {
00152 if (!image->Failed())
00153 {
00154 if (!unprocessed_.contains(uri_hash))
00155 {
00156
00157
00158
00159
00160 image->SetPriority(tick_++);
00161 unprocessed_[uri_hash] = image;
00162 uri_to_hash_map_[uri] = uri_hash;
00163 cache_thread_->notify();
00164 }
00165 else
00166 {
00167
00168
00169
00170
00171 image->IncreasePriority();
00172 }
00173 }
00174 else
00175 {
00176 ROS_ERROR("To many failures for image: %s", uri.toStdString().c_str());
00177 }
00178 }
00179
00180 unprocessed_mutex_.unlock();
00181
00182 return image;
00183 }
00184
00185 void ImageCache::ProcessRequest(QString uri)
00186 {
00187 QNetworkRequest request;
00188 request.setUrl(QUrl(uri));
00189 request.setRawHeader("User-Agent", "mapviz-1.0");
00190 request.setAttribute(
00191 QNetworkRequest::CacheLoadControlAttribute,
00192 QNetworkRequest::PreferCache);
00193 request.setAttribute(
00194 QNetworkRequest::HttpPipeliningAllowedAttribute,
00195 true);
00196
00197 ROS_INFO("Trying to get %s", uri.toStdString().c_str());
00198 QNetworkReply *reply = network_manager_.get(request);
00199 connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
00200 this, SLOT(NetworkError(QNetworkReply::NetworkError)));
00201 }
00202
00203 void ImageCache::ProcessReply(QNetworkReply* reply)
00204 {
00205 QString url = reply->url().toString();
00206
00207 ImagePtr image;
00208 unprocessed_mutex_.lock();
00209
00210 size_t hash = uri_to_hash_map_[url];
00211 image = unprocessed_[hash];
00212 if (image)
00213 {
00214 if (reply->error() == QNetworkReply::NoError)
00215 {
00216 QByteArray data = reply->readAll();
00217 image->InitializeImage();
00218 if (!image->GetImage()->loadFromData(data))
00219 {
00220 ROS_ERROR("FAILED TO CREATE IMAGE FROM REPLY: %s", url.toStdString().c_str());
00221 image->ClearImage();
00222 image->AddFailure();
00223 }
00224 }
00225 else
00226 {
00227 ROS_ERROR("============ AN ERROR OCCURRED ==============: %s", url.toStdString().c_str());
00228 image->AddFailure();
00229 }
00230 }
00231
00232 unprocessed_.remove(hash);
00233 uri_to_hash_map_.remove(url);
00234 if (image)
00235 {
00236 image->SetLoading(false);
00237 }
00238 network_request_semaphore_.release();
00239
00240 unprocessed_mutex_.unlock();
00241
00242 reply->deleteLater();
00243 }
00244
00245 void ImageCache::NetworkError(QNetworkReply::NetworkError error)
00246 {
00247 ROS_ERROR("NETWORK ERROR");
00248
00249 }
00250
00251 const int CacheThread::MAXIMUM_SEQUENTIAL_REQUESTS = 12;
00252
00253 CacheThread::CacheThread(ImageCache* parent) :
00254 p(parent),
00255 waiting_mutex_()
00256 {
00257 waiting_mutex_.lock();
00258 }
00259
00260 void CacheThread::notify()
00261 {
00262 waiting_mutex_.unlock();
00263 }
00264
00265 void CacheThread::run()
00266 {
00267 while (!p->exit_)
00268 {
00269
00270 waiting_mutex_.lock();
00271
00272
00273 p->unprocessed_mutex_.lock();
00274 QList<ImagePtr> images = p->unprocessed_.values();
00275 p->unprocessed_mutex_.unlock();
00276
00277 qSort(images.begin(), images.end(), ComparePriority);
00278
00279
00280
00281
00282
00283
00284
00285
00286 int count = 0;
00287 while (!p->exit_ && !images.empty() && count < MAXIMUM_SEQUENTIAL_REQUESTS)
00288 {
00289 p->network_request_semaphore_.acquire();
00290
00291 ImagePtr image = images.front();
00292 p->unprocessed_mutex_.lock();
00293 if (!image->Loading())
00294 {
00295 image->SetLoading(true);
00296 images.pop_front();
00297
00298 Q_EMIT RequestImage(image->Uri());
00299 }
00300 else
00301 {
00302 images.pop_front();
00303 }
00304 p->unprocessed_mutex_.unlock();
00305
00306 count++;
00307 }
00308 if (!images.empty())
00309 {
00310 waiting_mutex_.unlock();
00311 }
00312 }
00313 }
00314 }