From 728a8c7497dabba873e87053a8159a23f0e37fb1 Mon Sep 17 00:00:00 2001 From: shatty Date: Tue, 24 Sep 2002 02:25:35 +0000 Subject: [PATCH] it compiles git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1140 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../media/media-add-ons/demultiplexer/Jamfile | 1 + .../demultiplexer/MediaDemultiplexerAddOn.cpp | 161 ++++++++++ .../demultiplexer/MediaDemultiplexerNode.cpp | 201 +++++++------ .../demultiplexer/MediaDemultiplexerNode.h | 5 + .../demultiplexer/MediaOutputInfo.cpp | 282 ++++++++++++++++++ .../demultiplexer/MediaOutputInfo.h | 213 +++---------- 6 files changed, 597 insertions(+), 266 deletions(-) create mode 100644 src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerAddOn.cpp create mode 100644 src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.cpp diff --git a/src/add-ons/media/media-add-ons/demultiplexer/Jamfile b/src/add-ons/media/media-add-ons/demultiplexer/Jamfile index 6b7265f94a..2b19d4dec5 100644 --- a/src/add-ons/media/media-add-ons/demultiplexer/Jamfile +++ b/src/add-ons/media/media-add-ons/demultiplexer/Jamfile @@ -5,6 +5,7 @@ UsePrivateHeaders demultiplexer ; Addon demultiplexer.media_addon : media : MediaDemultiplexerNode.cpp MediaDemultiplexerAddOn.cpp + MediaOutputInfo.cpp misc.cpp ; diff --git a/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerAddOn.cpp b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerAddOn.cpp new file mode 100644 index 0000000000..adcd42788d --- /dev/null +++ b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerAddOn.cpp @@ -0,0 +1,161 @@ +// MediaDemultiplexerAddOn.cpp +// +// Andrew Bachmann, 2002 +// +// MediaDemultiplexerAddOn is an add-on +// that can make instances of MediaDemultiplexerNode +// +// MediaDemultiplexerNode handles a file and a multistream + + +#include +#include +#include + +#include "MediaDemultiplexerNode.h" +#include "MediaDemultiplexerAddOn.h" + +#include +#include +#include + +// instantiation function +extern "C" _EXPORT BMediaAddOn * make_media_addon(image_id image) +{ + return new MediaDemultiplexerAddOn(image); +} + +// -------------------------------------------------------- // +// ctor/dtor +// -------------------------------------------------------- // + +MediaDemultiplexerAddOn::~MediaDemultiplexerAddOn() +{ +} + +MediaDemultiplexerAddOn::MediaDemultiplexerAddOn(image_id image) : + BMediaAddOn(image) +{ + fprintf(stderr,"MediaDemultiplexerAddOn::MediaDemultiplexerAddOn\n"); + refCount = 0; +} + +// -------------------------------------------------------- // +// BMediaAddOn impl +// -------------------------------------------------------- // + +status_t MediaDemultiplexerAddOn::InitCheck( + const char ** out_failure_text) +{ + fprintf(stderr,"MediaDemultiplexerAddOn::InitCheck\n"); + return B_OK; +} + +int32 MediaDemultiplexerAddOn::CountFlavors() +{ + fprintf(stderr,"MediaDemultiplexerAddOn::CountFlavors\n"); + return 1; +} + +status_t MediaDemultiplexerAddOn::GetFlavorAt( + int32 n, + const flavor_info ** out_info) +{ + fprintf(stderr,"MediaDemultiplexerAddOn::GetFlavorAt\n"); + if (out_info == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // we refuse to crash because you were stupid + } + if (n != 0) { + fprintf(stderr,"<- B_BAD_INDEX\n"); + return B_BAD_INDEX; + } + flavor_info * infos = new flavor_info[1]; + MediaDemultiplexerNode::GetFlavor(&infos[0],n); + (*out_info) = infos; + return B_OK; +} + +BMediaNode * MediaDemultiplexerAddOn::InstantiateNodeFor( + const flavor_info * info, + BMessage * config, + status_t * out_error) +{ + fprintf(stderr,"MediaDemultiplexerAddOn::InstantiateNodeFor\n"); + if (out_error == 0) { + fprintf(stderr,"<- NULL\n"); + return 0; // we refuse to crash because you were stupid + } + MediaDemultiplexerNode * node + = new MediaDemultiplexerNode(info,config,this); + if (node == 0) { + *out_error = B_NO_MEMORY; + fprintf(stderr,"<- B_NO_MEMORY\n"); + } else { + *out_error = node->InitCheck(); + } + return node; +} + +status_t MediaDemultiplexerAddOn::GetConfigurationFor( + BMediaNode * your_node, + BMessage * into_message) +{ + fprintf(stderr,"MediaDemultiplexerAddOn::GetConfigurationFor\n"); + if (into_message == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // we refuse to crash because you were stupid + } + MediaDemultiplexerNode * node + = dynamic_cast(your_node); + if (node == 0) { + fprintf(stderr,"<- B_BAD_TYPE\n"); + return B_BAD_TYPE; + } + return node->GetConfigurationFor(into_message); +} + +bool MediaDemultiplexerAddOn::WantsAutoStart() +{ + fprintf(stderr,"MediaDemultiplexerAddOn::WantsAutoStart\n"); + return false; +} + +status_t MediaDemultiplexerAddOn::AutoStart( + int in_count, + BMediaNode ** out_node, + int32 * out_internal_id, + bool * out_has_more) +{ + fprintf(stderr,"MediaDemultiplexerAddOn::AutoStart\n"); + return B_OK; +} + +// -------------------------------------------------------- // +// main +// -------------------------------------------------------- // + +// int main(int argc, char *argv[]) +//{ +//} + +// -------------------------------------------------------- // +// stuffing +// -------------------------------------------------------- // + +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_0(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_1(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_2(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_3(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_4(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_5(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_6(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_7(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_8(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_9(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_10(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_11(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_12(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_13(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_14(void *) {}; +status_t MediaDemultiplexerAddOn::_Reserved_MediaDemultiplexerAddOn_15(void *) {}; diff --git a/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.cpp b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.cpp index b6466ea1e6..010d1f82fb 100644 --- a/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.cpp +++ b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.cpp @@ -34,11 +34,6 @@ 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( @@ -48,7 +43,7 @@ MediaDemultiplexerNode::MediaDemultiplexerNode( : BMediaNode("MediaDemultiplexerNode"), BMediaEventLooper(), BBufferConsumer(B_MEDIA_MULTISTREAM), - BBufferProducer(B_MEDIA_UNKNOWN) // no B_MEDIA_ANY + BBufferProducer(B_MEDIA_UNKNOWN_TYPE) // no B_MEDIA_ANY { fprintf(stderr,"MediaDemultiplexerNode::MediaDemultiplexerNode\n"); // keep our creator around for AddOn calls later @@ -550,7 +545,7 @@ status_t MediaDemultiplexerNode::GetNextOutput( /* cookie starts as 0 */ { fprintf(stderr,"MediaDemultiplexerNode::GetNextOutput\n"); // let's not crash even if they are stupid - if ((out_output == 0) || (oookie == 0)) { + if ((out_output == 0) || (cookie == 0)) { // no place to write! fprintf(stderr,"<- B_BAD_VALUE\n"); return B_BAD_VALUE; @@ -572,7 +567,7 @@ status_t MediaDemultiplexerNode::GetNextOutput( /* cookie starts as 0 */ // return this output *out_output = itr->output; // so next time they won't get the same output again - *cookie = (int32)itr.next(); + *cookie = (int32)++itr; return B_OK; } @@ -592,7 +587,7 @@ status_t MediaDemultiplexerNode::SetBufferGroup( // find the information for this output vector::iterator itr; for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { - if (itr->output.source == source) { + if (itr->output.source == for_source) { break; } } @@ -649,7 +644,7 @@ status_t MediaDemultiplexerNode::PrepareToConnect( // find the information for this output vector::iterator itr; for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { - if (itr->output.source == source) { + if (itr->output.source == what) { break; } } @@ -658,7 +653,7 @@ status_t MediaDemultiplexerNode::PrepareToConnect( fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); return B_MEDIA_BAD_SOURCE; } - return itr->PrepareToConnect(destination,format,out_source,out_name); + return itr->PrepareToConnect(where,format,out_source,out_name); } void MediaDemultiplexerNode::Connect( @@ -669,12 +664,6 @@ void MediaDemultiplexerNode::Connect( 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++) { @@ -687,68 +676,82 @@ void MediaDemultiplexerNode::Connect( fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); return; } - + if (error != B_OK) { + fprintf(stderr,"<- error already\n"); + itr->output.destination = media_destination::null; + itr->output.format = itr->generalFormat; + return; + } + + // calculate the downstream latency + // must happen before itr->Connect + bigtime_t downstreamLatency; + media_node_id id; + FindLatencyFor(itr->output.destination, &downstreamLatency, &id); + // record the agreed upon values status_t status; - status = itr->Connect(destination,format,io_name); + status = itr->Connect(destination,format,io_name,downstreamLatency); 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); + // compute the internal latency + // must happen after itr->Connect + if (fInternalLatency == 0) { + fInternalLatency = 100; // temporary until we finish computing it + ComputeInternalLatency(); } // 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; + if (downstreamLatency > fDownstreamLatency) { SetEventLatency(fDownstreamLatency + fInternalLatency); } + + // XXX: what do I set the buffer duration to? + // it depends on which output is sending!! + // SetBufferDuration(bufferPeriod); // XXX: do anything else? - return B_OK; + return; +} + +void MediaDemultiplexerNode::ComputeInternalLatency() { + fprintf(stderr,"MediaDemultiplexerNode::ComputeInternalLatency\n"); +// 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); +// } } void MediaDemultiplexerNode::Disconnect( @@ -756,10 +759,6 @@ void MediaDemultiplexerNode::Disconnect( 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++) { @@ -772,6 +771,10 @@ void MediaDemultiplexerNode::Disconnect( fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); return; } + if (itr->output.destination != where) { + fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\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. @@ -796,30 +799,39 @@ void MediaDemultiplexerNode::LateNoticeReceived( 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; + 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; + } + 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: + // XXX: try to catch up by producing buffers faster + break; + case B_DROP_DATA: + // XXX: should we really drop buffers? just for that output? + break; + default: + // huh?? there aren't any more run modes. + fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived with unexpected run mode.\n"); + break; + } } void MediaDemultiplexerNode::EnableOutput( @@ -865,7 +877,7 @@ void MediaDemultiplexerNode::AdditionalBufferRequested( // used to be Reserved // find the information for this output vector::iterator itr; for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { - if (itr->output.source == what) { + if (itr->output.source == source) { break; } } @@ -875,12 +887,11 @@ void MediaDemultiplexerNode::AdditionalBufferRequested( // used to be Reserved return; } BBuffer * buffer; - status_t status = GetFilledBuffer(*itr,&buffer); + status_t status = itr->AdditionalBufferRequested(prev_buffer,prev_time,prev_tag); if (status != B_OK) { - fprintf(stderr,"MediaDemultiplexerNode::AdditionalBufferRequested got an error from GetFilledBuffer.\n"); - return; // don't send the buffer + fprintf(stderr," itr->AdditionalBufferRequested returned an error.\n"); + return; } - SendBuffer(buffer,itr->output.destination); return; } @@ -1067,7 +1078,7 @@ status_t MediaDemultiplexerNode::HandleBuffer( // } // } // } - bigtime_t nextEventTime = event->event_time+fBufferPeriod; + bigtime_t nextEventTime = event->event_time+10000; // fBufferPeriod; // XXX : should multiply media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER); EventQueue()->AddEvent(nextBufferEvent); return status; diff --git a/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.h b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.h index 80e15aacf9..cfaea0a908 100644 --- a/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.h +++ b/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.h @@ -320,6 +320,11 @@ virtual status_t HandleParameter( bigtime_t lateness, bool realTimeEvent = false); +protected: + +void CreateBufferGroup(MediaOutputInfo * output_info); +void ComputeInternalLatency(); + public: static void GetFlavor(flavor_info * outInfo, int32 id); diff --git a/src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.cpp b/src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.cpp new file mode 100644 index 0000000000..43a42ad3b8 --- /dev/null +++ b/src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.cpp @@ -0,0 +1,282 @@ +// MediaOutputInfo.cpp +// +// Andrew Bachmann, 2002 +// +// A class to encapsulate and manipulate +// all the information for a particular +// output of a media node. + +#include +#include +#include +#include +#include +#include "MediaOutputInfo.h" +#include "misc.h" + +MediaOutputInfo::MediaOutputInfo(BBufferProducer * node, char * name) { + producer = node; + // null some fields + bufferGroup = 0; + bufferPeriod = 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_destination::null; +} + +MediaOutputInfo::~MediaOutputInfo() { + if (bufferGroup != 0) { + BBufferGroup * group = bufferGroup; + bufferGroup = 0; + delete group; + } +} + +status_t MediaOutputInfo::SetBufferGroup(BBufferGroup * group) { + if (bufferGroup != 0) { + if (bufferGroup == group) { + return B_OK; // time saver + } + delete bufferGroup; + } + bufferGroup = group; +} + +// 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 MediaOutputInfo::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 MediaOutputInfo::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 MediaOutputInfo::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); + 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 MediaOutputInfo::Connect(const media_destination & destination, + const media_format & format, + char * io_name, + bigtime_t _downstreamLatency) +{ + 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'; + downstreamLatency = _downstreamLatency; // must be set before create buffer group + + status_t status = CreateBufferGroup(); // also initializes buffer period + if (status != B_OK) { + output.destination = media_destination::null; + output.format = generalFormat; + return status; + } + return B_OK; +} + +status_t MediaOutputInfo::Disconnect() +{ + output.destination = media_destination::null; + output.format = generalFormat; + if (bufferGroup != 0) { + BBufferGroup * group = bufferGroup; + bufferGroup = 0; + delete group; + } +} + +status_t MediaOutputInfo::EnableOutput(bool enabled) +{ + outputEnabled = enabled; + return B_OK; +} + +status_t MediaOutputInfo::AdditionalBufferRequested( + media_buffer_id prev_buffer, + bigtime_t prev_time, + const media_seek_tag * prev_tag) +{ + // XXX: implement me + return B_OK; +} + +// protected: + +status_t MediaOutputInfo::CreateBufferGroup() { + bufferPeriod = ComputeBufferPeriod(); + + if (bufferGroup == 0) { + int32 count = int32(downstreamLatency/bufferPeriod)+2; + fprintf(stderr," downstream latency = %lld, buffer period = %lld, buffer count = %i\n", + downstreamLatency,bufferPeriod,count); + + // allocate the buffers + bufferGroup = new BBufferGroup(ComputeBufferSize(),count); + if (bufferGroup == 0) { + fprintf(stderr,"<- B_NO_MEMORY\n"); + return B_NO_MEMORY; + } + status_t status = bufferGroup->InitCheck(); + if (status != B_OK) { + fprintf(stderr,"<- BufferGroup initialization failed\n"); + BBufferGroup * group = bufferGroup; + bufferGroup = 0; + delete group; + return status; + } + } + return B_OK; +} + +// public: + +uint32 MediaOutputInfo::ComputeBufferSize() { + return ComputeBufferSize(output.format); +} + +// returns result in # of bytes +uint32 MediaOutputInfo::ComputeBufferSize(const media_format & format) { + uint64 bufferSize = 1024; // default 1024 bytes + switch (format.type) { + case B_MEDIA_MULTISTREAM: + bufferSize = format.u.multistream.max_chunk_size; + break; + case B_MEDIA_ENCODED_VIDEO: + bufferSize = format.u.encoded_video.frame_size; + break; + case B_MEDIA_RAW_VIDEO: + if (format.u.raw_video.interlace == 0) { + // okay, you have no fields, you need no space, right? + bufferSize = 0; + } else { + // this is the size of a *field*, not a frame + bufferSize = format.u.raw_video.display.bytes_per_row * + format.u.raw_video.display.line_count / + format.u.raw_video.interlace; + } + break; + case B_MEDIA_ENCODED_AUDIO: + bufferSize = format.u.encoded_audio.frame_size; + break; + case B_MEDIA_RAW_AUDIO: + bufferSize = format.u.raw_audio.buffer_size; + break; + default: + break; + } + if (bufferSize > INT_MAX) { + bufferSize = INT_MAX; + } + return int32(bufferSize); +} + +bigtime_t MediaOutputInfo::ComputeBufferPeriod() { + return ComputeBufferPeriod(output.format); +} + +// returns result in # of microseconds +bigtime_t MediaOutputInfo::ComputeBufferPeriod(const media_format & format) { + bigtime_t bufferPeriod = 25*1000; // default 25 milliseconds + switch (format.type) { + case B_MEDIA_MULTISTREAM: + // given a buffer size of 8192 bytes + // and a bitrate of 1024 kilobits/millisecond (= 128 bytes/millisecond) + // we need to produce a buffer every 64 milliseconds (= every 64000 microseconds) + bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format) + / format.u.multistream.max_bit_rate); + break; + case B_MEDIA_ENCODED_VIDEO: + bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format) + / format.u.encoded_video.max_bit_rate); + break; + case B_MEDIA_ENCODED_AUDIO: + bufferPeriod = bigtime_t(1000.0 * 8.0 * ComputeBufferSize(format) + / format.u.encoded_audio.bit_rate); + break; + case B_MEDIA_RAW_VIDEO: + // Given a field rate of 50.00 fields per second, (PAL) + // we need to generate a field/buffer + // every 1/50 of a second = 20000 microseconds. + bufferPeriod = bigtime_t(1000000.0 + / format.u.raw_video.field_rate); + break; + case B_MEDIA_RAW_AUDIO: + // Given a sample size of 4 bytes [B_AUDIO_INT] + // and a channel count of 2 and a buffer_size + // of 256 bytes and a frame_rate of 44100 Hertz (1/sec) + // 1 frame = 1 sample/channel. + // comes to ?? + // this is a guess: + bufferPeriod = bigtime_t(1000000.0 * ComputeBufferSize(format) + / (format.u.raw_audio.format + & media_raw_audio_format::B_AUDIO_SIZE_MASK) + / format.u.raw_audio.channel_count + / format.u.raw_audio.frame_rate); + break; + default: + break; + } + return bufferPeriod; +} + + diff --git a/src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.h b/src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.h index bedeb0a282..c1f58d7abf 100644 --- a/src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.h +++ b/src/add-ons/media/media-add-ons/demultiplexer/MediaOutputInfo.h @@ -10,188 +10,59 @@ #define _MEDIA_OUTPUT_INFO_H #include +#include +#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'; + MediaOutputInfo(BBufferProducer * _node, char * name); + ~MediaOutputInfo(); - // determine our downstream latency - media_node_id id; - FindLatencyFor(output.destination, &downstreamLatency, &id); +virtual status_t SetBufferGroup(BBufferGroup * group); - // compute the buffer period (must be done before setbuffergroup) - bufferPeriod = computeBufferPeriod(output.format); - SetBufferDuration(fBufferPeriod); +virtual status_t FormatProposal(media_format * format); - // 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; - } +virtual status_t FormatChangeRequested( + const media_destination & destination, + media_format * io_format); - status_t Disconnect() - { - output.destination = media_destination::null; - output.format = genericFormat; - if (bufferGroup != 0) { - BBufferGroup * group = bufferGroup; - bufferGroup = 0; - delete group; - } - } +virtual status_t PrepareToConnect( + const media_destination & where, + media_format * format, + media_source * out_source, + char * out_name); - status_t EnableOutput(bool enabled) - { - outputEnabled = enabled; - return B_OK; - } +virtual status_t Connect( + const media_destination & destination, + const media_format & format, + char * io_name, + bigtime_t _downstreamLatency); + +virtual status_t Disconnect(); + +virtual status_t EnableOutput(bool enabled); + +virtual status_t AdditionalBufferRequested( + media_buffer_id prev_buffer, + bigtime_t prev_time, + const media_seek_tag * prev_tag); + +protected: + +virtual status_t CreateBufferGroup(); public: + +virtual uint32 ComputeBufferSize(); +virtual bigtime_t ComputeBufferPeriod(); +static uint32 ComputeBufferSize(const media_format & format); +static bigtime_t ComputeBufferPeriod(const media_format & format); + +public: + BBufferProducer * producer; + media_output output; bool outputEnabled; @@ -220,7 +91,7 @@ public: media_format fullySpecifiedFormat; // do we need media_seek_tag in here? -} +}; #endif // _MEDIA_OUTPUT_INFO_H