1 /* 2 * Copyright 2004-2010, Marcus Overhagen. All rights reserved. 3 * Distributed under the terms of the OpenBeOS License. 4 */ 5 6 #include <Path.h> 7 #include <image.h> 8 #include <string.h> 9 10 #include "AddOnManager.h" 11 #include "PluginManager.h" 12 #include "DataExchange.h" 13 #include "debug.h" 14 15 16 PluginManager gPluginManager; 17 18 19 // #pragma mark - Readers/Decoders 20 21 22 status_t 23 PluginManager::CreateReader(Reader** reader, int32* streamCount, 24 media_file_format* mff, BDataIO* source) 25 { 26 TRACE("PluginManager::CreateReader enter\n"); 27 28 BPositionIO *seekable_source = dynamic_cast<BPositionIO *>(source); 29 if (seekable_source == 0) { 30 printf("PluginManager::CreateReader: non-seekable sources not " 31 "supported yet\n"); 32 return B_ERROR; 33 } 34 35 // get list of available readers from the server 36 entry_ref refs[MAX_READERS]; 37 int32 count; 38 39 status_t ret = AddOnManager::GetInstance()->GetReaders(refs, &count, 40 MAX_READERS); 41 if (ret != B_OK) { 42 printf("PluginManager::CreateReader: can't get list of readers: %s\n", 43 strerror(ret)); 44 return ret; 45 } 46 47 // try each reader by calling it's Sniff function... 48 for (int32 i = 0; i < count; i++) { 49 entry_ref ref = refs[i]; 50 MediaPlugin* plugin = GetPlugin(ref); 51 if (plugin == NULL) { 52 printf("PluginManager::CreateReader: GetPlugin failed\n"); 53 return B_ERROR; 54 } 55 56 ReaderPlugin* readerPlugin = dynamic_cast<ReaderPlugin*>(plugin); 57 if (readerPlugin == NULL) { 58 printf("PluginManager::CreateReader: dynamic_cast failed\n"); 59 PutPlugin(plugin); 60 return B_ERROR; 61 } 62 63 *reader = readerPlugin->NewReader(); 64 if (*reader == NULL) { 65 printf("PluginManager::CreateReader: NewReader failed\n"); 66 PutPlugin(plugin); 67 return B_ERROR; 68 } 69 70 seekable_source->Seek(0, SEEK_SET); 71 (*reader)->Setup(seekable_source); 72 (*reader)->fMediaPlugin = plugin; 73 74 if ((*reader)->Sniff(streamCount) == B_OK) { 75 TRACE("PluginManager::CreateReader: Sniff success " 76 "(%ld stream(s))\n", *streamCount); 77 (*reader)->GetFileFormatInfo(mff); 78 return B_OK; 79 } 80 81 DestroyReader(*reader); 82 *reader = NULL; 83 } 84 85 TRACE("PluginManager::CreateReader leave\n"); 86 return B_MEDIA_NO_HANDLER; 87 } 88 89 90 void 91 PluginManager::DestroyReader(Reader* reader) 92 { 93 if (reader != NULL) { 94 TRACE("PluginManager::DestroyReader(%p (plugin: %p))\n", reader, 95 reader->fMediaPlugin); 96 // NOTE: We have to put the plug-in after deleting the reader, 97 // since otherwise we may actually unload the code for the 98 // destructor... 99 MediaPlugin* plugin = reader->fMediaPlugin; 100 delete reader; 101 PutPlugin(plugin); 102 } 103 } 104 105 106 status_t 107 PluginManager::CreateDecoder(Decoder** _decoder, const media_format& format) 108 { 109 TRACE("PluginManager::CreateDecoder enter\n"); 110 111 // get decoder for this format 112 entry_ref ref; 113 status_t ret = AddOnManager::GetInstance()->GetDecoderForFormat( 114 &ref, format); 115 if (ret != B_OK) { 116 printf("PluginManager::CreateDecoder: can't get decoder for format: " 117 "%s\n", strerror(ret)); 118 return ret; 119 } 120 121 MediaPlugin* plugin = GetPlugin(ref); 122 if (plugin == NULL) { 123 printf("PluginManager::CreateDecoder: GetPlugin failed\n"); 124 return B_ERROR; 125 } 126 127 DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin); 128 if (decoderPlugin == NULL) { 129 printf("PluginManager::CreateDecoder: dynamic_cast failed\n"); 130 PutPlugin(plugin); 131 return B_ERROR; 132 } 133 134 // TODO: In theory, one DecoderPlugin could support multiple Decoders, 135 // but this is not yet handled (passing "0" as index/ID). 136 *_decoder = decoderPlugin->NewDecoder(0); 137 if (*_decoder == NULL) { 138 printf("PluginManager::CreateDecoder: NewDecoder() failed\n"); 139 PutPlugin(plugin); 140 return B_ERROR; 141 } 142 TRACE(" created decoder: %p\n", *_decoder); 143 (*_decoder)->fMediaPlugin = plugin; 144 145 TRACE("PluginManager::CreateDecoder leave\n"); 146 147 return B_OK; 148 } 149 150 151 status_t 152 PluginManager::CreateDecoder(Decoder** decoder, const media_codec_info& mci) 153 { 154 TRACE("PluginManager::CreateDecoder enter\n"); 155 entry_ref ref; 156 status_t status = AddOnManager::GetInstance()->GetEncoder(&ref, mci.id); 157 if (status != B_OK) 158 return status; 159 160 MediaPlugin* plugin = GetPlugin(ref); 161 if (plugin == NULL) { 162 ERROR("PluginManager::CreateDecoder: GetPlugin failed\n"); 163 return B_ERROR; 164 } 165 166 DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin); 167 if (decoderPlugin == NULL) { 168 ERROR("PluginManager::CreateDecoder: dynamic_cast failed\n"); 169 PutPlugin(plugin); 170 return B_ERROR; 171 } 172 173 // TODO: In theory, one DecoderPlugin could support multiple Decoders, 174 // but this is not yet handled (passing "0" as index/ID). 175 *decoder = decoderPlugin->NewDecoder(0); 176 if (*decoder == NULL) { 177 ERROR("PluginManager::CreateDecoder: NewDecoder() failed\n"); 178 PutPlugin(plugin); 179 return B_ERROR; 180 } 181 TRACE(" created decoder: %p\n", *decoder); 182 (*decoder)->fMediaPlugin = plugin; 183 184 TRACE("PluginManager::CreateDecoder leave\n"); 185 186 return B_OK; 187 188 } 189 190 191 status_t 192 PluginManager::GetDecoderInfo(Decoder* decoder, media_codec_info* _info) const 193 { 194 if (decoder == NULL) 195 return B_BAD_VALUE; 196 197 decoder->GetCodecInfo(_info); 198 // TODO: 199 // out_info->id = 200 // out_info->sub_id = 201 return B_OK; 202 } 203 204 205 void 206 PluginManager::DestroyDecoder(Decoder* decoder) 207 { 208 if (decoder != NULL) { 209 TRACE("PluginManager::DestroyDecoder(%p, plugin: %p)\n", decoder, 210 decoder->fMediaPlugin); 211 // NOTE: We have to put the plug-in after deleting the decoder, 212 // since otherwise we may actually unload the code for the 213 // destructor... 214 MediaPlugin* plugin = decoder->fMediaPlugin; 215 delete decoder; 216 PutPlugin(plugin); 217 } 218 } 219 220 221 // #pragma mark - Writers/Encoders 222 223 224 status_t 225 PluginManager::CreateWriter(Writer** writer, const media_file_format& mff, 226 BDataIO* target) 227 { 228 TRACE("PluginManager::CreateWriter enter\n"); 229 230 // Get the Writer responsible for this media_file_format from the server. 231 entry_ref ref; 232 status_t ret = AddOnManager::GetInstance()->GetWriter(&ref, 233 mff.id.internal_id); 234 if (ret != B_OK) { 235 printf("PluginManager::CreateWriter: can't get writer for file " 236 "family: %s\n", strerror(ret)); 237 return ret; 238 } 239 240 MediaPlugin* plugin = GetPlugin(ref); 241 if (plugin == NULL) { 242 printf("PluginManager::CreateWriter: GetPlugin failed\n"); 243 return B_ERROR; 244 } 245 246 WriterPlugin* writerPlugin = dynamic_cast<WriterPlugin*>(plugin); 247 if (writerPlugin == NULL) { 248 printf("PluginManager::CreateWriter: dynamic_cast failed\n"); 249 PutPlugin(plugin); 250 return B_ERROR; 251 } 252 253 *writer = writerPlugin->NewWriter(); 254 if (*writer == NULL) { 255 printf("PluginManager::CreateWriter: NewWriter failed\n"); 256 PutPlugin(plugin); 257 return B_ERROR; 258 } 259 260 (*writer)->Setup(target); 261 (*writer)->fMediaPlugin = plugin; 262 263 TRACE("PluginManager::CreateWriter leave\n"); 264 return B_OK; 265 } 266 267 268 void 269 PluginManager::DestroyWriter(Writer* writer) 270 { 271 if (writer != NULL) { 272 TRACE("PluginManager::DestroyWriter(%p (plugin: %p))\n", writer, 273 writer->fMediaPlugin); 274 // NOTE: We have to put the plug-in after deleting the writer, 275 // since otherwise we may actually unload the code for the 276 // destructor... 277 MediaPlugin* plugin = writer->fMediaPlugin; 278 delete writer; 279 PutPlugin(plugin); 280 } 281 } 282 283 284 status_t 285 PluginManager::CreateEncoder(Encoder** _encoder, 286 const media_codec_info* codecInfo, uint32 flags) 287 { 288 TRACE("PluginManager::CreateEncoder enter\n"); 289 290 // Get encoder for this codec info from the server 291 entry_ref ref; 292 status_t ret = AddOnManager::GetInstance()->GetEncoder(&ref, 293 codecInfo->id); 294 if (ret != B_OK) { 295 printf("PluginManager::CreateEncoder: can't get encoder for codec %s: " 296 "%s\n", codecInfo->pretty_name, strerror(ret)); 297 return ret; 298 } 299 300 MediaPlugin* plugin = GetPlugin(ref); 301 if (!plugin) { 302 printf("PluginManager::CreateEncoder: GetPlugin failed\n"); 303 return B_ERROR; 304 } 305 306 EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin); 307 if (encoderPlugin == NULL) { 308 printf("PluginManager::CreateEncoder: dynamic_cast failed\n"); 309 PutPlugin(plugin); 310 return B_ERROR; 311 } 312 313 *_encoder = encoderPlugin->NewEncoder(*codecInfo); 314 if (*_encoder == NULL) { 315 printf("PluginManager::CreateEncoder: NewEncoder() failed\n"); 316 PutPlugin(plugin); 317 return B_ERROR; 318 } 319 TRACE(" created encoder: %p\n", *_encoder); 320 (*_encoder)->fMediaPlugin = plugin; 321 322 TRACE("PluginManager::CreateEncoder leave\n"); 323 324 return B_OK; 325 } 326 327 328 status_t 329 PluginManager::CreateEncoder(Encoder** encoder, const media_format& format) 330 { 331 TRACE("PluginManager::CreateEncoder enter nr2\n"); 332 333 entry_ref ref; 334 335 status_t ret = AddOnManager::GetInstance()->GetEncoderForFormat( 336 &ref, format); 337 338 if (ret != B_OK) { 339 ERROR("PluginManager::CreateEncoder: can't get decoder for format: " 340 "%s\n", strerror(ret)); 341 return ret; 342 } 343 344 MediaPlugin* plugin = GetPlugin(ref); 345 if (plugin == NULL) { 346 ERROR("PluginManager::CreateEncoder: GetPlugin failed\n"); 347 return B_ERROR; 348 } 349 350 EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin); 351 if (encoderPlugin == NULL) { 352 ERROR("PluginManager::CreateEncoder: dynamic_cast failed\n"); 353 PutPlugin(plugin); 354 return B_ERROR; 355 } 356 357 358 *encoder = encoderPlugin->NewEncoder(format); 359 if (*encoder == NULL) { 360 ERROR("PluginManager::CreateEncoder: NewEncoder() failed\n"); 361 PutPlugin(plugin); 362 return B_ERROR; 363 } 364 TRACE(" created encoder: %p\n", *encoder); 365 (*encoder)->fMediaPlugin = plugin; 366 367 TRACE("PluginManager::CreateEncoder leave nr2\n"); 368 369 return B_OK; 370 } 371 372 373 void 374 PluginManager::DestroyEncoder(Encoder* encoder) 375 { 376 if (encoder != NULL) { 377 TRACE("PluginManager::DestroyEncoder(%p, plugin: %p)\n", encoder, 378 encoder->fMediaPlugin); 379 // NOTE: We have to put the plug-in after deleting the encoder, 380 // since otherwise we may actually unload the code for the 381 // destructor... 382 MediaPlugin* plugin = encoder->fMediaPlugin; 383 delete encoder; 384 PutPlugin(plugin); 385 } 386 } 387 388 389 // #pragma mark - 390 391 392 PluginManager::PluginManager() 393 : 394 fPluginList(), 395 fLocker("media plugin manager") 396 { 397 CALLED(); 398 } 399 400 401 PluginManager::~PluginManager() 402 { 403 CALLED(); 404 for (int i = fPluginList.CountItems() - 1; i >= 0; i--) { 405 plugin_info* info = NULL; 406 fPluginList.Get(i, &info); 407 TRACE("PluginManager: Error, unloading PlugIn %s with usecount " 408 "%d\n", info->name, info->usecount); 409 delete info->plugin; 410 unload_add_on(info->image); 411 } 412 } 413 414 415 MediaPlugin* 416 PluginManager::GetPlugin(const entry_ref& ref) 417 { 418 TRACE("PluginManager::GetPlugin(%s)\n", ref.name); 419 fLocker.Lock(); 420 421 MediaPlugin* plugin; 422 plugin_info* pinfo; 423 plugin_info info; 424 425 for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) { 426 if (0 == strcmp(ref.name, pinfo->name)) { 427 plugin = pinfo->plugin; 428 pinfo->usecount++; 429 TRACE(" found existing plugin: %p\n", pinfo->plugin); 430 fLocker.Unlock(); 431 return plugin; 432 } 433 } 434 435 if (_LoadPlugin(ref, &info.plugin, &info.image) < B_OK) { 436 printf("PluginManager: Error, loading PlugIn %s failed\n", ref.name); 437 fLocker.Unlock(); 438 return NULL; 439 } 440 441 strcpy(info.name, ref.name); 442 info.usecount = 1; 443 fPluginList.Insert(info); 444 445 TRACE("PluginManager: PlugIn %s loaded\n", ref.name); 446 447 plugin = info.plugin; 448 TRACE(" loaded plugin: %p\n", plugin); 449 450 fLocker.Unlock(); 451 return plugin; 452 } 453 454 455 void 456 PluginManager::PutPlugin(MediaPlugin* plugin) 457 { 458 TRACE("PluginManager::PutPlugin()\n"); 459 fLocker.Lock(); 460 461 plugin_info* pinfo; 462 463 for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) { 464 if (plugin == pinfo->plugin) { 465 pinfo->usecount--; 466 if (pinfo->usecount == 0) { 467 TRACE(" deleting %p\n", pinfo->plugin); 468 delete pinfo->plugin; 469 TRACE(" unloading add-on: %ld\n\n", pinfo->image); 470 unload_add_on(pinfo->image); 471 fPluginList.RemoveCurrent(); 472 } 473 fLocker.Unlock(); 474 return; 475 } 476 } 477 478 printf("PluginManager: Error, can't put PlugIn %p\n", plugin); 479 480 fLocker.Unlock(); 481 } 482 483 484 status_t 485 PluginManager::_LoadPlugin(const entry_ref& ref, MediaPlugin** plugin, 486 image_id* image) 487 { 488 BPath p(&ref); 489 490 TRACE("PluginManager: _LoadPlugin trying to load %s\n", p.Path()); 491 492 image_id id; 493 id = load_add_on(p.Path()); 494 if (id < 0) { 495 printf("PluginManager: Error, load_add_on(): %s\n", strerror(id)); 496 return B_ERROR; 497 } 498 499 MediaPlugin* (*instantiate_plugin_func)(); 500 501 if (get_image_symbol(id, "instantiate_plugin", B_SYMBOL_TYPE_TEXT, 502 (void**)&instantiate_plugin_func) < B_OK) { 503 printf("PluginManager: Error, _LoadPlugin can't find " 504 "instantiate_plugin in %s\n", p.Path()); 505 unload_add_on(id); 506 return B_ERROR; 507 } 508 509 MediaPlugin *pl; 510 511 pl = (*instantiate_plugin_func)(); 512 if (pl == NULL) { 513 printf("PluginManager: Error, _LoadPlugin instantiate_plugin in %s " 514 "returned NULL\n", p.Path()); 515 unload_add_on(id); 516 return B_ERROR; 517 } 518 519 *plugin = pl; 520 *image = id; 521 return B_OK; 522 } 523