1 // MediaDemultiplexerNode.cpp 2 // 3 // Andrew Bachmann, 2002 4 // 5 // The MediaDemultiplexerNode class 6 // takes a multistream input and supplies 7 // the individual constituent streams as 8 // the output. 9 10 #include <MediaDefs.h> 11 #include <MediaNode.h> 12 #include <MediaAddOn.h> 13 #include <BufferConsumer.h> 14 #include <BufferProducer.h> 15 #include <MediaEventLooper.h> 16 #include <Errors.h> 17 #include <BufferGroup.h> 18 #include <TimeSource.h> 19 #include <Buffer.h> 20 #include <limits.h> 21 22 #include "MediaDemultiplexerNode.h" 23 #include "misc.h" 24 25 #include <stdio.h> 26 #include <string.h> 27 28 // -------------------------------------------------------- // 29 // ctor/dtor 30 // -------------------------------------------------------- // 31 32 MediaDemultiplexerNode::~MediaDemultiplexerNode(void) 33 { 34 fprintf(stderr,"MediaDemultiplexerNode::~MediaDemultiplexerNode\n"); 35 // Stop the BMediaEventLooper thread 36 Quit(); 37 } 38 39 MediaDemultiplexerNode::MediaDemultiplexerNode( 40 const flavor_info * info = 0, 41 BMessage * config = 0, 42 BMediaAddOn * addOn = 0) 43 : BMediaNode("MediaDemultiplexerNode"), 44 BMediaEventLooper(), 45 BBufferConsumer(B_MEDIA_MULTISTREAM), 46 BBufferProducer(B_MEDIA_UNKNOWN_TYPE) // no B_MEDIA_ANY 47 { 48 fprintf(stderr,"MediaDemultiplexerNode::MediaDemultiplexerNode\n"); 49 // keep our creator around for AddOn calls later 50 fAddOn = addOn; 51 // null out our latency estimates 52 fDownstreamLatency = 0; 53 fInternalLatency = 0; 54 // don't overwrite available space, and be sure to terminate 55 strncpy(input.name,"Demultiplexer Input",B_MEDIA_NAME_LENGTH-1); 56 input.name[B_MEDIA_NAME_LENGTH-1] = '\0'; 57 // initialize the input 58 input.node = media_node::null; // until registration 59 input.source = media_source::null; 60 input.destination = media_destination::null; // until registration 61 GetInputFormat(&input.format); 62 63 outputs.empty(); 64 // outputs initialized after we connect, 65 // find a suitable extractor, 66 // and it tells us the ouputs 67 68 fInitCheckStatus = B_OK; 69 } 70 71 status_t MediaDemultiplexerNode::InitCheck(void) const 72 { 73 fprintf(stderr,"MediaDemultiplexerNode::InitCheck\n"); 74 return fInitCheckStatus; 75 } 76 77 status_t MediaDemultiplexerNode::GetConfigurationFor( 78 BMessage * into_message) 79 { 80 fprintf(stderr,"MediaDemultiplexerNode::GetConfigurationFor\n"); 81 return B_OK; 82 } 83 84 // -------------------------------------------------------- // 85 // implementation of BMediaNode 86 // -------------------------------------------------------- // 87 88 BMediaAddOn * MediaDemultiplexerNode::AddOn( 89 int32 * internal_id) const 90 { 91 fprintf(stderr,"MediaDemultiplexerNode::AddOn\n"); 92 // BeBook says this only gets called if we were in an add-on. 93 if (fAddOn != 0) { 94 // If we get a null pointer then we just won't write. 95 if (internal_id != 0) { 96 internal_id = 0; 97 } 98 } 99 return fAddOn; 100 } 101 102 void MediaDemultiplexerNode::Start( 103 bigtime_t performance_time) 104 { 105 fprintf(stderr,"MediaDemultiplexerNode::Start(pt=%lld)\n",performance_time); 106 BMediaEventLooper::Start(performance_time); 107 } 108 109 void MediaDemultiplexerNode::Stop( 110 bigtime_t performance_time, 111 bool immediate) 112 { 113 if (immediate) { 114 fprintf(stderr,"MediaDemultiplexerNode::Stop(pt=%lld,<immediate>)\n",performance_time); 115 } else { 116 fprintf(stderr,"MediaDemultiplexerNode::Stop(pt=%lld,<scheduled>)\n",performance_time); 117 } 118 BMediaEventLooper::Stop(performance_time,immediate); 119 } 120 121 void MediaDemultiplexerNode::Seek( 122 bigtime_t media_time, 123 bigtime_t performance_time) 124 { 125 fprintf(stderr,"MediaDemultiplexerNode::Seek(mt=%lld,pt=%lld)\n",media_time,performance_time); 126 BMediaEventLooper::Seek(media_time,performance_time); 127 } 128 129 void MediaDemultiplexerNode::SetRunMode( 130 run_mode mode) 131 { 132 fprintf(stderr,"MediaDemultiplexerNode::SetRunMode(%i)\n",mode); 133 BMediaEventLooper::SetRunMode(mode); 134 } 135 136 void MediaDemultiplexerNode::TimeWarp( 137 bigtime_t at_real_time, 138 bigtime_t to_performance_time) 139 { 140 fprintf(stderr,"MediaDemultiplexerNode::TimeWarp(rt=%lld,pt=%lld)\n",at_real_time,to_performance_time); 141 BMediaEventLooper::TimeWarp(at_real_time,to_performance_time); 142 } 143 144 void MediaDemultiplexerNode::Preroll(void) 145 { 146 fprintf(stderr,"MediaDemultiplexerNode::Preroll\n"); 147 // XXX:Performance opportunity 148 BMediaNode::Preroll(); 149 } 150 151 void MediaDemultiplexerNode::SetTimeSource( 152 BTimeSource * time_source) 153 { 154 fprintf(stderr,"MediaDemultiplexerNode::SetTimeSource\n"); 155 BMediaNode::SetTimeSource(time_source); 156 } 157 158 status_t MediaDemultiplexerNode::HandleMessage( 159 int32 message, 160 const void * data, 161 size_t size) 162 { 163 fprintf(stderr,"MediaDemultiplexerNode::HandleMessage\n"); 164 status_t status = B_OK; 165 switch (message) { 166 // no special messages for now 167 default: 168 status = BBufferConsumer::HandleMessage(message,data,size); 169 if (status == B_OK) { 170 break; 171 } 172 status = BBufferProducer::HandleMessage(message,data,size); 173 if (status == B_OK) { 174 break; 175 } 176 status = BMediaNode::HandleMessage(message,data,size); 177 if (status == B_OK) { 178 break; 179 } 180 BMediaNode::HandleBadMessage(message,data,size); 181 status = B_ERROR; 182 break; 183 } 184 return status; 185 } 186 187 status_t MediaDemultiplexerNode::RequestCompleted( 188 const media_request_info & info) 189 { 190 fprintf(stderr,"MediaDemultiplexerNode::RequestCompleted\n"); 191 return BMediaNode::RequestCompleted(info); 192 } 193 194 status_t MediaDemultiplexerNode::DeleteHook( 195 BMediaNode * node) 196 { 197 fprintf(stderr,"MediaDemultiplexerNode::DeleteHook\n"); 198 return BMediaEventLooper::DeleteHook(node); 199 } 200 201 void MediaDemultiplexerNode::NodeRegistered(void) 202 { 203 fprintf(stderr,"MediaDemultiplexerNode::NodeRegistered\n"); 204 205 // now we can do this 206 input.node = Node(); 207 input.destination.id = 0; 208 input.destination.port = input.node.port; // same as ControlPort() 209 210 // outputs initialized after we connect, 211 // find a suitable extractor, 212 // and it tells us the ouputs 213 214 // start the BMediaEventLooper thread 215 SetPriority(B_REAL_TIME_PRIORITY); 216 Run(); 217 } 218 219 status_t MediaDemultiplexerNode::GetNodeAttributes( 220 media_node_attribute * outAttributes, 221 size_t inMaxCount) 222 { 223 fprintf(stderr,"MediaDemultiplexerNode::GetNodeAttributes\n"); 224 return BMediaNode::GetNodeAttributes(outAttributes,inMaxCount); 225 } 226 227 status_t MediaDemultiplexerNode::AddTimer( 228 bigtime_t at_performance_time, 229 int32 cookie) 230 { 231 fprintf(stderr,"MediaDemultiplexerNode::AddTimer\n"); 232 return BMediaEventLooper::AddTimer(at_performance_time,cookie); 233 } 234 235 // -------------------------------------------------------- // 236 // implemention of BBufferConsumer 237 // -------------------------------------------------------- // 238 239 // Check to make sure the format is okay, then remove 240 // any wildcards corresponding to our requirements. 241 status_t MediaDemultiplexerNode::AcceptFormat( 242 const media_destination & dest, 243 media_format * format) 244 { 245 fprintf(stderr,"MediaDemultiplexerNode::AcceptFormat\n"); 246 if (input.destination != dest) { 247 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION"); 248 return B_MEDIA_BAD_DESTINATION; // we only have one input so that better be it 249 } 250 media_format myFormat; 251 GetInputFormat(&myFormat); 252 // Be's format_is_compatible doesn't work, 253 // so use our format_is_acceptible instead 254 if (!format_is_acceptible(*format,myFormat)) { 255 fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); 256 return B_MEDIA_BAD_FORMAT; 257 } 258 AddRequirements(format); 259 return B_OK; 260 } 261 262 status_t MediaDemultiplexerNode::GetNextInput( 263 int32 * cookie, 264 media_input * out_input) 265 { 266 fprintf(stderr,"MediaDemultiplexerNode::GetNextInput\n"); 267 if (*cookie != 0) { 268 fprintf(stderr,"<- B_ERROR (no more inputs)\n"); 269 return B_ERROR; 270 } 271 272 // so next time they won't get the same input again 273 *cookie = 1; 274 *out_input = input; 275 return B_OK; 276 } 277 278 void MediaDemultiplexerNode::DisposeInputCookie( 279 int32 cookie) 280 { 281 fprintf(stderr,"MediaDemultiplexerNode::DisposeInputCookie\n"); 282 // nothing to do since our cookies are just integers 283 return; // B_OK; 284 } 285 286 void MediaDemultiplexerNode::BufferReceived( 287 BBuffer * buffer) 288 { 289 fprintf(stderr,"MediaDemultiplexerNode::BufferReceived\n"); 290 switch (buffer->Header()->type) { 291 // case B_MEDIA_PARAMETERS: 292 // { 293 // status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed()); 294 // if (status != B_OK) { 295 // fprintf(stderr,"ApplyParameterData in MediaDemultiplexerNode::BufferReceived failed\n"); 296 // } 297 // buffer->Recycle(); 298 // } 299 // break; 300 case B_MEDIA_MULTISTREAM: 301 if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) { 302 fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in MediaDemultiplexerNode::BufferReceived\n"); 303 // XXX: implement this part 304 buffer->Recycle(); 305 } else { 306 media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER, 307 buffer, BTimedEventQueue::B_RECYCLE_BUFFER); 308 status_t status = EventQueue()->AddEvent(event); 309 if (status != B_OK) { 310 fprintf(stderr,"EventQueue()->AddEvent(event) in MediaDemultiplexerNode::BufferReceived failed\n"); 311 buffer->Recycle(); 312 } 313 } 314 break; 315 default: 316 fprintf(stderr,"unexpected buffer type in MediaDemultiplexerNode::BufferReceived\n"); 317 buffer->Recycle(); 318 break; 319 } 320 } 321 322 void MediaDemultiplexerNode::ProducerDataStatus( 323 const media_destination & for_whom, 324 int32 status, 325 bigtime_t at_performance_time) 326 { 327 fprintf(stderr,"MediaDemultiplexerNode::ProducerDataStatus\n"); 328 if (input.destination != for_whom) { 329 fprintf(stderr,"invalid destination received in MediaDemultiplexerNode::ProducerDataStatus\n"); 330 return; 331 } 332 media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS, 333 &input, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL); 334 EventQueue()->AddEvent(event); 335 } 336 337 status_t MediaDemultiplexerNode::GetLatencyFor( 338 const media_destination & for_whom, 339 bigtime_t * out_latency, 340 media_node_id * out_timesource) 341 { 342 fprintf(stderr,"MediaDemultiplexerNode::GetLatencyFor\n"); 343 if ((out_latency == 0) || (out_timesource == 0)) { 344 fprintf(stderr,"<- B_BAD_VALUE\n"); 345 return B_BAD_VALUE; 346 } 347 if (input.destination != for_whom) { 348 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 349 return B_MEDIA_BAD_DESTINATION; 350 } 351 *out_latency = EventLatency(); 352 *out_timesource = TimeSource()->ID(); 353 return B_OK; 354 } 355 356 status_t MediaDemultiplexerNode::Connected( 357 const media_source & producer, /* here's a good place to request buffer group usage */ 358 const media_destination & where, 359 const media_format & with_format, 360 media_input * out_input) 361 { 362 fprintf(stderr,"MediaDemultiplexerNode::Connected\n"); 363 if (input.destination != where) { 364 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 365 return B_MEDIA_BAD_DESTINATION; 366 } 367 368 // find an appropriate extractor to handle this type 369 fprintf(stderr," XXX: no extractors yet\n"); 370 371 // initialize the outputs here 372 // provide all the types that the extractor claims 373 outputs.empty(); 374 375 // compute the latency or just guess 376 fInternalLatency = 500; // just guess 377 fprintf(stderr," internal latency guessed = %lld\n",fInternalLatency); 378 379 SetEventLatency(fInternalLatency); 380 381 // record the agreed upon values 382 input.source = producer; 383 input.format = with_format; 384 *out_input = input; 385 return B_OK; 386 } 387 388 void MediaDemultiplexerNode::Disconnected( 389 const media_source & producer, 390 const media_destination & where) 391 { 392 fprintf(stderr,"MediaDemultiplexerNode::Disconnected\n"); 393 if (input.destination != where) { 394 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 395 return; 396 } 397 if (input.source != producer) { 398 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 399 return; 400 } 401 input.source = media_source::null; 402 GetInputFormat(&input.format); 403 404 outputs.empty(); 405 } 406 407 /* The notification comes from the upstream producer, so he's already cool with */ 408 /* the format; you should not ask him about it in here. */ 409 status_t MediaDemultiplexerNode::FormatChanged( 410 const media_source & producer, 411 const media_destination & consumer, 412 int32 change_tag, 413 const media_format & format) 414 { 415 fprintf(stderr,"MediaDemultiplexerNode::FormatChanged\n"); 416 if (input.source != producer) { 417 return B_MEDIA_BAD_SOURCE; 418 } 419 if (input.destination != consumer) { 420 return B_MEDIA_BAD_DESTINATION; 421 } 422 // XXX: implement 423 fprintf(stderr," This is because we asked to have the format changed.\n" 424 " Therefore we must switch to the other extractor that\n" 425 " we presumably have ready."); 426 input.format = format; 427 return B_OK; 428 } 429 430 /* Given a performance time of some previous buffer, retrieve the remembered tag */ 431 /* of the closest (previous or exact) performance time. Set *out_flags to 0; the */ 432 /* idea being that flags can be added later, and the understood flags returned in */ 433 /* *out_flags. */ 434 status_t MediaDemultiplexerNode::SeekTagRequested( 435 const media_destination & destination, 436 bigtime_t in_target_time, 437 uint32 in_flags, 438 media_seek_tag * out_seek_tag, 439 bigtime_t * out_tagged_time, 440 uint32 * out_flags) 441 { 442 fprintf(stderr,"MediaDemultiplexerNode::SeekTagRequested\n"); 443 // XXX: implement this 444 return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags, 445 out_seek_tag,out_tagged_time,out_flags); 446 } 447 448 // -------------------------------------------------------- // 449 // implemention of BBufferProducer 450 // -------------------------------------------------------- // 451 452 // They are asking us to make the first offering. 453 // So, we get a fresh format and then add requirements 454 status_t MediaDemultiplexerNode::FormatSuggestionRequested( 455 media_type type, 456 int32 quality, 457 media_format * format) 458 { 459 fprintf(stderr,"MediaDemultiplexerNode::FormatSuggestionRequested\n"); 460 // XXX: how do I pick which stream to supply here?.... 461 // answer?: get the first compatible stream that is available 462 fprintf(stderr," format suggestion requested not implemented\n"); 463 // if ((type != B_MEDIA_MULTISTREAM) && (type != B_MEDIA_UNKNOWN_TYPE)) { 464 // fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); 465 // return B_MEDIA_BAD_FORMAT; 466 // } 467 GetOutputFormat(format); 468 // AddRequirements(format); 469 470 return B_OK; 471 } 472 473 // They made an offer to us. We should make sure that the offer is 474 // acceptable, and then we can add any requirements we have on top of 475 // that. We leave wildcards for anything that we don't care about. 476 status_t MediaDemultiplexerNode::FormatProposal( 477 const media_source & output_source, 478 media_format * format) 479 { 480 fprintf(stderr,"MediaDemultiplexerNode::FormatProposal\n"); 481 // find the information for this output 482 vector<MediaOutputInfo>::iterator itr; 483 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 484 if (itr->output.source == output_source) { 485 break; 486 } 487 } 488 if (itr == outputs.end()) { 489 // we don't have that output 490 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 491 return B_MEDIA_BAD_SOURCE; 492 } 493 return itr->FormatProposal(format); 494 } 495 496 // Presumably we have already agreed with them that this format is 497 // okay. But just in case, we check the offer. (and complain if it 498 // is invalid) Then as the last thing we do, we get rid of any 499 // remaining wilcards. 500 status_t MediaDemultiplexerNode::FormatChangeRequested( 501 const media_source & source, 502 const media_destination & destination, 503 media_format * io_format, 504 int32 * _deprecated_) 505 { 506 fprintf(stderr,"MediaDemultiplexerNode::FormatChangeRequested\n"); 507 // find the information for this output 508 vector<MediaOutputInfo>::iterator itr; 509 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 510 if (itr->output.source == source) { 511 break; 512 } 513 } 514 if (itr == outputs.end()) { 515 // we don't have that output 516 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 517 return B_MEDIA_BAD_SOURCE; 518 } 519 return itr->FormatChangeRequested(destination,io_format); 520 } 521 522 status_t MediaDemultiplexerNode::GetNextOutput( /* cookie starts as 0 */ 523 int32 * cookie, 524 media_output * out_output) 525 { 526 fprintf(stderr,"MediaDemultiplexerNode::GetNextOutput\n"); 527 // they want a clean start 528 if (*cookie == 0) { 529 *cookie = (int32)outputs.begin(); 530 } 531 vector<MediaOutputInfo>::iterator itr 532 = (vector<MediaOutputInfo>::iterator)(*cookie); 533 // XXX: check here if the vector has been modified. 534 // if the iterator is invalid, return an error code?? 535 536 // they already got our 1 output 537 if (itr == outputs.end()) { 538 fprintf(stderr,"<- B_ERROR (no more outputs)\n"); 539 return B_ERROR; 540 } 541 // return this output 542 *out_output = itr->output; 543 // so next time they won't get the same output again 544 *cookie = (int32)++itr; 545 return B_OK; 546 } 547 548 status_t MediaDemultiplexerNode::DisposeOutputCookie( 549 int32 cookie) 550 { 551 fprintf(stderr,"MediaDemultiplexerNode::DisposeOutputCookie\n"); 552 // nothing to do since our cookies are part of the vector iterator 553 return B_OK; 554 } 555 556 status_t MediaDemultiplexerNode::SetBufferGroup( 557 const media_source & for_source, 558 BBufferGroup * group) 559 { 560 fprintf(stderr,"MediaDemultiplexerNode::SetBufferGroup\n"); 561 // find the information for this output 562 vector<MediaOutputInfo>::iterator itr; 563 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 564 if (itr->output.source == for_source) { 565 break; 566 } 567 } 568 if (itr == outputs.end()) { 569 // we don't have that output 570 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 571 return B_MEDIA_BAD_SOURCE; 572 } 573 return itr->SetBufferGroup(group); 574 } 575 576 /* Format of clipping is (as int16-s): <from line> <npairs> <startclip> <endclip>. */ 577 /* Repeat for each line where the clipping is different from the previous line. */ 578 /* If <npairs> is negative, use the data from line -<npairs> (there are 0 pairs after */ 579 /* a negative <npairs>. Yes, we only support 32k*32k frame buffers for clipping. */ 580 /* Any non-0 field of 'display' means that that field changed, and if you don't support */ 581 /* that change, you should return an error and ignore the request. Note that the buffer */ 582 /* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */ 583 /* be adhered to. */ 584 status_t MediaDemultiplexerNode::VideoClippingChanged( 585 const media_source & for_source, 586 int16 num_shorts, 587 int16 * clip_data, 588 const media_video_display_info & display, 589 int32 * _deprecated_) 590 { 591 return BBufferProducer::VideoClippingChanged(for_source,num_shorts,clip_data,display,_deprecated_); 592 } 593 594 status_t MediaDemultiplexerNode::GetLatency( 595 bigtime_t * out_latency) 596 { 597 fprintf(stderr,"MediaDemultiplexerNode::GetLatency\n"); 598 if (out_latency == 0) { 599 fprintf(stderr,"<- B_BAD_VALUE\n"); 600 return B_BAD_VALUE; 601 } 602 *out_latency = EventLatency() + SchedulingLatency(); 603 return B_OK; 604 } 605 606 status_t MediaDemultiplexerNode::PrepareToConnect( 607 const media_source & what, 608 const media_destination & where, 609 media_format * format, 610 media_source * out_source, 611 char * out_name) 612 { 613 fprintf(stderr,"MediaDemultiplexerNode::PrepareToConnect\n"); 614 // find the information for this output 615 vector<MediaOutputInfo>::iterator itr; 616 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 617 if (itr->output.source == what) { 618 break; 619 } 620 } 621 if (itr == outputs.end()) { 622 // we don't have that output 623 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 624 return B_MEDIA_BAD_SOURCE; 625 } 626 return itr->PrepareToConnect(where,format,out_source,out_name); 627 } 628 629 void MediaDemultiplexerNode::Connect( 630 status_t error, 631 const media_source & source, 632 const media_destination & destination, 633 const media_format & format, 634 char * io_name) 635 { 636 fprintf(stderr,"MediaDemultiplexerNode::Connect\n"); 637 // find the information for this output 638 vector<MediaOutputInfo>::iterator itr; 639 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 640 if (itr->output.source == source) { 641 break; 642 } 643 } 644 if (itr == outputs.end()) { 645 // we don't have that output 646 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 647 return; 648 } 649 if (error != B_OK) { 650 fprintf(stderr,"<- error already\n"); 651 itr->output.destination = media_destination::null; 652 itr->output.format = itr->generalFormat; 653 return; 654 } 655 656 // calculate the downstream latency 657 // must happen before itr->Connect 658 bigtime_t downstreamLatency; 659 media_node_id id; 660 FindLatencyFor(itr->output.destination, &downstreamLatency, &id); 661 662 // record the agreed upon values 663 status_t status; 664 status = itr->Connect(destination,format,io_name,downstreamLatency); 665 if (status != B_OK) { 666 fprintf(stderr," itr->Connect returned an error\n"); 667 return; 668 } 669 670 // compute the internal latency 671 // must happen after itr->Connect 672 if (fInternalLatency == 0) { 673 fInternalLatency = 100; // temporary until we finish computing it 674 ComputeInternalLatency(); 675 } 676 677 // If the downstream latency for this output is larger 678 // than our current downstream latency, we have to increase 679 // our current downstream latency to be the larger value. 680 if (downstreamLatency > fDownstreamLatency) { 681 SetEventLatency(fDownstreamLatency + fInternalLatency); 682 } 683 684 // XXX: what do I set the buffer duration to? 685 // it depends on which output is sending!! 686 // SetBufferDuration(bufferPeriod); 687 688 // XXX: do anything else? 689 return; 690 } 691 692 void MediaDemultiplexerNode::ComputeInternalLatency() { 693 fprintf(stderr,"MediaDemultiplexerNode::ComputeInternalLatency\n"); 694 // if (GetCurrentFile() != 0) { 695 // bigtime_t start, end; 696 // uint8 * data = new uint8[output.format.u.multistream.max_chunk_size]; // <- buffer group buffer size 697 // BBuffer * buffer = 0; 698 // ssize_t bytesRead = 0; 699 // { // timed section 700 // start = TimeSource()->RealTime(); 701 // // first we try to use a real BBuffer 702 // buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod); 703 // if (buffer != 0) { 704 // FillFileBuffer(buffer); 705 // } else { 706 // // didn't get a real BBuffer, try simulation by just a read from the disk 707 // bytesRead = GetCurrentFile()->Read(data,output.format.u.multistream.max_chunk_size); 708 // } 709 // end = TimeSource()->RealTime(); 710 // } 711 // bytesRead = buffer->SizeUsed(); 712 // delete data; 713 // if (buffer != 0) { 714 // buffer->Recycle(); 715 // } 716 // GetCurrentFile()->Seek(-bytesRead,SEEK_CUR); // put it back where we found it 717 // 718 // fInternalLatency = end - start; 719 // 720 // fprintf(stderr," internal latency from disk read = %lld\n",fInternalLatency); 721 // } else { 722 fInternalLatency = 100; // just guess 723 fprintf(stderr," internal latency guessed = %lld\n",fInternalLatency); 724 // } 725 } 726 727 void MediaDemultiplexerNode::Disconnect( 728 const media_source & what, 729 const media_destination & where) 730 { 731 fprintf(stderr,"MediaDemultiplexerNode::Disconnect\n"); 732 // find the information for this output 733 vector<MediaOutputInfo>::iterator itr; 734 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 735 if (itr->output.source == what) { 736 break; 737 } 738 } 739 if (itr == outputs.end()) { 740 // we don't have that output 741 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 742 return; 743 } 744 if (itr->output.destination != where) { 745 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 746 return; 747 } 748 // if this output has an equal (or higher!) latency than 749 // our current believed downstream latency, we may have to 750 // update our downstream latency. 751 bool updateDownstreamLatency = (itr->downstreamLatency >= fDownstreamLatency); 752 // disconnect this output 753 itr->Disconnect(); 754 // update the downstream latency if necessary 755 if (updateDownstreamLatency) { 756 bigtime_t newDownstreamLatency = 0; 757 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 758 if (itr->downstreamLatency > newDownstreamLatency) { 759 newDownstreamLatency = itr->downstreamLatency; 760 } 761 } 762 fDownstreamLatency = newDownstreamLatency; 763 } 764 } 765 766 void MediaDemultiplexerNode::LateNoticeReceived( 767 const media_source & what, 768 bigtime_t how_much, 769 bigtime_t performance_time) 770 { 771 fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived\n"); 772 vector<MediaOutputInfo>::iterator itr; 773 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 774 if (itr->output.source == what) { 775 break; 776 } 777 } 778 if (itr == outputs.end()) { 779 // we don't have that output 780 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 781 return; 782 } 783 switch (RunMode()) { 784 case B_OFFLINE: 785 // nothing to do 786 break; 787 case B_RECORDING: 788 // nothing to do 789 break; 790 case B_INCREASE_LATENCY: 791 fInternalLatency += how_much; 792 SetEventLatency(fDownstreamLatency + fInternalLatency); 793 break; 794 case B_DECREASE_PRECISION: 795 // XXX: try to catch up by producing buffers faster 796 break; 797 case B_DROP_DATA: 798 // XXX: should we really drop buffers? just for that output? 799 break; 800 default: 801 // huh?? there aren't any more run modes. 802 fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived with unexpected run mode.\n"); 803 break; 804 } 805 } 806 807 void MediaDemultiplexerNode::EnableOutput( 808 const media_source & what, 809 bool enabled, 810 int32 * _deprecated_) 811 { 812 fprintf(stderr,"MediaDemultiplexerNode::EnableOutput\n"); 813 // find the information for this output 814 vector<MediaOutputInfo>::iterator itr; 815 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 816 if (itr->output.source == what) { 817 break; 818 } 819 } 820 if (itr == outputs.end()) { 821 // we don't have that output 822 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 823 return; 824 } 825 status_t status = itr->EnableOutput(enabled); 826 if (status != B_OK) { 827 fprintf(stderr," error in itr->EnableOutput\n"); 828 return; 829 } 830 return; 831 } 832 833 status_t MediaDemultiplexerNode::SetPlayRate( 834 int32 numer, 835 int32 denom) 836 { 837 BBufferProducer::SetPlayRate(numer,denom); // XXX: do something intelligent later 838 } 839 840 void MediaDemultiplexerNode::AdditionalBufferRequested( // used to be Reserved 0 841 const media_source & source, 842 media_buffer_id prev_buffer, 843 bigtime_t prev_time, 844 const media_seek_tag * prev_tag) 845 { 846 fprintf(stderr,"MediaDemultiplexerNode::AdditionalBufferRequested\n"); 847 // find the information for this output 848 vector<MediaOutputInfo>::iterator itr; 849 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 850 if (itr->output.source == source) { 851 break; 852 } 853 } 854 if (itr == outputs.end()) { 855 // we don't have that output 856 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 857 return; 858 } 859 BBuffer * buffer; 860 status_t status = itr->AdditionalBufferRequested(prev_buffer,prev_time,prev_tag); 861 if (status != B_OK) { 862 fprintf(stderr," itr->AdditionalBufferRequested returned an error.\n"); 863 return; 864 } 865 return; 866 } 867 868 void MediaDemultiplexerNode::LatencyChanged( 869 const media_source & source, 870 const media_destination & destination, 871 bigtime_t new_latency, 872 uint32 flags) 873 { 874 fprintf(stderr,"MediaDemultiplexerNode::LatencyChanged\n"); 875 // find the information for this output 876 vector<MediaOutputInfo>::iterator itr; 877 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 878 if (itr->output.source == source) { 879 break; 880 } 881 } 882 if (itr == outputs.end()) { 883 // we don't have that output 884 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 885 return; 886 } 887 if (itr->output.destination != destination) { 888 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 889 return; 890 } 891 fDownstreamLatency = new_latency; 892 SetEventLatency(fDownstreamLatency + fInternalLatency); 893 // XXX: we may have to recompute the number of buffers that we are using 894 // see SetBufferGroup 895 } 896 897 // -------------------------------------------------------- // 898 // implementation for BMediaEventLooper 899 // -------------------------------------------------------- // 900 901 void MediaDemultiplexerNode::HandleEvent( 902 const media_timed_event *event, 903 bigtime_t lateness, 904 bool realTimeEvent = false) 905 { 906 fprintf(stderr,"MediaDemultiplexerNode::HandleEvent\n"); 907 switch (event->type) { 908 case BTimedEventQueue::B_START: 909 HandleStart(event,lateness,realTimeEvent); 910 break; 911 case BTimedEventQueue::B_SEEK: 912 HandleSeek(event,lateness,realTimeEvent); 913 break; 914 case BTimedEventQueue::B_WARP: 915 HandleWarp(event,lateness,realTimeEvent); 916 break; 917 case BTimedEventQueue::B_STOP: 918 HandleStop(event,lateness,realTimeEvent); 919 break; 920 case BTimedEventQueue::B_HANDLE_BUFFER: 921 if (RunState() == BMediaEventLooper::B_STARTED) { 922 HandleBuffer(event,lateness,realTimeEvent); 923 } 924 break; 925 case BTimedEventQueue::B_DATA_STATUS: 926 HandleDataStatus(event,lateness,realTimeEvent); 927 break; 928 case BTimedEventQueue::B_PARAMETER: 929 HandleParameter(event,lateness,realTimeEvent); 930 break; 931 default: 932 fprintf(stderr," unknown event type: %i\n",event->type); 933 break; 934 } 935 } 936 937 /* override to clean up custom events you have added to your queue */ 938 void MediaDemultiplexerNode::CleanUpEvent( 939 const media_timed_event *event) 940 { 941 BMediaEventLooper::CleanUpEvent(event); 942 } 943 944 /* called from Offline mode to determine the current time of the node */ 945 /* update your internal information whenever it changes */ 946 bigtime_t MediaDemultiplexerNode::OfflineTime() 947 { 948 fprintf(stderr,"MediaDemultiplexerNode::OfflineTime\n"); 949 return BMediaEventLooper::OfflineTime(); 950 // XXX: do something else? 951 } 952 953 /* override only if you know what you are doing! */ 954 /* otherwise much badness could occur */ 955 /* the actual control loop function: */ 956 /* waits for messages, Pops events off the queue and calls DispatchEvent */ 957 void MediaDemultiplexerNode::ControlLoop() { 958 BMediaEventLooper::ControlLoop(); 959 } 960 961 // protected: 962 963 status_t MediaDemultiplexerNode::HandleStart( 964 const media_timed_event *event, 965 bigtime_t lateness, 966 bool realTimeEvent = false) 967 { 968 fprintf(stderr,"MediaDemultiplexerNode::HandleStart()\n"); 969 if (RunState() != B_STARTED) { 970 // XXX: Either use the following line or the lines that are not commented. 971 // There doesn't seem to be a practical difference that i can tell. 972 // HandleBuffer(event,lateness,realTimeEvent); 973 media_timed_event firstBufferEvent(event->event_time, BTimedEventQueue::B_HANDLE_BUFFER); 974 HandleEvent(&firstBufferEvent, 0, false); 975 EventQueue()->AddEvent(firstBufferEvent); 976 } 977 return B_OK; 978 } 979 980 status_t MediaDemultiplexerNode::HandleSeek( 981 const media_timed_event *event, 982 bigtime_t lateness, 983 bool realTimeEvent = false) 984 { 985 fprintf(stderr,"MediaDemultiplexerNode::HandleSeek(t=%lld,d=%i,bd=%lld)\n",event->event_time,event->data,event->bigdata); 986 return B_OK; 987 } 988 989 status_t MediaDemultiplexerNode::HandleWarp( 990 const media_timed_event *event, 991 bigtime_t lateness, 992 bool realTimeEvent = false) 993 { 994 fprintf(stderr,"MediaDemultiplexerNode::HandleWarp\n"); 995 return B_OK; 996 } 997 998 status_t MediaDemultiplexerNode::HandleStop( 999 const media_timed_event *event, 1000 bigtime_t lateness, 1001 bool realTimeEvent = false) 1002 { 1003 fprintf(stderr,"MediaDemultiplexerNode::HandleStop\n"); 1004 // flush the queue so downstreamers don't get any more 1005 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); 1006 return B_OK; 1007 } 1008 1009 status_t MediaDemultiplexerNode::HandleBuffer( 1010 const media_timed_event *event, 1011 bigtime_t lateness, 1012 bool realTimeEvent = false) 1013 { 1014 fprintf(stderr,"MediaDemultiplexerNode::HandleBuffer\n"); 1015 BBuffer * buffer = const_cast<BBuffer*>((BBuffer*)event->pointer); 1016 if (buffer == 0) { 1017 fprintf(stderr,"<- B_BAD_VALUE\n"); 1018 return B_BAD_VALUE; 1019 } 1020 if (buffer->Header()->destination != input.destination.id) { 1021 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 1022 return B_MEDIA_BAD_DESTINATION; 1023 } 1024 if (outputs.begin() == outputs.end()) { 1025 fprintf(stderr,"<- B_MEDIA_NOT_CONNECTED\n"); 1026 return B_MEDIA_NOT_CONNECTED; 1027 } 1028 status_t status = B_OK; 1029 fprintf(stderr," XXX: HandleBuffer not yet implemented.\n"); 1030 // we have to hand the buffer to the extractor 1031 // and then whenever we get a buffer for an output send it 1032 // to that particular output (assuming it exists and is enabled) 1033 // BBuffer * buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod); 1034 // if (buffer != 0) { 1035 // status = FillFileBuffer(buffer); 1036 // if (status != B_OK) { 1037 // fprintf(stderr,"MediaDemultiplexerNode::HandleEvent got an error from FillFileBuffer.\n"); 1038 // buffer->Recycle(); 1039 // } else { 1040 // if (fOutputEnabled) { 1041 // status = SendBuffer(buffer,output.destination); 1042 // if (status != B_OK) { 1043 // fprintf(stderr,"MediaDemultiplexerNode::HandleEvent got an error from SendBuffer.\n"); 1044 // buffer->Recycle(); 1045 // } 1046 // } else { 1047 buffer->Recycle(); 1048 // } 1049 // } 1050 // } 1051 bigtime_t nextEventTime = event->event_time+10000; // fBufferPeriod; // XXX : should multiply 1052 media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER); 1053 EventQueue()->AddEvent(nextBufferEvent); 1054 return status; 1055 } 1056 1057 status_t MediaDemultiplexerNode::HandleDataStatus( 1058 const media_timed_event *event, 1059 bigtime_t lateness, 1060 bool realTimeEvent = false) 1061 { 1062 fprintf(stderr,"MediaDemultiplexerNode::HandleDataStatus"); 1063 // find the information for this output 1064 vector<MediaOutputInfo>::iterator itr; 1065 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 1066 SendDataStatus(event->data,itr->output.destination,event->event_time); 1067 } 1068 return B_OK; 1069 } 1070 1071 status_t MediaDemultiplexerNode::HandleParameter( 1072 const media_timed_event *event, 1073 bigtime_t lateness, 1074 bool realTimeEvent = false) 1075 { 1076 fprintf(stderr,"MediaDemultiplexerNode::HandleParameter"); 1077 return B_OK; 1078 } 1079 1080 // -------------------------------------------------------- // 1081 // MediaDemultiplexerNode specific functions 1082 // -------------------------------------------------------- // 1083 1084 // public: 1085 1086 void MediaDemultiplexerNode::GetFlavor(flavor_info * outInfo, int32 id) 1087 { 1088 fprintf(stderr,"MediaDemultiplexerNode::GetFlavor\n"); 1089 if (outInfo == 0) { 1090 return; 1091 } 1092 outInfo->name = "Haiku Demultiplexer"; 1093 outInfo->info = "A MediaDemultiplexerNode node demultiplexes a multistream into its constituent streams."; 1094 outInfo->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER; 1095 outInfo->flavor_flags = B_FLAVOR_IS_LOCAL; 1096 outInfo->possible_count = INT_MAX; 1097 outInfo->in_format_count = 1; // 1 input 1098 media_format * inFormats = new media_format[outInfo->in_format_count]; 1099 GetInputFormat(&inFormats[0]); 1100 outInfo->in_formats = inFormats; 1101 outInfo->out_format_count = 1; // 1 output 1102 media_format * outFormats = new media_format[outInfo->out_format_count]; 1103 GetOutputFormat(&outFormats[0]); 1104 outInfo->out_formats = outFormats; 1105 outInfo->internal_id = id; 1106 return; 1107 } 1108 1109 void MediaDemultiplexerNode::GetInputFormat(media_format * outFormat) 1110 { 1111 fprintf(stderr,"MediaDemultiplexerNode::GetInputFormat\n"); 1112 if (outFormat == 0) { 1113 return; 1114 } 1115 outFormat->type = B_MEDIA_MULTISTREAM; 1116 outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 1117 outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 1118 outFormat->u.multistream = media_multistream_format::wildcard; 1119 } 1120 1121 void MediaDemultiplexerNode::GetOutputFormat(media_format * outFormat) 1122 { 1123 fprintf(stderr,"MediaDemultiplexerNode::GetOutputFormat\n"); 1124 if (outFormat == 0) { 1125 return; 1126 } 1127 outFormat->type = B_MEDIA_UNKNOWN_TYPE; // more like ANY_TYPE than unknown 1128 outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 1129 outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 1130 } 1131 1132 // protected: 1133 1134 status_t MediaDemultiplexerNode::AddRequirements(media_format * format) 1135 { 1136 fprintf(stderr,"MediaDemultiplexerNode::AddRequirements\n"); 1137 return B_OK; 1138 } 1139 1140 // -------------------------------------------------------- // 1141 // stuffing 1142 // -------------------------------------------------------- // 1143 1144 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_0(void *) {} 1145 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_1(void *) {} 1146 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_2(void *) {} 1147 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_3(void *) {} 1148 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_4(void *) {} 1149 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_5(void *) {} 1150 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_6(void *) {} 1151 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_7(void *) {} 1152 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_8(void *) {} 1153 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_9(void *) {} 1154 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_10(void *) {} 1155 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_11(void *) {} 1156 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_12(void *) {} 1157 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_13(void *) {} 1158 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_14(void *) {} 1159 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_15(void *) {} 1160