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