Mercurial > hg > svcore
comparison plugin/FeatureExtractionPluginFactory.cpp @ 1209:385deb828b4a piper
Bodge in piper-cpp client (not yet working)
author | Chris Cannam |
---|---|
date | Fri, 14 Oct 2016 14:33:43 +0100 |
parents | 98664afd518b |
children | 584b2d7d7cd9 |
comparison
equal
deleted
inserted
replaced
1208:fef49844b3f8 | 1209:385deb828b4a |
---|---|
34 | 34 |
35 using namespace std; | 35 using namespace std; |
36 | 36 |
37 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 | 37 //#define DEBUG_PLUGIN_SCAN_AND_INSTANTIATE 1 |
38 | 38 |
39 class PluginDeletionNotifyAdapter : public Vamp::HostExt::PluginWrapper { | |
40 public: | |
41 PluginDeletionNotifyAdapter(Vamp::Plugin *plugin, | |
42 FeatureExtractionPluginFactory *factory) : | |
43 PluginWrapper(plugin), m_factory(factory) { } | |
44 virtual ~PluginDeletionNotifyAdapter(); | |
45 protected: | |
46 FeatureExtractionPluginFactory *m_factory; | |
47 }; | |
48 | |
49 PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter() | |
50 { | |
51 // see notes in vamp-sdk/hostext/PluginLoader.cpp from which this is drawn | |
52 Vamp::Plugin *p = m_plugin; | |
53 delete m_plugin; | |
54 m_plugin = 0; | |
55 // acceptable use after free here, as pluginDeleted uses p only as | |
56 // pointer key and does not deref it | |
57 if (m_factory) m_factory->pluginDeleted(p); | |
58 } | |
59 | |
60 static FeatureExtractionPluginFactory *_nativeInstance = 0; | 39 static FeatureExtractionPluginFactory *_nativeInstance = 0; |
61 | 40 |
62 FeatureExtractionPluginFactory * | 41 FeatureExtractionPluginFactory * |
63 FeatureExtractionPluginFactory::instance(QString pluginType) | 42 FeatureExtractionPluginFactory::instance(QString pluginType) |
64 { | 43 { |
79 QString type, soName, label; | 58 QString type, soName, label; |
80 PluginIdentifier::parseIdentifier(identifier, type, soName, label); | 59 PluginIdentifier::parseIdentifier(identifier, type, soName, label); |
81 return instance(type); | 60 return instance(type); |
82 } | 61 } |
83 | 62 |
84 vector<QString> | 63 FeatureExtractionPluginFactory::FeatureExtractionPluginFactory() : |
85 FeatureExtractionPluginFactory::getPluginPath() | 64 m_transport("piper-cpp/bin/piper-vamp-server"), |
65 m_client(&m_transport) | |
86 { | 66 { |
87 if (!m_pluginPath.empty()) return m_pluginPath; | |
88 | |
89 vector<string> p = Vamp::PluginHostAdapter::getPluginPath(); | |
90 for (size_t i = 0; i < p.size(); ++i) m_pluginPath.push_back(p[i].c_str()); | |
91 return m_pluginPath; | |
92 } | 67 } |
93 | 68 |
94 vector<QString> | 69 vector<QString> |
95 FeatureExtractionPluginFactory::getAllPluginIdentifiers() | 70 FeatureExtractionPluginFactory::getAllPluginIdentifiers() |
96 { | 71 { |
115 vector<QString> | 90 vector<QString> |
116 FeatureExtractionPluginFactory::getPluginIdentifiers() | 91 FeatureExtractionPluginFactory::getPluginIdentifiers() |
117 { | 92 { |
118 Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers"); | 93 Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers"); |
119 | 94 |
95 QMutexLocker locker(&m_mutex); | |
96 | |
97 if (m_pluginData.empty()) { | |
98 populate(); | |
99 } | |
100 | |
120 vector<QString> rv; | 101 vector<QString> rv; |
121 | 102 |
122 QStringList candidates = PluginScan::getInstance()->getCandidateLibrariesFor | 103 for (const auto &d: m_pluginData) { |
123 (PluginScan::VampPlugin); | 104 rv.push_back(QString("vamp:") + QString::fromStdString(d.pluginKey)); |
124 | |
125 for (QString soname : candidates) { | |
126 | |
127 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); | |
128 | |
129 if (!libraryHandle) { | |
130 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to load library " << soname << ": " << DLERROR() << endl; | |
131 continue; | |
132 } | |
133 | |
134 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) | |
135 DLSYM(libraryHandle, "vampGetPluginDescriptor"); | |
136 | |
137 if (!fn) { | |
138 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: No descriptor function in " << soname << endl; | |
139 if (DLCLOSE(libraryHandle) != 0) { | |
140 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; | |
141 } | |
142 continue; | |
143 } | |
144 | |
145 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
146 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Vamp descriptor found" << endl; | |
147 #endif | |
148 | |
149 const VampPluginDescriptor *descriptor = 0; | |
150 int index = 0; | |
151 | |
152 map<string, int> known; | |
153 bool ok = true; | |
154 | |
155 while ((descriptor = fn(VAMP_API_VERSION, index))) { | |
156 | |
157 if (known.find(descriptor->identifier) != known.end()) { | |
158 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Plugin library " | |
159 << soname | |
160 << " returns the same plugin identifier \"" | |
161 << descriptor->identifier << "\" at indices " | |
162 << known[descriptor->identifier] << " and " | |
163 << index << endl; | |
164 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Avoiding this library (obsolete API?)" << endl; | |
165 ok = false; | |
166 break; | |
167 } else { | |
168 known[descriptor->identifier] = index; | |
169 } | |
170 | |
171 ++index; | |
172 } | |
173 | |
174 if (ok) { | |
175 | |
176 index = 0; | |
177 | |
178 while ((descriptor = fn(VAMP_API_VERSION, index))) { | |
179 | |
180 QString id = PluginIdentifier::createIdentifier | |
181 ("vamp", soname, descriptor->identifier); | |
182 rv.push_back(id); | |
183 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
184 cerr << "FeatureExtractionPluginFactory::getPluginIdentifiers: Found plugin id " << id << " at index " << index << endl; | |
185 #endif | |
186 ++index; | |
187 } | |
188 } | |
189 | |
190 if (DLCLOSE(libraryHandle) != 0) { | |
191 cerr << "WARNING: FeatureExtractionPluginFactory::getPluginIdentifiers: Failed to unload library " << soname << endl; | |
192 } | |
193 } | 105 } |
194 | 106 |
195 generateTaxonomy(); | |
196 | |
197 return rv; | 107 return rv; |
198 } | |
199 | |
200 QString | |
201 FeatureExtractionPluginFactory::findPluginFile(QString soname, QString inDir) | |
202 { | |
203 QString file = ""; | |
204 | |
205 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
206 cerr << "FeatureExtractionPluginFactory::findPluginFile(\"" | |
207 << soname << "\", \"" << inDir << "\")" | |
208 << endl; | |
209 #endif | |
210 | |
211 if (inDir != "") { | |
212 | |
213 QDir dir(inDir, PLUGIN_GLOB, | |
214 QDir::Name | QDir::IgnoreCase, | |
215 QDir::Files | QDir::Readable); | |
216 if (!dir.exists()) return ""; | |
217 | |
218 file = dir.filePath(QFileInfo(soname).fileName()); | |
219 | |
220 if (QFileInfo(file).exists() && QFileInfo(file).isFile()) { | |
221 | |
222 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
223 cerr << "FeatureExtractionPluginFactory::findPluginFile: " | |
224 << "found trivially at " << file << endl; | |
225 #endif | |
226 | |
227 return file; | |
228 } | |
229 | |
230 for (unsigned int j = 0; j < dir.count(); ++j) { | |
231 file = dir.filePath(dir[j]); | |
232 if (QFileInfo(file).baseName() == QFileInfo(soname).baseName()) { | |
233 | |
234 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
235 cerr << "FeatureExtractionPluginFactory::findPluginFile: " | |
236 << "found \"" << soname << "\" at " << file << endl; | |
237 #endif | |
238 | |
239 return file; | |
240 } | |
241 } | |
242 | |
243 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
244 cerr << "FeatureExtractionPluginFactory::findPluginFile (with dir): " | |
245 << "not found" << endl; | |
246 #endif | |
247 | |
248 return ""; | |
249 | |
250 } else { | |
251 | |
252 QFileInfo fi(soname); | |
253 | |
254 if (fi.isAbsolute() && fi.exists() && fi.isFile()) { | |
255 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
256 cerr << "FeatureExtractionPluginFactory::findPluginFile: " | |
257 << "found trivially at " << soname << endl; | |
258 #endif | |
259 return soname; | |
260 } | |
261 | |
262 if (fi.isAbsolute() && fi.absolutePath() != "") { | |
263 file = findPluginFile(soname, fi.absolutePath()); | |
264 if (file != "") return file; | |
265 } | |
266 | |
267 vector<QString> path = getPluginPath(); | |
268 for (vector<QString>::iterator i = path.begin(); | |
269 i != path.end(); ++i) { | |
270 if (*i != "") { | |
271 file = findPluginFile(soname, *i); | |
272 if (file != "") return file; | |
273 } | |
274 } | |
275 | |
276 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
277 cerr << "FeatureExtractionPluginFactory::findPluginFile: " | |
278 << "not found" << endl; | |
279 #endif | |
280 | |
281 return ""; | |
282 } | |
283 } | 108 } |
284 | 109 |
285 Vamp::Plugin * | 110 Vamp::Plugin * |
286 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier, | 111 FeatureExtractionPluginFactory::instantiatePlugin(QString identifier, |
287 sv_samplerate_t inputSampleRate) | 112 sv_samplerate_t inputSampleRate) |
288 { | 113 { |
289 Profiler profiler("FeatureExtractionPluginFactory::instantiatePlugin"); | 114 Profiler profiler("FeatureExtractionPluginFactory::instantiatePlugin"); |
290 | 115 |
291 Vamp::Plugin *rv = 0; | |
292 Vamp::PluginHostAdapter *plugin = 0; | |
293 | |
294 const VampPluginDescriptor *descriptor = 0; | |
295 int index = 0; | |
296 | |
297 QString type, soname, label; | 116 QString type, soname, label; |
298 PluginIdentifier::parseIdentifier(identifier, type, soname, label); | 117 PluginIdentifier::parseIdentifier(identifier, type, soname, label); |
299 if (type != "vamp") { | |
300 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
301 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Wrong factory for plugin type " << type << endl; | |
302 #endif | |
303 return 0; | |
304 } | |
305 | 118 |
306 QString found = findPluginFile(soname); | 119 piper_vamp::LoadRequest request; |
120 request.pluginKey = (soname + ":" + label).toStdString(); | |
121 request.inputSampleRate = inputSampleRate; | |
122 request.adapterFlags = 0; | |
123 piper_vamp::LoadResponse response = m_client.loadPlugin(request); | |
307 | 124 |
308 if (found == "") { | 125 return response.plugin; |
309 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find library file " << soname << endl; | |
310 return 0; | |
311 } else if (found != soname) { | |
312 | |
313 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
314 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Given library name was " << soname << ", found at " << found << endl; | |
315 cerr << soname << " -> " << found << endl; | |
316 #endif | |
317 | |
318 } | |
319 | |
320 soname = found; | |
321 | |
322 void *libraryHandle = DLOPEN(soname, RTLD_LAZY | RTLD_LOCAL); | |
323 | |
324 if (!libraryHandle) { | |
325 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to load library " << soname << ": " << DLERROR() << endl; | |
326 return 0; | |
327 } | |
328 | |
329 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) | |
330 DLSYM(libraryHandle, "vampGetPluginDescriptor"); | |
331 | |
332 if (!fn) { | |
333 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: No descriptor function in " << soname << endl; | |
334 goto done; | |
335 } | |
336 | |
337 while ((descriptor = fn(VAMP_API_VERSION, index))) { | |
338 if (label == descriptor->identifier) break; | |
339 ++index; | |
340 } | |
341 | |
342 if (!descriptor) { | |
343 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Failed to find plugin \"" << label << "\" in library " << soname << endl; | |
344 goto done; | |
345 } | |
346 | |
347 plugin = new Vamp::PluginHostAdapter(descriptor, float(inputSampleRate)); | |
348 | |
349 if (plugin) { | |
350 m_handleMap[plugin] = libraryHandle; | |
351 rv = new PluginDeletionNotifyAdapter(plugin, this); | |
352 } | |
353 | |
354 // SVDEBUG << "FeatureExtractionPluginFactory::instantiatePlugin: Constructed Vamp plugin, rv is " << rv << endl; | |
355 | |
356 //!!! need to dlclose() when plugins from a given library are unloaded | |
357 | |
358 done: | |
359 if (!rv) { | |
360 if (DLCLOSE(libraryHandle) != 0) { | |
361 cerr << "WARNING: FeatureExtractionPluginFactory::instantiatePlugin: Failed to unload library " << soname << endl; | |
362 } | |
363 } | |
364 | |
365 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
366 cerr << "FeatureExtractionPluginFactory::instantiatePlugin: Instantiated plugin " << label << " from library " << soname << ": descriptor " << descriptor << ", rv "<< rv << ", label " << rv->getName() << ", outputs " << rv->getOutputDescriptors().size() << endl; | |
367 #endif | |
368 | |
369 return rv; | |
370 } | |
371 | |
372 void | |
373 FeatureExtractionPluginFactory::pluginDeleted(Vamp::Plugin *plugin) | |
374 { | |
375 void *handle = m_handleMap[plugin]; | |
376 if (handle) { | |
377 #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | |
378 cerr << "unloading library " << handle << " for plugin " << plugin << endl; | |
379 #endif | |
380 DLCLOSE(handle); | |
381 } | |
382 m_handleMap.erase(plugin); | |
383 } | 126 } |
384 | 127 |
385 QString | 128 QString |
386 FeatureExtractionPluginFactory::getPluginCategory(QString identifier) | 129 FeatureExtractionPluginFactory::getPluginCategory(QString identifier) |
387 { | 130 { |
388 return m_taxonomy[identifier]; | 131 //!!! (re)implement |
132 // return m_taxonomy[identifier]; | |
133 return QString(); | |
389 } | 134 } |
390 | 135 |
391 void | 136 void |
392 FeatureExtractionPluginFactory::generateTaxonomy() | 137 FeatureExtractionPluginFactory::populate() |
393 { | 138 { |
394 vector<QString> pluginPath = getPluginPath(); | 139 piper_vamp::ListResponse lr = m_client.listPluginData(); |
395 vector<QString> path; | 140 m_pluginData = lr.available; |
141 } | |
396 | 142 |
397 for (size_t i = 0; i < pluginPath.size(); ++i) { | |
398 if (pluginPath[i].contains("/lib/")) { | |
399 QString p(pluginPath[i]); | |
400 path.push_back(p); | |
401 p.replace("/lib/", "/share/"); | |
402 path.push_back(p); | |
403 } | |
404 path.push_back(pluginPath[i]); | |
405 } | |
406 | |
407 for (size_t i = 0; i < path.size(); ++i) { | |
408 | |
409 QDir dir(path[i], "*.cat"); | |
410 | |
411 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: directory " << path[i] << " has " << dir.count() << " .cat files" << endl; | |
412 for (unsigned int j = 0; j < dir.count(); ++j) { | |
413 | |
414 QFile file(path[i] + "/" + dir[j]); | |
415 | |
416 // SVDEBUG << "LADSPAPluginFactory::generateFallbackCategories: about to open " << (path[i]+ "/" + dir[j]) << endl; | |
417 | |
418 if (file.open(QIODevice::ReadOnly)) { | |
419 // cerr << "...opened" << endl; | |
420 QTextStream stream(&file); | |
421 QString line; | |
422 | |
423 while (!stream.atEnd()) { | |
424 line = stream.readLine(); | |
425 // cerr << "line is: \"" << line << "\"" << endl; | |
426 QString id = PluginIdentifier::canonicalise | |
427 (line.section("::", 0, 0)); | |
428 QString cat = line.section("::", 1, 1); | |
429 m_taxonomy[id] = cat; | |
430 // cerr << "FeatureExtractionPluginFactory: set id \"" << id << "\" to cat \"" << cat << "\"" << endl; | |
431 } | |
432 } | |
433 } | |
434 } | |
435 } |