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 OpenBeOS License. 5 */ 6 7 8 #include <AdapterIO.h> 9 #include <BufferIO.h> 10 #include <DataIO.h> 11 #include <image.h> 12 #include <Path.h> 13 14 #include <string.h> 15 16 #include "AddOnManager.h" 17 #include "PluginManager.h" 18 #include "DataExchange.h" 19 #include "debug.h" 20 21 22 PluginManager gPluginManager; 23 24 #define BLOCK_SIZE 4096 25 #define MAX_STREAMERS 40 26 27 28 class DataIOAdapter : public BAdapterIO { 29 public: 30 DataIOAdapter(BDataIO* dataIO) 31 : 32 BAdapterIO(B_MEDIA_SEEK_BACKWARD | B_MEDIA_MUTABLE_SIZE, 33 B_INFINITE_TIMEOUT), 34 fDataIO(dataIO) 35 { 36 fDataInputAdapter = BuildInputAdapter(); 37 } 38 39 virtual ~DataIOAdapter() 40 { 41 } 42 43 virtual ssize_t ReadAt(off_t position, void* buffer, 44 size_t size) 45 { 46 if (position == Position()) { 47 ssize_t ret = fDataIO->Read(buffer, size); 48 fDataInputAdapter->Write(buffer, ret); 49 return ret; 50 } 51 52 off_t totalSize = 0; 53 if (GetSize(&totalSize) != B_OK) 54 return B_UNSUPPORTED; 55 56 if (position+size < (size_t)totalSize) 57 return ReadAt(position, buffer, size); 58 59 return B_NOT_SUPPORTED; 60 } 61 62 virtual ssize_t WriteAt(off_t position, const void* buffer, 63 size_t size) 64 { 65 if (position == Position()) { 66 ssize_t ret = fDataIO->Write(buffer, size); 67 fDataInputAdapter->Write(buffer, ret); 68 return ret; 69 } 70 71 return B_NOT_SUPPORTED; 72 } 73 74 private: 75 BDataIO* fDataIO; 76 BInputAdapter* fDataInputAdapter; 77 }; 78 79 80 class BMediaIOWrapper : public BMediaIO { 81 public: 82 BMediaIOWrapper(BDataIO* source) 83 : 84 fData(NULL), 85 fPosition(NULL), 86 fMedia(NULL), 87 fBufferIO(NULL), 88 fDataIOAdapter(NULL), 89 fErr(B_NO_ERROR) 90 { 91 CALLED(); 92 93 fPosition = dynamic_cast<BPositionIO*>(source); 94 fMedia = dynamic_cast<BMediaIO*>(source); 95 fBufferIO = dynamic_cast<BBufferIO *>(source); 96 fData = source; 97 98 // No need to do additional buffering if we have 99 // a BBufferIO or a BMediaIO. 100 if (!IsMedia() && fBufferIO == NULL) { 101 // Source needs to be at least a BPositionIO to wrap with a BBufferIO 102 if (IsPosition()) { 103 fBufferIO = new(std::nothrow) BBufferIO(fPosition, 65536, false); 104 if (fBufferIO == NULL) { 105 fErr = B_NO_MEMORY; 106 return; 107 } 108 // We have to reset our parents reference too 109 fPosition = dynamic_cast<BPositionIO*>(fBufferIO); 110 fData = dynamic_cast<BDataIO*>(fPosition); 111 } else { 112 // In this case we have to supply our own form 113 // of pseudo-seekable object from a non-seekable 114 // BDataIO. 115 fDataIOAdapter = new DataIOAdapter(source); 116 fMedia = dynamic_cast<BMediaIO*>(fDataIOAdapter); 117 fPosition = dynamic_cast<BPositionIO*>(fDataIOAdapter); 118 fData = dynamic_cast<BDataIO*>(fDataIOAdapter); 119 TRACE("Unable to improve performance with a BufferIO\n"); 120 } 121 } 122 123 if (IsMedia()) 124 fMedia->GetFlags(&fFlags); 125 else if (IsPosition()) 126 fFlags = B_MEDIA_SEEKABLE; 127 } 128 129 virtual ~BMediaIOWrapper() 130 { 131 if (fBufferIO != NULL) 132 delete fBufferIO; 133 134 if (fDataIOAdapter != NULL) 135 delete fDataIOAdapter; 136 } 137 138 // BMediaIO interface 139 140 virtual void GetFlags(int32* flags) const 141 { 142 *flags = fFlags; 143 } 144 145 // BPositionIO interface 146 147 virtual ssize_t ReadAt(off_t position, void* buffer, 148 size_t size) 149 { 150 CALLED(); 151 152 return fPosition->ReadAt(position, buffer, size); 153 } 154 155 virtual ssize_t WriteAt(off_t position, const void* buffer, 156 size_t size) 157 { 158 CALLED(); 159 160 return fPosition->WriteAt(position, buffer, size); 161 } 162 163 virtual off_t Seek(off_t position, uint32 seekMode) 164 { 165 CALLED(); 166 167 return fPosition->Seek(position, seekMode); 168 169 } 170 171 virtual off_t Position() const 172 { 173 CALLED(); 174 175 return fPosition->Position(); 176 } 177 178 virtual status_t SetSize(off_t size) 179 { 180 CALLED(); 181 182 return fPosition->SetSize(size); 183 } 184 185 virtual status_t GetSize(off_t* size) const 186 { 187 CALLED(); 188 189 return fPosition->GetSize(size); 190 } 191 192 // Utility methods 193 194 status_t InitCheck() const 195 { 196 return fErr; 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 status_t ret = buffered_source->InitCheck(); 238 if (ret != B_OK) 239 return ret; 240 241 // get list of available readers from the server 242 entry_ref refs[MAX_READERS]; 243 int32 count; 244 245 ret = AddOnManager::GetInstance()->GetReaders(refs, &count, 246 MAX_READERS); 247 if (ret != B_OK) { 248 printf("PluginManager::CreateReader: can't get list of readers: %s\n", 249 strerror(ret)); 250 return ret; 251 } 252 253 // try each reader by calling it's Sniff function... 254 for (int32 i = 0; i < count; i++) { 255 entry_ref ref = refs[i]; 256 MediaPlugin* plugin = GetPlugin(ref); 257 if (plugin == NULL) { 258 printf("PluginManager::CreateReader: GetPlugin failed\n"); 259 return B_ERROR; 260 } 261 262 ReaderPlugin* readerPlugin = dynamic_cast<ReaderPlugin*>(plugin); 263 if (readerPlugin == NULL) { 264 printf("PluginManager::CreateReader: dynamic_cast failed\n"); 265 PutPlugin(plugin); 266 return B_ERROR; 267 } 268 269 *reader = readerPlugin->NewReader(); 270 if (*reader == NULL) { 271 printf("PluginManager::CreateReader: NewReader failed\n"); 272 PutPlugin(plugin); 273 return B_ERROR; 274 } 275 276 buffered_source->Seek(0, SEEK_SET); 277 (*reader)->Setup(buffered_source); 278 (*reader)->fMediaPlugin = plugin; 279 280 if ((*reader)->Sniff(streamCount) == B_OK) { 281 TRACE("PluginManager::CreateReader: Sniff success " 282 "(%" B_PRId32 " stream(s))\n", *streamCount); 283 (*reader)->GetFileFormatInfo(mff); 284 return B_OK; 285 } 286 287 DestroyReader(*reader); 288 *reader = NULL; 289 } 290 291 TRACE("PluginManager::CreateReader leave\n"); 292 return B_MEDIA_NO_HANDLER; 293 } 294 295 296 void 297 PluginManager::DestroyReader(Reader* reader) 298 { 299 if (reader != NULL) { 300 TRACE("PluginManager::DestroyReader(%p (plugin: %p))\n", reader, 301 reader->fMediaPlugin); 302 // NOTE: We have to put the plug-in after deleting the reader, 303 // since otherwise we may actually unload the code for the 304 // destructor... 305 MediaPlugin* plugin = reader->fMediaPlugin; 306 delete reader; 307 PutPlugin(plugin); 308 } 309 } 310 311 312 status_t 313 PluginManager::CreateDecoder(Decoder** _decoder, const media_format& format) 314 { 315 TRACE("PluginManager::CreateDecoder enter\n"); 316 317 // get decoder for this format 318 entry_ref ref; 319 status_t ret = AddOnManager::GetInstance()->GetDecoderForFormat( 320 &ref, format); 321 if (ret != B_OK) { 322 printf("PluginManager::CreateDecoder: can't get decoder for format: " 323 "%s\n", strerror(ret)); 324 return ret; 325 } 326 327 MediaPlugin* plugin = GetPlugin(ref); 328 if (plugin == NULL) { 329 printf("PluginManager::CreateDecoder: GetPlugin failed\n"); 330 return B_ERROR; 331 } 332 333 DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin); 334 if (decoderPlugin == NULL) { 335 printf("PluginManager::CreateDecoder: dynamic_cast failed\n"); 336 PutPlugin(plugin); 337 return B_ERROR; 338 } 339 340 // TODO: In theory, one DecoderPlugin could support multiple Decoders, 341 // but this is not yet handled (passing "0" as index/ID). 342 *_decoder = decoderPlugin->NewDecoder(0); 343 if (*_decoder == NULL) { 344 printf("PluginManager::CreateDecoder: NewDecoder() failed\n"); 345 PutPlugin(plugin); 346 return B_ERROR; 347 } 348 TRACE(" created decoder: %p\n", *_decoder); 349 (*_decoder)->fMediaPlugin = plugin; 350 351 TRACE("PluginManager::CreateDecoder leave\n"); 352 353 return B_OK; 354 } 355 356 357 status_t 358 PluginManager::CreateDecoder(Decoder** decoder, const media_codec_info& mci) 359 { 360 TRACE("PluginManager::CreateDecoder enter\n"); 361 entry_ref ref; 362 status_t status = AddOnManager::GetInstance()->GetEncoder(&ref, mci.id); 363 if (status != B_OK) 364 return status; 365 366 MediaPlugin* plugin = GetPlugin(ref); 367 if (plugin == NULL) { 368 ERROR("PluginManager::CreateDecoder: GetPlugin failed\n"); 369 return B_ERROR; 370 } 371 372 DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin); 373 if (decoderPlugin == NULL) { 374 ERROR("PluginManager::CreateDecoder: dynamic_cast failed\n"); 375 PutPlugin(plugin); 376 return B_ERROR; 377 } 378 379 // TODO: In theory, one DecoderPlugin could support multiple Decoders, 380 // but this is not yet handled (passing "0" as index/ID). 381 *decoder = decoderPlugin->NewDecoder(0); 382 if (*decoder == NULL) { 383 ERROR("PluginManager::CreateDecoder: NewDecoder() failed\n"); 384 PutPlugin(plugin); 385 return B_ERROR; 386 } 387 TRACE(" created decoder: %p\n", *decoder); 388 (*decoder)->fMediaPlugin = plugin; 389 390 TRACE("PluginManager::CreateDecoder leave\n"); 391 392 return B_OK; 393 394 } 395 396 397 status_t 398 PluginManager::GetDecoderInfo(Decoder* decoder, media_codec_info* _info) const 399 { 400 if (decoder == NULL) 401 return B_BAD_VALUE; 402 403 decoder->GetCodecInfo(_info); 404 // TODO: 405 // out_info->id = 406 // out_info->sub_id = 407 return B_OK; 408 } 409 410 411 void 412 PluginManager::DestroyDecoder(Decoder* decoder) 413 { 414 if (decoder != NULL) { 415 TRACE("PluginManager::DestroyDecoder(%p, plugin: %p)\n", decoder, 416 decoder->fMediaPlugin); 417 // NOTE: We have to put the plug-in after deleting the decoder, 418 // since otherwise we may actually unload the code for the 419 // destructor... 420 MediaPlugin* plugin = decoder->fMediaPlugin; 421 delete decoder; 422 PutPlugin(plugin); 423 } 424 } 425 426 427 // #pragma mark - Writers/Encoders 428 429 430 status_t 431 PluginManager::CreateWriter(Writer** writer, const media_file_format& mff, 432 BDataIO* target) 433 { 434 TRACE("PluginManager::CreateWriter enter\n"); 435 436 // Get the Writer responsible for this media_file_format from the server. 437 entry_ref ref; 438 status_t ret = AddOnManager::GetInstance()->GetWriter(&ref, 439 mff.id.internal_id); 440 if (ret != B_OK) { 441 printf("PluginManager::CreateWriter: can't get writer for file " 442 "family: %s\n", strerror(ret)); 443 return ret; 444 } 445 446 MediaPlugin* plugin = GetPlugin(ref); 447 if (plugin == NULL) { 448 printf("PluginManager::CreateWriter: GetPlugin failed\n"); 449 return B_ERROR; 450 } 451 452 WriterPlugin* writerPlugin = dynamic_cast<WriterPlugin*>(plugin); 453 if (writerPlugin == NULL) { 454 printf("PluginManager::CreateWriter: dynamic_cast failed\n"); 455 PutPlugin(plugin); 456 return B_ERROR; 457 } 458 459 *writer = writerPlugin->NewWriter(); 460 if (*writer == NULL) { 461 printf("PluginManager::CreateWriter: NewWriter failed\n"); 462 PutPlugin(plugin); 463 return B_ERROR; 464 } 465 466 (*writer)->Setup(target); 467 (*writer)->fMediaPlugin = plugin; 468 469 TRACE("PluginManager::CreateWriter leave\n"); 470 return B_OK; 471 } 472 473 474 void 475 PluginManager::DestroyWriter(Writer* writer) 476 { 477 if (writer != NULL) { 478 TRACE("PluginManager::DestroyWriter(%p (plugin: %p))\n", writer, 479 writer->fMediaPlugin); 480 // NOTE: We have to put the plug-in after deleting the writer, 481 // since otherwise we may actually unload the code for the 482 // destructor... 483 MediaPlugin* plugin = writer->fMediaPlugin; 484 delete writer; 485 PutPlugin(plugin); 486 } 487 } 488 489 490 status_t 491 PluginManager::CreateEncoder(Encoder** _encoder, 492 const media_codec_info* codecInfo, uint32 flags) 493 { 494 TRACE("PluginManager::CreateEncoder enter\n"); 495 496 // Get encoder for this codec info from the server 497 entry_ref ref; 498 status_t ret = AddOnManager::GetInstance()->GetEncoder(&ref, 499 codecInfo->id); 500 if (ret != B_OK) { 501 printf("PluginManager::CreateEncoder: can't get encoder for codec %s: " 502 "%s\n", codecInfo->pretty_name, strerror(ret)); 503 return ret; 504 } 505 506 MediaPlugin* plugin = GetPlugin(ref); 507 if (!plugin) { 508 printf("PluginManager::CreateEncoder: GetPlugin failed\n"); 509 return B_ERROR; 510 } 511 512 EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin); 513 if (encoderPlugin == NULL) { 514 printf("PluginManager::CreateEncoder: dynamic_cast failed\n"); 515 PutPlugin(plugin); 516 return B_ERROR; 517 } 518 519 *_encoder = encoderPlugin->NewEncoder(*codecInfo); 520 if (*_encoder == NULL) { 521 printf("PluginManager::CreateEncoder: NewEncoder() failed\n"); 522 PutPlugin(plugin); 523 return B_ERROR; 524 } 525 TRACE(" created encoder: %p\n", *_encoder); 526 (*_encoder)->fMediaPlugin = plugin; 527 528 TRACE("PluginManager::CreateEncoder leave\n"); 529 530 return B_OK; 531 } 532 533 534 status_t 535 PluginManager::CreateEncoder(Encoder** encoder, const media_format& format) 536 { 537 TRACE("PluginManager::CreateEncoder enter nr2\n"); 538 539 entry_ref ref; 540 541 status_t ret = AddOnManager::GetInstance()->GetEncoderForFormat( 542 &ref, format); 543 544 if (ret != B_OK) { 545 ERROR("PluginManager::CreateEncoder: can't get decoder for format: " 546 "%s\n", strerror(ret)); 547 return ret; 548 } 549 550 MediaPlugin* plugin = GetPlugin(ref); 551 if (plugin == NULL) { 552 ERROR("PluginManager::CreateEncoder: GetPlugin failed\n"); 553 return B_ERROR; 554 } 555 556 EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin); 557 if (encoderPlugin == NULL) { 558 ERROR("PluginManager::CreateEncoder: dynamic_cast failed\n"); 559 PutPlugin(plugin); 560 return B_ERROR; 561 } 562 563 564 *encoder = encoderPlugin->NewEncoder(format); 565 if (*encoder == NULL) { 566 ERROR("PluginManager::CreateEncoder: NewEncoder() failed\n"); 567 PutPlugin(plugin); 568 return B_ERROR; 569 } 570 TRACE(" created encoder: %p\n", *encoder); 571 (*encoder)->fMediaPlugin = plugin; 572 573 TRACE("PluginManager::CreateEncoder leave nr2\n"); 574 575 return B_OK; 576 } 577 578 579 void 580 PluginManager::DestroyEncoder(Encoder* encoder) 581 { 582 if (encoder != NULL) { 583 TRACE("PluginManager::DestroyEncoder(%p, plugin: %p)\n", encoder, 584 encoder->fMediaPlugin); 585 // NOTE: We have to put the plug-in after deleting the encoder, 586 // since otherwise we may actually unload the code for the 587 // destructor... 588 MediaPlugin* plugin = encoder->fMediaPlugin; 589 delete encoder; 590 PutPlugin(plugin); 591 } 592 } 593 594 595 status_t 596 PluginManager::CreateStreamer(Streamer** streamer, BUrl url, BDataIO** source) 597 { 598 TRACE("PluginManager::CreateStreamer enter\n"); 599 600 entry_ref refs[MAX_STREAMERS]; 601 int32 count; 602 603 status_t ret = AddOnManager::GetInstance()->GetStreamers(refs, &count, 604 MAX_STREAMERS); 605 if (ret != B_OK) { 606 printf("PluginManager::CreateStreamer: can't get list of streamers:" 607 " %s\n", strerror(ret)); 608 return ret; 609 } 610 611 // try each reader by calling it's Sniff function... 612 for (int32 i = 0; i < count; i++) { 613 entry_ref ref = refs[i]; 614 MediaPlugin* plugin = GetPlugin(ref); 615 if (plugin == NULL) { 616 printf("PluginManager::CreateStreamer: GetPlugin failed\n"); 617 return B_ERROR; 618 } 619 620 StreamerPlugin* streamerPlugin = dynamic_cast<StreamerPlugin*>(plugin); 621 if (streamerPlugin == NULL) { 622 printf("PluginManager::CreateStreamer: dynamic_cast failed\n"); 623 PutPlugin(plugin); 624 return B_ERROR; 625 } 626 627 *streamer = streamerPlugin->NewStreamer(); 628 if (*streamer == NULL) { 629 printf("PluginManager::CreateStreamer: NewReader failed\n"); 630 PutPlugin(plugin); 631 return B_ERROR; 632 } 633 634 (*streamer)->fMediaPlugin = plugin; 635 (*streamer)->fReference.AcquireReference(); 636 637 BDataIO* streamSource = NULL; 638 if ((*streamer)->Sniff(url, &streamSource) == B_OK) { 639 TRACE("PluginManager::CreateStreamer: Sniff success\n"); 640 *source = streamSource; 641 return B_OK; 642 } 643 644 DestroyStreamer(*streamer); 645 *streamer = NULL; 646 } 647 648 TRACE("PluginManager::CreateStreamer leave\n"); 649 return B_MEDIA_NO_HANDLER; 650 } 651 652 653 void 654 PluginManager::DestroyStreamer(Streamer* streamer) 655 { 656 if (streamer != NULL) { 657 TRACE("PluginManager::DestroyStreamer(%p, plugin: %p)\n", streamer, 658 streamer->fMediaPlugin); 659 // NOTE: We have to put the plug-in after deleting the streamer, 660 // since otherwise we may actually unload the code for the 661 // destructor... 662 663 MediaPlugin* plugin = streamer->fMediaPlugin; 664 // Delete the streamer only when every reference is released 665 // we avoid to call ReleaseReference on the last object 666 // and handle deletion when the streamer is destroyed. 667 if (streamer->fReference.CountReferences() == 1) { 668 delete streamer; 669 PutPlugin(plugin); 670 } else 671 streamer->fReference.ReleaseReference(); 672 } 673 } 674 675 676 // #pragma mark - 677 678 679 PluginManager::PluginManager() 680 : 681 fPluginList(), 682 fLocker("media plugin manager") 683 { 684 CALLED(); 685 } 686 687 688 PluginManager::~PluginManager() 689 { 690 CALLED(); 691 for (int i = fPluginList.CountItems() - 1; i >= 0; i--) { 692 plugin_info* info = NULL; 693 fPluginList.Get(i, &info); 694 TRACE("PluginManager: Error, unloading PlugIn %s with usecount " 695 "%d\n", info->name, info->usecount); 696 delete info->plugin; 697 unload_add_on(info->image); 698 } 699 } 700 701 702 MediaPlugin* 703 PluginManager::GetPlugin(const entry_ref& ref) 704 { 705 TRACE("PluginManager::GetPlugin(%s)\n", ref.name); 706 fLocker.Lock(); 707 708 MediaPlugin* plugin; 709 plugin_info* pinfo; 710 plugin_info info; 711 712 for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) { 713 if (0 == strcmp(ref.name, pinfo->name)) { 714 plugin = pinfo->plugin; 715 pinfo->usecount++; 716 TRACE(" found existing plugin: %p\n", pinfo->plugin); 717 fLocker.Unlock(); 718 return plugin; 719 } 720 } 721 722 if (_LoadPlugin(ref, &info.plugin, &info.image) < B_OK) { 723 printf("PluginManager: Error, loading PlugIn %s failed\n", ref.name); 724 fLocker.Unlock(); 725 return NULL; 726 } 727 728 strcpy(info.name, ref.name); 729 info.usecount = 1; 730 fPluginList.Insert(info); 731 732 TRACE("PluginManager: PlugIn %s loaded\n", ref.name); 733 734 plugin = info.plugin; 735 TRACE(" loaded plugin: %p\n", plugin); 736 737 fLocker.Unlock(); 738 return plugin; 739 } 740 741 742 void 743 PluginManager::PutPlugin(MediaPlugin* plugin) 744 { 745 TRACE("PluginManager::PutPlugin()\n"); 746 fLocker.Lock(); 747 748 plugin_info* pinfo; 749 750 for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) { 751 if (plugin == pinfo->plugin) { 752 pinfo->usecount--; 753 if (pinfo->usecount == 0) { 754 TRACE(" deleting %p\n", pinfo->plugin); 755 delete pinfo->plugin; 756 TRACE(" unloading add-on: %" B_PRId32 "\n\n", pinfo->image); 757 unload_add_on(pinfo->image); 758 fPluginList.RemoveCurrent(); 759 } 760 fLocker.Unlock(); 761 return; 762 } 763 } 764 765 printf("PluginManager: Error, can't put PlugIn %p\n", plugin); 766 767 fLocker.Unlock(); 768 } 769 770 771 status_t 772 PluginManager::_LoadPlugin(const entry_ref& ref, MediaPlugin** plugin, 773 image_id* image) 774 { 775 BPath p(&ref); 776 777 TRACE("PluginManager: _LoadPlugin trying to load %s\n", p.Path()); 778 779 image_id id; 780 id = load_add_on(p.Path()); 781 if (id < 0) { 782 printf("PluginManager: Error, load_add_on(): %s\n", strerror(id)); 783 return B_ERROR; 784 } 785 786 MediaPlugin* (*instantiate_plugin_func)(); 787 788 if (get_image_symbol(id, "instantiate_plugin", B_SYMBOL_TYPE_TEXT, 789 (void**)&instantiate_plugin_func) < B_OK) { 790 printf("PluginManager: Error, _LoadPlugin can't find " 791 "instantiate_plugin in %s\n", p.Path()); 792 unload_add_on(id); 793 return B_ERROR; 794 } 795 796 MediaPlugin *pl; 797 798 pl = (*instantiate_plugin_func)(); 799 if (pl == NULL) { 800 printf("PluginManager: Error, _LoadPlugin instantiate_plugin in %s " 801 "returned NULL\n", p.Path()); 802 unload_add_on(id); 803 return B_ERROR; 804 } 805 806 *plugin = pl; 807 *image = id; 808 return B_OK; 809 } 810