xref: /haiku/src/kits/media/PluginManager.cpp (revision 0fe022fd0d6d600863555f5a556ab5a5273d20e0)
1 /*
2  * Copyright 2004-2010, Marcus Overhagen. All rights reserved.
3  * Distributed under the terms of the OpenBeOS License.
4  */
5 
6 #include <Path.h>
7 #include <image.h>
8 #include <string.h>
9 
10 #include "AddOnManager.h"
11 #include "PluginManager.h"
12 #include "DataExchange.h"
13 #include "debug.h"
14 
15 
16 PluginManager gPluginManager;
17 
18 
19 // #pragma mark - Readers/Decoders
20 
21 
22 status_t
23 PluginManager::CreateReader(Reader** reader, int32* streamCount,
24 	media_file_format* mff, BDataIO* source)
25 {
26 	TRACE("PluginManager::CreateReader enter\n");
27 
28 	BPositionIO *seekable_source = dynamic_cast<BPositionIO *>(source);
29 	if (seekable_source == 0) {
30 		printf("PluginManager::CreateReader: non-seekable sources not "
31 			"supported yet\n");
32 		return B_ERROR;
33 	}
34 
35 	// get list of available readers from the server
36 	entry_ref refs[MAX_READERS];
37 	int32 count;
38 
39 	status_t ret = AddOnManager::GetInstance()->GetReaders(refs, &count,
40 		MAX_READERS);
41 	if (ret != B_OK) {
42 		printf("PluginManager::CreateReader: can't get list of readers: %s\n",
43 			strerror(ret));
44 		return ret;
45 	}
46 
47 	// try each reader by calling it's Sniff function...
48 	for (int32 i = 0; i < count; i++) {
49 		entry_ref ref = refs[i];
50 		MediaPlugin* plugin = GetPlugin(ref);
51 		if (plugin == NULL) {
52 			printf("PluginManager::CreateReader: GetPlugin failed\n");
53 			return B_ERROR;
54 		}
55 
56 		ReaderPlugin* readerPlugin = dynamic_cast<ReaderPlugin*>(plugin);
57 		if (readerPlugin == NULL) {
58 			printf("PluginManager::CreateReader: dynamic_cast failed\n");
59 			PutPlugin(plugin);
60 			return B_ERROR;
61 		}
62 
63 		*reader = readerPlugin->NewReader();
64 		if (*reader == NULL) {
65 			printf("PluginManager::CreateReader: NewReader failed\n");
66 			PutPlugin(plugin);
67 			return B_ERROR;
68 		}
69 
70 		seekable_source->Seek(0, SEEK_SET);
71 		(*reader)->Setup(seekable_source);
72 		(*reader)->fMediaPlugin = plugin;
73 
74 		if ((*reader)->Sniff(streamCount) == B_OK) {
75 			TRACE("PluginManager::CreateReader: Sniff success "
76 				"(%ld stream(s))\n", *streamCount);
77 			(*reader)->GetFileFormatInfo(mff);
78 			return B_OK;
79 		}
80 
81 		DestroyReader(*reader);
82 		*reader = NULL;
83 	}
84 
85 	TRACE("PluginManager::CreateReader leave\n");
86 	return B_MEDIA_NO_HANDLER;
87 }
88 
89 
90 void
91 PluginManager::DestroyReader(Reader* reader)
92 {
93 	if (reader != NULL) {
94 		TRACE("PluginManager::DestroyReader(%p (plugin: %p))\n", reader,
95 			reader->fMediaPlugin);
96 		// NOTE: We have to put the plug-in after deleting the reader,
97 		// since otherwise we may actually unload the code for the
98 		// destructor...
99 		MediaPlugin* plugin = reader->fMediaPlugin;
100 		delete reader;
101 		PutPlugin(plugin);
102 	}
103 }
104 
105 
106 status_t
107 PluginManager::CreateDecoder(Decoder** _decoder, const media_format& format)
108 {
109 	TRACE("PluginManager::CreateDecoder enter\n");
110 
111 	// get decoder for this format
112 	entry_ref ref;
113 	status_t ret = AddOnManager::GetInstance()->GetDecoderForFormat(
114 		&ref, format);
115 	if (ret != B_OK) {
116 		printf("PluginManager::CreateDecoder: can't get decoder for format: "
117 			"%s\n", strerror(ret));
118 		return ret;
119 	}
120 
121 	MediaPlugin* plugin = GetPlugin(ref);
122 	if (plugin == NULL) {
123 		printf("PluginManager::CreateDecoder: GetPlugin failed\n");
124 		return B_ERROR;
125 	}
126 
127 	DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin);
128 	if (decoderPlugin == NULL) {
129 		printf("PluginManager::CreateDecoder: dynamic_cast failed\n");
130 		PutPlugin(plugin);
131 		return B_ERROR;
132 	}
133 
134 	// TODO: In theory, one DecoderPlugin could support multiple Decoders,
135 	// but this is not yet handled (passing "0" as index/ID).
136 	*_decoder = decoderPlugin->NewDecoder(0);
137 	if (*_decoder == NULL) {
138 		printf("PluginManager::CreateDecoder: NewDecoder() failed\n");
139 		PutPlugin(plugin);
140 		return B_ERROR;
141 	}
142 	TRACE("  created decoder: %p\n", *_decoder);
143 	(*_decoder)->fMediaPlugin = plugin;
144 
145 	TRACE("PluginManager::CreateDecoder leave\n");
146 
147 	return B_OK;
148 }
149 
150 
151 status_t
152 PluginManager::CreateDecoder(Decoder** decoder, const media_codec_info& mci)
153 {
154 	TRACE("PluginManager::CreateDecoder enter\n");
155 	entry_ref ref;
156 	status_t status = AddOnManager::GetInstance()->GetEncoder(&ref, mci.id);
157 	if (status != B_OK)
158 		return status;
159 
160 	MediaPlugin* plugin = GetPlugin(ref);
161 	if (plugin == NULL) {
162 		ERROR("PluginManager::CreateDecoder: GetPlugin failed\n");
163 		return B_ERROR;
164 	}
165 
166 	DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin);
167 	if (decoderPlugin == NULL) {
168 		ERROR("PluginManager::CreateDecoder: dynamic_cast failed\n");
169 		PutPlugin(plugin);
170 		return B_ERROR;
171 	}
172 
173 	// TODO: In theory, one DecoderPlugin could support multiple Decoders,
174 	// but this is not yet handled (passing "0" as index/ID).
175 	*decoder = decoderPlugin->NewDecoder(0);
176 	if (*decoder == NULL) {
177 		ERROR("PluginManager::CreateDecoder: NewDecoder() failed\n");
178 		PutPlugin(plugin);
179 		return B_ERROR;
180 	}
181 	TRACE("  created decoder: %p\n", *decoder);
182 	(*decoder)->fMediaPlugin = plugin;
183 
184 	TRACE("PluginManager::CreateDecoder leave\n");
185 
186 	return B_OK;
187 
188 }
189 
190 
191 status_t
192 PluginManager::GetDecoderInfo(Decoder* decoder, media_codec_info* _info) const
193 {
194 	if (decoder == NULL)
195 		return B_BAD_VALUE;
196 
197 	decoder->GetCodecInfo(_info);
198 	// TODO:
199 	// out_info->id =
200 	// out_info->sub_id =
201 	return B_OK;
202 }
203 
204 
205 void
206 PluginManager::DestroyDecoder(Decoder* decoder)
207 {
208 	if (decoder != NULL) {
209 		TRACE("PluginManager::DestroyDecoder(%p, plugin: %p)\n", decoder,
210 			decoder->fMediaPlugin);
211 		// NOTE: We have to put the plug-in after deleting the decoder,
212 		// since otherwise we may actually unload the code for the
213 		// destructor...
214 		MediaPlugin* plugin = decoder->fMediaPlugin;
215 		delete decoder;
216 		PutPlugin(plugin);
217 	}
218 }
219 
220 
221 // #pragma mark - Writers/Encoders
222 
223 
224 status_t
225 PluginManager::CreateWriter(Writer** writer, const media_file_format& mff,
226 	BDataIO* target)
227 {
228 	TRACE("PluginManager::CreateWriter enter\n");
229 
230 	// Get the Writer responsible for this media_file_format from the server.
231 	entry_ref ref;
232 	status_t ret = AddOnManager::GetInstance()->GetWriter(&ref,
233 		mff.id.internal_id);
234 	if (ret != B_OK) {
235 		printf("PluginManager::CreateWriter: can't get writer for file "
236 			"family: %s\n", strerror(ret));
237 		return ret;
238 	}
239 
240 	MediaPlugin* plugin = GetPlugin(ref);
241 	if (plugin == NULL) {
242 		printf("PluginManager::CreateWriter: GetPlugin failed\n");
243 		return B_ERROR;
244 	}
245 
246 	WriterPlugin* writerPlugin = dynamic_cast<WriterPlugin*>(plugin);
247 	if (writerPlugin == NULL) {
248 		printf("PluginManager::CreateWriter: dynamic_cast failed\n");
249 		PutPlugin(plugin);
250 		return B_ERROR;
251 	}
252 
253 	*writer = writerPlugin->NewWriter();
254 	if (*writer == NULL) {
255 		printf("PluginManager::CreateWriter: NewWriter failed\n");
256 		PutPlugin(plugin);
257 		return B_ERROR;
258 	}
259 
260 	(*writer)->Setup(target);
261 	(*writer)->fMediaPlugin = plugin;
262 
263 	TRACE("PluginManager::CreateWriter leave\n");
264 	return B_OK;
265 }
266 
267 
268 void
269 PluginManager::DestroyWriter(Writer* writer)
270 {
271 	if (writer != NULL) {
272 		TRACE("PluginManager::DestroyWriter(%p (plugin: %p))\n", writer,
273 			writer->fMediaPlugin);
274 		// NOTE: We have to put the plug-in after deleting the writer,
275 		// since otherwise we may actually unload the code for the
276 		// destructor...
277 		MediaPlugin* plugin = writer->fMediaPlugin;
278 		delete writer;
279 		PutPlugin(plugin);
280 	}
281 }
282 
283 
284 status_t
285 PluginManager::CreateEncoder(Encoder** _encoder,
286 	const media_codec_info* codecInfo, uint32 flags)
287 {
288 	TRACE("PluginManager::CreateEncoder enter\n");
289 
290 	// Get encoder for this codec info from the server
291 	entry_ref ref;
292 	status_t ret = AddOnManager::GetInstance()->GetEncoder(&ref,
293 		codecInfo->id);
294 	if (ret != B_OK) {
295 		printf("PluginManager::CreateEncoder: can't get encoder for codec %s: "
296 			"%s\n", codecInfo->pretty_name, strerror(ret));
297 		return ret;
298 	}
299 
300 	MediaPlugin* plugin = GetPlugin(ref);
301 	if (!plugin) {
302 		printf("PluginManager::CreateEncoder: GetPlugin failed\n");
303 		return B_ERROR;
304 	}
305 
306 	EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin);
307 	if (encoderPlugin == NULL) {
308 		printf("PluginManager::CreateEncoder: dynamic_cast failed\n");
309 		PutPlugin(plugin);
310 		return B_ERROR;
311 	}
312 
313 	*_encoder = encoderPlugin->NewEncoder(*codecInfo);
314 	if (*_encoder == NULL) {
315 		printf("PluginManager::CreateEncoder: NewEncoder() failed\n");
316 		PutPlugin(plugin);
317 		return B_ERROR;
318 	}
319 	TRACE("  created encoder: %p\n", *_encoder);
320 	(*_encoder)->fMediaPlugin = plugin;
321 
322 	TRACE("PluginManager::CreateEncoder leave\n");
323 
324 	return B_OK;
325 }
326 
327 
328 status_t
329 PluginManager::CreateEncoder(Encoder** encoder, const media_format& format)
330 {
331 	TRACE("PluginManager::CreateEncoder enter nr2\n");
332 
333 	entry_ref ref;
334 
335 	status_t ret = AddOnManager::GetInstance()->GetEncoderForFormat(
336 		&ref, format);
337 
338 	if (ret != B_OK) {
339 		ERROR("PluginManager::CreateEncoder: can't get decoder for format: "
340 			"%s\n", strerror(ret));
341 		return ret;
342 	}
343 
344 	MediaPlugin* plugin = GetPlugin(ref);
345 	if (plugin == NULL) {
346 		ERROR("PluginManager::CreateEncoder: GetPlugin failed\n");
347 		return B_ERROR;
348 	}
349 
350 	EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin);
351 	if (encoderPlugin == NULL) {
352 		ERROR("PluginManager::CreateEncoder: dynamic_cast failed\n");
353 		PutPlugin(plugin);
354 		return B_ERROR;
355 	}
356 
357 
358 	*encoder = encoderPlugin->NewEncoder(format);
359 	if (*encoder == NULL) {
360 		ERROR("PluginManager::CreateEncoder: NewEncoder() failed\n");
361 		PutPlugin(plugin);
362 		return B_ERROR;
363 	}
364 	TRACE("  created encoder: %p\n", *encoder);
365 	(*encoder)->fMediaPlugin = plugin;
366 
367 	TRACE("PluginManager::CreateEncoder leave nr2\n");
368 
369 	return B_OK;
370 }
371 
372 
373 void
374 PluginManager::DestroyEncoder(Encoder* encoder)
375 {
376 	if (encoder != NULL) {
377 		TRACE("PluginManager::DestroyEncoder(%p, plugin: %p)\n", encoder,
378 			encoder->fMediaPlugin);
379 		// NOTE: We have to put the plug-in after deleting the encoder,
380 		// since otherwise we may actually unload the code for the
381 		// destructor...
382 		MediaPlugin* plugin = encoder->fMediaPlugin;
383 		delete encoder;
384 		PutPlugin(plugin);
385 	}
386 }
387 
388 
389 // #pragma mark -
390 
391 
392 PluginManager::PluginManager()
393 	:
394 	fPluginList(),
395 	fLocker("media plugin manager")
396 {
397 	CALLED();
398 }
399 
400 
401 PluginManager::~PluginManager()
402 {
403 	CALLED();
404 	for (int i = fPluginList.CountItems() - 1; i >= 0; i--) {
405 		plugin_info* info = NULL;
406 		fPluginList.Get(i, &info);
407 		TRACE("PluginManager: Error, unloading PlugIn %s with usecount "
408 			"%d\n", info->name, info->usecount);
409 		delete info->plugin;
410 		unload_add_on(info->image);
411 	}
412 }
413 
414 
415 MediaPlugin*
416 PluginManager::GetPlugin(const entry_ref& ref)
417 {
418 	TRACE("PluginManager::GetPlugin(%s)\n", ref.name);
419 	fLocker.Lock();
420 
421 	MediaPlugin* plugin;
422 	plugin_info* pinfo;
423 	plugin_info info;
424 
425 	for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) {
426 		if (0 == strcmp(ref.name, pinfo->name)) {
427 			plugin = pinfo->plugin;
428 			pinfo->usecount++;
429 			TRACE("  found existing plugin: %p\n", pinfo->plugin);
430 			fLocker.Unlock();
431 			return plugin;
432 		}
433 	}
434 
435 	if (_LoadPlugin(ref, &info.plugin, &info.image) < B_OK) {
436 		printf("PluginManager: Error, loading PlugIn %s failed\n", ref.name);
437 		fLocker.Unlock();
438 		return NULL;
439 	}
440 
441 	strcpy(info.name, ref.name);
442 	info.usecount = 1;
443 	fPluginList.Insert(info);
444 
445 	TRACE("PluginManager: PlugIn %s loaded\n", ref.name);
446 
447 	plugin = info.plugin;
448 	TRACE("  loaded plugin: %p\n", plugin);
449 
450 	fLocker.Unlock();
451 	return plugin;
452 }
453 
454 
455 void
456 PluginManager::PutPlugin(MediaPlugin* plugin)
457 {
458 	TRACE("PluginManager::PutPlugin()\n");
459 	fLocker.Lock();
460 
461 	plugin_info* pinfo;
462 
463 	for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) {
464 		if (plugin == pinfo->plugin) {
465 			pinfo->usecount--;
466 			if (pinfo->usecount == 0) {
467 				TRACE("  deleting %p\n", pinfo->plugin);
468 				delete pinfo->plugin;
469 				TRACE("  unloading add-on: %ld\n\n", pinfo->image);
470 				unload_add_on(pinfo->image);
471 				fPluginList.RemoveCurrent();
472 			}
473 			fLocker.Unlock();
474 			return;
475 		}
476 	}
477 
478 	printf("PluginManager: Error, can't put PlugIn %p\n", plugin);
479 
480 	fLocker.Unlock();
481 }
482 
483 
484 status_t
485 PluginManager::_LoadPlugin(const entry_ref& ref, MediaPlugin** plugin,
486 	image_id* image)
487 {
488 	BPath p(&ref);
489 
490 	TRACE("PluginManager: _LoadPlugin trying to load %s\n", p.Path());
491 
492 	image_id id;
493 	id = load_add_on(p.Path());
494 	if (id < 0) {
495 		printf("PluginManager: Error, load_add_on(): %s\n", strerror(id));
496 		return B_ERROR;
497 	}
498 
499 	MediaPlugin* (*instantiate_plugin_func)();
500 
501 	if (get_image_symbol(id, "instantiate_plugin", B_SYMBOL_TYPE_TEXT,
502 			(void**)&instantiate_plugin_func) < B_OK) {
503 		printf("PluginManager: Error, _LoadPlugin can't find "
504 			"instantiate_plugin in %s\n", p.Path());
505 		unload_add_on(id);
506 		return B_ERROR;
507 	}
508 
509 	MediaPlugin *pl;
510 
511 	pl = (*instantiate_plugin_func)();
512 	if (pl == NULL) {
513 		printf("PluginManager: Error, _LoadPlugin instantiate_plugin in %s "
514 			"returned NULL\n", p.Path());
515 		unload_add_on(id);
516 		return B_ERROR;
517 	}
518 
519 	*plugin = pl;
520 	*image = id;
521 	return B_OK;
522 }
523