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