/* * Copyright 2015, Dario Casalinuovo * Copyright 2004, 2006, Jérôme Duval. * Copyright 2003-2004, Andrew Bachmann. * Copyright 2002-2004, 2006 Marcus Overhagen. * Copyright 2002, Eric Jaessler. * All rights reserved. Distributed under the terms of the MIT license. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AddOnManager.h" #include "DataExchange.h" #include "MediaDebug.h" #include "MediaMisc.h" #include "MediaRosterEx.h" #define META_DATA_MAX_SIZE (16 << 20) #define META_DATA_AREA_MIN_SIZE 32000 #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "MediaDefs" // #pragma mark - media_destination media_destination::media_destination(port_id port, int32 id) : port(port), id(id) { } media_destination::media_destination(const media_destination& clone) : port(clone.port), id(clone.id) { } media_destination& media_destination::operator=(const media_destination& clone) { port = clone.port; id = clone.id; return *this; } media_destination::media_destination() : port(-1), id(-1) { } media_destination::~media_destination() { } media_destination media_destination::null(-1, -1); // #pragma mark - media_source media_source::media_source(port_id port, int32 id) : port(port), id(id) { } media_source::media_source(const media_source& clone) : port(clone.port), id(clone.id) { } media_source& media_source::operator=(const media_source& clone) { port = clone.port; id = clone.id; return *this; } media_source::media_source() : port(-1), id(-1) { } media_source::~media_source() { } media_source media_source::null(-1, -1); // #pragma mark - 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) { return a.port != b.port || a.id != b.id; } bool operator<(const media_destination& a, const media_destination& b) { UNIMPLEMENTED(); return false; } 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) { return a.port != b.port || a.id != b.id; } bool operator<(const media_source& a, const media_source& b) { UNIMPLEMENTED(); return false; } 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) { 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; } // #pragma mark - #if __GNUC__ == 2 const media_multi_audio_format media_raw_audio_format::wildcard = media_multi_audio_format(); const media_multi_audio_format media_multi_audio_format::wildcard = media_multi_audio_format(); #else const media_multi_audio_format media_raw_audio_format::wildcard = {}; const media_multi_audio_format media_multi_audio_format::wildcard = {}; #endif const media_encoded_audio_format media_encoded_audio_format::wildcard = {}; const media_video_display_info media_video_display_info::wildcard = {}; const media_raw_video_format media_raw_video_format::wildcard = {}; const media_encoded_video_format media_encoded_video_format::wildcard = {}; const media_multistream_format media_multistream_format::wildcard = {}; // #pragma mark - media_format::Matches() support 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) { // TODO: How do we compare two formats with no type? return true; } switch ((a.format != 0) ? a.format : b.format) { default: return true; // TODO: 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; } } // #pragma mark - media_format::SpecializeTo() support 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 %" B_PRId32 "\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; } // #pragma mark - media_format bool media_format::Matches(const media_format* other) const { CALLED(); if (type == 0 && other->type == 0) { // TODO: How do we compare two formats with no type? return true; } 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; // TODO: 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) { if (!data || size > META_DATA_MAX_SIZE) return B_BAD_VALUE; void* new_addr; area_id new_area; if (size < META_DATA_AREA_MIN_SIZE) { new_area = B_BAD_VALUE; new_addr = malloc(size); if (!new_addr) return B_NO_MEMORY; } else { new_area = create_area("meta_data_area", &new_addr, B_ANY_ADDRESS, ROUND_UP_TO_PAGE(size), B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); if (new_area < 0) return (status_t)new_area; } if (meta_data_area > 0) delete_area(meta_data_area); else free(meta_data); meta_data = new_addr; meta_data_size = size; meta_data_area = new_area; memcpy(meta_data, data, size); if (meta_data_area > 0) set_area_protection(meta_data_area, B_READ_AREA); return B_OK; } const void* media_format::MetaData() const { return meta_data; } int32 media_format::MetaDataSize() const { return meta_data_size; } void media_format::Unflatten(const char *flatBuffer) { // TODO: we should not!!! make flat copies of media_format memcpy(this, flatBuffer, sizeof(*this)); meta_data = NULL; meta_data_area = B_BAD_VALUE; } void media_format::Clear() { memset(this, 0x00, sizeof(*this)); meta_data = NULL; meta_data_area = B_BAD_VALUE; } media_format::media_format() { this->Clear(); } media_format::media_format(const media_format& other) { this->Clear(); *this = other; } media_format::~media_format() { if (meta_data_area > 0) delete_area(meta_data_area); else free(meta_data); } // final media_format& media_format::operator=(const media_format& clone) { // get rid of this format's meta data this->~media_format(); // danger: using only ~media_format() would call the constructor // make a binary copy memcpy(this, &clone, sizeof(*this)); // some binary copies are invalid: meta_data = NULL; meta_data_area = B_BAD_VALUE; // clone or copy the meta data if (clone.meta_data) { if (clone.meta_data_area != B_BAD_VALUE) { meta_data_area = clone_area("meta_data_clone_area", &meta_data, B_ANY_ADDRESS, B_READ_AREA, clone.meta_data_area); if (meta_data_area < 0) { // whoops, we just lost our meta data meta_data = NULL; meta_data_size = 0; } } else { meta_data = malloc(meta_data_size); if (meta_data) { memcpy(meta_data, clone.meta_data, meta_data_size); } else { // whoops, we just lost our meta data meta_data_size = 0; } } } return *this; } // #pragma mark - 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; // TODO: really? } } bool operator==(const media_format& a, const media_format& b) { if (a.type != b.type || a.user_data_type != b.user_data_type // TODO: 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; // TODO: really? } } // #pragma mark - /*! return \c true if a and b are compatible (accounting for wildcards) a is the format you want to feed to something accepting b */ bool format_is_compatible(const media_format& a, const media_format& 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* videoOrientation = "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;%" B_PRIu32 ";0x%" B_PRIx32 ";%" B_PRIu32 ";0x%" B_PRIxSIZE ";0x%#" B_PRIx32 ";%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) videoOrientation = "TopLR"; else if (f.u.raw_video.orientation == B_VIDEO_BOTTOM_LEFT_RIGHT) videoOrientation = "BotLR"; snprintf(buf, size, "raw_video;%g;0x%x;%" B_PRIu32 ";%" B_PRIu32 ";%" B_PRIu32 ";%" B_PRIu32 ";%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, videoOrientation, 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;%" B_PRIu32 ";0x%" B_PRIx32 ";%" B_PRIu32 ";0x%" B_PRIxSIZE ";0x%08" B_PRIx32 ";%d;0x%04x)", 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) videoOrientation = "TopLR"; else if (f.u.encoded_video.output.orientation == B_VIDEO_BOTTOM_LEFT_RIGHT) videoOrientation = "BotLR"; snprintf(buf, size, "cvideo;%s;%g;%g;%" B_PRIuSIZE ";(%g;0x%x;%" B_PRIu32 ";%" B_PRIu32 ";%" B_PRIu32 ";%" B_PRIu32 ";%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, videoOrientation, 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; } // #pragma mark - bool operator==(const media_file_format_id& a, const media_file_format_id& b) { return a.node == b.node && a.device == b.device && a.internal_id == b.internal_id; } bool operator<(const media_file_format_id& a, const media_file_format_id& b) { return a.internal_id < b.internal_id; } // #pragma mark - //! Use this function to iterate through available file format writers. status_t get_next_file_format(int32* cookie, media_file_format* mff) { if (cookie == NULL || mff == NULL) return B_BAD_VALUE; status_t ret = AddOnManager::GetInstance()->GetFileFormat(mff, *cookie); if (ret != B_OK) return ret; *cookie = *cookie + 1; return B_OK; } // #pragma mark - // final & verified const char* B_MEDIA_SERVER_SIGNATURE = "application/x-vnd.Be.media-server"; const char* B_MEDIA_ADDON_SERVER_SIGNATURE = "application/x-vnd.Be.addon-host"; const type_code B_CODEC_TYPE_INFO = 0x040807b2; // #pragma mark - // shutdown_media_server() and launch_media_server() // are provided by libbe.so in BeOS R5 #define MEDIA_SERVICE_NOTIFICATION_ID "MediaServiceNotificationID" void notify_system(float progress, const char* message) { BNotification notification(B_PROGRESS_NOTIFICATION); notification.SetMessageID(MEDIA_SERVICE_NOTIFICATION_ID); notification.SetProgress(progress); notification.SetGroup(B_TRANSLATE("Media Service")); notification.SetContent(message); app_info info; be_app->GetAppInfo(&info); BBitmap icon(BRect(0, 0, 32, 32), B_RGBA32); BNode node(&info.ref); BIconUtils::GetVectorIcon(&node, "BEOS:ICON", &icon); notification.SetIcon(&icon); notification.Send(); } void progress_shutdown(int stage, bool (*progress)(int stage, const char* message, void* cookie), void* cookie) { // parameter "message" is no longer used. It is kept for compatibility with // BeOS as this is used as a shutdown_media_server callback. TRACE("stage: %i\n", stage); const char* string = "Unknown stage"; switch (stage) { case 10: string = B_TRANSLATE("Stopping media server" B_UTF8_ELLIPSIS); break; case 20: string = B_TRANSLATE("Waiting for media_server to quit."); break; case 40: string = B_TRANSLATE("Telling media_addon_server to quit."); break; case 50: string = B_TRANSLATE("Waiting for media_addon_server to quit."); break; case 70: string = B_TRANSLATE("Cleaning up."); break; case 100: string = B_TRANSLATE("Done shutting down."); break; } if (progress == NULL) notify_system(stage / 100.0f, string); else progress(stage, string, cookie); } status_t shutdown_media_server(bigtime_t timeout, bool (*progress)(int stage, const char* message, void* cookie), void* cookie) { BLaunchRoster launchRoster; launchRoster.StopTarget(B_MEDIA_SERVER_SIGNATURE); BMessage msg(B_QUIT_REQUESTED); status_t err = B_MEDIA_SYSTEM_FAILURE; bool shutdown = false; BMediaRoster* roster = BMediaRoster::Roster(&err); if (roster == NULL || err != B_OK) return err; if (progress == NULL && roster->Lock()) { MediaRosterEx(roster)->EnableLaunchNotification(true, true); roster->Unlock(); } if ((err = msg.AddBool("be:_user_request", true)) != B_OK) return err; team_id mediaServer = be_roster->TeamFor(B_MEDIA_SERVER_SIGNATURE); team_id addOnServer = be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE); if (mediaServer != B_ERROR) { BMessage reply; BMessenger messenger(B_MEDIA_SERVER_SIGNATURE, mediaServer); progress_shutdown(10, progress, cookie); err = messenger.SendMessage(&msg, &reply, 2000000, 2000000); reply.FindBool("_shutdown", &shutdown); if (err == B_TIMED_OUT || shutdown == false) { if (messenger.IsValid()) kill_team(mediaServer); } else if (err != B_OK) return err; progress_shutdown(20, progress, cookie); int32 rv; if (reply.FindInt32("error", &rv) == B_OK && rv != B_OK) return rv; } if (addOnServer != B_ERROR) { shutdown = false; BMessage reply; BMessenger messenger(B_MEDIA_ADDON_SERVER_SIGNATURE, addOnServer); progress_shutdown(40, progress, cookie); // The media_server usually shutdown the media_addon_server, // if not let's do something. if (messenger.IsValid()) { err = messenger.SendMessage(&msg, &reply, 2000000, 2000000); reply.FindBool("_shutdown", &shutdown); if (err == B_TIMED_OUT || shutdown == false) { if (messenger.IsValid()) kill_team(addOnServer); } else if (err != B_OK) return err; progress_shutdown(50, progress, cookie); int32 rv; if (reply.FindInt32("error", &rv) == B_OK && rv != B_OK) return rv; } } progress_shutdown(100, progress, cookie); return B_OK; } void progress_startup(int stage, bool (*progress)(int stage, const char* message, void* cookie), void* cookie) { // parameter "message" is no longer used. It is kept for compatibility with // BeOS as this is used as a shutdown_media_server callback. TRACE("stage: %i\n", stage); const char* string = "Unknown stage"; switch (stage) { case 10: string = B_TRANSLATE("Stopping media server" B_UTF8_ELLIPSIS); break; case 20: string = B_TRANSLATE("Stopping media_addon_server."); break; case 50: string = B_TRANSLATE("Starting media_services."); break; case 90: string = B_TRANSLATE("Error occurred starting media services."); break; case 100: string = B_TRANSLATE("Ready for use."); break; } if (progress == NULL) notify_system(stage / 100.0f, string); else progress(stage, string, cookie); } status_t launch_media_server(bigtime_t timeout, bool (*progress)(int stage, const char* message, void* cookie), void* cookie, uint32 flags) { if (BMediaRoster::IsRunning()) return B_ALREADY_RUNNING; status_t err = B_MEDIA_SYSTEM_FAILURE; BMediaRoster* roster = BMediaRoster::Roster(&err); if (roster == NULL || err != B_OK) return err; if (progress == NULL && roster->Lock()) { MediaRosterEx(roster)->EnableLaunchNotification(true, true); roster->Unlock(); } // The media_server crashed if (be_roster->IsRunning(B_MEDIA_ADDON_SERVER_SIGNATURE)) { progress_startup(10, progress, cookie); kill_team(be_roster->TeamFor(B_MEDIA_ADDON_SERVER_SIGNATURE)); } // The media_addon_server crashed if (be_roster->IsRunning(B_MEDIA_SERVER_SIGNATURE)) { progress_startup(20, progress, cookie); kill_team(be_roster->TeamFor(B_MEDIA_SERVER_SIGNATURE)); } progress_startup(50, progress, cookie); err = BLaunchRoster().Start(B_MEDIA_SERVER_SIGNATURE); if (err != B_OK) progress_startup(90, progress, cookie); else if (progress != NULL) { progress_startup(100, progress, cookie); err = B_OK; } return err; } // #pragma mark - media_encode_info media_encode_info::media_encode_info() { flags = 0; used_data_size = 0; start_time = 0; time_to_encode = INT64_MAX; file_format_data = NULL; file_format_data_size = 0; codec_data = NULL; codec_data_size = 0; } media_decode_info::media_decode_info() { time_to_decode = INT64_MAX; file_format_data = NULL; file_format_data_size = 0; codec_data = NULL; codec_data_size = 0; }