diff --git a/src/add-ons/media/media-add-ons/writer/Jamfile b/src/add-ons/media/media-add-ons/writer/Jamfile index c4aea24e9f..76bc5c1b85 100644 --- a/src/add-ons/media/media-add-ons/writer/Jamfile +++ b/src/add-ons/media/media-add-ons/writer/Jamfile @@ -3,6 +3,8 @@ SubDir OBOS_TOP src add-ons media media-add-ons writer ; UsePrivateHeaders media ; Addon writer.media_addon : media : + ../AbstractFileInterfaceNode.cpp + ../AbstractFileInterfaceAddOn.cpp MediaWriter.cpp MediaWriterAddOn.cpp ; diff --git a/src/add-ons/media/media-add-ons/writer/MediaWriter.cpp b/src/add-ons/media/media-add-ons/writer/MediaWriter.cpp index 79a310a3b7..cabe3a980f 100644 --- a/src/add-ons/media/media-add-ons/writer/MediaWriter.cpp +++ b/src/add-ons/media/media-add-ons/writer/MediaWriter.cpp @@ -25,6 +25,7 @@ #include #include +#include "../AbstractFileInterfaceNode.h" #include "MediaWriter.h" #include @@ -37,16 +38,11 @@ MediaWriter::~MediaWriter(void) { fprintf(stderr,"MediaWriter::~MediaWriter\n"); - // Stop the BMediaEventLooper thread - Quit(); - if (outputFile != 0) { - delete outputFile; - } - if (bufferGroup != 0) { - BBufferGroup * group = bufferGroup; - bufferGroup = 0; + if (fBufferGroup != 0) { + BBufferGroup * group = fBufferGroup; + fBufferGroup = 0; delete group; - } + } } MediaWriter::MediaWriter( @@ -56,18 +52,14 @@ MediaWriter::MediaWriter( BMessage * config = 0, BMediaAddOn * addOn = 0) : BMediaNode("MediaWriter"), - BBufferConsumer(B_MEDIA_MULTISTREAM), - BFileInterface(), - BControllable(), - BMediaEventLooper() + AbstractFileInterfaceNode(defaultChunkSize,defaultBitRate,info,config,addOn), + BBufferConsumer(B_MEDIA_MULTISTREAM) { fprintf(stderr,"MediaWriter::MediaWriter\n"); - // keep our creator around for AddOn calls later - mediaWriterAddOn = addOn; // null some fields - outputFile = 0; - bufferGroup = 0; - output_mime_type[0] = '\0'; + fBufferGroup = 0; + // start enabled + fInputEnabled = true; // don't overwrite available space, and be sure to terminate strncpy(input.name,"MediaWriter Input",B_MEDIA_NAME_LENGTH-1); input.name[B_MEDIA_NAME_LENGTH-1] = '\0'; @@ -75,100 +67,13 @@ MediaWriter::MediaWriter( input.node = media_node::null; // until registration input.source = media_source::null; input.destination = media_destination::null; // until registration - // 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(&input.format); -} - -status_t MediaWriter::InitCheck(void) const -{ - fprintf(stderr,"MediaWriter::InitCheck\n"); - return initCheckStatus; -} - -status_t MediaWriter::GetConfigurationFor( - BMessage * into_message) -{ - fprintf(stderr,"MediaWriter::GetConfigurationFor\n"); - return B_OK; + input.format = *GetFormat(); } // -------------------------------------------------------- // // implementation of BMediaNode // -------------------------------------------------------- // -BMediaAddOn * MediaWriter::AddOn( - int32 * internal_id) const -{ - fprintf(stderr,"MediaWriter::AddOn\n"); - // BeBook says this only gets called if we were in an add-on. - if (mediaWriterAddOn != 0) { - // If we get a null pointer then we just won't write. - if (internal_id != 0) { - internal_id = 0; - } - } - return mediaWriterAddOn; -} - -void MediaWriter::Start( - bigtime_t performance_time) -{ - fprintf(stderr,"MediaWriter::Start(pt=%i)\n",performance_time); - BMediaEventLooper::Start(performance_time); -} - -void MediaWriter::Stop( - bigtime_t performance_time, - bool immediate) -{ - fprintf(stderr,"MediaWriter::Stop(pt=%i,%s)\n",performance_time,(immediate?"now":"then")); - BMediaEventLooper::Stop(performance_time,immediate); -} - -void MediaWriter::Seek( - bigtime_t media_time, - bigtime_t performance_time) -{ - fprintf(stderr,"MediaWriter::Seek(mt=%i,pt=%i)\n",media_time,performance_time); - BMediaEventLooper::Seek(media_time,performance_time); -} - -void MediaWriter::SetRunMode( - run_mode mode) -{ - fprintf(stderr,"MediaWriter::SetRunMode(%i)\n",mode); - BMediaEventLooper::SetRunMode(mode); -} - -void MediaWriter::TimeWarp( - bigtime_t at_real_time, - bigtime_t to_performance_time) -{ - fprintf(stderr,"MediaWriter::TimeWarp(rt=%i,pt=%i)\n",at_real_time,to_performance_time); - BMediaEventLooper::TimeWarp(at_real_time,to_performance_time); -} - void MediaWriter::Preroll(void) { fprintf(stderr,"MediaWriter::Preroll\n"); @@ -176,13 +81,6 @@ void MediaWriter::Preroll(void) BMediaNode::Preroll(); } -void MediaWriter::SetTimeSource( - BTimeSource * time_source) -{ - fprintf(stderr,"MediaWriter::SetTimeSource\n"); - BMediaNode::SetTimeSource(time_source); -} - status_t MediaWriter::HandleMessage( int32 message, const void * data, @@ -191,253 +89,180 @@ status_t MediaWriter::HandleMessage( fprintf(stderr,"MediaWriter::HandleMessage\n"); status_t status = B_OK; switch (message) { - // none for now - // maybe seeks later + // no special messages for now default: - // XXX:FileInterface before BBufferConsumer or vice versa? - status = BFileInterface::HandleMessage(message,data,size); - if (status == B_OK) { - break; - } status = BBufferConsumer::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; + status = AbstractFileInterfaceNode::HandleMessage(message,data,size); break; } return status; } -status_t MediaWriter::RequestCompleted( - const media_request_info & info) -{ - fprintf(stderr,"MediaWriter::RequestCompleted\n"); - return BMediaNode::RequestCompleted(info); -} - -status_t MediaWriter::DeleteHook( - BMediaNode * node) -{ - fprintf(stderr,"MediaWriter::DeleteHook\n"); - return BMediaEventLooper::DeleteHook(node); -} - void MediaWriter::NodeRegistered(void) { fprintf(stderr,"MediaWriter::NodeRegistered\n"); - // start the BMediaEventLooper thread - SetPriority(B_REAL_TIME_PRIORITY); - Run(); // now we can do this input.node = Node(); input.destination.id = 0; input.destination.port = input.node.port; - // and set up our parameter web - SetParameterWeb(MakeParameterWeb()); -} - -status_t MediaWriter::GetNodeAttributes( - media_node_attribute * outAttributes, - size_t inMaxCount) -{ - fprintf(stderr,"MediaWriter::GetNodeAttributes\n"); - return BMediaNode::GetNodeAttributes(outAttributes,inMaxCount); -} - -status_t MediaWriter::AddTimer( - bigtime_t at_performance_time, - int32 cookie) -{ - fprintf(stderr,"MediaWriter::AddTimer\n"); - return BMediaEventLooper::AddTimer(at_performance_time,cookie); -} - -// protected: - -BParameterWeb * MediaWriter::MakeParameterWeb(void) -{ - fprintf(stderr,"MediaWriter::MakeParameterWeb\n"); - - BParameterWeb * web = new BParameterWeb(); - BParameterGroup * mainGroup = web->MakeGroup("MediaWriter 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; + // creates the parameter web and starts the looper thread + AbstractFileInterfaceNode::NodeRegistered(); } // -------------------------------------------------------- // // implementation of BFileInterface // -------------------------------------------------------- // -status_t MediaWriter::GetNextFileFormat( - int32 * cookie, - media_file_format * out_format) -{ - fprintf(stderr,"MediaWriter::GetNextFileFormat\n"); - // let's not crash even if they are stupid - if (out_format == 0) { - // no place to write! - fprintf(stderr,"<- B_BAD_VALUE\n"); - return B_BAD_VALUE; - } - if (cookie != 0) { - // it's valid but they already got our 1 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; - } - *out_format = GetFileFormat(); - return B_OK; -} - -void MediaWriter::DisposeFileFormatCookie( - int32 cookie) -{ - fprintf(stderr,"MediaWriter::DisposeFileFormatCookie\n"); - // nothing to do since our cookies are just integers -} - -status_t MediaWriter::GetDuration( - bigtime_t * out_time) -{ - fprintf(stderr,"MediaWriter::GetDuration\n"); - if (out_time == 0) { - fprintf(stderr,"<- B_BAD_VALUE\n"); - return B_BAD_VALUE; - } - if (outputFile == 0) { - fprintf(stderr,"<- B_NO_INIT\n"); - return B_NO_INIT; - } - return outputFile->GetSize(out_time); -} - -status_t MediaWriter::SniffRef( - const entry_ref & file, - char * out_mime_type, /* 256 bytes */ - float * out_quality) -{ - fprintf(stderr,"MediaWriter::SniffRef\n"); - return StaticSniffRef(file,out_mime_type,out_quality); -} - status_t MediaWriter::SetRef( const entry_ref & file, bool create, bigtime_t * out_time) { fprintf(stderr,"MediaWriter::SetRef\n"); - if (out_time == 0) { - fprintf(stderr,"<- B_BAD_VALUE\n"); - return B_BAD_VALUE; // no crashes today thanks - } - status_t status; - output_ref = file; - if (outputFile == 0) { - outputFile = new BFile(&output_ref,(B_WRITE_ONLY|(create?B_CREATE_FILE:0))); - status = outputFile->InitCheck(); - } else { - status = outputFile->SetTo(&output_ref,(B_WRITE_ONLY|(create?B_CREATE_FILE:0))); - } + status_t status = AbstractFileInterfaceNode::SetRef(file,B_WRITE_ONLY,create,out_time); if (status != B_OK) { - fprintf(stderr,"<- failed BFile initialization\n"); + fprintf(stderr,"AbstractFileInterfaceNode::SetRef returned an error\n"); return status; } - // cache the output mime type for later - outputFile->WriteAttr("BEOS:TYPE",0,0,output_mime_type,B_MIME_TYPE_LENGTH); - // respecialize our preferred format based on this file type - status = ResetFormat(&input.format); - if (status != B_OK) { - fprintf(stderr,"<- ResetFormat failed\n"); - return status; + // reset the format, and set the requirements imposed by this file + input.format = *GetFormat(); + AddRequirements(&input.format); + // if we are connected we have to re-negotiate the connection + if (input.source != media_source::null) { + fprintf(stderr," error connection re-negotiation not implemented"); + // XXX: implement re-negotiation } - // compute the duration and return any error - return GetDuration(out_time); -} - -status_t MediaWriter::GetRef( - entry_ref * out_ref, - char * out_mime_type) -{ - fprintf(stderr,"MediaWriter::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 (outputFile == 0) { - fprintf(stderr,"<- B_NO_INIT\n"); - return B_NO_INIT; // the output_ref isn't valid yet either - } - *out_ref = output_ref; - // they hopefully allocated enough space (no way to check :-/ ) - strcpy(out_mime_type,output_mime_type); - return B_OK; -} - -// provided for BMediaWriterAddOn - -status_t MediaWriter::StaticSniffRef( - const entry_ref & file, - char * out_mime_type, /* 256 bytes */ - float * out_quality) -{ - fprintf(stderr,"MediaWriter::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.WriteAttr("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; + return B_OK; } // -------------------------------------------------------- // // implemention of BBufferConsumer // -------------------------------------------------------- // +/* +void print_multistream_format(media_multistream_format * format) { + fprintf(stderr,"["); + switch (format->format) { + case media_multistream_format::B_ANY: fprintf(stderr,"ANY"); break; + case media_multistream_format::B_VID: fprintf(stderr,"VID"); break; + case media_multistream_format::B_AVI: fprintf(stderr,"AVI"); break; + case media_multistream_format::B_MPEG1: fprintf(stderr,"MPEG1"); break; + case media_multistream_format::B_MPEG2: fprintf(stderr,"MPEG2"); break; + case media_multistream_format::B_QUICKTIME: fprintf(stderr,"QUICKTIME"); break; + default: fprintf(stderr,"????"); break; + } + fprintf(stderr," avg_bit_rate(%f) max_bit_rate(%f)", + format->avg_bit_rate,format->max_bit_rate); + fprintf(stderr," avg_chunk_size(%i) max_chunk_size(%i)", + format->avg_chunk_size,format->max_chunk_size); +} + +void print_media_format(media_format * format) { + fprintf(stderr,"{"); + switch (format->type) { + case B_MEDIA_NO_TYPE: fprintf(stderr,"NO_TYPE"); break; + case B_MEDIA_UNKNOWN_TYPE: fprintf(stderr,"UNKNOWN_TYPE"); break; + case B_MEDIA_RAW_AUDIO: fprintf(stderr,"RAW_AUDIO"); break; + case B_MEDIA_RAW_VIDEO: fprintf(stderr,"RAW_VIDEO"); break; + case B_MEDIA_VBL: fprintf(stderr,"VBL"); break; + case B_MEDIA_TIMECODE: fprintf(stderr,"TIMECODE"); break; + case B_MEDIA_MIDI: fprintf(stderr,"MIDI"); break; + case B_MEDIA_TEXT: fprintf(stderr,"TEXT"); break; + case B_MEDIA_HTML: fprintf(stderr,"HTML"); break; + case B_MEDIA_MULTISTREAM: fprintf(stderr,"MULTISTREAM"); break; + case B_MEDIA_PARAMETERS: fprintf(stderr,"PARAMETERS"); break; + case B_MEDIA_ENCODED_AUDIO: fprintf(stderr,"ENCODED_AUDIO"); break; + case B_MEDIA_ENCODED_VIDEO: fprintf(stderr,"ENCODED_VIDEO"); break; + default: fprintf(stderr,"????"); break; + } + fprintf(stderr,":"); + switch (format->type) { + case B_MEDIA_RAW_AUDIO: fprintf(stderr,"RAW_AUDIO"); break; + case B_MEDIA_RAW_VIDEO: fprintf(stderr,"RAW_VIDEO"); break; + case B_MEDIA_MULTISTREAM: print_multistream_format(&format->u.multistream); break; + case B_MEDIA_ENCODED_AUDIO: fprintf(stderr,"ENCODED_AUDIO"); break; + case B_MEDIA_ENCODED_VIDEO: fprintf(stderr,"ENCODED_VIDEO"); break; + default: fprintf(stderr,"????"); break; + } + fprintf(stderr,"}"); +} +*/ + +bool multistream_format_is_acceptible( + const media_multistream_format & producer_format, + const media_multistream_format & consumer_format) +{ + // first check the format, if necessary + if (consumer_format.format != media_multistream_format::B_ANY) { + if (consumer_format.format != producer_format.format) { + return false; + } + } + // then check the average bit rate + if (consumer_format.avg_bit_rate != media_multistream_format::wildcard.avg_bit_rate) { + if (consumer_format.avg_bit_rate != producer_format.avg_bit_rate) { + // do they have to match exactly? I don't know. assume yes. + return false; + } + } + // then check the maximum bit rate + if (consumer_format.max_bit_rate != media_multistream_format::wildcard.max_bit_rate) { + if (consumer_format.max_bit_rate != producer_format.max_bit_rate) { + // do they have to match exactly? I don't know. assume yes. + return false; + } + } + // then check the average chunk size + if (consumer_format.avg_chunk_size != media_multistream_format::wildcard.avg_chunk_size) { + if (consumer_format.avg_chunk_size != producer_format.avg_chunk_size) { + // do they have to match exactly? I don't know. assume yes. + return false; + } + } + // then check the maximum bit rate + if (consumer_format.max_chunk_size != media_multistream_format::wildcard.max_chunk_size) { + if (consumer_format.max_chunk_size != producer_format.max_chunk_size) { + // do they have to match exactly? I don't know. assume yes. + return false; + } + } + // should also check format specific fields, and others? + return true; +} + +bool format_is_acceptible( + const media_format & producer_format, + const media_format & consumer_format) +{ + // first check the type, if necessary + if (consumer_format.type != B_MEDIA_UNKNOWN_TYPE) { + if (consumer_format.type != producer_format.type) { + return false; + } + switch (consumer_format.type) { + case B_MEDIA_MULTISTREAM: + if (!multistream_format_is_acceptible(producer_format.u.multistream, + consumer_format.u.multistream)) { + return false; + } + break; + default: + fprintf(stderr,"format_is_acceptible : unimplemented type.\n"); + return format_is_compatible(producer_format,consumer_format); + break; + } + } + // should also check non-type fields? + return true; +} + +// Check to make sure the format is okay, then remove +// any wildcards corresponding to our requirements. status_t MediaWriter::AcceptFormat( const media_destination & dest, media_format * format) @@ -451,11 +276,20 @@ status_t MediaWriter::AcceptFormat( fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION"); return B_MEDIA_BAD_DESTINATION; // we only have one input so that better be it } - // XXX: broken??? -// if (!format_is_compatible(input.format,*format)) { -// fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); -// return B_MEDIA_BAD_FORMAT; -// } +/* media_format * myFormat = GetFormat(); + fprintf(stderr,"proposed format: "); + print_media_format(format); + fprintf(stderr,"\n"); + fprintf(stderr,"my format: "); + print_media_format(myFormat); + fprintf(stderr,"\n");*/ + // Be's format_is_compatible doesn't work. +// if (!format_is_compatible(*format,*myFormat)) { + if (!format_is_acceptible(*format,*GetFormat())) { + fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); + return B_MEDIA_BAD_FORMAT; + } + AddRequirements(format); return B_OK; } @@ -481,7 +315,6 @@ status_t MediaWriter::GetNextInput( } *out_input = input; return B_OK; - } void MediaWriter::DisposeInputCookie( @@ -489,7 +322,7 @@ void MediaWriter::DisposeInputCookie( { fprintf(stderr,"MediaWriter::DisposeInputCookie\n"); // nothing to do since our cookies are just integers - return; + return; // B_OK; } void MediaWriter::BufferReceived( @@ -579,9 +412,9 @@ status_t MediaWriter::Connected( } // clear any stale buffer groups - if (bufferGroup != 0) { - BBufferGroup * group = bufferGroup; - bufferGroup = 0; + if (fBufferGroup != 0) { + BBufferGroup * group = fBufferGroup; + fBufferGroup = 0; delete group; } @@ -600,9 +433,20 @@ void MediaWriter::Disconnected( const media_destination & where) { fprintf(stderr,"MediaWriter::Disconnected\n"); - if ((input.source == producer) && (input.destination == where)) { - input.source = media_source::null; - ResetFormat(&input.format); + if (input.destination != where) { + fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); + return; + } + if (input.source != producer) { + fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); + return; + } + input.source = media_source::null; + input.format = *GetFormat(); + if (fBufferGroup != 0) { + BBufferGroup * group = fBufferGroup; + fBufferGroup = 0; + delete group; } } @@ -615,8 +459,16 @@ status_t MediaWriter::FormatChanged( const media_format & format) { fprintf(stderr,"MediaWriter::FormatChanged\n"); - - + if (input.source != producer) { + return B_MEDIA_BAD_SOURCE; + } + if (input.destination != consumer) { + return B_MEDIA_BAD_DESTINATION; + } + // Since we don't really care about the format of the data + // we can just continue to treat things the same way. + input.format = format; + return B_OK; } /* Given a performance time of some previous buffer, retrieve the remembered tag */ @@ -636,174 +488,14 @@ status_t MediaWriter::SeekTagRequested( out_seek_tag,out_tagged_time,out_flags); } -// -------------------------------------------------------- // -// implementation for BControllable -// -------------------------------------------------------- // - -const int32 MediaWriter::DEFAULT_CHUNK_SIZE_PARAM = 1; -const int32 MediaWriter::DEFAULT_BIT_RATE_PARAM = 2; -const int32 MediaWriter::DEFAULT_BUFFER_PERIOD_PARAM = 3; - -status_t MediaWriter::GetParameterValue( - int32 id, - bigtime_t * last_change, - void * value, - size_t * ioSize) -{ - fprintf(stderr,"MediaWriter::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,"MediaWriter::GetParameterValue unknown id (%i)\n",id); - return B_ERROR; - } - return B_OK; -} - -void MediaWriter::SetParameterValue( - int32 id, - bigtime_t when, - const void * value, - size_t size) -{ - fprintf(stderr,"MediaWriter::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,"MediaWriter::SetParameterValue unknown id (%i)\n",id); - break; - } -} - -// the default implementation should call the add-on main() -status_t MediaWriter::StartControlPanel( - BMessenger * out_messenger) -{ - BControllable::StartControlPanel(out_messenger); -} - // -------------------------------------------------------- // // implementation for BMediaEventLooper // -------------------------------------------------------- // -void MediaWriter::HandleEvent( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent = false) -{ - fprintf(stderr,"MediaWriter::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 (outputFile != 0) { - outputFile->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) - || (input.source == media_source::null)) { - break; // confusing to receive a buffer without an input :-| - } - 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 MediaWriter::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 MediaWriter::OfflineTime() -{ - fprintf(stderr,"MediaWriter::OfflineTime\n"); - if (outputFile == 0) { - return 0; - } else { - return outputFile->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 MediaWriter::ControlLoop() { - BMediaEventLooper::ControlLoop(); -} - // protected: +// how should we handle late buffers? drop them? +// notify the producer? status_t MediaWriter::HandleBuffer( const media_timed_event *event, bigtime_t lateness, @@ -811,326 +503,75 @@ status_t MediaWriter::HandleBuffer( { fprintf(stderr,"MediaWriter::HandleBuffer\n"); status_t status = B_OK; + BBuffer * buffer = const_cast((BBuffer*)event->pointer); + WriteFileBuffer(buffer); + buffer->Recycle(); return status; } -status_t MediaWriter::HandleParameter( - const media_timed_event *event, - bigtime_t lateness, - bool realTimeEvent = false) +status_t MediaWriter::HandleDataStatus( + const media_timed_event *event, + bigtime_t lateness, + bool realTimeEvent = false) { - fprintf(stderr,"MediaWriter::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,"MediaWriter::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; + fprintf(stderr,"MediaWriter::HandleDataStatus"); + // we have no where to send a data status to. + return B_OK; } + // -------------------------------------------------------- // // MediaWriter specific functions // -------------------------------------------------------- // -status_t MediaWriter::GetFlavor( - int32 id, - const flavor_info ** out_info) +// static: + +void MediaWriter::GetFlavor(flavor_info * info, int32 id) { fprintf(stderr,"MediaWriter::GetFlavor\n"); - static flavor_info flavorInfo; - flavorInfo.name = "MediaWriter"; - flavorInfo.info = - "A MediaWriter node consumes a multistream and writes a file."; - flavorInfo.kinds = B_FILE_INTERFACE | B_BUFFER_CONSUMER | B_CONTROLLABLE; - flavorInfo.flavor_flags = B_FLAVOR_IS_LOCAL; - flavorInfo.possible_count = INT_MAX; - - flavorInfo.in_format_count = 1; // 1 input - flavorInfo.in_formats = &GetFormat(); - - flavorInfo.out_format_count = 0; // no outputs - flavorInfo.out_formats = 0; - - flavorInfo.internal_id = id; - - *out_info = &flavorInfo; - return B_OK; + AbstractFileInterfaceNode::GetFlavor(info,id); + info->name = "OpenBeOS Media Writer"; + info->info = "The OpenBeOS Media Writer consumes a multistream and writes a file."; + info->kinds |= B_BUFFER_CONSUMER; + info->in_format_count = 1; // 1 input + info->in_formats = GetFormat(); + return; } -media_format & MediaWriter::GetFormat() +media_format * MediaWriter::GetFormat() { fprintf(stderr,"MediaWriter::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; + return AbstractFileInterfaceNode::GetFormat(); } -media_file_format & MediaWriter::GetFileFormat() +media_file_format * MediaWriter::GetFileFormat() { fprintf(stderr,"MediaWriter::GetFileFormat\n"); - static media_file_format file_format; - file_format.capabilities = - media_file_format::B_WRITABLE - | 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,""); + static bool initialized = false; + static media_file_format * file_format; + if (initialized == false) { + file_format = AbstractFileInterfaceNode::GetFileFormat(); + file_format->capabilities |= media_file_format::B_WRITABLE; + initialized = true; + } return file_format; } -status_t MediaWriter::ResetFormat(media_format * format) -{ - fprintf(stderr,"MediaWriter::ResetFormat\n"); - if (format == 0) { - fprintf(stderr,"<- B_BAD_VALUE\n"); - return B_BAD_VALUE; - } - *format = GetFormat(); - return ResolveWildcards(&format->u.multistream); -} +// protected: -// 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 MediaWriter::ResolveWildcards( - media_multistream_format * multistream_format) -{ - fprintf(stderr,"MediaWriter::ResolveWildcards\n"); - if (strcmp("video/x-msvideo",output_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",output_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",output_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",output_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 MediaWriter::GetFilledBuffer( - BBuffer ** outBuffer) -{ - fprintf(stderr,"MediaWriter::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,"MediaWriter::GetFilledBuffer needs a new buffer.\n"); -// return B_ERROR; // don't send the buffer -// } -// status_t status = FillFileBuffer(buffer); -// *outBuffer = buffer; -// return status; - return B_OK; -} - -status_t MediaWriter::FillFileBuffer( +status_t MediaWriter::WriteFileBuffer( BBuffer * buffer) { - fprintf(stderr,"MediaWriter::FillFileBuffer\n"); - if (outputFile == 0) { + fprintf(stderr,"MediaWriter::WriteFileBuffer\n"); + if (GetCurrentFile() == 0) { fprintf(stderr,"<- B_NO_INIT\n"); return B_NO_INIT; - } - off_t position = outputFile->Position(); - ssize_t bytesWrite = outputFile->Write(buffer->Data(),buffer->SizeAvailable()); - if (bytesWrite < 0) { + } + ssize_t bytesWriten = GetCurrentFile()->Write(buffer->Data(),buffer->SizeUsed()); + if (bytesWriten < 0) { fprintf(stderr,"<- B_FILE_ERROR\n"); return B_FILE_ERROR; // some sort of file related error } - buffer->SetSizeUsed(bytesWrite); - media_header * header = buffer->Header(); - header->type = B_MEDIA_MULTISTREAM; - header->size_used = bytesWrite; - header->file_pos = position; - header->orig_size = bytesWrite; - 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; } diff --git a/src/add-ons/media/media-add-ons/writer/MediaWriter.h b/src/add-ons/media/media-add-ons/writer/MediaWriter.h index 83d7d1bccb..ca4fb03043 100644 --- a/src/add-ons/media/media-add-ons/writer/MediaWriter.h +++ b/src/add-ons/media/media-add-ons/writer/MediaWriter.h @@ -23,11 +23,11 @@ #include #include +#include "../AbstractFileInterfaceNode.h" + class MediaWriter : - public BFileInterface, public BBufferConsumer, - public BControllable, - public BMediaEventLooper + public AbstractFileInterfaceNode { protected: virtual ~MediaWriter(void); @@ -41,43 +41,15 @@ explicit MediaWriter( 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( @@ -86,62 +58,18 @@ virtual status_t HandleMessage( 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 */ /***************************/ @@ -215,78 +143,13 @@ virtual status_t SeekTagRequested( /* end from BBufferConsumer */ /****************************/ -/****************************/ -/* begin from BControllable */ +/*****************/ +/* 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 */ -/******************************/ +/*********************/ +/* BMediaEventLooper */ +/*********************/ protected: @@ -294,24 +157,20 @@ virtual status_t HandleBuffer( const media_timed_event *event, bigtime_t lateness, bool realTimeEvent = false); - -virtual status_t HandleParameter( +virtual status_t HandleDataStatus( 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(); +static void GetFlavor(flavor_info * info, int32 id); +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); +virtual status_t WriteFileBuffer(BBuffer * buffer); private: @@ -320,25 +179,16 @@ private: MediaWriter & operator=( const MediaWriter & clone); - status_t initCheckStatus; - - BMediaAddOn * mediaWriterAddOn; media_input input; - BFile * outputFile; - entry_ref output_ref; - char output_mime_type[B_MIME_TYPE_LENGTH+1]; - - BBufferGroup * bufferGroup; - - bigtime_t downstreamLatency; - bigtime_t internalLatency; - - bool intputEnabled; + bool fInputEnabled; + BBufferGroup * fBufferGroup; + bigtime_t fDownstreamLatency; + bigtime_t fInternalLatency; // this is computed from the real (negotiated) chunk size and bit rate, // not the defaults that are in the parameters - bigtime_t bufferPeriod; + bigtime_t fBufferPeriod; /* Mmmh, stuffing! */ virtual status_t _Reserved_MediaWriter_0(void *); diff --git a/src/add-ons/media/media-add-ons/writer/MediaWriterAddOn.cpp b/src/add-ons/media/media-add-ons/writer/MediaWriterAddOn.cpp index 2ed3966317..d6b24b724a 100644 --- a/src/add-ons/media/media-add-ons/writer/MediaWriterAddOn.cpp +++ b/src/add-ons/media/media-add-ons/writer/MediaWriterAddOn.cpp @@ -36,29 +36,15 @@ MediaWriterAddOn::~MediaWriterAddOn() } MediaWriterAddOn::MediaWriterAddOn(image_id image) : - BMediaAddOn(image) + AbstractFileInterfaceAddOn(image) { fprintf(stderr,"MediaWriterAddOn::MediaWriterAddOn\n"); - refCount = 0; } - + // -------------------------------------------------------- // // BMediaAddOn impl // -------------------------------------------------------- // -status_t MediaWriterAddOn::InitCheck( - const char ** out_failure_text) -{ - fprintf(stderr,"MediaWriterAddOn::InitCheck\n"); - return B_OK; -} - -int32 MediaWriterAddOn::CountFlavors() -{ - fprintf(stderr,"MediaWriterAddOn::CountFlavors\n"); - return 1; -} - status_t MediaWriterAddOn::GetFlavorAt( int32 n, const flavor_info ** out_info) @@ -72,7 +58,10 @@ status_t MediaWriterAddOn::GetFlavorAt( fprintf(stderr,"<- B_BAD_INDEX\n"); return B_BAD_INDEX; } - return MediaWriter::GetFlavor(n,out_info); + flavor_info * infos = new flavor_info[1]; + MediaWriter::GetFlavor(&infos[0],n); + (*out_info) = infos; + return B_OK; } BMediaNode * MediaWriterAddOn::InstantiateNodeFor( @@ -87,9 +76,10 @@ BMediaNode * MediaWriterAddOn::InstantiateNodeFor( } size_t defaultChunkSize = size_t(8192); // XXX: read from add-on's attributes float defaultBitRate = 800000; - MediaWriter * node = new MediaWriter(defaultChunkSize, - defaultBitRate, - info,config,this); + MediaWriter * node + = new MediaWriter(defaultChunkSize, + defaultBitRate, + info,config,this); if (node == 0) { *out_error = B_NO_MEMORY; fprintf(stderr,"<- B_NO_MEMORY\n"); @@ -108,7 +98,8 @@ status_t MediaWriterAddOn::GetConfigurationFor( fprintf(stderr,"<- B_BAD_VALUE\n"); return B_BAD_VALUE; // we refuse to crash because you were stupid } - MediaWriter * node = dynamic_cast(your_node); + MediaWriter * node + = dynamic_cast(your_node); if (node == 0) { fprintf(stderr,"<- B_BAD_TYPE\n"); return B_BAD_TYPE; @@ -116,66 +107,18 @@ status_t MediaWriterAddOn::GetConfigurationFor( return node->GetConfigurationFor(into_message); } -bool MediaWriterAddOn::WantsAutoStart() -{ - fprintf(stderr,"MediaWriterAddOn::WantsAutoStart\n"); - return false; -} - -status_t MediaWriterAddOn::AutoStart( - int in_count, - BMediaNode ** out_node, - int32 * out_internal_id, - bool * out_has_more) -{ - fprintf(stderr,"MediaWriterAddOn::AutoStart\n"); - return B_OK; -} - // -------------------------------------------------------- // // BMediaAddOn impl for B_FILE_INTERFACE nodes // -------------------------------------------------------- // -status_t MediaWriterAddOn::SniffRef( - const entry_ref & file, - BMimeType * io_mime_type, - float * out_quality, - int32 * out_internal_id) -{ - fprintf(stderr,"MediaWriterAddOn::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 = MediaWriter::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 MediaWriterAddOn::SniffType( - const BMimeType & type, - float * out_quality, - int32 * out_internal_id) -{ - fprintf(stderr,"MediaWriterAddOn::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 +// about any junk, get the out_read_items or out_write_items and then use +// that to create an array of sufficient size to hold the result, and then +// call us again. So we won't punish them if they supply us with null +// pointers the first time around. +// +// A stupid program might 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... @@ -203,11 +146,10 @@ status_t MediaWriterAddOn::GetFileFormatList( 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] = MediaWriter::GetFileFormat(); + if (in_write_items > 0) { + out_writable_formats[0] = *MediaWriter::GetFileFormat(); } } return B_OK; @@ -220,21 +162,11 @@ status_t MediaWriterAddOn::SniffTypeKind( int32 * out_internal_id, void * _reserved) { - fprintf(stderr,"MediaWriterAddOn::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_CONSUMER | 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; - } + fprintf(stderr,"MediaReaderAddOn::SniffTypeKind\n"); + return AbstractFileInterfaceAddOn::SniffTypeKind(type,in_kinds, + B_BUFFER_CONSUMER, + out_quality,out_internal_id, + _reserved); } // -------------------------------------------------------- // diff --git a/src/add-ons/media/media-add-ons/writer/MediaWriterAddOn.h b/src/add-ons/media/media-add-ons/writer/MediaWriterAddOn.h index 1674506dd2..e5e61d7ff9 100644 --- a/src/add-ons/media/media-add-ons/writer/MediaWriterAddOn.h +++ b/src/add-ons/media/media-add-ons/writer/MediaWriterAddOn.h @@ -12,9 +12,10 @@ #include #include +#include "../AbstractFileInterfaceAddOn.h" class MediaWriterAddOn : - public BMediaAddOn + public AbstractFileInterfaceAddOn { public: virtual ~MediaWriterAddOn(void); @@ -23,9 +24,6 @@ public: /**************************/ /* 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); @@ -36,23 +34,8 @@ virtual BMediaNode * InstantiateNodeFor( 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 @@ -69,7 +52,6 @@ virtual status_t SniffTypeKind( // Like SniffType, but for the specific kind( int32 * out_internal_id, void * _reserved); - /* end from BMediaAddOn */ /************************/ @@ -80,8 +62,6 @@ private: MediaWriterAddOn & operator=( const MediaWriterAddOn & clone); - int32 refCount; - /* Mmmh, stuffing! */ virtual status_t _Reserved_MediaWriterAddOn_0(void *); virtual status_t _Reserved_MediaWriterAddOn_1(void *);