1 // MediaReader.cpp 2 // 3 // Andrew Bachmann, 2002 4 // 5 // A MediaReader is a node that 6 // implements FileInterface and BBufferProducer. 7 // It reads any file and produces one output, 8 // which is a multistream. 9 // 10 // see also MediaReaderAddOn.cpp 11 #include "../AbstractFileInterfaceNode.h" 12 #include "MediaReader.h" 13 #include "misc.h" 14 #include "debug.h" 15 16 #include <Buffer.h> 17 #include <BufferGroup.h> 18 #include <BufferProducer.h> 19 #include <Controllable.h> 20 #include <Entry.h> 21 #include <Errors.h> 22 #include <File.h> 23 #include <FileInterface.h> 24 #include <MediaAddOn.h> 25 #include <MediaDefs.h> 26 #include <MediaEventLooper.h> 27 #include <MediaNode.h> 28 #include <MediaRoster.h> 29 #include <ParameterWeb.h> 30 #include <TimeSource.h> 31 32 33 #include <limits.h> 34 #include <stdio.h> 35 #include <string.h> 36 37 38 MediaReader::~MediaReader(void) 39 { 40 fprintf(stderr,"MediaReader::~MediaReader\n"); 41 if (fBufferGroup != 0) { 42 BBufferGroup * group = fBufferGroup; 43 fBufferGroup = 0; 44 delete group; 45 } 46 } 47 48 49 MediaReader::MediaReader( 50 size_t defaultChunkSize, 51 float defaultBitRate, 52 const flavor_info * info, 53 BMessage * config, 54 BMediaAddOn * addOn) 55 : BMediaNode("MediaReader"), 56 BBufferProducer(B_MEDIA_MULTISTREAM), 57 AbstractFileInterfaceNode(defaultChunkSize, defaultBitRate, info, config, addOn) 58 { 59 CALLED(); 60 61 // null some fields 62 fBufferGroup = 0; 63 // start enabled 64 fOutputEnabled = true; 65 // don't overwrite available space, and be sure to terminate 66 strncpy(output.name,"MediaReader Output",B_MEDIA_NAME_LENGTH-1); 67 output.name[B_MEDIA_NAME_LENGTH-1] = '\0'; 68 // initialize the output 69 output.node = media_node::null; // until registration 70 output.source = media_source::null; // until registration 71 output.destination = media_destination::null; 72 GetFormat(&output.format); 73 } 74 75 76 // -------------------------------------------------------- // 77 // implementation of BMediaNode 78 // -------------------------------------------------------- // 79 void MediaReader::Preroll(void) 80 { 81 CALLED(); 82 // XXX:Performance opportunity 83 BMediaNode::Preroll(); 84 } 85 86 87 status_t MediaReader::HandleMessage( 88 int32 message, 89 const void * data, 90 size_t size) 91 { 92 CALLED(); 93 94 status_t status = B_OK; 95 96 switch (message) { 97 // no special messages for now 98 default: 99 status = BBufferProducer::HandleMessage(message,data,size); 100 if (status == B_OK) { 101 break; 102 } 103 status = AbstractFileInterfaceNode::HandleMessage(message,data,size); 104 break; 105 } 106 107 return status; 108 } 109 110 111 void MediaReader::NodeRegistered(void) 112 { 113 CALLED(); 114 115 // now we can do this 116 output.node = Node(); 117 output.source.id = 0; 118 output.source.port = output.node.port; // same as ControlPort(); 119 120 // creates the parameter web and starts the looper thread 121 AbstractFileInterfaceNode::NodeRegistered(); 122 } 123 124 125 // -------------------------------------------------------- // 126 // implementation of BFileInterface 127 // -------------------------------------------------------- // 128 status_t MediaReader::SetRef( 129 const entry_ref & file, 130 bool create, 131 bigtime_t * out_time) 132 { 133 CALLED(); 134 135 status_t status = AbstractFileInterfaceNode::SetRef(file,B_READ_ONLY,create,out_time); 136 if (status != B_OK) { 137 PRINT("AbstractFileInterfaceNode::SetRef returned an error\n"); 138 return status; 139 } 140 141 if (output.destination == media_destination::null) { 142 // reset the format, and set the requirements imposed by this file 143 GetFormat(&output.format); 144 AddRequirements(&output.format); 145 return B_OK; 146 } 147 148 // if we are connected we may have to re-negotiate the connection 149 media_format format; 150 GetFormat(&format); 151 AddRequirements(&format); 152 if (format_is_acceptible(format,output.format)) { 153 fprintf(stderr," compatible format = no re-negotiation necessary\n"); 154 return B_OK; 155 } 156 // first try the easy way : SORRY DEPRECATED into private :-( 157 // this code from MediaWriter would be different for MediaReader even if it worked... 158 // int32 change_tag = NewChangeTag(); 159 // status = this->BBufferConsumer::RequestFormatChange(output.source,output.destination,&format,&change_tag); 160 // if (status == B_OK) { 161 // fprintf(stderr," format change successful\n"); 162 // return B_OK; 163 // } 164 165 // okay, the hard way requires we get the MediaRoster 166 BMediaRoster * roster = BMediaRoster::Roster(&status); 167 if (roster == 0) 168 return B_MEDIA_SYSTEM_FAILURE; 169 170 if (status != B_OK) 171 return status; 172 173 // before disconnect one should always stop the nodes (bebook says) 174 // requires run_state cast since the return type on RunState() is 175 // wrong [int32] 176 run_state destinationRunState = run_state(RunState()); 177 if (destinationRunState == BMediaEventLooper::B_STARTED) 178 Stop(0,true); // stop us right now 179 180 // should also stop the destination if it is running, but how? 181 /* BMediaNode destinationNode = ?? 182 run_state destinationRunState = destinationNode->??; 183 status = destinationNode->StopNode(??,0,true); 184 if (status != B_OK) { 185 return status; 186 } */ 187 // we should disconnect right now 188 media_destination outputDestination = output.destination; 189 status = roster->Disconnect(output.source.id,output.source, 190 output.destination.id,output.destination); 191 if (status != B_OK) 192 return status; 193 194 // if that went okay, we'll try reconnecting 195 media_output connectOutput; 196 media_input connectInput; 197 status = roster->Connect(output.source,outputDestination, 198 &format,&connectOutput,&connectInput); 199 if (status != B_OK) 200 return status; 201 202 // now restart if necessary 203 if (destinationRunState == BMediaEventLooper::B_STARTED) { 204 Start(0); 205 } 206 return status; 207 } 208 209 210 // -------------------------------------------------------- // 211 // implemention of BBufferProducer 212 // -------------------------------------------------------- // 213 214 // They are asking us to make the first offering. 215 // So, we get a fresh format and then add requirements based 216 // on the current file. (if any) 217 status_t MediaReader::FormatSuggestionRequested( 218 media_type type, 219 int32 quality, 220 media_format * format) 221 { 222 CALLED(); 223 224 if ((type != B_MEDIA_MULTISTREAM) && (type != B_MEDIA_UNKNOWN_TYPE)) { 225 PRINT("\t<- B_MEDIA_BAD_FORMAT\n"); 226 return B_MEDIA_BAD_FORMAT; 227 } 228 229 GetFormat(format); 230 AddRequirements(format); 231 return B_OK; 232 } 233 234 235 // They made an offer to us. We should make sure that the offer is 236 // acceptable, and then we can add any requirements we have on top of 237 // that. We leave wildcards for anything that we don't care about. 238 status_t MediaReader::FormatProposal( 239 const media_source & output_source, 240 media_format * format) 241 { 242 CALLED(); 243 244 if (output.source != output_source) { 245 PRINT("\t<- B_MEDIA_BAD_SOURCE\n"); 246 return B_MEDIA_BAD_SOURCE; // we only have one output so that better be it 247 } 248 /* media_format * myFormat = GetFormat(); 249 fprintf(stderr,"proposed format: "); 250 print_media_format(format); 251 fprintf(stderr,"\n"); 252 fprintf(stderr,"my format: "); 253 print_media_format(myFormat); 254 fprintf(stderr,"\n"); */ 255 // Be's format_is_compatible doesn't work. 256 // if (!format_is_compatible(*format,*myFormat)) { 257 media_format myFormat; 258 GetFormat(&myFormat); 259 if (!format_is_acceptible(*format,myFormat)) { 260 PRINT("\t<- B_MEDIA_BAD_FORMAT\n"); 261 return B_MEDIA_BAD_FORMAT; 262 } 263 AddRequirements(format); 264 return B_OK; 265 } 266 267 268 // Presumably we have already agreed with them that this format is 269 // okay. But just in case, we check the offer. (and complain if it 270 // is invalid) Then as the last thing we do, we get rid of any 271 // remaining wilcards. 272 status_t MediaReader::FormatChangeRequested( 273 const media_source & source, 274 const media_destination & destination, 275 media_format * io_format, 276 int32 * _deprecated_) 277 { 278 CALLED(); 279 280 if (output.source != source) { 281 PRINT("\t<- B_MEDIA_BAD_SOURCE\n"); 282 return B_MEDIA_BAD_SOURCE; 283 } 284 status_t status = FormatProposal(source,io_format); 285 if (status != B_OK) { 286 PRINT("\terror returned by FormatProposal\n"); 287 GetFormat(io_format); 288 return status; 289 } 290 291 return ResolveWildcards(io_format); 292 } 293 294 295 status_t MediaReader::GetNextOutput( /* cookie starts as 0 */ 296 int32 * cookie, 297 media_output * out_output) 298 { 299 CALLED(); 300 301 if (*cookie != 0) { 302 PRINT("\t<- B_ERROR (no more outputs)\n"); 303 return B_ERROR; 304 } 305 306 // so next time they won't get the same output again 307 *cookie = 1; 308 *out_output = output; 309 return B_OK; 310 } 311 312 313 status_t MediaReader::DisposeOutputCookie( 314 int32 cookie) 315 { 316 CALLED(); 317 // nothing to do since our cookies are just integers 318 return B_OK; 319 } 320 321 322 status_t MediaReader::SetBufferGroup( 323 const media_source & for_source, 324 BBufferGroup * group) 325 { 326 CALLED(); 327 328 if (output.source != for_source) { 329 PRINT("\t<- B_MEDIA_BAD_SOURCE\n"); 330 return B_MEDIA_BAD_SOURCE; // we only have one output so that better be it 331 } 332 if (fBufferGroup != 0) { 333 if (fBufferGroup == group) 334 return B_OK; // time saver 335 delete fBufferGroup; 336 } 337 if (group != 0) { 338 fBufferGroup = group; 339 } else { 340 // let's take advantage of this opportunity to recalculate 341 // our downstream latency and ensure that it is up to date 342 media_node_id id; 343 FindLatencyFor(output.destination, &fDownstreamLatency, &id); 344 // buffer period gets initialized in Connect() because 345 // that is the first time we get the real values for 346 // chunk size and bit rate, which are used to compute buffer period 347 // note: you can still make a buffer group before connecting (why?) 348 // but we don't make it, you make it yourself and pass it here. 349 // not sure why anybody would want to do that since they need 350 // a connection anyway... 351 if (fBufferPeriod <= 0) { 352 fprintf(stderr,"<- B_NO_INIT"); 353 return B_NO_INIT; 354 } 355 int32 count = int32(fDownstreamLatency/fBufferPeriod)+2; 356 PRINT("\tdownstream latency = %lld, buffer period = %lld, buffer count = %ld\n", 357 fDownstreamLatency, fBufferPeriod, count); 358 359 // allocate the buffers 360 fBufferGroup = new BBufferGroup(output.format.u.multistream.max_chunk_size,count); 361 if (fBufferGroup == 0) { 362 PRINT("\t<- B_NO_MEMORY\n"); 363 return B_NO_MEMORY; 364 } 365 status_t status = fBufferGroup->InitCheck(); 366 if (status != B_OK) { 367 PRINT("\t<- fBufferGroup initialization failed\n"); 368 return status; 369 } 370 } 371 return B_OK; 372 } 373 374 375 /* Format of clipping is (as int16-s): <from line> <npairs> <startclip> <endclip>. */ 376 /* Repeat for each line where the clipping is different from the previous line. */ 377 /* If <npairs> is negative, use the data from line -<npairs> (there are 0 pairs after */ 378 /* a negative <npairs>. Yes, we only support 32k*32k frame buffers for clipping. */ 379 /* Any non-0 field of 'display' means that that field changed, and if you don't support */ 380 /* that change, you should return an error and ignore the request. Note that the buffer */ 381 /* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */ 382 /* be adhered to. */ 383 status_t MediaReader::VideoClippingChanged( 384 const media_source & for_source, 385 int16 num_shorts, 386 int16 * clip_data, 387 const media_video_display_info & display, 388 int32 * _deprecated_) 389 { 390 return BBufferProducer::VideoClippingChanged(for_source,num_shorts,clip_data,display,_deprecated_); 391 } 392 393 394 status_t MediaReader::GetLatency( 395 bigtime_t * out_latency) 396 { 397 CALLED(); 398 399 *out_latency = EventLatency() + SchedulingLatency(); 400 return B_OK; 401 } 402 403 404 status_t MediaReader::PrepareToConnect( 405 const media_source & what, 406 const media_destination & where, 407 media_format * format, 408 media_source * out_source, 409 char * out_name) 410 { 411 CALLED(); 412 413 if (output.source != what) { 414 PRINT("\t<- B_MEDIA_BAD_SOURCE\n"); 415 return B_MEDIA_BAD_SOURCE; 416 } 417 if (output.destination != media_destination::null) { 418 PRINT("\t<- B_MEDIA_ALREADY_CONNECTED\n"); 419 return B_MEDIA_ALREADY_CONNECTED; 420 } 421 422 status_t status = FormatChangeRequested(output.source,where,format,0); 423 if (status != B_OK) { 424 PRINT("\t<- MediaReader::FormatChangeRequested failed\n"); 425 return status; 426 } 427 428 // last check for wildcards and general validity 429 if (format->type != B_MEDIA_MULTISTREAM) { 430 PRINT("\t<- B_MEDIA_BAD_FORMAT\n"); 431 return B_MEDIA_BAD_FORMAT; 432 } 433 434 *out_source = output.source; 435 output.destination = where; 436 strncpy(out_name,output.name,B_MEDIA_NAME_LENGTH-1); 437 out_name[B_MEDIA_NAME_LENGTH] = '\0'; 438 return ResolveWildcards(format); 439 } 440 441 442 void MediaReader::Connect( 443 status_t error, 444 const media_source & source, 445 const media_destination & destination, 446 const media_format & format, 447 char * io_name) 448 { 449 CALLED(); 450 451 if (error != B_OK) { 452 PRINT("\t<- error already\n"); 453 output.destination = media_destination::null; 454 GetFormat(&output.format); 455 return; 456 } 457 if (output.source != source) { 458 PRINT("\t<- B_MEDIA_BAD_SOURCE\n"); 459 output.destination = media_destination::null; 460 GetFormat(&output.format); 461 return; 462 } 463 464 // record the agreed upon values 465 output.destination = destination; 466 output.format = format; 467 strncpy(io_name,output.name,B_MEDIA_NAME_LENGTH-1); 468 io_name[B_MEDIA_NAME_LENGTH-1] = '\0'; 469 470 // determine our downstream latency 471 media_node_id id; 472 FindLatencyFor(output.destination, &fDownstreamLatency, &id); 473 474 // compute the buffer period (must be done before setbuffergroup) 475 fBufferPeriod = bigtime_t(1000 * 8000000 / 1024 476 * output.format.u.multistream.max_chunk_size 477 / output.format.u.multistream.max_bit_rate); 478 479 PRINT("\tmax chunk size = %ld, max bit rate = %f, buffer period = %lld\n", 480 output.format.u.multistream.max_chunk_size, 481 output.format.u.multistream.max_bit_rate,fBufferPeriod); 482 483 // setup the buffers if they aren't setup yet 484 if (fBufferGroup == 0) { 485 status_t status = SetBufferGroup(output.source,0); 486 if (status != B_OK) { 487 PRINT("\t<- SetBufferGroup failed\n"); 488 output.destination = media_destination::null; 489 GetFormat(&output.format); 490 return; 491 } 492 } 493 494 SetBufferDuration(fBufferPeriod); 495 496 if (GetCurrentFile() != 0) { 497 bigtime_t start, end; 498 // buffer group buffer size 499 uint8 * data = new uint8[output.format.u.multistream.max_chunk_size]; 500 BBuffer * buffer = 0; 501 ssize_t bytesRead = 0; 502 { // timed section 503 start = TimeSource()->RealTime(); 504 // first we try to use a real BBuffer 505 buffer = fBufferGroup->RequestBuffer( 506 output.format.u.multistream.max_chunk_size,fBufferPeriod); 507 if (buffer != 0) { 508 FillFileBuffer(buffer); 509 } else { 510 // didn't get a real BBuffer, try simulation by just a read from the disk 511 bytesRead = GetCurrentFile()->Read( 512 data, output.format.u.multistream.max_chunk_size); 513 } 514 end = TimeSource()->RealTime(); 515 } 516 bytesRead = buffer->SizeUsed(); 517 delete[] data; 518 if (buffer != 0) { 519 buffer->Recycle(); 520 } 521 GetCurrentFile()->Seek(-bytesRead,SEEK_CUR); // put it back where we found it 522 523 fInternalLatency = end - start; 524 525 PRINT("\tinternal latency from disk read = %lld\n", fInternalLatency); 526 } else { 527 fInternalLatency = 100; // just guess 528 PRINT("\tinternal latency guessed = %lld\n", fInternalLatency); 529 } 530 531 SetEventLatency(fDownstreamLatency + fInternalLatency); 532 533 // XXX: do anything else? 534 } 535 536 537 void MediaReader::Disconnect( 538 const media_source & what, 539 const media_destination & where) 540 { 541 CALLED(); 542 543 if (output.destination != where) { 544 PRINT("\t<- B_MEDIA_BAD_DESTINATION\n"); 545 return; 546 } 547 if (output.source != what) { 548 PRINT("\t<- B_MEDIA_BAD_SOURCE\n"); 549 return; 550 } 551 552 output.destination = media_destination::null; 553 GetFormat(&output.format); 554 if (fBufferGroup != 0) { 555 BBufferGroup * group = fBufferGroup; 556 fBufferGroup = 0; 557 delete group; 558 } 559 } 560 561 562 void MediaReader::LateNoticeReceived( 563 const media_source & what, 564 bigtime_t how_much, 565 bigtime_t performance_time) 566 { 567 CALLED(); 568 569 if (what == output.source) { 570 switch (RunMode()) { 571 case B_OFFLINE: 572 // nothing to do 573 break; 574 case B_RECORDING: 575 // nothing to do 576 break; 577 case B_INCREASE_LATENCY: 578 fInternalLatency += how_much; 579 SetEventLatency(fDownstreamLatency + fInternalLatency); 580 break; 581 case B_DECREASE_PRECISION: 582 // XXX : shorten our buffer period 583 // We could opt to just not wait but we should 584 // probably gradually shorten the period so we 585 // don't starve others. Also, we need to make 586 // sure we are catching up! We may have some sort 587 // of time goal for how long it takes us to 588 // catch up, as well. 589 break; 590 case B_DROP_DATA: 591 // Okay you asked for it, we'll skip ahead in the file! 592 // We'll drop 1 buffer's worth 593 if (GetCurrentFile() == 0) { 594 PRINT("MediaReader::LateNoticeReceived called without" 595 "an GetCurrentFile() (!)\n"); 596 } else { 597 GetCurrentFile()->Seek(output.format.u.multistream.max_chunk_size,SEEK_CUR); 598 } 599 break; 600 default: 601 // huh?? there aren't any more run modes. 602 PRINT("MediaReader::LateNoticeReceived with unexpected run mode.\n"); 603 break; 604 } 605 } 606 } 607 608 609 void MediaReader::EnableOutput( 610 const media_source & what, 611 bool enabled, 612 int32 * _deprecated_) 613 { 614 CALLED(); 615 616 if (output.source != what) { 617 PRINT("\t<- B_MEDIA_BAD_SOURCE\n"); 618 return; 619 } 620 621 fOutputEnabled = enabled; 622 } 623 624 625 status_t MediaReader::SetPlayRate( 626 int32 numer, 627 int32 denom) 628 { 629 return BBufferProducer::SetPlayRate(numer,denom); // XXX: do something intelligent later 630 } 631 632 633 void MediaReader::AdditionalBufferRequested( // used to be Reserved 0 634 const media_source & source, 635 media_buffer_id prev_buffer, 636 bigtime_t prev_time, 637 const media_seek_tag * prev_tag) 638 { 639 CALLED(); 640 641 if (output.source == source) { 642 BBuffer * buffer; 643 status_t status = GetFilledBuffer(&buffer); 644 if (status != B_OK) { 645 PRINT("MediaReader::AdditionalBufferRequested got an error from GetFilledBuffer.\n"); 646 return; // don't send the buffer 647 } 648 SendBuffer(buffer,output.destination); 649 } 650 } 651 652 653 void MediaReader::LatencyChanged( 654 const media_source & source, 655 const media_destination & destination, 656 bigtime_t new_latency, 657 uint32 flags) 658 { 659 CALLED(); 660 if ((output.source == source) && (output.destination == destination)) { 661 fDownstreamLatency = new_latency; 662 SetEventLatency(fDownstreamLatency + fInternalLatency); 663 } 664 // we may have to recompute the number of buffers that we are using 665 // see SetBufferGroup 666 } 667 668 669 // -------------------------------------------------------- // 670 // implementation for BMediaEventLooper 671 // -------------------------------------------------------- // 672 // protected: 673 status_t MediaReader::HandleBuffer( 674 const media_timed_event *event, 675 bigtime_t lateness, 676 bool realTimeEvent) 677 { 678 CALLED(); 679 680 if (output.destination == media_destination::null) 681 return B_MEDIA_NOT_CONNECTED; 682 683 status_t status = B_OK; 684 BBuffer * buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod); 685 if (buffer != 0) { 686 status = FillFileBuffer(buffer); 687 if (status != B_OK) { 688 PRINT("MediaReader::HandleEvent got an error from FillFileBuffer.\n"); 689 buffer->Recycle(); 690 } else { 691 if (fOutputEnabled) { 692 status = SendBuffer(buffer,output.destination); 693 if (status != B_OK) { 694 PRINT("MediaReader::HandleEvent got an error from SendBuffer.\n"); 695 buffer->Recycle(); 696 } 697 } else { 698 buffer->Recycle(); 699 } 700 } 701 } 702 bigtime_t nextEventTime = event->event_time+fBufferPeriod; 703 media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER); 704 EventQueue()->AddEvent(nextBufferEvent); 705 return status; 706 } 707 708 709 status_t MediaReader::HandleDataStatus( 710 const media_timed_event *event, 711 bigtime_t lateness, 712 bool realTimeEvent) 713 { 714 CALLED(); 715 return SendDataStatus(event->data,output.destination,event->event_time); 716 } 717 718 719 // -------------------------------------------------------- // 720 // MediaReader specific functions 721 // -------------------------------------------------------- // 722 // static: 723 void MediaReader::GetFlavor(flavor_info * outInfo, int32 id) 724 { 725 CALLED(); 726 727 if (outInfo == 0) 728 return; 729 730 AbstractFileInterfaceNode::GetFlavor(outInfo,id); 731 outInfo->name = strdup("OpenBeOS Media Reader"); 732 outInfo->info = strdup("The OpenBeOS Media Reader reads a file and produces a multistream."); 733 outInfo->kinds |= B_BUFFER_PRODUCER; 734 outInfo->out_format_count = 1; // 1 output 735 media_format * formats = new media_format[outInfo->out_format_count]; 736 GetFormat(&formats[0]); 737 outInfo->out_formats = formats; 738 return; 739 } 740 741 742 void MediaReader::GetFormat(media_format * outFormat) 743 { 744 CALLED(); 745 746 AbstractFileInterfaceNode::GetFormat(outFormat); 747 return; 748 } 749 750 751 void MediaReader::GetFileFormat(media_file_format * outFileFormat) 752 { 753 CALLED(); 754 755 AbstractFileInterfaceNode::GetFileFormat(outFileFormat); 756 outFileFormat->capabilities |= media_file_format::B_READABLE; 757 return; 758 } 759 760 761 // protected: 762 status_t MediaReader::GetFilledBuffer( 763 BBuffer ** outBuffer) 764 { 765 CALLED(); 766 767 BBuffer * buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,-1); 768 if (buffer == 0) { 769 // XXX: add a new buffer and get it 770 PRINT("MediaReader::GetFilledBuffer needs a new buffer.\n"); 771 return B_ERROR; // don't send the buffer 772 } 773 774 status_t status = FillFileBuffer(buffer); 775 *outBuffer = buffer; 776 return status; 777 } 778 779 780 status_t MediaReader::FillFileBuffer( 781 BBuffer * buffer) 782 { 783 CALLED(); 784 785 if (GetCurrentFile() == 0) { 786 PRINT("\t<- B_NO_INIT\n"); 787 return B_NO_INIT; 788 } 789 PRINT("\t%ld buffer bytes used, %ld buffer bytes available\n", 790 buffer->SizeUsed(), buffer->SizeAvailable()); 791 off_t position = GetCurrentFile()->Position(); 792 ssize_t bytesRead = GetCurrentFile()->Read(buffer->Data(),buffer->SizeAvailable()); 793 if (bytesRead < 0) { 794 PRINT("\t<- B_FILE_ERROR\n"); 795 return B_FILE_ERROR; // some sort of file related error 796 } 797 PRINT("\t%ld file bytes read at position %ld.\n", 798 bytesRead, position); 799 800 buffer->SetSizeUsed(bytesRead); 801 media_header * header = buffer->Header(); 802 header->type = B_MEDIA_MULTISTREAM; 803 header->size_used = bytesRead; 804 header->file_pos = position; 805 header->orig_size = bytesRead; 806 header->time_source = TimeSource()->ID(); 807 header->start_time = TimeSource()->Now(); 808 // nothing more to say? 809 return B_OK; 810 } 811 812 813 // -------------------------------------------------------- // 814 // stuffing 815 // -------------------------------------------------------- // 816 status_t MediaReader::_Reserved_MediaReader_0(void *) { return B_ERROR; } 817 status_t MediaReader::_Reserved_MediaReader_1(void *) { return B_ERROR; } 818 status_t MediaReader::_Reserved_MediaReader_2(void *) { return B_ERROR; } 819 status_t MediaReader::_Reserved_MediaReader_3(void *) { return B_ERROR; } 820 status_t MediaReader::_Reserved_MediaReader_4(void *) { return B_ERROR; } 821 status_t MediaReader::_Reserved_MediaReader_5(void *) { return B_ERROR; } 822 status_t MediaReader::_Reserved_MediaReader_6(void *) { return B_ERROR; } 823 status_t MediaReader::_Reserved_MediaReader_7(void *) { return B_ERROR; } 824 status_t MediaReader::_Reserved_MediaReader_8(void *) { return B_ERROR; } 825 status_t MediaReader::_Reserved_MediaReader_9(void *) { return B_ERROR; } 826 status_t MediaReader::_Reserved_MediaReader_10(void *) { return B_ERROR; } 827 status_t MediaReader::_Reserved_MediaReader_11(void *) { return B_ERROR; } 828 status_t MediaReader::_Reserved_MediaReader_12(void *) { return B_ERROR; } 829 status_t MediaReader::_Reserved_MediaReader_13(void *) { return B_ERROR; } 830 status_t MediaReader::_Reserved_MediaReader_14(void *) { return B_ERROR; } 831 status_t MediaReader::_Reserved_MediaReader_15(void *) { return B_ERROR; } 832