1 /* 2 * Copyright 2004-2009, The Haiku Project. All rights reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Axel Dörfler 7 * Marcus Overhagen 8 */ 9 10 #include <MediaFormats.h> 11 12 #include <CodecRoster.h> 13 #include <ObjectList.h> 14 #include <Message.h> 15 #include <Autolock.h> 16 17 #include "AddOnManager.h" 18 #include "DataExchange.h" 19 #include "FormatManager.h" 20 #include "MetaFormat.h" 21 #include "MediaDebug.h" 22 23 #include <string.h> 24 25 using namespace BPrivate::media; 26 27 28 static BLocker sLock; 29 static BObjectList<meta_format> sFormats; 30 static bigtime_t sLastFormatsUpdate; 31 32 33 status_t 34 get_next_encoder(int32* cookie, const media_file_format* fileFormat, 35 const media_format* inputFormat, media_format* _outputFormat, 36 media_codec_info* _codecInfo) 37 { 38 return BCodecKit::BCodecRoster::GetNextEncoder(cookie, fileFormat, 39 inputFormat, _outputFormat, _codecInfo); 40 } 41 42 43 status_t 44 get_next_encoder(int32* cookie, const media_file_format* fileFormat, 45 const media_format* inputFormat, const media_format* outputFormat, 46 media_codec_info* _codecInfo, media_format* _acceptedInputFormat, 47 media_format* _acceptedOutputFormat) 48 { 49 return BCodecKit::BCodecRoster::GetNextEncoder(cookie, fileFormat, 50 inputFormat, outputFormat, _codecInfo, _acceptedInputFormat, 51 _acceptedOutputFormat); 52 } 53 54 55 status_t 56 get_next_encoder(int32* cookie, media_codec_info* _codecInfo) 57 { 58 return BCodecKit::BCodecRoster::GetNextEncoder(cookie, _codecInfo); 59 } 60 61 62 bool 63 does_file_accept_format(const media_file_format* _fileFormat, 64 media_format* format, uint32 flags) 65 { 66 UNIMPLEMENTED(); 67 return false; 68 } 69 70 71 // #pragma mark - 72 73 74 _media_format_description::_media_format_description() 75 { 76 memset(this, 0, sizeof(*this)); 77 } 78 79 80 _media_format_description::~_media_format_description() 81 { 82 } 83 84 85 _media_format_description::_media_format_description( 86 const _media_format_description& other) 87 { 88 memcpy(this, &other, sizeof(*this)); 89 } 90 91 92 _media_format_description& 93 _media_format_description::operator=(const _media_format_description& other) 94 { 95 memcpy(this, &other, sizeof(*this)); 96 return *this; 97 } 98 99 100 bool 101 operator==(const media_format_description& a, 102 const media_format_description& b) 103 { 104 if (a.family != b.family) 105 return false; 106 107 switch (a.family) { 108 case B_BEOS_FORMAT_FAMILY: 109 return a.u.beos.format == b.u.beos.format; 110 case B_QUICKTIME_FORMAT_FAMILY: 111 return a.u.quicktime.codec == b.u.quicktime.codec 112 && a.u.quicktime.vendor == b.u.quicktime.vendor; 113 case B_AVI_FORMAT_FAMILY: 114 return a.u.avi.codec == b.u.avi.codec; 115 case B_ASF_FORMAT_FAMILY: 116 return a.u.asf.guid == b.u.asf.guid; 117 case B_MPEG_FORMAT_FAMILY: 118 return a.u.mpeg.id == b.u.mpeg.id; 119 case B_WAV_FORMAT_FAMILY: 120 return a.u.wav.codec == b.u.wav.codec; 121 case B_AIFF_FORMAT_FAMILY: 122 return a.u.aiff.codec == b.u.aiff.codec; 123 case B_AVR_FORMAT_FAMILY: 124 return a.u.avr.id == b.u.avr.id; 125 case B_MISC_FORMAT_FAMILY: 126 return a.u.misc.file_format == b.u.misc.file_format 127 && a.u.misc.codec == b.u.misc.codec; 128 129 default: 130 return false; 131 } 132 } 133 134 135 bool 136 operator<(const media_format_description& a, const media_format_description& b) 137 { 138 if (a.family != b.family) 139 return a.family < b.family; 140 141 switch (a.family) { 142 case B_BEOS_FORMAT_FAMILY: 143 return a.u.beos.format < b.u.beos.format; 144 case B_QUICKTIME_FORMAT_FAMILY: 145 if (a.u.quicktime.vendor == b.u.quicktime.vendor) 146 return a.u.quicktime.codec < b.u.quicktime.codec; 147 return a.u.quicktime.vendor < b.u.quicktime.vendor; 148 case B_AVI_FORMAT_FAMILY: 149 return a.u.avi.codec < b.u.avi.codec; 150 case B_ASF_FORMAT_FAMILY: 151 return a.u.asf.guid < b.u.asf.guid; 152 case B_MPEG_FORMAT_FAMILY: 153 return a.u.mpeg.id < b.u.mpeg.id; 154 case B_WAV_FORMAT_FAMILY: 155 return a.u.wav.codec < b.u.wav.codec; 156 case B_AIFF_FORMAT_FAMILY: 157 return a.u.aiff.codec < b.u.aiff.codec; 158 case B_AVR_FORMAT_FAMILY: 159 return a.u.avr.id < b.u.avr.id; 160 case B_MISC_FORMAT_FAMILY: 161 if (a.u.misc.file_format == b.u.misc.file_format) 162 return a.u.misc.codec < b.u.misc.codec; 163 return a.u.misc.file_format < b.u.misc.file_format; 164 165 default: 166 return true; 167 } 168 } 169 170 171 bool 172 operator==(const GUID& a, const GUID& b) 173 { 174 return memcmp(&a, &b, sizeof(a)) == 0; 175 } 176 177 178 bool 179 operator<(const GUID& a, const GUID& b) 180 { 181 return memcmp(&a, &b, sizeof(a)) < 0; 182 } 183 184 185 // #pragma mark - 186 // 187 // Some (meta) formats supply functions 188 189 190 meta_format::meta_format() 191 : 192 id(0) 193 { 194 } 195 196 197 198 meta_format::meta_format(const media_format_description& description, 199 const media_format& format, int32 id) 200 : 201 description(description), 202 format(format), 203 id(id) 204 { 205 } 206 207 208 meta_format::meta_format(const media_format_description& description) 209 : 210 description(description), 211 id(0) 212 { 213 } 214 215 216 meta_format::meta_format(const meta_format& other) 217 : 218 description(other.description), 219 format(other.format) 220 { 221 } 222 223 224 bool 225 meta_format::Matches(const media_format& otherFormat, 226 media_format_family family) 227 { 228 if (family != description.family) 229 return false; 230 231 return format.Matches(&otherFormat); 232 } 233 234 235 int 236 meta_format::CompareDescriptions(const meta_format* a, const meta_format* b) 237 { 238 if (a->description == b->description) 239 return 0; 240 241 if (a->description < b->description) 242 return -1; 243 244 return 1; 245 } 246 247 248 int 249 meta_format::Compare(const meta_format* a, const meta_format* b) 250 { 251 int compare = CompareDescriptions(a, b); 252 if (compare != 0) 253 return compare; 254 255 return a->id - b->id; 256 } 257 258 259 /** We share one global list for all BMediaFormats in the team - since the 260 * format data can change at any time, we have to update the list to ensure 261 * that we are working on the latest data set. The list is always sorted by 262 * description. The formats lock has to be held when you call this function. 263 */ 264 static status_t 265 update_media_formats() 266 { 267 if (!sLock.IsLocked()) 268 return B_NOT_ALLOWED; 269 270 // We want the add-ons to register themselves with the format manager, so 271 // the list is up to date. 272 BCodecKit::BPrivate::AddOnManager::GetInstance()->RegisterAddOns(); 273 274 BMessage reply; 275 FormatManager::GetInstance()->GetFormats(sLastFormatsUpdate, reply); 276 277 // do we need an update at all? 278 bool needUpdate; 279 if (reply.FindBool("need_update", &needUpdate) < B_OK) 280 return B_ERROR; 281 if (!needUpdate) 282 return B_OK; 283 284 // update timestamp and check if the message is okay 285 type_code code; 286 int32 count; 287 if (reply.FindInt64("timestamp", &sLastFormatsUpdate) < B_OK 288 || reply.GetInfo("formats", &code, &count) < B_OK) 289 return B_ERROR; 290 291 // overwrite already existing formats 292 293 int32 index = 0; 294 for (; index < sFormats.CountItems() && index < count; index++) { 295 meta_format* item = sFormats.ItemAt(index); 296 297 const meta_format* newItem; 298 ssize_t size; 299 if (reply.FindData("formats", MEDIA_META_FORMAT_TYPE, index, 300 (const void**)&newItem, &size) == B_OK) 301 *item = *newItem; 302 } 303 304 // allocate additional formats 305 306 for (; index < count; index++) { 307 const meta_format* newItem; 308 ssize_t size; 309 if (reply.FindData("formats", MEDIA_META_FORMAT_TYPE, index, 310 (const void**)&newItem, &size) == B_OK) 311 sFormats.AddItem(new meta_format(*newItem)); 312 } 313 314 // remove no longer used formats 315 316 while (count < sFormats.CountItems()) 317 delete sFormats.RemoveItemAt(count); 318 319 return B_OK; 320 } 321 322 323 // #pragma mark - 324 325 326 BMediaFormats::BMediaFormats() 327 : 328 fIteratorIndex(0) 329 { 330 } 331 332 333 BMediaFormats::~BMediaFormats() 334 { 335 } 336 337 338 status_t 339 BMediaFormats::InitCheck() 340 { 341 return sLock.Sem() >= B_OK ? B_OK : sLock.Sem(); 342 } 343 344 345 status_t 346 BMediaFormats::GetCodeFor(const media_format& format, 347 media_format_family family, 348 media_format_description* _description) 349 { 350 BAutolock locker(sLock); 351 352 status_t status = update_media_formats(); 353 if (status < B_OK) 354 return status; 355 356 // search for a matching format 357 358 for (int32 index = sFormats.CountItems(); index-- > 0;) { 359 meta_format* metaFormat = sFormats.ItemAt(index); 360 361 if (metaFormat->Matches(format, family)) { 362 *_description = metaFormat->description; 363 return B_OK; 364 } 365 } 366 367 return B_MEDIA_BAD_FORMAT; 368 } 369 370 371 status_t 372 BMediaFormats::GetFormatFor(const media_format_description& description, 373 media_format* _format) 374 { 375 BAutolock locker(sLock); 376 377 status_t status = update_media_formats(); 378 if (status < B_OK) { 379 ERROR("BMediaFormats: updating formats from server failed: %s!\n", 380 strerror(status)); 381 return status; 382 } 383 TRACE("search for description family = %d, a = 0x%" 384 B_PRId32 "x, b = 0x%" B_PRId32 "x\n", 385 description.family, description.u.misc.file_format, 386 description.u.misc.codec); 387 388 // search for a matching format description 389 390 meta_format other(description); 391 const meta_format* metaFormat = sFormats.BinarySearch(other, 392 meta_format::CompareDescriptions); 393 TRACE("meta format == %p\n", metaFormat); 394 if (metaFormat == NULL) { 395 _format->Clear(); // clear to widlcard 396 return B_MEDIA_BAD_FORMAT; 397 } 398 399 // found it! 400 *_format = metaFormat->format; 401 return B_OK; 402 } 403 404 405 status_t 406 BMediaFormats::GetBeOSFormatFor(uint32 format, 407 media_format* _format, media_type type) 408 { 409 BMediaFormats formats; 410 411 media_format_description description; 412 description.family = B_BEOS_FORMAT_FAMILY; 413 description.u.beos.format = format; 414 415 status_t status = formats.GetFormatFor(description, _format); 416 if (status < B_OK) 417 return status; 418 419 if (type != B_MEDIA_UNKNOWN_TYPE && type != _format->type) 420 return B_BAD_TYPE; 421 422 return B_OK; 423 } 424 425 426 status_t 427 BMediaFormats::GetAVIFormatFor(uint32 codec, 428 media_format* _format, media_type type) 429 { 430 UNIMPLEMENTED(); 431 BMediaFormats formats; 432 433 media_format_description description; 434 description.family = B_AVI_FORMAT_FAMILY; 435 description.u.avi.codec = codec; 436 437 status_t status = formats.GetFormatFor(description, _format); 438 if (status < B_OK) 439 return status; 440 441 if (type != B_MEDIA_UNKNOWN_TYPE && type != _format->type) 442 return B_BAD_TYPE; 443 444 return B_OK; 445 } 446 447 448 status_t 449 BMediaFormats::GetQuicktimeFormatFor(uint32 vendor, uint32 codec, 450 media_format* _format, media_type type) 451 { 452 BMediaFormats formats; 453 454 media_format_description description; 455 description.family = B_QUICKTIME_FORMAT_FAMILY; 456 description.u.quicktime.vendor = vendor; 457 description.u.quicktime.codec = codec; 458 459 status_t status = formats.GetFormatFor(description, _format); 460 if (status < B_OK) 461 return status; 462 463 if (type != B_MEDIA_UNKNOWN_TYPE && type != _format->type) 464 return B_BAD_TYPE; 465 466 return B_OK; 467 } 468 469 470 status_t 471 BMediaFormats::RewindFormats() 472 { 473 if (!sLock.IsLocked() || sLock.LockingThread() != find_thread(NULL)) { 474 // TODO: Shouldn't we simply drop into the debugger in this case? 475 return B_NOT_ALLOWED; 476 } 477 478 fIteratorIndex = 0; 479 return B_OK; 480 } 481 482 483 status_t 484 BMediaFormats::GetNextFormat(media_format* _format, 485 media_format_description* _description) 486 { 487 if (!sLock.IsLocked() || sLock.LockingThread() != find_thread(NULL)) { 488 // TODO: Shouldn't we simply drop into the debugger in this case? 489 return B_NOT_ALLOWED; 490 } 491 492 if (fIteratorIndex == 0) { 493 // This is the first call, so let's make sure we have current data to 494 // operate on. 495 status_t status = update_media_formats(); 496 if (status < B_OK) 497 return status; 498 } 499 500 meta_format* format = sFormats.ItemAt(fIteratorIndex++); 501 if (format == NULL) 502 return B_BAD_INDEX; 503 504 return B_OK; 505 } 506 507 508 bool 509 BMediaFormats::Lock() 510 { 511 return sLock.Lock(); 512 } 513 514 515 void 516 BMediaFormats::Unlock() 517 { 518 sLock.Unlock(); 519 } 520 521 522 status_t 523 BMediaFormats::MakeFormatFor(const media_format_description* descriptions, 524 int32 descriptionCount, media_format* format, uint32 flags, 525 void* _reserved) 526 { 527 return FormatManager::GetInstance()->MakeFormatFor(descriptions, 528 descriptionCount, *format, flags, _reserved); 529 } 530 531 532 // #pragma mark - deprecated API 533 534 535 status_t 536 BMediaFormats::MakeFormatFor(const media_format_description& description, 537 const media_format& inFormat, media_format* _outFormat) 538 { 539 *_outFormat = inFormat; 540 return MakeFormatFor(&description, 1, _outFormat); 541 } 542