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 "PluginManager.h" 11 #include "DataExchange.h" 12 #include "debug.h" 13 14 15 PluginManager gPluginManager; 16 17 18 // #pragma mark - Readers/Decoders 19 20 21 status_t 22 PluginManager::CreateReader(Reader** reader, int32* streamCount, 23 media_file_format* mff, BDataIO* source) 24 { 25 TRACE("PluginManager::CreateReader enter\n"); 26 27 BPositionIO *seekable_source = dynamic_cast<BPositionIO *>(source); 28 if (seekable_source == 0) { 29 printf("PluginManager::CreateReader: non-seekable sources not " 30 "supported yet\n"); 31 return B_ERROR; 32 } 33 34 // get list of available readers from the server 35 server_get_readers_request request; 36 server_get_readers_reply reply; 37 status_t ret = QueryServer(SERVER_GET_READERS, &request, sizeof(request), 38 &reply, sizeof(reply)); 39 if (ret != B_OK) { 40 printf("PluginManager::CreateReader: can't get list of readers: %s\n", 41 strerror(ret)); 42 return ret; 43 } 44 45 // try each reader by calling it's Sniff function... 46 for (int32 i = 0; i < reply.count; i++) { 47 entry_ref ref = reply.ref[i]; 48 MediaPlugin* plugin = GetPlugin(ref); 49 if (plugin == NULL) { 50 printf("PluginManager::CreateReader: GetPlugin failed\n"); 51 return B_ERROR; 52 } 53 54 ReaderPlugin* readerPlugin = dynamic_cast<ReaderPlugin*>(plugin); 55 if (readerPlugin == NULL) { 56 printf("PluginManager::CreateReader: dynamic_cast failed\n"); 57 PutPlugin(plugin); 58 return B_ERROR; 59 } 60 61 *reader = readerPlugin->NewReader(); 62 if (*reader == NULL) { 63 printf("PluginManager::CreateReader: NewReader failed\n"); 64 PutPlugin(plugin); 65 return B_ERROR; 66 } 67 68 seekable_source->Seek(0, SEEK_SET); 69 (*reader)->Setup(seekable_source); 70 (*reader)->fMediaPlugin = plugin; 71 72 if ((*reader)->Sniff(streamCount) == B_OK) { 73 TRACE("PluginManager::CreateReader: Sniff success " 74 "(%ld stream(s))\n", *streamCount); 75 (*reader)->GetFileFormatInfo(mff); 76 return B_OK; 77 } 78 79 DestroyReader(*reader); 80 *reader = NULL; 81 } 82 83 TRACE("PluginManager::CreateReader leave\n"); 84 return B_MEDIA_NO_HANDLER; 85 } 86 87 88 void 89 PluginManager::DestroyReader(Reader* reader) 90 { 91 if (reader != NULL) { 92 TRACE("PluginManager::DestroyReader(%p (plugin: %p))\n", reader, 93 reader->fMediaPlugin); 94 // NOTE: We have to put the plug-in after deleting the reader, 95 // since otherwise we may actually unload the code for the 96 // destructor... 97 MediaPlugin* plugin = reader->fMediaPlugin; 98 delete reader; 99 PutPlugin(plugin); 100 } 101 } 102 103 104 status_t 105 PluginManager::CreateDecoder(Decoder** _decoder, const media_format& format) 106 { 107 TRACE("PluginManager::CreateDecoder enter\n"); 108 109 // get decoder for this format from the server 110 server_get_decoder_for_format_request request; 111 server_get_decoder_for_format_reply reply; 112 request.format = format; 113 status_t ret = QueryServer(SERVER_GET_DECODER_FOR_FORMAT, &request, 114 sizeof(request), &reply, sizeof(reply)); 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(reply.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 server_get_writer_request request; 201 request.internal_id = mff.id.internal_id; 202 server_get_writer_reply reply; 203 status_t ret = QueryServer(SERVER_GET_WRITER_FOR_FORMAT_FAMILY, &request, 204 sizeof(request), &reply, sizeof(reply)); 205 if (ret != B_OK) { 206 printf("PluginManager::CreateWriter: can't get writer for file " 207 "family: %s\n", strerror(ret)); 208 return ret; 209 } 210 211 MediaPlugin* plugin = GetPlugin(reply.ref); 212 if (plugin == NULL) { 213 printf("PluginManager::CreateWriter: GetPlugin failed\n"); 214 return B_ERROR; 215 } 216 217 WriterPlugin* writerPlugin = dynamic_cast<WriterPlugin*>(plugin); 218 if (writerPlugin == NULL) { 219 printf("PluginManager::CreateWriter: dynamic_cast failed\n"); 220 PutPlugin(plugin); 221 return B_ERROR; 222 } 223 224 *writer = writerPlugin->NewWriter(); 225 if (*writer == NULL) { 226 printf("PluginManager::CreateWriter: NewWriter failed\n"); 227 PutPlugin(plugin); 228 return B_ERROR; 229 } 230 231 (*writer)->Setup(target); 232 (*writer)->fMediaPlugin = plugin; 233 234 TRACE("PluginManager::CreateWriter leave\n"); 235 return B_OK; 236 } 237 238 239 void 240 PluginManager::DestroyWriter(Writer* writer) 241 { 242 if (writer != NULL) { 243 TRACE("PluginManager::DestroyWriter(%p (plugin: %p))\n", writer, 244 reader->fMediaPlugin); 245 // NOTE: We have to put the plug-in after deleting the writer, 246 // since otherwise we may actually unload the code for the 247 // destructor... 248 MediaPlugin* plugin = writer->fMediaPlugin; 249 delete writer; 250 PutPlugin(plugin); 251 } 252 } 253 254 255 status_t 256 PluginManager::CreateEncoder(Encoder** _encoder, 257 const media_codec_info* codecInfo, uint32 flags) 258 { 259 TRACE("PluginManager::CreateEncoder enter\n"); 260 261 // Get encoder for this codec info from the server 262 server_get_encoder_for_codec_info_request request; 263 server_get_encoder_for_codec_info_reply reply; 264 request.id = codecInfo->id; 265 status_t ret = QueryServer(SERVER_GET_ENCODER_FOR_CODEC_INFO, &request, 266 sizeof(request), &reply, sizeof(reply)); 267 if (ret != B_OK) { 268 printf("PluginManager::CreateEncoder: can't get encoder for codec %s: " 269 "%s\n", codecInfo->pretty_name, strerror(ret)); 270 return ret; 271 } 272 273 MediaPlugin* plugin = GetPlugin(reply.ref); 274 if (!plugin) { 275 printf("PluginManager::CreateEncoder: GetPlugin failed\n"); 276 return B_ERROR; 277 } 278 279 EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin); 280 if (encoderPlugin == NULL) { 281 printf("PluginManager::CreateEncoder: dynamic_cast failed\n"); 282 PutPlugin(plugin); 283 return B_ERROR; 284 } 285 286 *_encoder = encoderPlugin->NewEncoder(*codecInfo); 287 if (*_encoder == NULL) { 288 printf("PluginManager::CreateEncoder: NewEncoder() failed\n"); 289 PutPlugin(plugin); 290 return B_ERROR; 291 } 292 TRACE(" created encoder: %p\n", *_encoder); 293 (*_encoder)->fMediaPlugin = plugin; 294 295 TRACE("PluginManager::CreateEncoder leave\n"); 296 297 return B_OK; 298 } 299 300 301 void 302 PluginManager::DestroyEncoder(Encoder* encoder) 303 { 304 if (encoder != NULL) { 305 TRACE("PluginManager::DestroyEncoder(%p, plugin: %p)\n", encoder, 306 encoder->fMediaPlugin); 307 // NOTE: We have to put the plug-in after deleting the encoder, 308 // since otherwise we may actually unload the code for the 309 // destructor... 310 MediaPlugin* plugin = encoder->fMediaPlugin; 311 delete encoder; 312 PutPlugin(plugin); 313 } 314 } 315 316 317 // #pragma mark - 318 319 320 PluginManager::PluginManager() 321 : 322 fPluginList(), 323 fLocker("media plugin manager") 324 { 325 CALLED(); 326 } 327 328 329 PluginManager::~PluginManager() 330 { 331 CALLED(); 332 for (int i = fPluginList.CountItems() - 1; i >= 0; i--) { 333 plugin_info* info = NULL; 334 fPluginList.Get(i, &info); 335 printf("PluginManager: Error, unloading PlugIn %s with usecount " 336 "%d\n", info->name, info->usecount); 337 delete info->plugin; 338 unload_add_on(info->image); 339 } 340 } 341 342 343 MediaPlugin* 344 PluginManager::GetPlugin(const entry_ref& ref) 345 { 346 TRACE("PluginManager::GetPlugin(%s)\n", ref.name); 347 fLocker.Lock(); 348 349 MediaPlugin* plugin; 350 plugin_info* pinfo; 351 plugin_info info; 352 353 for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) { 354 if (0 == strcmp(ref.name, pinfo->name)) { 355 plugin = pinfo->plugin; 356 pinfo->usecount++; 357 TRACE(" found existing plugin: %p\n", pinfo->plugin); 358 fLocker.Unlock(); 359 return plugin; 360 } 361 } 362 363 if (_LoadPlugin(ref, &info.plugin, &info.image) < B_OK) { 364 printf("PluginManager: Error, loading PlugIn %s failed\n", ref.name); 365 fLocker.Unlock(); 366 return NULL; 367 } 368 369 strcpy(info.name, ref.name); 370 info.usecount = 1; 371 fPluginList.Insert(info); 372 373 TRACE("PluginManager: PlugIn %s loaded\n", ref.name); 374 375 plugin = info.plugin; 376 TRACE(" loaded plugin: %p\n", plugin); 377 378 fLocker.Unlock(); 379 return plugin; 380 } 381 382 383 void 384 PluginManager::PutPlugin(MediaPlugin* plugin) 385 { 386 TRACE("PluginManager::PutPlugin()\n"); 387 fLocker.Lock(); 388 389 plugin_info* pinfo; 390 391 for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) { 392 if (plugin == pinfo->plugin) { 393 pinfo->usecount--; 394 if (pinfo->usecount == 0) { 395 TRACE(" deleting %p\n", pinfo->plugin); 396 delete pinfo->plugin; 397 TRACE(" unloading add-on: %ld\n\n", pinfo->image); 398 unload_add_on(pinfo->image); 399 fPluginList.RemoveCurrent(); 400 } 401 fLocker.Unlock(); 402 return; 403 } 404 } 405 406 printf("PluginManager: Error, can't put PlugIn %p\n", plugin); 407 408 fLocker.Unlock(); 409 } 410 411 412 status_t 413 PluginManager::_LoadPlugin(const entry_ref& ref, MediaPlugin** plugin, 414 image_id* image) 415 { 416 BPath p(&ref); 417 418 TRACE("PluginManager: _LoadPlugin trying to load %s\n", p.Path()); 419 420 image_id id; 421 id = load_add_on(p.Path()); 422 if (id < 0) { 423 printf("PluginManager: Error, load_add_on(): %s\n", strerror(id)); 424 return B_ERROR; 425 } 426 427 MediaPlugin* (*instantiate_plugin_func)(); 428 429 if (get_image_symbol(id, "instantiate_plugin", B_SYMBOL_TYPE_TEXT, 430 (void**)&instantiate_plugin_func) < B_OK) { 431 printf("PluginManager: Error, _LoadPlugin can't find " 432 "instantiate_plugin in %s\n", p.Path()); 433 unload_add_on(id); 434 return B_ERROR; 435 } 436 437 MediaPlugin *pl; 438 439 pl = (*instantiate_plugin_func)(); 440 if (pl == NULL) { 441 printf("PluginManager: Error, _LoadPlugin instantiate_plugin in %s " 442 "returned NULL\n", p.Path()); 443 unload_add_on(id); 444 return B_ERROR; 445 } 446 447 *plugin = pl; 448 *image = id; 449 return B_OK; 450 } 451