1/*
2 * Copyright 2015, Dario Casalinuovo
3 * Copyright 2004, 2006, J��r��me Duval.
4 * Copyright 2003-2004, Andrew Bachmann.
5 * Copyright 2002-2004, 2006 Marcus Overhagen.
6 * Copyright 2002, Eric Jaessler.
7 * All rights reserved. Distributed under the terms of the MIT license.
8 */
9
10
11#include <MediaDefs.h>
12
13#include <Application.h>
14#include <Bitmap.h>
15#include <Catalog.h>
16#include <IconUtils.h>
17#include <LaunchRoster.h>
18#include <Locale.h>
19#include <MediaNode.h>
20#include <MediaRoster.h>
21#include <Node.h>
22#include <Notification.h>
23#include <Roster.h>
24
25#include <inttypes.h>
26#include <stdio.h>
27#include <string.h>
28
29#include "AddOnManager.h"
30#include "DataExchange.h"
31#include "MediaDebug.h"
32#include "MediaMisc.h"
33#include "MediaRosterEx.h"
34
35
36#define META_DATA_MAX_SIZE			(16 << 20)
37#define META_DATA_AREA_MIN_SIZE		32000
38
39#undef B_TRANSLATION_CONTEXT
40#define B_TRANSLATION_CONTEXT "MediaDefs"
41
42
43// #pragma mark - media_destination
44
45
46media_destination::media_destination(port_id port, int32 id)
47	:
48	port(port),
49	id(id)
50{
51}
52
53
54media_destination::media_destination(const media_destination& clone)
55	:
56	port(clone.port),
57	id(clone.id)
58{
59}
60
61
62media_destination&
63media_destination::operator=(const media_destination& clone)
64{
65	port = clone.port;
66	id = clone.id;
67	return *this;
68}
69
70
71media_destination::media_destination()
72	:
73	port(-1),
74	id(-1)
75{
76}
77
78
79media_destination::~media_destination()
80{
81}
82
83
84media_destination media_destination::null(-1, -1);
85
86
87// #pragma mark - media_source
88
89
90media_source::media_source(port_id port,
91						   int32 id)
92	:
93	port(port),
94	id(id)
95{
96}
97
98
99media_source::media_source(const media_source& clone)
100	:
101	port(clone.port),
102	id(clone.id)
103{
104}
105
106
107media_source&
108media_source::operator=(const media_source& clone)
109{
110	port = clone.port;
111	id = clone.id;
112	return *this;
113}
114
115
116media_source::media_source()
117	:
118	port(-1),
119	id(-1)
120{
121}
122
123
124media_source::~media_source()
125{
126}
127
128
129media_source media_source::null(-1, -1);
130
131
132// #pragma mark -
133
134
135bool
136operator==(const media_destination& a, const media_destination& b)
137{
138	return a.port == b.port && a.id == b.id;
139}
140
141
142bool
143operator!=(const media_destination& a, const media_destination& b)
144{
145	return a.port != b.port || a.id != b.id;
146}
147
148
149bool
150operator<(const media_destination& a, const media_destination& b)
151{
152	UNIMPLEMENTED();
153	return false;
154}
155
156
157bool
158operator==(const media_source& a, const media_source& b)
159{
160	return a.port == b.port && a.id == b.id;
161}
162
163
164bool
165operator!=(const media_source& a, const media_source& b)
166{
167	return a.port != b.port || a.id != b.id;
168}
169
170
171bool
172operator<(const media_source& a, const media_source& b)
173{
174	UNIMPLEMENTED();
175	return false;
176}
177
178
179bool
180operator==(const media_node& a, const media_node& b)
181{
182	return a.node == b.node && a.port == b.port && a.kind == b.kind;
183}
184
185
186bool
187operator!=(const media_node& a, const media_node& b)
188{
189	return a.node != b.node || a.port != b.port || a.kind != b.kind;
190}
191
192
193bool
194operator<(const media_node& a, const media_node& b)
195{
196	UNIMPLEMENTED();
197	return false;
198}
199
200
201// #pragma mark -
202
203
204#if __GNUC__ == 2
205const media_multi_audio_format media_raw_audio_format::wildcard
206	= media_multi_audio_format();
207
208const media_multi_audio_format media_multi_audio_format::wildcard
209	= media_multi_audio_format();
210#else
211const media_multi_audio_format media_raw_audio_format::wildcard = {};
212
213const media_multi_audio_format media_multi_audio_format::wildcard = {};
214#endif
215
216const media_encoded_audio_format media_encoded_audio_format::wildcard = {};
217
218const media_video_display_info media_video_display_info::wildcard = {};
219
220const media_raw_video_format media_raw_video_format::wildcard = {};
221
222const media_encoded_video_format media_encoded_video_format::wildcard = {};
223
224const media_multistream_format media_multistream_format::wildcard = {};
225
226
227// #pragma mark - media_format::Matches() support
228
229
230static bool
231raw_audio_format_matches(const media_raw_audio_format& a,
232	const media_raw_audio_format& b)
233{
234	if (a.frame_rate != 0 && b.frame_rate != 0 && a.frame_rate != b.frame_rate)
235		return false;
236	if (a.channel_count != 0 && b.channel_count != 0
237		&& a.channel_count != b.channel_count) {
238		return false;
239	}
240	if (a.format != 0 && b.format != 0 && a.format != b.format)
241		return false;
242	if (a.byte_order != 0 && b.byte_order != 0 && a.byte_order != b.byte_order)
243		return false;
244	if (a.buffer_size != 0 && b.buffer_size != 0
245		&& a.buffer_size != b.buffer_size) {
246		return false;
247	}
248	if (a.frame_rate != 0 && b.frame_rate != 0 && a.frame_rate != b.frame_rate)
249		return false;
250	return true;
251}
252
253
254static bool
255multi_audio_info_matches(const media_multi_audio_info& a,
256	const media_multi_audio_info& b)
257{
258	if (a.channel_mask != 0 && b.channel_mask != 0
259		&& a.channel_mask != b.channel_mask) {
260		return false;
261	}
262	if (a.valid_bits != 0 && b.valid_bits != 0 && a.valid_bits != b.valid_bits)
263		return false;
264	if (a.matrix_mask != 0 && b.matrix_mask != 0
265		&& a.matrix_mask != b.matrix_mask) {
266		return false;
267	}
268	return true;
269}
270
271
272static bool
273multi_audio_format_matches(const media_multi_audio_format& a,
274	const media_multi_audio_format& b)
275{
276	return raw_audio_format_matches(a, b) && multi_audio_info_matches(a, b);
277}
278
279
280static bool
281raw_video_format_matches(const media_raw_video_format& a,
282	const media_raw_video_format& b)
283{
284	if (a.field_rate != 0 && b.field_rate != 0
285		&& a.field_rate != b.field_rate) {
286		return false;
287	}
288	if (a.interlace != 0 && b.interlace != 0
289		&& a.interlace != b.interlace) {
290		return false;
291	}
292	if (a.first_active != 0 && b.first_active != 0
293		&& a.first_active != b.first_active) {
294		return false;
295	}
296	if (a.last_active != 0 && b.last_active != 0
297		&& a.last_active != b.last_active) {
298		return false;
299	}
300	if (a.orientation != 0 && b.orientation != 0
301		&& a.orientation != b.orientation) {
302		return false;
303	}
304	if (a.pixel_width_aspect != 0 && b.pixel_width_aspect != 0
305		&& a.pixel_width_aspect != b.pixel_width_aspect) {
306		return false;
307	}
308	if (a.pixel_height_aspect != 0 && b.pixel_height_aspect != 0
309		&& a.pixel_height_aspect != b.pixel_height_aspect) {
310		return false;
311	}
312	if (a.display.format != 0 && b.display.format != 0
313		&& a.display.format != b.display.format) {
314		return false;
315	}
316	if (a.display.line_width != 0 && b.display.line_width != 0
317		&& a.display.line_width != b.display.line_width) {
318		return false;
319	}
320	if (a.display.line_count != 0 && b.display.line_count != 0
321		&& a.display.line_count != b.display.line_count) {
322		return false;
323	}
324	if (a.display.bytes_per_row != 0 && b.display.bytes_per_row != 0
325		&& a.display.bytes_per_row != b.display.bytes_per_row) {
326		return false;
327	}
328	if (a.display.pixel_offset != 0 && b.display.pixel_offset != 0
329		&& a.display.pixel_offset != b.display.pixel_offset) {
330		return false;
331	}
332	if (a.display.line_offset != 0 && b.display.line_offset != 0
333		&& a.display.line_offset != b.display.line_offset) {
334		return false;
335	}
336	if (a.display.flags != 0 && b.display.flags != 0
337		&& a.display.flags != b.display.flags) {
338		return false;
339	}
340
341	return true;
342}
343
344
345static bool
346multistream_format_matches(const media_multistream_format& a,
347	const media_multistream_format& b)
348{
349	if (a.avg_bit_rate != 0 && b.avg_bit_rate != 0
350		&& a.avg_bit_rate != b.avg_bit_rate) {
351		return false;
352	}
353	if (a.max_bit_rate != 0 && b.max_bit_rate != 0
354		&& a.max_bit_rate != b.max_bit_rate) {
355		return false;
356	}
357	if (a.avg_chunk_size != 0 && b.avg_chunk_size != 0
358		&& a.avg_chunk_size != b.avg_chunk_size) {
359		return false;
360	}
361	if (a.max_chunk_size != 0 && b.max_chunk_size != 0
362		&& a.max_chunk_size != b.max_chunk_size) {
363		return false;
364	}
365	if (a.flags != 0 && b.flags != 0 && a.flags != b.flags)
366		return false;
367	if (a.format != 0 && b.format != 0 && a.format != b.format)
368		return false;
369
370	if (a.format == 0 && b.format == 0) {
371		// TODO: How do we compare two formats with no type?
372		return true;
373	}
374
375	switch ((a.format != 0) ? a.format : b.format) {
376		default:
377			return true; // TODO: really?
378
379		case media_multistream_format::B_VID:
380			if (a.u.vid.frame_rate != 0 && b.u.vid.frame_rate != 0
381				&& a.u.vid.frame_rate != b.u.vid.frame_rate) {
382				return false;
383			}
384			if (a.u.vid.width != 0 && b.u.vid.width != 0
385				&& a.u.vid.width != b.u.vid.width) {
386				return false;
387			}
388			if (a.u.vid.height != 0 && b.u.vid.height != 0
389				&& a.u.vid.height != b.u.vid.height) {
390				return false;
391			}
392			if (a.u.vid.space != 0 && b.u.vid.space != 0
393				&& a.u.vid.space != b.u.vid.space) {
394				return false;
395			}
396			if (a.u.vid.sampling_rate != 0 && b.u.vid.sampling_rate != 0
397				&& a.u.vid.sampling_rate != b.u.vid.sampling_rate) {
398				return false;
399			}
400			if (a.u.vid.sample_format != 0 && b.u.vid.sample_format != 0
401				&& a.u.vid.sample_format != b.u.vid.sample_format) {
402				return false;
403			}
404			if (a.u.vid.byte_order != 0 && b.u.vid.byte_order != 0
405				&& a.u.vid.byte_order != b.u.vid.byte_order) {
406				return false;
407			}
408			if (a.u.vid.channel_count != 0 && b.u.vid.channel_count != 0
409				&& a.u.vid.channel_count != b.u.vid.channel_count) {
410				return false;
411			}
412			return true;
413
414		case media_multistream_format::B_AVI:
415			if (a.u.avi.us_per_frame != 0 && b.u.avi.us_per_frame != 0
416				&& a.u.avi.us_per_frame != b.u.avi.us_per_frame) {
417				return false;
418			}
419			if (a.u.avi.width != 0 && b.u.avi.width != 0
420				&& a.u.avi.width != b.u.avi.width) {
421				return false;
422			}
423			if (a.u.avi.height != 0 && b.u.avi.height != 0
424				&& a.u.avi.height != b.u.avi.height) {
425				return false;
426			}
427			if (a.u.avi.type_count != 0 && b.u.avi.type_count != 0
428				&& a.u.avi.type_count != b.u.avi.type_count) {
429				return false;
430			}
431			if (a.u.avi.types[0] != 0 && b.u.avi.types[0] != 0
432				&& a.u.avi.types[0] != b.u.avi.types[0]) {
433				return false;
434			}
435			if (a.u.avi.types[1] != 0 && b.u.avi.types[1] != 0
436				&& a.u.avi.types[1] != b.u.avi.types[1]) {
437				return false;
438			}
439			if (a.u.avi.types[2] != 0 && b.u.avi.types[2] != 0
440				&& a.u.avi.types[2] != b.u.avi.types[2]) {
441				return false;
442			}
443			if (a.u.avi.types[3] != 0 && b.u.avi.types[3] != 0
444				&& a.u.avi.types[3] != b.u.avi.types[3]) {
445				return false;
446			}
447			if (a.u.avi.types[4] != 0 && b.u.avi.types[4] != 0
448				&& a.u.avi.types[4] != b.u.avi.types[4]) {
449				return false;
450			}
451			return true;
452	}
453}
454
455
456static bool
457encoded_audio_format_matches(const media_encoded_audio_format& a,
458	const media_encoded_audio_format& b)
459{
460	if (!raw_audio_format_matches(a.output, b.output))
461		return false;
462	if (a.encoding != 0 && b.encoding != 0 && a.encoding != b.encoding)
463		return false;
464	if (a.bit_rate != 0 && b.bit_rate != 0 && a.bit_rate != b.bit_rate)
465		return false;
466	if (a.frame_size != 0 && b.frame_size != 0 && a.frame_size != b.frame_size)
467		return false;
468	if (!multi_audio_info_matches(a.multi_info, b.multi_info))
469		return false;
470
471	if (a.encoding == 0 && b.encoding == 0)
472		return true; // can't compare
473
474	switch((a.encoding != 0) ? a.encoding : b.encoding) {
475		case media_encoded_audio_format::B_ANY:
476		default:
477			return true;
478	}
479}
480
481
482static bool
483encoded_video_format_matches(const media_encoded_video_format& a,
484	const media_encoded_video_format& b)
485{
486	if (!raw_video_format_matches(a.output, b.output))
487		return false;
488	if (a.encoding != 0 && b.encoding != 0 && a.encoding != b.encoding)
489		return false;
490
491	if (a.avg_bit_rate != 0 && b.avg_bit_rate != 0
492		&& a.avg_bit_rate != b.avg_bit_rate) {
493		return false;
494	}
495	if (a.max_bit_rate != 0 && b.max_bit_rate != 0
496		&& a.max_bit_rate != b.max_bit_rate) {
497		return false;
498	}
499	if (a.frame_size != 0 && b.frame_size != 0
500		&& a.frame_size != b.frame_size) {
501		return false;
502	}
503	if (a.forward_history != 0 && b.forward_history != 0
504		&& a.forward_history != b.forward_history) {
505		return false;
506	}
507	if (a.backward_history != 0 && b.backward_history != 0
508		&& a.backward_history != b.backward_history) {
509		return false;
510	}
511
512	if (a.encoding == 0 && b.encoding == 0)
513		return true; // can't compare
514
515	switch((a.encoding != 0) ? a.encoding : b.encoding) {
516		case media_encoded_video_format::B_ANY:
517		default:
518			return true;
519	}
520}
521
522
523// #pragma mark - media_format::SpecializeTo() support
524
525
526static void
527raw_audio_format_specialize(media_raw_audio_format* format,
528	const media_raw_audio_format* other)
529{
530	if (format->frame_rate == 0)
531		format->frame_rate = other->frame_rate;
532	if (format->channel_count == 0)
533		format->channel_count = other->channel_count;
534	if (format->format == 0)
535		format->format = other->format;
536	if (format->byte_order == 0)
537		format->byte_order = other->byte_order;
538	if (format->buffer_size == 0)
539		format->buffer_size = other->buffer_size;
540	if (format->frame_rate == 0)
541		format->frame_rate = other->frame_rate;
542}
543
544
545static void
546multi_audio_info_specialize(media_multi_audio_info* format,
547	const media_multi_audio_info* other)
548{
549	if (format->channel_mask == 0)
550		format->channel_mask = other->channel_mask;
551	if (format->valid_bits == 0)
552		format->valid_bits = other->valid_bits;
553	if (format->matrix_mask == 0)
554		format->matrix_mask = other->matrix_mask;
555}
556
557
558static void
559multi_audio_format_specialize(media_multi_audio_format* format,
560	const media_multi_audio_format* other)
561{
562	raw_audio_format_specialize(format, other);
563	multi_audio_info_specialize(format, other);
564}
565
566
567static void
568raw_video_format_specialize(media_raw_video_format* format,
569	const media_raw_video_format* other)
570{
571	if (format->field_rate == 0)
572		format->field_rate = other->field_rate;
573	if (format->interlace == 0)
574		format->interlace = other->interlace;
575	if (format->first_active == 0)
576		format->first_active = other->first_active;
577	if (format->last_active == 0)
578		format->last_active = other->last_active;
579	if (format->orientation == 0)
580		format->orientation = other->orientation;
581	if (format->pixel_width_aspect == 0)
582		format->pixel_width_aspect = other->pixel_width_aspect;
583	if (format->pixel_height_aspect == 0)
584		format->pixel_height_aspect = other->pixel_height_aspect;
585	if (format->display.format == 0)
586		format->display.format = other->display.format;
587	if (format->display.line_width == 0)
588		format->display.line_width = other->display.line_width;
589	if (format->display.line_count == 0)
590		format->display.line_count = other->display.line_count;
591	if (format->display.bytes_per_row == 0)
592		format->display.bytes_per_row = other->display.bytes_per_row;
593	if (format->display.pixel_offset == 0)
594		format->display.pixel_offset = other->display.pixel_offset;
595	if (format->display.line_offset == 0)
596		format->display.line_offset = other->display.line_offset;
597	if (format->display.flags == 0)
598		format->display.flags = other->display.flags;
599}
600
601
602static void
603multistream_format_specialize(media_multistream_format* format,
604	const media_multistream_format* other)
605{
606	if (format->avg_bit_rate == 0)
607		format->avg_bit_rate = other->avg_bit_rate;
608	if (format->max_bit_rate == 0)
609		format->max_bit_rate = other->max_bit_rate;
610	if (format->avg_chunk_size == 0)
611		format->avg_chunk_size = other->avg_chunk_size;
612	if (format->max_chunk_size == 0)
613		format->max_chunk_size = other->max_chunk_size;
614	if (format->flags == 0)
615		format->flags = other->flags;
616	if (format->format == 0)
617		format->format = other->format;
618
619	switch (format->format) {
620		case media_multistream_format::B_VID:
621			if (format->u.vid.frame_rate == 0)
622				format->u.vid.frame_rate = other->u.vid.frame_rate;
623			if (format->u.vid.width == 0)
624				format->u.vid.width = other->u.vid.width;
625			if (format->u.vid.height == 0)
626				format->u.vid.height = other->u.vid.height;
627			if (format->u.vid.space == 0)
628				format->u.vid.space = other->u.vid.space;
629			if (format->u.vid.sampling_rate == 0)
630				format->u.vid.sampling_rate = other->u.vid.sampling_rate;
631			if (format->u.vid.sample_format == 0)
632				format->u.vid.sample_format = other->u.vid.sample_format;
633			if (format->u.vid.byte_order == 0)
634				format->u.vid.byte_order = other->u.vid.byte_order;
635			if (format->u.vid.channel_count == 0)
636				format->u.vid.channel_count = other->u.vid.channel_count;
637			break;
638
639		case media_multistream_format::B_AVI:
640			if (format->u.avi.us_per_frame == 0)
641				format->u.avi.us_per_frame = other->u.avi.us_per_frame;
642			if (format->u.avi.width == 0)
643				format->u.avi.width = other->u.avi.width;
644			if (format->u.avi.height == 0)
645				format->u.avi.height = other->u.avi.height;
646			if (format->u.avi.type_count == 0)
647				format->u.avi.type_count = other->u.avi.type_count;
648			if (format->u.avi.types[0] == 0)
649				format->u.avi.types[0] = other->u.avi.types[0];
650			if (format->u.avi.types[1] == 0)
651				format->u.avi.types[1] = other->u.avi.types[1];
652			if (format->u.avi.types[2] == 0)
653				format->u.avi.types[2] = other->u.avi.types[2];
654			if (format->u.avi.types[3] == 0)
655				format->u.avi.types[3] = other->u.avi.types[3];
656			if (format->u.avi.types[4] == 0)
657				format->u.avi.types[4] = other->u.avi.types[4];
658			break;
659
660		default:
661			ERROR("media_format::SpecializeTo can't specialize "
662				"media_multistream_format of format %" B_PRId32 "\n",
663				format->format);
664	}
665}
666
667
668static void
669encoded_audio_format_specialize(media_encoded_audio_format* format,
670	const media_encoded_audio_format* other)
671{
672	raw_audio_format_specialize(&format->output, &other->output);
673	if (format->encoding == 0)
674		format->encoding = other->encoding;
675	if (format->bit_rate == 0)
676		format->bit_rate = other->bit_rate;
677	if (format->frame_size == 0)
678		format->frame_size = other->frame_size;
679	multi_audio_info_specialize(&format->multi_info, &other->multi_info);
680}
681
682
683static void
684encoded_video_format_specialize(media_encoded_video_format* format,
685	const media_encoded_video_format* other)
686{
687	raw_video_format_specialize(&format->output, &other->output);
688	if (format->avg_bit_rate == 0)
689		format->avg_bit_rate = other->avg_bit_rate;
690	if (format->max_bit_rate == 0)
691		format->max_bit_rate = other->max_bit_rate;
692	if (format->encoding == 0)
693		format->encoding = other->encoding;
694	if (format->frame_size == 0)
695		format->frame_size = other->frame_size;
696	if (format->forward_history == 0)
697		format->forward_history = other->forward_history;
698	if (format->backward_history == 0)
699		format->backward_history = other->backward_history;
700}
701
702
703// #pragma mark - media_format
704
705
706bool
707media_format::Matches(const media_format* other) const
708{
709	CALLED();
710
711	if (type == 0 && other->type == 0) {
712		// TODO: How do we compare two formats with no type?
713		return true;
714	}
715
716	if (type != 0 && other->type != 0 && type != other->type)
717		return false;
718
719	switch ((type != 0) ? type : other->type) {
720		case B_MEDIA_RAW_AUDIO:
721			return multi_audio_format_matches(u.raw_audio, other->u.raw_audio);
722
723		case B_MEDIA_RAW_VIDEO:
724			return raw_video_format_matches(u.raw_video, other->u.raw_video);
725
726		case B_MEDIA_MULTISTREAM:
727			return multistream_format_matches(u.multistream,
728				other->u.multistream);
729
730		case B_MEDIA_ENCODED_AUDIO:
731			return encoded_audio_format_matches(u.encoded_audio,
732				other->u.encoded_audio);
733
734		case B_MEDIA_ENCODED_VIDEO:
735			return encoded_video_format_matches(u.encoded_video,
736				other->u.encoded_video);
737
738		default:
739			return true; // TODO: really?
740	}
741}
742
743
744void
745media_format::SpecializeTo(const media_format* otherFormat)
746{
747	CALLED();
748
749	if (type == 0 && otherFormat->type == 0) {
750		ERROR("media_format::SpecializeTo can't specialize wildcard to other "
751			"wildcard format\n");
752		return;
753	}
754
755	if (type == 0)
756		type = otherFormat->type;
757
758	switch (type) {
759		case B_MEDIA_RAW_AUDIO:
760			multi_audio_format_specialize(&u.raw_audio,
761				&otherFormat->u.raw_audio);
762			return;
763
764		case B_MEDIA_RAW_VIDEO:
765			raw_video_format_specialize(&u.raw_video,
766				&otherFormat->u.raw_video);
767			return;
768
769		case B_MEDIA_MULTISTREAM:
770			multistream_format_specialize(&u.multistream,
771				&otherFormat->u.multistream);
772			return;
773
774		case B_MEDIA_ENCODED_AUDIO:
775			encoded_audio_format_specialize(&u.encoded_audio,
776				&otherFormat->u.encoded_audio);
777			return;
778
779		case B_MEDIA_ENCODED_VIDEO:
780			encoded_video_format_specialize(&u.encoded_video,
781				&otherFormat->u.encoded_video);
782			return;
783
784		default:
785			ERROR("media_format::SpecializeTo can't specialize format "
786				"type %d\n", type);
787	}
788}
789
790
791status_t
792media_format::SetMetaData(const void* data, size_t size)
793{
794	if (!data || size > META_DATA_MAX_SIZE)
795		return B_BAD_VALUE;
796
797	void* new_addr;
798	area_id new_area;
799	if (size < META_DATA_AREA_MIN_SIZE) {
800		new_area = B_BAD_VALUE;
801		new_addr = malloc(size);
802		if (!new_addr)
803			return B_NO_MEMORY;
804	} else {
805		new_area = create_area("meta_data_area", &new_addr, B_ANY_ADDRESS,
806			ROUND_UP_TO_PAGE(size), B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
807		if (new_area < 0)
808			return (status_t)new_area;
809	}
810
811	if (meta_data_area > 0)
812		delete_area(meta_data_area);
813	else
814		free(meta_data);
815
816	meta_data = new_addr;
817	meta_data_size = size;
818	meta_data_area = new_area;
819
820	memcpy(meta_data, data, size);
821
822	if (meta_data_area > 0)
823		set_area_protection(meta_data_area, B_READ_AREA);
824
825	return B_OK;
826}
827
828
829const void*
830media_format::MetaData() const
831{
832	return meta_data;
833}
834
835
836int32
837media_format::MetaDataSize() const
838{
839	return meta_data_size;
840}
841
842
843void
844media_format::Unflatten(const char *flatBuffer)
845{
846	// TODO: we should not!!! make flat copies of media_format
847	memcpy(this, flatBuffer, sizeof(*this));
848	meta_data = NULL;
849	meta_data_area = B_BAD_VALUE;
850}
851
852
853void
854media_format::Clear()
855{
856	memset(this, 0x00, sizeof(*this));
857	meta_data = NULL;
858	meta_data_area = B_BAD_VALUE;
859}
860
861
862media_format::media_format()
863{
864	this->Clear();
865}
866
867
868media_format::media_format(const media_format& other)
869{
870	this->Clear();
871	*this = other;
872}
873
874
875media_format::~media_format()
876{
877	if (meta_data_area > 0)
878		delete_area(meta_data_area);
879	else
880		free(meta_data);
881}
882
883
884// final
885media_format&
886media_format::operator=(const media_format& clone)
887{
888	// get rid of this format's meta data
889	this->~media_format();
890		// danger: using only ~media_format() would call the constructor
891
892	// make a binary copy
893	memcpy(this, &clone, sizeof(*this));
894	// some binary copies are invalid:
895	meta_data = NULL;
896	meta_data_area = B_BAD_VALUE;
897
898	// clone or copy the meta data
899	if (clone.meta_data) {
900		if (clone.meta_data_area != B_BAD_VALUE) {
901			meta_data_area = clone_area("meta_data_clone_area", &meta_data,
902				B_ANY_ADDRESS, B_READ_AREA, clone.meta_data_area);
903			if (meta_data_area < 0) {
904				// whoops, we just lost our meta data
905				meta_data = NULL;
906				meta_data_size = 0;
907			}
908		} else {
909			meta_data = malloc(meta_data_size);
910			if (meta_data) {
911				memcpy(meta_data, clone.meta_data, meta_data_size);
912			} else {
913				// whoops, we just lost our meta data
914				meta_data_size = 0;
915			}
916		}
917	}
918	return *this;
919}
920
921
922// #pragma mark -
923
924
925bool
926operator==(const media_raw_audio_format& a, const media_raw_audio_format& b)
927{
928	return a.frame_rate == b.frame_rate
929		&& a.channel_count == b.channel_count
930		&& a.format == b.format
931		&& a.byte_order == b.byte_order
932		&& a.buffer_size == b.buffer_size;
933}
934
935
936bool
937operator==(const media_multi_audio_info& a, const media_multi_audio_info& b)
938{
939	return a.channel_mask == b.channel_mask
940		&& a.valid_bits == b.valid_bits
941		&& a.matrix_mask == b.matrix_mask;
942}
943
944
945bool
946operator==(const media_multi_audio_format& a,
947	const media_multi_audio_format& b)
948{
949	return (media_raw_audio_format)a == (media_raw_audio_format)b
950		&& (media_multi_audio_info)a == (media_multi_audio_info)b;
951}
952
953
954bool
955operator==(const media_encoded_audio_format& a,
956	const media_encoded_audio_format& b)
957{
958	return a.output == b.output
959		&& a.encoding == b.encoding
960		&& a.bit_rate == b.bit_rate
961		&& a.frame_size == b.frame_size
962		&& a.multi_info == b.multi_info;
963}
964
965
966bool
967operator==(const media_video_display_info& a,
968	const media_video_display_info& b)
969{
970	return a.format == b.format
971		&& a.line_width == b.line_width
972		&& a.line_count == b.line_count
973		&& a.bytes_per_row == b.bytes_per_row
974		&& a.pixel_offset == b.pixel_offset
975		&& a.line_offset == b.line_offset
976		&& a.flags == b.flags;
977}
978
979
980bool
981operator==(const media_raw_video_format& a, const media_raw_video_format& b)
982{
983	return a.field_rate == b.field_rate
984		&& a.interlace == b.interlace
985		&& a.first_active == b.first_active
986		&& a.last_active == b.last_active
987		&& a.orientation == b.orientation
988		&& a.pixel_width_aspect == b.pixel_width_aspect
989		&& a.pixel_height_aspect == b.pixel_height_aspect
990		&& a.display == b.display;
991}
992
993
994bool
995operator==(const media_encoded_video_format& a,
996	const media_encoded_video_format& b)
997{
998	return a.output == b.output
999		&& a.avg_bit_rate == b.avg_bit_rate
1000		&& a.max_bit_rate == b.max_bit_rate
1001		&& a.encoding == b.encoding
1002		&& a.frame_size == b.frame_size
1003		&& a.forward_history == b.forward_history
1004		&& a.backward_history == b.backward_history;
1005}
1006
1007
1008bool
1009operator==(const media_multistream_format::vid_info& a,
1010	const media_multistream_format::vid_info& b)
1011{
1012	return a.frame_rate == b.frame_rate
1013		&& a.width == b.width
1014		&& a.height == b.height
1015		&& a.space == b.space
1016		&& a.sampling_rate == b.sampling_rate
1017		&& a.sample_format == b.sample_format
1018		&& a.byte_order == b.byte_order
1019		&& a.channel_count == b.channel_count;
1020}
1021
1022
1023bool
1024operator==(const media_multistream_format::avi_info& a,
1025	const media_multistream_format::avi_info& b)
1026{
1027	return a.us_per_frame == b.us_per_frame
1028		&& a.width == b.width
1029		&& a.height == b.height
1030		&& a.type_count == b.type_count
1031		&& a.types[0] == b.types[0]
1032		&& a.types[1] == b.types[1]
1033		&& a.types[2] == b.types[2]
1034		&& a.types[3] == b.types[3]
1035		&& a.types[4] == b.types[4];
1036}
1037
1038
1039bool
1040operator==(const media_multistream_format& a,
1041	const media_multistream_format& b)
1042{
1043	if (a.avg_bit_rate != b.avg_bit_rate
1044		|| a.max_bit_rate != b.max_bit_rate
1045		|| a.avg_chunk_size != b.avg_chunk_size
1046		|| a.max_chunk_size != b.max_chunk_size
1047		|| a.format != b.format
1048		|| a.flags != b.flags) {
1049		return false;
1050	}
1051
1052	switch (a.format) {
1053		case media_multistream_format::B_VID:
1054			return a.u.vid == b.u.vid;
1055
1056		case media_multistream_format::B_AVI:
1057			return a.u.avi == b.u.avi;
1058
1059		default:
1060			return true; // TODO: really?
1061	}
1062}
1063
1064
1065bool
1066operator==(const media_format& a, const media_format& b)
1067{
1068	if (a.type != b.type
1069		|| a.user_data_type != b.user_data_type
1070		// TODO: compare user_data[48] ?
1071		|| a.require_flags != b.require_flags
1072		|| a.deny_flags != b.deny_flags) {
1073		return false;
1074	}
1075
1076	switch (a.type) {
1077		case B_MEDIA_RAW_AUDIO:
1078			return a.u.raw_audio == b.u.raw_audio;
1079
1080		case B_MEDIA_RAW_VIDEO:
1081			return a.u.raw_video == b.u.raw_video;
1082
1083		case B_MEDIA_MULTISTREAM:
1084			return a.u.multistream == b.u.multistream;
1085
1086		case B_MEDIA_ENCODED_AUDIO:
1087			return a.u.encoded_audio == b.u.encoded_audio;
1088
1089		case B_MEDIA_ENCODED_VIDEO:
1090			return a.u.encoded_video == b.u.encoded_video;
1091
1092		default:
1093			return true; // TODO: really?
1094	}
1095}
1096
1097
1098// #pragma mark -
1099
1100
1101/*! return \c true if a and b are compatible (accounting for wildcards)
1102	a is the format you want to feed to something accepting b
1103*/
1104bool
1105format_is_compatible(const media_format& a, const media_format& b)
1106{
1107	return a.Matches(&b);
1108}
1109
1110
1111bool
1112string_for_format(const media_format& f, char* buf, size_t size)
1113{
1114	char encoding[10]; /* maybe Be wanted to use some 4CCs ? */
1115	const char* videoOrientation = "0"; /* I'd use "NC", R5 uses 0. */
1116
1117	if (buf == NULL)
1118		return false;
1119	switch (f.type) {
1120	case B_MEDIA_RAW_AUDIO:
1121		snprintf(buf, size,
1122			"raw_audio;%g;%" B_PRIu32 ";0x%" B_PRIx32 ";%" B_PRIu32 ";0x%"
1123				B_PRIxSIZE ";0x%#" B_PRIx32 ";%d;0x%04x",
1124			f.u.raw_audio.frame_rate,
1125			f.u.raw_audio.channel_count,
1126			f.u.raw_audio.format,
1127			f.u.raw_audio.byte_order,
1128			f.u.raw_audio.buffer_size,
1129			f.u.raw_audio.channel_mask,
1130			f.u.raw_audio.valid_bits,
1131			f.u.raw_audio.matrix_mask);
1132		return true;
1133	case B_MEDIA_RAW_VIDEO:
1134		if (f.u.raw_video.orientation == B_VIDEO_TOP_LEFT_RIGHT)
1135			videoOrientation = "TopLR";
1136		else if (f.u.raw_video.orientation == B_VIDEO_BOTTOM_LEFT_RIGHT)
1137			videoOrientation = "BotLR";
1138		snprintf(buf, size, "raw_video;%g;0x%x;%" B_PRIu32 ";%" B_PRIu32 ";%"
1139				B_PRIu32 ";%" B_PRIu32 ";%s;%d;%d",
1140			f.u.raw_video.field_rate,
1141			f.u.raw_video.display.format,
1142			f.u.raw_video.interlace,
1143			f.u.raw_video.display.line_width,
1144			f.u.raw_video.display.line_count,
1145			f.u.raw_video.first_active,
1146			videoOrientation,
1147			f.u.raw_video.pixel_width_aspect,
1148			f.u.raw_video.pixel_height_aspect);
1149		return true;
1150	case B_MEDIA_ENCODED_AUDIO:
1151		snprintf(encoding, 10, "%d", f.u.encoded_audio.encoding);
1152		snprintf(buf, size,
1153			"caudio;%s;%g;%ld;(%g;%" B_PRIu32 ";0x%" B_PRIx32 ";%" B_PRIu32
1154				";0x%" B_PRIxSIZE ";0x%08" B_PRIx32 ";%d;0x%04x)",
1155			encoding,
1156			f.u.encoded_audio.bit_rate,
1157			f.u.encoded_audio.frame_size,
1158			f.u.encoded_audio.output.frame_rate,
1159			f.u.encoded_audio.output.channel_count,
1160			f.u.encoded_audio.output.format,
1161			f.u.encoded_audio.output.byte_order,
1162			f.u.encoded_audio.output.buffer_size,
1163			f.u.encoded_audio.multi_info.channel_mask,
1164			f.u.encoded_audio.multi_info.valid_bits,
1165			f.u.encoded_audio.multi_info.matrix_mask);
1166		return true;
1167	case B_MEDIA_ENCODED_VIDEO:
1168		snprintf(encoding, 10, "%d", f.u.encoded_video.encoding);
1169		if (f.u.encoded_video.output.orientation == B_VIDEO_TOP_LEFT_RIGHT)
1170			videoOrientation = "TopLR";
1171		else if (f.u.encoded_video.output.orientation == B_VIDEO_BOTTOM_LEFT_RIGHT)
1172			videoOrientation = "BotLR";
1173		snprintf(buf, size,
1174			"cvideo;%s;%g;%g;%" B_PRIuSIZE ";(%g;0x%x;%" B_PRIu32 ";%" B_PRIu32
1175				";%" B_PRIu32 ";%" B_PRIu32 ";%s;%d;%d)",
1176			encoding,
1177			f.u.encoded_video.avg_bit_rate,
1178			f.u.encoded_video.max_bit_rate,
1179			f.u.encoded_video.frame_size,
1180			f.u.encoded_video.output.field_rate,
1181			f.u.encoded_video.output.display.format,
1182			f.u.encoded_video.output.interlace,
1183			f.u.encoded_video.output.display.line_width,
1184			f.u.encoded_video.output.display.line_count,
1185			f.u.encoded_video.output.first_active,
1186			videoOrientation,
1187			f.u.encoded_video.output.pixel_width_aspect,
1188			f.u.encoded_video.output.pixel_height_aspect);
1189		return true;
1190	default:
1191		snprintf(buf, size, "%d-", f.type);
1192		unsigned char* p = (unsigned char*)&(f.u);
1193		size -= strlen(buf);
1194		buf += strlen(buf);
1195		for (int i = 0; (size > 2) && (i < 96); i++) {
1196			snprintf(buf, 3, "%2.2x", *(p + i));
1197			buf+=2;
1198			size-=2;
1199		}
1200		return true; // ?
1201	}
1202	return false;
1203}
1204
1205
1206// #pragma mark -
1207
1208
1209bool
1210operator==(const media_file_format_id& a, const media_file_format_id& b)
1211{
1212	return a.node == b.node && a.device == b.device
1213		&& a.internal_id == b.internal_id;
1214}
1215
1216
1217bool
1218operator<(const media_file_format_id& a, const media_file_format_id& b)
1219{
1220	return a.internal_id < b.internal_id;
1221}
1222
1223
1224// #pragma mark -
1225
1226
1227//! Use this function to iterate through available file format writers.
1228status_t
1229get_next_file_format(int32* cookie, media_file_format* mff)
1230{
1231	if (cookie == NULL || mff == NULL)
1232		return B_BAD_VALUE;
1233
1234	status_t ret = AddOnManager::GetInstance()->GetFileFormat(mff, *cookie);
1235	if (ret != B_OK)
1236		return ret;
1237
1238	*cookie = *cookie + 1;
1239
1240	return B_OK;
1241}
1242
1243
1244// #pragma mark -
1245
1246
1247// final & verified
1248const char* B_MEDIA_SERVER_SIGNATURE = "application/x-vnd.Be.media-server";
1249const char* B_MEDIA_ADDON_SERVER_SIGNATURE = "application/x-vnd.Be.addon-host";
1250
1251const type_code B_CODEC_TYPE_INFO = 0x040807b2;
1252
1253
1254// #pragma mark -
1255
1256
1257// shutdown_media_server() and launch_media_server()
1258// are provided by libbe.so in BeOS R5
1259
1260#define MEDIA_SERVICE_NOTIFICATION_ID "MediaServiceNotificationID"
1261
1262
1263void
1264notify_system(float progress, const char* message)
1265{
1266	BNotification notification(B_PROGRESS_NOTIFICATION);
1267	notification.SetMessageID(MEDIA_SERVICE_NOTIFICATION_ID);
1268	notification.SetProgress(progress);
1269	notification.SetGroup(B_TRANSLATE("Media Service"));
1270	notification.SetContent(message);
1271
1272	app_info info;
1273	be_app->GetAppInfo(&info);
1274	BBitmap icon(BRect(0, 0, 32, 32), B_RGBA32);
1275	BNode node(&info.ref);
1276	BIconUtils::GetVectorIcon(&node, "BEOS:ICON", &icon);
1277	notification.SetIcon(&icon);
1278
1279	notification.Send();
1280}
1281
1282
1283void
1284progress_shutdown(int stage,
1285	bool (*progress)(int stage, const char* message, void* cookie),
1286	void* cookie)
1287{
1288	// parameter "message" is no longer used. It is kept for compatibility with
1289	// BeOS as this is used as a shutdown_media_server callback.
1290
1291	TRACE("stage: %i\n", stage);
1292	const char* string = "Unknown stage";
1293	switch (stage) {
1294		case 10:
1295			string = B_TRANSLATE("Stopping media server" B_UTF8_ELLIPSIS);
1296			break;
1297		case 20:
1298			string = B_TRANSLATE("Waiting for media_server to quit.");
1299			break;
1300		case 40:
1301			string = B_TRANSLATE("Telling media_addon_server to quit.");
1302			break;
1303		case 50:
1304			string = B_TRANSLATE("Waiting for media_addon_server to quit.");
1305			break;
1306		case 70:
1307			string = B_TRANSLATE("Cleaning up.");
1308			break;
1309		case 100:
1310			string = B_TRANSLATE("Done shutting down.");
1311			break;
1312	}
1313
1314	if (progress == NULL)
1315		notify_system(stage / 100.0f, string);
1316	else
1317		progress(stage, string, cookie);
1318}
1319
1320
1321status_t
1322shutdown_media_server(bigtime_t timeout,
1323	bool (*progress)(int stage, const char* message, void* cookie),
1324	void* cookie)
1325{
1326	BLaunchRoster launchRoster;
1327	launchRoster.StopTarget(B_MEDIA_SERVER_SIGNATURE);
1328
1329	BMessage msg(B_QUIT_REQUESTED);
1330	status_t err = B_MEDIA_SYSTEM_FAILURE;
1331	bool shutdown = false;
1332
1333	BMediaRoster* roster = BMediaRoster::Roster(&err);
1334	if (roster == NULL || err != B_OK)
1335		return err;
1336
1337	if (progress == NULL && roster->Lock()) {
1338		MediaRosterEx(roster)->EnableLaunchNotification(true, true);
1339		roster->Unlock();
1340	}
1341
1342	if ((err = msg.AddBool("be:_user_request", true)) != B_OK)
1343		return err;
1344
1345	team_id mediaServer = be_roster->TeamFor(B_MEDIA_SERVER_SIGNATURE);
1346	team_id addOnServer = be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE);
1347
1348	if (mediaServer != B_ERROR) {
1349		BMessage reply;
1350		BMessenger messenger(B_MEDIA_SERVER_SIGNATURE, mediaServer);
1351		progress_shutdown(10, progress, cookie);
1352
1353		err = messenger.SendMessage(&msg, &reply, 2000000, 2000000);
1354		reply.FindBool("_shutdown", &shutdown);
1355		if (err == B_TIMED_OUT || shutdown == false) {
1356			if (messenger.IsValid())
1357				kill_team(mediaServer);
1358		} else if (err != B_OK)
1359			return err;
1360
1361		progress_shutdown(20, progress, cookie);
1362
1363		int32 rv;
1364		if (reply.FindInt32("error", &rv) == B_OK && rv != B_OK)
1365			return rv;
1366	}
1367
1368	if (addOnServer != B_ERROR) {
1369		shutdown = false;
1370		BMessage reply;
1371		BMessenger messenger(B_MEDIA_ADDON_SERVER_SIGNATURE, addOnServer);
1372		progress_shutdown(40, progress, cookie);
1373
1374		// The media_server usually shutdown the media_addon_server,
1375		// if not let's do something.
1376		if (messenger.IsValid()) {
1377			err = messenger.SendMessage(&msg, &reply, 2000000, 2000000);
1378			reply.FindBool("_shutdown", &shutdown);
1379			if (err == B_TIMED_OUT || shutdown == false) {
1380				if (messenger.IsValid())
1381					kill_team(addOnServer);
1382			} else if (err != B_OK)
1383				return err;
1384
1385			progress_shutdown(50, progress, cookie);
1386
1387			int32 rv;
1388			if (reply.FindInt32("error", &rv) == B_OK && rv != B_OK)
1389				return rv;
1390		}
1391	}
1392
1393	progress_shutdown(100, progress, cookie);
1394	return B_OK;
1395}
1396
1397
1398void
1399progress_startup(int stage,
1400	bool (*progress)(int stage, const char* message, void* cookie),
1401	void* cookie)
1402{
1403	// parameter "message" is no longer used. It is kept for compatibility with
1404	// BeOS as this is used as a shutdown_media_server callback.
1405
1406	TRACE("stage: %i\n", stage);
1407	const char* string = "Unknown stage";
1408	switch (stage) {
1409		case 10:
1410			string = B_TRANSLATE("Stopping media server" B_UTF8_ELLIPSIS);
1411			break;
1412		case 20:
1413			string = B_TRANSLATE("Stopping media_addon_server.");
1414			break;
1415		case 50:
1416			string = B_TRANSLATE("Starting media_services.");
1417			break;
1418		case 90:
1419			string = B_TRANSLATE("Error occurred starting media services.");
1420			break;
1421		case 100:
1422			string = B_TRANSLATE("Ready for use.");
1423			break;
1424	}
1425
1426	if (progress == NULL)
1427		notify_system(stage / 100.0f, string);
1428	else
1429		progress(stage, string, cookie);
1430}
1431
1432
1433status_t
1434launch_media_server(bigtime_t timeout,
1435	bool (*progress)(int stage, const char* message, void* cookie),
1436	void* cookie, uint32 flags)
1437{
1438	if (BMediaRoster::IsRunning())
1439		return B_ALREADY_RUNNING;
1440
1441	status_t err = B_MEDIA_SYSTEM_FAILURE;
1442	BMediaRoster* roster = BMediaRoster::Roster(&err);
1443	if (roster == NULL || err != B_OK)
1444		return err;
1445
1446	if (progress == NULL && roster->Lock()) {
1447		MediaRosterEx(roster)->EnableLaunchNotification(true, true);
1448		roster->Unlock();
1449	}
1450
1451	// The media_server crashed
1452	if (be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE)) {
1453		progress_startup(10, progress, cookie);
1454		kill_team(be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE));
1455	}
1456
1457	// The media_addon_server crashed
1458	if (be_roster->IsRunning(B_MEDIA_SERVER_SIGNATURE)) {
1459		progress_startup(20, progress, cookie);
1460		kill_team(be_roster->TeamFor(B_MEDIA_SERVER_SIGNATURE));
1461	}
1462
1463	progress_startup(50, progress, cookie);
1464
1465	err = BLaunchRoster().Start(B_MEDIA_SERVER_SIGNATURE);
1466
1467	if (err != B_OK)
1468		progress_startup(90, progress, cookie);
1469	else if (progress != NULL) {
1470		progress_startup(100, progress, cookie);
1471		err = B_OK;
1472	}
1473
1474	return err;
1475}
1476
1477
1478// #pragma mark - media_encode_info
1479
1480
1481media_encode_info::media_encode_info()
1482{
1483	flags = 0;
1484	used_data_size = 0;
1485	start_time = 0;
1486	time_to_encode = INT64_MAX;
1487	file_format_data = NULL;
1488	file_format_data_size = 0;
1489	codec_data = NULL;
1490	codec_data_size = 0;
1491}
1492
1493
1494media_decode_info::media_decode_info()
1495{
1496	time_to_decode = INT64_MAX;
1497	file_format_data = NULL;
1498	file_format_data_size = 0;
1499	codec_data = NULL;
1500	codec_data_size = 0;
1501}
1502
1503
1504