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 MIT License. 5 */ 6 7 8 #include <AdapterIO.h> 9 #include <AutoDeleter.h> 10 #include <Autolock.h> 11 #include <BufferIO.h> 12 #include <DataIO.h> 13 #include <image.h> 14 #include <Path.h> 15 16 #include <string.h> 17 18 #include "AddOnManager.h" 19 #include "PluginManager.h" 20 #include "DataExchange.h" 21 #include "MediaDebug.h" 22 23 24 PluginManager gPluginManager; 25 26 #define BLOCK_SIZE 4096 27 #define MAX_STREAMERS 40 28 29 30 class DataIOAdapter : public BAdapterIO { 31 public: 32 DataIOAdapter(BDataIO* dataIO) 33 : 34 BAdapterIO(B_MEDIA_SEEK_BACKWARD | B_MEDIA_MUTABLE_SIZE, 35 B_INFINITE_TIMEOUT), 36 fDataIO(dataIO) 37 { 38 fDataInputAdapter = BuildInputAdapter(); 39 } 40 41 virtual ~DataIOAdapter() 42 { 43 } 44 45 virtual ssize_t ReadAt(off_t position, void* buffer, 46 size_t size) 47 { 48 if (position == Position()) { 49 ssize_t ret = fDataIO->Read(buffer, size); 50 fDataInputAdapter->Write(buffer, ret); 51 return ret; 52 } 53 54 off_t totalSize = 0; 55 if (GetSize(&totalSize) != B_OK) 56 return B_UNSUPPORTED; 57 58 if (position+size < (size_t)totalSize) 59 return ReadAt(position, buffer, size); 60 61 return B_NOT_SUPPORTED; 62 } 63 64 virtual ssize_t WriteAt(off_t position, const void* buffer, 65 size_t size) 66 { 67 if (position == Position()) { 68 ssize_t ret = fDataIO->Write(buffer, size); 69 fDataInputAdapter->Write(buffer, ret); 70 return ret; 71 } 72 73 return B_NOT_SUPPORTED; 74 } 75 76 private: 77 BDataIO* fDataIO; 78 BInputAdapter* fDataInputAdapter; 79 }; 80 81 82 class BMediaIOWrapper : public BMediaIO { 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 status_t InitCheck() const 141 { 142 return fErr; 143 } 144 145 // BMediaIO interface 146 147 virtual void GetFlags(int32* flags) const 148 { 149 *flags = fFlags; 150 } 151 152 // BPositionIO interface 153 154 virtual ssize_t ReadAt(off_t position, void* buffer, 155 size_t size) 156 { 157 CALLED(); 158 159 return fPosition->ReadAt(position, buffer, size); 160 } 161 162 virtual ssize_t WriteAt(off_t position, const void* buffer, 163 size_t size) 164 { 165 CALLED(); 166 167 return fPosition->WriteAt(position, buffer, size); 168 } 169 170 virtual off_t Seek(off_t position, uint32 seekMode) 171 { 172 CALLED(); 173 174 return fPosition->Seek(position, seekMode); 175 176 } 177 178 virtual off_t Position() const 179 { 180 CALLED(); 181 182 return fPosition->Position(); 183 } 184 185 virtual status_t SetSize(off_t size) 186 { 187 CALLED(); 188 189 return fPosition->SetSize(size); 190 } 191 192 virtual status_t GetSize(off_t* size) const 193 { 194 CALLED(); 195 196 return fPosition->GetSize(size); 197 } 198 199 protected: 200 201 bool IsMedia() const 202 { 203 return fMedia != NULL; 204 } 205 206 bool IsPosition() const 207 { 208 return fPosition != NULL; 209 } 210 211 private: 212 BDataIO* fData; 213 BPositionIO* fPosition; 214 BMediaIO* fMedia; 215 BBufferIO* fBufferIO; 216 DataIOAdapter* fDataIOAdapter; 217 218 int32 fFlags; 219 220 status_t fErr; 221 }; 222 223 224 // #pragma mark - Readers/Decoders 225 226 227 status_t 228 PluginManager::CreateReader(Reader** reader, int32* streamCount, 229 media_file_format* mff, BDataIO* source) 230 { 231 TRACE("PluginManager::CreateReader enter\n"); 232 233 // The wrapper class will present our source in a more useful 234 // way, we create an instance which is buffering our reads and 235 // writes. 236 BMediaIOWrapper* buffered_source = new BMediaIOWrapper(source); 237 ObjectDeleter<BMediaIOWrapper> ioDeleter(buffered_source); 238 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 ioDeleter.Detach(); 287 return B_OK; 288 } 289 290 DestroyReader(*reader); 291 *reader = NULL; 292 } 293 294 TRACE("PluginManager::CreateReader leave\n"); 295 return B_MEDIA_NO_HANDLER; 296 } 297 298 299 void 300 PluginManager::DestroyReader(Reader* reader) 301 { 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 307 // destructor... 308 MediaPlugin* plugin = reader->fMediaPlugin; 309 delete reader; 310 PutPlugin(plugin); 311 } 312 } 313 314 315 status_t 316 PluginManager::CreateDecoder(Decoder** _decoder, const media_format& format) 317 { 318 TRACE("PluginManager::CreateDecoder enter\n"); 319 320 // get decoder for this format 321 entry_ref ref; 322 status_t ret = AddOnManager::GetInstance()->GetDecoderForFormat( 323 &ref, format); 324 if (ret != B_OK) { 325 printf("PluginManager::CreateDecoder: can't get decoder for format: " 326 "%s\n", strerror(ret)); 327 return ret; 328 } 329 330 MediaPlugin* plugin = GetPlugin(ref); 331 if (plugin == NULL) { 332 printf("PluginManager::CreateDecoder: GetPlugin failed\n"); 333 return B_ERROR; 334 } 335 336 DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin); 337 if (decoderPlugin == NULL) { 338 printf("PluginManager::CreateDecoder: dynamic_cast failed\n"); 339 PutPlugin(plugin); 340 return B_ERROR; 341 } 342 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"); 348 PutPlugin(plugin); 349 return B_ERROR; 350 } 351 TRACE(" created decoder: %p\n", *_decoder); 352 (*_decoder)->fMediaPlugin = plugin; 353 354 TRACE("PluginManager::CreateDecoder leave\n"); 355 356 return B_OK; 357 } 358 359 360 status_t 361 PluginManager::CreateDecoder(Decoder** decoder, const media_codec_info& mci) 362 { 363 TRACE("PluginManager::CreateDecoder enter\n"); 364 entry_ref ref; 365 status_t status = AddOnManager::GetInstance()->GetEncoder(&ref, mci.id); 366 if (status != B_OK) 367 return status; 368 369 MediaPlugin* plugin = GetPlugin(ref); 370 if (plugin == NULL) { 371 ERROR("PluginManager::CreateDecoder: GetPlugin failed\n"); 372 return B_ERROR; 373 } 374 375 DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin); 376 if (decoderPlugin == NULL) { 377 ERROR("PluginManager::CreateDecoder: dynamic_cast failed\n"); 378 PutPlugin(plugin); 379 return B_ERROR; 380 } 381 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"); 387 PutPlugin(plugin); 388 return B_ERROR; 389 } 390 TRACE(" created decoder: %p\n", *decoder); 391 (*decoder)->fMediaPlugin = plugin; 392 393 TRACE("PluginManager::CreateDecoder leave\n"); 394 395 return B_OK; 396 397 } 398 399 400 status_t 401 PluginManager::GetDecoderInfo(Decoder* decoder, media_codec_info* _info) const 402 { 403 if (decoder == NULL) 404 return B_BAD_VALUE; 405 406 decoder->GetCodecInfo(_info); 407 // TODO: 408 // out_info->id = 409 // out_info->sub_id = 410 return B_OK; 411 } 412 413 414 void 415 PluginManager::DestroyDecoder(Decoder* decoder) 416 { 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 422 // destructor... 423 MediaPlugin* plugin = decoder->fMediaPlugin; 424 delete decoder; 425 PutPlugin(plugin); 426 } 427 } 428 429 430 // #pragma mark - Writers/Encoders 431 432 433 status_t 434 PluginManager::CreateWriter(Writer** writer, const media_file_format& mff, 435 BDataIO* target) 436 { 437 TRACE("PluginManager::CreateWriter enter\n"); 438 439 // Get the Writer responsible for this media_file_format from the server. 440 entry_ref ref; 441 status_t ret = AddOnManager::GetInstance()->GetWriter(&ref, 442 mff.id.internal_id); 443 if (ret != B_OK) { 444 printf("PluginManager::CreateWriter: can't get writer for file " 445 "family: %s\n", strerror(ret)); 446 return ret; 447 } 448 449 MediaPlugin* plugin = GetPlugin(ref); 450 if (plugin == NULL) { 451 printf("PluginManager::CreateWriter: GetPlugin failed\n"); 452 return B_ERROR; 453 } 454 455 WriterPlugin* writerPlugin = dynamic_cast<WriterPlugin*>(plugin); 456 if (writerPlugin == NULL) { 457 printf("PluginManager::CreateWriter: dynamic_cast failed\n"); 458 PutPlugin(plugin); 459 return B_ERROR; 460 } 461 462 *writer = writerPlugin->NewWriter(); 463 if (*writer == NULL) { 464 printf("PluginManager::CreateWriter: NewWriter failed\n"); 465 PutPlugin(plugin); 466 return B_ERROR; 467 } 468 469 (*writer)->Setup(target); 470 (*writer)->fMediaPlugin = plugin; 471 472 TRACE("PluginManager::CreateWriter leave\n"); 473 return B_OK; 474 } 475 476 477 void 478 PluginManager::DestroyWriter(Writer* writer) 479 { 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 485 // destructor... 486 MediaPlugin* plugin = writer->fMediaPlugin; 487 delete writer; 488 PutPlugin(plugin); 489 } 490 } 491 492 493 status_t 494 PluginManager::CreateEncoder(Encoder** _encoder, 495 const media_codec_info* codecInfo, uint32 flags) 496 { 497 TRACE("PluginManager::CreateEncoder enter\n"); 498 499 // Get encoder for this codec info from the server 500 entry_ref ref; 501 status_t ret = AddOnManager::GetInstance()->GetEncoder(&ref, 502 codecInfo->id); 503 if (ret != B_OK) { 504 printf("PluginManager::CreateEncoder: can't get encoder for codec %s: " 505 "%s\n", codecInfo->pretty_name, strerror(ret)); 506 return ret; 507 } 508 509 MediaPlugin* plugin = GetPlugin(ref); 510 if (!plugin) { 511 printf("PluginManager::CreateEncoder: GetPlugin failed\n"); 512 return B_ERROR; 513 } 514 515 EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin); 516 if (encoderPlugin == NULL) { 517 printf("PluginManager::CreateEncoder: dynamic_cast failed\n"); 518 PutPlugin(plugin); 519 return B_ERROR; 520 } 521 522 *_encoder = encoderPlugin->NewEncoder(*codecInfo); 523 if (*_encoder == NULL) { 524 printf("PluginManager::CreateEncoder: NewEncoder() failed\n"); 525 PutPlugin(plugin); 526 return B_ERROR; 527 } 528 TRACE(" created encoder: %p\n", *_encoder); 529 (*_encoder)->fMediaPlugin = plugin; 530 531 TRACE("PluginManager::CreateEncoder leave\n"); 532 533 return B_OK; 534 } 535 536 537 status_t 538 PluginManager::CreateEncoder(Encoder** encoder, const media_format& format) 539 { 540 TRACE("PluginManager::CreateEncoder enter nr2\n"); 541 542 entry_ref ref; 543 544 status_t ret = AddOnManager::GetInstance()->GetEncoderForFormat( 545 &ref, format); 546 547 if (ret != B_OK) { 548 ERROR("PluginManager::CreateEncoder: can't get decoder for format: " 549 "%s\n", strerror(ret)); 550 return ret; 551 } 552 553 MediaPlugin* plugin = GetPlugin(ref); 554 if (plugin == NULL) { 555 ERROR("PluginManager::CreateEncoder: GetPlugin failed\n"); 556 return B_ERROR; 557 } 558 559 EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin); 560 if (encoderPlugin == NULL) { 561 ERROR("PluginManager::CreateEncoder: dynamic_cast failed\n"); 562 PutPlugin(plugin); 563 return B_ERROR; 564 } 565 566 567 *encoder = encoderPlugin->NewEncoder(format); 568 if (*encoder == NULL) { 569 ERROR("PluginManager::CreateEncoder: NewEncoder() failed\n"); 570 PutPlugin(plugin); 571 return B_ERROR; 572 } 573 TRACE(" created encoder: %p\n", *encoder); 574 (*encoder)->fMediaPlugin = plugin; 575 576 TRACE("PluginManager::CreateEncoder leave nr2\n"); 577 578 return B_OK; 579 } 580 581 582 void 583 PluginManager::DestroyEncoder(Encoder* encoder) 584 { 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 590 // destructor... 591 MediaPlugin* plugin = encoder->fMediaPlugin; 592 delete encoder; 593 PutPlugin(plugin); 594 } 595 } 596 597 598 status_t 599 PluginManager::CreateStreamer(Streamer** streamer, BUrl url, BDataIO** source) 600 { 601 BAutolock _(fLocker); 602 603 TRACE("PluginManager::CreateStreamer enter\n"); 604 605 entry_ref refs[MAX_STREAMERS]; 606 int32 count; 607 608 status_t ret = AddOnManager::GetInstance()->GetStreamers(refs, &count, 609 MAX_STREAMERS); 610 if (ret != B_OK) { 611 printf("PluginManager::CreateStreamer: can't get list of streamers:" 612 " %s\n", strerror(ret)); 613 return ret; 614 } 615 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"); 622 return B_ERROR; 623 } 624 625 StreamerPlugin* streamerPlugin = dynamic_cast<StreamerPlugin*>(plugin); 626 if (streamerPlugin == NULL) { 627 printf("PluginManager::CreateStreamer: dynamic_cast failed\n"); 628 PutPlugin(plugin); 629 return B_ERROR; 630 } 631 632 *streamer = streamerPlugin->NewStreamer(); 633 if (*streamer == NULL) { 634 printf("PluginManager::CreateStreamer: NewReader failed\n"); 635 PutPlugin(plugin); 636 return B_ERROR; 637 } 638 639 (*streamer)->fMediaPlugin = plugin; 640 plugin->fRefCount++; 641 642 BDataIO* streamSource = NULL; 643 if ((*streamer)->Sniff(url, &streamSource) == B_OK) { 644 TRACE("PluginManager::CreateStreamer: Sniff success\n"); 645 *source = streamSource; 646 return B_OK; 647 } 648 649 DestroyStreamer(*streamer); 650 *streamer = NULL; 651 } 652 653 TRACE("PluginManager::CreateStreamer leave\n"); 654 return B_MEDIA_NO_HANDLER; 655 } 656 657 658 void 659 PluginManager::DestroyStreamer(Streamer* streamer) 660 { 661 BAutolock _(fLocker); 662 663 if (streamer != NULL) { 664 TRACE("PluginManager::DestroyStreamer(%p, plugin: %p)\n", streamer, 665 streamer->fMediaPlugin); 666 667 // NOTE: We have to put the plug-in after deleting the streamer, 668 // since otherwise we may actually unload the code for the 669 // destructor... 670 MediaPlugin* plugin = streamer->fMediaPlugin; 671 delete streamer; 672 673 // Delete the plugin only when every reference is released 674 if (plugin->fRefCount == 1) { 675 plugin->fRefCount = 0; 676 PutPlugin(plugin); 677 } else 678 plugin->fRefCount--; 679 } 680 } 681 682 683 // #pragma mark - 684 685 686 PluginManager::PluginManager() 687 : 688 fPluginList(), 689 fLocker("media plugin manager") 690 { 691 CALLED(); 692 } 693 694 695 PluginManager::~PluginManager() 696 { 697 CALLED(); 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); 703 delete info->plugin; 704 unload_add_on(info->image); 705 } 706 } 707 708 709 MediaPlugin* 710 PluginManager::GetPlugin(const entry_ref& ref) 711 { 712 TRACE("PluginManager::GetPlugin(%s)\n", ref.name); 713 fLocker.Lock(); 714 715 MediaPlugin* plugin; 716 plugin_info* pinfo; 717 plugin_info info; 718 719 for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) { 720 if (0 == strcmp(ref.name, pinfo->name)) { 721 plugin = pinfo->plugin; 722 pinfo->usecount++; 723 TRACE(" found existing plugin: %p\n", pinfo->plugin); 724 fLocker.Unlock(); 725 return plugin; 726 } 727 } 728 729 if (_LoadPlugin(ref, &info.plugin, &info.image) < B_OK) { 730 printf("PluginManager: Error, loading PlugIn %s failed\n", ref.name); 731 fLocker.Unlock(); 732 return NULL; 733 } 734 735 strcpy(info.name, ref.name); 736 info.usecount = 1; 737 fPluginList.Insert(info); 738 739 TRACE("PluginManager: PlugIn %s loaded\n", ref.name); 740 741 plugin = info.plugin; 742 TRACE(" loaded plugin: %p\n", plugin); 743 744 fLocker.Unlock(); 745 return plugin; 746 } 747 748 749 void 750 PluginManager::PutPlugin(MediaPlugin* plugin) 751 { 752 TRACE("PluginManager::PutPlugin()\n"); 753 fLocker.Lock(); 754 755 plugin_info* pinfo; 756 757 for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) { 758 if (plugin == pinfo->plugin) { 759 pinfo->usecount--; 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(); 766 } 767 fLocker.Unlock(); 768 return; 769 } 770 } 771 772 printf("PluginManager: Error, can't put PlugIn %p\n", plugin); 773 774 fLocker.Unlock(); 775 } 776 777 778 status_t 779 PluginManager::_LoadPlugin(const entry_ref& ref, MediaPlugin** plugin, 780 image_id* image) 781 { 782 BPath p(&ref); 783 784 TRACE("PluginManager: _LoadPlugin trying to load %s\n", p.Path()); 785 786 image_id id; 787 id = load_add_on(p.Path()); 788 if (id < 0) { 789 printf("PluginManager: Error, load_add_on(): %s\n", strerror(id)); 790 return B_ERROR; 791 } 792 793 MediaPlugin* (*instantiate_plugin_func)(); 794 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()); 799 unload_add_on(id); 800 return B_ERROR; 801 } 802 803 MediaPlugin *pl; 804 805 pl = (*instantiate_plugin_func)(); 806 if (pl == NULL) { 807 printf("PluginManager: Error, _LoadPlugin instantiate_plugin in %s " 808 "returned NULL\n", p.Path()); 809 unload_add_on(id); 810 return B_ERROR; 811 } 812 813 *plugin = pl; 814 *image = id; 815 return B_OK; 816 } 817