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