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\n"); 285 // change any wild cards to specific values 286 287 return ret; 288 289 } 290 291 292 status_t 293 VideoProducer::FormatChangeRequested(const media_source& source, 294 const media_destination& destination, media_format* ioFormat, 295 int32 *_deprecated_) 296 { 297 TOUCH(destination); TOUCH(ioFormat); TOUCH(_deprecated_); 298 299 if (source != fOutput.source) 300 return B_MEDIA_BAD_SOURCE; 301 302 return B_ERROR; 303 } 304 305 306 status_t 307 VideoProducer::GetNextOutput(int32* cookie, media_output* outOutput) 308 { 309 if (!outOutput) 310 return B_BAD_VALUE; 311 312 if ((*cookie) != 0) 313 return B_BAD_INDEX; 314 315 *outOutput = fOutput; 316 (*cookie)++; 317 318 return B_OK; 319 } 320 321 322 status_t 323 VideoProducer::DisposeOutputCookie(int32 cookie) 324 { 325 TOUCH(cookie); 326 327 return B_OK; 328 } 329 330 331 status_t 332 VideoProducer::SetBufferGroup(const media_source& forSource, 333 BBufferGroup *group) 334 { 335 if (forSource != fOutput.source) 336 return B_MEDIA_BAD_SOURCE; 337 338 TRACE("VideoProducer::SetBufferGroup() - using buffer group of " 339 "consumer.\n"); 340 fUsedBufferGroup = group; 341 342 return B_OK; 343 } 344 345 346 status_t 347 VideoProducer::VideoClippingChanged(const media_source& forSource, 348 int16 numShorts, int16* clipData, const media_video_display_info& display, 349 int32* _deprecated_) 350 { 351 TOUCH(forSource); TOUCH(numShorts); TOUCH(clipData); 352 TOUCH(display); TOUCH(_deprecated_); 353 354 return B_ERROR; 355 } 356 357 358 status_t 359 VideoProducer::GetLatency(bigtime_t* _latency) 360 { 361 if (!_latency) 362 return B_BAD_VALUE; 363 364 *_latency = EventLatency() + SchedulingLatency(); 365 366 return B_OK; 367 } 368 369 370 status_t 371 VideoProducer::PrepareToConnect(const media_source& source, 372 const media_destination& destination, media_format* format, 373 media_source* outSource, char* outName) 374 { 375 FUNCTION("PrepareToConnect() %ldx%ld\n", 376 format->u.raw_video.display.line_width, 377 format->u.raw_video.display.line_count); 378 379 if (fConnected) { 380 ERROR("PrepareToConnect() - already connected!\n"); 381 return B_MEDIA_ALREADY_CONNECTED; 382 } 383 384 if (source != fOutput.source) 385 return B_MEDIA_BAD_SOURCE; 386 387 if (fOutput.destination != media_destination::null) { 388 ERROR("PrepareToConnect() - destination != null.\n"); 389 return B_MEDIA_ALREADY_CONNECTED; 390 } 391 392 // The format parameter comes in with the suggested format, and may be 393 // specialized as desired by the node 394 if (!format_is_compatible(*format, fOutput.format)) { 395 ERROR("PrepareToConnect() - incompatible format.\n"); 396 *format = fOutput.format; 397 return B_MEDIA_BAD_FORMAT; 398 } 399 400 if (format->u.raw_video.display.line_width == 0) 401 format->u.raw_video.display.line_width = 384; 402 if (format->u.raw_video.display.line_count == 0) 403 format->u.raw_video.display.line_count = 288; 404 if (format->u.raw_video.field_rate == 0) 405 format->u.raw_video.field_rate = 25.0; 406 if (format->u.raw_video.display.bytes_per_row == 0) 407 format->u.raw_video.display.bytes_per_row = format->u.raw_video.display.line_width * 4; 408 409 *outSource = fOutput.source; 410 strcpy(outName, fOutput.name); 411 412 return B_OK; 413 } 414 415 416 #define NODE_LATENCY 20000 417 418 419 void 420 VideoProducer::Connect(status_t error, const media_source& source, 421 const media_destination& destination, const media_format& format, 422 char* _name) 423 { 424 FUNCTION("Connect() %ldx%ld\n", 425 format.u.raw_video.display.line_width, 426 format.u.raw_video.display.line_count); 427 428 if (fConnected) { 429 ERROR("Connect() - already connected.\n"); 430 return; 431 } 432 433 if (source != fOutput.source) { 434 ERROR("Connect() - wrong source.\n"); 435 return; 436 } 437 if (error < B_OK) { 438 ERROR("Connect() - consumer error: %s\n", strerror(error)); 439 return; 440 } 441 if (!const_cast<media_format*>(&format)->Matches(&fOutput.format)) { 442 ERROR("Connect() - format mismatch.\n"); 443 return; 444 } 445 446 fOutput.destination = destination; 447 strcpy(_name, fOutput.name); 448 449 if (fOutput.format.u.raw_video.field_rate != 0.0f) { 450 fPerformanceTimeBase = fPerformanceTimeBase 451 + (bigtime_t)((fFrame - fFrameBase) 452 * 1000000 / fOutput.format.u.raw_video.field_rate); 453 fFrameBase = fFrame; 454 } 455 456 fConnectedFormat = format.u.raw_video; 457 if (fConnectedFormat.display.bytes_per_row == 0) { 458 ERROR("Connect() - connected format still has BPR wildcard!\n"); 459 fConnectedFormat.display.bytes_per_row 460 = 4 * fConnectedFormat.display.line_width; 461 } 462 463 // get the latency 464 bigtime_t latency = 0; 465 media_node_id tsID = 0; 466 FindLatencyFor(fOutput.destination, &latency, &tsID); 467 SetEventLatency(latency + NODE_LATENCY); 468 469 // Create the buffer group 470 if (!fUsedBufferGroup) { 471 fBufferGroup = new BBufferGroup(fConnectedFormat.display.bytes_per_row 472 * fConnectedFormat.display.line_count, BUFFER_COUNT); 473 status_t err = fBufferGroup->InitCheck(); 474 if (err < B_OK) { 475 delete fBufferGroup; 476 fBufferGroup = NULL; 477 ERROR("Connect() - buffer group error: %s\n", strerror(err)); 478 return; 479 } 480 fUsedBufferGroup = fBufferGroup; 481 } 482 483 fConnected = true; 484 fEnabled = true; 485 486 // Tell frame generation thread to recalculate delay value 487 release_sem(fFrameSync); 488 } 489 490 491 void 492 VideoProducer::Disconnect(const media_source& source, 493 const media_destination& destination) 494 { 495 FUNCTION("Disconnect()\n"); 496 497 if (!fConnected) { 498 ERROR("Disconnect() - Not connected\n"); 499 return; 500 } 501 502 if ((source != fOutput.source) || (destination != fOutput.destination)) { 503 ERROR("Disconnect() - Bad source and/or destination\n"); 504 return; 505 } 506 507 fEnabled = false; 508 fOutput.destination = media_destination::null; 509 510 if (fLock.Lock()) { 511 // Always delete the buffer group, even if it is not ours. 512 // (See BeBook::SetBufferGroup()). 513 delete fUsedBufferGroup; 514 fUsedBufferGroup = NULL; 515 fBufferGroup = NULL; 516 fLock.Unlock(); 517 } 518 519 fConnected = false; 520 TRACE("Disconnect() done\n"); 521 } 522 523 524 void 525 VideoProducer::LateNoticeReceived(const media_source &source, 526 bigtime_t how_much, bigtime_t performanceTime) 527 { 528 TOUCH(source); TOUCH(how_much); TOUCH(performanceTime); 529 TRACE("Late!!!\n"); 530 } 531 532 533 void 534 VideoProducer::EnableOutput(const media_source& source, bool enabled, 535 int32* _deprecated_) 536 { 537 TOUCH(_deprecated_); 538 539 if (source != fOutput.source) 540 return; 541 542 fEnabled = enabled; 543 } 544 545 546 status_t 547 VideoProducer::SetPlayRate(int32 numer, int32 denom) 548 { 549 TOUCH(numer); TOUCH(denom); 550 551 return B_ERROR; 552 } 553 554 555 void 556 VideoProducer::AdditionalBufferRequested(const media_source& source, 557 media_buffer_id prevBuffer, bigtime_t prevTime, 558 const media_seek_tag* prevTag) 559 { 560 TOUCH(source); TOUCH(prevBuffer); TOUCH(prevTime); TOUCH(prevTag); 561 } 562 563 564 void 565 VideoProducer::LatencyChanged(const media_source& source, 566 const media_destination& destination, 567 bigtime_t newLatency, uint32 flags) 568 { 569 TOUCH(source); TOUCH(destination); TOUCH(newLatency); TOUCH(flags); 570 TRACE("Latency changed!\n"); 571 } 572 573 574 // #pragma mark - 575 576 577 void 578 VideoProducer::_HandleStart(bigtime_t performanceTime) 579 { 580 // Start producing frames, even if the output hasn't been connected yet. 581 TRACE("_HandleStart(%Ld)\n", performanceTime); 582 583 if (fRunning) { 584 TRACE("_HandleStart: Node already started\n"); 585 return; 586 } 587 588 fFrame = 0; 589 fFrameBase = 0; 590 fPerformanceTimeBase = performanceTime; 591 592 fFrameSync = create_sem(0, "frame synchronization"); 593 if (fFrameSync < B_OK) 594 return; 595 596 fThread = spawn_thread(_FrameGeneratorThreadEntry, "frame generator", 597 B_NORMAL_PRIORITY, this); 598 if (fThread < B_OK) { 599 delete_sem(fFrameSync); 600 return; 601 } 602 603 resume_thread(fThread); 604 fRunning = true; 605 return; 606 } 607 608 609 void 610 VideoProducer::_HandleStop() 611 { 612 TRACE("_HandleStop()\n"); 613 614 if (!fRunning) { 615 TRACE("_HandleStop: Node isn't running\n"); 616 return; 617 } 618 619 delete_sem(fFrameSync); 620 wait_for_thread(fThread, &fThread); 621 622 fRunning = false; 623 } 624 625 626 void 627 VideoProducer::_HandleTimeWarp(bigtime_t performanceTime) 628 { 629 fPerformanceTimeBase = performanceTime; 630 fFrameBase = fFrame; 631 632 // Tell frame generation thread to recalculate delay value 633 release_sem(fFrameSync); 634 } 635 636 637 void 638 VideoProducer::_HandleSeek(bigtime_t performanceTime) 639 { 640 fPerformanceTimeBase = performanceTime; 641 fFrameBase = fFrame; 642 643 // Tell frame generation thread to recalculate delay value 644 release_sem(fFrameSync); 645 } 646 647 648 int32 649 VideoProducer::_FrameGeneratorThreadEntry(void* data) 650 { 651 return ((VideoProducer*)data)->_FrameGeneratorThread(); 652 } 653 654 655 int32 656 VideoProducer::_FrameGeneratorThread() 657 { 658 bool forceSendingBuffer = true; 659 bigtime_t lastFrameSentAt = 0; 660 int64 lastPlaylistFrame = 0; 661 bool running = true; 662 while (running) { 663 TRACE("_FrameGeneratorThread: loop: %Ld\n", fFrame); 664 // lock the node manager 665 status_t err = fManager->LockWithTimeout(10000); 666 bool ignoreEvent = false; 667 // Data to be retrieved from the node manager. 668 bigtime_t performanceTime = 0; 669 bigtime_t nextPerformanceTime = 0; 670 bigtime_t waitUntil = 0; 671 bigtime_t nextWaitUntil = 0; 672 bigtime_t maxRenderTime = 0; 673 int32 playingDirection = 0; 674 int32 playingMode = 0; 675 int64 playlistFrame = 0; 676 switch (err) { 677 case B_OK: { 678 TRACE("_FrameGeneratorThread: node manager successfully " 679 "locked\n"); 680 // get the times for the current and the next frame 681 performanceTime = fManager->TimeForFrame(fFrame); 682 nextPerformanceTime = fManager->TimeForFrame(fFrame + 1); 683 maxRenderTime = min_c(bigtime_t(33334 * 0.9), 684 max_c(fSupplier->ProcessingLatency(), maxRenderTime)); 685 playingMode = fManager->PlayModeAtFrame(fFrame); 686 687 waitUntil = TimeSource()->RealTimeFor(fPerformanceTimeBase 688 + performanceTime, 0) - maxRenderTime; 689 nextWaitUntil = TimeSource()->RealTimeFor(fPerformanceTimeBase 690 + nextPerformanceTime, 0) - maxRenderTime; 691 // get playing direction and playlist frame for the current 692 // frame 693 bool newPlayingState; 694 playlistFrame = fManager->PlaylistFrameAtFrame(fFrame, 695 playingDirection, newPlayingState); 696 TRACE("_FrameGeneratorThread: performance time: %Ld, " 697 "playlist frame: %lld\n", performanceTime, playlistFrame); 698 forceSendingBuffer |= newPlayingState; 699 if (lastPlaylistFrame != playlistFrame) { 700 forceSendingBuffer = true; 701 lastPlaylistFrame = playlistFrame; 702 } 703 fManager->SetCurrentVideoTime(nextPerformanceTime); 704 fManager->Unlock(); 705 break; 706 } 707 case B_TIMED_OUT: 708 TRACE("_FrameGeneratorThread: Couldn't lock the node " 709 "manager.\n"); 710 ignoreEvent = true; 711 waitUntil = system_time() - 1; 712 break; 713 default: 714 ERROR("_FrameGeneratorThread: Couldn't lock the node manager. " 715 "Terminating video producer frame generator thread.\n"); 716 TRACE("_FrameGeneratorThread: frame generator thread done.\n"); 717 // do not access any member variables, since this could 718 // also mean the Node has been deleted 719 return B_OK; 720 } 721 722 TRACE("_FrameGeneratorThread: waiting (%Ld)...\n", waitUntil); 723 // wait until... 724 err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT, waitUntil); 725 // The only acceptable responses are B_OK and B_TIMED_OUT. Everything 726 // else means the thread should quit. Deleting the semaphore, as in 727 // VideoProducer::_HandleStop(), will trigger this behavior. 728 switch (err) { 729 case B_OK: 730 TRACE("_FrameGeneratorThread: going back to sleep.\n"); 731 break; 732 case B_TIMED_OUT: 733 TRACE("_FrameGeneratorThread: timed out => event\n"); 734 // Catch the cases in which the node manager could not be 735 // locked and we therefore have no valid data to work with, 736 // or the producer is not running or enabled. 737 if (ignoreEvent || !fRunning || !fEnabled) { 738 TRACE("_FrameGeneratorThread: ignore event\n"); 739 // nothing to do 740 } else if (nextWaitUntil < system_time()) { 741 // Drop frame if it's at least a frame late. 742 printf("VideoProducer: dropped frame (%Ld)\n", fFrame); 743 if (fManager->LockWithTimeout(10000) == B_OK) { 744 fManager->FrameDropped(); 745 fManager->Unlock(); 746 } 747 // next frame 748 fFrame++; 749 } else if (playingDirection != 0 || forceSendingBuffer) { 750 // Send buffers only, if playing, the node is running and 751 // the output has been enabled 752 TRACE("_FrameGeneratorThread: produce frame\n"); 753 BAutolock _(fLock); 754 // Fetch a buffer from the buffer group 755 BBuffer *buffer = fUsedBufferGroup->RequestBuffer( 756 fConnectedFormat.display.bytes_per_row 757 * fConnectedFormat.display.line_count, 0LL); 758 if (buffer) { 759 // Fill out the details about this buffer. 760 media_header *h = buffer->Header(); 761 h->type = B_MEDIA_RAW_VIDEO; 762 h->time_source = TimeSource()->ID(); 763 h->size_used = fConnectedFormat.display.bytes_per_row 764 * fConnectedFormat.display.line_count; 765 // For a buffer originating from a device, you might 766 // want to calculate this based on the 767 // PerformanceTimeFor the time your buffer arrived at 768 // the hardware (plus any applicable adjustments). 769 h->start_time = fPerformanceTimeBase + performanceTime; 770 // TODO: Fix the runmode stuff! Setting the consumer to B_OFFLINE does 771 // not do the trick. I made the VideoConsumer check the performance 772 // time of the buffer and if it is 0, it plays it regardless. 773 if (playingMode < 0) { 774 h->start_time = 0; 775 } 776 h->file_pos = 0; 777 h->orig_size = 0; 778 h->data_offset = 0; 779 h->u.raw_video.field_gamma = 1.0; 780 h->u.raw_video.field_sequence = fFrame; 781 h->u.raw_video.field_number = 0; 782 h->u.raw_video.pulldown_number = 0; 783 h->u.raw_video.first_active_line = 1; 784 h->u.raw_video.line_count 785 = fConnectedFormat.display.line_count; 786 // Fill in a frame 787 media_format mf; 788 mf.type = B_MEDIA_RAW_VIDEO; 789 mf.u.raw_video = fConnectedFormat; 790 TRACE("_FrameGeneratorThread: frame: %Ld, " 791 "playlistFrame: %Ld\n", fFrame, playlistFrame); 792 bool forceOrWasCached = forceSendingBuffer; 793 794 err = fSupplier->FillBuffer(playlistFrame, 795 buffer->Data(), &mf, forceOrWasCached); 796 // clean the buffer if something went wrong 797 if (err != B_OK) { 798 // TODO: should use "back value" according 799 // to color space! 800 memset(buffer->Data(), 0, h->size_used); 801 err = B_OK; 802 } 803 // Send the buffer on down to the consumer 804 if (SendBuffer(buffer, fOutput.destination) < B_OK) { 805 ERROR("_FrameGeneratorThread: Error " 806 "sending buffer\n"); 807 // If there is a problem sending the buffer, 808 // or if we don't send the buffer because its 809 // contents are the same as the last one, 810 // return it to its buffer group. 811 buffer->Recycle(); 812 // we tell the supplier to delete 813 // its caches if there was a problem sending 814 // the buffer 815 fSupplier->DeleteCaches(); 816 } 817 // Only if everything went fine we clear the flag 818 // that forces us to send a buffer even if not 819 // playing. 820 if (err == B_OK) { 821 forceSendingBuffer = false; 822 lastFrameSentAt = performanceTime; 823 } 824 } else { 825 TRACE("_FrameGeneratorThread: no buffer!\n"); 826 // ERROR("_FrameGeneratorThread: no buffer!\n"); 827 } 828 // next frame 829 fFrame++; 830 } else { 831 TRACE("_FrameGeneratorThread: not playing\n"); 832 // next frame 833 fFrame++; 834 } 835 break; 836 default: 837 TRACE("_FrameGeneratorThread: Couldn't acquire semaphore. " 838 "Error: %s\n", strerror(err)); 839 running = false; 840 break; 841 } 842 } 843 TRACE("_FrameGeneratorThread: frame generator thread done.\n"); 844 return B_OK; 845 } 846 847