2 * Copyright 2004-2009, The Haiku Project. All rights reserved.
3 * Distributed under the terms of the MIT license.
11 #include "AddOnManager.h"
12 #include "DataExchange.h"
13 #include "FormatManager.h"
14 #include "MetaFormat.h"
17 #include <MediaFormats.h>
18 #include <ObjectList.h>
24 using namespace BPrivate::media
;
28 static BObjectList
<meta_format
> sFormats
;
29 static bigtime_t sLastFormatsUpdate
;
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
)
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
);
57 *cookie
= *cookie
+ 1;
59 if (fileFormat
!= NULL
&& candidateFormatFamily
!= B_ANY_FORMAT_FAMILY
60 && fileFormat
->family
!= B_ANY_FORMAT_FAMILY
61 && fileFormat
->family
!= candidateFormatFamily
) {
65 if (!candidateInputFormat
.Matches(inputFormat
))
68 if (_outputFormat
!= NULL
)
69 *_outputFormat
= candidateOutputFormat
;
71 *_codecInfo
= candidateCodecInfo
;
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
) {
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
);
107 *cookie
= *cookie
+ 1;
109 if (fileFormat
!= NULL
&& candidateFormatFamily
!= B_ANY_FORMAT_FAMILY
110 && fileFormat
->family
!= B_ANY_FORMAT_FAMILY
111 && fileFormat
->family
!= candidateFormatFamily
) {
115 if (!candidateInputFormat
.Matches(inputFormat
)
116 || !candidateOutputFormat
.Matches(outputFormat
)) {
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
;
139 get_next_encoder(int32
* cookie
, media_codec_info
* _codecInfo
)
141 if (cookie
== NULL
|| _codecInfo
== NULL
)
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
);
153 *cookie
= *cookie
+ 1;
160 does_file_accept_format(const media_file_format
* _fileFormat
,
161 media_format
* format
, uint32 flags
)
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));
198 operator==(const media_format_description
& a
,
199 const media_format_description
& b
)
201 if (a
.family
!= b
.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
;
233 operator<(const media_format_description
& a
, const media_format_description
& b
)
235 if (a
.family
!= b
.family
)
236 return a
.family
< b
.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
;
269 operator==(const GUID
& a
, const GUID
& b
)
271 return memcmp(&a
, &b
, sizeof(a
)) == 0;
276 operator<(const GUID
& a
, const GUID
& b
)
278 return memcmp(&a
, &b
, sizeof(a
)) < 0;
284 // Some (meta) formats supply functions
287 meta_format::meta_format()
295 meta_format::meta_format(const media_format_description
& description
,
296 const media_format
& format
, int32 id
)
298 description(description
),
305 meta_format::meta_format(const media_format_description
& description
)
307 description(description
),
313 meta_format::meta_format(const meta_format
& other
)
315 description(other
.description
),
322 meta_format::Matches(const media_format
& otherFormat
,
323 media_format_family family
)
325 if (family
!= description
.family
)
328 return format
.Matches(&otherFormat
);
333 meta_format::CompareDescriptions(const meta_format
* a
, const meta_format
* b
)
335 if (a
->description
== b
->description
)
338 if (a
->description
< b
->description
)
346 meta_format::Compare(const meta_format
* a
, const meta_format
* b
)
348 int compare
= CompareDescriptions(a
, b
);
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.
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();
372 FormatManager::GetInstance()->GetFormats(sLastFormatsUpdate
, reply
);
374 // do we need an update at all?
376 if (reply
.FindBool("need_update", &needUpdate
) < B_OK
)
381 // update timestamp and check if the message is okay
384 if (reply
.FindInt64("timestamp", &sLastFormatsUpdate
) < B_OK
385 || reply
.GetInfo("formats", &code
, &count
) < B_OK
)
388 // overwrite already existing formats
391 for (; index
< sFormats
.CountItems() && index
< count
; index
++) {
392 meta_format
* item
= sFormats
.ItemAt(index
);
394 const meta_format
* newItem
;
396 if (reply
.FindData("formats", MEDIA_META_FORMAT_TYPE
, index
,
397 (const void**)&newItem
, &size
) == B_OK
)
401 // allocate additional formats
403 for (; index
< count
; index
++) {
404 const meta_format
* newItem
;
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
);
423 BMediaFormats::BMediaFormats()
430 BMediaFormats::~BMediaFormats()
436 BMediaFormats::InitCheck()
438 return sLock
.Sem() >= B_OK
? B_OK
: sLock
.Sem();
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();
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
;
464 return B_MEDIA_BAD_FORMAT
;
469 BMediaFormats::GetFormatFor(const media_format_description
& description
,
470 media_format
* _format
)
472 BAutolock
locker(sLock
);
474 status_t status
= update_media_formats();
476 ERROR("BMediaFormats: updating formats from server failed: %s!\n",
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
;
497 *_format
= metaFormat
->format
;
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
);
516 if (type
!= B_MEDIA_UNKNOWN_TYPE
&& type
!= _format
->type
)
524 BMediaFormats::GetAVIFormatFor(uint32 codec
,
525 media_format
* _format
, media_type type
)
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
);
538 if (type
!= B_MEDIA_UNKNOWN_TYPE
&& type
!= _format
->type
)
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
);
560 if (type
!= B_MEDIA_UNKNOWN_TYPE
&& type
!= _format
->type
)
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
;
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
592 status_t status
= update_media_formats();
597 meta_format
* format
= sFormats
.ItemAt(fIteratorIndex
++);
606 BMediaFormats::Lock()
613 BMediaFormats::Unlock()
620 BMediaFormats::MakeFormatFor(const media_format_description
* descriptions
,
621 int32 descriptionCount
, media_format
* format
, uint32 flags
,
624 status_t status
= FormatManager::GetInstance()->MakeFormatFor(descriptions
,
625 descriptionCount
, *format
, flags
, _reserved
);
631 // #pragma mark - deprecated API
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
);