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