diff --git a/src/add-ons/media/media-add-ons/demultiplexer/Jamfile b/src/add-ons/media/media-add-ons/demultiplexer/Jamfile new file mode 100644 index 0000000000..6b7265f94a --- /dev/null +++ b/src/add-ons/media/media-add-ons/demultiplexer/Jamfile @@ -0,0 +1,11 @@ +SubDir OBOS_TOP src add-ons media media-add-ons demultiplexer ; + +UsePrivateHeaders demultiplexer ; + +Addon demultiplexer.media_addon : media : + MediaDemultiplexerNode.cpp + MediaDemultiplexerAddOn.cpp + misc.cpp +; + +LinkSharedOSLibs demultiplexer.media_addon : be media ; diff --git a/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerAddOn.h b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerAddOn.h new file mode 100644 index 0000000000..65990e3728 --- /dev/null +++ b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerAddOn.h @@ -0,0 +1,84 @@ +// MediaDemultiplexerAddOn.h +// +// Andrew Bachmann, 2002 +// +// MediaDemultiplexerAddOn is an add-on +// that can make instances of MediaDemultiplexerNode +// +// MediaDemultiplexerNode handles a file and a multistream + +#if !defined(_MEDIA_DEMULTIPLEXER_ADD_ON_H) +#define _MEDIA_DEMULTIPLEXER_ADD_ON_H + +#include +#include + +class MediaDemultiplexerAddOn : + public BMediaAddOn +{ +public: + virtual ~MediaDemultiplexerAddOn(void); + explicit MediaDemultiplexerAddOn(image_id image); + +/**************************/ +/* begin from BMediaAddOn */ +public: +virtual status_t InitCheck( + const char ** out_failure_text); +virtual int32 CountFlavors(void); +virtual status_t GetFlavorAt( + int32 n, + const flavor_info ** out_info); +virtual BMediaNode * InstantiateNodeFor( + const flavor_info * info, + BMessage * config, + status_t * out_error); +virtual status_t GetConfigurationFor( + BMediaNode * your_node, + BMessage * into_message); +virtual bool WantsAutoStart(void); +virtual status_t AutoStart( + int in_count, + BMediaNode ** out_node, + int32 * out_internal_id, + bool * out_has_more); + +/* end from BMediaAddOn */ +/************************/ + +private: + + MediaDemultiplexerAddOn( /* private unimplemented */ + const MediaDemultiplexerAddOn & clone); + MediaDemultiplexerAddOn & operator=( + const MediaDemultiplexerAddOn & clone); + + int32 refCount; + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_MediaDemultiplexerAddOn_0(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_1(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_2(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_3(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_4(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_5(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_6(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_7(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_8(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_9(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_10(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_11(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_12(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_13(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_14(void *); +virtual status_t _Reserved_MediaDemultiplexerAddOn_15(void *); + + uint32 _reserved_media_demultiplexer_add_on_[16]; + +}; + +#if BUILDING_MEDIA_DEMULTIPLEXER__ADD_ON +extern "C" _EXPORT BMediaAddOn * make_media_demultiplexer_add_on(image_id you); +#endif + +#endif /* _MEDIA_DEMULTIPLEXER_ADD_ON_H */ diff --git a/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.cpp b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.cpp new file mode 100644 index 0000000000..b6466ea1e6 --- /dev/null +++ b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.cpp @@ -0,0 +1,1178 @@ +// MediaDemultiplexerNode.cpp +// +// Andrew Bachmann, 2002 +// +// The MediaDemultiplexerNode class +// takes a multistream input and supplies +// the individual constituent streams as +// the output. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MediaDemultiplexerNode.h" +#include "misc.h" + +#include +#include + +// -------------------------------------------------------- // +// ctor/dtor +// -------------------------------------------------------- // + +MediaDemultiplexerNode::~MediaDemultiplexerNode(void) +{ + fprintf(stderr,"MediaDemultiplexerNode::~MediaDemultiplexerNode\n"); + // Stop the BMediaEventLooper thread + Quit(); + if (fBufferGroup != 0) { + BBufferGroup * group = fBufferGroup; + fBufferGroup = 0; + delete group; + } +} + +MediaDemultiplexerNode::MediaDemultiplexerNode( + const flavor_info * info = 0, + BMessage * config = 0, + BMediaAddOn * addOn = 0) + : BMediaNode("MediaDemultiplexerNode"), + BMediaEventLooper(), + BBufferConsumer(B_MEDIA_MULTISTREAM), + BBufferProducer(B_MEDIA_UNKNOWN) // no B_MEDIA_ANY +{ + fprintf(stderr,"MediaDemultiplexerNode::MediaDemultiplexerNode\n"); + // keep our creator around for AddOn calls later + fAddOn = addOn; + // null out our latency estimates + fDownstreamLatency = 0; + fInternalLatency = 0; + // don't overwrite available space, and be sure to terminate + strncpy(input.name,"Demultiplexer Input",B_MEDIA_NAME_LENGTH-1); + input.name[B_MEDIA_NAME_LENGTH-1] = '\0'; + // initialize the input + input.node = media_node::null; // until registration + input.source = media_source::null; + input.destination = media_destination::null; // until registration + GetInputFormat(&input.format); + + outputs.empty(); + // outputs initialized after we connect, + // find a suitable extractor, + // and it tells us the ouputs + + fInitCheckStatus = B_OK; +} + +status_t MediaDemultiplexerNode::InitCheck(void) const +{ + fprintf(stderr,"MediaDemultiplexerNode::InitCheck\n"); + return fInitCheckStatus; +} + +status_t MediaDemultiplexerNode::GetConfigurationFor( + BMessage * into_message) +{ + fprintf(stderr,"MediaDemultiplexerNode::GetConfigurationFor\n"); + return B_OK; +} + +// -------------------------------------------------------- // +// implementation of BMediaNode +// -------------------------------------------------------- // + +BMediaAddOn * MediaDemultiplexerNode::AddOn( + int32 * internal_id) const +{ + fprintf(stderr,"MediaDemultiplexerNode::AddOn\n"); + // BeBook says this only gets called if we were in an add-on. + if (fAddOn != 0) { + // If we get a null pointer then we just won't write. + if (internal_id != 0) { + internal_id = 0; + } + } + return fAddOn; +} + +void MediaDemultiplexerNode::Start( + bigtime_t performance_time) +{ + fprintf(stderr,"MediaDemultiplexerNode::Start(pt=%lld)\n",performance_time); + BMediaEventLooper::Start(performance_time); +} + +void MediaDemultiplexerNode::Stop( + bigtime_t performance_time, + bool immediate) +{ + if (immediate) { + fprintf(stderr,"MediaDemultiplexerNode::Stop(pt=%lld,)\n",performance_time); + } else { + fprintf(stderr,"MediaDemultiplexerNode::Stop(pt=%lld,)\n",performance_time); + } + BMediaEventLooper::Stop(performance_time,immediate); +} + +void MediaDemultiplexerNode::Seek( + bigtime_t media_time, + bigtime_t performance_time) +{ + fprintf(stderr,"MediaDemultiplexerNode::Seek(mt=%lld,pt=%lld)\n",media_time,performance_time); + BMediaEventLooper::Seek(media_time,performance_time); +} + +void MediaDemultiplexerNode::SetRunMode( + run_mode mode) +{ + fprintf(stderr,"MediaDemultiplexerNode::SetRunMode(%i)\n",mode); + BMediaEventLooper::SetRunMode(mode); +} + +void MediaDemultiplexerNode::TimeWarp( + bigtime_t at_real_time, + bigtime_t to_performance_time) +{ + fprintf(stderr,"MediaDemultiplexerNode::TimeWarp(rt=%lld,pt=%lld)\n",at_real_time,to_performance_time); + BMediaEventLooper::TimeWarp(at_real_time,to_performance_time); +} + +void MediaDemultiplexerNode::Preroll(void) +{ + fprintf(stderr,"MediaDemultiplexerNode::Preroll\n"); + // XXX:Performance opportunity + BMediaNode::Preroll(); +} + +void MediaDemultiplexerNode::SetTimeSource( + BTimeSource * time_source) +{ + fprintf(stderr,"MediaDemultiplexerNode::SetTimeSource\n"); + BMediaNode::SetTimeSource(time_source); +} + +status_t MediaDemultiplexerNode::HandleMessage( + int32 message, + const void * data, + size_t size) +{ + fprintf(stderr,"MediaDemultiplexerNode::HandleMessage\n"); + status_t status = B_OK; + switch (message) { + // no special messages for now + default: + status = BBufferConsumer::HandleMessage(message,data,size); + if (status == B_OK) { + break; + } + status = BBufferProducer::HandleMessage(message,data,size); + if (status == B_OK) { + break; + } + status = BMediaNode::HandleMessage(message,data,size); + if (status == B_OK) { + break; + } + BMediaNode::HandleBadMessage(message,data,size); + status = B_ERROR; + break; + } + return status; +} + +status_t MediaDemultiplexerNode::RequestCompleted( + const media_request_info & info) +{ + fprintf(stderr,"MediaDemultiplexerNode::RequestCompleted\n"); + return BMediaNode::RequestCompleted(info); +} + +status_t MediaDemultiplexerNode::DeleteHook( + BMediaNode * node) +{ + fprintf(stderr,"MediaDemultiplexerNode::DeleteHook\n"); + return BMediaEventLooper::DeleteHook(node); +} + +void MediaDemultiplexerNode::NodeRegistered(void) +{ + fprintf(stderr,"MediaDemultiplexerNode::NodeRegistered\n"); + + // now we can do this + input.node = Node(); + input.destination.id = 0; + input.destination.port = input.node.port; // same as ControlPort() + + // outputs initialized after we connect, + // find a suitable extractor, + // and it tells us the ouputs + + // start the BMediaEventLooper thread + SetPriority(B_REAL_TIME_PRIORITY); + Run(); +} + +status_t MediaDemultiplexerNode::GetNodeAttributes( + media_node_attribute * outAttributes, + size_t inMaxCount) +{ + fprintf(stderr,"MediaDemultiplexerNode::GetNodeAttributes\n"); + return BMediaNode::GetNodeAttributes(outAttributes,inMaxCount); +} + +status_t MediaDemultiplexerNode::AddTimer( + bigtime_t at_performance_time, + int32 cookie) +{ + fprintf(stderr,"MediaDemultiplexerNode::AddTimer\n"); + return BMediaEventLooper::AddTimer(at_performance_time,cookie); +} + +// -------------------------------------------------------- // +// implemention of BBufferConsumer +// -------------------------------------------------------- // + +// Check to make sure the format is okay, then remove +// any wildcards corresponding to our requirements. +status_t MediaDemultiplexerNode::AcceptFormat( + const media_destination & dest, + media_format * format) +{ + fprintf(stderr,"MediaDemultiplexerNode::AcceptFormat\n"); + if (format == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashing + } + if (input.destination != dest) { + fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION"); + return B_MEDIA_BAD_DESTINATION; // we only have one input so that better be it + } + media_format myFormat; + GetInputFormat(&myFormat); + // Be's format_is_compatible doesn't work, + // so use our format_is_acceptible instead + if (!format_is_acceptible(*format,myFormat)) { + fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); + return B_MEDIA_BAD_FORMAT; + } + AddRequirements(format); + return B_OK; +} + +status_t MediaDemultiplexerNode::GetNextInput( + int32 * cookie, + media_input * out_input) +{ + fprintf(stderr,"MediaDemultiplexerNode::GetNextInput\n"); + // let's not crash even if they are stupid + if (out_input == 0) { + // no place to write! + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; + } + if (cookie != 0) { + // it's valid but they already got our 1 input + if (*cookie != 0) { + fprintf(stderr,"<- B_ERROR (no more inputs)\n"); + return B_ERROR; + } + // so next time they won't get the same input again + *cookie = 1; + } + *out_input = input; + return B_OK; +} + +void MediaDemultiplexerNode::DisposeInputCookie( + int32 cookie) +{ + fprintf(stderr,"MediaDemultiplexerNode::DisposeInputCookie\n"); + // nothing to do since our cookies are just integers + return; // B_OK; +} + +void MediaDemultiplexerNode::BufferReceived( + BBuffer * buffer) +{ + fprintf(stderr,"MediaDemultiplexerNode::BufferReceived\n"); + switch (buffer->Header()->type) { +// case B_MEDIA_PARAMETERS: +// { +// status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed()); +// if (status != B_OK) { +// fprintf(stderr,"ApplyParameterData in MediaDemultiplexerNode::BufferReceived failed\n"); +// } +// buffer->Recycle(); +// } +// break; + case B_MEDIA_MULTISTREAM: + if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) { + fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in MediaDemultiplexerNode::BufferReceived\n"); + // XXX: implement this part + buffer->Recycle(); + } else { + media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER, + buffer, BTimedEventQueue::B_RECYCLE_BUFFER); + status_t status = EventQueue()->AddEvent(event); + if (status != B_OK) { + fprintf(stderr,"EventQueue()->AddEvent(event) in MediaDemultiplexerNode::BufferReceived failed\n"); + buffer->Recycle(); + } + } + break; + default: + fprintf(stderr,"unexpected buffer type in MediaDemultiplexerNode::BufferReceived\n"); + buffer->Recycle(); + break; + } +} + +void MediaDemultiplexerNode::ProducerDataStatus( + const media_destination & for_whom, + int32 status, + bigtime_t at_performance_time) +{ + fprintf(stderr,"MediaDemultiplexerNode::ProducerDataStatus\n"); + if (input.destination != for_whom) { + fprintf(stderr,"invalid destination received in MediaDemultiplexerNode::ProducerDataStatus\n"); + return; + } + media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS, + &input, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL); + EventQueue()->AddEvent(event); +} + +status_t MediaDemultiplexerNode::GetLatencyFor( + const media_destination & for_whom, + bigtime_t * out_latency, + media_node_id * out_timesource) +{ + fprintf(stderr,"MediaDemultiplexerNode::GetLatencyFor\n"); + if ((out_latency == 0) || (out_timesource == 0)) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; + } + if (input.destination != for_whom) { + fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); + return B_MEDIA_BAD_DESTINATION; + } + *out_latency = EventLatency(); + *out_timesource = TimeSource()->ID(); + return B_OK; +} + +status_t MediaDemultiplexerNode::Connected( + const media_source & producer, /* here's a good place to request buffer group usage */ + const media_destination & where, + const media_format & with_format, + media_input * out_input) +{ + fprintf(stderr,"MediaDemultiplexerNode::Connected\n"); + if (out_input == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashing + } + if (input.destination != where) { + fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); + return B_MEDIA_BAD_DESTINATION; + } + + // find an appropriate extractor to handle this type + fprintf(stderr," XXX: no extractors yet\n"); + + // initialize the outputs here + // provide all the types that the extractor claims + outputs.empty(); + + // compute the latency or just guess + fInternalLatency = 500; // just guess + fprintf(stderr," internal latency guessed = %lld\n",fInternalLatency); + + SetEventLatency(fInternalLatency); + + // record the agreed upon values + input.source = producer; + input.format = with_format; + *out_input = input; + return B_OK; +} + +void MediaDemultiplexerNode::Disconnected( + const media_source & producer, + const media_destination & where) +{ + fprintf(stderr,"MediaDemultiplexerNode::Disconnected\n"); + if (input.destination != where) { + fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); + return; + } + if (input.source != producer) { + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return; + } + input.source = media_source::null; + GetInputFormat(&input.format); + + outputs.empty(); +} + + /* The notification comes from the upstream producer, so he's already cool with */ + /* the format; you should not ask him about it in here. */ +status_t MediaDemultiplexerNode::FormatChanged( + const media_source & producer, + const media_destination & consumer, + int32 change_tag, + const media_format & format) +{ + fprintf(stderr,"MediaDemultiplexerNode::FormatChanged\n"); + if (input.source != producer) { + return B_MEDIA_BAD_SOURCE; + } + if (input.destination != consumer) { + return B_MEDIA_BAD_DESTINATION; + } + // XXX: implement + fprintf(stderr," This is because we asked to have the format changed.\n" + " Therefore we must switch to the other extractor that\n" + " we presumably have ready."); + input.format = format; + return B_OK; +} + + /* Given a performance time of some previous buffer, retrieve the remembered tag */ + /* of the closest (previous or exact) performance time. Set *out_flags to 0; the */ + /* idea being that flags can be added later, and the understood flags returned in */ + /* *out_flags. */ +status_t MediaDemultiplexerNode::SeekTagRequested( + const media_destination & destination, + bigtime_t in_target_time, + uint32 in_flags, + media_seek_tag * out_seek_tag, + bigtime_t * out_tagged_time, + uint32 * out_flags) +{ + fprintf(stderr,"MediaDemultiplexerNode::SeekTagRequested\n"); + // XXX: implement this + return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags, + out_seek_tag,out_tagged_time,out_flags); +} + +// -------------------------------------------------------- // +// implemention of BBufferProducer +// -------------------------------------------------------- // + +// They are asking us to make the first offering. +// So, we get a fresh format and then add requirements +status_t MediaDemultiplexerNode::FormatSuggestionRequested( + media_type type, + int32 quality, + media_format * format) +{ + fprintf(stderr,"MediaDemultiplexerNode::FormatSuggestionRequested\n"); + if (format == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashing + } + // XXX: how do I pick which stream to supply here?.... + // answer?: get the first compatible stream that is available + fprintf(stderr," format suggestion requested not implemented\n"); +// if ((type != B_MEDIA_MULTISTREAM) && (type != B_MEDIA_UNKNOWN_TYPE)) { +// fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); +// return B_MEDIA_BAD_FORMAT; +// } + GetOutputFormat(format); +// AddRequirements(format); + + return B_OK; +} + +// They made an offer to us. We should make sure that the offer is +// acceptable, and then we can add any requirements we have on top of +// that. We leave wildcards for anything that we don't care about. +status_t MediaDemultiplexerNode::FormatProposal( + const media_source & output_source, + media_format * format) +{ + fprintf(stderr,"MediaDemultiplexerNode::FormatProposal\n"); + // find the information for this output + vector::iterator itr; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + if (itr->output.source == output_source) { + break; + } + } + if (itr == outputs.end()) { + // we don't have that output + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return B_MEDIA_BAD_SOURCE; + } + return itr->FormatProposal(format); +} + +// Presumably we have already agreed with them that this format is +// okay. But just in case, we check the offer. (and complain if it +// is invalid) Then as the last thing we do, we get rid of any +// remaining wilcards. +status_t MediaDemultiplexerNode::FormatChangeRequested( + const media_source & source, + const media_destination & destination, + media_format * io_format, + int32 * _deprecated_) +{ + fprintf(stderr,"MediaDemultiplexerNode::FormatChangeRequested\n"); + // find the information for this output + vector::iterator itr; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + if (itr->output.source == source) { + break; + } + } + if (itr == outputs.end()) { + // we don't have that output + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return B_MEDIA_BAD_SOURCE; + } + return itr->FormatChangeRequested(destination,io_format); +} + +status_t MediaDemultiplexerNode::GetNextOutput( /* cookie starts as 0 */ + int32 * cookie, + media_output * out_output) +{ + fprintf(stderr,"MediaDemultiplexerNode::GetNextOutput\n"); + // let's not crash even if they are stupid + if ((out_output == 0) || (oookie == 0)) { + // no place to write! + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; + } + // they want a clean start + if (*cookie == 0) { + *cookie = (int32)outputs.begin(); + } + vector::iterator itr + = (vector::iterator)(*cookie); + // XXX: check here if the vector has been modified. + // if the iterator is invalid, return an error code?? + + // they already got our 1 output + if (itr == outputs.end()) { + fprintf(stderr,"<- B_ERROR (no more outputs)\n"); + return B_ERROR; + } + // return this output + *out_output = itr->output; + // so next time they won't get the same output again + *cookie = (int32)itr.next(); + return B_OK; +} + +status_t MediaDemultiplexerNode::DisposeOutputCookie( + int32 cookie) +{ + fprintf(stderr,"MediaDemultiplexerNode::DisposeOutputCookie\n"); + // nothing to do since our cookies are part of the vector iterator + return B_OK; +} + +status_t MediaDemultiplexerNode::SetBufferGroup( + const media_source & for_source, + BBufferGroup * group) +{ + fprintf(stderr,"MediaDemultiplexerNode::SetBufferGroup\n"); + // find the information for this output + vector::iterator itr; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + if (itr->output.source == source) { + break; + } + } + if (itr == outputs.end()) { + // we don't have that output + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return B_MEDIA_BAD_SOURCE; + } + return itr->SetBufferGroup(group); +} + + /* Format of clipping is (as int16-s): . */ + /* Repeat for each line where the clipping is different from the previous line. */ + /* If is negative, use the data from line - (there are 0 pairs after */ + /* a negative . Yes, we only support 32k*32k frame buffers for clipping. */ + /* Any non-0 field of 'display' means that that field changed, and if you don't support */ + /* that change, you should return an error and ignore the request. Note that the buffer */ + /* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */ + /* be adhered to. */ +status_t MediaDemultiplexerNode::VideoClippingChanged( + const media_source & for_source, + int16 num_shorts, + int16 * clip_data, + const media_video_display_info & display, + int32 * _deprecated_) +{ + return BBufferProducer::VideoClippingChanged(for_source,num_shorts,clip_data,display,_deprecated_); +} + +status_t MediaDemultiplexerNode::GetLatency( + bigtime_t * out_latency) +{ + fprintf(stderr,"MediaDemultiplexerNode::GetLatency\n"); + if (out_latency == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; + } + *out_latency = EventLatency() + SchedulingLatency(); + return B_OK; +} + +status_t MediaDemultiplexerNode::PrepareToConnect( + const media_source & what, + const media_destination & where, + media_format * format, + media_source * out_source, + char * out_name) +{ + fprintf(stderr,"MediaDemultiplexerNode::PrepareToConnect\n"); + if ((format == 0) || (out_source == 0) || (out_name == 0)) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashes... + } + // find the information for this output + vector::iterator itr; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + if (itr->output.source == source) { + break; + } + } + if (itr == outputs.end()) { + // we don't have that output + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return B_MEDIA_BAD_SOURCE; + } + return itr->PrepareToConnect(destination,format,out_source,out_name); +} + +void MediaDemultiplexerNode::Connect( + status_t error, + const media_source & source, + const media_destination & destination, + const media_format & format, + char * io_name) +{ + fprintf(stderr,"MediaDemultiplexerNode::Connect\n"); + if (error != B_OK) { + fprintf(stderr,"<- error already\n"); + output.destination = media_destination::null; + GetFormat(&output.format); + return; + } + // find the information for this output + vector::iterator itr; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + if (itr->output.source == source) { + break; + } + } + if (itr == outputs.end()) { + // we don't have that output + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return; + } + + // record the agreed upon values + status_t status; + status = itr->Connect(destination,format,io_name); + if (status != B_OK) { + fprintf(stderr," itr->Connect returned an error\n"); + return; + } + +// // compute the buffer period (must be done before setbuffergroup) +// fBufferPeriod = bigtime_t(1000 * 8000000 / 1024 +// * output.format.u.multistream.max_chunk_size +// / output.format.u.multistream.max_bit_rate); +// +// fprintf(stderr," max chunk size = %i, max bit rate = %f, buffer period = %lld\n", +// output.format.u.multistream.max_chunk_size, +// output.format.u.multistream.max_bit_rate,fBufferPeriod); +// +// SetBufferDuration(fBufferPeriod); + + if (GetCurrentFile() != 0) { + bigtime_t start, end; + uint8 * data = new uint8[output.format.u.multistream.max_chunk_size]; // <- buffer group buffer size + BBuffer * buffer = 0; + ssize_t bytesRead = 0; + { // timed section + start = TimeSource()->RealTime(); + // first we try to use a real BBuffer + buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod); + if (buffer != 0) { + FillFileBuffer(buffer); + } else { + // didn't get a real BBuffer, try simulation by just a read from the disk + bytesRead = GetCurrentFile()->Read(data,output.format.u.multistream.max_chunk_size); + } + end = TimeSource()->RealTime(); + } + bytesRead = buffer->SizeUsed(); + delete data; + if (buffer != 0) { + buffer->Recycle(); + } + GetCurrentFile()->Seek(-bytesRead,SEEK_CUR); // put it back where we found it + + fInternalLatency = end - start; + + fprintf(stderr," internal latency from disk read = %lld\n",fInternalLatency); + } else { + fInternalLatency = 100; // just guess + fprintf(stderr," internal latency guessed = %lld\n",fInternalLatency); + } + + // If the downstream latency for this output is larger + // than our current downstream latency, we have to increase + // our current downstream latency to be the larger value. + if (itr->downstreamLatency > fDownstreamLatency) { + fDownstreamLatency = itr->downstreamLatency; + SetEventLatency(fDownstreamLatency + fInternalLatency); + } + + // XXX: do anything else? + return B_OK; +} + +void MediaDemultiplexerNode::Disconnect( + const media_source & what, + const media_destination & where) +{ + fprintf(stderr,"MediaDemultiplexerNode::Disconnect\n"); + if (output.destination != where) { + fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); + return; + } + // find the information for this output + vector::iterator itr; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + if (itr->output.source == what) { + break; + } + } + if (itr == outputs.end()) { + // we don't have that output + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return; + } + // if this output has an equal (or higher!) latency than + // our current believed downstream latency, we may have to + // update our downstream latency. + bool updateDownstreamLatency = (itr->downstreamLatency >= fDownstreamLatency); + // disconnect this output + itr->Disconnect(); + // update the downstream latency if necessary + if (updateDownstreamLatency) { + bigtime_t newDownstreamLatency = 0; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + if (itr->downstreamLatency > newDownstreamLatency) { + newDownstreamLatency = itr->downstreamLatency; + } + } + fDownstreamLatency = newDownstreamLatency; + } +} + +void MediaDemultiplexerNode::LateNoticeReceived( + const media_source & what, + bigtime_t how_much, + bigtime_t performance_time) +{ + fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived\n"); + if (what == output.source) { + switch (RunMode()) { + case B_OFFLINE: + // nothing to do + break; + case B_RECORDING: + // nothing to do + break; + case B_INCREASE_LATENCY: + fInternalLatency += how_much; + SetEventLatency(fDownstreamLatency + fInternalLatency); + break; + case B_DECREASE_PRECISION: + // what to do? + break; + case B_DROP_DATA: + // what to do? + break; + default: + // huh?? there aren't any more run modes. + fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived with unexpected run mode.\n"); + break; + } + } +} + +void MediaDemultiplexerNode::EnableOutput( + const media_source & what, + bool enabled, + int32 * _deprecated_) +{ + fprintf(stderr,"MediaDemultiplexerNode::EnableOutput\n"); + // find the information for this output + vector::iterator itr; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + if (itr->output.source == what) { + break; + } + } + if (itr == outputs.end()) { + // we don't have that output + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return; + } + status_t status = itr->EnableOutput(enabled); + if (status != B_OK) { + fprintf(stderr," error in itr->EnableOutput\n"); + return; + } + return; +} + +status_t MediaDemultiplexerNode::SetPlayRate( + int32 numer, + int32 denom) +{ + BBufferProducer::SetPlayRate(numer,denom); // XXX: do something intelligent later +} + +void MediaDemultiplexerNode::AdditionalBufferRequested( // used to be Reserved 0 + const media_source & source, + media_buffer_id prev_buffer, + bigtime_t prev_time, + const media_seek_tag * prev_tag) +{ + fprintf(stderr,"MediaDemultiplexerNode::AdditionalBufferRequested\n"); + // find the information for this output + vector::iterator itr; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + if (itr->output.source == what) { + break; + } + } + if (itr == outputs.end()) { + // we don't have that output + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return; + } + BBuffer * buffer; + status_t status = GetFilledBuffer(*itr,&buffer); + if (status != B_OK) { + fprintf(stderr,"MediaDemultiplexerNode::AdditionalBufferRequested got an error from GetFilledBuffer.\n"); + return; // don't send the buffer + } + SendBuffer(buffer,itr->output.destination); + return; +} + +void MediaDemultiplexerNode::LatencyChanged( + const media_source & source, + const media_destination & destination, + bigtime_t new_latency, + uint32 flags) +{ + fprintf(stderr,"MediaDemultiplexerNode::LatencyChanged\n"); + // find the information for this output + vector::iterator itr; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + if (itr->output.source == source) { + break; + } + } + if (itr == outputs.end()) { + // we don't have that output + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return; + } + if (itr->output.destination != destination) { + fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); + return; + } + fDownstreamLatency = new_latency; + SetEventLatency(fDownstreamLatency + fInternalLatency); + // XXX: we may have to recompute the number of buffers that we are using + // see SetBufferGroup +} + +// -------------------------------------------------------- // +// implementation for BMediaEventLooper +// -------------------------------------------------------- // + +void MediaDemultiplexerNode::HandleEvent( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaDemultiplexerNode::HandleEvent\n"); + switch (event->type) { + case BTimedEventQueue::B_START: + HandleStart(event,lateness,realTimeEvent); + break; + case BTimedEventQueue::B_SEEK: + HandleSeek(event,lateness,realTimeEvent); + break; + case BTimedEventQueue::B_WARP: + HandleWarp(event,lateness,realTimeEvent); + break; + case BTimedEventQueue::B_STOP: + HandleStop(event,lateness,realTimeEvent); + break; + case BTimedEventQueue::B_HANDLE_BUFFER: + if (RunState() == BMediaEventLooper::B_STARTED) { + HandleBuffer(event,lateness,realTimeEvent); + } + break; + case BTimedEventQueue::B_DATA_STATUS: + HandleDataStatus(event,lateness,realTimeEvent); + break; + case BTimedEventQueue::B_PARAMETER: + HandleParameter(event,lateness,realTimeEvent); + break; + default: + fprintf(stderr," unknown event type: %i\n",event->type); + break; + } +} + +/* override to clean up custom events you have added to your queue */ +void MediaDemultiplexerNode::CleanUpEvent( + const media_timed_event *event) +{ + BMediaEventLooper::CleanUpEvent(event); +} + +/* called from Offline mode to determine the current time of the node */ +/* update your internal information whenever it changes */ +bigtime_t MediaDemultiplexerNode::OfflineTime() +{ + fprintf(stderr,"MediaDemultiplexerNode::OfflineTime\n"); + return BMediaEventLooper::OfflineTime(); +// XXX: do something else? +} + +/* override only if you know what you are doing! */ +/* otherwise much badness could occur */ +/* the actual control loop function: */ +/* waits for messages, Pops events off the queue and calls DispatchEvent */ +void MediaDemultiplexerNode::ControlLoop() { + BMediaEventLooper::ControlLoop(); +} + +// protected: + +status_t MediaDemultiplexerNode::HandleStart( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaDemultiplexerNode::HandleStart()\n"); + if (RunState() != B_STARTED) { +// XXX: Either use the following line or the lines that are not commented. +// There doesn't seem to be a practical difference that i can tell. +// HandleBuffer(event,lateness,realTimeEvent); + media_timed_event firstBufferEvent(event->event_time, BTimedEventQueue::B_HANDLE_BUFFER); + HandleEvent(&firstBufferEvent, 0, false); + EventQueue()->AddEvent(firstBufferEvent); + } + return B_OK; +} + +status_t MediaDemultiplexerNode::HandleSeek( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaDemultiplexerNode::HandleSeek(t=%lld,d=%i,bd=%lld)\n",event->event_time,event->data,event->bigdata); + return B_OK; +} + +status_t MediaDemultiplexerNode::HandleWarp( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaDemultiplexerNode::HandleWarp\n"); + return B_OK; +} + +status_t MediaDemultiplexerNode::HandleStop( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaDemultiplexerNode::HandleStop\n"); + // flush the queue so downstreamers don't get any more + EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); + return B_OK; +} + +status_t MediaDemultiplexerNode::HandleBuffer( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaDemultiplexerNode::HandleBuffer\n"); + BBuffer * buffer = const_cast((BBuffer*)event->pointer); + if (buffer == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; + } + if (buffer->Header()->destination != input.destination.id) { + fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); + return B_MEDIA_BAD_DESTINATION; + } + if (outputs.begin() == outputs.end()) { + fprintf(stderr,"<- B_MEDIA_NOT_CONNECTED\n"); + return B_MEDIA_NOT_CONNECTED; + } + status_t status = B_OK; + fprintf(stderr," XXX: HandleBuffer not yet implemented.\n"); + // we have to hand the buffer to the extractor + // and then whenever we get a buffer for an output send it + // to that particular output (assuming it exists and is enabled) +// BBuffer * buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod); +// if (buffer != 0) { +// status = FillFileBuffer(buffer); +// if (status != B_OK) { +// fprintf(stderr,"MediaDemultiplexerNode::HandleEvent got an error from FillFileBuffer.\n"); +// buffer->Recycle(); +// } else { +// if (fOutputEnabled) { +// status = SendBuffer(buffer,output.destination); +// if (status != B_OK) { +// fprintf(stderr,"MediaDemultiplexerNode::HandleEvent got an error from SendBuffer.\n"); +// buffer->Recycle(); +// } +// } else { + buffer->Recycle(); +// } +// } +// } + bigtime_t nextEventTime = event->event_time+fBufferPeriod; + media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER); + EventQueue()->AddEvent(nextBufferEvent); + return status; +} + +status_t MediaDemultiplexerNode::HandleDataStatus( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaDemultiplexerNode::HandleDataStatus"); + // find the information for this output + vector::iterator itr; + for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { + SendDataStatus(event->data,itr->output.destination,event->event_time); + } + return B_OK; +} + +status_t MediaDemultiplexerNode::HandleParameter( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaDemultiplexerNode::HandleParameter"); + return B_OK; +} + +// -------------------------------------------------------- // +// MediaDemultiplexerNode specific functions +// -------------------------------------------------------- // + +// public: + +void MediaDemultiplexerNode::GetFlavor(flavor_info * outInfo, int32 id) +{ + fprintf(stderr,"MediaDemultiplexerNode::GetFlavor\n"); + if (outInfo == 0) { + return; + } + outInfo->name = "OpenBeOS Demultiplexer"; + outInfo->info = "A MediaDemultiplexerNode node demultiplexes a multistream into its constituent streams."; + outInfo->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER; + outInfo->flavor_flags = B_FLAVOR_IS_LOCAL; + outInfo->possible_count = INT_MAX; + outInfo->in_format_count = 1; // 1 input + media_format * inFormats = new media_format[outInfo->in_format_count]; + GetInputFormat(&inFormats[0]); + outInfo->in_formats = inFormats; + outInfo->out_format_count = 1; // 1 output + media_format * outFormats = new media_format[outInfo->out_format_count]; + GetOutputFormat(&outFormats[0]); + outInfo->out_formats = outFormats; + outInfo->internal_id = id; + return; +} + +void MediaDemultiplexerNode::GetInputFormat(media_format * outFormat) +{ + fprintf(stderr,"MediaDemultiplexerNode::GetInputFormat\n"); + if (outFormat == 0) { + return; + } + outFormat->type = B_MEDIA_MULTISTREAM; + outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; + outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; + outFormat->u.multistream = media_multistream_format::wildcard; +} + +void MediaDemultiplexerNode::GetOutputFormat(media_format * outFormat) +{ + fprintf(stderr,"MediaDemultiplexerNode::GetOutputFormat\n"); + if (outFormat == 0) { + return; + } + outFormat->type = B_MEDIA_UNKNOWN_TYPE; // more like ANY_TYPE than unknown + outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; + outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; +} + +// protected: + +status_t MediaDemultiplexerNode::AddRequirements(media_format * format) +{ + fprintf(stderr,"MediaDemultiplexerNode::AddRequirements\n"); + return B_OK; +} + +// -------------------------------------------------------- // +// stuffing +// -------------------------------------------------------- // + +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_0(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_1(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_2(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_3(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_4(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_5(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_6(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_7(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_8(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_9(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_10(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_11(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_12(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_13(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_14(void *) {} +status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_15(void *) {} diff --git a/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.h b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.h new file mode 100644 index 0000000000..80e15aacf9 --- /dev/null +++ b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.h @@ -0,0 +1,375 @@ +// MediaDemultiplexerNode.h +// +// Andrew Bachmann, 2002 +// +// The MediaDemultiplexerNode class +// takes a multistream input and supplies +// the individual constituent streams as +// the output. + +#if !defined(_MEDIA_DEMULTIPLEXER_NODE_H) +#define _MEDIA_DEMULTIPLEXER_NODE_H + +#include +#include +#include +#include +#include +#include +#include +#include "MediaOutputInfo.h" + +class MediaDemultiplexerNode : + public BBufferConsumer, + public BBufferProducer, + public BMediaEventLooper +{ +protected: +virtual ~MediaDemultiplexerNode(void); + +public: + +explicit MediaDemultiplexerNode( + const flavor_info * info = 0, + BMessage * config = 0, + BMediaAddOn * addOn = 0); + +virtual status_t InitCheck(void) const; + +// see BMediaAddOn::GetConfigurationFor +virtual status_t GetConfigurationFor( + BMessage * into_message); + +/*************************/ +/* begin from BMediaNode */ +public: +// /* this port is what a media node listens to for commands */ +// virtual port_id ControlPort(void) const; + +virtual BMediaAddOn* AddOn( + int32 * internal_id) const; /* Who instantiated you -- or NULL for app class */ + +protected: + /* These don't return errors; instead, they use the global error condition reporter. */ + /* A node is required to have a queue of at least one pending command (plus TimeWarp) */ + /* and is recommended to allow for at least one pending command of each type. */ + /* Allowing an arbitrary number of outstanding commands might be nice, but apps */ + /* cannot depend on that happening. */ +virtual void Start( + bigtime_t performance_time); +virtual void Stop( + bigtime_t performance_time, + bool immediate); +virtual void Seek( + bigtime_t media_time, + bigtime_t performance_time); +virtual void SetRunMode( + run_mode mode); +virtual void TimeWarp( + bigtime_t at_real_time, + bigtime_t to_performance_time); +virtual void Preroll(void); +virtual void SetTimeSource( + BTimeSource * time_source); + +public: +virtual status_t HandleMessage( + int32 message, + const void * data, + size_t size); + +protected: + /* Called when requests have completed, or failed. */ +virtual status_t RequestCompleted( /* reserved 0 */ + const media_request_info & info); + +protected: +virtual status_t DeleteHook(BMediaNode * node); /* reserved 1 */ + +virtual void NodeRegistered(void); /* reserved 2 */ + +public: + + /* fill out your attributes in the provided array, returning however many you have. */ +virtual status_t GetNodeAttributes( /* reserved 3 */ + media_node_attribute * outAttributes, + size_t inMaxCount); + +virtual status_t AddTimer( + bigtime_t at_performance_time, + int32 cookie); + +/* end from BMediaNode */ +/***********************/ + +/******************************/ +/* begin from BBufferConsumer */ + +//included from BMediaAddOn +//virtual status_t HandleMessage( +// int32 message, +// const void * data, +// size_t size); + + /* Someone, probably the producer, is asking you about this format. Give */ + /* your honest opinion, possibly modifying *format. Do not ask upstream */ + /* producer about the format, since he's synchronously waiting for your */ + /* reply. */ +virtual status_t AcceptFormat( + const media_destination & dest, + media_format * format); +virtual status_t GetNextInput( + int32 * cookie, + media_input * out_input); +virtual void DisposeInputCookie( + int32 cookie); +virtual void BufferReceived( + BBuffer * buffer); +virtual void ProducerDataStatus( + const media_destination & for_whom, + int32 status, + bigtime_t at_performance_time); +virtual status_t GetLatencyFor( + const media_destination & for_whom, + bigtime_t * out_latency, + media_node_id * out_timesource); +virtual status_t Connected( + const media_source & producer, /* here's a good place to request buffer group usage */ + const media_destination & where, + const media_format & with_format, + media_input * out_input); +virtual void Disconnected( + const media_source & producer, + const media_destination & where); + /* The notification comes from the upstream producer, so he's already cool with */ + /* the format; you should not ask him about it in here. */ +virtual status_t FormatChanged( + const media_source & producer, + const media_destination & consumer, + int32 change_tag, + const media_format & format); + + /* Given a performance time of some previous buffer, retrieve the remembered tag */ + /* of the closest (previous or exact) performance time. Set *out_flags to 0; the */ + /* idea being that flags can be added later, and the understood flags returned in */ + /* *out_flags. */ +virtual status_t SeekTagRequested( + const media_destination & destination, + bigtime_t in_target_time, + uint32 in_flags, + media_seek_tag * out_seek_tag, + bigtime_t * out_tagged_time, + uint32 * out_flags); + +/* end from BBufferConsumer */ +/****************************/ + +/******************************/ +/* begin from BBufferProducer */ +protected: + /* functionality of BBufferProducer */ +virtual status_t FormatSuggestionRequested( + media_type type, + int32 quality, + media_format * format); +virtual status_t FormatProposal( + const media_source & output, + media_format * format); + /* If the format isn't good, put a good format into *io_format and return error */ + /* If format has wildcard, specialize to what you can do (and change). */ + /* If you can change the format, return OK. */ + /* The request comes from your destination sychronously, so you cannot ask it */ + /* whether it likes it -- you should assume it will since it asked. */ +virtual status_t FormatChangeRequested( + const media_source & source, + const media_destination & destination, + media_format * io_format, + int32 * _deprecated_); +virtual status_t GetNextOutput( /* cookie starts as 0 */ + int32 * cookie, + media_output * out_output); +virtual status_t DisposeOutputCookie( + int32 cookie); + /* In this function, you should either pass on the group to your upstream guy, */ + /* or delete your current group and hang on to this group. Deleting the previous */ + /* group (unless you passed it on with the reclaim flag set to false) is very */ + /* important, else you will 1) leak memory and 2) block someone who may want */ + /* to reclaim the buffers living in that group. */ +virtual status_t SetBufferGroup( + const media_source & for_source, + BBufferGroup * group); + /* Format of clipping is (as int16-s): . */ + /* Repeat for each line where the clipping is different from the previous line. */ + /* If is negative, use the data from line - (there are 0 pairs after */ + /* a negative . Yes, we only support 32k*32k frame buffers for clipping. */ + /* Any non-0 field of 'display' means that that field changed, and if you don't support */ + /* that change, you should return an error and ignore the request. Note that the buffer */ + /* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */ + /* be adhered to. */ +virtual status_t VideoClippingChanged( + const media_source & for_source, + int16 num_shorts, + int16 * clip_data, + const media_video_display_info & display, + int32 * _deprecated_); + /* Iterates over all outputs and maxes the latency found */ +virtual status_t GetLatency( + bigtime_t * out_latency); +virtual status_t PrepareToConnect( + const media_source & what, + const media_destination & where, + media_format * format, + media_source * out_source, + char * out_name); +virtual void Connect( + status_t error, + const media_source & source, + const media_destination & destination, + const media_format & format, + char * io_name); +virtual void Disconnect( + const media_source & what, + const media_destination & where); +virtual void LateNoticeReceived( + const media_source & what, + bigtime_t how_much, + bigtime_t performance_time); +virtual void EnableOutput( + const media_source & what, + bool enabled, + int32 * _deprecated_); +virtual status_t SetPlayRate( + int32 numer, + int32 denom); + +//included from BMediaNode +//virtual status_t HandleMessage( /* call this from the thread that listens to the port */ +// int32 message, +// const void * data, +// size_t size); + +virtual void AdditionalBufferRequested( // used to be Reserved 0 + const media_source & source, + media_buffer_id prev_buffer, + bigtime_t prev_time, + const media_seek_tag * prev_tag); // may be NULL + +virtual void LatencyChanged( // used to be Reserved 1 + const media_source & source, + const media_destination & destination, + bigtime_t new_latency, + uint32 flags); + +/* end from BBufferProducer */ +/****************************/ + +/********************************/ +/* start from BMediaEventLooper */ + + protected: + /* you must override to handle your events! */ + /* you should not call HandleEvent directly */ + virtual void HandleEvent( const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); + + /* override to clean up custom events you have added to your queue */ + virtual void CleanUpEvent(const media_timed_event *event); + + /* called from Offline mode to determine the current time of the node */ + /* update your internal information whenever it changes */ + virtual bigtime_t OfflineTime(); + + /* override only if you know what you are doing! */ + /* otherwise much badness could occur */ + /* the actual control loop function: */ + /* waits for messages, Pops events off the queue and calls DispatchEvent */ + virtual void ControlLoop(); + +/* end from BMediaEventLooper */ +/******************************/ + +protected: + +virtual status_t HandleStart( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); +virtual status_t HandleSeek( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); +virtual status_t HandleWarp( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); +virtual status_t HandleStop( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); +virtual status_t HandleBuffer( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); +virtual status_t HandleDataStatus( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); +virtual status_t HandleParameter( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false); + +public: + +static void GetFlavor(flavor_info * outInfo, int32 id); + +private: + +static void GetInputFormat(media_format * outFormat); +static void GetOutputFormat(media_format * outFormat); + +protected: + +virtual status_t AddRequirements(media_format * format); + +private: + + MediaDemultiplexerNode( /* private unimplemented */ + const MediaDemultiplexerNode & clone); + MediaDemultiplexerNode & operator=( + const MediaDemultiplexerNode & clone); + + status_t fInitCheckStatus; + + BMediaAddOn * fAddOn; + + media_input input; + vector outputs; + + bigtime_t fDownstreamLatency; + bigtime_t fInternalLatency; + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_MediaDemultiplexerNode_0(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_1(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_2(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_3(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_4(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_5(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_6(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_7(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_8(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_9(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_10(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_11(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_12(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_13(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_14(void *); +virtual status_t _Reserved_MediaDemultiplexerNode_15(void *); + + uint32 _reserved_media_demultiplexer_node_[16]; + +}; + +#endif /* _MEDIA_DEMULTIPLEXER_NODE_H */ diff --git a/src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.h b/src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.h new file mode 100644 index 0000000000..bedeb0a282 --- /dev/null +++ b/src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.h @@ -0,0 +1,226 @@ +// MediaOutputInfo.h +// +// Andrew Bachmann, 2002 +// +// A class to encapsulate and manipulate +// all the information for a particular +// output of a media node. + +#if !defined(_MEDIA_OUTPUT_INFO_H) +#define _MEDIA_OUTPUT_INFO_H + +#include +#include + +class MediaOutputInfo +{ +public: + MediaOutputInfo(char * name) { + // null some fields + bufferGroup = 0; + // start enabled + outputEnabled = true; + // don't overwrite available space, and be sure to terminate + strncpy(output.name,name,B_MEDIA_NAME_LENGTH-1); + output.name[B_MEDIA_NAME_LENGTH-1] = '\0'; + // initialize the output + output.node = media_node::null; + output.source = media_source::null; + output.destination = media_source::null; + } + ~MediaOutputInfo() { + if (bufferGroup != 0) { + BBufferGroup * group = bufferGroup; + bufferGroup = 0; + delete group; + } + } + SetBufferGroup(BBufferGroup * group) { +// if (fBufferGroup != 0) { +// if (fBufferGroup == group) { +// return B_OK; // time saver +// } +// delete fBufferGroup; +// } +// if (group != 0) { +// fBufferGroup = group; +// } else { +// // let's take advantage of this opportunity to recalculate +// // our downstream latency and ensure that it is up to date +// media_node_id id; +// FindLatencyFor(output.destination, &fDownstreamLatency, &id); +// // buffer period gets initialized in Connect() because +// // that is the first time we get the real values for +// // chunk size and bit rate, which are used to compute buffer period +// // note: you can still make a buffer group before connecting (why?) +// // but we don't make it, you make it yourself and pass it here. +// // not sure why anybody would want to do that since they need +// // a connection anyway... +// if (fBufferPeriod <= 0) { +// fprintf(stderr,"<- B_NO_INIT"); +// return B_NO_INIT; +// } +// int32 count = int32(fDownstreamLatency/fBufferPeriod)+2; +// fprintf(stderr," downstream latency = %lld, buffer period = %lld, buffer count = %i\n", +// fDownstreamLatency,fBufferPeriod,count); +// +// // allocate the buffers +// fBufferGroup = new BBufferGroup(output.format.u.multistream.max_chunk_size,count); +// if (fBufferGroup == 0) { +// fprintf(stderr,"<- B_NO_MEMORY\n"); +// return B_NO_MEMORY; +// } +// status_t status = fBufferGroup->InitCheck(); +// if (status != B_OK) { +// fprintf(stderr,"<- fBufferGroup initialization failed\n"); +// return status; +// } +// } + } + +// They made an offer to us. We should make sure that the offer is +// acceptable, and then we can add any requirements we have on top of +// that. We leave wildcards for anything that we don't care about. + status_t FormatProposal(media_format * format) + { + if (format == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashing + } + // Be's format_is_compatible doesn't work, + // so use our format_is_acceptible instead + if (!format_is_acceptible(*format,generalFormat)) { + fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); + return B_MEDIA_BAD_FORMAT; + } + // XXX: test because we don't trust them! + format->SpecializeTo(wildcardedFormat); + return B_OK; + } + +// Presumably we have already agreed with them that this format is +// okay. But just in case, we check the offer. (and complain if it +// is invalid) Then as the last thing we do, we get rid of any +// remaining wilcards. + status_t FormatChangeRequested(const media_destination & destination, + media_format * io_format) + { + if (io_format == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashing + } + status_t status = FormatProposal(io_format); + if (status != B_OK) { + fprintf(stderr,"<- MediaOutputInfo::FormatProposal failed\n"); + *io_format = generalFormat; + return status; + } + io_format->SpecializeTo(fullySpecifiedFormat); + return B_OK; + } + + status_t PrepareToConnect(const media_destination & where, + media_format * format, + media_source * out_source, + char * out_name) + { + if (output.destination != media_destination::null) { + fprintf(stderr,"<- B_MEDIA_ALREADY_CONNECTED\n"); + return B_MEDIA_ALREADY_CONNECTED; + } + status_t status = FormatChangeRequested(where,format,out_name); + if (status != B_OK) { + fprintf(stderr,"<- MediaOutputInfo::FormatChangeRequested failed\n"); + return status; + } + *out_source = output.source; + output.destination = where; + strncpy(out_name,output.name,B_MEDIA_NAME_LENGTH-1); + out_name[B_MEDIA_NAME_LENGTH] = '\0'; + return B_OK; + } + + status_t Connect(const media_destination & destination, + const media_format & format, + char * io_name) + { + if (io_name == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; + } + output.destination = destination; + output.format = format; + strncpy(io_name,output.name,B_MEDIA_NAME_LENGTH-1); + io_name[B_MEDIA_NAME_LENGTH-1] = '\0'; + + // determine our downstream latency + media_node_id id; + FindLatencyFor(output.destination, &downstreamLatency, &id); + + // compute the buffer period (must be done before setbuffergroup) + bufferPeriod = computeBufferPeriod(output.format); + SetBufferDuration(fBufferPeriod); + + // setup the buffers if they aren't setup yet + if (bufferGroup == 0) { + status_t status = SetBufferGroup(output.source,0); + if (status != B_OK) { + fprintf(stderr,"<- SetBufferGroup failed\n"); + output.destination = media_destination::null; + output.format = generalFormat; + return; + } + } + return B_OK; + } + + status_t Disconnect() + { + output.destination = media_destination::null; + output.format = genericFormat; + if (bufferGroup != 0) { + BBufferGroup * group = bufferGroup; + bufferGroup = 0; + delete group; + } + } + + status_t EnableOutput(bool enabled) + { + outputEnabled = enabled; + return B_OK; + } + +public: + media_output output; + + bool outputEnabled; + + BBufferGroup * bufferGroup; + size_t bufferSize; + + bigtime_t downstreamLatency; + + bigtime_t bufferPeriod; + + // This format is the least restrictive we can + // support in the general case. (no restrictions + // based on content) + media_format generalFormat; + + // This format is the next least restrictive. It + // takes into account the content that we are using. + // It should be the same as above with a few wildcards + // removed. Wildcards for things we are flexible on + // may still be present. + media_format wildcardedFormat; + + // This format provides default values for all fields. + // These defaults are used to resolve all wildcards. + media_format fullySpecifiedFormat; + + // do we need media_seek_tag in here? +} + +#endif // _MEDIA_OUTPUT_INFO_H + diff --git a/src/add-ons/media/media-add-ons/demultiplexer/misc.cpp b/src/add-ons/media/media-add-ons/demultiplexer/misc.cpp new file mode 100644 index 0000000000..037ba0b8c5 --- /dev/null +++ b/src/add-ons/media/media-add-ons/demultiplexer/misc.cpp @@ -0,0 +1,129 @@ +// misc.cpp +// +// Andrew Bachmann, 2002 +// +// Some functions for general debugging and +// working around be media kit bugs. + +#include "misc.h" +#include + +// -------------------------------------------------------- // +// lib functions +// -------------------------------------------------------- // + +void print_multistream_format(media_multistream_format * format) { + fprintf(stderr,"["); + switch (format->format) { + case media_multistream_format::B_ANY: fprintf(stderr,"ANY"); break; + case media_multistream_format::B_VID: fprintf(stderr,"VID"); break; + case media_multistream_format::B_AVI: fprintf(stderr,"AVI"); break; + case media_multistream_format::B_MPEG1: fprintf(stderr,"MPEG1"); break; + case media_multistream_format::B_MPEG2: fprintf(stderr,"MPEG2"); break; + case media_multistream_format::B_QUICKTIME: fprintf(stderr,"QUICKTIME"); break; + default: fprintf(stderr,"????"); break; + } + fprintf(stderr," avg_bit_rate(%f) max_bit_rate(%f)", + format->avg_bit_rate,format->max_bit_rate); + fprintf(stderr," avg_chunk_size(%i) max_chunk_size(%i)", + format->avg_chunk_size,format->max_chunk_size); +} + +void print_media_format(media_format * format) { + fprintf(stderr,"{"); + switch (format->type) { + case B_MEDIA_NO_TYPE: fprintf(stderr,"NO_TYPE"); break; + case B_MEDIA_UNKNOWN_TYPE: fprintf(stderr,"UNKNOWN_TYPE"); break; + case B_MEDIA_RAW_AUDIO: fprintf(stderr,"RAW_AUDIO"); break; + case B_MEDIA_RAW_VIDEO: fprintf(stderr,"RAW_VIDEO"); break; + case B_MEDIA_VBL: fprintf(stderr,"VBL"); break; + case B_MEDIA_TIMECODE: fprintf(stderr,"TIMECODE"); break; + case B_MEDIA_MIDI: fprintf(stderr,"MIDI"); break; + case B_MEDIA_TEXT: fprintf(stderr,"TEXT"); break; + case B_MEDIA_HTML: fprintf(stderr,"HTML"); break; + case B_MEDIA_MULTISTREAM: fprintf(stderr,"MULTISTREAM"); break; + case B_MEDIA_PARAMETERS: fprintf(stderr,"PARAMETERS"); break; + case B_MEDIA_ENCODED_AUDIO: fprintf(stderr,"ENCODED_AUDIO"); break; + case B_MEDIA_ENCODED_VIDEO: fprintf(stderr,"ENCODED_VIDEO"); break; + default: fprintf(stderr,"????"); break; + } + fprintf(stderr,":"); + switch (format->type) { + case B_MEDIA_RAW_AUDIO: fprintf(stderr,"RAW_AUDIO"); break; + case B_MEDIA_RAW_VIDEO: fprintf(stderr,"RAW_VIDEO"); break; + case B_MEDIA_MULTISTREAM: print_multistream_format(&format->u.multistream); break; + case B_MEDIA_ENCODED_AUDIO: fprintf(stderr,"ENCODED_AUDIO"); break; + case B_MEDIA_ENCODED_VIDEO: fprintf(stderr,"ENCODED_VIDEO"); break; + default: fprintf(stderr,"????"); break; + } + fprintf(stderr,"}"); +} + +bool multistream_format_is_acceptible( + const media_multistream_format & producer_format, + const media_multistream_format & consumer_format) +{ + // first check the format, if necessary + if (consumer_format.format != media_multistream_format::B_ANY) { + if (consumer_format.format != producer_format.format) { + return false; + } + } + // then check the average bit rate + if (consumer_format.avg_bit_rate != media_multistream_format::wildcard.avg_bit_rate) { + if (consumer_format.avg_bit_rate != producer_format.avg_bit_rate) { + // do they have to match exactly? I don't know. assume yes. + return false; + } + } + // then check the maximum bit rate + if (consumer_format.max_bit_rate != media_multistream_format::wildcard.max_bit_rate) { + if (consumer_format.max_bit_rate != producer_format.max_bit_rate) { + // do they have to match exactly? I don't know. assume yes. + return false; + } + } + // then check the average chunk size + if (consumer_format.avg_chunk_size != media_multistream_format::wildcard.avg_chunk_size) { + if (consumer_format.avg_chunk_size != producer_format.avg_chunk_size) { + // do they have to match exactly? I don't know. assume yes. + return false; + } + } + // then check the maximum bit rate + if (consumer_format.max_chunk_size != media_multistream_format::wildcard.max_chunk_size) { + if (consumer_format.max_chunk_size != producer_format.max_chunk_size) { + // do they have to match exactly? I don't know. assume yes. + return false; + } + } + // should also check format specific fields, and others? + return true; +} + +bool format_is_acceptible( + const media_format & producer_format, + const media_format & consumer_format) +{ + // first check the type, if necessary + if (consumer_format.type != B_MEDIA_UNKNOWN_TYPE) { + if (consumer_format.type != producer_format.type) { + return false; + } + switch (consumer_format.type) { + case B_MEDIA_MULTISTREAM: + if (!multistream_format_is_acceptible(producer_format.u.multistream, + consumer_format.u.multistream)) { + return false; + } + break; + default: + fprintf(stderr,"format_is_acceptible : unimplemented type.\n"); + return format_is_compatible(producer_format,consumer_format); + break; + } + } + // should also check non-type fields? + return true; +} + diff --git a/src/add-ons/media/media-add-ons/demultiplexer/misc.h b/src/add-ons/media/media-add-ons/demultiplexer/misc.h new file mode 100644 index 0000000000..621730c675 --- /dev/null +++ b/src/add-ons/media/media-add-ons/demultiplexer/misc.h @@ -0,0 +1,30 @@ +// misc.h +// +// Andrew Bachmann, 2002 +// +// Some functions for general debugging and +// working around be media kit bugs. + +#if !defined(_MISC_H) +#define _MISC_H + +#include + +// -------------------------------------------------------- // +// lib functions +// -------------------------------------------------------- // + +void print_multistream_format(media_multistream_format * format); + +void print_media_format(media_format * format); + +bool multistream_format_is_acceptible( + const media_multistream_format & producer_format, + const media_multistream_format & consumer_format); + +bool format_is_acceptible( + const media_format & producer_format, + const media_format & consumer_format); + +#endif // _MISC_H +