headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / media / MediaFormats.cpp
blobe0bda690c2a857144e23ca26cd643dc760fe6867
1 /*
2 * Copyright 2004-2009, The Haiku Project. All rights reserved.
3 * Distributed under the terms of the MIT license.
5 * Authors:
6 * Axel Dörfler
7 * Marcus Overhagen
8 */
11 #include "AddOnManager.h"
12 #include "DataExchange.h"
13 #include "FormatManager.h"
14 #include "MetaFormat.h"
15 #include "debug.h"
17 #include <MediaFormats.h>
18 #include <ObjectList.h>
19 #include <Message.h>
20 #include <Autolock.h>
22 #include <string.h>
24 using namespace BPrivate::media;
27 static BLocker sLock;
28 static BObjectList<meta_format> sFormats;
29 static bigtime_t sLastFormatsUpdate;
32 status_t
33 get_next_encoder(int32* cookie, const media_file_format* fileFormat,
34 const media_format* inputFormat, media_format* _outputFormat,
35 media_codec_info* _codecInfo)
37 // TODO: If fileFormat is provided (existing apps also pass NULL),
38 // we could at least check fileFormat->capabilities against
39 // outputFormat->type without even contacting the server.
41 if (cookie == NULL || inputFormat == NULL || _codecInfo == NULL)
42 return B_BAD_VALUE;
44 while (true) {
45 media_codec_info candidateCodecInfo;
46 media_format_family candidateFormatFamily;
47 media_format candidateInputFormat;
48 media_format candidateOutputFormat;
50 status_t ret = AddOnManager::GetInstance()->GetCodecInfo(
51 &candidateCodecInfo, &candidateFormatFamily,
52 &candidateInputFormat, &candidateOutputFormat, *cookie);
54 if (ret != B_OK)
55 return ret;
57 *cookie = *cookie + 1;
59 if (fileFormat != NULL && candidateFormatFamily != B_ANY_FORMAT_FAMILY
60 && fileFormat->family != B_ANY_FORMAT_FAMILY
61 && fileFormat->family != candidateFormatFamily) {
62 continue;
65 if (!candidateInputFormat.Matches(inputFormat))
66 continue;
68 if (_outputFormat != NULL)
69 *_outputFormat = candidateOutputFormat;
71 *_codecInfo = candidateCodecInfo;
72 break;
75 return B_OK;
79 status_t
80 get_next_encoder(int32* cookie, const media_file_format* fileFormat,
81 const media_format* inputFormat, const media_format* outputFormat,
82 media_codec_info* _codecInfo, media_format* _acceptedInputFormat,
83 media_format* _acceptedOutputFormat)
85 // TODO: If fileFormat is provided (existing apps also pass NULL),
86 // we could at least check fileFormat->capabilities against
87 // outputFormat->type without even contacting the server.
89 if (cookie == NULL || inputFormat == NULL || outputFormat == NULL
90 || _codecInfo == NULL) {
91 return B_BAD_VALUE;
94 while (true) {
95 media_codec_info candidateCodecInfo;
96 media_format_family candidateFormatFamily;
97 media_format candidateInputFormat;
98 media_format candidateOutputFormat;
100 status_t ret = AddOnManager::GetInstance()->GetCodecInfo(
101 &candidateCodecInfo, &candidateFormatFamily, &candidateInputFormat,
102 &candidateOutputFormat, *cookie);
104 if (ret != B_OK)
105 return ret;
107 *cookie = *cookie + 1;
109 if (fileFormat != NULL && candidateFormatFamily != B_ANY_FORMAT_FAMILY
110 && fileFormat->family != B_ANY_FORMAT_FAMILY
111 && fileFormat->family != candidateFormatFamily) {
112 continue;
115 if (!candidateInputFormat.Matches(inputFormat)
116 || !candidateOutputFormat.Matches(outputFormat)) {
117 continue;
120 // TODO: These formats are currently way too generic. For example,
121 // an encoder may want to adjust video width to a multiple of 16,
122 // or overwrite the intput and or output color space. To make this
123 // possible, we actually have to instantiate an Encoder here and
124 // ask it to specifiy the format.
125 if (_acceptedInputFormat != NULL)
126 *_acceptedInputFormat = candidateInputFormat;
127 if (_acceptedOutputFormat != NULL)
128 *_acceptedOutputFormat = candidateOutputFormat;
130 *_codecInfo = candidateCodecInfo;
131 break;
134 return B_OK;
138 status_t
139 get_next_encoder(int32* cookie, media_codec_info* _codecInfo)
141 if (cookie == NULL || _codecInfo == NULL)
142 return B_BAD_VALUE;
144 media_format_family formatFamily;
145 media_format inputFormat;
146 media_format outputFormat;
148 status_t ret = AddOnManager::GetInstance()->GetCodecInfo(_codecInfo,
149 &formatFamily, &inputFormat, &outputFormat, *cookie);
150 if (ret != B_OK)
151 return ret;
153 *cookie = *cookie + 1;
155 return B_OK;
159 bool
160 does_file_accept_format(const media_file_format* _fileFormat,
161 media_format* format, uint32 flags)
163 UNIMPLEMENTED();
164 return false;
168 // #pragma mark -
171 _media_format_description::_media_format_description()
173 memset(this, 0, sizeof(*this));
177 _media_format_description::~_media_format_description()
182 _media_format_description::_media_format_description(
183 const _media_format_description& other)
185 memcpy(this, &other, sizeof(*this));
189 _media_format_description&
190 _media_format_description::operator=(const _media_format_description& other)
192 memcpy(this, &other, sizeof(*this));
193 return *this;
197 bool
198 operator==(const media_format_description& a,
199 const media_format_description& b)
201 if (a.family != b.family)
202 return false;
204 switch (a.family) {
205 case B_BEOS_FORMAT_FAMILY:
206 return a.u.beos.format == b.u.beos.format;
207 case B_QUICKTIME_FORMAT_FAMILY:
208 return a.u.quicktime.codec == b.u.quicktime.codec
209 && a.u.quicktime.vendor == b.u.quicktime.vendor;
210 case B_AVI_FORMAT_FAMILY:
211 return a.u.avi.codec == b.u.avi.codec;
212 case B_ASF_FORMAT_FAMILY:
213 return a.u.asf.guid == b.u.asf.guid;
214 case B_MPEG_FORMAT_FAMILY:
215 return a.u.mpeg.id == b.u.mpeg.id;
216 case B_WAV_FORMAT_FAMILY:
217 return a.u.wav.codec == b.u.wav.codec;
218 case B_AIFF_FORMAT_FAMILY:
219 return a.u.aiff.codec == b.u.aiff.codec;
220 case B_AVR_FORMAT_FAMILY:
221 return a.u.avr.id == b.u.avr.id;
222 case B_MISC_FORMAT_FAMILY:
223 return a.u.misc.file_format == b.u.misc.file_format
224 && a.u.misc.codec == b.u.misc.codec;
226 default:
227 return false;
232 bool
233 operator<(const media_format_description& a, const media_format_description& b)
235 if (a.family != b.family)
236 return a.family < b.family;
238 switch (a.family) {
239 case B_BEOS_FORMAT_FAMILY:
240 return a.u.beos.format < b.u.beos.format;
241 case B_QUICKTIME_FORMAT_FAMILY:
242 if (a.u.quicktime.vendor == b.u.quicktime.vendor)
243 return a.u.quicktime.codec < b.u.quicktime.codec;
244 return a.u.quicktime.vendor < b.u.quicktime.vendor;
245 case B_AVI_FORMAT_FAMILY:
246 return a.u.avi.codec < b.u.avi.codec;
247 case B_ASF_FORMAT_FAMILY:
248 return a.u.asf.guid < b.u.asf.guid;
249 case B_MPEG_FORMAT_FAMILY:
250 return a.u.mpeg.id < b.u.mpeg.id;
251 case B_WAV_FORMAT_FAMILY:
252 return a.u.wav.codec < b.u.wav.codec;
253 case B_AIFF_FORMAT_FAMILY:
254 return a.u.aiff.codec < b.u.aiff.codec;
255 case B_AVR_FORMAT_FAMILY:
256 return a.u.avr.id < b.u.avr.id;
257 case B_MISC_FORMAT_FAMILY:
258 if (a.u.misc.file_format == b.u.misc.file_format)
259 return a.u.misc.codec < b.u.misc.codec;
260 return a.u.misc.file_format < b.u.misc.file_format;
262 default:
263 return true;
268 bool
269 operator==(const GUID& a, const GUID& b)
271 return memcmp(&a, &b, sizeof(a)) == 0;
275 bool
276 operator<(const GUID& a, const GUID& b)
278 return memcmp(&a, &b, sizeof(a)) < 0;
282 // #pragma mark -
284 // Some (meta) formats supply functions
287 meta_format::meta_format()
289 id(0)
295 meta_format::meta_format(const media_format_description& description,
296 const media_format& format, int32 id)
298 description(description),
299 format(format),
300 id(id)
305 meta_format::meta_format(const media_format_description& description)
307 description(description),
308 id(0)
313 meta_format::meta_format(const meta_format& other)
315 description(other.description),
316 format(other.format)
321 bool
322 meta_format::Matches(const media_format& otherFormat,
323 media_format_family family)
325 if (family != description.family)
326 return false;
328 return format.Matches(&otherFormat);
332 int
333 meta_format::CompareDescriptions(const meta_format* a, const meta_format* b)
335 if (a->description == b->description)
336 return 0;
338 if (a->description < b->description)
339 return -1;
341 return 1;
345 int
346 meta_format::Compare(const meta_format* a, const meta_format* b)
348 int compare = CompareDescriptions(a, b);
349 if (compare != 0)
350 return compare;
352 return a->id - b->id;
356 /** We share one global list for all BMediaFormats in the team - since the
357 * format data can change at any time, we have to update the list to ensure
358 * that we are working on the latest data set. The list is always sorted by
359 * description. The formats lock has to be held when you call this function.
361 static status_t
362 update_media_formats()
364 if (!sLock.IsLocked())
365 return B_NOT_ALLOWED;
367 // We want the add-ons to register themselves with the format manager, so
368 // the list is up to date.
369 AddOnManager::GetInstance()->RegisterAddOns();
371 BMessage reply;
372 FormatManager::GetInstance()->GetFormats(sLastFormatsUpdate, reply);
374 // do we need an update at all?
375 bool needUpdate;
376 if (reply.FindBool("need_update", &needUpdate) < B_OK)
377 return B_ERROR;
378 if (!needUpdate)
379 return B_OK;
381 // update timestamp and check if the message is okay
382 type_code code;
383 int32 count;
384 if (reply.FindInt64("timestamp", &sLastFormatsUpdate) < B_OK
385 || reply.GetInfo("formats", &code, &count) < B_OK)
386 return B_ERROR;
388 // overwrite already existing formats
390 int32 index = 0;
391 for (; index < sFormats.CountItems() && index < count; index++) {
392 meta_format* item = sFormats.ItemAt(index);
394 const meta_format* newItem;
395 ssize_t size;
396 if (reply.FindData("formats", MEDIA_META_FORMAT_TYPE, index,
397 (const void**)&newItem, &size) == B_OK)
398 *item = *newItem;
401 // allocate additional formats
403 for (; index < count; index++) {
404 const meta_format* newItem;
405 ssize_t size;
406 if (reply.FindData("formats", MEDIA_META_FORMAT_TYPE, index,
407 (const void**)&newItem, &size) == B_OK)
408 sFormats.AddItem(new meta_format(*newItem));
411 // remove no longer used formats
413 while (count < sFormats.CountItems())
414 delete sFormats.RemoveItemAt(count);
416 return B_OK;
420 // #pragma mark -
423 BMediaFormats::BMediaFormats()
425 fIteratorIndex(0)
430 BMediaFormats::~BMediaFormats()
435 status_t
436 BMediaFormats::InitCheck()
438 return sLock.Sem() >= B_OK ? B_OK : sLock.Sem();
442 status_t
443 BMediaFormats::GetCodeFor(const media_format& format,
444 media_format_family family,
445 media_format_description* _description)
447 BAutolock locker(sLock);
449 status_t status = update_media_formats();
450 if (status < B_OK)
451 return status;
453 // search for a matching format
455 for (int32 index = sFormats.CountItems(); index-- > 0;) {
456 meta_format* metaFormat = sFormats.ItemAt(index);
458 if (metaFormat->Matches(format, family)) {
459 *_description = metaFormat->description;
460 return B_OK;
464 return B_MEDIA_BAD_FORMAT;
468 status_t
469 BMediaFormats::GetFormatFor(const media_format_description& description,
470 media_format* _format)
472 BAutolock locker(sLock);
474 status_t status = update_media_formats();
475 if (status < B_OK) {
476 ERROR("BMediaFormats: updating formats from server failed: %s!\n",
477 strerror(status));
478 return status;
480 TRACE("search for description family = %d, a = 0x%"
481 B_PRId32 "x, b = 0x%" B_PRId32 "x\n",
482 description.family, description.u.misc.file_format,
483 description.u.misc.codec);
485 // search for a matching format description
487 meta_format other(description);
488 const meta_format* metaFormat = sFormats.BinarySearch(other,
489 meta_format::CompareDescriptions);
490 TRACE("meta format == %p\n", metaFormat);
491 if (metaFormat == NULL) {
492 memset(_format, 0, sizeof(*_format)); // clear to widlcard
493 return B_MEDIA_BAD_FORMAT;
496 // found it!
497 *_format = metaFormat->format;
498 return B_OK;
502 status_t
503 BMediaFormats::GetBeOSFormatFor(uint32 format,
504 media_format* _format, media_type type)
506 BMediaFormats formats;
508 media_format_description description;
509 description.family = B_BEOS_FORMAT_FAMILY;
510 description.u.beos.format = format;
512 status_t status = formats.GetFormatFor(description, _format);
513 if (status < B_OK)
514 return status;
516 if (type != B_MEDIA_UNKNOWN_TYPE && type != _format->type)
517 return B_BAD_TYPE;
519 return B_OK;
523 status_t
524 BMediaFormats::GetAVIFormatFor(uint32 codec,
525 media_format* _format, media_type type)
527 UNIMPLEMENTED();
528 BMediaFormats formats;
530 media_format_description description;
531 description.family = B_AVI_FORMAT_FAMILY;
532 description.u.avi.codec = codec;
534 status_t status = formats.GetFormatFor(description, _format);
535 if (status < B_OK)
536 return status;
538 if (type != B_MEDIA_UNKNOWN_TYPE && type != _format->type)
539 return B_BAD_TYPE;
541 return B_OK;
545 status_t
546 BMediaFormats::GetQuicktimeFormatFor(uint32 vendor, uint32 codec,
547 media_format* _format, media_type type)
549 BMediaFormats formats;
551 media_format_description description;
552 description.family = B_QUICKTIME_FORMAT_FAMILY;
553 description.u.quicktime.vendor = vendor;
554 description.u.quicktime.codec = codec;
556 status_t status = formats.GetFormatFor(description, _format);
557 if (status < B_OK)
558 return status;
560 if (type != B_MEDIA_UNKNOWN_TYPE && type != _format->type)
561 return B_BAD_TYPE;
563 return B_OK;
567 status_t
568 BMediaFormats::RewindFormats()
570 if (!sLock.IsLocked() || sLock.LockingThread() != find_thread(NULL)) {
571 // TODO: Shouldn't we simply drop into the debugger in this case?
572 return B_NOT_ALLOWED;
575 fIteratorIndex = 0;
576 return B_OK;
580 status_t
581 BMediaFormats::GetNextFormat(media_format* _format,
582 media_format_description* _description)
584 if (!sLock.IsLocked() || sLock.LockingThread() != find_thread(NULL)) {
585 // TODO: Shouldn't we simply drop into the debugger in this case?
586 return B_NOT_ALLOWED;
589 if (fIteratorIndex == 0) {
590 // This is the first call, so let's make sure we have current data to
591 // operate on.
592 status_t status = update_media_formats();
593 if (status < B_OK)
594 return status;
597 meta_format* format = sFormats.ItemAt(fIteratorIndex++);
598 if (format == NULL)
599 return B_BAD_INDEX;
601 return B_OK;
605 bool
606 BMediaFormats::Lock()
608 return sLock.Lock();
612 void
613 BMediaFormats::Unlock()
615 sLock.Unlock();
619 status_t
620 BMediaFormats::MakeFormatFor(const media_format_description* descriptions,
621 int32 descriptionCount, media_format* format, uint32 flags,
622 void* _reserved)
624 status_t status = FormatManager::GetInstance()->MakeFormatFor(descriptions,
625 descriptionCount, *format, flags, _reserved);
627 return status;
631 // #pragma mark - deprecated API
634 status_t
635 BMediaFormats::MakeFormatFor(const media_format_description& description,
636 const media_format& inFormat, media_format* _outFormat)
638 *_outFormat = inFormat;
639 return MakeFormatFor(&description, 1, _outFormat);