xref: /haiku/src/kits/media/MediaFormats.cpp (revision 1f0635d2277dcd0818dc7f539c1cb1b296f6444b)
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