comparison plugin/FeatureExtractionPluginFactory.cpp @ 1172:59ae7e04f7e9

Merge
author Chris Cannam
date Fri, 04 Mar 2016 12:29:35 +0000
parents 7c4f4701b49f
children 6877f4200912
comparison
equal deleted inserted replaced
1171:fa1bec83441e 1172:59ae7e04f7e9
27 #include <QTextStream> 27 #include <QTextStream>
28 28
29 #include <iostream> 29 #include <iostream>
30 30
31 #include "base/Profiler.h" 31 #include "base/Profiler.h"
32
33 using namespace std;
32 34
33 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 35 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1
34 36
35 class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper { 37 class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper {
36 public: 38 public:
75 QString type, soName, label; 77 QString type, soName, label;
76 PluginIdentifier::parseIdentifier(identifier, type, soName, label); 78 PluginIdentifier::parseIdentifier(identifier, type, soName, label);
77 return instance(type); 79 return instance(type);
78 } 80 }
79 81
80 std::vector<QString> 82 vector<QString>
81 FeatureExtractionPluginFactory::getPluginPath() 83 FeatureExtractionPluginFactory::getPluginPath()
82 { 84 {
83 if (!m_pluginPath.empty()) return m_pluginPath; 85 if (!m_pluginPath.empty()) return m_pluginPath;
84 86
85 std::vector<std::string> p = Vamp::PluginHostAdapter::getPluginPath(); 87 vector<string> p = Vamp::PluginHostAdapter::getPluginPath();
86 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str()); 88 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str());
87 return m_pluginPath; 89 return m_pluginPath;
88 } 90 }
89 91
90 std::vector<QString> 92 vector<QString>
91 FeatureExtractionPluginFactory::getAllPluginIdentifiers() 93 FeatureExtractionPluginFactory::getAllPluginIdentifiers()
92 { 94 {
93 FeatureExtractionPluginFactory *factory; 95 FeatureExtractionPluginFactory *factory;
94 std::vector<QString> rv; 96 vector<QString> rv;
95 97
96 factory = instance("vamp"); 98 factory = instance("vamp");
97 if (factory) { 99 if (factory) {
98 std::vector<QString> tmp = factory->getPluginIdentifiers(); 100 vector<QString> tmp = factory->getPluginIdentifiers();
99 for (size_t i = 0; i < tmp.size(); ++i) { 101 for (size_t i = 0; i < tmp.size(); ++i) {
100 // cerr << "identifier: " << tmp[i] << endl; 102 // cerr << "identifier: " << tmp[i] << endl;
101 rv.push_back(tmp[i]); 103 rv.push_back(tmp[i]);
102 } 104 }
103 } 105 }
106 RestoreStartupLocale(); 108 RestoreStartupLocale();
107 109
108 return rv; 110 return rv;
109 } 111 }
110 112
111 std::vector<QString> 113 vector<QString>
112 FeatureExtractionPluginFactory::getPluginIdentifiers() 114 FeatureExtractionPluginFactory::getPluginCandidateFiles()
113 { 115 {
114 Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers"); 116 vector<QString> path = getPluginPath();
115 117 vector<QString> candidates;
116 std::vector<QString> rv; 118
117 std::vector<QString> path = getPluginPath(); 119 for (QString dirname : path) {
118 120
119 for (std::vector<QString>::iterator i = path.begin(); i != path.end(); ++i) { 121 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
120 122 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << dirname << endl;
121 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 123 #endif
122 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: scanning directory " << *i << endl; 124
123 #endif 125 QDir pluginDir(dirname, PLUGIN_GLOB,
124
125 QDir pluginDir(*i, PLUGIN_GLOB,
126 QDir::Name | QDir::IgnoreCase, 126 QDir::Name | QDir::IgnoreCase,
127 QDir::Files | QDir::Readable); 127 QDir::Files | QDir::Readable);
128 128
129 for (unsigned int j = 0; j < pluginDir.count(); ++j) { 129 for (unsigned int j = 0; j < pluginDir.count(); ++j) {
130
131 QString soname = pluginDir.filePath(pluginDir[j]); 130 QString soname = pluginDir.filePath(pluginDir[j]);
132 131 candidates.push_back(soname);
133 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 132 }
134 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: trying potential library " << soname << endl; 133 }
135 #endif 134
136 135 return candidates;
137 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); 136 }
137
138 vector<QString>
139 FeatureExtractionPluginFactory::winnowPluginCandidates(vector<QString> candidates,
140 QString &warningMessage)
141 {
142 vector<QString> good, bad;
143 vector<PluginLoadStatus> badStatuses;
144
145 for (QString c: candidates) {
146
147 PluginLoadStatus status =
148 TestPluginLoadability(c, "vampGetPluginDescriptor");
149
150 if (status == PluginLoadOK) {
151 good.push_back(c);
152 } else if (status == UnknownPluginLoadStatus) {
153 cerr << "WARNING: Unknown load status for plugin candidate \""
154 << c << "\", continuing" << endl;
155 good.push_back(c);
156 } else {
157 bad.push_back(c);
158 badStatuses.push_back(status);
159 }
160 }
161
162 if (!bad.empty()) {
163 warningMessage =
164 QObject::tr("<b>Failed to load plugins</b>"
165 "<p>Failed to load one or more plugin libraries:</p>\n");
166 warningMessage += "<ul>";
167 for (int i = 0; in_range_for(bad, i); ++i) {
168 QString m;
169 if (badStatuses[i] == PluginLoadFailedToLoadLibrary) {
170 m = QObject::tr("Failed to load library");
171 } else if (badStatuses[i] == PluginLoadFailedToFindDescriptor) {
172 m = QObject::tr("Failed to query plugins from library after loading");
173 } else if (badStatuses[i] == PluginLoadFailedElsewhere) {
174 m = QObject::tr("Unknown failure");
175 } else {
176 m = QObject::tr("Success: internal error?");
177 }
178 warningMessage += QString("<li>%1 (%2)</li>\n")
179 .arg(bad[i])
180 .arg(m);
181 }
182 warningMessage += "</ul>";
183 }
184 return good;
185 }
186
187 vector<QString>
188 FeatureExtractionPluginFactory::getPluginIdentifiers()
189 {
190 Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers");
191
192 vector<QString> rv;
193 vector<QString> candidates = winnowPluginCandidates(getPluginCandidateFiles(),
194 m_pluginScanError);
195
196 for (QString soname : candidates) {
197
198 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
199 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: trying potential library " << soname << endl;
200 #endif
201
202 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL);
138 203
139 if (!libraryHandle) { 204 if (!libraryHandle) {
140 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl; 205 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl;
141 continue; 206 continue;
142 } 207 }
143 208
144 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 209 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
145 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: It's a library all right, checking for descriptor" << endl; 210 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: It's a library all right, checking for descriptor" << endl;
146 #endif 211 #endif
147 212
148 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) 213 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
149 DLSYM(libraryHandle, "vampGetPluginDescriptor"); 214 DLSYM(libraryHandle, "vampGetPluginDescriptor");
150 215
151 if (!fn) { 216 if (!fn) {
152 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl; 217 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl;
153 if (DLCLOSE(libraryHandle) != 0) {
154 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
155 }
156 continue;
157 }
158
159 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
160 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl;
161 #endif
162
163 const VampPluginDescriptor *descriptor = 0;
164 int index = 0;
165
166 std::map<std::string, int> known;
167 bool ok = true;
168
169 while ((descriptor = fn(VAMP_API_VERSION, index))) {
170
171 if (known.find(descriptor->identifier) != known.end()) {
172 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library "
173 << soname
174 << " returns the same plugin identifier \""
175 << descriptor->identifier << "\" at indices "
176 << known[descriptor->identifier] << " and "
177 << index << endl;
178 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl;
179 ok = false;
180 break;
181 } else {
182 known[descriptor->identifier] = index;
183 }
184
185 ++index;
186 }
187
188 if (ok) {
189
190 index = 0;
191
192 while ((descriptor = fn(VAMP_API_VERSION, index))) {
193
194 QString id = PluginIdentifier::createIdentifier
195 ("vamp", soname, descriptor->identifier);
196 rv.push_back(id);
197 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
198 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl;
199 #endif
200 ++index;
201 }
202 }
203
204 if (DLCLOSE(libraryHandle) != 0) { 218 if (DLCLOSE(libraryHandle) != 0) {
205 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; 219 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
206 } 220 }
207 } 221 continue;
222 }
223
224 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
225 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl;
226 #endif
227
228 const VampPluginDescriptor *descriptor = 0;
229 int index = 0;
230
231 map<string, int> known;
232 bool ok = true;
233
234 while ((descriptor = fn(VAMP_API_VERSION, index))) {
235
236 if (known.find(descriptor->identifier) != known.end()) {
237 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library "
238 << soname
239 << " returns the same plugin identifier \""
240 << descriptor->identifier << "\" at indices "
241 << known[descriptor->identifier] << " and "
242 << index << endl;
243 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl;
244 ok = false;
245 break;
246 } else {
247 known[descriptor->identifier] = index;
248 }
249
250 ++index;
251 }
252
253 if (ok) {
254
255 index = 0;
256
257 while ((descriptor = fn(VAMP_API_VERSION, index))) {
258
259 QString id = PluginIdentifier::createIdentifier
260 ("vamp", soname, descriptor->identifier);
261 rv.push_back(id);
262 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
263 SVDEBUG << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl;
264 #endif
265 ++index;
266 }
267 }
268
269 if (DLCLOSE(libraryHandle) != 0) {
270 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl;
271 }
208 } 272 }
209 273
210 generateTaxonomy(); 274 generateTaxonomy();
211 275
212 return rv; 276 return rv;
277 if (fi.isAbsolute() && fi.absolutePath() != "") { 341 if (fi.isAbsolute() && fi.absolutePath() != "") {
278 file = findPluginFile(soname, fi.absolutePath()); 342 file = findPluginFile(soname, fi.absolutePath());
279 if (file != "") return file; 343 if (file != "") return file;
280 } 344 }
281 345
282 std::vector<QString> path = getPluginPath(); 346 vector<QString> path = getPluginPath();
283 for (std::vector<QString>::iterator i = path.begin(); 347 for (vector<QString>::iterator i = path.begin();
284 i != path.end(); ++i) { 348 i != path.end(); ++i) {
285 if (*i != "") { 349 if (*i != "") {
286 file = findPluginFile(soname, *i); 350 file = findPluginFile(soname, *i);
287 if (file != "") return file; 351 if (file != "") return file;
288 } 352 }
310 int index = 0; 374 int index = 0;
311 375
312 QString type, soname, label; 376 QString type, soname, label;
313 PluginIdentifier::parseIdentifier(identifier, type, soname, label); 377 PluginIdentifier::parseIdentifier(identifier, type, soname, label);
314 if (type != "vamp") { 378 if (type != "vamp") {
315 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl; 379 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
380 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl;
381 #endif
316 return 0; 382 return 0;
317 } 383 }
318 384
319 QString found = findPluginFile(soname); 385 QString found = findPluginFile(soname);
320 386
373 if (DLCLOSE(libraryHandle) != 0) { 439 if (DLCLOSE(libraryHandle) != 0) {
374 cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl; 440 cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl;
375 } 441 }
376 } 442 }
377 443
378 // SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl; 444 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
445 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl;
446 #endif
379 447
380 return rv; 448 return rv;
381 } 449 }
382 450
383 void 451 void
384 FeatureExtractionPluginFactory::pluginDeleted(Vamp::Plugin *plugin) 452 FeatureExtractionPluginFactory::pluginDeleted(Vamp::Plugin *plugin)
385 { 453 {
386 void *handle = m_handleMap[plugin]; 454 void *handle = m_handleMap[plugin];
387 if (handle) { 455 if (handle) {
388 // SVDEBUG << "unloading library " << handle << " for plugin " << plugin << endl; 456 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
457 cerr << "unloading library " << handle << " for plugin " << plugin << endl;
458 #endif
389 DLCLOSE(handle); 459 DLCLOSE(handle);
390 } 460 }
391 m_handleMap.erase(plugin); 461 m_handleMap.erase(plugin);
392 } 462 }
393 463
398 } 468 }
399 469
400 void 470 void
401 FeatureExtractionPluginFactory::generateTaxonomy() 471 FeatureExtractionPluginFactory::generateTaxonomy()
402 { 472 {
403 std::vector<QString> pluginPath = getPluginPath(); 473 vector<QString> pluginPath = getPluginPath();
404 std::vector<QString> path; 474 vector<QString> path;
405 475
406 for (size_t i = 0; i < pluginPath.size(); ++i) { 476 for (size_t i = 0; i < pluginPath.size(); ++i) {
407 if (pluginPath[i].contains("/lib/")) { 477 if (pluginPath[i].contains("/lib/")) {
408 QString p(pluginPath[i]); 478 QString p(pluginPath[i]);
409 path.push_back(p); 479 path.push_back(p);