2 * Copyright 2004-2010, Marcus Overhagen. All rights reserved.
3 * Copyright 2016, Dario Casalinuovo. All rights reserved.
4 * Distributed under the terms of the MIT License.
9 #include <AutoDeleter.h>
18 #include "AddOnManager.h"
19 #include "PluginManager.h"
20 #include "DataExchange.h"
24 PluginManager gPluginManager
;
26 #define BLOCK_SIZE 4096
27 #define MAX_STREAMERS 40
30 class DataIOAdapter
: public BAdapterIO
{
32 DataIOAdapter(BDataIO
* dataIO
)
34 BAdapterIO(B_MEDIA_SEEK_BACKWARD
| B_MEDIA_MUTABLE_SIZE
,
38 fDataInputAdapter
= BuildInputAdapter();
41 virtual ~DataIOAdapter()
45 virtual ssize_t
ReadAt(off_t position
, void* buffer
,
48 if (position
== Position()) {
49 ssize_t ret
= fDataIO
->Read(buffer
, size
);
50 fDataInputAdapter
->Write(buffer
, ret
);
55 if (GetSize(&totalSize
) != B_OK
)
58 if (position
+size
< (size_t)totalSize
)
59 return ReadAt(position
, buffer
, size
);
61 return B_NOT_SUPPORTED
;
64 virtual ssize_t
WriteAt(off_t position
, const void* buffer
,
67 if (position
== Position()) {
68 ssize_t ret
= fDataIO
->Write(buffer
, size
);
69 fDataInputAdapter
->Write(buffer
, ret
);
73 return B_NOT_SUPPORTED
;
78 BInputAdapter
* fDataInputAdapter
;
82 class BMediaIOWrapper
: public BMediaIO
{
84 BMediaIOWrapper(BDataIO
* source
)
95 fPosition
= dynamic_cast<BPositionIO
*>(source
);
96 fMedia
= dynamic_cast<BMediaIO
*>(source
);
97 fBufferIO
= dynamic_cast<BBufferIO
*>(source
);
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
105 fBufferIO
= new(std::nothrow
) BBufferIO(fPosition
, 65536, false);
106 if (fBufferIO
== NULL
) {
110 // We have to reset our parents reference too
111 fPosition
= dynamic_cast<BPositionIO
*>(fBufferIO
);
112 fData
= dynamic_cast<BDataIO
*>(fPosition
);
114 // In this case we have to supply our own form
115 // of pseudo-seekable object from a non-seekable
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");
126 fMedia
->GetFlags(&fFlags
);
127 else if (IsPosition())
128 fFlags
= B_MEDIA_SEEKABLE
;
131 virtual ~BMediaIOWrapper()
133 if (fBufferIO
!= NULL
)
136 if (fDataIOAdapter
!= NULL
)
137 delete fDataIOAdapter
;
140 status_t
InitCheck() const
145 // BMediaIO interface
147 virtual void GetFlags(int32
* flags
) const
152 // BPositionIO interface
154 virtual ssize_t
ReadAt(off_t position
, void* buffer
,
159 return fPosition
->ReadAt(position
, buffer
, size
);
162 virtual ssize_t
WriteAt(off_t position
, const void* buffer
,
167 return fPosition
->WriteAt(position
, buffer
, size
);
170 virtual off_t
Seek(off_t position
, uint32 seekMode
)
174 return fPosition
->Seek(position
, seekMode
);
178 virtual off_t
Position() const
182 return fPosition
->Position();
185 virtual status_t
SetSize(off_t size
)
189 return fPosition
->SetSize(size
);
192 virtual status_t
GetSize(off_t
* size
) const
196 return fPosition
->GetSize(size
);
203 return fMedia
!= NULL
;
206 bool IsPosition() const
208 return fPosition
!= NULL
;
213 BPositionIO
* fPosition
;
215 BBufferIO
* fBufferIO
;
216 DataIOAdapter
* fDataIOAdapter
;
224 // #pragma mark - Readers/Decoders
228 PluginManager::CreateReader(Reader
** reader
, int32
* streamCount
,
229 media_file_format
* mff
, BDataIO
* source
)
231 TRACE("PluginManager::CreateReader enter\n");
233 // The wrapper class will present our source in a more useful
234 // way, we create an instance which is buffering our reads and
236 BMediaIOWrapper
* buffered_source
= new BMediaIOWrapper(source
);
237 ObjectDeleter
<BMediaIOWrapper
> ioDeleter(buffered_source
);
239 status_t ret
= buffered_source
->InitCheck();
243 // get list of available readers from the server
244 entry_ref refs
[MAX_READERS
];
247 ret
= AddOnManager::GetInstance()->GetReaders(refs
, &count
,
250 printf("PluginManager::CreateReader: can't get list of readers: %s\n",
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");
264 ReaderPlugin
* readerPlugin
= dynamic_cast<ReaderPlugin
*>(plugin
);
265 if (readerPlugin
== NULL
) {
266 printf("PluginManager::CreateReader: dynamic_cast failed\n");
271 *reader
= readerPlugin
->NewReader();
272 if (*reader
== NULL
) {
273 printf("PluginManager::CreateReader: NewReader failed\n");
278 buffered_source
->Seek(0, SEEK_SET
);
279 (*reader
)->Setup(buffered_source
);
280 (*reader
)->fMediaPlugin
= plugin
;
282 if ((*reader
)->Sniff(streamCount
) == B_OK
) {
283 TRACE("PluginManager::CreateReader: Sniff success "
284 "(%" B_PRId32
" stream(s))\n", *streamCount
);
285 (*reader
)->GetFileFormatInfo(mff
);
290 DestroyReader(*reader
);
294 TRACE("PluginManager::CreateReader leave\n");
295 return B_MEDIA_NO_HANDLER
;
300 PluginManager::DestroyReader(Reader
* reader
)
302 if (reader
!= NULL
) {
303 TRACE("PluginManager::DestroyReader(%p (plugin: %p))\n", reader
,
304 reader
->fMediaPlugin
);
305 // NOTE: We have to put the plug-in after deleting the reader,
306 // since otherwise we may actually unload the code for the
308 MediaPlugin
* plugin
= reader
->fMediaPlugin
;
316 PluginManager::CreateDecoder(Decoder
** _decoder
, const media_format
& format
)
318 TRACE("PluginManager::CreateDecoder enter\n");
320 // get decoder for this format
322 status_t ret
= AddOnManager::GetInstance()->GetDecoderForFormat(
325 printf("PluginManager::CreateDecoder: can't get decoder for format: "
326 "%s\n", strerror(ret
));
330 MediaPlugin
* plugin
= GetPlugin(ref
);
331 if (plugin
== NULL
) {
332 printf("PluginManager::CreateDecoder: GetPlugin failed\n");
336 DecoderPlugin
* decoderPlugin
= dynamic_cast<DecoderPlugin
*>(plugin
);
337 if (decoderPlugin
== NULL
) {
338 printf("PluginManager::CreateDecoder: dynamic_cast failed\n");
343 // TODO: In theory, one DecoderPlugin could support multiple Decoders,
344 // but this is not yet handled (passing "0" as index/ID).
345 *_decoder
= decoderPlugin
->NewDecoder(0);
346 if (*_decoder
== NULL
) {
347 printf("PluginManager::CreateDecoder: NewDecoder() failed\n");
351 TRACE(" created decoder: %p\n", *_decoder
);
352 (*_decoder
)->fMediaPlugin
= plugin
;
354 TRACE("PluginManager::CreateDecoder leave\n");
361 PluginManager::CreateDecoder(Decoder
** decoder
, const media_codec_info
& mci
)
363 TRACE("PluginManager::CreateDecoder enter\n");
365 status_t status
= AddOnManager::GetInstance()->GetEncoder(&ref
, mci
.id
);
369 MediaPlugin
* plugin
= GetPlugin(ref
);
370 if (plugin
== NULL
) {
371 ERROR("PluginManager::CreateDecoder: GetPlugin failed\n");
375 DecoderPlugin
* decoderPlugin
= dynamic_cast<DecoderPlugin
*>(plugin
);
376 if (decoderPlugin
== NULL
) {
377 ERROR("PluginManager::CreateDecoder: dynamic_cast failed\n");
382 // TODO: In theory, one DecoderPlugin could support multiple Decoders,
383 // but this is not yet handled (passing "0" as index/ID).
384 *decoder
= decoderPlugin
->NewDecoder(0);
385 if (*decoder
== NULL
) {
386 ERROR("PluginManager::CreateDecoder: NewDecoder() failed\n");
390 TRACE(" created decoder: %p\n", *decoder
);
391 (*decoder
)->fMediaPlugin
= plugin
;
393 TRACE("PluginManager::CreateDecoder leave\n");
401 PluginManager::GetDecoderInfo(Decoder
* decoder
, media_codec_info
* _info
) const
406 decoder
->GetCodecInfo(_info
);
409 // out_info->sub_id =
415 PluginManager::DestroyDecoder(Decoder
* decoder
)
417 if (decoder
!= NULL
) {
418 TRACE("PluginManager::DestroyDecoder(%p, plugin: %p)\n", decoder
,
419 decoder
->fMediaPlugin
);
420 // NOTE: We have to put the plug-in after deleting the decoder,
421 // since otherwise we may actually unload the code for the
423 MediaPlugin
* plugin
= decoder
->fMediaPlugin
;
430 // #pragma mark - Writers/Encoders
434 PluginManager::CreateWriter(Writer
** writer
, const media_file_format
& mff
,
437 TRACE("PluginManager::CreateWriter enter\n");
439 // Get the Writer responsible for this media_file_format from the server.
441 status_t ret
= AddOnManager::GetInstance()->GetWriter(&ref
,
444 printf("PluginManager::CreateWriter: can't get writer for file "
445 "family: %s\n", strerror(ret
));
449 MediaPlugin
* plugin
= GetPlugin(ref
);
450 if (plugin
== NULL
) {
451 printf("PluginManager::CreateWriter: GetPlugin failed\n");
455 WriterPlugin
* writerPlugin
= dynamic_cast<WriterPlugin
*>(plugin
);
456 if (writerPlugin
== NULL
) {
457 printf("PluginManager::CreateWriter: dynamic_cast failed\n");
462 *writer
= writerPlugin
->NewWriter();
463 if (*writer
== NULL
) {
464 printf("PluginManager::CreateWriter: NewWriter failed\n");
469 (*writer
)->Setup(target
);
470 (*writer
)->fMediaPlugin
= plugin
;
472 TRACE("PluginManager::CreateWriter leave\n");
478 PluginManager::DestroyWriter(Writer
* writer
)
480 if (writer
!= NULL
) {
481 TRACE("PluginManager::DestroyWriter(%p (plugin: %p))\n", writer
,
482 writer
->fMediaPlugin
);
483 // NOTE: We have to put the plug-in after deleting the writer,
484 // since otherwise we may actually unload the code for the
486 MediaPlugin
* plugin
= writer
->fMediaPlugin
;
494 PluginManager::CreateEncoder(Encoder
** _encoder
,
495 const media_codec_info
* codecInfo
, uint32 flags
)
497 TRACE("PluginManager::CreateEncoder enter\n");
499 // Get encoder for this codec info from the server
501 status_t ret
= AddOnManager::GetInstance()->GetEncoder(&ref
,
504 printf("PluginManager::CreateEncoder: can't get encoder for codec %s: "
505 "%s\n", codecInfo
->pretty_name
, strerror(ret
));
509 MediaPlugin
* plugin
= GetPlugin(ref
);
511 printf("PluginManager::CreateEncoder: GetPlugin failed\n");
515 EncoderPlugin
* encoderPlugin
= dynamic_cast<EncoderPlugin
*>(plugin
);
516 if (encoderPlugin
== NULL
) {
517 printf("PluginManager::CreateEncoder: dynamic_cast failed\n");
522 *_encoder
= encoderPlugin
->NewEncoder(*codecInfo
);
523 if (*_encoder
== NULL
) {
524 printf("PluginManager::CreateEncoder: NewEncoder() failed\n");
528 TRACE(" created encoder: %p\n", *_encoder
);
529 (*_encoder
)->fMediaPlugin
= plugin
;
531 TRACE("PluginManager::CreateEncoder leave\n");
538 PluginManager::CreateEncoder(Encoder
** encoder
, const media_format
& format
)
540 TRACE("PluginManager::CreateEncoder enter nr2\n");
544 status_t ret
= AddOnManager::GetInstance()->GetEncoderForFormat(
548 ERROR("PluginManager::CreateEncoder: can't get decoder for format: "
549 "%s\n", strerror(ret
));
553 MediaPlugin
* plugin
= GetPlugin(ref
);
554 if (plugin
== NULL
) {
555 ERROR("PluginManager::CreateEncoder: GetPlugin failed\n");
559 EncoderPlugin
* encoderPlugin
= dynamic_cast<EncoderPlugin
*>(plugin
);
560 if (encoderPlugin
== NULL
) {
561 ERROR("PluginManager::CreateEncoder: dynamic_cast failed\n");
567 *encoder
= encoderPlugin
->NewEncoder(format
);
568 if (*encoder
== NULL
) {
569 ERROR("PluginManager::CreateEncoder: NewEncoder() failed\n");
573 TRACE(" created encoder: %p\n", *encoder
);
574 (*encoder
)->fMediaPlugin
= plugin
;
576 TRACE("PluginManager::CreateEncoder leave nr2\n");
583 PluginManager::DestroyEncoder(Encoder
* encoder
)
585 if (encoder
!= NULL
) {
586 TRACE("PluginManager::DestroyEncoder(%p, plugin: %p)\n", encoder
,
587 encoder
->fMediaPlugin
);
588 // NOTE: We have to put the plug-in after deleting the encoder,
589 // since otherwise we may actually unload the code for the
591 MediaPlugin
* plugin
= encoder
->fMediaPlugin
;
599 PluginManager::CreateStreamer(Streamer
** streamer
, BUrl url
, BDataIO
** source
)
601 BAutolock
_(fLocker
);
603 TRACE("PluginManager::CreateStreamer enter\n");
605 entry_ref refs
[MAX_STREAMERS
];
608 status_t ret
= AddOnManager::GetInstance()->GetStreamers(refs
, &count
,
611 printf("PluginManager::CreateStreamer: can't get list of streamers:"
612 " %s\n", strerror(ret
));
616 // try each reader by calling it's Sniff function...
617 for (int32 i
= 0; i
< count
; i
++) {
618 entry_ref ref
= refs
[i
];
619 MediaPlugin
* plugin
= GetPlugin(ref
);
620 if (plugin
== NULL
) {
621 printf("PluginManager::CreateStreamer: GetPlugin failed\n");
625 StreamerPlugin
* streamerPlugin
= dynamic_cast<StreamerPlugin
*>(plugin
);
626 if (streamerPlugin
== NULL
) {
627 printf("PluginManager::CreateStreamer: dynamic_cast failed\n");
632 *streamer
= streamerPlugin
->NewStreamer();
633 if (*streamer
== NULL
) {
634 printf("PluginManager::CreateStreamer: NewReader failed\n");
639 (*streamer
)->fMediaPlugin
= plugin
;
642 BDataIO
* streamSource
= NULL
;
643 if ((*streamer
)->Sniff(url
, &streamSource
) == B_OK
) {
644 TRACE("PluginManager::CreateStreamer: Sniff success\n");
645 *source
= streamSource
;
649 DestroyStreamer(*streamer
);
653 TRACE("PluginManager::CreateStreamer leave\n");
654 return B_MEDIA_NO_HANDLER
;
659 PluginManager::DestroyStreamer(Streamer
* streamer
)
661 BAutolock
_(fLocker
);
663 if (streamer
!= NULL
) {
664 TRACE("PluginManager::DestroyStreamer(%p, plugin: %p)\n", streamer
,
665 streamer
->fMediaPlugin
);
667 // NOTE: We have to put the plug-in after deleting the streamer,
668 // since otherwise we may actually unload the code for the
670 MediaPlugin
* plugin
= streamer
->fMediaPlugin
;
673 // Delete the plugin only when every reference is released
674 if (plugin
->fRefCount
== 1) {
675 plugin
->fRefCount
= 0;
686 PluginManager::PluginManager()
689 fLocker("media plugin manager")
695 PluginManager::~PluginManager()
698 for (int i
= fPluginList
.CountItems() - 1; i
>= 0; i
--) {
699 plugin_info
* info
= NULL
;
700 fPluginList
.Get(i
, &info
);
701 TRACE("PluginManager: Error, unloading PlugIn %s with usecount "
702 "%d\n", info
->name
, info
->usecount
);
704 unload_add_on(info
->image
);
710 PluginManager::GetPlugin(const entry_ref
& ref
)
712 TRACE("PluginManager::GetPlugin(%s)\n", ref
.name
);
719 for (fPluginList
.Rewind(); fPluginList
.GetNext(&pinfo
); ) {
720 if (0 == strcmp(ref
.name
, pinfo
->name
)) {
721 plugin
= pinfo
->plugin
;
723 TRACE(" found existing plugin: %p\n", pinfo
->plugin
);
729 if (_LoadPlugin(ref
, &info
.plugin
, &info
.image
) < B_OK
) {
730 printf("PluginManager: Error, loading PlugIn %s failed\n", ref
.name
);
735 strcpy(info
.name
, ref
.name
);
737 fPluginList
.Insert(info
);
739 TRACE("PluginManager: PlugIn %s loaded\n", ref
.name
);
741 plugin
= info
.plugin
;
742 TRACE(" loaded plugin: %p\n", plugin
);
750 PluginManager::PutPlugin(MediaPlugin
* plugin
)
752 TRACE("PluginManager::PutPlugin()\n");
757 for (fPluginList
.Rewind(); fPluginList
.GetNext(&pinfo
); ) {
758 if (plugin
== pinfo
->plugin
) {
760 if (pinfo
->usecount
== 0) {
761 TRACE(" deleting %p\n", pinfo
->plugin
);
762 delete pinfo
->plugin
;
763 TRACE(" unloading add-on: %" B_PRId32
"\n\n", pinfo
->image
);
764 unload_add_on(pinfo
->image
);
765 fPluginList
.RemoveCurrent();
772 printf("PluginManager: Error, can't put PlugIn %p\n", plugin
);
779 PluginManager::_LoadPlugin(const entry_ref
& ref
, MediaPlugin
** plugin
,
784 TRACE("PluginManager: _LoadPlugin trying to load %s\n", p
.Path());
787 id
= load_add_on(p
.Path());
789 printf("PluginManager: Error, load_add_on(): %s\n", strerror(id
));
793 MediaPlugin
* (*instantiate_plugin_func
)();
795 if (get_image_symbol(id
, "instantiate_plugin", B_SYMBOL_TYPE_TEXT
,
796 (void**)&instantiate_plugin_func
) < B_OK
) {
797 printf("PluginManager: Error, _LoadPlugin can't find "
798 "instantiate_plugin in %s\n", p
.Path());
805 pl
= (*instantiate_plugin_func
)();
807 printf("PluginManager: Error, _LoadPlugin instantiate_plugin in %s "
808 "returned NULL\n", p
.Path());