2 * Copyright 2004-2010, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT license.
8 * Stephan Aßmus <superstippi@gmx.de>
12 #include "AddOnManager.h"
17 #include <Architecture.h>
18 #include <AutoDeleter.h>
20 #include <Directory.h>
22 #include <FindDirectory.h>
28 #include "FormatManager.h"
29 #include "MetaFormat.h"
36 // #pragma mark - ImageLoader
38 /*! The ImageLoader class is a convenience class to temporarily load
39 an image file, and unload it on deconstruction automatically.
43 ImageLoader(BPath
& path
)
45 fImage
= load_add_on(path
.Path());
51 unload_add_on(fImage
);
54 status_t
InitCheck() const { return fImage
>= 0 ? B_OK
: fImage
; }
55 image_id
Image() const { return fImage
; }
65 AddOnManager::AddOnManager()
67 fLock("add-on manager"),
68 fNextWriterFormatFamilyID(0),
69 fNextEncoderCodecInfoID(0)
74 AddOnManager::~AddOnManager()
79 AddOnManager
AddOnManager::sInstance
;
82 /* static */ AddOnManager
*
83 AddOnManager::GetInstance()
90 AddOnManager::GetDecoderForFormat(entry_ref
* _decoderRef
,
91 const media_format
& format
)
93 if ((format
.type
== B_MEDIA_ENCODED_VIDEO
94 || format
.type
== B_MEDIA_ENCODED_AUDIO
95 || format
.type
== B_MEDIA_MULTISTREAM
)
96 && format
.Encoding() == 0) {
97 return B_MEDIA_BAD_FORMAT
;
99 if (format
.type
== B_MEDIA_NO_TYPE
|| format
.type
== B_MEDIA_UNKNOWN_TYPE
)
100 return B_MEDIA_BAD_FORMAT
;
102 BAutolock
locker(fLock
);
105 // Since the list of decoders is unsorted, we need to search for
106 // a decoder by add-on directory, in order to maintain the shadowing
107 // of system add-ons by user add-ons, in case they offer decoders
108 // for the same format.
110 char** directories
= NULL
;
111 size_t directoryCount
= 0;
113 if (find_paths_etc(get_architecture(), B_FIND_PATH_ADD_ONS_DIRECTORY
,
114 "media/plugins", B_FIND_PATH_EXISTING_ONLY
, &directories
,
115 &directoryCount
) != B_OK
) {
116 printf("AddOnManager::GetDecoderForFormat: failed to locate plugins\n");
117 return B_ENTRY_NOT_FOUND
;
120 MemoryDeleter
directoriesDeleter(directories
);
123 for (uint i
= 0; i
< directoryCount
; i
++) {
124 path
.SetTo(directories
[i
]);
125 if (_FindDecoder(format
, path
, _decoderRef
))
129 return B_ENTRY_NOT_FOUND
;
134 AddOnManager::GetEncoderForFormat(entry_ref
* _encoderRef
,
135 const media_format
& outputFormat
)
137 if ((outputFormat
.type
== B_MEDIA_RAW_VIDEO
138 || outputFormat
.type
== B_MEDIA_RAW_AUDIO
)) {
139 return B_MEDIA_BAD_FORMAT
;
142 if (outputFormat
.type
== B_MEDIA_NO_TYPE
143 || outputFormat
.type
== B_MEDIA_UNKNOWN_TYPE
) {
144 return B_MEDIA_BAD_FORMAT
;
147 BAutolock
locker(fLock
);
150 char** directories
= NULL
;
151 size_t directoryCount
= 0;
153 if (find_paths_etc(get_architecture(), B_FIND_PATH_ADD_ONS_DIRECTORY
,
154 "media/plugins", B_FIND_PATH_EXISTING_ONLY
, &directories
,
155 &directoryCount
) != B_OK
) {
156 printf("AddOnManager::GetDecoderForFormat: failed to locate plugins\n");
157 return B_ENTRY_NOT_FOUND
;
160 MemoryDeleter
directoriesDeleter(directories
);
163 for (uint i
= 0; i
< directoryCount
; i
++) {
164 path
.SetTo(directories
[i
]);
165 if (_FindEncoder(outputFormat
, path
, _encoderRef
))
169 return B_ENTRY_NOT_FOUND
;
174 AddOnManager::GetReaders(entry_ref
* outRefs
, int32
* outCount
,
177 BAutolock
locker(fLock
);
182 // See GetDecoderForFormat() for why we need to scan the list by path.
184 char** directories
= NULL
;
185 size_t directoryCount
= 0;
187 if (find_paths_etc(get_architecture(), B_FIND_PATH_ADD_ONS_DIRECTORY
,
188 "media/plugins", B_FIND_PATH_EXISTING_ONLY
, &directories
,
189 &directoryCount
) != B_OK
) {
190 printf("AddOnManager::GetReaders: failed to locate plugins\n");
191 return B_ENTRY_NOT_FOUND
;
194 MemoryDeleter
directoriesDeleter(directories
);
197 for (uint i
= 0; i
< directoryCount
; i
++) {
198 path
.SetTo(directories
[i
]);
199 _GetReaders(path
, outRefs
, outCount
, maxCount
);
207 AddOnManager::GetStreamers(entry_ref
* outRefs
, int32
* outCount
,
210 BAutolock
locker(fLock
);
215 for (fStreamerList
.Rewind(); fStreamerList
.GetNext(&info
);) {
216 if (count
== maxCount
)
219 *outRefs
= info
->ref
;
230 AddOnManager::GetEncoder(entry_ref
* _encoderRef
, int32 id
)
232 BAutolock
locker(fLock
);
236 for (fEncoderList
.Rewind(); fEncoderList
.GetNext(&info
);) {
237 // check if the encoder matches the supplied format
238 if (info
->internalID
== (uint32
)id
) {
239 *_encoderRef
= info
->ref
;
244 return B_ENTRY_NOT_FOUND
;
249 AddOnManager::GetWriter(entry_ref
* _ref
, uint32 internalID
)
251 BAutolock
locker(fLock
);
255 for (fWriterList
.Rewind(); fWriterList
.GetNext(&info
);) {
256 if (info
->internalID
== internalID
) {
267 AddOnManager::GetFileFormat(media_file_format
* _fileFormat
, int32 cookie
)
269 BAutolock
locker(fLock
);
272 media_file_format
* fileFormat
;
273 if (fWriterFileFormats
.Get(cookie
, &fileFormat
)) {
274 *_fileFormat
= *fileFormat
;
283 AddOnManager::GetCodecInfo(media_codec_info
* _codecInfo
,
284 media_format_family
* _formatFamily
,
285 media_format
* _inputFormat
, media_format
* _outputFormat
, int32 cookie
)
287 BAutolock
locker(fLock
);
291 if (fEncoderList
.Get(cookie
, &info
)) {
292 *_codecInfo
= info
->codecInfo
;
293 *_formatFamily
= info
->formatFamily
;
294 *_inputFormat
= info
->intputFormat
;
295 *_outputFormat
= info
->outputFormat
;
307 AddOnManager::RegisterAddOns()
309 // Check if add-ons are already registered.
310 if (!fReaderList
.IsEmpty() || !fWriterList
.IsEmpty()
311 || !fDecoderList
.IsEmpty() || !fEncoderList
.IsEmpty()) {
315 char** directories
= NULL
;
316 size_t directoryCount
= 0;
318 if (find_paths_etc(get_architecture(), B_FIND_PATH_ADD_ONS_DIRECTORY
,
319 "media/plugins", B_FIND_PATH_EXISTING_ONLY
, &directories
,
320 &directoryCount
) != B_OK
) {
324 MemoryDeleter
directoriesDeleter(directories
);
327 for (uint i
= 0; i
< directoryCount
; i
++) {
328 BDirectory directory
;
329 if (directory
.SetTo(directories
[i
]) == B_OK
) {
331 while(directory
.GetNextRef(&ref
) == B_OK
)
339 AddOnManager::_RegisterAddOn(const entry_ref
& ref
)
343 ImageLoader
loader(path
);
344 status_t status
= loader
.InitCheck();
348 MediaPlugin
* (*instantiate_plugin_func
)();
350 if (get_image_symbol(loader
.Image(), "instantiate_plugin",
351 B_SYMBOL_TYPE_TEXT
, (void**)&instantiate_plugin_func
) < B_OK
) {
352 printf("AddOnManager::_RegisterAddOn(): can't find instantiate_plugin "
353 "in \"%s\"\n", path
.Path());
357 MediaPlugin
* plugin
= (*instantiate_plugin_func
)();
358 if (plugin
== NULL
) {
359 printf("AddOnManager::_RegisterAddOn(): instantiate_plugin in \"%s\" "
360 "returned NULL\n", path
.Path());
364 ReaderPlugin
* reader
= dynamic_cast<ReaderPlugin
*>(plugin
);
366 _RegisterReader(reader
, ref
);
368 DecoderPlugin
* decoder
= dynamic_cast<DecoderPlugin
*>(plugin
);
370 _RegisterDecoder(decoder
, ref
);
372 WriterPlugin
* writer
= dynamic_cast<WriterPlugin
*>(plugin
);
374 _RegisterWriter(writer
, ref
);
376 EncoderPlugin
* encoder
= dynamic_cast<EncoderPlugin
*>(plugin
);
378 _RegisterEncoder(encoder
, ref
);
380 StreamerPlugin
* streamer
= dynamic_cast<StreamerPlugin
*>(plugin
);
381 if (streamer
!= NULL
)
382 _RegisterStreamer(streamer
, ref
);
391 AddOnManager::_UnregisterAddOn(const entry_ref
& ref
)
393 BAutolock
locker(fLock
);
395 // Remove any Readers exported by this add-on
396 reader_info
* readerInfo
;
397 for (fReaderList
.Rewind(); fReaderList
.GetNext(&readerInfo
);) {
398 if (readerInfo
->ref
== ref
) {
399 fReaderList
.RemoveCurrent();
404 // Remove any Decoders exported by this add-on
405 decoder_info
* decoderInfo
;
406 for (fDecoderList
.Rewind(); fDecoderList
.GetNext(&decoderInfo
);) {
407 if (decoderInfo
->ref
== ref
) {
408 media_format
* format
;
409 for (decoderInfo
->formats
.Rewind();
410 decoderInfo
->formats
.GetNext(&format
);) {
411 FormatManager::GetInstance()->RemoveFormat(*format
);
413 fDecoderList
.RemoveCurrent();
418 // Remove any Writers exported by this add-on
419 writer_info
* writerInfo
;
420 for (fWriterList
.Rewind(); fWriterList
.GetNext(&writerInfo
);) {
421 if (writerInfo
->ref
== ref
) {
422 // Remove any formats from this writer
423 media_file_format
* writerFormat
;
424 for (fWriterFileFormats
.Rewind();
425 fWriterFileFormats
.GetNext(&writerFormat
);) {
426 if (writerFormat
->id
.internal_id
== writerInfo
->internalID
)
427 fWriterFileFormats
.RemoveCurrent();
429 fWriterList
.RemoveCurrent();
434 encoder_info
* encoderInfo
;
435 for (fEncoderList
.Rewind(); fEncoderList
.GetNext(&encoderInfo
);) {
436 if (encoderInfo
->ref
== ref
) {
437 fEncoderList
.RemoveCurrent();
438 // Keep going, since we add multiple encoder infos per add-on.
447 AddOnManager::_RegisterReader(ReaderPlugin
* reader
, const entry_ref
& ref
)
449 BAutolock
locker(fLock
);
452 for (fReaderList
.Rewind(); fReaderList
.GetNext(&pinfo
);) {
453 if (!strcmp(pinfo
->ref
.name
, ref
.name
)) {
454 // we already know this reader
462 fReaderList
.Insert(info
);
467 AddOnManager::_RegisterDecoder(DecoderPlugin
* plugin
, const entry_ref
& ref
)
469 BAutolock
locker(fLock
);
472 for (fDecoderList
.Rewind(); fDecoderList
.GetNext(&pinfo
);) {
473 if (!strcmp(pinfo
->ref
.name
, ref
.name
)) {
474 // we already know this decoder
482 media_format
* formats
= 0;
484 if (plugin
->GetSupportedFormats(&formats
, &count
) != B_OK
) {
485 printf("AddOnManager::_RegisterDecoder(): plugin->GetSupportedFormats"
489 for (uint i
= 0 ; i
< count
; i
++)
490 info
.formats
.Insert(formats
[i
]);
492 fDecoderList
.Insert(info
);
497 AddOnManager::_RegisterWriter(WriterPlugin
* writer
, const entry_ref
& ref
)
499 BAutolock
locker(fLock
);
502 for (fWriterList
.Rewind(); fWriterList
.GetNext(&pinfo
);) {
503 if (!strcmp(pinfo
->ref
.name
, ref
.name
)) {
504 // we already know this writer
511 info
.internalID
= fNextWriterFormatFamilyID
++;
513 // Get list of support media_file_formats...
514 const media_file_format
* fileFormats
= NULL
;
516 if (writer
->GetSupportedFileFormats(&fileFormats
, &count
) != B_OK
) {
517 printf("AddOnManager::_RegisterWriter(): "
518 "plugin->GetSupportedFileFormats(...) failed!\n");
521 for (uint i
= 0 ; i
< count
; i
++) {
522 // Generate a proper ID before inserting this format, this encodes
523 // the specific plugin in the media_file_format.
524 media_file_format fileFormat
= fileFormats
[i
];
525 fileFormat
.id
.node
= ref
.directory
;
526 fileFormat
.id
.device
= ref
.device
;
527 fileFormat
.id
.internal_id
= info
.internalID
;
529 fWriterFileFormats
.Insert(fileFormat
);
532 fWriterList
.Insert(info
);
537 AddOnManager::_RegisterEncoder(EncoderPlugin
* plugin
, const entry_ref
& ref
)
539 BAutolock
locker(fLock
);
542 for (fEncoderList
.Rewind(); fEncoderList
.GetNext(&pinfo
);) {
543 if (!strcmp(pinfo
->ref
.name
, ref
.name
)) {
544 // We already know this encoder. When we reject encoders with
545 // the same name, we allow the user to overwrite system encoders
546 // in her home folder.
551 // Get list of supported encoders...
555 info
.internalID
= fNextEncoderCodecInfoID
++;
560 memset(&info
.codecInfo
, 0, sizeof(media_codec_info
));
561 memset(&info
.intputFormat
, 0, sizeof(media_format
));
562 memset(&info
.outputFormat
, 0, sizeof(media_format
));
563 if (plugin
->RegisterNextEncoder(&cookie
,
564 &info
.codecInfo
, &info
.formatFamily
, &info
.intputFormat
,
565 &info
.outputFormat
) != B_OK
) {
568 info
.codecInfo
.id
= info
.internalID
;
569 // NOTE: info.codecInfo.sub_id is for private use by the Encoder,
570 // we don't touch it, but it is maintained and passed back to the
571 // EncoderPlugin in NewEncoder(media_codec_info).
573 if (!fEncoderList
.Insert(info
))
580 AddOnManager::_RegisterStreamer(StreamerPlugin
* streamer
, const entry_ref
& ref
)
582 BAutolock
locker(fLock
);
584 streamer_info
* pInfo
;
585 for (fStreamerList
.Rewind(); fStreamerList
.GetNext(&pInfo
);) {
586 if (!strcmp(pInfo
->ref
.name
, ref
.name
)) {
587 // We already know this streamer
594 fStreamerList
.Insert(info
);
599 AddOnManager::_FindDecoder(const media_format
& format
, const BPath
& path
,
600 entry_ref
* _decoderRef
)
603 BDirectory directory
;
604 if (directory
.SetTo(path
.Path()) != B_OK
605 || directory
.GetNodeRef(&nref
) != B_OK
) {
610 for (fDecoderList
.Rewind(); fDecoderList
.GetNext(&info
);) {
611 if (info
->ref
.directory
!= nref
.node
)
614 media_format
* decoderFormat
;
615 for (info
->formats
.Rewind(); info
->formats
.GetNext(&decoderFormat
);) {
616 // check if the decoder matches the supplied format
617 if (!decoderFormat
->Matches(&format
))
620 *_decoderRef
= info
->ref
;
629 AddOnManager::_FindEncoder(const media_format
& format
, const BPath
& path
,
630 entry_ref
* _encoderRef
)
633 BDirectory directory
;
634 if (directory
.SetTo(path
.Path()) != B_OK
635 || directory
.GetNodeRef(&nref
) != B_OK
) {
640 for (fEncoderList
.Rewind(); fEncoderList
.GetNext(&info
);) {
641 if (info
->ref
.directory
!= nref
.node
)
644 // check if the encoder matches the supplied format
645 if (info
->outputFormat
.Matches(&format
)) {
646 *_encoderRef
= info
->ref
;
656 AddOnManager::_GetReaders(const BPath
& path
, entry_ref
* outRefs
,
657 int32
* outCount
, int32 maxCount
)
660 BDirectory directory
;
661 if (directory
.SetTo(path
.Path()) != B_OK
662 || directory
.GetNodeRef(&nref
) != B_OK
) {
667 for (fReaderList
.Rewind(); fReaderList
.GetNext(&info
)
668 && *outCount
< maxCount
;) {
669 if (info
->ref
.directory
!= nref
.node
)
672 outRefs
[*outCount
] = info
->ref
;
679 } // namespace BPrivate