/***********************************************************************
 * AUTHOR: Marcus Overhagen
 *   FILE: MediaDefs.cpp
 *  DESCR: 
 ***********************************************************************/
#include <MediaDefs.h>
#include <MediaNode.h>
#include <stdio.h>
#include <string.h>
#include "debug.h"

/*************************************************************
 * media_destination
 *************************************************************/

// final
media_destination::media_destination(port_id port,
									 int32 id)
	: port(port),
	id(id)
{
}

// final
media_destination::media_destination(const media_destination &clone)
	: port(clone.port),
	id(clone.id)
{
}

// final
media_destination &
media_destination::operator=(const media_destination &clone)
{
	port = clone.port;
	id = clone.id;
	return *this;
}

// final & verfied
media_destination::media_destination()
	: port(-1),
	id(-1)
{
}

// final
media_destination::~media_destination()
{
}

// final & verfied
media_destination media_destination::null(-1,-1);

/*************************************************************
 * media_source
 *************************************************************/

// final
media_source::media_source(port_id port,
						   int32 id)
	: port(port),
	id(id)
{
}

// final
media_source::media_source(const media_source &clone)
	: port(clone.port),
	id(clone.id)
{
}

// final
media_source &
media_source::operator=(const media_source &clone)
{
	port = clone.port;
	id = clone.id;
	return *this;
}

// final & verfied
media_source::media_source()
	: port(-1),
	id(-1)
{
}

// final
media_source::~media_source()
{
}

// final & verfied
media_source media_source::null(-1,-1);

/*************************************************************
 * 
 *************************************************************/

// final
bool operator==(const media_destination & a, const media_destination & b)
{
	return (a.port == b.port) && (a.id == b.id);
}

// final
bool operator!=(const media_destination & a, const media_destination & b)
{
	return (a.port != b.port) || (a.id != b.id);
}

bool operator<(const media_destination & a, const media_destination & b)
{
	UNIMPLEMENTED();
	return false;
}

// final
bool operator==(const media_source & a, const media_source & b)
{
	return (a.port == b.port) && (a.id == b.id);
}

// final
bool operator!=(const media_source & a, const media_source & b)
{
	return (a.port != b.port) || (a.id != b.id);
}

bool operator<(const media_source & a, const media_source & b)
{
	UNIMPLEMENTED();
	return false;
}

// final
bool operator==(const media_node & a, const media_node & b)
{
	return (a.node == b.node) && (a.port == b.port) && (a.kind == b.kind);
}

// final
bool operator!=(const media_node & a, const media_node & b)
{
	return (a.node != b.node) || (a.port != b.port) || (a.kind != b.kind);
}

bool operator<(const media_node & a, const media_node & b)
{
	UNIMPLEMENTED();
	return false;
}


/*************************************************************
 * 
 *************************************************************/

media_multi_audio_format media_raw_audio_format::wildcard;

media_multi_audio_format media_multi_audio_format::wildcard;

media_encoded_audio_format media_encoded_audio_format::wildcard = {{0}};

media_video_display_info media_video_display_info::wildcard = {(color_space)0};

media_raw_video_format media_raw_video_format::wildcard = {0};

media_encoded_video_format media_encoded_video_format::wildcard = {{0}};

media_multistream_format media_multistream_format::wildcard = {0};

/*************************************************************
 * helper functions for media_format::Matches()
 *************************************************************/

static bool raw_audio_format_matches(const media_raw_audio_format &a, const media_raw_audio_format &b);
static bool multi_audio_info_matches(const media_multi_audio_info &a, const media_multi_audio_info &b);
static bool multi_audio_format_matches(const media_multi_audio_format &a, const media_multi_audio_format &b);
static bool raw_video_format_matches(const media_raw_video_format &a, const media_raw_video_format &b);
static bool multistream_format_matches(const media_multistream_format &a, const media_multistream_format &b);
static bool encoded_audio_format_matches(const media_encoded_audio_format &a, const media_encoded_audio_format &b);
static bool encoded_video_format_matches(const media_encoded_video_format &a, const media_encoded_video_format &b);

static bool
raw_audio_format_matches(const media_raw_audio_format &a, const media_raw_audio_format &b)
{
	if (a.frame_rate != 0 && b.frame_rate != 0 && a.frame_rate != b.frame_rate)
		return false;
	if (a.channel_count != 0 && b.channel_count != 0 && a.channel_count != b.channel_count)
		return false;
	if (a.format != 0 && b.format != 0 && a.format != b.format)
		return false;
	if (a.byte_order != 0 && b.byte_order != 0 && a.byte_order != b.byte_order)
		return false;
	if (a.buffer_size != 0 && b.buffer_size != 0 && a.buffer_size != b.buffer_size)
		return false;
	if (a.frame_rate != 0 && b.frame_rate != 0 && a.frame_rate != b.frame_rate)
		return false;
	return true;
}

static bool
multi_audio_info_matches(const media_multi_audio_info &a, const media_multi_audio_info &b)
{
	if (a.channel_mask != 0 && b.channel_mask != 0 && a.channel_mask != b.channel_mask)
		return false;
	if (a.valid_bits != 0 && b.valid_bits != 0 && a.valid_bits != b.valid_bits)
		return false;
	if (a.matrix_mask != 0 && b.matrix_mask != 0 && a.matrix_mask != b.matrix_mask)
		return false;
	return true;
}

static bool
multi_audio_format_matches(const media_multi_audio_format &a, const media_multi_audio_format &b)
{
	return raw_audio_format_matches(a, b) && multi_audio_info_matches(a, b);
}

static bool
raw_video_format_matches(const media_raw_video_format &a, const media_raw_video_format &b)
{
	if (a.field_rate != 0 && b.field_rate != 0 && a.field_rate != b.field_rate)
		return false;
	if (a.interlace != 0 && b.interlace != 0 && a.interlace != b.interlace)
		return false;
	if (a.first_active != 0 && b.first_active != 0 && a.first_active != b.first_active)
		return false;
	if (a.last_active != 0 && b.last_active != 0 && a.last_active != b.last_active)
		return false;
	if (a.orientation != 0 && b.orientation != 0 && a.orientation != b.orientation)
		return false;
	if (a.pixel_width_aspect != 0 && b.pixel_width_aspect != 0 && a.pixel_width_aspect != b.pixel_width_aspect)
		return false;
	if (a.pixel_height_aspect != 0 && b.pixel_height_aspect != 0 && a.pixel_height_aspect != b.pixel_height_aspect)
		return false;
	if (a.display.format != 0 && b.display.format != 0 && a.display.format != b.display.format)
		return false;
	if (a.display.line_width != 0 && b.display.line_width != 0 && a.display.line_width != b.display.line_width)
		return false;
	if (a.display.line_count != 0 && b.display.line_count != 0 && a.display.line_count != b.display.line_count)
		return false;
	if (a.display.bytes_per_row != 0 && b.display.bytes_per_row != 0 && a.display.bytes_per_row != b.display.bytes_per_row)
		return false;
	if (a.display.pixel_offset != 0 && b.display.pixel_offset != 0 && a.display.pixel_offset != b.display.pixel_offset)
		return false;
	if (a.display.line_offset != 0 && b.display.line_offset != 0 && a.display.line_offset != b.display.line_offset)
		return false;
	if (a.display.flags != 0 && b.display.flags != 0 && a.display.flags != b.display.flags)
		return false;
	return true;
}

static bool
multistream_format_matches(const media_multistream_format &a, const media_multistream_format &b)
{
	if (a.avg_bit_rate != 0 && b.avg_bit_rate != 0 && a.avg_bit_rate != b.avg_bit_rate)
		return false;
	if (a.max_bit_rate != 0 && b.max_bit_rate != 0 && a.max_bit_rate != b.max_bit_rate)
		return false;
	if (a.avg_chunk_size != 0 && b.avg_chunk_size != 0 && a.avg_chunk_size != b.avg_chunk_size)
		return false;
	if (a.max_chunk_size != 0 && b.max_chunk_size != 0 && a.max_chunk_size != b.max_chunk_size)
		return false;
	if (a.flags != 0 && b.flags != 0 && a.flags != b.flags)
		return false;
	if (a.format != 0 && b.format != 0 && a.format != b.format)
		return false;

	if (a.format == 0 && b.format == 0)
		return true; // XXX how do we compare two formats with no type?

	switch ((a.format != 0) ? a.format : b.format) {
		default:
			return true; // XXX really?
					
		case media_multistream_format::B_VID:
			if (a.u.vid.frame_rate != 0 && b.u.vid.frame_rate != 0 && a.u.vid.frame_rate != b.u.vid.frame_rate)
				return false;
			if (a.u.vid.width != 0 && b.u.vid.width != 0 && a.u.vid.width != b.u.vid.width)
				return false;
			if (a.u.vid.height != 0 && b.u.vid.height != 0 && a.u.vid.height != b.u.vid.height)
				return false;
			if (a.u.vid.space != 0 && b.u.vid.space != 0 && a.u.vid.space != b.u.vid.space)
				return false;
			if (a.u.vid.sampling_rate != 0 && b.u.vid.sampling_rate != 0 && a.u.vid.sampling_rate != b.u.vid.sampling_rate)
				return false;
			if (a.u.vid.sample_format != 0 && b.u.vid.sample_format != 0 && a.u.vid.sample_format != b.u.vid.sample_format)
				return false;
			if (a.u.vid.byte_order != 0 && b.u.vid.byte_order != 0 && a.u.vid.byte_order != b.u.vid.byte_order)
				return false;
			if (a.u.vid.channel_count != 0 && b.u.vid.channel_count != 0 && a.u.vid.channel_count != b.u.vid.channel_count)
				return false;
			return true;
					
		case media_multistream_format::B_AVI:
			if (a.u.avi.us_per_frame != 0 && b.u.avi.us_per_frame != 0 && a.u.avi.us_per_frame != b.u.avi.us_per_frame)
				return false;
			if (a.u.avi.width != 0 && b.u.avi.width != 0 && a.u.avi.width != b.u.avi.width)
				return false;
			if (a.u.avi.height != 0 && b.u.avi.height != 0 && a.u.avi.height != b.u.avi.height)
				return false;
			if (a.u.avi.type_count != 0 && b.u.avi.type_count != 0 && a.u.avi.type_count != b.u.avi.type_count)
				return false;
			if (a.u.avi.types[0] != 0 && b.u.avi.types[0] != 0 && a.u.avi.types[0] != b.u.avi.types[0])
				return false;
			if (a.u.avi.types[1] != 0 && b.u.avi.types[1] != 0 && a.u.avi.types[1] != b.u.avi.types[1])
				return false;
			if (a.u.avi.types[2] != 0 && b.u.avi.types[2] != 0 && a.u.avi.types[2] != b.u.avi.types[2])
				return false;
			if (a.u.avi.types[3] != 0 && b.u.avi.types[3] != 0 && a.u.avi.types[3] != b.u.avi.types[3])
				return false;
			if (a.u.avi.types[4] != 0 && b.u.avi.types[4] != 0 && a.u.avi.types[4] != b.u.avi.types[4])
				return false;
			return true;
	}
}

static bool
encoded_audio_format_matches(const media_encoded_audio_format &a, const media_encoded_audio_format &b)
{
	if (!raw_audio_format_matches(a.output, b.output))
		return false;
	if (a.encoding != 0 && b.encoding != 0 && a.encoding != b.encoding)
		return false;
	if (a.bit_rate != 0 && b.bit_rate != 0 && a.bit_rate != b.bit_rate)
		return false;
	if (a.frame_size != 0 && b.frame_size != 0 && a.frame_size != b.frame_size)
		return false;
	if (!multi_audio_info_matches(a.multi_info, b.multi_info))
		return false;
		
	if (a.encoding == 0 && b.encoding == 0)
		return true; // can't compare
		
	switch((a.encoding != 0) ? a.encoding : b.encoding) {
		case media_encoded_audio_format::B_ANY:
		default:
			return true;
	}
}

static bool
encoded_video_format_matches(const media_encoded_video_format &a, const media_encoded_video_format &b)
{
	if (!raw_video_format_matches(a.output, b.output))
		return false;
	if (a.encoding != 0 && b.encoding != 0 && a.encoding != b.encoding)
		return false;

	if (a.avg_bit_rate != 0 && b.avg_bit_rate != 0 && a.avg_bit_rate != b.avg_bit_rate)
		return false;
	if (a.max_bit_rate != 0 && b.max_bit_rate != 0 && a.max_bit_rate != b.max_bit_rate)
		return false;
	if (a.frame_size != 0 && b.frame_size != 0 && a.frame_size != b.frame_size)
		return false;
	if (a.forward_history != 0 && b.forward_history != 0 && a.forward_history != b.forward_history)
		return false;
	if (a.backward_history != 0 && b.backward_history != 0 && a.backward_history != b.backward_history)
		return false;

	if (a.encoding == 0 && b.encoding == 0)
		return true; // can't compare
		
	switch((a.encoding != 0) ? a.encoding : b.encoding) {
		case media_encoded_video_format::B_ANY:
		default:
			return true;
	}
}

/*************************************************************
 * helper functions for media_format::SpecializeTo()
 *************************************************************/

static void raw_audio_format_specialize(media_raw_audio_format *format, const media_raw_audio_format *other);
static void multi_audio_info_specialize(media_multi_audio_info *format, const media_multi_audio_info *other);
static void multi_audio_format_specialize(media_multi_audio_format *format, const media_multi_audio_format *other);
static void raw_video_format_specialize(media_raw_video_format *format, const media_raw_video_format *other);
static void multistream_format_specialize(media_multistream_format *format, const media_multistream_format *other);
static void encoded_audio_format_specialize(media_encoded_audio_format *format, const media_encoded_audio_format *other);
static void encoded_video_format_specialize(media_encoded_video_format *format, const media_encoded_video_format *other);


static void
raw_audio_format_specialize(media_raw_audio_format *format, const media_raw_audio_format *other)
{
	if (format->frame_rate == 0)
		format->frame_rate = other->frame_rate;
	if (format->channel_count == 0)
		format->channel_count = other->channel_count;
	if (format->format == 0)
		format->format = other->format;
	if (format->byte_order == 0)
		format->byte_order = other->byte_order;
	if (format->buffer_size == 0)
		format->buffer_size = other->buffer_size;
	if (format->frame_rate == 0)
		format->frame_rate = other->frame_rate;
}

static void
multi_audio_info_specialize(media_multi_audio_info *format, const media_multi_audio_info *other)
{
	if (format->channel_mask == 0)
		format->channel_mask = other->channel_mask;
	if (format->valid_bits == 0)
		format->valid_bits = other->valid_bits;
	if (format->matrix_mask == 0)
		format->matrix_mask = other->matrix_mask;
}

static void
multi_audio_format_specialize(media_multi_audio_format *format, const media_multi_audio_format *other)
{
	raw_audio_format_specialize(format, other);
	multi_audio_info_specialize(format, other);
}

static void
raw_video_format_specialize(media_raw_video_format *format, const media_raw_video_format *other)
{
	if (format->field_rate == 0)
		format->field_rate = other->field_rate;
	if (format->interlace == 0)
		format->interlace = other->interlace;
	if (format->first_active == 0)
		format->first_active = other->first_active;
	if (format->last_active == 0)
		format->last_active = other->last_active;
	if (format->orientation == 0)
		format->orientation = other->orientation;
	if (format->pixel_width_aspect == 0)
		format->pixel_width_aspect = other->pixel_width_aspect;
	if (format->pixel_height_aspect == 0)
		format->pixel_height_aspect = other->pixel_height_aspect;
	if (format->display.format == 0)
		format->display.format = other->display.format;
	if (format->display.line_width == 0)
		format->display.line_width = other->display.line_width;
	if (format->display.line_count == 0)
		format->display.line_count = other->display.line_count;
	if (format->display.bytes_per_row == 0)
		format->display.bytes_per_row = other->display.bytes_per_row;
	if (format->display.pixel_offset == 0)
		format->display.pixel_offset = other->display.pixel_offset;
	if (format->display.line_offset == 0)
		format->display.line_offset = other->display.line_offset;
	if (format->display.flags == 0)
		format->display.flags = other->display.flags;
}

static void
multistream_format_specialize(media_multistream_format *format, const media_multistream_format *other)
{
	if (format->avg_bit_rate == 0)
		format->avg_bit_rate = other->avg_bit_rate;
	if (format->max_bit_rate == 0)
		format->max_bit_rate = other->max_bit_rate;
	if (format->avg_chunk_size == 0)
		format->avg_chunk_size = other->avg_chunk_size;
	if (format->max_chunk_size == 0)
		format->max_chunk_size = other->max_chunk_size;
	if (format->flags == 0)
		format->flags = other->flags;
	if (format->format == 0)
		format->format = other->format;
		
	switch (format->format) {
		case media_multistream_format::B_VID:
			if (format->u.vid.frame_rate == 0)
				format->u.vid.frame_rate = other->u.vid.frame_rate;
			if (format->u.vid.width == 0)
				format->u.vid.width = other->u.vid.width;
			if (format->u.vid.height == 0)
				format->u.vid.height = other->u.vid.height;
			if (format->u.vid.space == 0)
				format->u.vid.space = other->u.vid.space;
			if (format->u.vid.sampling_rate == 0)
				format->u.vid.sampling_rate = other->u.vid.sampling_rate;
			if (format->u.vid.sample_format == 0)
				format->u.vid.sample_format = other->u.vid.sample_format;
			if (format->u.vid.byte_order == 0)
				format->u.vid.byte_order = other->u.vid.byte_order;
			if (format->u.vid.channel_count == 0)
				format->u.vid.channel_count = other->u.vid.channel_count;
			break;

		case media_multistream_format::B_AVI:
			if (format->u.avi.us_per_frame == 0)
				format->u.avi.us_per_frame = other->u.avi.us_per_frame;
			if (format->u.avi.width == 0)
				format->u.avi.width = other->u.avi.width;
			if (format->u.avi.height == 0)
				format->u.avi.height = other->u.avi.height;
			if (format->u.avi.type_count == 0)
				format->u.avi.type_count = other->u.avi.type_count;
			if (format->u.avi.types[0] == 0)
				format->u.avi.types[0] = other->u.avi.types[0];
			if (format->u.avi.types[1] == 0)
				format->u.avi.types[1] = other->u.avi.types[1];
			if (format->u.avi.types[2] == 0)
				format->u.avi.types[2] = other->u.avi.types[2];
			if (format->u.avi.types[3] == 0)
				format->u.avi.types[3] = other->u.avi.types[3];
			if (format->u.avi.types[4] == 0)
				format->u.avi.types[4] = other->u.avi.types[4];
			break;

		default:
			ERROR("media_format::SpecializeTo can't specialize media_multistream_format of format %d\n", format->format);
	}
}

static void
encoded_audio_format_specialize(media_encoded_audio_format *format, const media_encoded_audio_format *other)
{
	raw_audio_format_specialize(&format->output, &other->output);
	if (format->encoding == 0)
		format->encoding = other->encoding;
	if (format->bit_rate == 0)
		format->bit_rate = other->bit_rate;
	if (format->frame_size == 0)
		format->frame_size = other->frame_size;
	multi_audio_info_specialize(&format->multi_info, &other->multi_info);
}

static void
encoded_video_format_specialize(media_encoded_video_format *format, const media_encoded_video_format *other)
{
	raw_video_format_specialize(&format->output, &other->output);
	if (format->avg_bit_rate == 0)
		format->avg_bit_rate = other->avg_bit_rate;
	if (format->max_bit_rate == 0)
		format->max_bit_rate = other->max_bit_rate;
	if (format->encoding == 0)
		format->encoding = other->encoding;
	if (format->frame_size == 0)
		format->frame_size = other->frame_size;
	if (format->forward_history == 0)
		format->forward_history = other->forward_history;
	if (format->backward_history == 0)
		format->backward_history = other->backward_history;
}


/*************************************************************
 * media_format
 *************************************************************/

bool
media_format::Matches(const media_format *other) const
{
	CALLED();
	if (type == 0 && other->type == 0)
		return true; // XXX how do we compare two formats with no type?
		
	if (type != 0 && other->type != 0 && type != other->type)
		return false;
	
	switch ((type != 0) ? type : other->type) {
		case B_MEDIA_RAW_AUDIO:
			return multi_audio_format_matches(u.raw_audio, other->u.raw_audio);
			
		case B_MEDIA_RAW_VIDEO:
			return raw_video_format_matches(u.raw_video, other->u.raw_video);

		case B_MEDIA_MULTISTREAM:
			return multistream_format_matches(u.multistream, other->u.multistream);
				
		case B_MEDIA_ENCODED_AUDIO:
			return encoded_audio_format_matches(u.encoded_audio, other->u.encoded_audio);

		case B_MEDIA_ENCODED_VIDEO:
			return encoded_video_format_matches(u.encoded_video, other->u.encoded_video);
		
		default:
			return true; // XXX really?
	}
}

void
media_format::SpecializeTo(const media_format *otherFormat)
{
	CALLED();
	if (type == 0 && otherFormat->type == 0) {
		ERROR("media_format::SpecializeTo can't specialize wildcard to other wildcard format\n");
		return;
	}
		
	if (type == 0)
		type = otherFormat->type;
	
	switch (type) {
		case B_MEDIA_RAW_AUDIO:
			multi_audio_format_specialize(&u.raw_audio, &otherFormat->u.raw_audio);
			return;
			
		case B_MEDIA_RAW_VIDEO:
			raw_video_format_specialize(&u.raw_video, &otherFormat->u.raw_video);
			return;

		case B_MEDIA_MULTISTREAM:
			multistream_format_specialize(&u.multistream, &otherFormat->u.multistream);
			return;
	
		case B_MEDIA_ENCODED_AUDIO:
			encoded_audio_format_specialize(&u.encoded_audio, &otherFormat->u.encoded_audio);
			return;

		case B_MEDIA_ENCODED_VIDEO:
			encoded_video_format_specialize(&u.encoded_video, &otherFormat->u.encoded_video);
			return;
		
		default:
			ERROR("media_format::SpecializeTo can't specialize format type %d\n", type);
	}
}


status_t
media_format::SetMetaData(const void *data,
						  size_t size)
{
	UNIMPLEMENTED();

	return B_ERROR;
}


const void *
media_format::MetaData() const
{
	UNIMPLEMENTED();
	return NULL;
}


int32
media_format::MetaDataSize() const
{
	UNIMPLEMENTED();

	return 0;
}

// final
media_format::media_format()
{
	memset(this, 0x00, sizeof(*this));
	//meta_data, meta_data_size, meta_data_area, use_area, 
	//team, and thisPtr are currently only used by decoders
	//when communicating with the file reader; they're not
	//currently for public use.
	
	//If any field is 0, it's treated as a wildcard
}


// final
media_format::media_format(const media_format &other)
{
	*this = other;
}

// final
media_format::~media_format()
{
}


// final
media_format &
media_format::operator=(const media_format &clone)
{
	memset(this, 0x00, sizeof(*this));

	type = clone.type;
	user_data_type = clone.user_data_type;

	memcpy(user_data, clone.user_data, sizeof(media_format::user_data));

	require_flags = clone.require_flags;
	deny_flags = clone.deny_flags;

	memcpy(u._reserved_, clone.u._reserved_, sizeof(media_format::u._reserved_));
	return *this;
}

/*************************************************************
 * 
 *************************************************************/


bool operator==(const media_raw_audio_format & a, const media_raw_audio_format & b)
{
	return (   a.frame_rate == b.frame_rate
			&& a.channel_count == b.channel_count
			&& a.format == b.format
			&& a.byte_order == b.byte_order
			&& a.buffer_size == b.buffer_size);
}

bool operator==(const media_multi_audio_info & a, const media_multi_audio_info & b)
{
	return (   a.channel_mask == b.channel_mask
			&& a.valid_bits == b.valid_bits
			&& a.matrix_mask == b.matrix_mask);
}

bool operator==(const media_multi_audio_format & a, const media_multi_audio_format & b)
{
	return (   (media_raw_audio_format)a == (media_raw_audio_format)b
			&& (media_multi_audio_info)a == (media_multi_audio_info)b);
}

bool operator==(const media_encoded_audio_format & a, const media_encoded_audio_format & b)
{
	return (   a.output == b.output
			&& a.encoding == b.encoding
			&& a.bit_rate == b.bit_rate
			&& a.frame_size == b.frame_size
			&& a.multi_info == b.multi_info);
}

bool operator==(const media_video_display_info & a, const media_video_display_info & b)
{
	return (   a.format == b.format
			&& a.line_width == b.line_width
			&& a.line_count == b.line_count
			&& a.bytes_per_row == b.bytes_per_row
			&& a.pixel_offset == b.pixel_offset
			&& a.line_offset == b.line_offset
			&& a.flags == b.flags);
}

bool operator==(const media_raw_video_format & a, const media_raw_video_format & b)
{
	return (   a.field_rate == b.field_rate
			&& a.interlace == b.interlace
			&& a.first_active == b.first_active
			&& a.last_active == b.last_active
			&& a.orientation == b.orientation
			&& a.pixel_width_aspect == b.pixel_width_aspect
			&& a.pixel_height_aspect == b.pixel_height_aspect
			&& a.display == b.display);
}

bool operator==(const media_encoded_video_format & a, const media_encoded_video_format & b)
{
	return (   a.output == b.output
			&& a.avg_bit_rate == b.avg_bit_rate
			&& a.max_bit_rate == b.max_bit_rate
			&& a.encoding == b.encoding
			&& a.frame_size == b.frame_size
			&& a.forward_history == b.forward_history
			&& a.backward_history == b.backward_history);
}

bool operator==(const media_multistream_format::vid_info & a, const media_multistream_format::vid_info & b)
{
	return (   a.frame_rate == b.frame_rate
			&& a.width == b.width
			&& a.height == b.height
			&& a.space == b.space
			&& a.sampling_rate == b.sampling_rate
			&& a.sample_format == b.sample_format
			&& a.byte_order == b.byte_order
			&& a.channel_count == b.channel_count);
}

bool operator==(const media_multistream_format::avi_info & a, const media_multistream_format::avi_info & b)
{
	return (   a.us_per_frame == b.us_per_frame
			&& a.width == b.width
			&& a.height == b.height
			&& a.type_count == b.type_count
			&& a.types[0] == b.types[0]
			&& a.types[1] == b.types[1]
			&& a.types[2] == b.types[2]
			&& a.types[3] == b.types[3]
			&& a.types[4] == b.types[4]);
}

bool operator==(const media_multistream_format & a, const media_multistream_format & b)
{
	if (a.avg_bit_rate != b.avg_bit_rate
		|| a.max_bit_rate != b.max_bit_rate
		|| a.avg_chunk_size != b.avg_chunk_size
		|| a.max_chunk_size != b.max_chunk_size
		|| a.format != b.format
		|| a.flags != b.flags)
		return false;

	switch (a.format) {
		case media_multistream_format::B_VID:
			return a.u.vid == b.u.vid;
			
		case media_multistream_format::B_AVI:
			return a.u.avi == b.u.avi;

		default:
			return true; // XXX really?
	}
}

bool operator==(const media_format & a, const media_format & b)
{
	if (a.type != b.type
		|| a.user_data_type != b.user_data_type
		// XXX compare user_data[48] ?
		|| a.require_flags != b.require_flags
		|| a.deny_flags != b.deny_flags)
		return false;
		
	switch (a.type) {
		case B_MEDIA_RAW_AUDIO:
			return a.u.raw_audio == b.u.raw_audio;
			
		case B_MEDIA_RAW_VIDEO:
			return a.u.raw_video == b.u.raw_video;
			
		case B_MEDIA_MULTISTREAM:
			return a.u.multistream == b.u.multistream;
			
		case B_MEDIA_ENCODED_AUDIO:
			return a.u.encoded_audio == b.u.encoded_audio;
			
		case B_MEDIA_ENCODED_VIDEO:
			return a.u.encoded_video == b.u.encoded_video;
			
		default:
			return true; // XXX really?
	}
}

/*************************************************************
 * 
 *************************************************************/

/* return true if a and b are compatible (accounting for wildcards) */
bool format_is_compatible(const media_format & a, const media_format & b)	/* a is the format you want to feed to something accepting b */
{
	return a.Matches(&b);
}

bool string_for_format(const media_format & f, char * buf, size_t size)
{
	char encoding[10]; /* maybe Be wanted to use some 4CCs ? */
	const char *video_orientation = "0"; /* I'd use "NC", R5 uses 0. */
	
	if (buf == NULL)
		return false;
	switch (f.type) {
	case B_MEDIA_RAW_AUDIO:
		snprintf(buf, size, 
				"raw_audio;%g;%ld;0x%lx;%ld;0x%lx;0x%08lx;%d;0x%04x", 
				f.u.raw_audio.frame_rate, 
				f.u.raw_audio.channel_count, 
				f.u.raw_audio.format, 
				f.u.raw_audio.byte_order, 
				f.u.raw_audio.buffer_size,
				f.u.raw_audio.channel_mask,
				f.u.raw_audio.valid_bits,
				f.u.raw_audio.matrix_mask);
		return true;
	case B_MEDIA_RAW_VIDEO:
		if (f.u.raw_video.orientation == B_VIDEO_TOP_LEFT_RIGHT)
			video_orientation = "TopLR";
		else if (f.u.raw_video.orientation == B_VIDEO_BOTTOM_LEFT_RIGHT)
			video_orientation = "BotLR";
		//snprintf(buf, size, "raw_video;%g;%ld;%ld;%ld;%s;%d;%d;%d;%d;%d;%d;%d;%d",
		snprintf(buf, size, "raw_video;%g;0x%x;%ld;%ld;%ld;%ld;%s;%d;%d",
				f.u.raw_video.field_rate,
				f.u.raw_video.display.format,
				f.u.raw_video.interlace,
				f.u.raw_video.display.line_width,
				f.u.raw_video.display.line_count,
				f.u.raw_video.first_active,
				video_orientation,
				f.u.raw_video.pixel_width_aspect,
				f.u.raw_video.pixel_height_aspect);
		return true;
	case B_MEDIA_ENCODED_AUDIO:
		snprintf(encoding, 10, "%d", f.u.encoded_audio.encoding);
		snprintf(buf, size, 
				"caudio;%s;%g;%ld;(%g;%ld;0x%lx;%ld;0x%lx;0x%08lx;%d;0x%04x)", 
				encoding, // f.u.encoded_audio.encoding, 
				f.u.encoded_audio.bit_rate, 
				f.u.encoded_audio.frame_size, 
				// (
				f.u.encoded_audio.output.frame_rate, 
				f.u.encoded_audio.output.channel_count, 
				f.u.encoded_audio.output.format, 
				f.u.encoded_audio.output.byte_order, 
				f.u.encoded_audio.output.buffer_size,
				f.u.encoded_audio.multi_info.channel_mask,
				f.u.encoded_audio.multi_info.valid_bits,
				f.u.encoded_audio.multi_info.matrix_mask);
				// )
		return true;
	case B_MEDIA_ENCODED_VIDEO:
		snprintf(encoding, 10, "%d", f.u.encoded_video.encoding);
		if (f.u.encoded_video.output.orientation == B_VIDEO_TOP_LEFT_RIGHT)
			video_orientation = "TopLR";
		else if (f.u.encoded_video.output.orientation == B_VIDEO_BOTTOM_LEFT_RIGHT)
			video_orientation = "BotLR";
		snprintf(buf, size, 
				"cvideo;%s;%g;%g;%ld;(%g;0x%x;%ld;%ld;%ld;%ld;%s;%d;%d)",
				encoding, 
				f.u.encoded_video.avg_bit_rate, 
				f.u.encoded_video.max_bit_rate, 
				f.u.encoded_video.frame_size,
				// (
				f.u.encoded_video.output.field_rate,
				f.u.encoded_video.output.display.format,
				f.u.encoded_video.output.interlace,
				f.u.encoded_video.output.display.line_width, 
				f.u.encoded_video.output.display.line_count,
				f.u.encoded_video.output.first_active,
				video_orientation,
				f.u.encoded_video.output.pixel_width_aspect,
				f.u.encoded_video.output.pixel_height_aspect);
				// )
		return true;
	default:
		snprintf(buf, size, "%d-", f.type);
		unsigned char *p = (unsigned char *)&(f.u);
		size -= strlen(buf);
		buf += strlen(buf);
		for (int i = 0; (size > 2) && (i < 96); i++) {
			snprintf(buf, 3, "%2.2x", *(p + i));
			buf+=2;
			size-=2;
		}
		return true; // ?
	}
	return false;
}

/*************************************************************
 * 
 *************************************************************/

bool operator==(const media_file_format_id & a, const media_file_format_id & b)
{
	UNIMPLEMENTED();
	return false;
}

bool operator<(const media_file_format_id & a, const media_file_format_id & b)
{
	UNIMPLEMENTED();
	return false;
}

/*************************************************************
 * 
 *************************************************************/

//
// Use this function iterate through available file format writers
//
status_t get_next_file_format(int32 *cookie, media_file_format *mfi)
{
	UNIMPLEMENTED();
	return B_ERROR;
}


/*************************************************************
 * 
 *************************************************************/

// final & verified
const char * B_MEDIA_SERVER_SIGNATURE = "application/x-vnd.Be.media-server";

const type_code B_CODEC_TYPE_INFO = 0x12345678; // XXX fixme

/*************************************************************
 * 
 *************************************************************/

struct dormant_node_info
{
};

struct buffer_clone_info
{
};

/*************************************************************
 * 
 *************************************************************/


//	If you for some reason need to get rid of the media_server (and friends)
//	use these functions, rather than sending messages yourself.
//	The callback will be called for various stages of the process, with 100 meaning completely done
//	The callback should always return TRUE for the time being.
status_t shutdown_media_server(bigtime_t timeout = B_INFINITE_TIMEOUT, bool (*progress)(int stage, const char * message, void * cookie) = NULL, void * cookie = NULL)
{
	UNIMPLEMENTED();
	return B_OK;
}

status_t launch_media_server(uint32 flags = 0)
{
	UNIMPLEMENTED();
	return B_OK;
}

//	Given an image_id, prepare that image_id for realtime media
//	If the kind of media indicated by "flags" is not enabled for real-time,
//	B_MEDIA_REALTIME_DISABLED is returned.
//	If there are not enough system resources to enable real-time performance,
//	B_MEDIA_REALTIME_UNAVAILABLE is returned.
status_t media_realtime_init_image(image_id image, uint32 flags)
{
	UNIMPLEMENTED();
	return B_OK;
}

//	Given a thread ID, and an optional indication of what the thread is
//	doing in "flags", prepare the thread for real-time media performance.
//	Currently, this means locking the thread stack, up to size_used bytes,
//	or all of it if 0 is passed. Typically, you will not be using all
//	256 kB of the stack, so you should pass some smaller value you determine
//	from profiling the thread; typically in the 32-64kB range.
//	Return values are the same as for media_prepare_realtime_image().
status_t media_realtime_init_thread(thread_id thread, size_t stack_used, uint32 flags)
{
	UNIMPLEMENTED();
	return B_OK;
}

/*************************************************************
 * media_encode_info
 *************************************************************/


media_encode_info::media_encode_info()
{
	UNIMPLEMENTED();
}


media_decode_info::media_decode_info()
{
	UNIMPLEMENTED();
}


