1 /* Copyright (c) 1998-99, Be Incorporated, All Rights Reserved. 2 * Distributed under the terms of the Be Sample Code license. 3 * 4 * Copyright (c) 2000-2008, Ingo Weinhold <ingo_weinhold@gmx.de>, 5 * Copyright (c) 2000-2008, Stephan Aßmus <superstippi@gmx.de>, 6 * All Rights Reserved. Distributed under the terms of the MIT license. 7 */ 8 #include "VideoProducer.h" 9 10 #include <stdio.h> 11 #include <string.h> 12 13 #include <Autolock.h> 14 #include <Buffer.h> 15 #include <BufferGroup.h> 16 #include <TimeSource.h> 17 18 #include "NodeManager.h" 19 #include "VideoSupplier.h" 20 21 22 // debugging 23 //#define TRACE_VIDEO_PRODUCER 24 #ifdef TRACE_VIDEO_PRODUCER 25 # define TRACE(x...) printf("VideoProducer::"); printf(x) 26 # define FUNCTION(x...) TRACE(x) 27 # define ERROR(x...) fprintf(stderr, "VideoProducer::"); fprintf(stderr, x) 28 #else 29 # define TRACE(x...) 30 # define FUNCTION(x...) 31 # define ERROR(x...) fprintf(stderr, "VideoProducer::"); fprintf(stderr, x) 32 #endif 33 34 35 #define BUFFER_COUNT 3 36 37 #define TOUCH(x) ((void)(x)) 38 39 40 VideoProducer::VideoProducer(BMediaAddOn* addon, const char* name, 41 int32 internalId, NodeManager* manager, VideoSupplier* supplier) 42 : BMediaNode(name), 43 BMediaEventLooper(), 44 BBufferProducer(B_MEDIA_RAW_VIDEO), 45 fInitStatus(B_NO_INIT), 46 fInternalID(internalId), 47 fAddOn(addon), 48 fBufferGroup(NULL), 49 fUsedBufferGroup(NULL), 50 fThread(-1), 51 fFrameSync(-1), 52 fRunning(false), 53 fConnected(false), 54 fEnabled(false), 55 fManager(manager), 56 fSupplier(supplier) 57 { 58 fOutput.destination = media_destination::null; 59 fInitStatus = B_OK; 60 } 61 62 63 VideoProducer::~VideoProducer() 64 { 65 if (fInitStatus == B_OK) { 66 // Clean up after ourselves, in case the application didn't make us 67 // do so. 68 if (fConnected) 69 Disconnect(fOutput.source, fOutput.destination); 70 if (fRunning) 71 _HandleStop(); 72 } 73 Quit(); 74 } 75 76 77 port_id 78 VideoProducer::ControlPort() const 79 { 80 return BMediaNode::ControlPort(); 81 } 82 83 84 BMediaAddOn* 85 VideoProducer::AddOn(int32* _internalId) const 86 { 87 if (_internalId) 88 *_internalId = fInternalID; 89 return fAddOn; 90 } 91 92 93 status_t 94 VideoProducer::HandleMessage(int32 message, const void* data, size_t size) 95 { 96 return B_ERROR; 97 } 98 99 100 void 101 VideoProducer::SetTimeSource(BTimeSource* timeSource) 102 { 103 // Tell frame generation thread to recalculate delay value 104 release_sem(fFrameSync); 105 } 106 107 108 status_t 109 VideoProducer::RequestCompleted(const media_request_info& info) 110 { 111 return BMediaNode::RequestCompleted(info); 112 } 113 114 115 void 116 VideoProducer::NodeRegistered() 117 { 118 if (fInitStatus != B_OK) { 119 ReportError(B_NODE_IN_DISTRESS); 120 return; 121 } 122 123 fOutput.node = Node(); 124 fOutput.source.port = ControlPort(); 125 fOutput.source.id = 0; 126 fOutput.destination = media_destination::null; 127 strcpy(fOutput.name, Name()); 128 129 // fill with wild cards at this point in time 130 fOutput.format.type = B_MEDIA_RAW_VIDEO; 131 fOutput.format.u.raw_video = media_raw_video_format::wildcard; 132 fOutput.format.u.raw_video.interlace = 1; 133 fOutput.format.u.raw_video.display.format = B_NO_COLOR_SPACE; 134 fOutput.format.u.raw_video.display.bytes_per_row = 0; 135 fOutput.format.u.raw_video.display.line_width = 0; 136 fOutput.format.u.raw_video.display.line_count = 0; 137 138 // start the BMediaEventLooper control loop running 139 Run(); 140 } 141 142 143 void 144 VideoProducer::Start(bigtime_t performanceTime) 145 { 146 // notify the manager in case we were started from the outside world 147 // fManager->StartPlaying(); 148 149 BMediaEventLooper::Start(performanceTime); 150 } 151 152 153 void 154 VideoProducer::Stop(bigtime_t performanceTime, bool immediate) 155 { 156 // notify the manager in case we were stopped from the outside world 157 // fManager->StopPlaying(); 158 159 BMediaEventLooper::Stop(performanceTime, immediate); 160 } 161 162 163 void 164 VideoProducer::Seek(bigtime_t media_time, bigtime_t performanceTime) 165 { 166 BMediaEventLooper::Seek(media_time, performanceTime); 167 } 168 169 170 void 171 VideoProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time) 172 { 173 BMediaEventLooper::TimeWarp(at_real_time, to_performance_time); 174 } 175 176 177 status_t 178 VideoProducer::AddTimer(bigtime_t at_performance_time, int32 cookie) 179 { 180 return BMediaEventLooper::AddTimer(at_performance_time, cookie); 181 } 182 183 184 void 185 VideoProducer::SetRunMode(run_mode mode) 186 { 187 printf("VideoProducer::SetRunMode(%d)\n", mode); 188 TRACE("SetRunMode(%d)\n", mode); 189 BMediaEventLooper::SetRunMode(mode); 190 } 191 192 193 void 194 VideoProducer::HandleEvent(const media_timed_event* event, 195 bigtime_t lateness, bool realTimeEvent) 196 { 197 TOUCH(lateness); TOUCH(realTimeEvent); 198 199 switch(event->type) { 200 case BTimedEventQueue::B_START: 201 _HandleStart(event->event_time); 202 break; 203 case BTimedEventQueue::B_STOP: 204 _HandleStop(); 205 break; 206 case BTimedEventQueue::B_WARP: 207 _HandleTimeWarp(event->bigdata); 208 break; 209 case BTimedEventQueue::B_SEEK: 210 _HandleSeek(event->bigdata); 211 break; 212 case BTimedEventQueue::B_HANDLE_BUFFER: 213 case BTimedEventQueue::B_DATA_STATUS: 214 case BTimedEventQueue::B_PARAMETER: 215 default: 216 TRACE("HandleEvent: Unhandled event -- %lx\n", event->type); 217 break; 218 } 219 } 220 221 222 void 223 VideoProducer::CleanUpEvent(const media_timed_event *event) 224 { 225 BMediaEventLooper::CleanUpEvent(event); 226 } 227 228 229 bigtime_t 230 VideoProducer::OfflineTime() 231 { 232 return BMediaEventLooper::OfflineTime(); 233 } 234 235 236 void 237 VideoProducer::ControlLoop() 238 { 239 BMediaEventLooper::ControlLoop(); 240 } 241 242 243 status_t 244 VideoProducer::DeleteHook(BMediaNode* node) 245 { 246 return BMediaEventLooper::DeleteHook(node); 247 } 248 249 250 status_t 251 VideoProducer::FormatSuggestionRequested(media_type type, int32 quality, 252 media_format* _format) 253 { 254 FUNCTION("FormatSuggestionRequested\n"); 255 256 if (type != B_MEDIA_ENCODED_VIDEO) 257 return B_MEDIA_BAD_FORMAT; 258 259 TOUCH(quality); 260 261 *_format = fOutput.format; 262 return B_OK; 263 } 264 265 266 status_t 267 VideoProducer::FormatProposal(const media_source& output, media_format* format) 268 { 269 #ifdef TRACE_VIDEO_PRODUCER 270 char string[256]; 271 string_for_format(*format, string, 256); 272 FUNCTION("FormatProposal(%s)\n", string); 273 #endif 274 275 if (!format) 276 return B_BAD_VALUE; 277 278 if (output != fOutput.source) 279 return B_MEDIA_BAD_SOURCE; 280 281 status_t ret = format_is_compatible(*format, fOutput.format) ? 282 B_OK : B_MEDIA_BAD_FORMAT; 283 if (ret != B_OK) { 284 ERROR("FormatProposal() error: %s\n", strerror(ret)); 285 char string[512]; 286 string_for_format(*format, string, sizeof(string)); 287 ERROR(" requested: %s\n", string); 288 string_for_format(fOutput.format, string, sizeof(string)); 289 ERROR(" output: %s\n", string); 290 } 291 292 // change any wild cards to specific values 293 294 return ret; 295 296 } 297 298 299 status_t 300 VideoProducer::FormatChangeRequested(const media_source& source, 301 const media_destination& destination, media_format* ioFormat, 302 int32 *_deprecated_) 303 { 304 TOUCH(destination); TOUCH(ioFormat); TOUCH(_deprecated_); 305 306 if (source != fOutput.source) 307 return B_MEDIA_BAD_SOURCE; 308 309 return B_ERROR; 310 } 311 312 313 status_t 314 VideoProducer::GetNextOutput(int32* cookie, media_output* outOutput) 315 { 316 if (!outOutput) 317 return B_BAD_VALUE; 318 319 if ((*cookie) != 0) 320 return B_BAD_INDEX; 321 322 *outOutput = fOutput; 323 (*cookie)++; 324 325 return B_OK; 326 } 327 328 329 status_t 330 VideoProducer::DisposeOutputCookie(int32 cookie) 331 { 332 TOUCH(cookie); 333 334 return B_OK; 335 } 336 337 338 status_t 339 VideoProducer::SetBufferGroup(const media_source& forSource, 340 BBufferGroup *group) 341 { 342 if (forSource != fOutput.source) 343 return B_MEDIA_BAD_SOURCE; 344 345 TRACE("VideoProducer::SetBufferGroup() - using buffer group of " 346 "consumer.\n"); 347 fUsedBufferGroup = group; 348 349 return B_OK; 350 } 351 352 353 status_t 354 VideoProducer::VideoClippingChanged(const media_source& forSource, 355 int16 numShorts, int16* clipData, const media_video_display_info& display, 356 int32* _deprecated_) 357 { 358 TOUCH(forSource); TOUCH(numShorts); TOUCH(clipData); 359 TOUCH(display); TOUCH(_deprecated_); 360 361 return B_ERROR; 362 } 363 364 365 status_t 366 VideoProducer::GetLatency(bigtime_t* _latency) 367 { 368 if (!_latency) 369 return B_BAD_VALUE; 370 371 *_latency = EventLatency() + SchedulingLatency(); 372 373 return B_OK; 374 } 375 376 377 status_t 378 VideoProducer::PrepareToConnect(const media_source& source, 379 const media_destination& destination, media_format* format, 380 media_source* outSource, char* outName) 381 { 382 FUNCTION("PrepareToConnect() %ldx%ld\n", 383 format->u.raw_video.display.line_width, 384 format->u.raw_video.display.line_count); 385 386 if (fConnected) { 387 ERROR("PrepareToConnect() - already connected!\n"); 388 return B_MEDIA_ALREADY_CONNECTED; 389 } 390 391 if (source != fOutput.source) 392 return B_MEDIA_BAD_SOURCE; 393 394 if (fOutput.destination != media_destination::null) { 395 ERROR("PrepareToConnect() - destination != null.\n"); 396 return B_MEDIA_ALREADY_CONNECTED; 397 } 398 399 // The format parameter comes in with the suggested format, and may be 400 // specialized as desired by the node 401 if (!format_is_compatible(*format, fOutput.format)) { 402 ERROR("PrepareToConnect() - incompatible format.\n"); 403 *format = fOutput.format; 404 return B_MEDIA_BAD_FORMAT; 405 } 406 407 if (format->u.raw_video.display.line_width == 0) 408 format->u.raw_video.display.line_width = 384; 409 if (format->u.raw_video.display.line_count == 0) 410 format->u.raw_video.display.line_count = 288; 411 if (format->u.raw_video.field_rate == 0) 412 format->u.raw_video.field_rate = 25.0; 413 if (format->u.raw_video.display.bytes_per_row == 0) 414 format->u.raw_video.display.bytes_per_row = format->u.raw_video.display.line_width * 4; 415 416 *outSource = fOutput.source; 417 strcpy(outName, fOutput.name); 418 419 return B_OK; 420 } 421 422 423 #define NODE_LATENCY 20000 424 425 426 void 427 VideoProducer::Connect(status_t error, const media_source& source, 428 const media_destination& destination, const media_format& format, 429 char* _name) 430 { 431 FUNCTION("Connect() %ldx%ld\n", 432 format.u.raw_video.display.line_width, 433 format.u.raw_video.display.line_count); 434 435 if (fConnected) { 436 ERROR("Connect() - already connected.\n"); 437 return; 438 } 439 440 if (source != fOutput.source) { 441 ERROR("Connect() - wrong source.\n"); 442 return; 443 } 444 if (error < B_OK) { 445 ERROR("Connect() - consumer error: %s\n", strerror(error)); 446 return; 447 } 448 if (!const_cast<media_format*>(&format)->Matches(&fOutput.format)) { 449 ERROR("Connect() - format mismatch.\n"); 450 return; 451 } 452 453 fOutput.destination = destination; 454 strcpy(_name, fOutput.name); 455 456 if (fOutput.format.u.raw_video.field_rate != 0.0f) { 457 fPerformanceTimeBase = fPerformanceTimeBase 458 + (bigtime_t)((fFrame - fFrameBase) 459 * 1000000 / fOutput.format.u.raw_video.field_rate); 460 fFrameBase = fFrame; 461 } 462 463 fConnectedFormat = format.u.raw_video; 464 if (fConnectedFormat.display.bytes_per_row == 0) { 465 ERROR("Connect() - connected format still has BPR wildcard!\n"); 466 fConnectedFormat.display.bytes_per_row 467 = 4 * fConnectedFormat.display.line_width; 468 } 469 470 // get the latency 471 bigtime_t latency = 0; 472 media_node_id tsID = 0; 473 FindLatencyFor(fOutput.destination, &latency, &tsID); 474 SetEventLatency(latency + NODE_LATENCY); 475 476 // Create the buffer group 477 if (!fUsedBufferGroup) { 478 fBufferGroup = new BBufferGroup(fConnectedFormat.display.bytes_per_row 479 * fConnectedFormat.display.line_count, BUFFER_COUNT); 480 status_t err = fBufferGroup->InitCheck(); 481 if (err < B_OK) { 482 delete fBufferGroup; 483 fBufferGroup = NULL; 484 ERROR("Connect() - buffer group error: %s\n", strerror(err)); 485 return; 486 } 487 fUsedBufferGroup = fBufferGroup; 488 } 489 490 fConnected = true; 491 fEnabled = true; 492 493 // Tell frame generation thread to recalculate delay value 494 release_sem(fFrameSync); 495 } 496 497 498 void 499 VideoProducer::Disconnect(const media_source& source, 500 const media_destination& destination) 501 { 502 FUNCTION("Disconnect()\n"); 503 504 if (!fConnected) { 505 ERROR("Disconnect() - Not connected\n"); 506 return; 507 } 508 509 if ((source != fOutput.source) || (destination != fOutput.destination)) { 510 ERROR("Disconnect() - Bad source and/or destination\n"); 511 return; 512 } 513 514 fEnabled = false; 515 fOutput.destination = media_destination::null; 516 517 if (fLock.Lock()) { 518 // Always delete the buffer group, even if it is not ours. 519 // (See BeBook::SetBufferGroup()). 520 delete fUsedBufferGroup; 521 fUsedBufferGroup = NULL; 522 fBufferGroup = NULL; 523 fLock.Unlock(); 524 } 525 526 fConnected = false; 527 TRACE("Disconnect() done\n"); 528 } 529 530 531 void 532 VideoProducer::LateNoticeReceived(const media_source &source, 533 bigtime_t how_much, bigtime_t performanceTime) 534 { 535 TOUCH(source); TOUCH(how_much); TOUCH(performanceTime); 536 TRACE("Late!!!\n"); 537 } 538 539 540 void 541 VideoProducer::EnableOutput(const media_source& source, bool enabled, 542 int32* _deprecated_) 543 { 544 TOUCH(_deprecated_); 545 546 if (source != fOutput.source) 547 return; 548 549 fEnabled = enabled; 550 } 551 552 553 status_t 554 VideoProducer::SetPlayRate(int32 numer, int32 denom) 555 { 556 TOUCH(numer); TOUCH(denom); 557 558 return B_ERROR; 559 } 560 561 562 void 563 VideoProducer::AdditionalBufferRequested(const media_source& source, 564 media_buffer_id prevBuffer, bigtime_t prevTime, 565 const media_seek_tag* prevTag) 566 { 567 TOUCH(source); TOUCH(prevBuffer); TOUCH(prevTime); TOUCH(prevTag); 568 } 569 570 571 void 572 VideoProducer::LatencyChanged(const media_source& source, 573 const media_destination& destination, 574 bigtime_t newLatency, uint32 flags) 575 { 576 TOUCH(source); TOUCH(destination); TOUCH(newLatency); TOUCH(flags); 577 TRACE("Latency changed!\n"); 578 } 579 580 581 // #pragma mark - 582 583 584 void 585 VideoProducer::_HandleStart(bigtime_t performanceTime) 586 { 587 // Start producing frames, even if the output hasn't been connected yet. 588 TRACE("_HandleStart(%Ld)\n", performanceTime); 589 590 if (fRunning) { 591 TRACE("_HandleStart: Node already started\n"); 592 return; 593 } 594 595 fFrame = 0; 596 fFrameBase = 0; 597 fPerformanceTimeBase = performanceTime; 598 599 fFrameSync = create_sem(0, "frame synchronization"); 600 if (fFrameSync < B_OK) 601 return; 602 603 fThread = spawn_thread(_FrameGeneratorThreadEntry, "frame generator", 604 B_NORMAL_PRIORITY, this); 605 if (fThread < B_OK) { 606 delete_sem(fFrameSync); 607 return; 608 } 609 610 resume_thread(fThread); 611 fRunning = true; 612 return; 613 } 614 615 616 void 617 VideoProducer::_HandleStop() 618 { 619 TRACE("_HandleStop()\n"); 620 621 if (!fRunning) { 622 TRACE("_HandleStop: Node isn't running\n"); 623 return; 624 } 625 626 delete_sem(fFrameSync); 627 wait_for_thread(fThread, &fThread); 628 629 fRunning = false; 630 } 631 632 633 void 634 VideoProducer::_HandleTimeWarp(bigtime_t performanceTime) 635 { 636 fPerformanceTimeBase = performanceTime; 637 fFrameBase = fFrame; 638 639 // Tell frame generation thread to recalculate delay value 640 release_sem(fFrameSync); 641 } 642 643 644 void 645 VideoProducer::_HandleSeek(bigtime_t performanceTime) 646 { 647 fPerformanceTimeBase = performanceTime; 648 fFrameBase = fFrame; 649 650 // Tell frame generation thread to recalculate delay value 651 release_sem(fFrameSync); 652 } 653 654 655 int32 656 VideoProducer::_FrameGeneratorThreadEntry(void* data) 657 { 658 return ((VideoProducer*)data)->_FrameGeneratorThread(); 659 } 660 661 662 int32 663 VideoProducer::_FrameGeneratorThread() 664 { 665 bool forceSendingBuffer = true; 666 bigtime_t lastFrameSentAt = 0; 667 int64 lastPlaylistFrame = 0; 668 bool running = true; 669 while (running) { 670 TRACE("_FrameGeneratorThread: loop: %Ld\n", fFrame); 671 // lock the node manager 672 status_t err = fManager->LockWithTimeout(10000); 673 bool ignoreEvent = false; 674 // Data to be retrieved from the node manager. 675 bigtime_t performanceTime = 0; 676 bigtime_t nextPerformanceTime = 0; 677 bigtime_t waitUntil = 0; 678 bigtime_t nextWaitUntil = 0; 679 bigtime_t maxRenderTime = 0; 680 int32 playingDirection = 0; 681 int32 playingMode = 0; 682 int64 playlistFrame = 0; 683 switch (err) { 684 case B_OK: { 685 TRACE("_FrameGeneratorThread: node manager successfully " 686 "locked\n"); 687 // get the times for the current and the next frame 688 performanceTime = fManager->TimeForFrame(fFrame); 689 nextPerformanceTime = fManager->TimeForFrame(fFrame + 1); 690 maxRenderTime = min_c(bigtime_t(33334 * 0.9), 691 max_c(fSupplier->ProcessingLatency(), maxRenderTime)); 692 playingMode = fManager->PlayModeAtFrame(fFrame); 693 694 waitUntil = TimeSource()->RealTimeFor(fPerformanceTimeBase 695 + performanceTime, 0) - maxRenderTime; 696 nextWaitUntil = TimeSource()->RealTimeFor(fPerformanceTimeBase 697 + nextPerformanceTime, 0) - maxRenderTime; 698 // get playing direction and playlist frame for the current 699 // frame 700 bool newPlayingState; 701 playlistFrame = fManager->PlaylistFrameAtFrame(fFrame, 702 playingDirection, newPlayingState); 703 TRACE("_FrameGeneratorThread: performance time: %Ld, " 704 "playlist frame: %lld\n", performanceTime, playlistFrame); 705 forceSendingBuffer |= newPlayingState; 706 if (lastPlaylistFrame != playlistFrame) { 707 forceSendingBuffer = true; 708 lastPlaylistFrame = playlistFrame; 709 } 710 fManager->SetCurrentVideoTime(nextPerformanceTime); 711 fManager->Unlock(); 712 break; 713 } 714 case B_TIMED_OUT: 715 TRACE("_FrameGeneratorThread: Couldn't lock the node " 716 "manager.\n"); 717 ignoreEvent = true; 718 waitUntil = system_time() - 1; 719 break; 720 default: 721 ERROR("_FrameGeneratorThread: Couldn't lock the node manager. " 722 "Terminating video producer frame generator thread.\n"); 723 TRACE("_FrameGeneratorThread: frame generator thread done.\n"); 724 // do not access any member variables, since this could 725 // also mean the Node has been deleted 726 return B_OK; 727 } 728 729 TRACE("_FrameGeneratorThread: waiting (%Ld)...\n", waitUntil); 730 // wait until... 731 err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT, waitUntil); 732 // The only acceptable responses are B_OK and B_TIMED_OUT. Everything 733 // else means the thread should quit. Deleting the semaphore, as in 734 // VideoProducer::_HandleStop(), will trigger this behavior. 735 switch (err) { 736 case B_OK: 737 TRACE("_FrameGeneratorThread: going back to sleep.\n"); 738 break; 739 case B_TIMED_OUT: 740 TRACE("_FrameGeneratorThread: timed out => event\n"); 741 // Catch the cases in which the node manager could not be 742 // locked and we therefore have no valid data to work with, 743 // or the producer is not running or enabled. 744 if (ignoreEvent || !fRunning || !fEnabled) { 745 TRACE("_FrameGeneratorThread: ignore event\n"); 746 // nothing to do 747 } else if (nextWaitUntil < system_time()) { 748 // Drop frame if it's at least a frame late. 749 printf("VideoProducer: dropped frame (%Ld)\n", fFrame); 750 if (fManager->LockWithTimeout(10000) == B_OK) { 751 fManager->FrameDropped(); 752 fManager->Unlock(); 753 } 754 // next frame 755 fFrame++; 756 } else if (playingDirection != 0 || forceSendingBuffer) { 757 // Send buffers only, if playing, the node is running and 758 // the output has been enabled 759 TRACE("_FrameGeneratorThread: produce frame\n"); 760 BAutolock _(fLock); 761 // Fetch a buffer from the buffer group 762 BBuffer *buffer = fUsedBufferGroup->RequestBuffer( 763 fConnectedFormat.display.bytes_per_row 764 * fConnectedFormat.display.line_count, 0LL); 765 if (buffer) { 766 // Fill out the details about this buffer. 767 media_header *h = buffer->Header(); 768 h->type = B_MEDIA_RAW_VIDEO; 769 h->time_source = TimeSource()->ID(); 770 h->size_used = fConnectedFormat.display.bytes_per_row 771 * fConnectedFormat.display.line_count; 772 // For a buffer originating from a device, you might 773 // want to calculate this based on the 774 // PerformanceTimeFor the time your buffer arrived at 775 // the hardware (plus any applicable adjustments). 776 h->start_time = fPerformanceTimeBase + performanceTime; 777 // TODO: Fix the runmode stuff! Setting the consumer to B_OFFLINE does 778 // not do the trick. I made the VideoConsumer check the performance 779 // time of the buffer and if it is 0, it plays it regardless. 780 if (playingMode < 0) { 781 h->start_time = 0; 782 } 783 h->file_pos = 0; 784 h->orig_size = 0; 785 h->data_offset = 0; 786 h->u.raw_video.field_gamma = 1.0; 787 h->u.raw_video.field_sequence = fFrame; 788 h->u.raw_video.field_number = 0; 789 h->u.raw_video.pulldown_number = 0; 790 h->u.raw_video.first_active_line = 1; 791 h->u.raw_video.line_count 792 = fConnectedFormat.display.line_count; 793 // Fill in a frame 794 media_format mf; 795 mf.type = B_MEDIA_RAW_VIDEO; 796 mf.u.raw_video = fConnectedFormat; 797 TRACE("_FrameGeneratorThread: frame: %Ld, " 798 "playlistFrame: %Ld\n", fFrame, playlistFrame); 799 bool forceOrWasCached = forceSendingBuffer; 800 801 err = fSupplier->FillBuffer(playlistFrame, 802 buffer->Data(), &mf, forceOrWasCached); 803 // clean the buffer if something went wrong 804 if (err != B_OK) { 805 // TODO: should use "back value" according 806 // to color space! 807 memset(buffer->Data(), 0, h->size_used); 808 err = B_OK; 809 } 810 // Send the buffer on down to the consumer 811 if (SendBuffer(buffer, fOutput.destination) < B_OK) { 812 ERROR("_FrameGeneratorThread: Error " 813 "sending buffer\n"); 814 // If there is a problem sending the buffer, 815 // or if we don't send the buffer because its 816 // contents are the same as the last one, 817 // return it to its buffer group. 818 buffer->Recycle(); 819 // we tell the supplier to delete 820 // its caches if there was a problem sending 821 // the buffer 822 fSupplier->DeleteCaches(); 823 } 824 // Only if everything went fine we clear the flag 825 // that forces us to send a buffer even if not 826 // playing. 827 if (err == B_OK) { 828 forceSendingBuffer = false; 829 lastFrameSentAt = performanceTime; 830 } 831 } else { 832 TRACE("_FrameGeneratorThread: no buffer!\n"); 833 // ERROR("_FrameGeneratorThread: no buffer!\n"); 834 } 835 // next frame 836 fFrame++; 837 } else { 838 TRACE("_FrameGeneratorThread: not playing\n"); 839 // next frame 840 fFrame++; 841 } 842 break; 843 default: 844 TRACE("_FrameGeneratorThread: Couldn't acquire semaphore. " 845 "Error: %s\n", strerror(err)); 846 running = false; 847 break; 848 } 849 } 850 TRACE("_FrameGeneratorThread: frame generator thread done.\n"); 851 return B_OK; 852 } 853 854