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 // TODO 155 debugger("not implemented"); 156 return B_ERROR; 157 } 158 159 160 status_t 161 PluginManager::GetDecoderInfo(Decoder* decoder, media_codec_info* _info) const 162 { 163 if (decoder == NULL) 164 return B_BAD_VALUE; 165 166 decoder->GetCodecInfo(_info); 167 // TODO: 168 // out_info->id = 169 // out_info->sub_id = 170 return B_OK; 171 } 172 173 174 void 175 PluginManager::DestroyDecoder(Decoder* decoder) 176 { 177 if (decoder != NULL) { 178 TRACE("PluginManager::DestroyDecoder(%p, plugin: %p)\n", decoder, 179 decoder->fMediaPlugin); 180 // NOTE: We have to put the plug-in after deleting the decoder, 181 // since otherwise we may actually unload the code for the 182 // destructor... 183 MediaPlugin* plugin = decoder->fMediaPlugin; 184 delete decoder; 185 PutPlugin(plugin); 186 } 187 } 188 189 190 // #pragma mark - Writers/Encoders 191 192 193 status_t 194 PluginManager::CreateWriter(Writer** writer, const media_file_format& mff, 195 BDataIO* target) 196 { 197 TRACE("PluginManager::CreateWriter enter\n"); 198 199 // Get the Writer responsible for this media_file_format from the server. 200 entry_ref ref; 201 status_t ret = AddOnManager::GetInstance()->GetWriter(&ref, 202 mff.id.internal_id); 203 if (ret != B_OK) { 204 printf("PluginManager::CreateWriter: can't get writer for file " 205 "family: %s\n", strerror(ret)); 206 return ret; 207 } 208 209 MediaPlugin* plugin = GetPlugin(ref); 210 if (plugin == NULL) { 211 printf("PluginManager::CreateWriter: GetPlugin failed\n"); 212 return B_ERROR; 213 } 214 215 WriterPlugin* writerPlugin = dynamic_cast<WriterPlugin*>(plugin); 216 if (writerPlugin == NULL) { 217 printf("PluginManager::CreateWriter: dynamic_cast failed\n"); 218 PutPlugin(plugin); 219 return B_ERROR; 220 } 221 222 *writer = writerPlugin->NewWriter(); 223 if (*writer == NULL) { 224 printf("PluginManager::CreateWriter: NewWriter failed\n"); 225 PutPlugin(plugin); 226 return B_ERROR; 227 } 228 229 (*writer)->Setup(target); 230 (*writer)->fMediaPlugin = plugin; 231 232 TRACE("PluginManager::CreateWriter leave\n"); 233 return B_OK; 234 } 235 236 237 void 238 PluginManager::DestroyWriter(Writer* writer) 239 { 240 if (writer != NULL) { 241 TRACE("PluginManager::DestroyWriter(%p (plugin: %p))\n", writer, 242 writer->fMediaPlugin); 243 // NOTE: We have to put the plug-in after deleting the writer, 244 // since otherwise we may actually unload the code for the 245 // destructor... 246 MediaPlugin* plugin = writer->fMediaPlugin; 247 delete writer; 248 PutPlugin(plugin); 249 } 250 } 251 252 253 status_t 254 PluginManager::CreateEncoder(Encoder** _encoder, 255 const media_codec_info* codecInfo, uint32 flags) 256 { 257 TRACE("PluginManager::CreateEncoder enter\n"); 258 259 // Get encoder for this codec info from the server 260 entry_ref ref; 261 status_t ret = AddOnManager::GetInstance()->GetEncoder(&ref, 262 codecInfo->id); 263 if (ret != B_OK) { 264 printf("PluginManager::CreateEncoder: can't get encoder for codec %s: " 265 "%s\n", codecInfo->pretty_name, strerror(ret)); 266 return ret; 267 } 268 269 MediaPlugin* plugin = GetPlugin(ref); 270 if (!plugin) { 271 printf("PluginManager::CreateEncoder: GetPlugin failed\n"); 272 return B_ERROR; 273 } 274 275 EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin); 276 if (encoderPlugin == NULL) { 277 printf("PluginManager::CreateEncoder: dynamic_cast failed\n"); 278 PutPlugin(plugin); 279 return B_ERROR; 280 } 281 282 *_encoder = encoderPlugin->NewEncoder(*codecInfo); 283 if (*_encoder == NULL) { 284 printf("PluginManager::CreateEncoder: NewEncoder() failed\n"); 285 PutPlugin(plugin); 286 return B_ERROR; 287 } 288 TRACE(" created encoder: %p\n", *_encoder); 289 (*_encoder)->fMediaPlugin = plugin; 290 291 TRACE("PluginManager::CreateEncoder leave\n"); 292 293 return B_OK; 294 } 295 296 297 void 298 PluginManager::DestroyEncoder(Encoder* encoder) 299 { 300 if (encoder != NULL) { 301 TRACE("PluginManager::DestroyEncoder(%p, plugin: %p)\n", encoder, 302 encoder->fMediaPlugin); 303 // NOTE: We have to put the plug-in after deleting the encoder, 304 // since otherwise we may actually unload the code for the 305 // destructor... 306 MediaPlugin* plugin = encoder->fMediaPlugin; 307 delete encoder; 308 PutPlugin(plugin); 309 } 310 } 311 312 313 // #pragma mark - 314 315 316 PluginManager::PluginManager() 317 : 318 fPluginList(), 319 fLocker("media plugin manager") 320 { 321 CALLED(); 322 } 323 324 325 PluginManager::~PluginManager() 326 { 327 CALLED(); 328 for (int i = fPluginList.CountItems() - 1; i >= 0; i--) { 329 plugin_info* info = NULL; 330 fPluginList.Get(i, &info); 331 TRACE("PluginManager: Error, unloading PlugIn %s with usecount " 332 "%d\n", info->name, info->usecount); 333 delete info->plugin; 334 unload_add_on(info->image); 335 } 336 } 337 338 339 MediaPlugin* 340 PluginManager::GetPlugin(const entry_ref& ref) 341 { 342 TRACE("PluginManager::GetPlugin(%s)\n", ref.name); 343 fLocker.Lock(); 344 345 MediaPlugin* plugin; 346 plugin_info* pinfo; 347 plugin_info info; 348 349 for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) { 350 if (0 == strcmp(ref.name, pinfo->name)) { 351 plugin = pinfo->plugin; 352 pinfo->usecount++; 353 TRACE(" found existing plugin: %p\n", pinfo->plugin); 354 fLocker.Unlock(); 355 return plugin; 356 } 357 } 358 359 if (_LoadPlugin(ref, &info.plugin, &info.image) < B_OK) { 360 printf("PluginManager: Error, loading PlugIn %s failed\n", ref.name); 361 fLocker.Unlock(); 362 return NULL; 363 } 364 365 strcpy(info.name, ref.name); 366 info.usecount = 1; 367 fPluginList.Insert(info); 368 369 TRACE("PluginManager: PlugIn %s loaded\n", ref.name); 370 371 plugin = info.plugin; 372 TRACE(" loaded plugin: %p\n", plugin); 373 374 fLocker.Unlock(); 375 return plugin; 376 } 377 378 379 void 380 PluginManager::PutPlugin(MediaPlugin* plugin) 381 { 382 TRACE("PluginManager::PutPlugin()\n"); 383 fLocker.Lock(); 384 385 plugin_info* pinfo; 386 387 for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) { 388 if (plugin == pinfo->plugin) { 389 pinfo->usecount--; 390 if (pinfo->usecount == 0) { 391 TRACE(" deleting %p\n", pinfo->plugin); 392 delete pinfo->plugin; 393 TRACE(" unloading add-on: %ld\n\n", pinfo->image); 394 unload_add_on(pinfo->image); 395 fPluginList.RemoveCurrent(); 396 } 397 fLocker.Unlock(); 398 return; 399 } 400 } 401 402 printf("PluginManager: Error, can't put PlugIn %p\n", plugin); 403 404 fLocker.Unlock(); 405 } 406 407 408 status_t 409 PluginManager::_LoadPlugin(const entry_ref& ref, MediaPlugin** plugin, 410 image_id* image) 411 { 412 BPath p(&ref); 413 414 TRACE("PluginManager: _LoadPlugin trying to load %s\n", p.Path()); 415 416 image_id id; 417 id = load_add_on(p.Path()); 418 if (id < 0) { 419 printf("PluginManager: Error, load_add_on(): %s\n", strerror(id)); 420 return B_ERROR; 421 } 422 423 MediaPlugin* (*instantiate_plugin_func)(); 424 425 if (get_image_symbol(id, "instantiate_plugin", B_SYMBOL_TYPE_TEXT, 426 (void**)&instantiate_plugin_func) < B_OK) { 427 printf("PluginManager: Error, _LoadPlugin can't find " 428 "instantiate_plugin in %s\n", p.Path()); 429 unload_add_on(id); 430 return B_ERROR; 431 } 432 433 MediaPlugin *pl; 434 435 pl = (*instantiate_plugin_func)(); 436 if (pl == NULL) { 437 printf("PluginManager: Error, _LoadPlugin instantiate_plugin in %s " 438 "returned NULL\n", p.Path()); 439 unload_add_on(id); 440 return B_ERROR; 441 } 442 443 *plugin = pl; 444 *image = id; 445 return B_OK; 446 } 447