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