From 8c5a53fbe5aff8da54bbe38d1374488fc6eed05a Mon Sep 17 00:00:00 2001 From: shatty Date: Sat, 14 Sep 2002 10:01:19 +0000 Subject: [PATCH] initial commit git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1032 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../media/media-add-ons/fileproducer/Jamfile | 10 + .../fileproducer/MediaFileProducer.cpp | 1353 +++++++++++++++++ .../fileproducer/MediaFileProducer.h | 402 +++++ .../fileproducer/MediaFileProducerAddOn.cpp | 268 ++++ .../fileproducer/MediaFileProducerAddOn.h | 111 ++ 5 files changed, 2144 insertions(+) create mode 100644 src/add-ons/media/media-add-ons/fileproducer/Jamfile create mode 100644 src/add-ons/media/media-add-ons/fileproducer/MediaFileProducer.cpp create mode 100644 src/add-ons/media/media-add-ons/fileproducer/MediaFileProducer.h create mode 100644 src/add-ons/media/media-add-ons/fileproducer/MediaFileProducerAddOn.cpp create mode 100644 src/add-ons/media/media-add-ons/fileproducer/MediaFileProducerAddOn.h diff --git a/src/add-ons/media/media-add-ons/fileproducer/Jamfile b/src/add-ons/media/media-add-ons/fileproducer/Jamfile new file mode 100644 index 0000000000..47e4aab4ab --- /dev/null +++ b/src/add-ons/media/media-add-ons/fileproducer/Jamfile @@ -0,0 +1,10 @@ +SubDir OBOS_TOP src add-ons media media-add-ons fileproducer ; + +UsePrivateHeaders media ; + +Addon fileproducer.media_addon : media : + MediaFileProducer.cpp + MediaFileProducerAddOn.cpp +; + +LinkSharedOSLibs fileproducer.media_addon : be media ; diff --git a/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducer.cpp b/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducer.cpp new file mode 100644 index 0000000000..f7b4a81e6a --- /dev/null +++ b/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducer.cpp @@ -0,0 +1,1353 @@ +// MediaFileProducer.cpp +// +// Andrew Bachmann, 2002 +// +// A MediaFileProducer is a node that +// implements FileInterface and BBufferProducer. +// It reads any file and produces one output, +// which is a multistream. +// +// see also MediaFileProducerAddOn.cpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MediaFileProducer.h" + +#include +#include + +// -------------------------------------------------------- // +// ctor/dtor +// -------------------------------------------------------- // + +MediaFileProducer::~MediaFileProducer(void) +{ + fprintf(stderr,"MediaFileProducer::~MediaFileProducer\n"); + // Stop the BMediaEventLooper thread + Quit(); + if (inputFile != 0) { + delete inputFile; + } +} + +MediaFileProducer::MediaFileProducer( + size_t defaultChunkSize = 8192, + float defaultBitRate = 800000, + const flavor_info * info = 0, + BMessage * config = 0, + BMediaAddOn * addOn = 0) + : BMediaNode("MediaFileProducer"), + BBufferProducer(B_MEDIA_MULTISTREAM), + BFileInterface(), + BControllable(), + BMediaEventLooper() +{ + fprintf(stderr,"MediaFileProducer::MediaFileProducer\n"); + // keep our creator around for AddOn calls later + mediaFileProducerAddOn = addOn; + // null some fields + inputFile = 0; + bufferGroup = 0; + input_mime_type[0] = '\0'; + // start enabled + outputEnabled = true; + // don't overwrite available space, and be sure to terminate + strncpy(output.name,"MediaFileProducer Output",B_MEDIA_NAME_LENGTH-1); + output.name[B_MEDIA_NAME_LENGTH-1] = '\0'; + // initialize the output + output.node = media_node::null; // until registration + output.source = media_source::null; // until registration + output.destination = media_destination::null; + // initialize the parameters + if (defaultChunkSize <= 0) { + initCheckStatus = B_BAD_VALUE; + return; + } + defaultChunkSizeParam = defaultChunkSize; + defaultChunkSizeParamChangeTime = 0; + if (defaultBitRate <= 0) { + initCheckStatus = B_BAD_VALUE; + return; + } + defaultBitRateParam = defaultBitRate; + defaultBitRateParamChangeTime = 0; + // From the chunk size and bit rate we compute the buffer period. + defaultBufferPeriodParam = int32(8000000/1024*defaultChunkSizeParam/defaultBitRateParam); + if (defaultBufferPeriodParam <= 0) { + initCheckStatus = B_BAD_VALUE; + return; + } + defaultBufferPeriodParamChangeTime = 0; + + // this is also our preferred format + initCheckStatus = ResetFormat(&output.format); +} + +status_t MediaFileProducer::InitCheck(void) const +{ + fprintf(stderr,"MediaFileProducer::InitCheck\n"); + return initCheckStatus; +} + +status_t MediaFileProducer::GetConfigurationFor( + BMessage * into_message) +{ + fprintf(stderr,"MediaFileProducer::GetConfigurationFor\n"); + return B_OK; +} + +// -------------------------------------------------------- // +// implementation of BMediaNode +// -------------------------------------------------------- // + +BMediaAddOn * MediaFileProducer::AddOn( + int32 * internal_id) const +{ + fprintf(stderr,"MediaFileProducer::AddOn\n"); + // BeBook says this only gets called if we were in an add-on. + if (mediaFileProducerAddOn != 0) { + // If we get a null pointer then we just won't write. + if (internal_id != 0) { + internal_id = 0; + } + } + return mediaFileProducerAddOn; +} + +void MediaFileProducer::Start( + bigtime_t performance_time) +{ + fprintf(stderr,"MediaFileProducer::Start(pt=%i)\n",performance_time); + BMediaEventLooper::Start(performance_time); +} + +void MediaFileProducer::Stop( + bigtime_t performance_time, + bool immediate) +{ + fprintf(stderr,"MediaFileProducer::Stop(pt=%i,%s)\n",performance_time,(immediate?"now":"then")); + BMediaEventLooper::Stop(performance_time,immediate); +} + +void MediaFileProducer::Seek( + bigtime_t media_time, + bigtime_t performance_time) +{ + fprintf(stderr,"MediaFileProducer::Seek(mt=%i,pt=%i)\n",media_time,performance_time); + BMediaEventLooper::Seek(media_time,performance_time); +} + +void MediaFileProducer::SetRunMode( + run_mode mode) +{ + fprintf(stderr,"MediaFileProducer::SetRunMode(%i)\n",mode); + BMediaEventLooper::SetRunMode(mode); +} + +void MediaFileProducer::TimeWarp( + bigtime_t at_real_time, + bigtime_t to_performance_time) +{ + fprintf(stderr,"MediaFileProducer::TimeWarp(rt=%i,pt=%i)\n",at_real_time,to_performance_time); + BMediaEventLooper::TimeWarp(at_real_time,to_performance_time); +} + +void MediaFileProducer::Preroll(void) +{ + fprintf(stderr,"MediaFileProducer::Preroll\n"); + // XXX:Performance opportunity + BMediaNode::Preroll(); +} + +void MediaFileProducer::SetTimeSource( + BTimeSource * time_source) +{ + fprintf(stderr,"MediaFileProducer::SetTimeSource\n"); + BMediaNode::SetTimeSource(time_source); +} + +status_t MediaFileProducer::HandleMessage( + int32 message, + const void * data, + size_t size) +{ + fprintf(stderr,"MediaFileProducer::HandleMessage\n"); + status_t status = B_OK; + switch (message) { + // none for now + // maybe seeks later + default: + // XXX:FileInterface before BufferProducer or vice versa? + status = BFileInterface::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 MediaFileProducer::RequestCompleted( + const media_request_info & info) +{ + fprintf(stderr,"MediaFileProducer::RequestCompleted\n"); + return BMediaNode::RequestCompleted(info); +} + +status_t MediaFileProducer::DeleteHook( + BMediaNode * node) +{ + fprintf(stderr,"MediaFileProducer::DeleteHook\n"); + return BMediaEventLooper::DeleteHook(node); +} + +void MediaFileProducer::NodeRegistered(void) +{ + fprintf(stderr,"MediaFileProducer::NodeRegistered\n"); + // start the BMediaEventLooper thread + SetPriority(B_REAL_TIME_PRIORITY); + Run(); + + // now we can do this + output.node = Node(); + output.source.id = 0; + output.source.port = output.node.port; + + // and set up our parameter web + SetParameterWeb(MakeParameterWeb()); +} + +status_t MediaFileProducer::GetNodeAttributes( + media_node_attribute * outAttributes, + size_t inMaxCount) +{ + fprintf(stderr,"MediaFileProducer::GetNodeAttributes\n"); + return BMediaNode::GetNodeAttributes(outAttributes,inMaxCount); +} + +status_t MediaFileProducer::AddTimer( + bigtime_t at_performance_time, + int32 cookie) +{ + fprintf(stderr,"MediaFileProducer::AddTimer\n"); + return BMediaEventLooper::AddTimer(at_performance_time,cookie); +} + +// protected: + +BParameterWeb * MediaFileProducer::MakeParameterWeb(void) +{ + fprintf(stderr,"MediaFileProducer::MakeParameterWeb\n"); + + BParameterWeb * web = new BParameterWeb(); + BParameterGroup * mainGroup = web->MakeGroup("MediaFileProducer Parameters"); + + // these three are related: + // DEFAULT_CHUNK_SIZE_PARAM = DEFAULT_BIT_RATE_PARAM / 1024 * DEFAULT_BUFFER_PERIOD_PARAM * 1000 + BParameterGroup * chunkSizeGroup = mainGroup->MakeGroup("Chunk Size Group"); + BContinuousParameter * chunkSizeParameter + = chunkSizeGroup->MakeContinuousParameter( + DEFAULT_CHUNK_SIZE_PARAM, B_MEDIA_MULTISTREAM, + "Chunk Size", B_GAIN, "bytes", 1024, 32*1024, 512); + chunkSizeParameter->SetResponse(BContinuousParameter::B_LINEAR,1,0); + chunkSizeParameter->SetValue(&defaultChunkSizeParam,sizeof(defaultChunkSizeParam),0); + + BParameterGroup * bitRateGroup = mainGroup->MakeGroup("Bit Rate Group"); + BContinuousParameter * bitRateParameter + = bitRateGroup->MakeContinuousParameter( + DEFAULT_BIT_RATE_PARAM, B_MEDIA_MULTISTREAM, + "Bit Rate", B_GAIN, "kbits/sec", 1, 320000, 1); + bitRateParameter->SetResponse(BContinuousParameter::B_LINEAR,.001,0); + bitRateParameter->SetValue(&defaultBitRateParam,sizeof(defaultBitRateParam),0); + + BParameterGroup * bufferPeriodGroup = mainGroup->MakeGroup("Buffer Period Group"); + BContinuousParameter * bufferPeriodParameter + = bufferPeriodGroup->MakeContinuousParameter( + DEFAULT_BUFFER_PERIOD_PARAM, B_MEDIA_MULTISTREAM, + "Buffer Period", B_GAIN, "ms", 1, 10000, 1); + bufferPeriodParameter->SetResponse(BContinuousParameter::B_LINEAR,1,0); + bufferPeriodParameter->SetValue(&defaultBufferPeriodParam,sizeof(defaultBufferPeriodParam),0); + + return web; +} + +// -------------------------------------------------------- // +// implementation of BFileInterface +// -------------------------------------------------------- // + +status_t MediaFileProducer::GetNextFileFormat( + int32 * cookie, + media_file_format * out_format) +{ + fprintf(stderr,"MediaFileProducer::GetNextFileFormat\n"); + // let's not crash even if they are stupid + if (cookie != 0) { + // it's valid but they already got our 1 file format + if (*cookie != 0) { + fprintf(stderr,"<- B_ERROR\n"); + return B_ERROR; + } + // so next time they won't get the same format again + *cookie = 1; + } + if (out_format == 0) { + // no place to write! + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; + } + *out_format = GetFileFormat(); + return B_OK; +} + +void MediaFileProducer::DisposeFileFormatCookie( + int32 cookie) +{ + fprintf(stderr,"MediaFileProducer::DisposeFileFormatCookie\n"); + // nothing to do since our cookies are just integers +} + +status_t MediaFileProducer::GetDuration( + bigtime_t * out_time) +{ + fprintf(stderr,"MediaFileProducer::GetDuration\n"); + if (out_time == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; + } + if (inputFile == 0) { + fprintf(stderr,"<- B_NO_INIT\n"); + return B_NO_INIT; + } + return inputFile->GetSize(out_time); +} + +status_t MediaFileProducer::SniffRef( + const entry_ref & file, + char * out_mime_type, /* 256 bytes */ + float * out_quality) +{ + fprintf(stderr,"MediaFileProducer::SniffRef\n"); + return StaticSniffRef(file,out_mime_type,out_quality); +} + +status_t MediaFileProducer::SetRef( + const entry_ref & file, + bool create, + bigtime_t * out_time) +{ + fprintf(stderr,"MediaFileProducer::SetRef\n"); + if (out_time == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashes today thanks + } + status_t status; + input_ref = file; + if (inputFile == 0) { + inputFile = new BFile(&input_ref,(B_READ_ONLY|(create?B_CREATE_FILE:0))); + status = inputFile->InitCheck(); + } else { + status = inputFile->SetTo(&input_ref,(B_READ_ONLY|(create?B_CREATE_FILE:0))); + } + if (status != B_OK) { + fprintf(stderr,"<- failed BFile initialization\n"); + return status; + } + // cache the input mime type for later + inputFile->ReadAttr("BEOS:TYPE",0,0,input_mime_type,B_MIME_TYPE_LENGTH); + // respecialize our preferred format based on this file type + status = ResetFormat(&output.format); + if (status != B_OK) { + fprintf(stderr,"<- ResetFormat failed\n"); + return status; + } + // compute the duration and return any error + return GetDuration(out_time); +} + +status_t MediaFileProducer::GetRef( + entry_ref * out_ref, + char * out_mime_type) +{ + fprintf(stderr,"MediaFileProducer::GetRef\n"); + if ((out_ref == 0) || (out_mime_type == 0)) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashes today thanks + } + if (inputFile == 0) { + fprintf(stderr,"<- B_NO_INIT\n"); + return B_NO_INIT; // the input_ref isn't valid yet either + } + *out_ref = input_ref; + // they hopefully allocated enough space (no way to check :-/ ) + strcpy(out_mime_type,input_mime_type); + return B_OK; +} + +// provided for BMediaFileProducerAddOn + +status_t MediaFileProducer::StaticSniffRef( + const entry_ref & file, + char * out_mime_type, /* 256 bytes */ + float * out_quality) +{ + fprintf(stderr,"MediaFileProducer::StaticSniffRef\n"); + if ((out_mime_type == 0) || (out_quality == 0)) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // we refuse to crash because you were stupid + } + BNode node(&file); + status_t initCheck = node.InitCheck(); + if (initCheck != B_OK) { + fprintf(stderr,"<- failed BNode::InitCheck()\n"); + return initCheck; + } + // they hopefully allocated enough room + node.ReadAttr("BEOS:TYPE",0,0,out_mime_type,B_MIME_TYPE_LENGTH); + *out_quality = 1.0; // we handle all files perfectly! we are so amazing! + return B_OK; +} + +// -------------------------------------------------------- // +// implemention of BBufferProducer +// -------------------------------------------------------- // + +status_t MediaFileProducer::FormatSuggestionRequested( + media_type type, + int32 quality, + media_format * format) +{ + fprintf(stderr,"MediaFileProducer::GetRef\n"); + if (format == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashing + } + if ((type != B_MEDIA_MULTISTREAM) && (type != B_MEDIA_UNKNOWN_TYPE)) { + fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); + return B_MEDIA_BAD_FORMAT; + } + return ResetFormat(format); +} + +status_t MediaFileProducer::FormatProposal( + const media_source & output_source, + media_format * format) +{ + fprintf(stderr,"MediaFileProducer::FormatProposal\n"); + if (format == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashing + } + if (output.source != output_source) { + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return B_MEDIA_BAD_SOURCE; // we only have one output so that better be it + } + if (!format_is_compatible(*format,output.format)) { + fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); + return B_MEDIA_BAD_FORMAT; + } + output.format.SpecializeTo(format); + return B_OK; +} + +status_t MediaFileProducer::FormatChangeRequested( + const media_source & source, + const media_destination & destination, + media_format * io_format, + int32 * _deprecated_) +{ + fprintf(stderr,"MediaFileProducer::FormatChangeRequested\n"); + if (io_format == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashing + } + status_t status = FormatProposal(source,io_format); + if (status == B_MEDIA_BAD_FORMAT) { + fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); + ResetFormat(io_format); + } + return status; +} + +status_t MediaFileProducer::GetNextOutput( /* cookie starts as 0 */ + int32 * cookie, + media_output * out_output) +{ + fprintf(stderr,"MediaFileProducer::GetNextOutput\n"); + // let's not crash even if they are stupid + if (cookie != 0) { + // it's valid but they already got our 1 output + if (*cookie != 0) { + fprintf(stderr,"<- B_ERROR\n"); + return B_ERROR; + } + // so next time they won't get the same output again + *cookie = 1; + } + if (out_output == 0) { + // no place to write! + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; + } + *out_output = output; + return B_OK; +} + +status_t MediaFileProducer::DisposeOutputCookie( + int32 cookie) +{ + fprintf(stderr,"MediaFileProducer::DisposeOutputCookie\n"); + // nothing to do since our cookies are just integers + return B_OK; +} + +status_t MediaFileProducer::SetBufferGroup( + const media_source & for_source, + BBufferGroup * group) +{ + fprintf(stderr,"MediaFileProducer::SetBufferGroup\n"); + if (output.source != for_source) { + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return B_MEDIA_BAD_SOURCE; // we only have one output so that better be it + } + if (bufferGroup != 0) { + if (bufferGroup == group) { + return B_OK; // time saver + } + delete bufferGroup; + } + if (group != 0) { + bufferGroup = 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, &downstreamLatency, &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 (bufferPeriod <= 0) { + fprintf(stderr,"<- B_NO_INIT"); + return B_NO_INIT; + } + int32 count = int32(downstreamLatency/bufferPeriod)+2; + // allocate the buffers + bufferGroup = new BBufferGroup(output.format.u.multistream.max_chunk_size,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"); + return status; + } + } + return B_OK; +} + + /* 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 MediaFileProducer::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 MediaFileProducer::GetLatency( + bigtime_t * out_latency) +{ + fprintf(stderr,"MediaFileProducer::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 MediaFileProducer::PrepareToConnect( + const media_source & what, + const media_destination & where, + media_format * format, + media_source * out_source, + char * out_name) +{ + fprintf(stderr,"MediaFileProducer::PrepareToConnect\n"); + if ((format == 0) || (out_source == 0) || (out_name == 0)) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // no crashes... + } + if (output.destination != media_destination::null) { + fprintf(stderr,"<- B_MEDIA_ALREADY_CONNECTED\n"); + return B_MEDIA_ALREADY_CONNECTED; + } + status_t status = FormatChangeRequested(output.source,where,format,0); + if (status != B_OK) { + fprintf(stderr,"<- MediaFileProducer::FormatChangeRequested failed\n"); + return status; + } + // last check for wildcards and general validity + if (format->type != B_MEDIA_MULTISTREAM) { + fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); + return B_MEDIA_BAD_FORMAT; + } + *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 ResolveWildcards(&format->u.multistream); +} + +void MediaFileProducer::Connect( + status_t error, + const media_source & source, + const media_destination & destination, + const media_format & format, + char * io_name) +{ + fprintf(stderr,"MediaFileProducer::Connect\n"); + if (error != B_OK) { + fprintf(stderr,"<- error already\n"); + output.destination = media_destination::null; + ResetFormat(&output.format); + return; + } + + // record the agreed upon values + output.destination = destination; + output.format = format; + strncpy(io_name,output.name,B_MEDIA_NAME_LENGTH-1); + io_name[B_MEDIA_NAME_LENGTH] = '\0'; + + // determine our downstream latency + media_node_id id; + FindLatencyFor(output.destination, &downstreamLatency, &id); + + // compute the buffer period (must be done before setbuffergroup) + bufferPeriod = int32(8000000 / 1024 + * output.format.u.multistream.max_chunk_size + / output.format.u.multistream.max_bit_rate); + + // 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"); + return; + } + } + SetBufferDuration(bufferPeriod); + + if (inputFile != 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 = bufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,bufferPeriod); + if (buffer != 0) { + FillFileBuffer(buffer); + } else { + // didn't get a real BBuffer, try simulation by just a read from the disk + bytesRead = inputFile->Read(data,output.format.u.multistream.max_chunk_size); + } + end = TimeSource()->RealTime(); + } + bytesRead = buffer->SizeUsed(); + delete data; + if (buffer != 0) { + buffer->Recycle(); + } + inputFile->Seek(-bytesRead,SEEK_CUR); // put it back where we found it + + internalLatency = end - start; + + fprintf(stderr,"internal latency from disk read = %i\n",internalLatency); + } else { + internalLatency = 100; // just guess + fprintf(stderr,"internal latency guessed = %i\n",internalLatency); + } + + SetEventLatency(downstreamLatency + internalLatency); + + // XXX: do anything else? +} + +void MediaFileProducer::Disconnect( + const media_source & what, + const media_destination & where) +{ + fprintf(stderr,"MediaFileProducer::Disconnect\n"); + if ((where == output.destination) && (what == output.source)) { + output.destination = media_destination::null; + ResetFormat(&output.format); + BBufferGroup * group = bufferGroup; + bufferGroup = 0; + delete group; + } +} + +void MediaFileProducer::LateNoticeReceived( + const media_source & what, + bigtime_t how_much, + bigtime_t performance_time) +{ + fprintf(stderr,"MediaFileProducer::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: + internalLatency += how_much; + SetEventLatency(downstreamLatency + internalLatency); + break; + case B_DECREASE_PRECISION: + // What you want us to give you fewer bits or something? + break; + case B_DROP_DATA: + // Okay you asked for it, we'll skip ahead in the file! + // We'll drop 1 buffer's worth + if (inputFile == 0) { + fprintf(stderr,"MediaFileProducer::LateNoticeReceived called without an inputFile (!)\n"); + } else { + inputFile->Seek(output.format.u.multistream.max_chunk_size,SEEK_CUR); + } + break; + default: + // huh?? there aren't any more run modes. + fprintf(stderr,"MediaFileProducer::LateNoticeReceived with unexpected run mode.\n"); + break; + } + } +} + +void MediaFileProducer::EnableOutput( + const media_source & what, + bool enabled, + int32 * _deprecated_) +{ + fprintf(stderr,"MediaFileProducer::EnableOutput\n"); + if (what == output.source) { + outputEnabled = enabled; + } +} + +status_t MediaFileProducer::SetPlayRate( + int32 numer, + int32 denom) +{ + BBufferProducer::SetPlayRate(numer,denom); // XXX: do something intelligent later +} + +void MediaFileProducer::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,"MediaFileProducer::AdditionalBufferRequested\n"); + if (output.source == source) { + BBuffer * buffer; + status_t status = GetFilledBuffer(&buffer); + if (status != B_OK) { + fprintf(stderr,"MediaFileProducer::AdditionalBufferRequested got an error from GetFilledBuffer.\n"); + return; // don't send the buffer + } + SendBuffer(buffer,output.destination); + } +} + +void MediaFileProducer::LatencyChanged( + const media_source & source, + const media_destination & destination, + bigtime_t new_latency, + uint32 flags) +{ + fprintf(stderr,"MediaFileProducer::LatencyChanged\n"); + if ((output.source == source) && (output.destination == destination)) { + downstreamLatency = new_latency; + SetEventLatency(downstreamLatency + internalLatency); + } +} + +// -------------------------------------------------------- // +// implementation for BControllable +// -------------------------------------------------------- // + +const int32 MediaFileProducer::DEFAULT_CHUNK_SIZE_PARAM = 1; +const int32 MediaFileProducer::DEFAULT_BIT_RATE_PARAM = 2; +const int32 MediaFileProducer::DEFAULT_BUFFER_PERIOD_PARAM = 3; + +status_t MediaFileProducer::GetParameterValue( + int32 id, + bigtime_t * last_change, + void * value, + size_t * ioSize) +{ + fprintf(stderr,"MediaFileProducer::GetParameterValue\n"); + if ((last_change == 0) || (value == 0) || (ioSize == 0)) { + return B_BAD_VALUE; // no crashing + } + switch (id) { + case DEFAULT_CHUNK_SIZE_PARAM: + if (*ioSize < sizeof(size_t)) { + return B_ERROR; // not enough room + } + *last_change = defaultChunkSizeParamChangeTime; + *((size_t*)value) = defaultChunkSizeParam; + *ioSize = sizeof(size_t); + break; + + case DEFAULT_BIT_RATE_PARAM: + if (*ioSize < sizeof(float)) { + return B_ERROR; // not enough room + } + *last_change = defaultBitRateParamChangeTime; + *((float*)value) = defaultBitRateParam; + *ioSize = sizeof(float); + break; + + case DEFAULT_BUFFER_PERIOD_PARAM: + if (*ioSize < sizeof(bigtime_t)) { + return B_ERROR; // not enough room + } + *last_change = defaultBufferPeriodParamChangeTime; + *((bigtime_t*)value) = defaultBufferPeriodParam; + *ioSize = sizeof(bigtime_t); + break; + + default: + fprintf(stderr,"MediaFileProducer::GetParameterValue unknown id (%i)\n",id); + return B_ERROR; + } + return B_OK; +} + +void MediaFileProducer::SetParameterValue( + int32 id, + bigtime_t when, + const void * value, + size_t size) +{ + fprintf(stderr,"MediaFileProducer::SetParameterValue\n"); + switch (id) { + case DEFAULT_CHUNK_SIZE_PARAM: + case DEFAULT_BIT_RATE_PARAM: + case DEFAULT_BUFFER_PERIOD_PARAM: + { + media_timed_event event(when, BTimedEventQueue::B_PARAMETER, + NULL, BTimedEventQueue::B_NO_CLEANUP, + size, id, (char*) value, size); + EventQueue()->AddEvent(event); + } + break; + + default: + fprintf(stderr,"MediaFileProducer::SetParameterValue unknown id (%i)\n",id); + break; + } +} + +// the default implementation should call the add-on main() +status_t MediaFileProducer::StartControlPanel( + BMessenger * out_messenger) +{ + BControllable::StartControlPanel(out_messenger); +} + +// -------------------------------------------------------- // +// implementation for BMediaEventLooper +// -------------------------------------------------------- // + +void MediaFileProducer::HandleEvent( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaFileProducer::HandleEvent("); + switch (event->type) { + case BTimedEventQueue::B_START: + fprintf(stderr,"B_START)\n"); + if (RunState() != B_STARTED) { + media_timed_event firstBufferEvent(event->event_time, BTimedEventQueue::B_HANDLE_BUFFER); + //this->HandleEvent(&firstBufferEvent, 0, false); + EventQueue()->AddEvent(firstBufferEvent); + } + break; + case BTimedEventQueue::B_SEEK: + // XXX: argghh.. seek events seem broken when received from + // the usual BMediaEventLooper::Seek() dispatcher :-( + fprintf(stderr,"B_SEEK(t=%i,d=%i,bd=%ld))\n",event->event_time,event->data,event->bigdata); + if (inputFile != 0) { + inputFile->Seek(event->bigdata,SEEK_SET); + } + break; + case BTimedEventQueue::B_STOP: + fprintf(stderr,"B_STOP)\n"); + // flush the queue so downstreamers don't get any more + EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); + break; + case BTimedEventQueue::B_HANDLE_BUFFER: + fprintf(stderr,"B_HANDLE_BUFFER)\n"); + if ((RunState() != BMediaEventLooper::B_STARTED) + || (output.destination == media_destination::null)) { + break; + } + HandleBuffer(event,lateness,realTimeEvent); + break; + case BTimedEventQueue::B_DATA_STATUS: + fprintf(stderr,"B_DATA_STATUS)\n"); + SendDataStatus(event->data,output.destination,event->event_time); + break; + case BTimedEventQueue::B_PARAMETER: + fprintf(stderr,"B_PARAMETER)\n"); + HandleParameter(event,lateness,realTimeEvent); + break; + default: + fprintf(stderr,"%i)\n",event->type); + break; + } +} + +/* override to clean up custom events you have added to your queue */ +void MediaFileProducer::CleanUpEvent( + const media_timed_event *event) +{ + return BMediaEventLooper::CleanUpEvent(event); +} + +/* called from Offline mode to determine the current time of the node */ +/* update your internal information whenever it changes */ +bigtime_t MediaFileProducer::OfflineTime() +{ + fprintf(stderr,"MediaFileProducer::OfflineTime\n"); + if (inputFile == 0) { + return 0; + } else { + return inputFile->Position(); + } +} + +/* 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 MediaFileProducer::ControlLoop() { + BMediaEventLooper::ControlLoop(); +} + +// protected: + +status_t MediaFileProducer::HandleBuffer( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaFileProducer::HandleBuffer\n"); + status_t status = B_OK; + BBuffer * buffer = bufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,bufferPeriod); + if (buffer != 0) { + status = FillFileBuffer(buffer); + if (status != B_OK) { + fprintf(stderr,"MediaFileProducer::HandleEvent got an error from FillFileBuffer.\n"); + buffer->Recycle(); + } else { + if (outputEnabled) { + status = SendBuffer(buffer,output.destination); + } + if (status != B_OK) { + fprintf(stderr,"MediaFileProducer::HandleEvent got an error from SendBuffer.\n"); + buffer->Recycle(); + } + } + } + bigtime_t nextEventTime = event->event_time+bufferPeriod; + media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER); + EventQueue()->AddEvent(nextBufferEvent); + return status; +} + +status_t MediaFileProducer::HandleParameter( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) +{ + fprintf(stderr,"MediaFileProducer::HandleParameter\n"); + status_t status = B_OK; + + bool chunkSizeUpdated = false, bitRateUpdated = false, bufferPeriodUpdated = false; + + size_t dataSize = size_t(event->data); + int32 param = int32(event->bigdata); + + switch (param) { + case DEFAULT_CHUNK_SIZE_PARAM: + if (dataSize < sizeof(size_t)) { + fprintf(stderr,"<- B_BAD_VALUE\n",param); + status = B_BAD_VALUE; + } else { + size_t newDefaultChunkSize = *((size_t*)event->user_data); + // ignore non positive chunk sizes + // XXX: we may decide later that a 0 chunk size means ship the whole file in one chunk (!) + if ((newDefaultChunkSize > 0) && (newDefaultChunkSize != defaultChunkSizeParam)) { + defaultChunkSizeParam = newDefaultChunkSize; + defaultChunkSizeParamChangeTime = TimeSource()->Now(); + chunkSizeUpdated = true; + if (leastRecentlyUpdatedParameter == DEFAULT_CHUNK_SIZE_PARAM) { + // Okay we were the least recently updated parameter, + // but we just got an update so we are no longer that. + // Let's figure out who the new least recently updated + // parameter is. We are going to prefer to compute the + // bit rate since you usually don't want to muck with + // the buffer period. However, if you just set the bitrate + // then we are stuck with making the buffer period the new + // parameter to be computed. + if (lastUpdatedParameter == DEFAULT_BIT_RATE_PARAM) { + leastRecentlyUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM; + } else { + leastRecentlyUpdatedParameter = DEFAULT_BIT_RATE_PARAM; + } + } + // we just got an update, so we are the new lastUpdatedParameter + lastUpdatedParameter = DEFAULT_CHUNK_SIZE_PARAM; + // now we have to compute the new value for the leastRecentlyUpdatedParameter + // we use the chunk size change time to preserve "simultaneity" information + if (leastRecentlyUpdatedParameter == DEFAULT_BUFFER_PERIOD_PARAM) { + defaultBufferPeriodParam = MAX(1,int32(8000000/1024*defaultChunkSizeParam/defaultBitRateParam)); + defaultBufferPeriodParamChangeTime = defaultChunkSizeParamChangeTime; + bufferPeriodUpdated = true; + } else { // must have been bit rate + defaultBitRateParam = MAX(0.001,8000000/1024*defaultChunkSizeParam/defaultBufferPeriodParam); + defaultBitRateParamChangeTime = defaultChunkSizeParamChangeTime; + bitRateUpdated = true; + } + } + } + break; + case DEFAULT_BIT_RATE_PARAM: + if (dataSize < sizeof(size_t)) { + fprintf(stderr,"<- B_BAD_VALUE\n",param); + status = B_BAD_VALUE; + } else { + float newDefaultBitRate = *((size_t*)event->user_data); + // ignore non positive bitrates + if ((newDefaultBitRate > 0) && (newDefaultBitRate != defaultBitRateParam)) { + defaultBitRateParam = newDefaultBitRate; + defaultBitRateParamChangeTime = TimeSource()->Now(); + bitRateUpdated = true; + if (leastRecentlyUpdatedParameter == DEFAULT_BIT_RATE_PARAM) { + // Okay we were the least recently updated parameter, + // but we just got an update so we are no longer that. + // Let's figure out who the new least recently updated + // parameter is. We are going to prefer to compute the + // chunk size since you usually don't want to muck with + // the buffer period. However, if you just set the chunk size + // then we are stuck with making the buffer period the new + // parameter to be computed. + if (lastUpdatedParameter == DEFAULT_CHUNK_SIZE_PARAM) { + leastRecentlyUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM; + } else { + leastRecentlyUpdatedParameter = DEFAULT_CHUNK_SIZE_PARAM; + } + } + // we just got an update, so we are the new lastUpdatedParameter + lastUpdatedParameter = DEFAULT_BIT_RATE_PARAM; + // now we have to compute the new value for the leastRecentlyUpdatedParameter + // we use the bit rate change time to preserve "simultaneity" information + if (leastRecentlyUpdatedParameter == DEFAULT_BUFFER_PERIOD_PARAM) { + defaultBufferPeriodParam = MAX(1,int32(8000000/1024*defaultChunkSizeParam/defaultBitRateParam)); + defaultBufferPeriodParamChangeTime = defaultBitRateParamChangeTime; + bufferPeriodUpdated = true; + } else { // must have been chunk size + defaultChunkSizeParam = MAX(1,int32(1024/8000000*defaultBitRateParam*defaultBufferPeriodParam)); + defaultChunkSizeParamChangeTime = defaultBitRateParamChangeTime; + chunkSizeUpdated = true; + } + } + } + break; + case DEFAULT_BUFFER_PERIOD_PARAM: + if (dataSize < sizeof(bigtime_t)) { + fprintf(stderr,"<- B_BAD_VALUE\n",param); + status = B_BAD_VALUE; + } else { + bigtime_t newBufferPeriod = *((bigtime_t*)event->user_data); + // ignore non positive buffer period + if ((newBufferPeriod > 0) && (newBufferPeriod != defaultBufferPeriodParam)) { + defaultBufferPeriodParam = newBufferPeriod; + defaultBufferPeriodParamChangeTime = TimeSource()->Now(); + bufferPeriodUpdated = true; + if (lastUpdatedParameter == DEFAULT_BUFFER_PERIOD_PARAM) { + // prefer to update bit rate, unless you just set it + if (lastUpdatedParameter == DEFAULT_BIT_RATE_PARAM) { + leastRecentlyUpdatedParameter = DEFAULT_CHUNK_SIZE_PARAM; + } else { + leastRecentlyUpdatedParameter = DEFAULT_BIT_RATE_PARAM; + } + } + // we just got an update, so we are the new lastUpdatedParameter + lastUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM; + // now we have to compute the new value for the leastRecentlyUpdatedParameter + // we use the buffer period change time to preserve "simultaneity" information + if (leastRecentlyUpdatedParameter == DEFAULT_BIT_RATE_PARAM) { + defaultBitRateParam = MAX(0.001,8000000/1024*defaultChunkSizeParam/defaultBufferPeriodParam); + defaultBitRateParamChangeTime = defaultBufferPeriodParamChangeTime; + bitRateUpdated = true; + } else { // must have been chunk size + defaultChunkSizeParam = MAX(1,int32(1024/8000000*defaultBitRateParam*defaultBufferPeriodParam)); + defaultChunkSizeParamChangeTime = defaultBufferPeriodParamChangeTime; + chunkSizeUpdated = true; + } + } + } + break; + default: + fprintf(stderr,"MediaFileProducer::HandleParameter called with unknown param id (%i)\n",param); + status = B_ERROR; + } + // send updates out for all the parameters that changed + // in every case this should be two updates. (if I have not made an error :-) ) + if (chunkSizeUpdated) { + BroadcastNewParameterValue(defaultChunkSizeParamChangeTime, + DEFAULT_CHUNK_SIZE_PARAM, + &defaultChunkSizeParam, + sizeof(defaultChunkSizeParam)); + } + if (bitRateUpdated) { + BroadcastNewParameterValue(defaultBitRateParamChangeTime, + DEFAULT_BIT_RATE_PARAM, + &defaultBitRateParam, + sizeof(defaultBitRateParam)); + } + if (bufferPeriodUpdated) { + BroadcastNewParameterValue(defaultBufferPeriodParamChangeTime, + DEFAULT_BUFFER_PERIOD_PARAM, + &defaultBufferPeriodParam, + sizeof(defaultBufferPeriodParam)); + } + return status; +} + +// -------------------------------------------------------- // +// MediaFileProducer specific functions +// -------------------------------------------------------- // + +status_t MediaFileProducer::GetFlavor( + int32 id, + const flavor_info ** out_info) +{ + fprintf(stderr,"MediaFileProducer::GetFlavor\n"); + static flavor_info flavorInfo; + flavorInfo.name = "MediaFileProducer"; + flavorInfo.info = + "A MediaFileProducer node reads a file and produces a multistream.\n"; + flavorInfo.kinds = B_FILE_INTERFACE | B_BUFFER_PRODUCER | B_CONTROLLABLE; + flavorInfo.flavor_flags = B_FLAVOR_IS_LOCAL; + flavorInfo.possible_count = INT_MAX; + + flavorInfo.in_format_count = 0; // no inputs + flavorInfo.in_formats = 0; + + flavorInfo.out_format_count = 1; // 1 output + flavorInfo.out_formats = &GetFormat(); + + flavorInfo.internal_id = id; + + *out_info = &flavorInfo; + return B_OK; +} + +media_format & MediaFileProducer::GetFormat() +{ + fprintf(stderr,"MediaFileProducer::GetFormat\n"); + static media_format format; + format.type = B_MEDIA_MULTISTREAM; + format.require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; + format.deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; + format.u.multistream = media_multistream_format::wildcard; + return format; +} + +media_file_format & MediaFileProducer::GetFileFormat() +{ + fprintf(stderr,"MediaFileProducer::GetFileFormat\n"); + static media_file_format file_format; + file_format.capabilities = + media_file_format::B_READABLE + | media_file_format::B_PERFECTLY_SEEKABLE + | media_file_format::B_IMPERFECTLY_SEEKABLE + | media_file_format::B_KNOWS_ANYTHING; + /* I don't know what to initialize this to. (or if I should) */ + // format.id = + file_format.family = B_ANY_FORMAT_FAMILY; + file_format.version = 100; + strcpy(file_format.mime_type,""); + strcpy(file_format.pretty_name,"any media file format"); + strcpy(file_format.short_name,"any"); + strcpy(file_format.file_extension,""); + return file_format; +} + +status_t MediaFileProducer::ResetFormat(media_format * format) +{ + fprintf(stderr,"MediaFileProducer::ResetFormat\n"); + if (format == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; + } + *format = GetFormat(); + return ResolveWildcards(&format->u.multistream); +} + +// Here we make some guesses based on the file's mime type +// It's not our job to fill all the fields but this may help +// find the right node that does have that job. +status_t MediaFileProducer::ResolveWildcards( + media_multistream_format * multistream_format) +{ + fprintf(stderr,"MediaFileProducer::ResolveWildcards\n"); + if (strcmp("video/x-msvideo",input_mime_type) == 0) { + if (multistream_format->format == media_multistream_format::wildcard.format) { + multistream_format->format = media_multistream_format::B_AVI; + } + } else + if (strcmp("video/mpeg",input_mime_type) == 0) { + if (multistream_format->format == media_multistream_format::wildcard.format) { + multistream_format->format = media_multistream_format::B_MPEG1; + } + } else + if (strcmp("video/quicktime",input_mime_type) == 0) { + if (multistream_format->format == media_multistream_format::wildcard.format) { + multistream_format->format = media_multistream_format::B_QUICKTIME; + } + } else + if (strcmp("audio/x-mpeg",input_mime_type) == 0) { + if (multistream_format->format == media_multistream_format::wildcard.format) { + multistream_format->format = media_multistream_format::B_MPEG1; + } + } + // the thing that we connect to should really supply these, + // but just in case we have some defaults handy! + if (multistream_format->max_bit_rate == media_multistream_format::wildcard.max_bit_rate) { + multistream_format->max_bit_rate = defaultBitRateParam; + } + if (multistream_format->max_chunk_size == media_multistream_format::wildcard.max_chunk_size) { + multistream_format->max_chunk_size = defaultChunkSizeParam; + } + // we also default the averages to the maxes + if (multistream_format->avg_bit_rate == media_multistream_format::wildcard.avg_bit_rate) { + multistream_format->avg_bit_rate = multistream_format->max_bit_rate; + } + if (multistream_format->avg_chunk_size == media_multistream_format::wildcard.avg_chunk_size) { + multistream_format->avg_chunk_size = multistream_format->max_chunk_size; + } + return B_OK; +} + +status_t MediaFileProducer::GetFilledBuffer( + BBuffer ** outBuffer) +{ + fprintf(stderr,"MediaFileProducer::GetFilledBuffer\n"); + BBuffer * buffer = bufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,-1); + if (buffer == 0) { + // XXX: add a new buffer and get it + fprintf(stderr,"MediaFileProducer::GetFilledBuffer needs a new buffer.\n"); + return B_ERROR; // don't send the buffer + } + status_t status = FillFileBuffer(buffer); + *outBuffer = buffer; + return status; +} + +status_t MediaFileProducer::FillFileBuffer( + BBuffer * buffer) +{ + fprintf(stderr,"MediaFileProducer::FillFileBuffer\n"); + if (inputFile == 0) { + fprintf(stderr,"<- B_NO_INIT\n"); + return B_NO_INIT; + } + off_t position = inputFile->Position(); + ssize_t bytesRead = inputFile->Read(buffer->Data(),buffer->SizeAvailable()); + if (bytesRead < 0) { + fprintf(stderr,"<- B_FILE_ERROR\n"); + return B_FILE_ERROR; // some sort of file related error + } + buffer->SetSizeUsed(bytesRead); + media_header * header = buffer->Header(); + header->type = B_MEDIA_MULTISTREAM; + header->size_used = bytesRead; + header->file_pos = position; + header->orig_size = bytesRead; + header->time_source = TimeSource()->ID(); + // in our world performance time corresponds to bytes in the file + // so the start time of this buffer of bytes is simply its position + header->start_time = position; + // nothing more to say? + return B_OK; +} + +// -------------------------------------------------------- // +// stuffing +// -------------------------------------------------------- // + +status_t MediaFileProducer::_Reserved_MediaFileProducer_0(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_1(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_2(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_3(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_4(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_5(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_6(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_7(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_8(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_9(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_10(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_11(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_12(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_13(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_14(void *) {} +status_t MediaFileProducer::_Reserved_MediaFileProducer_15(void *) {} diff --git a/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducer.h b/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducer.h new file mode 100644 index 0000000000..ea213c4182 --- /dev/null +++ b/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducer.h @@ -0,0 +1,402 @@ +// MediaFileProducer.h +// +// Andrew Bachmann, 2002 +// +// A MediaFileProducer is a node that +// implements FileInterface and BBufferProducer. +// It reads any file and produces one output, +// which is a multistream. It has a rather +// unique interpretation of time. Time is +// distance in the file. So the duration is the +// file length. (in bytes) + +#if !defined(_MEDIA_FILE_PRODUCER_H) +#define _MEDIA_FILE_PRODUCER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class MediaFileProducer : + public BFileInterface, + public BBufferProducer, + public BControllable, + public BMediaEventLooper +{ +protected: +virtual ~MediaFileProducer(void); + +public: + +explicit MediaFileProducer( + size_t defaultChunkSize = 8192, // chunk size = 8 KB + float defaultBitRate = 800000, // bit rate = 100.000 KB/sec = 5.85 MB/minute + const flavor_info * info = 0, // buffer period = 80 milliseconds + 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 */ +/***********************/ + +protected: +virtual BParameterWeb * MakeParameterWeb(void); + +/*****************************/ +/* begin from BFileInterface */ +protected: +//included from BMediaNode +//virtual status_t HandleMessage( +// int32 message, +// const void * data, +// size_t size); + +virtual status_t GetNextFileFormat( + int32 * cookie, + media_file_format * out_format); +virtual void DisposeFileFormatCookie( + int32 cookie); + +virtual status_t GetDuration( + bigtime_t * out_time); + +virtual status_t SniffRef( + const entry_ref & file, + char * out_mime_type, /* 256 bytes */ + float * out_quality); + +virtual status_t SetRef( + const entry_ref & file, + bool create, + bigtime_t * out_time); +virtual status_t GetRef( + entry_ref * out_ref, + char * out_mime_type); + +/* end from BFileInterface */ +/***************************/ + +// provided for BMediaFileProducerAddOn +public: +static status_t StaticSniffRef( + const entry_ref & file, + char * out_mime_type, /* 256 bytes */ + float * out_quality); + +/******************************/ +/* 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 */ +/****************************/ + +/****************************/ +/* begin from BControllable */ + +//included from BMediaNode +//virtual status_t HandleMessage( +// int32 message, +// const void * data, +// size_t size); +public: + /* These are alternate methods of accomplishing the same thing as */ + /* connecting to control information source/destinations would. */ +virtual status_t GetParameterValue( + int32 id, + bigtime_t * last_change, + void * value, + size_t * ioSize); +virtual void SetParameterValue( + int32 id, + bigtime_t when, + const void * value, + size_t size); +virtual status_t StartControlPanel( + BMessenger * out_messenger); + +/* end from BControllable */ +/**************************/ + +public: + // these three are related: + // DEFAULT_CHUNK_SIZE = (DEFAULT_BIT_RATE * 1024) * (DEFAULT_BUFFER_PERIOD / 8000000) + static const int32 DEFAULT_CHUNK_SIZE_PARAM; // in bytes + static const int32 DEFAULT_BIT_RATE_PARAM; // in 1000*kilobits/sec + static const int32 DEFAULT_BUFFER_PERIOD_PARAM; // milliseconds + +private: + size_t defaultChunkSizeParam; + bigtime_t defaultChunkSizeParamChangeTime; + float defaultBitRateParam; + bigtime_t defaultBitRateParamChangeTime; + bigtime_t defaultBufferPeriodParam; + bigtime_t defaultBufferPeriodParamChangeTime; + + // This is used to figure out which parameter to compute + // when enforcing the above constraint relating the three params + int32 lastUpdatedParameter; + int32 leastRecentlyUpdatedParameter; + +/********************************/ +/* 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 HandleBuffer( + 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 status_t GetFlavor(int32 id, const flavor_info ** out_info); +static media_format & GetFormat(); +static media_file_format & GetFileFormat(); + +protected: + +virtual status_t ResetFormat(media_format * format); +virtual status_t ResolveWildcards(media_multistream_format * multistream_format); +virtual status_t GetFilledBuffer(BBuffer ** outBuffer); +virtual status_t FillFileBuffer(BBuffer * buffer); + +private: + + MediaFileProducer( /* private unimplemented */ + const MediaFileProducer & clone); + MediaFileProducer & operator=( + const MediaFileProducer & clone); + + status_t initCheckStatus; + + BMediaAddOn * mediaFileProducerAddOn; + media_output output; + + BFile * inputFile; + entry_ref input_ref; + char input_mime_type[B_MIME_TYPE_LENGTH+1]; + + BBufferGroup * bufferGroup; + + bigtime_t downstreamLatency; + bigtime_t internalLatency; + + bool outputEnabled; + + // this is computed from the real (negotiated) chunk size and bit rate, + // not the defaults that are in the parameters + bigtime_t bufferPeriod; + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_MediaFileProducer_0(void *); +virtual status_t _Reserved_MediaFileProducer_1(void *); +virtual status_t _Reserved_MediaFileProducer_2(void *); +virtual status_t _Reserved_MediaFileProducer_3(void *); +virtual status_t _Reserved_MediaFileProducer_4(void *); +virtual status_t _Reserved_MediaFileProducer_5(void *); +virtual status_t _Reserved_MediaFileProducer_6(void *); +virtual status_t _Reserved_MediaFileProducer_7(void *); +virtual status_t _Reserved_MediaFileProducer_8(void *); +virtual status_t _Reserved_MediaFileProducer_9(void *); +virtual status_t _Reserved_MediaFileProducer_10(void *); +virtual status_t _Reserved_MediaFileProducer_11(void *); +virtual status_t _Reserved_MediaFileProducer_12(void *); +virtual status_t _Reserved_MediaFileProducer_13(void *); +virtual status_t _Reserved_MediaFileProducer_14(void *); +virtual status_t _Reserved_MediaFileProducer_15(void *); + + uint32 _reserved_media_file_node_[16]; + +}; + +#endif /* _MEDIA_FILE_PRODUCER_H */ diff --git a/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducerAddOn.cpp b/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducerAddOn.cpp new file mode 100644 index 0000000000..e27bafff1b --- /dev/null +++ b/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducerAddOn.cpp @@ -0,0 +1,268 @@ +// MediaFileProducerAddOn.cpp +// +// Andrew Bachmann, 2002 +// +// A MediaFileProducerAddOn is an add-on +// that can make MediaFileProducer nodes +// +// MediaFileProducer nodes read a file into a multistream + + +#include +#include +#include +#include +#include +#include + +#include "MediaFileProducer.h" +#include "MediaFileProducerAddOn.h" + +#include +#include +#include + +// instantiation function +extern "C" _EXPORT BMediaAddOn * make_media_addon(image_id image) { + return new MediaFileProducerAddOn(image); +} + +// -------------------------------------------------------- // +// ctor/dtor +// -------------------------------------------------------- // + +MediaFileProducerAddOn::~MediaFileProducerAddOn() +{ +} + +MediaFileProducerAddOn::MediaFileProducerAddOn(image_id image) : + BMediaAddOn(image) +{ + fprintf(stderr,"MediaFileProducerAddOn::MediaFileProducerAddOn\n"); + refCount = 0; +} + +// -------------------------------------------------------- // +// BMediaAddOn impl +// -------------------------------------------------------- // + +status_t MediaFileProducerAddOn::InitCheck( + const char ** out_failure_text) +{ + fprintf(stderr,"MediaFileProducerAddOn::InitCheck\n"); + return B_OK; +} + +int32 MediaFileProducerAddOn::CountFlavors() +{ + fprintf(stderr,"MediaFileProducerAddOn::CountFlavors\n"); + return 1; +} + +status_t MediaFileProducerAddOn::GetFlavorAt( + int32 n, + const flavor_info ** out_info) +{ + fprintf(stderr,"MediaFileProducerAddOn::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; + } + return MediaFileProducer::GetFlavor(n,out_info); +} + +BMediaNode * MediaFileProducerAddOn::InstantiateNodeFor( + const flavor_info * info, + BMessage * config, + status_t * out_error) +{ + fprintf(stderr,"MediaFileProducerAddOn::InstantiateNodeFor\n"); + if (out_error == 0) { + fprintf(stderr,"<- NULL\n"); + return 0; // we refuse to crash because you were stupid + } + size_t defaultChunkSize = size_t(8192); // XXX: read from add-on's attributes + float defaultBitRate = 800000; + MediaFileProducer * node = new MediaFileProducer(defaultChunkSize, + defaultBitRate, + 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 MediaFileProducerAddOn::GetConfigurationFor( + BMediaNode * your_node, + BMessage * into_message) +{ + fprintf(stderr,"MediaFileProducerAddOn::GetConfigurationFor\n"); + if (into_message == 0) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // we refuse to crash because you were stupid + } + MediaFileProducer * node = dynamic_cast(your_node); + if (node == 0) { + fprintf(stderr,"<- B_BAD_TYPE\n"); + return B_BAD_TYPE; + } + return node->GetConfigurationFor(into_message); +} + +bool MediaFileProducerAddOn::WantsAutoStart() +{ + fprintf(stderr,"MediaFileProducerAddOn::WantsAutoStart\n"); + return false; +} + +status_t MediaFileProducerAddOn::AutoStart( + int in_count, + BMediaNode ** out_node, + int32 * out_internal_id, + bool * out_has_more) +{ + fprintf(stderr,"MediaFileProducerAddOn::AutoStart\n"); + return B_OK; +} + +// -------------------------------------------------------- // +// BMediaAddOn impl for B_FILE_INTERFACE nodes +// -------------------------------------------------------- // + +status_t MediaFileProducerAddOn::SniffRef( + const entry_ref & file, + BMimeType * io_mime_type, + float * out_quality, + int32 * out_internal_id) +{ + fprintf(stderr,"MediaFileProducerAddOn::SniffRef\n"); + if ((io_mime_type == 0) || (out_quality == 0) || (out_internal_id == 0)) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // we refuse to crash because you were stupid + } + *out_internal_id = 0; // only one flavor + char mime_string[B_MIME_TYPE_LENGTH+1]; + status_t status = MediaFileProducer::StaticSniffRef(file,mime_string,out_quality); + io_mime_type->SetTo(mime_string); + return status; +} + +// even though I implemented SniffTypeKind below and this shouldn't get called, +// I am going to implement it anyway. I'll use it later anyhow. +status_t MediaFileProducerAddOn::SniffType( + const BMimeType & type, + float * out_quality, + int32 * out_internal_id) +{ + fprintf(stderr,"MediaFileProducerAddOn::SniffType\n"); + if ((out_quality == 0) || (out_internal_id == 0)) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // we refuse to crash because you were stupid + } + *out_quality = 1.0; + *out_internal_id = 0; + return B_OK; +} + +// This function treats null pointers slightly differently than the others. +// This is because a program could reasonably call this function with just +// about any junk, get the out_read_items and then use that to create an +// array of sufficient size to hold the result, and then recall. Also, a +// stupid program could not supply an out_read_items, but actually supply +// an out_readable_formats and then try to do something useful with it. As +// an extreme gesture of nicety we will fill the out_readable_formats with +// a valid entry, although they could easily read into garbage after that... +status_t MediaFileProducerAddOn::GetFileFormatList( + int32 flavor_id, + media_file_format * out_writable_formats, + int32 in_write_items, + int32 * out_write_items, + media_file_format * out_readable_formats, + int32 in_read_items, + int32 * out_read_items, + void * _reserved) +{ + fprintf(stderr,"MediaFileProducerAddOn::GetFileFormatList\n"); + if (flavor_id != 0) { + // this is a sanity check for now + fprintf(stderr,"<- B_BAD_INDEX\n"); + return B_BAD_INDEX; + } + // see null check comment above + if (out_write_items != 0) { + *out_write_items = 0; + } + // see null check comment above + if (out_read_items != 0) { + *out_read_items = 1; + } + // see null check comment above + if (out_readable_formats != 0) { + // don't go off the end + if (in_read_items > 0) { + out_readable_formats[0] = MediaFileProducer::GetFileFormat(); + } + } + return B_OK; +} + +status_t MediaFileProducerAddOn::SniffTypeKind( + const BMimeType & type, + uint64 in_kinds, + float * out_quality, + int32 * out_internal_id, + void * _reserved) +{ + fprintf(stderr,"MediaFileProducerAddOn::SniffTypeKind\n"); + if ((out_quality == 0) || (out_internal_id == 0)) { + fprintf(stderr,"<- B_BAD_VALUE\n"); + return B_BAD_VALUE; // we refuse to crash because you were stupid + } + if (in_kinds & (B_BUFFER_PRODUCER | B_FILE_INTERFACE | B_CONTROLLABLE)) { + return SniffType(type,out_quality,out_internal_id); + } else { + // They asked for some kind we don't supply. We set the output + // just in case they try to do something with it anyway (!) + *out_quality = 0; + *out_internal_id = -1; + fprintf(stderr,"<- B_BAD_TYPE\n"); + return B_BAD_TYPE; + } +} + +// -------------------------------------------------------- // +// stuffing +// -------------------------------------------------------- // + +int main(int argc, char *argv[]) +{ + +} + +// -------------------------------------------------------- // +// stuffing +// -------------------------------------------------------- // + +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_0(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_1(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_2(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_3(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_4(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_5(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_6(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_7(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_8(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_9(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_10(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_11(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_12(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_13(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_14(void *) {}; +status_t MediaFileProducerAddOn::_Reserved_MediaFileProducerAddOn_15(void *) {}; diff --git a/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducerAddOn.h b/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducerAddOn.h new file mode 100644 index 0000000000..18861c3eb5 --- /dev/null +++ b/src/add-ons/media/media-add-ons/fileproducer/MediaFileProducerAddOn.h @@ -0,0 +1,111 @@ +// MediaFileProducerAddOn.h +// +// Andrew Bachmann, 2002 +// +// A MediaFileProducerAddOn is an add-on +// that can make MediaFileProducer nodes +// +// MediaFileProducer nodes read a file into a multistream + +#if !defined(_MEDIA_FILE_PRODUCER_ADD_ON_H) +#define _MEDIA_FILE_PRODUCER_ADD_ON_H + +#include +#include + +class MediaFileProducerAddOn : + public BMediaAddOn +{ +public: + virtual ~MediaFileProducerAddOn(void); + explicit MediaFileProducerAddOn(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); + +/* only implement if you have a B_FILE_INTERFACE node */ +virtual status_t SniffRef( + const entry_ref & file, + BMimeType * io_mime_type, + float * out_quality, + int32 * out_internal_id); +virtual status_t SniffType( // This is broken if you deal with producers + const BMimeType & type, // and consumers both. Use SniffTypeKind instead. + float * out_quality, // If you implement SniffTypeKind, this doesn't + int32 * out_internal_id); // get called. +virtual status_t GetFileFormatList( + int32 flavor_id, // for this node flavor (if it matters) + media_file_format * out_writable_formats, // don't write here if NULL + int32 in_write_items, // this many slots in out_writable_formats + int32 * out_write_items, // set this to actual # available, even if bigger than in count + media_file_format * out_readable_formats, // don't write here if NULL + int32 in_read_items, // this many slots in out_readable_formats + int32 * out_read_items, // set this to actual # available, even if bigger than in count + void * _reserved); // ignore until further notice +virtual status_t SniffTypeKind( // Like SniffType, but for the specific kind(s) + const BMimeType & type, + uint64 in_kinds, + float * out_quality, + int32 * out_internal_id, + void * _reserved); + + +/* end from BMediaAddOn */ +/************************/ + +private: + + MediaFileProducerAddOn( /* private unimplemented */ + const MediaFileProducerAddOn & clone); + MediaFileProducerAddOn & operator=( + const MediaFileProducerAddOn & clone); + + int32 refCount; + + /* Mmmh, stuffing! */ +virtual status_t _Reserved_MediaFileProducerAddOn_0(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_1(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_2(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_3(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_4(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_5(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_6(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_7(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_8(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_9(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_10(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_11(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_12(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_13(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_14(void *); +virtual status_t _Reserved_MediaFileProducerAddOn_15(void *); + + uint32 _reserved_media_file_node_[16]; + +}; + +#if BUILDING_MEDIA_FILE_PRODUCER__ADD_ON +extern "C" _EXPORT BMediaAddOn * make_media_file_producer_add_on(image_id you); +#endif + +#endif /* _MEDIA_FILE_PRODUCER_ADD_ON_H */