xref: /haiku/src/kits/media/PluginManager.cpp (revision 05fc1277c47440dc36134816d70e5723c99cfcd2)
1 /*
2  * Copyright 2004-2010, Marcus Overhagen. All rights reserved.
3  * Copyright 2016, Dario Casalinuovo. All rights reserved.
4  * Distributed under the terms of the OpenBeOS License.
5  */
6 
7 
8 #include <AdapterIO.h>
9 #include <BufferIO.h>
10 #include <DataIO.h>
11 #include <image.h>
12 #include <Path.h>
13 
14 #include <string.h>
15 
16 #include "AddOnManager.h"
17 #include "PluginManager.h"
18 #include "DataExchange.h"
19 #include "debug.h"
20 
21 
22 PluginManager gPluginManager;
23 
24 #define BLOCK_SIZE 4096
25 #define MAX_STREAMERS 40
26 
27 
28 class DataIOAdapter : public BAdapterIO
29 {
30 public:
31 	DataIOAdapter(BDataIO* dataIO)
32 		:
33 		BAdapterIO(B_MEDIA_SEEK_BACKWARD | B_MEDIA_MUTABLE_SIZE,
34 			B_INFINITE_TIMEOUT),
35 		fDataIO(dataIO)
36 	{
37 		fDataInputAdapter = BuildInputAdapter();
38 	}
39 
40 	virtual	~DataIOAdapter()
41 	{
42 	}
43 
44 	virtual	ssize_t	ReadAt(off_t position, void* buffer,
45 		size_t size)
46 	{
47 		if (position == Position()) {
48 			ssize_t ret = fDataIO->Read(buffer, size);
49 			fDataInputAdapter->Write(buffer, ret);
50 			return ret;
51 		}
52 
53 		off_t totalSize = 0;
54 		if (GetSize(&totalSize) != B_OK)
55 			return B_UNSUPPORTED;
56 
57 		if (position+size < (size_t)totalSize)
58 			return ReadAt(position, buffer, size);
59 
60 		return B_NOT_SUPPORTED;
61 	}
62 
63 	virtual	ssize_t	WriteAt(off_t position, const void* buffer,
64 		size_t size)
65 	{
66 		if (position == Position()) {
67 			ssize_t ret = fDataIO->Write(buffer, size);
68 			fDataInputAdapter->Write(buffer, ret);
69 			return ret;
70 		}
71 
72 		return B_NOT_SUPPORTED;
73 	}
74 
75 private:
76 	BDataIO*		fDataIO;
77 	BInputAdapter*	fDataInputAdapter;
78 };
79 
80 
81 class BMediaIOWrapper : public BMediaIO
82 {
83 public:
84 	BMediaIOWrapper(BDataIO* source)
85 		:
86 		fData(NULL),
87 		fPosition(NULL),
88 		fMedia(NULL),
89 		fBufferIO(NULL),
90 		fDataIOAdapter(NULL),
91 		fErr(B_NO_ERROR)
92 	{
93 		CALLED();
94 
95 		fPosition = dynamic_cast<BPositionIO*>(source);
96 		fMedia = dynamic_cast<BMediaIO*>(source);
97 		fBufferIO = dynamic_cast<BBufferIO *>(source);
98 		fData = source;
99 
100 		// No need to do additional buffering if we have
101 		// a BBufferIO or a BMediaIO.
102 		if (!IsMedia() && fBufferIO == NULL) {
103 			// Source needs to be at least a BPositionIO to wrap with a BBufferIO
104 			if (IsPosition()) {
105 				fBufferIO = new(std::nothrow) BBufferIO(fPosition, 65536, false);
106 				if (fBufferIO == NULL) {
107 					fErr = B_NO_MEMORY;
108 					return;
109 				}
110 				// We have to reset our parents reference too
111 				fPosition = dynamic_cast<BPositionIO*>(fBufferIO);
112 				fData = dynamic_cast<BDataIO*>(fPosition);
113 			} else {
114 				// In this case we have to supply our own form
115 				// of pseudo-seekable object from a non-seekable
116 				// BDataIO.
117 				fDataIOAdapter = new DataIOAdapter(source);
118 				fMedia = dynamic_cast<BMediaIO*>(fDataIOAdapter);
119 				fPosition = dynamic_cast<BPositionIO*>(fDataIOAdapter);
120 				fData = dynamic_cast<BDataIO*>(fDataIOAdapter);
121 				TRACE("Unable to improve performance with a BufferIO\n");
122 			}
123 		}
124 
125 		if (IsMedia())
126 			fMedia->GetFlags(&fFlags);
127 		else if (IsPosition())
128 			fFlags = B_MEDIA_SEEKABLE;
129 	}
130 
131 	virtual	~BMediaIOWrapper()
132 	{
133 		if (fBufferIO != NULL)
134 			delete fBufferIO;
135 
136 		if (fDataIOAdapter != NULL)
137 			delete fDataIOAdapter;
138 	}
139 
140 	// BMediaIO interface
141 
142 	virtual void GetFlags(int32* flags) const
143 	{
144 		*flags = fFlags;
145 	}
146 
147 	// BPositionIO interface
148 
149 	virtual	ssize_t ReadAt(off_t position, void* buffer,
150 		size_t size)
151 	{
152 		CALLED();
153 
154 		return fPosition->ReadAt(position, buffer, size);
155 	}
156 
157 	virtual	ssize_t WriteAt(off_t position, const void* buffer,
158 		size_t size)
159 	{
160 		CALLED();
161 
162 		return fPosition->WriteAt(position, buffer, size);
163 	}
164 
165 	virtual	off_t Seek(off_t position, uint32 seekMode)
166 	{
167 		CALLED();
168 
169 		return fPosition->Seek(position, seekMode);
170 
171 	}
172 
173 	virtual off_t Position() const
174 	{
175 		CALLED();
176 
177 		return fPosition->Position();
178 	}
179 
180 	virtual	status_t SetSize(off_t size)
181 	{
182 		CALLED();
183 
184 		return fPosition->SetSize(size);
185 	}
186 
187 	virtual	status_t GetSize(off_t* size) const
188 	{
189 		CALLED();
190 
191 		return fPosition->GetSize(size);
192 	}
193 
194 	// Utility methods
195 
196 	status_t InitCheck() const
197 	{
198 		return fErr;
199 	}
200 
201 protected:
202 
203 	bool IsMedia() const
204 	{
205 		return fMedia != NULL;
206 	}
207 
208 	bool IsPosition() const
209 	{
210 		return fPosition != NULL;
211 	}
212 
213 private:
214 	BDataIO*			fData;
215 	BPositionIO*		fPosition;
216 	BMediaIO*			fMedia;
217 	BBufferIO*			fBufferIO;
218 	DataIOAdapter*		fDataIOAdapter;
219 
220 	int32				fFlags;
221 
222 	status_t			fErr;
223 };
224 
225 
226 // #pragma mark - Readers/Decoders
227 
228 
229 status_t
230 PluginManager::CreateReader(Reader** reader, int32* streamCount,
231 	media_file_format* mff, BDataIO* source)
232 {
233 	TRACE("PluginManager::CreateReader enter\n");
234 
235 	// The wrapper class will present our source in a more useful
236 	// way, we create an instance which is buffering our reads and
237 	// writes.
238 	BMediaIOWrapper* buffered_source = new BMediaIOWrapper(source);
239 	status_t ret = buffered_source->InitCheck();
240 	if (ret != B_OK)
241 		return ret;
242 
243 	// get list of available readers from the server
244 	entry_ref refs[MAX_READERS];
245 	int32 count;
246 
247 	ret = AddOnManager::GetInstance()->GetReaders(refs, &count,
248 		MAX_READERS);
249 	if (ret != B_OK) {
250 		printf("PluginManager::CreateReader: can't get list of readers: %s\n",
251 			strerror(ret));
252 		return ret;
253 	}
254 
255 	// try each reader by calling it's Sniff function...
256 	for (int32 i = 0; i < count; i++) {
257 		entry_ref ref = refs[i];
258 		MediaPlugin* plugin = GetPlugin(ref);
259 		if (plugin == NULL) {
260 			printf("PluginManager::CreateReader: GetPlugin failed\n");
261 			return B_ERROR;
262 		}
263 
264 		ReaderPlugin* readerPlugin = dynamic_cast<ReaderPlugin*>(plugin);
265 		if (readerPlugin == NULL) {
266 			printf("PluginManager::CreateReader: dynamic_cast failed\n");
267 			PutPlugin(plugin);
268 			return B_ERROR;
269 		}
270 
271 		*reader = readerPlugin->NewReader();
272 		if (*reader == NULL) {
273 			printf("PluginManager::CreateReader: NewReader failed\n");
274 			PutPlugin(plugin);
275 			return B_ERROR;
276 		}
277 
278 		buffered_source->Seek(0, SEEK_SET);
279 		(*reader)->Setup(buffered_source);
280 		(*reader)->fMediaPlugin = plugin;
281 
282 		if ((*reader)->Sniff(streamCount) == B_OK) {
283 			TRACE("PluginManager::CreateReader: Sniff success "
284 				"(%" B_PRId32 " stream(s))\n", *streamCount);
285 			(*reader)->GetFileFormatInfo(mff);
286 			return B_OK;
287 		}
288 
289 		DestroyReader(*reader);
290 		*reader = NULL;
291 	}
292 
293 	TRACE("PluginManager::CreateReader leave\n");
294 	return B_MEDIA_NO_HANDLER;
295 }
296 
297 
298 void
299 PluginManager::DestroyReader(Reader* reader)
300 {
301 	if (reader != NULL) {
302 		TRACE("PluginManager::DestroyReader(%p (plugin: %p))\n", reader,
303 			reader->fMediaPlugin);
304 		// NOTE: We have to put the plug-in after deleting the reader,
305 		// since otherwise we may actually unload the code for the
306 		// destructor...
307 		MediaPlugin* plugin = reader->fMediaPlugin;
308 		delete reader;
309 		PutPlugin(plugin);
310 	}
311 }
312 
313 
314 status_t
315 PluginManager::CreateDecoder(Decoder** _decoder, const media_format& format)
316 {
317 	TRACE("PluginManager::CreateDecoder enter\n");
318 
319 	// get decoder for this format
320 	entry_ref ref;
321 	status_t ret = AddOnManager::GetInstance()->GetDecoderForFormat(
322 		&ref, format);
323 	if (ret != B_OK) {
324 		printf("PluginManager::CreateDecoder: can't get decoder for format: "
325 			"%s\n", strerror(ret));
326 		return ret;
327 	}
328 
329 	MediaPlugin* plugin = GetPlugin(ref);
330 	if (plugin == NULL) {
331 		printf("PluginManager::CreateDecoder: GetPlugin failed\n");
332 		return B_ERROR;
333 	}
334 
335 	DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin);
336 	if (decoderPlugin == NULL) {
337 		printf("PluginManager::CreateDecoder: dynamic_cast failed\n");
338 		PutPlugin(plugin);
339 		return B_ERROR;
340 	}
341 
342 	// TODO: In theory, one DecoderPlugin could support multiple Decoders,
343 	// but this is not yet handled (passing "0" as index/ID).
344 	*_decoder = decoderPlugin->NewDecoder(0);
345 	if (*_decoder == NULL) {
346 		printf("PluginManager::CreateDecoder: NewDecoder() failed\n");
347 		PutPlugin(plugin);
348 		return B_ERROR;
349 	}
350 	TRACE("  created decoder: %p\n", *_decoder);
351 	(*_decoder)->fMediaPlugin = plugin;
352 
353 	TRACE("PluginManager::CreateDecoder leave\n");
354 
355 	return B_OK;
356 }
357 
358 
359 status_t
360 PluginManager::CreateDecoder(Decoder** decoder, const media_codec_info& mci)
361 {
362 	TRACE("PluginManager::CreateDecoder enter\n");
363 	entry_ref ref;
364 	status_t status = AddOnManager::GetInstance()->GetEncoder(&ref, mci.id);
365 	if (status != B_OK)
366 		return status;
367 
368 	MediaPlugin* plugin = GetPlugin(ref);
369 	if (plugin == NULL) {
370 		ERROR("PluginManager::CreateDecoder: GetPlugin failed\n");
371 		return B_ERROR;
372 	}
373 
374 	DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin);
375 	if (decoderPlugin == NULL) {
376 		ERROR("PluginManager::CreateDecoder: dynamic_cast failed\n");
377 		PutPlugin(plugin);
378 		return B_ERROR;
379 	}
380 
381 	// TODO: In theory, one DecoderPlugin could support multiple Decoders,
382 	// but this is not yet handled (passing "0" as index/ID).
383 	*decoder = decoderPlugin->NewDecoder(0);
384 	if (*decoder == NULL) {
385 		ERROR("PluginManager::CreateDecoder: NewDecoder() failed\n");
386 		PutPlugin(plugin);
387 		return B_ERROR;
388 	}
389 	TRACE("  created decoder: %p\n", *decoder);
390 	(*decoder)->fMediaPlugin = plugin;
391 
392 	TRACE("PluginManager::CreateDecoder leave\n");
393 
394 	return B_OK;
395 
396 }
397 
398 
399 status_t
400 PluginManager::GetDecoderInfo(Decoder* decoder, media_codec_info* _info) const
401 {
402 	if (decoder == NULL)
403 		return B_BAD_VALUE;
404 
405 	decoder->GetCodecInfo(_info);
406 	// TODO:
407 	// out_info->id =
408 	// out_info->sub_id =
409 	return B_OK;
410 }
411 
412 
413 void
414 PluginManager::DestroyDecoder(Decoder* decoder)
415 {
416 	if (decoder != NULL) {
417 		TRACE("PluginManager::DestroyDecoder(%p, plugin: %p)\n", decoder,
418 			decoder->fMediaPlugin);
419 		// NOTE: We have to put the plug-in after deleting the decoder,
420 		// since otherwise we may actually unload the code for the
421 		// destructor...
422 		MediaPlugin* plugin = decoder->fMediaPlugin;
423 		delete decoder;
424 		PutPlugin(plugin);
425 	}
426 }
427 
428 
429 // #pragma mark - Writers/Encoders
430 
431 
432 status_t
433 PluginManager::CreateWriter(Writer** writer, const media_file_format& mff,
434 	BDataIO* target)
435 {
436 	TRACE("PluginManager::CreateWriter enter\n");
437 
438 	// Get the Writer responsible for this media_file_format from the server.
439 	entry_ref ref;
440 	status_t ret = AddOnManager::GetInstance()->GetWriter(&ref,
441 		mff.id.internal_id);
442 	if (ret != B_OK) {
443 		printf("PluginManager::CreateWriter: can't get writer for file "
444 			"family: %s\n", strerror(ret));
445 		return ret;
446 	}
447 
448 	MediaPlugin* plugin = GetPlugin(ref);
449 	if (plugin == NULL) {
450 		printf("PluginManager::CreateWriter: GetPlugin failed\n");
451 		return B_ERROR;
452 	}
453 
454 	WriterPlugin* writerPlugin = dynamic_cast<WriterPlugin*>(plugin);
455 	if (writerPlugin == NULL) {
456 		printf("PluginManager::CreateWriter: dynamic_cast failed\n");
457 		PutPlugin(plugin);
458 		return B_ERROR;
459 	}
460 
461 	*writer = writerPlugin->NewWriter();
462 	if (*writer == NULL) {
463 		printf("PluginManager::CreateWriter: NewWriter failed\n");
464 		PutPlugin(plugin);
465 		return B_ERROR;
466 	}
467 
468 	(*writer)->Setup(target);
469 	(*writer)->fMediaPlugin = plugin;
470 
471 	TRACE("PluginManager::CreateWriter leave\n");
472 	return B_OK;
473 }
474 
475 
476 void
477 PluginManager::DestroyWriter(Writer* writer)
478 {
479 	if (writer != NULL) {
480 		TRACE("PluginManager::DestroyWriter(%p (plugin: %p))\n", writer,
481 			writer->fMediaPlugin);
482 		// NOTE: We have to put the plug-in after deleting the writer,
483 		// since otherwise we may actually unload the code for the
484 		// destructor...
485 		MediaPlugin* plugin = writer->fMediaPlugin;
486 		delete writer;
487 		PutPlugin(plugin);
488 	}
489 }
490 
491 
492 status_t
493 PluginManager::CreateEncoder(Encoder** _encoder,
494 	const media_codec_info* codecInfo, uint32 flags)
495 {
496 	TRACE("PluginManager::CreateEncoder enter\n");
497 
498 	// Get encoder for this codec info from the server
499 	entry_ref ref;
500 	status_t ret = AddOnManager::GetInstance()->GetEncoder(&ref,
501 		codecInfo->id);
502 	if (ret != B_OK) {
503 		printf("PluginManager::CreateEncoder: can't get encoder for codec %s: "
504 			"%s\n", codecInfo->pretty_name, strerror(ret));
505 		return ret;
506 	}
507 
508 	MediaPlugin* plugin = GetPlugin(ref);
509 	if (!plugin) {
510 		printf("PluginManager::CreateEncoder: GetPlugin failed\n");
511 		return B_ERROR;
512 	}
513 
514 	EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin);
515 	if (encoderPlugin == NULL) {
516 		printf("PluginManager::CreateEncoder: dynamic_cast failed\n");
517 		PutPlugin(plugin);
518 		return B_ERROR;
519 	}
520 
521 	*_encoder = encoderPlugin->NewEncoder(*codecInfo);
522 	if (*_encoder == NULL) {
523 		printf("PluginManager::CreateEncoder: NewEncoder() failed\n");
524 		PutPlugin(plugin);
525 		return B_ERROR;
526 	}
527 	TRACE("  created encoder: %p\n", *_encoder);
528 	(*_encoder)->fMediaPlugin = plugin;
529 
530 	TRACE("PluginManager::CreateEncoder leave\n");
531 
532 	return B_OK;
533 }
534 
535 
536 status_t
537 PluginManager::CreateEncoder(Encoder** encoder, const media_format& format)
538 {
539 	TRACE("PluginManager::CreateEncoder enter nr2\n");
540 
541 	entry_ref ref;
542 
543 	status_t ret = AddOnManager::GetInstance()->GetEncoderForFormat(
544 		&ref, format);
545 
546 	if (ret != B_OK) {
547 		ERROR("PluginManager::CreateEncoder: can't get decoder for format: "
548 			"%s\n", strerror(ret));
549 		return ret;
550 	}
551 
552 	MediaPlugin* plugin = GetPlugin(ref);
553 	if (plugin == NULL) {
554 		ERROR("PluginManager::CreateEncoder: GetPlugin failed\n");
555 		return B_ERROR;
556 	}
557 
558 	EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin);
559 	if (encoderPlugin == NULL) {
560 		ERROR("PluginManager::CreateEncoder: dynamic_cast failed\n");
561 		PutPlugin(plugin);
562 		return B_ERROR;
563 	}
564 
565 
566 	*encoder = encoderPlugin->NewEncoder(format);
567 	if (*encoder == NULL) {
568 		ERROR("PluginManager::CreateEncoder: NewEncoder() failed\n");
569 		PutPlugin(plugin);
570 		return B_ERROR;
571 	}
572 	TRACE("  created encoder: %p\n", *encoder);
573 	(*encoder)->fMediaPlugin = plugin;
574 
575 	TRACE("PluginManager::CreateEncoder leave nr2\n");
576 
577 	return B_OK;
578 }
579 
580 
581 void
582 PluginManager::DestroyEncoder(Encoder* encoder)
583 {
584 	if (encoder != NULL) {
585 		TRACE("PluginManager::DestroyEncoder(%p, plugin: %p)\n", encoder,
586 			encoder->fMediaPlugin);
587 		// NOTE: We have to put the plug-in after deleting the encoder,
588 		// since otherwise we may actually unload the code for the
589 		// destructor...
590 		MediaPlugin* plugin = encoder->fMediaPlugin;
591 		delete encoder;
592 		PutPlugin(plugin);
593 	}
594 }
595 
596 
597 status_t
598 PluginManager::CreateStreamer(Streamer** streamer, BUrl url, BDataIO** source)
599 {
600 	TRACE("PluginManager::CreateStreamer enter\n");
601 
602 	entry_ref refs[MAX_STREAMERS];
603 	int32 count;
604 
605 	status_t ret = AddOnManager::GetInstance()->GetStreamers(refs, &count,
606 		MAX_STREAMERS);
607 	if (ret != B_OK) {
608 		printf("PluginManager::CreateStreamer: can't get list of streamers:"
609 			" %s\n", strerror(ret));
610 		return ret;
611 	}
612 
613 	// try each reader by calling it's Sniff function...
614 	for (int32 i = 0; i < count; i++) {
615 		entry_ref ref = refs[i];
616 		MediaPlugin* plugin = GetPlugin(ref);
617 		if (plugin == NULL) {
618 			printf("PluginManager::CreateStreamer: GetPlugin failed\n");
619 			return B_ERROR;
620 		}
621 
622 		StreamerPlugin* streamerPlugin = dynamic_cast<StreamerPlugin*>(plugin);
623 		if (streamerPlugin == NULL) {
624 			printf("PluginManager::CreateStreamer: dynamic_cast failed\n");
625 			PutPlugin(plugin);
626 			return B_ERROR;
627 		}
628 
629 		*streamer = streamerPlugin->NewStreamer();
630 		if (*streamer == NULL) {
631 			printf("PluginManager::CreateStreamer: NewReader failed\n");
632 			PutPlugin(plugin);
633 			return B_ERROR;
634 		}
635 
636 		(*streamer)->fMediaPlugin = plugin;
637 
638 		BDataIO* streamSource = NULL;
639 		if ((*streamer)->Sniff(url, &streamSource) == B_OK) {
640 			TRACE("PluginManager::CreateStreamer: Sniff success\n");
641 			*source = streamSource;
642 			return B_OK;
643 		}
644 
645 		DestroyStreamer(*streamer);
646 		*streamer = NULL;
647 	}
648 
649 	TRACE("PluginManager::CreateStreamer leave\n");
650 	return B_MEDIA_NO_HANDLER;
651 }
652 
653 
654 void
655 PluginManager::DestroyStreamer(Streamer* streamer)
656 {
657 	if (streamer != NULL) {
658 		TRACE("PluginManager::DestroyStreamer(%p, plugin: %p)\n", streamer,
659 			streamer->fMediaPlugin);
660 		// NOTE: We have to put the plug-in after deleting the encoder,
661 		// since otherwise we may actually unload the code for the
662 		// destructor...
663 		MediaPlugin* plugin = streamer->fMediaPlugin;
664 		delete streamer;
665 		PutPlugin(plugin);
666 	}
667 }
668 
669 
670 // #pragma mark -
671 
672 
673 PluginManager::PluginManager()
674 	:
675 	fPluginList(),
676 	fLocker("media plugin manager")
677 {
678 	CALLED();
679 }
680 
681 
682 PluginManager::~PluginManager()
683 {
684 	CALLED();
685 	for (int i = fPluginList.CountItems() - 1; i >= 0; i--) {
686 		plugin_info* info = NULL;
687 		fPluginList.Get(i, &info);
688 		TRACE("PluginManager: Error, unloading PlugIn %s with usecount "
689 			"%d\n", info->name, info->usecount);
690 		delete info->plugin;
691 		unload_add_on(info->image);
692 	}
693 }
694 
695 
696 MediaPlugin*
697 PluginManager::GetPlugin(const entry_ref& ref)
698 {
699 	TRACE("PluginManager::GetPlugin(%s)\n", ref.name);
700 	fLocker.Lock();
701 
702 	MediaPlugin* plugin;
703 	plugin_info* pinfo;
704 	plugin_info info;
705 
706 	for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) {
707 		if (0 == strcmp(ref.name, pinfo->name)) {
708 			plugin = pinfo->plugin;
709 			pinfo->usecount++;
710 			TRACE("  found existing plugin: %p\n", pinfo->plugin);
711 			fLocker.Unlock();
712 			return plugin;
713 		}
714 	}
715 
716 	if (_LoadPlugin(ref, &info.plugin, &info.image) < B_OK) {
717 		printf("PluginManager: Error, loading PlugIn %s failed\n", ref.name);
718 		fLocker.Unlock();
719 		return NULL;
720 	}
721 
722 	strcpy(info.name, ref.name);
723 	info.usecount = 1;
724 	fPluginList.Insert(info);
725 
726 	TRACE("PluginManager: PlugIn %s loaded\n", ref.name);
727 
728 	plugin = info.plugin;
729 	TRACE("  loaded plugin: %p\n", plugin);
730 
731 	fLocker.Unlock();
732 	return plugin;
733 }
734 
735 
736 void
737 PluginManager::PutPlugin(MediaPlugin* plugin)
738 {
739 	TRACE("PluginManager::PutPlugin()\n");
740 	fLocker.Lock();
741 
742 	plugin_info* pinfo;
743 
744 	for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) {
745 		if (plugin == pinfo->plugin) {
746 			pinfo->usecount--;
747 			if (pinfo->usecount == 0) {
748 				TRACE("  deleting %p\n", pinfo->plugin);
749 				delete pinfo->plugin;
750 				TRACE("  unloading add-on: %" B_PRId32 "\n\n", pinfo->image);
751 				unload_add_on(pinfo->image);
752 				fPluginList.RemoveCurrent();
753 			}
754 			fLocker.Unlock();
755 			return;
756 		}
757 	}
758 
759 	printf("PluginManager: Error, can't put PlugIn %p\n", plugin);
760 
761 	fLocker.Unlock();
762 }
763 
764 
765 status_t
766 PluginManager::_LoadPlugin(const entry_ref& ref, MediaPlugin** plugin,
767 	image_id* image)
768 {
769 	BPath p(&ref);
770 
771 	TRACE("PluginManager: _LoadPlugin trying to load %s\n", p.Path());
772 
773 	image_id id;
774 	id = load_add_on(p.Path());
775 	if (id < 0) {
776 		printf("PluginManager: Error, load_add_on(): %s\n", strerror(id));
777 		return B_ERROR;
778 	}
779 
780 	MediaPlugin* (*instantiate_plugin_func)();
781 
782 	if (get_image_symbol(id, "instantiate_plugin", B_SYMBOL_TYPE_TEXT,
783 			(void**)&instantiate_plugin_func) < B_OK) {
784 		printf("PluginManager: Error, _LoadPlugin can't find "
785 			"instantiate_plugin in %s\n", p.Path());
786 		unload_add_on(id);
787 		return B_ERROR;
788 	}
789 
790 	MediaPlugin *pl;
791 
792 	pl = (*instantiate_plugin_func)();
793 	if (pl == NULL) {
794 		printf("PluginManager: Error, _LoadPlugin instantiate_plugin in %s "
795 			"returned NULL\n", p.Path());
796 		unload_add_on(id);
797 		return B_ERROR;
798 	}
799 
800 	*plugin = pl;
801 	*image = id;
802 	return B_OK;
803 }
804