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 (format == 0) { 247 fprintf(stderr,"<- B_BAD_VALUE\n"); 248 return B_BAD_VALUE; // no crashing 249 } 250 if (input.destination != dest) { 251 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION"); 252 return B_MEDIA_BAD_DESTINATION; // we only have one input so that better be it 253 } 254 media_format myFormat; 255 GetInputFormat(&myFormat); 256 // Be's format_is_compatible doesn't work, 257 // so use our format_is_acceptible instead 258 if (!format_is_acceptible(*format,myFormat)) { 259 fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); 260 return B_MEDIA_BAD_FORMAT; 261 } 262 AddRequirements(format); 263 return B_OK; 264 } 265 266 status_t MediaDemultiplexerNode::GetNextInput( 267 int32 * cookie, 268 media_input * out_input) 269 { 270 fprintf(stderr,"MediaDemultiplexerNode::GetNextInput\n"); 271 // let's not crash even if they are stupid 272 if (out_input == 0) { 273 // no place to write! 274 fprintf(stderr,"<- B_BAD_VALUE\n"); 275 return B_BAD_VALUE; 276 } 277 if (cookie != 0) { 278 // it's valid but they already got our 1 input 279 if (*cookie != 0) { 280 fprintf(stderr,"<- B_ERROR (no more inputs)\n"); 281 return B_ERROR; 282 } 283 // so next time they won't get the same input again 284 *cookie = 1; 285 } 286 *out_input = input; 287 return B_OK; 288 } 289 290 void MediaDemultiplexerNode::DisposeInputCookie( 291 int32 cookie) 292 { 293 fprintf(stderr,"MediaDemultiplexerNode::DisposeInputCookie\n"); 294 // nothing to do since our cookies are just integers 295 return; // B_OK; 296 } 297 298 void MediaDemultiplexerNode::BufferReceived( 299 BBuffer * buffer) 300 { 301 fprintf(stderr,"MediaDemultiplexerNode::BufferReceived\n"); 302 switch (buffer->Header()->type) { 303 // case B_MEDIA_PARAMETERS: 304 // { 305 // status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed()); 306 // if (status != B_OK) { 307 // fprintf(stderr,"ApplyParameterData in MediaDemultiplexerNode::BufferReceived failed\n"); 308 // } 309 // buffer->Recycle(); 310 // } 311 // break; 312 case B_MEDIA_MULTISTREAM: 313 if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) { 314 fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in MediaDemultiplexerNode::BufferReceived\n"); 315 // XXX: implement this part 316 buffer->Recycle(); 317 } else { 318 media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER, 319 buffer, BTimedEventQueue::B_RECYCLE_BUFFER); 320 status_t status = EventQueue()->AddEvent(event); 321 if (status != B_OK) { 322 fprintf(stderr,"EventQueue()->AddEvent(event) in MediaDemultiplexerNode::BufferReceived failed\n"); 323 buffer->Recycle(); 324 } 325 } 326 break; 327 default: 328 fprintf(stderr,"unexpected buffer type in MediaDemultiplexerNode::BufferReceived\n"); 329 buffer->Recycle(); 330 break; 331 } 332 } 333 334 void MediaDemultiplexerNode::ProducerDataStatus( 335 const media_destination & for_whom, 336 int32 status, 337 bigtime_t at_performance_time) 338 { 339 fprintf(stderr,"MediaDemultiplexerNode::ProducerDataStatus\n"); 340 if (input.destination != for_whom) { 341 fprintf(stderr,"invalid destination received in MediaDemultiplexerNode::ProducerDataStatus\n"); 342 return; 343 } 344 media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS, 345 &input, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL); 346 EventQueue()->AddEvent(event); 347 } 348 349 status_t MediaDemultiplexerNode::GetLatencyFor( 350 const media_destination & for_whom, 351 bigtime_t * out_latency, 352 media_node_id * out_timesource) 353 { 354 fprintf(stderr,"MediaDemultiplexerNode::GetLatencyFor\n"); 355 if ((out_latency == 0) || (out_timesource == 0)) { 356 fprintf(stderr,"<- B_BAD_VALUE\n"); 357 return B_BAD_VALUE; 358 } 359 if (input.destination != for_whom) { 360 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 361 return B_MEDIA_BAD_DESTINATION; 362 } 363 *out_latency = EventLatency(); 364 *out_timesource = TimeSource()->ID(); 365 return B_OK; 366 } 367 368 status_t MediaDemultiplexerNode::Connected( 369 const media_source & producer, /* here's a good place to request buffer group usage */ 370 const media_destination & where, 371 const media_format & with_format, 372 media_input * out_input) 373 { 374 fprintf(stderr,"MediaDemultiplexerNode::Connected\n"); 375 if (out_input == 0) { 376 fprintf(stderr,"<- B_BAD_VALUE\n"); 377 return B_BAD_VALUE; // no crashing 378 } 379 if (input.destination != where) { 380 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 381 return B_MEDIA_BAD_DESTINATION; 382 } 383 384 // find an appropriate extractor to handle this type 385 fprintf(stderr," XXX: no extractors yet\n"); 386 387 // initialize the outputs here 388 // provide all the types that the extractor claims 389 outputs.empty(); 390 391 // compute the latency or just guess 392 fInternalLatency = 500; // just guess 393 fprintf(stderr," internal latency guessed = %lld\n",fInternalLatency); 394 395 SetEventLatency(fInternalLatency); 396 397 // record the agreed upon values 398 input.source = producer; 399 input.format = with_format; 400 *out_input = input; 401 return B_OK; 402 } 403 404 void MediaDemultiplexerNode::Disconnected( 405 const media_source & producer, 406 const media_destination & where) 407 { 408 fprintf(stderr,"MediaDemultiplexerNode::Disconnected\n"); 409 if (input.destination != where) { 410 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 411 return; 412 } 413 if (input.source != producer) { 414 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 415 return; 416 } 417 input.source = media_source::null; 418 GetInputFormat(&input.format); 419 420 outputs.empty(); 421 } 422 423 /* The notification comes from the upstream producer, so he's already cool with */ 424 /* the format; you should not ask him about it in here. */ 425 status_t MediaDemultiplexerNode::FormatChanged( 426 const media_source & producer, 427 const media_destination & consumer, 428 int32 change_tag, 429 const media_format & format) 430 { 431 fprintf(stderr,"MediaDemultiplexerNode::FormatChanged\n"); 432 if (input.source != producer) { 433 return B_MEDIA_BAD_SOURCE; 434 } 435 if (input.destination != consumer) { 436 return B_MEDIA_BAD_DESTINATION; 437 } 438 // XXX: implement 439 fprintf(stderr," This is because we asked to have the format changed.\n" 440 " Therefore we must switch to the other extractor that\n" 441 " we presumably have ready."); 442 input.format = format; 443 return B_OK; 444 } 445 446 /* Given a performance time of some previous buffer, retrieve the remembered tag */ 447 /* of the closest (previous or exact) performance time. Set *out_flags to 0; the */ 448 /* idea being that flags can be added later, and the understood flags returned in */ 449 /* *out_flags. */ 450 status_t MediaDemultiplexerNode::SeekTagRequested( 451 const media_destination & destination, 452 bigtime_t in_target_time, 453 uint32 in_flags, 454 media_seek_tag * out_seek_tag, 455 bigtime_t * out_tagged_time, 456 uint32 * out_flags) 457 { 458 fprintf(stderr,"MediaDemultiplexerNode::SeekTagRequested\n"); 459 // XXX: implement this 460 return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags, 461 out_seek_tag,out_tagged_time,out_flags); 462 } 463 464 // -------------------------------------------------------- // 465 // implemention of BBufferProducer 466 // -------------------------------------------------------- // 467 468 // They are asking us to make the first offering. 469 // So, we get a fresh format and then add requirements 470 status_t MediaDemultiplexerNode::FormatSuggestionRequested( 471 media_type type, 472 int32 quality, 473 media_format * format) 474 { 475 fprintf(stderr,"MediaDemultiplexerNode::FormatSuggestionRequested\n"); 476 if (format == 0) { 477 fprintf(stderr,"<- B_BAD_VALUE\n"); 478 return B_BAD_VALUE; // no crashing 479 } 480 // XXX: how do I pick which stream to supply here?.... 481 // answer?: get the first compatible stream that is available 482 fprintf(stderr," format suggestion requested not implemented\n"); 483 // if ((type != B_MEDIA_MULTISTREAM) && (type != B_MEDIA_UNKNOWN_TYPE)) { 484 // fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); 485 // return B_MEDIA_BAD_FORMAT; 486 // } 487 GetOutputFormat(format); 488 // AddRequirements(format); 489 490 return B_OK; 491 } 492 493 // They made an offer to us. We should make sure that the offer is 494 // acceptable, and then we can add any requirements we have on top of 495 // that. We leave wildcards for anything that we don't care about. 496 status_t MediaDemultiplexerNode::FormatProposal( 497 const media_source & output_source, 498 media_format * format) 499 { 500 fprintf(stderr,"MediaDemultiplexerNode::FormatProposal\n"); 501 // find the information for this output 502 vector<MediaOutputInfo>::iterator itr; 503 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 504 if (itr->output.source == output_source) { 505 break; 506 } 507 } 508 if (itr == outputs.end()) { 509 // we don't have that output 510 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 511 return B_MEDIA_BAD_SOURCE; 512 } 513 return itr->FormatProposal(format); 514 } 515 516 // Presumably we have already agreed with them that this format is 517 // okay. But just in case, we check the offer. (and complain if it 518 // is invalid) Then as the last thing we do, we get rid of any 519 // remaining wilcards. 520 status_t MediaDemultiplexerNode::FormatChangeRequested( 521 const media_source & source, 522 const media_destination & destination, 523 media_format * io_format, 524 int32 * _deprecated_) 525 { 526 fprintf(stderr,"MediaDemultiplexerNode::FormatChangeRequested\n"); 527 // find the information for this output 528 vector<MediaOutputInfo>::iterator itr; 529 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 530 if (itr->output.source == source) { 531 break; 532 } 533 } 534 if (itr == outputs.end()) { 535 // we don't have that output 536 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 537 return B_MEDIA_BAD_SOURCE; 538 } 539 return itr->FormatChangeRequested(destination,io_format); 540 } 541 542 status_t MediaDemultiplexerNode::GetNextOutput( /* cookie starts as 0 */ 543 int32 * cookie, 544 media_output * out_output) 545 { 546 fprintf(stderr,"MediaDemultiplexerNode::GetNextOutput\n"); 547 // let's not crash even if they are stupid 548 if ((out_output == 0) || (cookie == 0)) { 549 // no place to write! 550 fprintf(stderr,"<- B_BAD_VALUE\n"); 551 return B_BAD_VALUE; 552 } 553 // they want a clean start 554 if (*cookie == 0) { 555 *cookie = (int32)outputs.begin(); 556 } 557 vector<MediaOutputInfo>::iterator itr 558 = (vector<MediaOutputInfo>::iterator)(*cookie); 559 // XXX: check here if the vector has been modified. 560 // if the iterator is invalid, return an error code?? 561 562 // they already got our 1 output 563 if (itr == outputs.end()) { 564 fprintf(stderr,"<- B_ERROR (no more outputs)\n"); 565 return B_ERROR; 566 } 567 // return this output 568 *out_output = itr->output; 569 // so next time they won't get the same output again 570 *cookie = (int32)++itr; 571 return B_OK; 572 } 573 574 status_t MediaDemultiplexerNode::DisposeOutputCookie( 575 int32 cookie) 576 { 577 fprintf(stderr,"MediaDemultiplexerNode::DisposeOutputCookie\n"); 578 // nothing to do since our cookies are part of the vector iterator 579 return B_OK; 580 } 581 582 status_t MediaDemultiplexerNode::SetBufferGroup( 583 const media_source & for_source, 584 BBufferGroup * group) 585 { 586 fprintf(stderr,"MediaDemultiplexerNode::SetBufferGroup\n"); 587 // find the information for this output 588 vector<MediaOutputInfo>::iterator itr; 589 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 590 if (itr->output.source == for_source) { 591 break; 592 } 593 } 594 if (itr == outputs.end()) { 595 // we don't have that output 596 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 597 return B_MEDIA_BAD_SOURCE; 598 } 599 return itr->SetBufferGroup(group); 600 } 601 602 /* Format of clipping is (as int16-s): <from line> <npairs> <startclip> <endclip>. */ 603 /* Repeat for each line where the clipping is different from the previous line. */ 604 /* If <npairs> is negative, use the data from line -<npairs> (there are 0 pairs after */ 605 /* a negative <npairs>. Yes, we only support 32k*32k frame buffers for clipping. */ 606 /* Any non-0 field of 'display' means that that field changed, and if you don't support */ 607 /* that change, you should return an error and ignore the request. Note that the buffer */ 608 /* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */ 609 /* be adhered to. */ 610 status_t MediaDemultiplexerNode::VideoClippingChanged( 611 const media_source & for_source, 612 int16 num_shorts, 613 int16 * clip_data, 614 const media_video_display_info & display, 615 int32 * _deprecated_) 616 { 617 return BBufferProducer::VideoClippingChanged(for_source,num_shorts,clip_data,display,_deprecated_); 618 } 619 620 status_t MediaDemultiplexerNode::GetLatency( 621 bigtime_t * out_latency) 622 { 623 fprintf(stderr,"MediaDemultiplexerNode::GetLatency\n"); 624 if (out_latency == 0) { 625 fprintf(stderr,"<- B_BAD_VALUE\n"); 626 return B_BAD_VALUE; 627 } 628 *out_latency = EventLatency() + SchedulingLatency(); 629 return B_OK; 630 } 631 632 status_t MediaDemultiplexerNode::PrepareToConnect( 633 const media_source & what, 634 const media_destination & where, 635 media_format * format, 636 media_source * out_source, 637 char * out_name) 638 { 639 fprintf(stderr,"MediaDemultiplexerNode::PrepareToConnect\n"); 640 if ((format == 0) || (out_source == 0) || (out_name == 0)) { 641 fprintf(stderr,"<- B_BAD_VALUE\n"); 642 return B_BAD_VALUE; // no crashes... 643 } 644 // find the information for this output 645 vector<MediaOutputInfo>::iterator itr; 646 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 647 if (itr->output.source == what) { 648 break; 649 } 650 } 651 if (itr == outputs.end()) { 652 // we don't have that output 653 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 654 return B_MEDIA_BAD_SOURCE; 655 } 656 return itr->PrepareToConnect(where,format,out_source,out_name); 657 } 658 659 void MediaDemultiplexerNode::Connect( 660 status_t error, 661 const media_source & source, 662 const media_destination & destination, 663 const media_format & format, 664 char * io_name) 665 { 666 fprintf(stderr,"MediaDemultiplexerNode::Connect\n"); 667 // find the information for this output 668 vector<MediaOutputInfo>::iterator itr; 669 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 670 if (itr->output.source == source) { 671 break; 672 } 673 } 674 if (itr == outputs.end()) { 675 // we don't have that output 676 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 677 return; 678 } 679 if (error != B_OK) { 680 fprintf(stderr,"<- error already\n"); 681 itr->output.destination = media_destination::null; 682 itr->output.format = itr->generalFormat; 683 return; 684 } 685 686 // calculate the downstream latency 687 // must happen before itr->Connect 688 bigtime_t downstreamLatency; 689 media_node_id id; 690 FindLatencyFor(itr->output.destination, &downstreamLatency, &id); 691 692 // record the agreed upon values 693 status_t status; 694 status = itr->Connect(destination,format,io_name,downstreamLatency); 695 if (status != B_OK) { 696 fprintf(stderr," itr->Connect returned an error\n"); 697 return; 698 } 699 700 // compute the internal latency 701 // must happen after itr->Connect 702 if (fInternalLatency == 0) { 703 fInternalLatency = 100; // temporary until we finish computing it 704 ComputeInternalLatency(); 705 } 706 707 // If the downstream latency for this output is larger 708 // than our current downstream latency, we have to increase 709 // our current downstream latency to be the larger value. 710 if (downstreamLatency > fDownstreamLatency) { 711 SetEventLatency(fDownstreamLatency + fInternalLatency); 712 } 713 714 // XXX: what do I set the buffer duration to? 715 // it depends on which output is sending!! 716 // SetBufferDuration(bufferPeriod); 717 718 // XXX: do anything else? 719 return; 720 } 721 722 void MediaDemultiplexerNode::ComputeInternalLatency() { 723 fprintf(stderr,"MediaDemultiplexerNode::ComputeInternalLatency\n"); 724 // if (GetCurrentFile() != 0) { 725 // bigtime_t start, end; 726 // uint8 * data = new uint8[output.format.u.multistream.max_chunk_size]; // <- buffer group buffer size 727 // BBuffer * buffer = 0; 728 // ssize_t bytesRead = 0; 729 // { // timed section 730 // start = TimeSource()->RealTime(); 731 // // first we try to use a real BBuffer 732 // buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod); 733 // if (buffer != 0) { 734 // FillFileBuffer(buffer); 735 // } else { 736 // // didn't get a real BBuffer, try simulation by just a read from the disk 737 // bytesRead = GetCurrentFile()->Read(data,output.format.u.multistream.max_chunk_size); 738 // } 739 // end = TimeSource()->RealTime(); 740 // } 741 // bytesRead = buffer->SizeUsed(); 742 // delete data; 743 // if (buffer != 0) { 744 // buffer->Recycle(); 745 // } 746 // GetCurrentFile()->Seek(-bytesRead,SEEK_CUR); // put it back where we found it 747 // 748 // fInternalLatency = end - start; 749 // 750 // fprintf(stderr," internal latency from disk read = %lld\n",fInternalLatency); 751 // } else { 752 fInternalLatency = 100; // just guess 753 fprintf(stderr," internal latency guessed = %lld\n",fInternalLatency); 754 // } 755 } 756 757 void MediaDemultiplexerNode::Disconnect( 758 const media_source & what, 759 const media_destination & where) 760 { 761 fprintf(stderr,"MediaDemultiplexerNode::Disconnect\n"); 762 // find the information for this output 763 vector<MediaOutputInfo>::iterator itr; 764 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 765 if (itr->output.source == what) { 766 break; 767 } 768 } 769 if (itr == outputs.end()) { 770 // we don't have that output 771 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 772 return; 773 } 774 if (itr->output.destination != where) { 775 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 776 return; 777 } 778 // if this output has an equal (or higher!) latency than 779 // our current believed downstream latency, we may have to 780 // update our downstream latency. 781 bool updateDownstreamLatency = (itr->downstreamLatency >= fDownstreamLatency); 782 // disconnect this output 783 itr->Disconnect(); 784 // update the downstream latency if necessary 785 if (updateDownstreamLatency) { 786 bigtime_t newDownstreamLatency = 0; 787 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 788 if (itr->downstreamLatency > newDownstreamLatency) { 789 newDownstreamLatency = itr->downstreamLatency; 790 } 791 } 792 fDownstreamLatency = newDownstreamLatency; 793 } 794 } 795 796 void MediaDemultiplexerNode::LateNoticeReceived( 797 const media_source & what, 798 bigtime_t how_much, 799 bigtime_t performance_time) 800 { 801 fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived\n"); 802 vector<MediaOutputInfo>::iterator itr; 803 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 804 if (itr->output.source == what) { 805 break; 806 } 807 } 808 if (itr == outputs.end()) { 809 // we don't have that output 810 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 811 return; 812 } 813 switch (RunMode()) { 814 case B_OFFLINE: 815 // nothing to do 816 break; 817 case B_RECORDING: 818 // nothing to do 819 break; 820 case B_INCREASE_LATENCY: 821 fInternalLatency += how_much; 822 SetEventLatency(fDownstreamLatency + fInternalLatency); 823 break; 824 case B_DECREASE_PRECISION: 825 // XXX: try to catch up by producing buffers faster 826 break; 827 case B_DROP_DATA: 828 // XXX: should we really drop buffers? just for that output? 829 break; 830 default: 831 // huh?? there aren't any more run modes. 832 fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived with unexpected run mode.\n"); 833 break; 834 } 835 } 836 837 void MediaDemultiplexerNode::EnableOutput( 838 const media_source & what, 839 bool enabled, 840 int32 * _deprecated_) 841 { 842 fprintf(stderr,"MediaDemultiplexerNode::EnableOutput\n"); 843 // find the information for this output 844 vector<MediaOutputInfo>::iterator itr; 845 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 846 if (itr->output.source == what) { 847 break; 848 } 849 } 850 if (itr == outputs.end()) { 851 // we don't have that output 852 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 853 return; 854 } 855 status_t status = itr->EnableOutput(enabled); 856 if (status != B_OK) { 857 fprintf(stderr," error in itr->EnableOutput\n"); 858 return; 859 } 860 return; 861 } 862 863 status_t MediaDemultiplexerNode::SetPlayRate( 864 int32 numer, 865 int32 denom) 866 { 867 BBufferProducer::SetPlayRate(numer,denom); // XXX: do something intelligent later 868 } 869 870 void MediaDemultiplexerNode::AdditionalBufferRequested( // used to be Reserved 0 871 const media_source & source, 872 media_buffer_id prev_buffer, 873 bigtime_t prev_time, 874 const media_seek_tag * prev_tag) 875 { 876 fprintf(stderr,"MediaDemultiplexerNode::AdditionalBufferRequested\n"); 877 // find the information for this output 878 vector<MediaOutputInfo>::iterator itr; 879 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 880 if (itr->output.source == source) { 881 break; 882 } 883 } 884 if (itr == outputs.end()) { 885 // we don't have that output 886 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 887 return; 888 } 889 BBuffer * buffer; 890 status_t status = itr->AdditionalBufferRequested(prev_buffer,prev_time,prev_tag); 891 if (status != B_OK) { 892 fprintf(stderr," itr->AdditionalBufferRequested returned an error.\n"); 893 return; 894 } 895 return; 896 } 897 898 void MediaDemultiplexerNode::LatencyChanged( 899 const media_source & source, 900 const media_destination & destination, 901 bigtime_t new_latency, 902 uint32 flags) 903 { 904 fprintf(stderr,"MediaDemultiplexerNode::LatencyChanged\n"); 905 // find the information for this output 906 vector<MediaOutputInfo>::iterator itr; 907 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 908 if (itr->output.source == source) { 909 break; 910 } 911 } 912 if (itr == outputs.end()) { 913 // we don't have that output 914 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 915 return; 916 } 917 if (itr->output.destination != destination) { 918 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 919 return; 920 } 921 fDownstreamLatency = new_latency; 922 SetEventLatency(fDownstreamLatency + fInternalLatency); 923 // XXX: we may have to recompute the number of buffers that we are using 924 // see SetBufferGroup 925 } 926 927 // -------------------------------------------------------- // 928 // implementation for BMediaEventLooper 929 // -------------------------------------------------------- // 930 931 void MediaDemultiplexerNode::HandleEvent( 932 const media_timed_event *event, 933 bigtime_t lateness, 934 bool realTimeEvent = false) 935 { 936 fprintf(stderr,"MediaDemultiplexerNode::HandleEvent\n"); 937 switch (event->type) { 938 case BTimedEventQueue::B_START: 939 HandleStart(event,lateness,realTimeEvent); 940 break; 941 case BTimedEventQueue::B_SEEK: 942 HandleSeek(event,lateness,realTimeEvent); 943 break; 944 case BTimedEventQueue::B_WARP: 945 HandleWarp(event,lateness,realTimeEvent); 946 break; 947 case BTimedEventQueue::B_STOP: 948 HandleStop(event,lateness,realTimeEvent); 949 break; 950 case BTimedEventQueue::B_HANDLE_BUFFER: 951 if (RunState() == BMediaEventLooper::B_STARTED) { 952 HandleBuffer(event,lateness,realTimeEvent); 953 } 954 break; 955 case BTimedEventQueue::B_DATA_STATUS: 956 HandleDataStatus(event,lateness,realTimeEvent); 957 break; 958 case BTimedEventQueue::B_PARAMETER: 959 HandleParameter(event,lateness,realTimeEvent); 960 break; 961 default: 962 fprintf(stderr," unknown event type: %i\n",event->type); 963 break; 964 } 965 } 966 967 /* override to clean up custom events you have added to your queue */ 968 void MediaDemultiplexerNode::CleanUpEvent( 969 const media_timed_event *event) 970 { 971 BMediaEventLooper::CleanUpEvent(event); 972 } 973 974 /* called from Offline mode to determine the current time of the node */ 975 /* update your internal information whenever it changes */ 976 bigtime_t MediaDemultiplexerNode::OfflineTime() 977 { 978 fprintf(stderr,"MediaDemultiplexerNode::OfflineTime\n"); 979 return BMediaEventLooper::OfflineTime(); 980 // XXX: do something else? 981 } 982 983 /* override only if you know what you are doing! */ 984 /* otherwise much badness could occur */ 985 /* the actual control loop function: */ 986 /* waits for messages, Pops events off the queue and calls DispatchEvent */ 987 void MediaDemultiplexerNode::ControlLoop() { 988 BMediaEventLooper::ControlLoop(); 989 } 990 991 // protected: 992 993 status_t MediaDemultiplexerNode::HandleStart( 994 const media_timed_event *event, 995 bigtime_t lateness, 996 bool realTimeEvent = false) 997 { 998 fprintf(stderr,"MediaDemultiplexerNode::HandleStart()\n"); 999 if (RunState() != B_STARTED) { 1000 // XXX: Either use the following line or the lines that are not commented. 1001 // There doesn't seem to be a practical difference that i can tell. 1002 // HandleBuffer(event,lateness,realTimeEvent); 1003 media_timed_event firstBufferEvent(event->event_time, BTimedEventQueue::B_HANDLE_BUFFER); 1004 HandleEvent(&firstBufferEvent, 0, false); 1005 EventQueue()->AddEvent(firstBufferEvent); 1006 } 1007 return B_OK; 1008 } 1009 1010 status_t MediaDemultiplexerNode::HandleSeek( 1011 const media_timed_event *event, 1012 bigtime_t lateness, 1013 bool realTimeEvent = false) 1014 { 1015 fprintf(stderr,"MediaDemultiplexerNode::HandleSeek(t=%lld,d=%i,bd=%lld)\n",event->event_time,event->data,event->bigdata); 1016 return B_OK; 1017 } 1018 1019 status_t MediaDemultiplexerNode::HandleWarp( 1020 const media_timed_event *event, 1021 bigtime_t lateness, 1022 bool realTimeEvent = false) 1023 { 1024 fprintf(stderr,"MediaDemultiplexerNode::HandleWarp\n"); 1025 return B_OK; 1026 } 1027 1028 status_t MediaDemultiplexerNode::HandleStop( 1029 const media_timed_event *event, 1030 bigtime_t lateness, 1031 bool realTimeEvent = false) 1032 { 1033 fprintf(stderr,"MediaDemultiplexerNode::HandleStop\n"); 1034 // flush the queue so downstreamers don't get any more 1035 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); 1036 return B_OK; 1037 } 1038 1039 status_t MediaDemultiplexerNode::HandleBuffer( 1040 const media_timed_event *event, 1041 bigtime_t lateness, 1042 bool realTimeEvent = false) 1043 { 1044 fprintf(stderr,"MediaDemultiplexerNode::HandleBuffer\n"); 1045 BBuffer * buffer = const_cast<BBuffer*>((BBuffer*)event->pointer); 1046 if (buffer == 0) { 1047 fprintf(stderr,"<- B_BAD_VALUE\n"); 1048 return B_BAD_VALUE; 1049 } 1050 if (buffer->Header()->destination != input.destination.id) { 1051 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 1052 return B_MEDIA_BAD_DESTINATION; 1053 } 1054 if (outputs.begin() == outputs.end()) { 1055 fprintf(stderr,"<- B_MEDIA_NOT_CONNECTED\n"); 1056 return B_MEDIA_NOT_CONNECTED; 1057 } 1058 status_t status = B_OK; 1059 fprintf(stderr," XXX: HandleBuffer not yet implemented.\n"); 1060 // we have to hand the buffer to the extractor 1061 // and then whenever we get a buffer for an output send it 1062 // to that particular output (assuming it exists and is enabled) 1063 // BBuffer * buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod); 1064 // if (buffer != 0) { 1065 // status = FillFileBuffer(buffer); 1066 // if (status != B_OK) { 1067 // fprintf(stderr,"MediaDemultiplexerNode::HandleEvent got an error from FillFileBuffer.\n"); 1068 // buffer->Recycle(); 1069 // } else { 1070 // if (fOutputEnabled) { 1071 // status = SendBuffer(buffer,output.destination); 1072 // if (status != B_OK) { 1073 // fprintf(stderr,"MediaDemultiplexerNode::HandleEvent got an error from SendBuffer.\n"); 1074 // buffer->Recycle(); 1075 // } 1076 // } else { 1077 buffer->Recycle(); 1078 // } 1079 // } 1080 // } 1081 bigtime_t nextEventTime = event->event_time+10000; // fBufferPeriod; // XXX : should multiply 1082 media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER); 1083 EventQueue()->AddEvent(nextBufferEvent); 1084 return status; 1085 } 1086 1087 status_t MediaDemultiplexerNode::HandleDataStatus( 1088 const media_timed_event *event, 1089 bigtime_t lateness, 1090 bool realTimeEvent = false) 1091 { 1092 fprintf(stderr,"MediaDemultiplexerNode::HandleDataStatus"); 1093 // find the information for this output 1094 vector<MediaOutputInfo>::iterator itr; 1095 for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) { 1096 SendDataStatus(event->data,itr->output.destination,event->event_time); 1097 } 1098 return B_OK; 1099 } 1100 1101 status_t MediaDemultiplexerNode::HandleParameter( 1102 const media_timed_event *event, 1103 bigtime_t lateness, 1104 bool realTimeEvent = false) 1105 { 1106 fprintf(stderr,"MediaDemultiplexerNode::HandleParameter"); 1107 return B_OK; 1108 } 1109 1110 // -------------------------------------------------------- // 1111 // MediaDemultiplexerNode specific functions 1112 // -------------------------------------------------------- // 1113 1114 // public: 1115 1116 void MediaDemultiplexerNode::GetFlavor(flavor_info * outInfo, int32 id) 1117 { 1118 fprintf(stderr,"MediaDemultiplexerNode::GetFlavor\n"); 1119 if (outInfo == 0) { 1120 return; 1121 } 1122 outInfo->name = "OpenBeOS Demultiplexer"; 1123 outInfo->info = "A MediaDemultiplexerNode node demultiplexes a multistream into its constituent streams."; 1124 outInfo->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER; 1125 outInfo->flavor_flags = B_FLAVOR_IS_LOCAL; 1126 outInfo->possible_count = INT_MAX; 1127 outInfo->in_format_count = 1; // 1 input 1128 media_format * inFormats = new media_format[outInfo->in_format_count]; 1129 GetInputFormat(&inFormats[0]); 1130 outInfo->in_formats = inFormats; 1131 outInfo->out_format_count = 1; // 1 output 1132 media_format * outFormats = new media_format[outInfo->out_format_count]; 1133 GetOutputFormat(&outFormats[0]); 1134 outInfo->out_formats = outFormats; 1135 outInfo->internal_id = id; 1136 return; 1137 } 1138 1139 void MediaDemultiplexerNode::GetInputFormat(media_format * outFormat) 1140 { 1141 fprintf(stderr,"MediaDemultiplexerNode::GetInputFormat\n"); 1142 if (outFormat == 0) { 1143 return; 1144 } 1145 outFormat->type = B_MEDIA_MULTISTREAM; 1146 outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 1147 outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 1148 outFormat->u.multistream = media_multistream_format::wildcard; 1149 } 1150 1151 void MediaDemultiplexerNode::GetOutputFormat(media_format * outFormat) 1152 { 1153 fprintf(stderr,"MediaDemultiplexerNode::GetOutputFormat\n"); 1154 if (outFormat == 0) { 1155 return; 1156 } 1157 outFormat->type = B_MEDIA_UNKNOWN_TYPE; // more like ANY_TYPE than unknown 1158 outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 1159 outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 1160 } 1161 1162 // protected: 1163 1164 status_t MediaDemultiplexerNode::AddRequirements(media_format * format) 1165 { 1166 fprintf(stderr,"MediaDemultiplexerNode::AddRequirements\n"); 1167 return B_OK; 1168 } 1169 1170 // -------------------------------------------------------- // 1171 // stuffing 1172 // -------------------------------------------------------- // 1173 1174 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_0(void *) {} 1175 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_1(void *) {} 1176 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_2(void *) {} 1177 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_3(void *) {} 1178 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_4(void *) {} 1179 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_5(void *) {} 1180 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_6(void *) {} 1181 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_7(void *) {} 1182 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_8(void *) {} 1183 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_9(void *) {} 1184 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_10(void *) {} 1185 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_11(void *) {} 1186 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_12(void *) {} 1187 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_13(void *) {} 1188 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_14(void *) {} 1189 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_15(void *) {} 1190