1 // AbstractFileInterfaceNode.cpp 2 // 3 // Andrew Bachmann, 2002 4 // 5 // The AbstractFileInterfaceNode class implements 6 // the common functionality between MediaReader 7 // and MediaWriter. 8 9 #include <MediaDefs.h> 10 #include <MediaNode.h> 11 #include <MediaAddOn.h> 12 #include <FileInterface.h> 13 #include <Controllable.h> 14 #include <MediaEventLooper.h> 15 #include <File.h> 16 #include <Errors.h> 17 #include <Entry.h> 18 #include <BufferGroup.h> 19 #include <TimeSource.h> 20 #include <Buffer.h> 21 #include <ParameterWeb.h> 22 #include <limits.h> 23 24 #include "AbstractFileInterfaceNode.h" 25 26 #include <stdio.h> 27 #include <string.h> 28 29 // -------------------------------------------------------- // 30 // ctor/dtor 31 // -------------------------------------------------------- // 32 33 AbstractFileInterfaceNode::~AbstractFileInterfaceNode(void) 34 { 35 fprintf(stderr,"AbstractFileInterfaceNode::~AbstractFileInterfaceNode\n"); 36 // Stop the BMediaEventLooper thread 37 Quit(); 38 if (fCurrentFile != 0) { 39 delete fCurrentFile; 40 } 41 } 42 43 AbstractFileInterfaceNode::AbstractFileInterfaceNode( 44 size_t defaultChunkSize = 8192, 45 float defaultBitRate = 800000, 46 const flavor_info * info = 0, 47 BMessage * config = 0, 48 BMediaAddOn * addOn = 0) 49 : BMediaNode("AbstractFileInterfaceNode"), 50 BFileInterface(), 51 BControllable(), 52 BMediaEventLooper() 53 { 54 fprintf(stderr,"AbstractFileInterfaceNode::AbstractFileInterfaceNode\n"); 55 // keep our creator around for AddOn calls later 56 fAddOn = addOn; 57 // null some fields 58 fCurrentFile = 0; 59 f_current_mime_type[0] = '\0'; 60 // initialize the parameters 61 if (defaultChunkSize <= 0) { 62 fInitCheckStatus = B_BAD_VALUE; 63 return; 64 } 65 fDefaultChunkSizeParam = defaultChunkSize; 66 fDefaultChunkSizeParamChangeTime = 0; 67 if (defaultBitRate <= 0) { 68 fInitCheckStatus = B_BAD_VALUE; 69 return; 70 } 71 fDefaultBitRateParam = defaultBitRate; 72 fDefaultBitRateParamChangeTime = 0; 73 // initialize parameter compute fields 74 fLeastRecentlyUpdatedParameter = DEFAULT_BIT_RATE_PARAM; 75 fLastUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM; 76 // From the chunk size and bit rate we compute the buffer period. 77 int64 value = int64(8000000/1024*fDefaultChunkSizeParam/fDefaultBitRateParam); 78 if ((value <= 0) || (value > INT_MAX)) { 79 fInitCheckStatus = B_BAD_VALUE; 80 return; 81 } 82 fDefaultBufferPeriodParam = int32(value); 83 fDefaultBufferPeriodParamChangeTime = 0; 84 85 fInitCheckStatus = B_OK; 86 } 87 88 status_t AbstractFileInterfaceNode::InitCheck(void) const 89 { 90 fprintf(stderr,"AbstractFileInterfaceNode::InitCheck\n"); 91 return fInitCheckStatus; 92 } 93 94 status_t AbstractFileInterfaceNode::GetConfigurationFor( 95 BMessage * into_message) 96 { 97 fprintf(stderr,"AbstractFileInterfaceNode::GetConfigurationFor\n"); 98 return B_OK; 99 } 100 101 // -------------------------------------------------------- // 102 // implementation of BMediaNode 103 // -------------------------------------------------------- // 104 105 BMediaAddOn * AbstractFileInterfaceNode::AddOn( 106 int32 * internal_id) const 107 { 108 fprintf(stderr,"AbstractFileInterfaceNode::AddOn\n"); 109 // BeBook says this only gets called if we were in an add-on. 110 if (fAddOn != 0) { 111 // If we get a null pointer then we just won't write. 112 if (internal_id != 0) { 113 internal_id = 0; 114 } 115 } 116 return fAddOn; 117 } 118 119 void AbstractFileInterfaceNode::Start( 120 bigtime_t performance_time) 121 { 122 fprintf(stderr,"AbstractFileInterfaceNode::Start(pt=%i)\n",performance_time); 123 BMediaEventLooper::Start(performance_time); 124 } 125 126 void AbstractFileInterfaceNode::Stop( 127 bigtime_t performance_time, 128 bool immediate) 129 { 130 fprintf(stderr,"AbstractFileInterfaceNode::Stop(pt=%i,%s)\n",performance_time,(immediate?"now":"then")); 131 BMediaEventLooper::Stop(performance_time,immediate); 132 } 133 134 void AbstractFileInterfaceNode::Seek( 135 bigtime_t media_time, 136 bigtime_t performance_time) 137 { 138 fprintf(stderr,"AbstractFileInterfaceNode::Seek(mt=%i,pt=%i)\n",media_time,performance_time); 139 BMediaEventLooper::Seek(media_time,performance_time); 140 } 141 142 void AbstractFileInterfaceNode::SetRunMode( 143 run_mode mode) 144 { 145 fprintf(stderr,"AbstractFileInterfaceNode::SetRunMode(%i)\n",mode); 146 BMediaEventLooper::SetRunMode(mode); 147 } 148 149 void AbstractFileInterfaceNode::TimeWarp( 150 bigtime_t at_real_time, 151 bigtime_t to_performance_time) 152 { 153 fprintf(stderr,"AbstractFileInterfaceNode::TimeWarp(rt=%i,pt=%i)\n",at_real_time,to_performance_time); 154 BMediaEventLooper::TimeWarp(at_real_time,to_performance_time); 155 } 156 157 void AbstractFileInterfaceNode::Preroll(void) 158 { 159 fprintf(stderr,"AbstractFileInterfaceNode::Preroll\n"); 160 // XXX:Performance opportunity 161 BMediaNode::Preroll(); 162 } 163 164 void AbstractFileInterfaceNode::SetTimeSource( 165 BTimeSource * time_source) 166 { 167 fprintf(stderr,"AbstractFileInterfaceNode::SetTimeSource\n"); 168 BMediaNode::SetTimeSource(time_source); 169 } 170 171 status_t AbstractFileInterfaceNode::HandleMessage( 172 int32 message, 173 const void * data, 174 size_t size) 175 { 176 fprintf(stderr,"AbstractFileInterfaceNode::HandleMessage\n"); 177 status_t status = B_OK; 178 switch (message) { 179 // no special messages for now 180 default: 181 status = BFileInterface::HandleMessage(message,data,size); 182 if (status == B_OK) { 183 break; 184 } 185 status = BMediaNode::HandleMessage(message,data,size); 186 if (status == B_OK) { 187 break; 188 } 189 BMediaNode::HandleBadMessage(message,data,size); 190 status = B_ERROR; 191 break; 192 } 193 return status; 194 } 195 196 status_t AbstractFileInterfaceNode::RequestCompleted( 197 const media_request_info & info) 198 { 199 fprintf(stderr,"AbstractFileInterfaceNode::RequestCompleted\n"); 200 return BMediaNode::RequestCompleted(info); 201 } 202 203 status_t AbstractFileInterfaceNode::DeleteHook( 204 BMediaNode * node) 205 { 206 fprintf(stderr,"AbstractFileInterfaceNode::DeleteHook\n"); 207 return BMediaEventLooper::DeleteHook(node); 208 } 209 210 void AbstractFileInterfaceNode::NodeRegistered(void) 211 { 212 fprintf(stderr,"AbstractFileInterfaceNode::NodeRegistered\n"); 213 214 // set up our parameter web 215 SetParameterWeb(MakeParameterWeb()); 216 217 // start the BMediaEventLooper thread 218 SetPriority(B_REAL_TIME_PRIORITY); 219 Run(); 220 } 221 222 status_t AbstractFileInterfaceNode::GetNodeAttributes( 223 media_node_attribute * outAttributes, 224 size_t inMaxCount) 225 { 226 fprintf(stderr,"AbstractFileInterfaceNode::GetNodeAttributes\n"); 227 return BMediaNode::GetNodeAttributes(outAttributes,inMaxCount); 228 } 229 230 status_t AbstractFileInterfaceNode::AddTimer( 231 bigtime_t at_performance_time, 232 int32 cookie) 233 { 234 fprintf(stderr,"AbstractFileInterfaceNode::AddTimer\n"); 235 return BMediaEventLooper::AddTimer(at_performance_time,cookie); 236 } 237 238 // protected: 239 240 BParameterWeb * AbstractFileInterfaceNode::MakeParameterWeb(void) 241 { 242 fprintf(stderr,"AbstractFileInterfaceNode::MakeParameterWeb\n"); 243 244 BParameterWeb * web = new BParameterWeb(); 245 BParameterGroup * mainGroup = web->MakeGroup("AbstractFileInterfaceNode Parameters"); 246 247 // these three are related: 248 // DEFAULT_CHUNK_SIZE_PARAM = DEFAULT_BIT_RATE_PARAM / 1024 * DEFAULT_BUFFER_PERIOD_PARAM * 1000 249 BParameterGroup * chunkSizeGroup = mainGroup->MakeGroup("Chunk Size Group"); 250 BContinuousParameter * chunkSizeParameter 251 = chunkSizeGroup->MakeContinuousParameter( 252 DEFAULT_CHUNK_SIZE_PARAM, B_MEDIA_MULTISTREAM, 253 "Chunk Size", B_GAIN, "bytes", 1024, 32*1024, 512); 254 chunkSizeParameter->SetResponse(BContinuousParameter::B_LINEAR,1,0); 255 chunkSizeParameter->SetValue(&fDefaultChunkSizeParam,sizeof(fDefaultChunkSizeParam),0); 256 257 BParameterGroup * bitRateGroup = mainGroup->MakeGroup("Bit Rate Group"); 258 BContinuousParameter * bitRateParameter 259 = bitRateGroup->MakeContinuousParameter( 260 DEFAULT_BIT_RATE_PARAM, B_MEDIA_MULTISTREAM, 261 "Bit Rate", B_GAIN, "kbits/sec", 1, 320000, 1); 262 bitRateParameter->SetResponse(BContinuousParameter::B_LINEAR,.001,0); 263 bitRateParameter->SetValue(&fDefaultBitRateParam,sizeof(fDefaultBitRateParam),0); 264 265 BParameterGroup * bufferPeriodGroup = mainGroup->MakeGroup("Buffer Period Group"); 266 BContinuousParameter * bufferPeriodParameter 267 = bufferPeriodGroup->MakeContinuousParameter( 268 DEFAULT_BUFFER_PERIOD_PARAM, B_MEDIA_MULTISTREAM, 269 "Buffer Period", B_GAIN, "ms", 1, 10000, 1); 270 bufferPeriodParameter->SetResponse(BContinuousParameter::B_LINEAR,1,0); 271 bufferPeriodParameter->SetValue(&fDefaultBufferPeriodParam,sizeof(fDefaultBufferPeriodParam),0); 272 273 return web; 274 } 275 276 // -------------------------------------------------------- // 277 // implementation of BFileInterface 278 // -------------------------------------------------------- // 279 280 status_t AbstractFileInterfaceNode::GetNextFileFormat( 281 int32 * cookie, 282 media_file_format * out_format) 283 { 284 fprintf(stderr,"AbstractFileInterfaceNode::GetNextFileFormat\n"); 285 // let's not crash even if they are stupid 286 if (out_format == 0) { 287 // no place to write! 288 fprintf(stderr,"<- B_BAD_VALUE\n"); 289 return B_BAD_VALUE; 290 } 291 if (cookie != 0) { 292 // it's valid but they already got our 1 file format 293 if (*cookie != 0) { 294 fprintf(stderr,"<- B_ERROR\n"); 295 return B_ERROR; 296 } 297 // so next time they won't get the same format again 298 *cookie = 1; 299 } 300 *out_format = *GetFileFormat(); 301 return B_OK; 302 } 303 304 void AbstractFileInterfaceNode::DisposeFileFormatCookie( 305 int32 cookie) 306 { 307 fprintf(stderr,"AbstractFileInterfaceNode::DisposeFileFormatCookie\n"); 308 // nothing to do since our cookies are just integers 309 } 310 311 status_t AbstractFileInterfaceNode::GetDuration( 312 bigtime_t * out_time) 313 { 314 fprintf(stderr,"AbstractFileInterfaceNode::GetDuration\n"); 315 if (out_time == 0) { 316 fprintf(stderr,"<- B_BAD_VALUE\n"); 317 return B_BAD_VALUE; 318 } 319 if (fCurrentFile == 0) { 320 fprintf(stderr,"<- B_NO_INIT\n"); 321 return B_NO_INIT; 322 } 323 return fCurrentFile->GetSize(out_time); 324 } 325 326 status_t AbstractFileInterfaceNode::SniffRef( 327 const entry_ref & file, 328 char * out_mime_type, /* 256 bytes */ 329 float * out_quality) 330 { 331 fprintf(stderr,"AbstractFileInterfaceNode::SniffRef\n"); 332 return StaticSniffRef(file,out_mime_type,out_quality); 333 } 334 335 status_t AbstractFileInterfaceNode::SetRef( 336 const entry_ref & file, 337 uint32 openMode, 338 bool create, 339 bigtime_t * out_time) 340 { 341 fprintf(stderr,"AbstractFileInterfaceNode::SetRef\n"); 342 if (out_time == 0) { 343 fprintf(stderr,"<- B_BAD_VALUE\n"); 344 return B_BAD_VALUE; // no crashes today thanks 345 } 346 status_t status; 347 f_current_ref = file; 348 if (fCurrentFile == 0) { 349 fCurrentFile = new BFile(&f_current_ref,(openMode|(create?B_CREATE_FILE:0))); 350 status = fCurrentFile->InitCheck(); 351 } else { 352 status = fCurrentFile->SetTo(&f_current_ref,(openMode|(create?B_CREATE_FILE:0))); 353 } 354 if (status != B_OK) { 355 fprintf(stderr,"<- failed BFile initialization\n"); 356 return status; 357 } 358 // cache the mime type for later 359 fCurrentFile->ReadAttr("BEOS:TYPE",0,0,f_current_mime_type,B_MIME_TYPE_LENGTH); 360 // compute the duration and return any error 361 return GetDuration(out_time); 362 } 363 364 status_t AbstractFileInterfaceNode::GetRef( 365 entry_ref * out_ref, 366 char * out_mime_type) 367 { 368 fprintf(stderr,"AbstractFileInterfaceNode::GetRef\n"); 369 if ((out_ref == 0) || (out_mime_type == 0)) { 370 fprintf(stderr,"<- B_BAD_VALUE\n"); 371 return B_BAD_VALUE; // no crashes today thanks 372 } 373 if (fCurrentFile == 0) { 374 fprintf(stderr,"<- B_NO_INIT\n"); 375 return B_NO_INIT; // the input_ref isn't valid yet either 376 } 377 *out_ref = f_current_ref; 378 // they hopefully allocated enough space (no way to check :-/ ) 379 strcpy(out_mime_type,f_current_mime_type); 380 return B_OK; 381 } 382 383 // provided for BAbstractFileInterfaceNodeAddOn 384 385 status_t AbstractFileInterfaceNode::StaticSniffRef( 386 const entry_ref & file, 387 char * out_mime_type, /* 256 bytes */ 388 float * out_quality) 389 { 390 fprintf(stderr,"AbstractFileInterfaceNode::StaticSniffRef\n"); 391 if ((out_mime_type == 0) || (out_quality == 0)) { 392 fprintf(stderr,"<- B_BAD_VALUE\n"); 393 return B_BAD_VALUE; // we refuse to crash because you were stupid 394 } 395 BNode node(&file); 396 status_t initCheck = node.InitCheck(); 397 if (initCheck != B_OK) { 398 fprintf(stderr,"<- failed BNode::InitCheck()\n"); 399 return initCheck; 400 } 401 // they hopefully allocated enough room 402 node.ReadAttr("BEOS:TYPE",0,0,out_mime_type,B_MIME_TYPE_LENGTH); 403 *out_quality = 1.0; // we handle all files perfectly! we are so amazing! 404 return B_OK; 405 } 406 407 // -------------------------------------------------------- // 408 // implementation for BControllable 409 // -------------------------------------------------------- // 410 411 const int32 AbstractFileInterfaceNode::DEFAULT_CHUNK_SIZE_PARAM = 1; 412 const int32 AbstractFileInterfaceNode::DEFAULT_BIT_RATE_PARAM = 2; 413 const int32 AbstractFileInterfaceNode::DEFAULT_BUFFER_PERIOD_PARAM = 3; 414 415 status_t AbstractFileInterfaceNode::GetParameterValue( 416 int32 id, 417 bigtime_t * last_change, 418 void * value, 419 size_t * ioSize) 420 { 421 fprintf(stderr,"AbstractFileInterfaceNode::GetParameterValue\n"); 422 if ((last_change == 0) || (value == 0) || (ioSize == 0)) { 423 return B_BAD_VALUE; // no crashing 424 } 425 switch (id) { 426 case DEFAULT_CHUNK_SIZE_PARAM: 427 if (*ioSize < sizeof(size_t)) { 428 return B_ERROR; // not enough room 429 } 430 *last_change = fDefaultChunkSizeParamChangeTime; 431 *((size_t*)value) = fDefaultChunkSizeParam; 432 *ioSize = sizeof(size_t); 433 break; 434 435 case DEFAULT_BIT_RATE_PARAM: 436 if (*ioSize < sizeof(float)) { 437 return B_ERROR; // not enough room 438 } 439 *last_change = fDefaultBitRateParamChangeTime; 440 *((float*)value) = fDefaultBitRateParam; 441 *ioSize = sizeof(float); 442 break; 443 444 case DEFAULT_BUFFER_PERIOD_PARAM: 445 if (*ioSize < sizeof(int32)) { 446 return B_ERROR; // not enough room 447 } 448 *last_change = fDefaultBufferPeriodParamChangeTime; 449 *((int32*)value) = fDefaultBufferPeriodParam; 450 *ioSize = sizeof(int32); 451 break; 452 453 default: 454 fprintf(stderr,"AbstractFileInterfaceNode::GetParameterValue unknown id (%i)\n",id); 455 return B_ERROR; 456 } 457 return B_OK; 458 } 459 460 void AbstractFileInterfaceNode::SetParameterValue( 461 int32 id, 462 bigtime_t when, 463 const void * value, 464 size_t size) 465 { 466 fprintf(stderr,"AbstractFileInterfaceNode::SetParameterValue(id=%i,when=%ld,size=%i)\n",id,int32(when),int32(size)); 467 switch (id) { 468 case DEFAULT_CHUNK_SIZE_PARAM: 469 case DEFAULT_BIT_RATE_PARAM: 470 case DEFAULT_BUFFER_PERIOD_PARAM: 471 { 472 media_timed_event event(when, BTimedEventQueue::B_PARAMETER, 473 NULL, BTimedEventQueue::B_NO_CLEANUP, 474 size, id, (char*) value, size); 475 EventQueue()->AddEvent(event); 476 } 477 break; 478 479 default: 480 fprintf(stderr,"AbstractFileInterfaceNode::SetParameterValue unknown id (%i)\n",id); 481 break; 482 } 483 } 484 485 // the default implementation should call the add-on main() 486 status_t AbstractFileInterfaceNode::StartControlPanel( 487 BMessenger * out_messenger) 488 { 489 BControllable::StartControlPanel(out_messenger); 490 } 491 492 // -------------------------------------------------------- // 493 // implementation for BMediaEventLooper 494 // -------------------------------------------------------- // 495 496 void AbstractFileInterfaceNode::HandleEvent( 497 const media_timed_event *event, 498 bigtime_t lateness, 499 bool realTimeEvent = false) 500 { 501 fprintf(stderr,"AbstractFileInterfaceNode::HandleEvent\n"); 502 switch (event->type) { 503 case BTimedEventQueue::B_START: 504 HandleStart(event,lateness,realTimeEvent); 505 break; 506 case BTimedEventQueue::B_SEEK: 507 HandleSeek(event,lateness,realTimeEvent); 508 break; 509 case BTimedEventQueue::B_WARP: 510 HandleWarp(event,lateness,realTimeEvent); 511 break; 512 case BTimedEventQueue::B_STOP: 513 HandleStop(event,lateness,realTimeEvent); 514 break; 515 case BTimedEventQueue::B_HANDLE_BUFFER: 516 if (RunState() == BMediaEventLooper::B_STARTED) { 517 HandleBuffer(event,lateness,realTimeEvent); 518 } 519 break; 520 case BTimedEventQueue::B_DATA_STATUS: 521 HandleDataStatus(event,lateness,realTimeEvent); 522 break; 523 case BTimedEventQueue::B_PARAMETER: 524 HandleParameter(event,lateness,realTimeEvent); 525 break; 526 default: 527 fprintf(stderr," unknown event type: %i\n",event->type); 528 break; 529 } 530 } 531 532 /* override to clean up custom events you have added to your queue */ 533 void AbstractFileInterfaceNode::CleanUpEvent( 534 const media_timed_event *event) 535 { 536 BMediaEventLooper::CleanUpEvent(event); 537 } 538 539 /* called from Offline mode to determine the current time of the node */ 540 /* update your internal information whenever it changes */ 541 bigtime_t AbstractFileInterfaceNode::OfflineTime() 542 { 543 fprintf(stderr,"AbstractFileInterfaceNode::OfflineTime\n"); 544 return BMediaEventLooper::OfflineTime(); 545 // if (inputFile == 0) { 546 // return 0; 547 // } else { 548 // return inputFile->Position(); 549 // } 550 } 551 552 /* override only if you know what you are doing! */ 553 /* otherwise much badness could occur */ 554 /* the actual control loop function: */ 555 /* waits for messages, Pops events off the queue and calls DispatchEvent */ 556 void AbstractFileInterfaceNode::ControlLoop() { 557 BMediaEventLooper::ControlLoop(); 558 } 559 560 // protected: 561 562 status_t AbstractFileInterfaceNode::HandleStart( 563 const media_timed_event *event, 564 bigtime_t lateness, 565 bool realTimeEvent = false) 566 { 567 fprintf(stderr,"MediaReader::HandleStart()\n"); 568 if (RunState() != B_STARTED) { 569 HandleBuffer(event,lateness,realTimeEvent); 570 // media_timed_event firstBufferEvent(event->event_time, BTimedEventQueue::B_HANDLE_BUFFER); 571 // //this->HandleEvent(&firstBufferEvent, 0, false); 572 // EventQueue()->AddEvent(firstBufferEvent); 573 } 574 } 575 576 status_t AbstractFileInterfaceNode::HandleSeek( 577 const media_timed_event *event, 578 bigtime_t lateness, 579 bool realTimeEvent = false) 580 { 581 // XXX: argghh.. seek events seem broken when received from 582 // the usual BMediaEventLooper::Seek() dispatcher :-( 583 // They lost where we are supposed to seek to!?! 584 fprintf(stderr,"AbstractFileInterfaceNode::HandleSeek(t=%i,d=%i,bd=%ld)\n",event->event_time,event->data,event->bigdata); 585 if (fCurrentFile != 0) { 586 fCurrentFile->Seek(event->bigdata,SEEK_SET); 587 } 588 } 589 590 status_t AbstractFileInterfaceNode::HandleWarp( 591 const media_timed_event *event, 592 bigtime_t lateness, 593 bool realTimeEvent = false) 594 { 595 fprintf(stderr,"AbstractFileInterfaceNode::HandleWarp\n"); 596 } 597 598 status_t AbstractFileInterfaceNode::HandleStop( 599 const media_timed_event *event, 600 bigtime_t lateness, 601 bool realTimeEvent = false) 602 { 603 fprintf(stderr,"AbstractFileInterfaceNode::HandleStop\n"); 604 // flush the queue so downstreamers don't get any more 605 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); 606 } 607 608 status_t AbstractFileInterfaceNode::HandleParameter( 609 const media_timed_event *event, 610 bigtime_t lateness, 611 bool realTimeEvent = false) 612 { 613 fprintf(stderr,"AbstractFileInterfaceNode::HandleParameter"); 614 status_t status = B_OK; 615 616 bool chunkSizeUpdated = false, bitRateUpdated = false, bufferPeriodUpdated = false; 617 618 size_t dataSize = size_t(event->data); 619 int32 param = int32(event->bigdata); 620 621 switch (param) { 622 case DEFAULT_CHUNK_SIZE_PARAM: 623 fprintf(stderr,"(DEFAULT_CHUNK_SIZE_PARAM,size=%i",dataSize); 624 if (dataSize < sizeof(size_t)) { 625 fprintf(stderr,")\n"); 626 fprintf(stderr,"<- B_BAD_VALUE\n",param); 627 status = B_BAD_VALUE; 628 } else { 629 size_t newDefaultChunkSize = *((size_t*)event->user_data); 630 fprintf(stderr,",%i)\n",newDefaultChunkSize); 631 // ignore non positive chunk sizes 632 // XXX: we may decide later that a 0 chunk size means ship the whole file in one chunk (!) 633 if ((newDefaultChunkSize > 0) && (newDefaultChunkSize != fDefaultChunkSizeParam)) { 634 fprintf(stderr," got a new chunk size, old chunk size was %i\n",fDefaultChunkSizeParam); 635 fDefaultChunkSizeParam = newDefaultChunkSize; 636 fDefaultChunkSizeParamChangeTime = TimeSource()->Now(); 637 chunkSizeUpdated = true; 638 if (fLeastRecentlyUpdatedParameter == DEFAULT_CHUNK_SIZE_PARAM) { 639 // Okay we were the least recently updated parameter, 640 // but we just got an update so we are no longer that. 641 // Let's figure out who the new least recently updated 642 // parameter is. We are going to prefer to compute the 643 // bit rate since you usually don't want to muck with 644 // the buffer period. However, if you just set the bitrate 645 // then we are stuck with making the buffer period the new 646 // parameter to be computed. 647 if (fLastUpdatedParameter == DEFAULT_BIT_RATE_PARAM) { 648 fLeastRecentlyUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM; 649 } else { 650 fLeastRecentlyUpdatedParameter = DEFAULT_BIT_RATE_PARAM; 651 } 652 } 653 // we just got an update, so we are the new lastUpdatedParameter 654 fLastUpdatedParameter = DEFAULT_CHUNK_SIZE_PARAM; 655 // now we have to compute the new value for the leastRecentlyUpdatedParameter 656 // we use the chunk size change time to preserve "simultaneity" information 657 if (fLeastRecentlyUpdatedParameter == DEFAULT_BUFFER_PERIOD_PARAM) { 658 int64 value = int64(8000000/1024*fDefaultChunkSizeParam/fDefaultBitRateParam); 659 if (value > INT_MAX) { 660 // clamp to INT_MAX 661 fDefaultBufferPeriodParam = INT_MAX; 662 // recompute chunk size 663 fDefaultChunkSizeParam = size_t(1024/8000000*fDefaultBitRateParam*fDefaultBufferPeriodParam); 664 } else { 665 fDefaultBufferPeriodParam = MAX(1,value); 666 } 667 fDefaultBufferPeriodParamChangeTime = fDefaultChunkSizeParamChangeTime; 668 bufferPeriodUpdated = true; 669 } else { // must have been bit rate 670 fDefaultBitRateParam = MAX(0.001,8000000/1024*fDefaultChunkSizeParam/fDefaultBufferPeriodParam); 671 fDefaultBitRateParamChangeTime = fDefaultChunkSizeParamChangeTime; 672 bitRateUpdated = true; 673 } 674 } 675 } 676 break; 677 case DEFAULT_BIT_RATE_PARAM: 678 fprintf(stderr,"(DEFAULT_BIT_RATE_PARAM,size=%i",dataSize); 679 if (dataSize < sizeof(float)) { 680 fprintf(stderr,")\n"); 681 fprintf(stderr,"<- B_BAD_VALUE\n",param); 682 status = B_BAD_VALUE; 683 } else { 684 float newDefaultBitRate = *((float*)event->user_data); 685 fprintf(stderr,",%f)\n",newDefaultBitRate); 686 // ignore non positive bitrates 687 if ((newDefaultBitRate > 0) && (newDefaultBitRate != fDefaultBitRateParam)) { 688 fprintf(stderr," got a new bit rate, old bit rate was %i\n",fDefaultBitRateParam); 689 fDefaultBitRateParam = newDefaultBitRate; 690 fDefaultBitRateParamChangeTime = TimeSource()->Now(); 691 bitRateUpdated = true; 692 if (fLeastRecentlyUpdatedParameter == DEFAULT_BIT_RATE_PARAM) { 693 // Okay we were the least recently updated parameter, 694 // but we just got an update so we are no longer that. 695 // Let's figure out who the new least recently updated 696 // parameter is. We are going to prefer to compute the 697 // chunk size since you usually don't want to muck with 698 // the buffer period. However, if you just set the chunk size 699 // then we are stuck with making the buffer period the new 700 // parameter to be computed. 701 if (fLastUpdatedParameter == DEFAULT_CHUNK_SIZE_PARAM) { 702 fLeastRecentlyUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM; 703 } else { 704 fLeastRecentlyUpdatedParameter = DEFAULT_CHUNK_SIZE_PARAM; 705 } 706 } 707 // we just got an update, so we are the new lastUpdatedParameter 708 fLastUpdatedParameter = DEFAULT_BIT_RATE_PARAM; 709 // now we have to compute the new value for the leastRecentlyUpdatedParameter 710 // we use the bit rate change time to preserve "simultaneity" information 711 if (fLeastRecentlyUpdatedParameter == DEFAULT_BUFFER_PERIOD_PARAM) { 712 int64 value = int64(8000000/1024*fDefaultChunkSizeParam/fDefaultBitRateParam); 713 if (value > INT_MAX) { 714 // clamp to INT_MAX 715 fDefaultBufferPeriodParam = INT_MAX; 716 // recompute bit rate 717 fDefaultBitRateParam = MAX(0.001,8000000/1024*fDefaultChunkSizeParam/fDefaultBufferPeriodParam); 718 } else { 719 fDefaultBufferPeriodParam = MAX(1,int32(value)); 720 } 721 fDefaultBufferPeriodParamChangeTime = fDefaultBitRateParamChangeTime; 722 bufferPeriodUpdated = true; 723 } else { // must have been chunk size 724 int64 value = int64(1024/8000000*fDefaultBitRateParam*fDefaultBufferPeriodParam); 725 if (value > INT_MAX) { 726 // clamp to INT_MAX 727 fDefaultChunkSizeParam = INT_MAX; 728 // recompute bit rate 729 fDefaultBitRateParam = MAX(0.001,8000000/1024*fDefaultChunkSizeParam/fDefaultBufferPeriodParam); 730 } else { 731 fDefaultChunkSizeParam = MAX(1,int32(value)); 732 } 733 fDefaultChunkSizeParamChangeTime = fDefaultBitRateParamChangeTime; 734 chunkSizeUpdated = true; 735 } 736 } 737 } 738 break; 739 case DEFAULT_BUFFER_PERIOD_PARAM: 740 fprintf(stderr,"(DEFAULT_BUFFER_PERIOD_PARAM,size=%i",dataSize); 741 if (dataSize < sizeof(int32)) { 742 fprintf(stderr,")\n"); 743 fprintf(stderr,"<- B_BAD_VALUE\n",param); 744 status = B_BAD_VALUE; 745 } else { 746 int32 newBufferPeriod = *((int32*)event->user_data); 747 fprintf(stderr,",%i)\n",newBufferPeriod); 748 // ignore non positive buffer period 749 if ((newBufferPeriod > 0) && (newBufferPeriod != fDefaultBufferPeriodParam)) { 750 fprintf(stderr," got a new buffer period, old buffer period was %i\n",fDefaultBufferPeriodParam); 751 fDefaultBufferPeriodParam = newBufferPeriod; 752 fDefaultBufferPeriodParamChangeTime = TimeSource()->Now(); 753 bufferPeriodUpdated = true; 754 if (fLastUpdatedParameter == DEFAULT_BUFFER_PERIOD_PARAM) { 755 // prefer to update bit rate, unless you just set it 756 if (fLastUpdatedParameter == DEFAULT_BIT_RATE_PARAM) { 757 fLeastRecentlyUpdatedParameter = DEFAULT_CHUNK_SIZE_PARAM; 758 } else { 759 fLeastRecentlyUpdatedParameter = DEFAULT_BIT_RATE_PARAM; 760 } 761 } 762 // we just got an update, so we are the new lastUpdatedParameter 763 fLastUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM; 764 // now we have to compute the new value for the leastRecentlyUpdatedParameter 765 // we use the buffer period change time to preserve "simultaneity" information 766 if (fLeastRecentlyUpdatedParameter == DEFAULT_BIT_RATE_PARAM) { 767 fDefaultBitRateParam = MAX(0.001,8000000/1024*fDefaultChunkSizeParam/fDefaultBufferPeriodParam); 768 fDefaultBitRateParamChangeTime = fDefaultBufferPeriodParamChangeTime; 769 bitRateUpdated = true; 770 } else { // must have been chunk size 771 int64 value = int64(1024/8000000*fDefaultBitRateParam*fDefaultBufferPeriodParam); 772 if (value > INT_MAX) { 773 // clamp to INT_MAX 774 fDefaultChunkSizeParam = INT_MAX; 775 // recompute buffer period 776 fDefaultBufferPeriodParam = size_t(8000000/1024*fDefaultChunkSizeParam/fDefaultBitRateParam); 777 } else { 778 fDefaultChunkSizeParam = MAX(1,int32(value)); 779 } 780 fDefaultChunkSizeParamChangeTime = fDefaultBufferPeriodParamChangeTime; 781 chunkSizeUpdated = true; 782 } 783 } 784 } 785 break; 786 default: 787 fprintf(stderr,"AbstractFileInterfaceNode::HandleParameter called with unknown param id (%i)\n",param); 788 status = B_ERROR; 789 } 790 // send updates out for all the parameters that changed 791 // in every case this should be two updates. (if I have not made an error :-) ) 792 if (chunkSizeUpdated) { 793 fprintf(stderr," chunk size parameter updated\n"); 794 BroadcastNewParameterValue(fDefaultChunkSizeParamChangeTime, 795 DEFAULT_CHUNK_SIZE_PARAM, 796 &fDefaultChunkSizeParam, 797 sizeof(fDefaultChunkSizeParam)); 798 } 799 if (bitRateUpdated) { 800 fprintf(stderr," bit rate parameter updated\n"); 801 BroadcastNewParameterValue(fDefaultBitRateParamChangeTime, 802 DEFAULT_BIT_RATE_PARAM, 803 &fDefaultBitRateParam, 804 sizeof(fDefaultBitRateParam)); 805 } 806 if (bufferPeriodUpdated) { 807 fprintf(stderr," buffer period parameter updated\n"); 808 BroadcastNewParameterValue(fDefaultBufferPeriodParamChangeTime, 809 DEFAULT_BUFFER_PERIOD_PARAM, 810 &fDefaultBufferPeriodParam, 811 sizeof(fDefaultBufferPeriodParam)); 812 } 813 return status; 814 } 815 816 // -------------------------------------------------------- // 817 // AbstractFileInterfaceNode specific functions 818 // -------------------------------------------------------- // 819 820 // public: 821 822 flavor_info * AbstractFileInterfaceNode::GetFlavor(int32 id) 823 { 824 fprintf(stderr,"AbstractFileInterfaceNode::GetFlavor\n"); 825 static bool initialized = false; 826 static flavor_info info; 827 if (initialized == false) { 828 info.name = "AbstractFileInterfaceNode"; 829 info.info = "A AbstractFileInterfaceNode node handles a file."; 830 info.kinds = B_FILE_INTERFACE | B_CONTROLLABLE; 831 info.flavor_flags = B_FLAVOR_IS_LOCAL; 832 info.possible_count = INT_MAX; 833 info.in_format_count = 0; // no inputs 834 info.in_formats = 0; 835 info.out_format_count = 0; // no outputs 836 info.out_formats = 0; 837 info.internal_id = id; 838 initialized = true; 839 } 840 return &info; 841 } 842 843 media_format * AbstractFileInterfaceNode::GetFormat() 844 { 845 fprintf(stderr,"AbstractFileInterfaceNode::GetFormat\n"); 846 static bool initialized = false; 847 static media_format format; 848 if (initialized == false) { 849 format.type = B_MEDIA_MULTISTREAM; 850 format.require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 851 format.deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 852 format.u.multistream = media_multistream_format::wildcard; 853 initialized = true; 854 } 855 return &format; 856 } 857 858 media_file_format * AbstractFileInterfaceNode::GetFileFormat() 859 { 860 fprintf(stderr,"AbstractFileInterfaceNode::GetFileFormat\n"); 861 static bool initialized = false; 862 static media_file_format file_format; 863 if (initialized == false) { 864 file_format.capabilities = 865 media_file_format::B_PERFECTLY_SEEKABLE 866 | media_file_format::B_IMPERFECTLY_SEEKABLE 867 | media_file_format::B_KNOWS_ANYTHING; 868 /* I don't know what to initialize this to. (or if I should) */ 869 // format.id = 870 file_format.family = B_ANY_FORMAT_FAMILY; 871 file_format.version = 100; 872 strcpy(file_format.mime_type,""); 873 strcpy(file_format.pretty_name,"any media file format"); 874 strcpy(file_format.short_name,"any"); 875 strcpy(file_format.file_extension,""); 876 initialized = true; 877 } 878 return &file_format; 879 } 880 881 // protected: 882 883 // Here we make some guesses based on the file's mime type. 884 // We don't have enough information to add any other requirements. 885 // This function doesn't complain if you have already decided you want 886 // the stream to be considered a different one. (so you can say that you 887 // want to read that mpeg file as avi if you are so nutty.) 888 // 889 status_t AbstractFileInterfaceNode::AddRequirements(media_format * format) 890 { 891 if (strcmp("video/x-msvideo",f_current_mime_type) == 0) { 892 if (format->u.multistream.format == media_multistream_format::wildcard.format) { 893 format->u.multistream.format = media_multistream_format::B_AVI; 894 } 895 } else 896 if (strcmp("video/mpeg",f_current_mime_type) == 0) { 897 if (format->u.multistream.format == media_multistream_format::wildcard.format) { 898 format->u.multistream.format = media_multistream_format::B_MPEG1; 899 } 900 } else 901 if (strcmp("video/quicktime",f_current_mime_type) == 0) { 902 if (format->u.multistream.format == media_multistream_format::wildcard.format) { 903 format->u.multistream.format = media_multistream_format::B_QUICKTIME; 904 } 905 } else 906 if (strcmp("audio/x-mpeg",f_current_mime_type) == 0) { 907 if (format->u.multistream.format == media_multistream_format::wildcard.format) { 908 format->u.multistream.format = media_multistream_format::B_MPEG1; 909 } 910 } 911 return B_OK; 912 } 913 914 // We need some sort of bit rate and chunk size, so if the other guy 915 // didn't care, we'll use our own defaults. 916 status_t AbstractFileInterfaceNode::ResolveWildcards(media_format * format) 917 { 918 fprintf(stderr,"AbstractFileInterfaceNode::ResolveWildcards\n"); 919 // There isn't an unknown format. hmph. 920 // if (format->u.multistream.format == media_multistream_format::wildcard.format) { 921 // format->u.multistream.format = media_multistream_format::B_UNKNOWN; 922 // } 923 if (format->u.multistream.max_bit_rate == media_multistream_format::wildcard.max_bit_rate) { 924 format->u.multistream.max_bit_rate = fDefaultBitRateParam; 925 } 926 if (format->u.multistream.max_chunk_size == media_multistream_format::wildcard.max_chunk_size) { 927 format->u.multistream.max_chunk_size = fDefaultChunkSizeParam; 928 } 929 if (format->u.multistream.avg_bit_rate == media_multistream_format::wildcard.avg_bit_rate) { 930 format->u.multistream.avg_bit_rate = fDefaultBitRateParam; 931 } 932 if (format->u.multistream.avg_chunk_size == media_multistream_format::wildcard.avg_chunk_size) { 933 format->u.multistream.avg_chunk_size = fDefaultChunkSizeParam; 934 } 935 return B_OK; 936 } 937 938 // -------------------------------------------------------- // 939 // stuffing 940 // -------------------------------------------------------- // 941 942 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_0(void *) {} 943 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_1(void *) {} 944 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_2(void *) {} 945 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_3(void *) {} 946 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_4(void *) {} 947 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_5(void *) {} 948 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_6(void *) {} 949 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_7(void *) {} 950 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_8(void *) {} 951 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_9(void *) {} 952 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_10(void *) {} 953 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_11(void *) {} 954 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_12(void *) {} 955 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_13(void *) {} 956 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_14(void *) {} 957 status_t AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_15(void *) {} 958