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