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::GetReaders(entry_ref
* outRefs
, int32
* outCount
,
137 BAutolock
locker(fLock
);
142 // See GetDecoderForFormat() for why we need to scan the list by path.
144 char** directories
= NULL
;
145 size_t directoryCount
= 0;
147 if (find_paths_etc(get_architecture(), B_FIND_PATH_ADD_ONS_DIRECTORY
,
148 "media/plugins", B_FIND_PATH_EXISTING_ONLY
, &directories
,
149 &directoryCount
) != B_OK
) {
150 printf("AddOnManager::GetReaders: failed to locate plugins\n");
151 return B_ENTRY_NOT_FOUND
;
154 MemoryDeleter
directoriesDeleter(directories
);
157 for (uint i
= 0; i
< directoryCount
; i
++) {
158 path
.SetTo(directories
[i
]);
159 _GetReaders(path
, outRefs
, outCount
, maxCount
);
167 AddOnManager::GetEncoder(entry_ref
* _encoderRef
, int32 id
)
169 BAutolock
locker(fLock
);
173 for (fEncoderList
.Rewind(); fEncoderList
.GetNext(&info
);) {
174 // check if the encoder matches the supplied format
175 if (info
->internalID
== (uint32
)id
) {
176 *_encoderRef
= info
->ref
;
181 return B_ENTRY_NOT_FOUND
;
186 AddOnManager::GetWriter(entry_ref
* _ref
, uint32 internalID
)
188 BAutolock
locker(fLock
);
192 for (fWriterList
.Rewind(); fWriterList
.GetNext(&info
);) {
193 if (info
->internalID
== internalID
) {
204 AddOnManager::GetFileFormat(media_file_format
* _fileFormat
, int32 cookie
)
206 BAutolock
locker(fLock
);
209 media_file_format
* fileFormat
;
210 if (fWriterFileFormats
.Get(cookie
, &fileFormat
)) {
211 *_fileFormat
= *fileFormat
;
220 AddOnManager::GetCodecInfo(media_codec_info
* _codecInfo
,
221 media_format_family
* _formatFamily
,
222 media_format
* _inputFormat
, media_format
* _outputFormat
, int32 cookie
)
224 BAutolock
locker(fLock
);
228 if (fEncoderList
.Get(cookie
, &info
)) {
229 *_codecInfo
= info
->codecInfo
;
230 *_formatFamily
= info
->formatFamily
;
231 *_inputFormat
= info
->intputFormat
;
232 *_outputFormat
= info
->outputFormat
;
244 AddOnManager::RegisterAddOns()
246 // Check if add-ons are already registered.
247 if (!fReaderList
.IsEmpty() || !fWriterList
.IsEmpty()
248 || !fDecoderList
.IsEmpty() || !fEncoderList
.IsEmpty()) {
252 char** directories
= NULL
;
253 size_t directoryCount
= 0;
255 if (find_paths_etc(get_architecture(), B_FIND_PATH_ADD_ONS_DIRECTORY
,
256 "media/plugins", B_FIND_PATH_EXISTING_ONLY
, &directories
,
257 &directoryCount
) != B_OK
) {
261 MemoryDeleter
directoriesDeleter(directories
);
264 for (uint i
= 0; i
< directoryCount
; i
++) {
265 BDirectory directory
;
266 if (directory
.SetTo(directories
[i
]) == B_OK
) {
268 while(directory
.GetNextRef(&ref
) == B_OK
)
276 AddOnManager::_RegisterAddOn(const entry_ref
& ref
)
280 ImageLoader
loader(path
);
281 status_t status
= loader
.InitCheck();
285 MediaPlugin
* (*instantiate_plugin_func
)();
287 if (get_image_symbol(loader
.Image(), "instantiate_plugin",
288 B_SYMBOL_TYPE_TEXT
, (void**)&instantiate_plugin_func
) < B_OK
) {
289 printf("AddOnManager::_RegisterAddOn(): can't find instantiate_plugin "
290 "in \"%s\"\n", path
.Path());
294 MediaPlugin
* plugin
= (*instantiate_plugin_func
)();
295 if (plugin
== NULL
) {
296 printf("AddOnManager::_RegisterAddOn(): instantiate_plugin in \"%s\" "
297 "returned NULL\n", path
.Path());
301 ReaderPlugin
* reader
= dynamic_cast<ReaderPlugin
*>(plugin
);
303 _RegisterReader(reader
, ref
);
305 DecoderPlugin
* decoder
= dynamic_cast<DecoderPlugin
*>(plugin
);
307 _RegisterDecoder(decoder
, ref
);
309 WriterPlugin
* writer
= dynamic_cast<WriterPlugin
*>(plugin
);
311 _RegisterWriter(writer
, ref
);
313 EncoderPlugin
* encoder
= dynamic_cast<EncoderPlugin
*>(plugin
);
315 _RegisterEncoder(encoder
, ref
);
324 AddOnManager::_UnregisterAddOn(const entry_ref
& ref
)
326 BAutolock
locker(fLock
);
328 // Remove any Readers exported by this add-on
329 reader_info
* readerInfo
;
330 for (fReaderList
.Rewind(); fReaderList
.GetNext(&readerInfo
);) {
331 if (readerInfo
->ref
== ref
) {
332 fReaderList
.RemoveCurrent();
337 // Remove any Decoders exported by this add-on
338 decoder_info
* decoderInfo
;
339 for (fDecoderList
.Rewind(); fDecoderList
.GetNext(&decoderInfo
);) {
340 if (decoderInfo
->ref
== ref
) {
341 media_format
* format
;
342 for (decoderInfo
->formats
.Rewind();
343 decoderInfo
->formats
.GetNext(&format
);) {
344 FormatManager::GetInstance()->RemoveFormat(*format
);
346 fDecoderList
.RemoveCurrent();
351 // Remove any Writers exported by this add-on
352 writer_info
* writerInfo
;
353 for (fWriterList
.Rewind(); fWriterList
.GetNext(&writerInfo
);) {
354 if (writerInfo
->ref
== ref
) {
355 // Remove any formats from this writer
356 media_file_format
* writerFormat
;
357 for (fWriterFileFormats
.Rewind();
358 fWriterFileFormats
.GetNext(&writerFormat
);) {
359 if (writerFormat
->id
.internal_id
== writerInfo
->internalID
)
360 fWriterFileFormats
.RemoveCurrent();
362 fWriterList
.RemoveCurrent();
367 encoder_info
* encoderInfo
;
368 for (fEncoderList
.Rewind(); fEncoderList
.GetNext(&encoderInfo
);) {
369 if (encoderInfo
->ref
== ref
) {
370 fEncoderList
.RemoveCurrent();
371 // Keep going, since we add multiple encoder infos per add-on.
380 AddOnManager::_RegisterReader(ReaderPlugin
* reader
, const entry_ref
& ref
)
382 BAutolock
locker(fLock
);
385 for (fReaderList
.Rewind(); fReaderList
.GetNext(&pinfo
);) {
386 if (!strcmp(pinfo
->ref
.name
, ref
.name
)) {
387 // we already know this reader
395 fReaderList
.Insert(info
);
400 AddOnManager::_RegisterDecoder(DecoderPlugin
* plugin
, const entry_ref
& ref
)
402 BAutolock
locker(fLock
);
405 for (fDecoderList
.Rewind(); fDecoderList
.GetNext(&pinfo
);) {
406 if (!strcmp(pinfo
->ref
.name
, ref
.name
)) {
407 // we already know this decoder
415 media_format
* formats
= 0;
417 if (plugin
->GetSupportedFormats(&formats
, &count
) != B_OK
) {
418 printf("AddOnManager::_RegisterDecoder(): plugin->GetSupportedFormats"
422 for (uint i
= 0 ; i
< count
; i
++)
423 info
.formats
.Insert(formats
[i
]);
425 fDecoderList
.Insert(info
);
430 AddOnManager::_RegisterWriter(WriterPlugin
* writer
, const entry_ref
& ref
)
432 BAutolock
locker(fLock
);
435 for (fWriterList
.Rewind(); fWriterList
.GetNext(&pinfo
);) {
436 if (!strcmp(pinfo
->ref
.name
, ref
.name
)) {
437 // we already know this writer
444 info
.internalID
= fNextWriterFormatFamilyID
++;
446 // Get list of support media_file_formats...
447 const media_file_format
* fileFormats
= NULL
;
449 if (writer
->GetSupportedFileFormats(&fileFormats
, &count
) != B_OK
) {
450 printf("AddOnManager::_RegisterWriter(): "
451 "plugin->GetSupportedFileFormats(...) failed!\n");
454 for (uint i
= 0 ; i
< count
; i
++) {
455 // Generate a proper ID before inserting this format, this encodes
456 // the specific plugin in the media_file_format.
457 media_file_format fileFormat
= fileFormats
[i
];
458 fileFormat
.id
.node
= ref
.directory
;
459 fileFormat
.id
.device
= ref
.device
;
460 fileFormat
.id
.internal_id
= info
.internalID
;
462 fWriterFileFormats
.Insert(fileFormat
);
465 fWriterList
.Insert(info
);
470 AddOnManager::_RegisterEncoder(EncoderPlugin
* plugin
, const entry_ref
& ref
)
472 BAutolock
locker(fLock
);
475 for (fEncoderList
.Rewind(); fEncoderList
.GetNext(&pinfo
);) {
476 if (!strcmp(pinfo
->ref
.name
, ref
.name
)) {
477 // We already know this encoder. When we reject encoders with
478 // the same name, we allow the user to overwrite system encoders
479 // in her home folder.
484 // Get list of supported encoders...
488 info
.internalID
= fNextEncoderCodecInfoID
++;
493 memset(&info
.codecInfo
, 0, sizeof(media_codec_info
));
494 memset(&info
.intputFormat
, 0, sizeof(media_format
));
495 memset(&info
.outputFormat
, 0, sizeof(media_format
));
496 if (plugin
->RegisterNextEncoder(&cookie
,
497 &info
.codecInfo
, &info
.formatFamily
, &info
.intputFormat
,
498 &info
.outputFormat
) != B_OK
) {
501 info
.codecInfo
.id
= info
.internalID
;
502 // NOTE: info.codecInfo.sub_id is for private use by the Encoder,
503 // we don't touch it, but it is maintained and passed back to the
504 // EncoderPlugin in NewEncoder(media_codec_info).
506 if (!fEncoderList
.Insert(info
))
513 AddOnManager::_FindDecoder(const media_format
& format
, const BPath
& path
,
514 entry_ref
* _decoderRef
)
517 BDirectory directory
;
518 if (directory
.SetTo(path
.Path()) != B_OK
519 || directory
.GetNodeRef(&nref
) != B_OK
) {
524 for (fDecoderList
.Rewind(); fDecoderList
.GetNext(&info
);) {
525 if (info
->ref
.directory
!= nref
.node
)
528 media_format
* decoderFormat
;
529 for (info
->formats
.Rewind(); info
->formats
.GetNext(&decoderFormat
);) {
530 // check if the decoder matches the supplied format
531 if (!decoderFormat
->Matches(&format
))
534 *_decoderRef
= info
->ref
;
543 AddOnManager::_GetReaders(const BPath
& path
, entry_ref
* outRefs
,
544 int32
* outCount
, int32 maxCount
)
547 BDirectory directory
;
548 if (directory
.SetTo(path
.Path()) != B_OK
549 || directory
.GetNodeRef(&nref
) != B_OK
) {
554 for (fReaderList
.Rewind(); fReaderList
.GetNext(&info
)
555 && *outCount
< maxCount
;) {
556 if (info
->ref
.directory
!= nref
.node
)
559 outRefs
[*outCount
] = info
->ref
;
566 } // namespace BPrivate