tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / media / AddOnManager.cpp
blob5f64abca5c4771074624012410f0a85fe18cc7f3
1 /*
2 * Copyright 2004-2010, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT license.
5 * Authors:
6 * Marcus Overhagen
7 * Axel Dörfler
8 * Stephan Aßmus <superstippi@gmx.de>
9 */
12 #include "AddOnManager.h"
14 #include <stdio.h>
15 #include <string.h>
17 #include <Architecture.h>
18 #include <AutoDeleter.h>
19 #include <Autolock.h>
20 #include <Directory.h>
21 #include <Entry.h>
22 #include <FindDirectory.h>
23 #include <image.h>
24 #include <Path.h>
26 #include "debug.h"
28 #include "FormatManager.h"
29 #include "MetaFormat.h"
32 namespace BPrivate {
33 namespace media {
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.
41 class ImageLoader {
42 public:
43 ImageLoader(BPath& path)
45 fImage = load_add_on(path.Path());
48 ~ImageLoader()
50 if (fImage >= B_OK)
51 unload_add_on(fImage);
54 status_t InitCheck() const { return fImage >= 0 ? B_OK : fImage; }
55 image_id Image() const { return fImage; }
57 private:
58 image_id fImage;
62 // #pragma mark -
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()
85 return &sInstance;
89 status_t
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);
103 RegisterAddOns();
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);
122 BPath path;
123 for (uint i = 0; i < directoryCount; i++) {
124 path.SetTo(directories[i]);
125 if (_FindDecoder(format, path, _decoderRef))
126 return B_OK;
129 return B_ENTRY_NOT_FOUND;
133 status_t
134 AddOnManager::GetReaders(entry_ref* outRefs, int32* outCount,
135 int32 maxCount)
137 BAutolock locker(fLock);
138 RegisterAddOns();
140 *outCount = 0;
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);
156 BPath path;
157 for (uint i = 0; i < directoryCount; i++) {
158 path.SetTo(directories[i]);
159 _GetReaders(path, outRefs, outCount, maxCount);
162 return B_OK;
166 status_t
167 AddOnManager::GetEncoder(entry_ref* _encoderRef, int32 id)
169 BAutolock locker(fLock);
170 RegisterAddOns();
172 encoder_info* info;
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;
177 return B_OK;
181 return B_ENTRY_NOT_FOUND;
185 status_t
186 AddOnManager::GetWriter(entry_ref* _ref, uint32 internalID)
188 BAutolock locker(fLock);
189 RegisterAddOns();
191 writer_info* info;
192 for (fWriterList.Rewind(); fWriterList.GetNext(&info);) {
193 if (info->internalID == internalID) {
194 *_ref = info->ref;
195 return B_OK;
199 return B_ERROR;
203 status_t
204 AddOnManager::GetFileFormat(media_file_format* _fileFormat, int32 cookie)
206 BAutolock locker(fLock);
207 RegisterAddOns();
209 media_file_format* fileFormat;
210 if (fWriterFileFormats.Get(cookie, &fileFormat)) {
211 *_fileFormat = *fileFormat;
212 return B_OK;
215 return B_BAD_INDEX;
219 status_t
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);
225 RegisterAddOns();
227 encoder_info* info;
228 if (fEncoderList.Get(cookie, &info)) {
229 *_codecInfo = info->codecInfo;
230 *_formatFamily = info->formatFamily;
231 *_inputFormat = info->intputFormat;
232 *_outputFormat = info->outputFormat;
233 return B_OK;
236 return B_BAD_INDEX;
240 // #pragma mark -
243 void
244 AddOnManager::RegisterAddOns()
246 // Check if add-ons are already registered.
247 if (!fReaderList.IsEmpty() || !fWriterList.IsEmpty()
248 || !fDecoderList.IsEmpty() || !fEncoderList.IsEmpty()) {
249 return;
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) {
258 return;
261 MemoryDeleter directoriesDeleter(directories);
263 BPath path;
264 for (uint i = 0; i < directoryCount; i++) {
265 BDirectory directory;
266 if (directory.SetTo(directories[i]) == B_OK) {
267 entry_ref ref;
268 while(directory.GetNextRef(&ref) == B_OK)
269 _RegisterAddOn(ref);
275 status_t
276 AddOnManager::_RegisterAddOn(const entry_ref& ref)
278 BPath path(&ref);
280 ImageLoader loader(path);
281 status_t status = loader.InitCheck();
282 if (status != B_OK)
283 return status;
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());
291 return B_BAD_TYPE;
294 MediaPlugin* plugin = (*instantiate_plugin_func)();
295 if (plugin == NULL) {
296 printf("AddOnManager::_RegisterAddOn(): instantiate_plugin in \"%s\" "
297 "returned NULL\n", path.Path());
298 return B_ERROR;
301 ReaderPlugin* reader = dynamic_cast<ReaderPlugin*>(plugin);
302 if (reader != NULL)
303 _RegisterReader(reader, ref);
305 DecoderPlugin* decoder = dynamic_cast<DecoderPlugin*>(plugin);
306 if (decoder != NULL)
307 _RegisterDecoder(decoder, ref);
309 WriterPlugin* writer = dynamic_cast<WriterPlugin*>(plugin);
310 if (writer != NULL)
311 _RegisterWriter(writer, ref);
313 EncoderPlugin* encoder = dynamic_cast<EncoderPlugin*>(plugin);
314 if (encoder != NULL)
315 _RegisterEncoder(encoder, ref);
317 delete plugin;
319 return B_OK;
323 status_t
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();
333 break;
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();
347 break;
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();
363 break;
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.
375 return B_OK;
379 void
380 AddOnManager::_RegisterReader(ReaderPlugin* reader, const entry_ref& ref)
382 BAutolock locker(fLock);
384 reader_info* pinfo;
385 for (fReaderList.Rewind(); fReaderList.GetNext(&pinfo);) {
386 if (!strcmp(pinfo->ref.name, ref.name)) {
387 // we already know this reader
388 return;
392 reader_info info;
393 info.ref = ref;
395 fReaderList.Insert(info);
399 void
400 AddOnManager::_RegisterDecoder(DecoderPlugin* plugin, const entry_ref& ref)
402 BAutolock locker(fLock);
404 decoder_info* pinfo;
405 for (fDecoderList.Rewind(); fDecoderList.GetNext(&pinfo);) {
406 if (!strcmp(pinfo->ref.name, ref.name)) {
407 // we already know this decoder
408 return;
412 decoder_info info;
413 info.ref = ref;
415 media_format* formats = 0;
416 size_t count = 0;
417 if (plugin->GetSupportedFormats(&formats, &count) != B_OK) {
418 printf("AddOnManager::_RegisterDecoder(): plugin->GetSupportedFormats"
419 "(...) failed!\n");
420 return;
422 for (uint i = 0 ; i < count ; i++)
423 info.formats.Insert(formats[i]);
425 fDecoderList.Insert(info);
429 void
430 AddOnManager::_RegisterWriter(WriterPlugin* writer, const entry_ref& ref)
432 BAutolock locker(fLock);
434 writer_info* pinfo;
435 for (fWriterList.Rewind(); fWriterList.GetNext(&pinfo);) {
436 if (!strcmp(pinfo->ref.name, ref.name)) {
437 // we already know this writer
438 return;
442 writer_info info;
443 info.ref = ref;
444 info.internalID = fNextWriterFormatFamilyID++;
446 // Get list of support media_file_formats...
447 const media_file_format* fileFormats = NULL;
448 size_t count = 0;
449 if (writer->GetSupportedFileFormats(&fileFormats, &count) != B_OK) {
450 printf("AddOnManager::_RegisterWriter(): "
451 "plugin->GetSupportedFileFormats(...) failed!\n");
452 return;
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);
469 void
470 AddOnManager::_RegisterEncoder(EncoderPlugin* plugin, const entry_ref& ref)
472 BAutolock locker(fLock);
474 encoder_info* pinfo;
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.
480 return;
484 // Get list of supported encoders...
486 encoder_info info;
487 info.ref = ref;
488 info.internalID = fNextEncoderCodecInfoID++;
490 int32 cookie = 0;
492 while (true) {
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) {
499 break;
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))
507 break;
512 bool
513 AddOnManager::_FindDecoder(const media_format& format, const BPath& path,
514 entry_ref* _decoderRef)
516 node_ref nref;
517 BDirectory directory;
518 if (directory.SetTo(path.Path()) != B_OK
519 || directory.GetNodeRef(&nref) != B_OK) {
520 return false;
523 decoder_info* info;
524 for (fDecoderList.Rewind(); fDecoderList.GetNext(&info);) {
525 if (info->ref.directory != nref.node)
526 continue;
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))
532 continue;
534 *_decoderRef = info->ref;
535 return true;
538 return false;
542 void
543 AddOnManager::_GetReaders(const BPath& path, entry_ref* outRefs,
544 int32* outCount, int32 maxCount)
546 node_ref nref;
547 BDirectory directory;
548 if (directory.SetTo(path.Path()) != B_OK
549 || directory.GetNodeRef(&nref) != B_OK) {
550 return;
553 reader_info* info;
554 for (fReaderList.Rewind(); fReaderList.GetNext(&info)
555 && *outCount < maxCount;) {
556 if (info->ref.directory != nref.node)
557 continue;
559 outRefs[*outCount] = info->ref;
560 (*outCount)++;
565 } // namespace media
566 } // namespace BPrivate