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 printf("BMediaFormats: updating formats from server failed: %s!\n", strerror(status)); 374 return status; 375 } 376 printf("search for description family = %d, a = 0x%lx, b = 0x%lx\n", 377 description.family, description.u.misc.file_format, description.u.misc.codec); 378 379 // search for a matching format description 380 381 meta_format other(description); 382 const meta_format *metaFormat = sFormats.BinarySearch(other, meta_format::CompareDescriptions); 383 printf("meta format == %p\n", metaFormat); 384 if (metaFormat == NULL) { 385 memset(_format, 0, sizeof(*_format)); // clear to widlcard 386 return B_MEDIA_BAD_FORMAT; 387 } 388 389 // found it! 390 *_format = metaFormat->format; 391 return B_OK; 392 } 393 394 395 status_t 396 BMediaFormats::GetBeOSFormatFor(uint32 format, 397 media_format *_format, media_type type) 398 { 399 BMediaFormats formats; 400 401 media_format_description description; 402 description.family = B_BEOS_FORMAT_FAMILY; 403 description.u.beos.format = format; 404 405 status_t status = formats.GetFormatFor(description, _format); 406 if (status < B_OK) 407 return status; 408 409 if (type != B_MEDIA_UNKNOWN_TYPE && type != _format->type) 410 return B_BAD_TYPE; 411 412 return B_OK; 413 } 414 415 416 status_t 417 BMediaFormats::GetAVIFormatFor(uint32 codec, 418 media_format *_format, media_type type) 419 { 420 UNIMPLEMENTED(); 421 BMediaFormats formats; 422 423 media_format_description description; 424 description.family = B_AVI_FORMAT_FAMILY; 425 description.u.avi.codec = codec; 426 427 status_t status = formats.GetFormatFor(description, _format); 428 if (status < B_OK) 429 return status; 430 431 if (type != B_MEDIA_UNKNOWN_TYPE && type != _format->type) 432 return B_BAD_TYPE; 433 434 return B_OK; 435 } 436 437 438 status_t 439 BMediaFormats::GetQuicktimeFormatFor(uint32 vendor, uint32 codec, 440 media_format *_format, media_type type) 441 { 442 BMediaFormats formats; 443 444 media_format_description description; 445 description.family = B_QUICKTIME_FORMAT_FAMILY; 446 description.u.quicktime.vendor = vendor; 447 description.u.quicktime.codec = codec; 448 449 status_t status = formats.GetFormatFor(description, _format); 450 if (status < B_OK) 451 return status; 452 453 if (type != B_MEDIA_UNKNOWN_TYPE && type != _format->type) 454 return B_BAD_TYPE; 455 456 return B_OK; 457 } 458 459 460 status_t 461 BMediaFormats::RewindFormats() 462 { 463 if (!sLock.IsLocked() || sLock.LockingThread() != find_thread(NULL)) { 464 // ToDo: shouldn't we simply drop into the debugger in this case? 465 return B_NOT_ALLOWED; 466 } 467 468 fIteratorIndex = 0; 469 return B_OK; 470 } 471 472 473 status_t 474 BMediaFormats::GetNextFormat(media_format *_format, 475 media_format_description *_description) 476 { 477 if (!sLock.IsLocked() || sLock.LockingThread() != find_thread(NULL)) { 478 // ToDo: shouldn't we simply drop into the debugger in this case? 479 return B_NOT_ALLOWED; 480 } 481 482 if (fIteratorIndex == 0) { 483 // this is the first call, so let's make sure we have 484 // current data to operate on 485 status_t status = update_media_formats(); 486 if (status < B_OK) 487 return status; 488 } 489 490 meta_format *format = sFormats.ItemAt(fIteratorIndex++); 491 if (format == NULL) 492 return B_BAD_INDEX; 493 494 return B_OK; 495 } 496 497 498 bool 499 BMediaFormats::Lock() 500 { 501 return sLock.Lock(); 502 } 503 504 505 void 506 BMediaFormats::Unlock() 507 { 508 sLock.Unlock(); 509 } 510 511 512 status_t 513 BMediaFormats::MakeFormatFor(const media_format_description *descriptions, 514 int32 descriptionCount, media_format *format, uint32 flags, void * _reserved) 515 { 516 BMessage request(MEDIA_SERVER_MAKE_FORMAT_FOR); 517 for (int32 i = 0 ; i < descriptionCount ; i++) { 518 request.AddData("description", B_RAW_TYPE, &descriptions[i], sizeof(descriptions[i])); 519 } 520 request.AddData("format", B_RAW_TYPE, format, sizeof(*format)); 521 request.AddData("flags", B_UINT32_TYPE, &flags, sizeof(flags)); 522 request.AddPointer("_reserved", _reserved); 523 524 BMessage reply; 525 status_t status = QueryServer(request, reply); 526 if (status != B_OK) { 527 ERROR("BMediaFormats: Could not make a format: %s\n", strerror(status)); 528 return status; 529 } 530 531 // check the status 532 if (reply.FindInt32("result", &status) < B_OK) { 533 return B_ERROR; 534 } 535 if (status != B_OK) { 536 return status; 537 } 538 539 // get the format 540 const void * data; 541 ssize_t size; 542 if (reply.FindData("format", B_RAW_TYPE, 0, &data, &size) != B_OK) { 543 return B_ERROR; 544 } 545 if (size != sizeof(*format)) { 546 return B_ERROR; 547 } 548 549 // copy the BMessage's data into our format 550 *format = *(media_format *)data; 551 552 return B_OK; 553 } 554 555 /* --- begin deprecated API --- */ 556 557 status_t 558 BMediaFormats::MakeFormatFor(const media_format_description &description, 559 const media_format &inFormat, media_format *_outFormat) 560 { 561 *_outFormat = inFormat; 562 return MakeFormatFor(&description, 1, _outFormat); 563 } 564 565