1 /* 2 * This file is a part of BeOS USBVision driver project. 3 * Copyright (c) 2003 by Siarzuk Zharski <imker@gmx.li> 4 * 5 * This file may be used under the terms of the BSD License 6 * 7 * Skeletal part of this code was inherired from original BeOS sample code, 8 * that is distributed under the terms of the Be Sample Code License. 9 * 10 */ 11 12 #include <fcntl.h> 13 #include <malloc.h> 14 #include <math.h> 15 #include <stdio.h> 16 #include <string.h> 17 #include <sys/uio.h> 18 #include <unistd.h> 19 20 #include <media/Buffer.h> 21 #include <media/BufferGroup.h> 22 #include <media/ParameterWeb.h> 23 #include <media/TimeSource.h> 24 25 #include <support/Autolock.h> 26 #include <support/Debug.h> 27 28 #define TOUCH(x) ((void)(x)) 29 30 #define PRINTF(a,b) \ 31 do { \ 32 if (a < 2) { \ 33 printf("VideoProducer::"); \ 34 printf b; \ 35 } \ 36 } while (0) 37 38 #include "Producer.h" 39 40 #define FIELD_RATE 30.f 41 42 const float kUSBBandWidthMin = 0.5f; 43 const float kUSBBandWidthMax = 7.5f; 44 const float kUSBBandWidthStep = 0.5f; 45 46 const float kVScreenOffsetMin = 0.f; 47 const float kVScreenOffsetMax = 4.f; 48 const float kVScreenOffsetStep = 1.f; 49 const float kHScreenOffsetMin = 0.f; 50 const float kHScreenOffsetMax = 4.f; 51 const float kHScreenOffsetStep = 1.f; 52 53 const float kEffectMin = 0.f; 54 const float kEffectMax = 31.f; 55 const float kEffectStep = 1.f; 56 57 const float kBrightnessMin = kEffectMin; 58 const float kBrightnessMax = kEffectMax; 59 const float kBrightnessStep = kEffectStep; 60 61 const float kContrastMin = kEffectMin; 62 const float kContrastMax = kEffectMax; 63 const float kContrastStep = kEffectStep; 64 65 const float kHueMin = kEffectMin; 66 const float kHueMax = kEffectMax; 67 const float kHueStep = kEffectStep; 68 69 const float kSaturationMin = kEffectMin; 70 const float kSaturationMax = kEffectMax; 71 const float kSaturationStep = kEffectStep; 72 73 const uint32 kDefChannel = 0; 74 //const VideoInput kDefVideoInput = P_VI_TUNER; 75 const uint32 kDefAudioInput = 0; 76 const uint32 kDefBrightness = 20; 77 const uint32 kDefContrast = 22; 78 const uint32 kDefSaturation = 15; 79 const uint32 kDefHue = 20; 80 const uint32 kDefCaptureSize = 0; 81 const uint32 kDefCaptureFormat = 0; 82 //const VideoStandard kDefStandard = P_VF_PAL_BDGHI; 83 const float kDefBandwidth = 7.0; 84 const uint32 kDefLocale = 0; 85 const uint32 kDefVertOffset = 1; 86 const uint32 kDefHorzOffset = 2; 87 88 int32 VideoProducer::fInstances = 0; 89 90 VideoProducer::VideoProducer( 91 BMediaAddOn *addon, const char *name, int32 internal_id) 92 : BMediaNode(name), 93 BMediaEventLooper(), 94 BBufferProducer(B_MEDIA_RAW_VIDEO), 95 BControllable() 96 { 97 status_t err; 98 99 fInitStatus = B_NO_INIT; 100 101 /* Only allow one instance of the node to exist at any time */ 102 if (atomic_add(&fInstances, 1) != 0) 103 return; 104 105 fInternalID = internal_id; 106 fAddOn = addon; 107 108 fBufferGroup = NULL; 109 110 fThread = -1; 111 fFrameSync = -1; 112 fProcessingLatency = 0LL; 113 114 fRunning = false; 115 fConnected = false; 116 fEnabled = false; 117 118 fOutput.destination = media_destination::null; 119 120 AddNodeKind(B_PHYSICAL_INPUT); 121 122 fInitStatus = B_OK; 123 124 //debugger("op-op"); 125 126 status_t status = Locale::TunerLocale::LoadLocales(fLocales); 127 128 printf("LoadLocales:%08x\n", status); 129 130 fChannel = kDefChannel; 131 fVideoInput = P_VI_TUNER; 132 fAudioInput = kDefAudioInput; 133 fBrightness = kDefBrightness; 134 fContrast = kDefContrast; 135 fSaturation = kDefSaturation; 136 fHue = kDefHue; 137 fCaptureSize = kDefCaptureSize; 138 fCaptureFormat = kDefCaptureFormat; 139 fStandard = P_VF_PAL_BDGHI; 140 fLocale = kDefLocale; 141 fBandwidth = kDefBandwidth; 142 fVertOffset = kDefVertOffset; 143 fHorzOffset = kDefHorzOffset; 144 fColor = B_HOST_TO_LENDIAN_INT32(0x00ff0000); 145 146 fLastChannelChange = 147 fLastVideoInputChange = 148 fLastAudioInputChange = 149 fLastBrightnessChange = 150 fLastContrastChange = 151 fLastSaturationChange = 152 fLastHueChange = 153 fLastCaptureSizeChange = 154 fLastCaptureFormatChange = 155 fLastStandardChange = 156 fLastLocaleChange = 157 fLastBandwidthChange = 158 fLastVertOffsetChange = 159 fLastHorzOffsetChange = 160 fLastColorChange = system_time(); 161 162 return; 163 } 164 165 VideoProducer::~VideoProducer() 166 { 167 if (fInitStatus == B_OK) { 168 /* Clean up after ourselves, in case the application didn't make us 169 * do so. */ 170 if (fConnected) 171 Disconnect(fOutput.source, fOutput.destination); 172 if (fRunning) 173 HandleStop(); 174 } 175 176 atomic_add(&fInstances, -1); 177 178 Locale::TunerLocale::ReleaseLocales(fLocales); 179 } 180 181 /* BMediaNode */ 182 183 port_id 184 VideoProducer::ControlPort() const 185 { 186 return BMediaNode::ControlPort(); 187 } 188 189 BMediaAddOn * 190 VideoProducer::AddOn(int32 *internal_id) const 191 { 192 if (internal_id) 193 *internal_id = fInternalID; 194 return fAddOn; 195 } 196 197 status_t 198 VideoProducer::HandleMessage(int32 message, const void *data, size_t size) 199 { 200 return B_ERROR; 201 } 202 203 void 204 VideoProducer::Preroll() 205 { 206 /* This hook may be called before the node is started to give the hardware 207 * a chance to start. */ 208 } 209 210 void 211 VideoProducer::SetTimeSource(BTimeSource *time_source) 212 { 213 /* Tell frame generation thread to recalculate delay value */ 214 release_sem(fFrameSync); 215 } 216 217 status_t 218 VideoProducer::RequestCompleted(const media_request_info &info) 219 { 220 return BMediaNode::RequestCompleted(info); 221 } 222 223 /* BMediaEventLooper */ 224 225 void 226 VideoProducer::NodeRegistered() 227 { 228 if (fInitStatus != B_OK) { 229 ReportError(B_NODE_IN_DISTRESS); 230 return; 231 } 232 233 /* After this call, the BControllable owns the BParameterWeb object and 234 * will delete it for you */ 235 SetParameterWeb(CreateParameterWeb()); 236 237 fOutput.node = Node(); 238 fOutput.source.port = ControlPort(); 239 fOutput.source.id = 0; 240 fOutput.destination = media_destination::null; 241 strcpy(fOutput.name, Name()); 242 243 /* Tailor these for the output of your device */ 244 fOutput.format.type = B_MEDIA_RAW_VIDEO; 245 fOutput.format.u.raw_video = media_raw_video_format::wildcard; 246 fOutput.format.u.raw_video.interlace = 1; 247 fOutput.format.u.raw_video.display.format = B_RGB32; 248 249 /* Start the BMediaEventLooper control loop running */ 250 Run(); 251 } 252 253 BParameterWeb *VideoProducer::CreateParameterWeb() 254 { 255 /* Set up the parameter web */ 256 BParameterWeb *web = new BParameterWeb(); 257 258 BParameterGroup *controls = web->MakeGroup("Controls"); 259 BParameterGroup *group = controls->MakeGroup("Main Controls"); 260 BDiscreteParameter *parameter = group->MakeDiscreteParameter( 261 P_CHANNEL, B_MEDIA_NO_TYPE, "Channel:", B_GENERIC); 262 for(int i = 0; i < fLocales[fLocale]->ChannelsCount(); i ++){ 263 parameter->AddItem(i, (fLocales[fLocale]->GetChannel(i)).Name().c_str()); 264 } 265 266 parameter = group->MakeDiscreteParameter( 267 P_VIDEO_INPUT, B_MEDIA_NO_TYPE, "Video Input:", B_INPUT_MUX); 268 parameter->AddItem(P_VI_TUNER, "Tuner"); 269 parameter->AddItem(P_VI_COMPOSITE, "Composite"); 270 parameter->AddItem(P_VI_SVIDEO, "SVideo"); 271 272 parameter = group->MakeDiscreteParameter( 273 P_AUDIO_INPUT, B_MEDIA_NO_TYPE, "Audio Input:", B_INPUT_MUX); 274 parameter->AddItem(1, "TODO"); 275 parameter->AddItem(2, "TODO"); 276 parameter->AddItem(3, "TODO"); 277 278 group = controls->MakeGroup("Effect Controls"); 279 group->MakeContinuousParameter( 280 P_BRIGHTNESS, B_MEDIA_NO_TYPE, "Brightness", B_LEVEL, 281 "", kBrightnessMin, kBrightnessMax, kBrightnessStep); 282 283 group->MakeContinuousParameter( 284 P_CONTRAST, B_MEDIA_NO_TYPE, "Contrast", B_LEVEL, 285 "", kContrastMin, kContrastMax, kContrastStep); 286 287 group = controls->MakeGroup("Adv. Effect Controls"); 288 group->MakeContinuousParameter( 289 P_SATURATION, B_MEDIA_NO_TYPE, "Saturation", B_LEVEL, 290 "", kSaturationMin, kSaturationMax, kSaturationStep); 291 292 group->MakeContinuousParameter( 293 P_HUE, B_MEDIA_NO_TYPE, "Hue", B_LEVEL, 294 "", kHueMin, kHueMax, kHueStep); 295 296 BParameterGroup *options = web->MakeGroup("Options"); 297 group = options->MakeGroup("Capture Option"); 298 parameter = group->MakeDiscreteParameter( 299 P_CAPTURE_SIZE, B_MEDIA_NO_TYPE, "Capture Size:", B_RESOLUTION); 300 parameter->AddItem(1, "TODO"); 301 parameter->AddItem(2, "TODO"); 302 303 parameter = group->MakeDiscreteParameter( 304 P_CAPTURE_FORMAT, B_MEDIA_NO_TYPE, "Capture Format:", B_COLOR_SPACE); 305 parameter->AddItem(1, "TODO"); 306 parameter->AddItem(2, "TODO"); 307 308 BParameterGroup *hardware = web->MakeGroup("Hardware Setup"); 309 group = hardware->MakeGroup("Format"); 310 parameter = group->MakeDiscreteParameter( 311 P_STANDART, B_MEDIA_NO_TYPE, "Video Format:", B_VIDEO_FORMAT); 312 parameter->AddItem(P_VF_NTSC_M, "NTSC M"); 313 parameter->AddItem(P_VF_NTSC_MJ, "NTSC MJ"); 314 parameter->AddItem(P_VF_PAL_BDGHI, "PAL BDGHI"); 315 parameter->AddItem(P_VF_PAL_M, "PAL M"); 316 parameter->AddItem(P_VF_PAL_N, "PAL N"); 317 parameter->AddItem(P_VF_SECAM, "SECAM"); 318 319 parameter = group->MakeDiscreteParameter( 320 P_LOCALE, B_MEDIA_NO_TYPE, "Tuner Locale:", B_GENERIC); 321 for(int i = 0; i < fLocales.size(); i++) 322 parameter->AddItem(i, fLocales[i]->Name().c_str()); 323 324 group = hardware->MakeGroup("Format"); 325 326 group->MakeContinuousParameter( 327 P_BANDWIDTH, B_MEDIA_NO_TYPE, "Max.Bandwidth", B_LEVEL, 328 "", kUSBBandWidthMin, kUSBBandWidthMax, kUSBBandWidthStep); 329 330 group = hardware->MakeGroup("Offsets"); 331 332 group->MakeContinuousParameter( 333 P_VERT_OFFSET, B_MEDIA_NO_TYPE, "Vertical Offset", B_LEVEL, 334 "", kVScreenOffsetMin, kVScreenOffsetMax, kVScreenOffsetStep); 335 336 group->MakeContinuousParameter( 337 P_HORZ_OFFSET, B_MEDIA_NO_TYPE, "Horizontal Offset", B_LEVEL, 338 "", kHScreenOffsetMin, kHScreenOffsetMax, kHScreenOffsetStep); 339 340 BParameterGroup *main = web->MakeGroup(Name()); 341 BDiscreteParameter *state = main->MakeDiscreteParameter( 342 P_COLOR, B_MEDIA_RAW_VIDEO, "Color", "Color"); 343 state->AddItem(B_HOST_TO_LENDIAN_INT32(0x00ff0000), "Red"); 344 state->AddItem(B_HOST_TO_LENDIAN_INT32(0x0000ff00), "Green"); 345 state->AddItem(B_HOST_TO_LENDIAN_INT32(0x000000ff), "Blue"); 346 347 return web; 348 } 349 350 void 351 VideoProducer::Start(bigtime_t performance_time) 352 { 353 BMediaEventLooper::Start(performance_time); 354 } 355 356 void 357 VideoProducer::Stop(bigtime_t performance_time, bool immediate) 358 { 359 BMediaEventLooper::Stop(performance_time, immediate); 360 } 361 362 void 363 VideoProducer::Seek(bigtime_t media_time, bigtime_t performance_time) 364 { 365 BMediaEventLooper::Seek(media_time, performance_time); 366 } 367 368 void 369 VideoProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time) 370 { 371 BMediaEventLooper::TimeWarp(at_real_time, to_performance_time); 372 } 373 374 status_t 375 VideoProducer::AddTimer(bigtime_t at_performance_time, int32 cookie) 376 { 377 return BMediaEventLooper::AddTimer(at_performance_time, cookie); 378 } 379 380 void 381 VideoProducer::SetRunMode(run_mode mode) 382 { 383 BMediaEventLooper::SetRunMode(mode); 384 } 385 386 void 387 VideoProducer::HandleEvent(const media_timed_event *event, 388 bigtime_t lateness, bool realTimeEvent) 389 { 390 TOUCH(lateness); TOUCH(realTimeEvent); 391 392 switch(event->type) 393 { 394 case BTimedEventQueue::B_START: 395 HandleStart(event->event_time); 396 break; 397 case BTimedEventQueue::B_STOP: 398 HandleStop(); 399 break; 400 case BTimedEventQueue::B_WARP: 401 HandleTimeWarp(event->bigdata); 402 break; 403 case BTimedEventQueue::B_SEEK: 404 HandleSeek(event->bigdata); 405 break; 406 case BTimedEventQueue::B_PARAMETER: 407 HandleParameter(event->data); 408 break; 409 case BTimedEventQueue::B_HANDLE_BUFFER: 410 case BTimedEventQueue::B_DATA_STATUS: 411 default: 412 PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type)); 413 break; 414 } 415 } 416 417 void 418 VideoProducer::CleanUpEvent(const media_timed_event *event) 419 { 420 BMediaEventLooper::CleanUpEvent(event); 421 } 422 423 bigtime_t 424 VideoProducer::OfflineTime() 425 { 426 return BMediaEventLooper::OfflineTime(); 427 } 428 429 void 430 VideoProducer::ControlLoop() 431 { 432 BMediaEventLooper::ControlLoop(); 433 } 434 435 status_t 436 VideoProducer::DeleteHook(BMediaNode * node) 437 { 438 return BMediaEventLooper::DeleteHook(node); 439 } 440 441 /* BBufferProducer */ 442 443 status_t 444 VideoProducer::FormatSuggestionRequested( 445 media_type type, int32 quality, media_format *format) 446 { 447 if (type != B_MEDIA_ENCODED_VIDEO) 448 return B_MEDIA_BAD_FORMAT; 449 450 TOUCH(quality); 451 452 *format = fOutput.format; 453 return B_OK; 454 } 455 456 status_t 457 VideoProducer::FormatProposal(const media_source &output, media_format *format) 458 { 459 status_t err; 460 461 if (!format) 462 return B_BAD_VALUE; 463 464 if (output != fOutput.source) 465 return B_MEDIA_BAD_SOURCE; 466 467 err = format_is_compatible(*format, fOutput.format) ? 468 B_OK : B_MEDIA_BAD_FORMAT; 469 *format = fOutput.format; 470 return err; 471 472 } 473 474 status_t 475 VideoProducer::FormatChangeRequested(const media_source &source, 476 const media_destination &destination, media_format *io_format, 477 int32 *_deprecated_) 478 { 479 TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_); 480 if (source != fOutput.source) 481 return B_MEDIA_BAD_SOURCE; 482 483 return B_ERROR; 484 } 485 486 status_t 487 VideoProducer::GetNextOutput(int32 *cookie, media_output *out_output) 488 { 489 if (!out_output) 490 return B_BAD_VALUE; 491 492 if ((*cookie) != 0) 493 return B_BAD_INDEX; 494 495 *out_output = fOutput; 496 (*cookie)++; 497 return B_OK; 498 } 499 500 status_t 501 VideoProducer::DisposeOutputCookie(int32 cookie) 502 { 503 TOUCH(cookie); 504 505 return B_OK; 506 } 507 508 status_t 509 VideoProducer::SetBufferGroup(const media_source &for_source, 510 BBufferGroup *group) 511 { 512 TOUCH(for_source); TOUCH(group); 513 514 return B_ERROR; 515 } 516 517 status_t 518 VideoProducer::VideoClippingChanged(const media_source &for_source, 519 int16 num_shorts, int16 *clip_data, 520 const media_video_display_info &display, int32 *_deprecated_) 521 { 522 TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data); 523 TOUCH(display); TOUCH(_deprecated_); 524 525 return B_ERROR; 526 } 527 528 status_t 529 VideoProducer::GetLatency(bigtime_t *out_latency) 530 { 531 *out_latency = EventLatency() + SchedulingLatency(); 532 return B_OK; 533 } 534 535 status_t 536 VideoProducer::PrepareToConnect(const media_source &source, 537 const media_destination &destination, media_format *format, 538 media_source *out_source, char *out_name) 539 { 540 status_t err; 541 542 PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \ 543 format->u.raw_video.display.line_width, \ 544 format->u.raw_video.display.line_count)); 545 546 if (fConnected) { 547 PRINTF(0, ("PrepareToConnect: Already connected\n")); 548 return EALREADY; 549 } 550 551 if (source != fOutput.source) 552 return B_MEDIA_BAD_SOURCE; 553 554 if (fOutput.destination != media_destination::null) 555 return B_MEDIA_ALREADY_CONNECTED; 556 557 /* The format parameter comes in with the suggested format, and may be 558 * specialized as desired by the node */ 559 if (!format_is_compatible(*format, fOutput.format)) { 560 *format = fOutput.format; 561 return B_MEDIA_BAD_FORMAT; 562 } 563 564 if (format->u.raw_video.display.line_width == 0) 565 format->u.raw_video.display.line_width = 320; 566 if (format->u.raw_video.display.line_count == 0) 567 format->u.raw_video.display.line_count = 240; 568 if (format->u.raw_video.field_rate == 0) 569 format->u.raw_video.field_rate = 29.97f; 570 571 *out_source = fOutput.source; 572 strcpy(out_name, fOutput.name); 573 574 fOutput.destination = destination; 575 576 return B_OK; 577 } 578 579 void 580 VideoProducer::Connect(status_t error, const media_source &source, 581 const media_destination &destination, const media_format &format, 582 char *io_name) 583 { 584 PRINTF(1, ("Connect() %ldx%ld\n", \ 585 format.u.raw_video.display.line_width, \ 586 format.u.raw_video.display.line_count)); 587 588 if (fConnected) { 589 PRINTF(0, ("Connect: Already connected\n")); 590 return; 591 } 592 593 if ( (source != fOutput.source) || (error < B_OK) || 594 !const_cast<media_format *>(&format)->Matches(&fOutput.format)) { 595 PRINTF(1, ("Connect: Connect error\n")); 596 return; 597 } 598 599 fOutput.destination = destination; 600 strcpy(io_name, fOutput.name); 601 602 if (fOutput.format.u.raw_video.field_rate != 0.0f) { 603 fPerformanceTimeBase = fPerformanceTimeBase + 604 (bigtime_t) 605 ((fFrame - fFrameBase) * 606 (1000000 / fOutput.format.u.raw_video.field_rate)); 607 fFrameBase = fFrame; 608 } 609 610 fConnectedFormat = format.u.raw_video; 611 612 /* get the latency */ 613 bigtime_t latency = 0; 614 media_node_id tsID = 0; 615 FindLatencyFor(fOutput.destination, &latency, &tsID); 616 #define NODE_LATENCY 1000 617 SetEventLatency(latency + NODE_LATENCY); 618 619 uint32 *buffer, *p, f = 3; 620 p = buffer = (uint32 *)malloc(4 * fConnectedFormat.display.line_count * 621 fConnectedFormat.display.line_width); 622 if (!buffer) { 623 PRINTF(0, ("Connect: Out of memory\n")); 624 return; 625 } 626 bigtime_t now = system_time(); 627 for (int y=0;y<fConnectedFormat.display.line_count;y++) 628 for (int x=0;x<fConnectedFormat.display.line_width;x++) 629 *(p++) = ((((x+y)^0^x)+f) & 0xff) * (0x01010101 & fColor); 630 fProcessingLatency = system_time() - now; 631 free(buffer); 632 633 /* Create the buffer group */ 634 fBufferGroup = new BBufferGroup(4 * fConnectedFormat.display.line_width * 635 fConnectedFormat.display.line_count, 8); 636 if (fBufferGroup->InitCheck() < B_OK) { 637 delete fBufferGroup; 638 fBufferGroup = NULL; 639 return; 640 } 641 642 fConnected = true; 643 fEnabled = true; 644 645 /* Tell frame generation thread to recalculate delay value */ 646 release_sem(fFrameSync); 647 } 648 649 void 650 VideoProducer::Disconnect(const media_source &source, 651 const media_destination &destination) 652 { 653 PRINTF(1, ("Disconnect()\n")); 654 655 if (!fConnected) { 656 PRINTF(0, ("Disconnect: Not connected\n")); 657 return; 658 } 659 660 if ((source != fOutput.source) || (destination != fOutput.destination)) { 661 PRINTF(0, ("Disconnect: Bad source and/or destination\n")); 662 return; 663 } 664 665 fEnabled = false; 666 fOutput.destination = media_destination::null; 667 668 fLock.Lock(); 669 delete fBufferGroup; 670 fBufferGroup = NULL; 671 fLock.Unlock(); 672 673 fConnected = false; 674 } 675 676 void 677 VideoProducer::LateNoticeReceived(const media_source &source, 678 bigtime_t how_much, bigtime_t performance_time) 679 { 680 TOUCH(source); TOUCH(how_much); TOUCH(performance_time); 681 } 682 683 void 684 VideoProducer::EnableOutput(const media_source &source, bool enabled, 685 int32 *_deprecated_) 686 { 687 TOUCH(_deprecated_); 688 689 if (source != fOutput.source) 690 return; 691 692 fEnabled = enabled; 693 } 694 695 status_t 696 VideoProducer::SetPlayRate(int32 numer, int32 denom) 697 { 698 TOUCH(numer); TOUCH(denom); 699 700 return B_ERROR; 701 } 702 703 void 704 VideoProducer::AdditionalBufferRequested(const media_source &source, 705 media_buffer_id prev_buffer, bigtime_t prev_time, 706 const media_seek_tag *prev_tag) 707 { 708 TOUCH(source); TOUCH(prev_buffer); TOUCH(prev_time); TOUCH(prev_tag); 709 } 710 711 void 712 VideoProducer::LatencyChanged(const media_source &source, 713 const media_destination &destination, bigtime_t new_latency, 714 uint32 flags) 715 { 716 TOUCH(source); TOUCH(destination); TOUCH(new_latency); TOUCH(flags); 717 } 718 719 /* BControllable */ 720 721 status_t 722 VideoProducer::GetParameterValue( 723 int32 id, bigtime_t *last_change, void *value, size_t *size) 724 { 725 switch(id){ 726 case P_CHANNEL: 727 *last_change = fLastChannelChange; 728 *size = sizeof(uint32); 729 *((uint32*)value) = fChannel; 730 break; 731 case P_VIDEO_INPUT: 732 *last_change = fLastVideoInputChange; 733 *size = sizeof(uint32); 734 *((uint32*)value) = fVideoInput; 735 break; 736 case P_AUDIO_INPUT: 737 *last_change = fLastAudioInputChange; 738 *size = sizeof(uint32); 739 *((uint32*)value) = fAudioInput; 740 break; 741 case P_BRIGHTNESS: 742 *last_change = fLastBrightnessChange; 743 *size = sizeof(float); 744 *((float *)value) = fBrightness; 745 break; 746 case P_CONTRAST: 747 *last_change = fLastContrastChange; 748 *size = sizeof(float); 749 *((float*)value) = fContrast; 750 break; 751 case P_SATURATION: 752 *last_change = fLastSaturationChange; 753 *size = sizeof(float); 754 *((float*)value) = fSaturation; 755 break; 756 case P_HUE: 757 *last_change = fLastHueChange; 758 *size = sizeof(float); 759 *((float*)value) = fHue; 760 break; 761 case P_CAPTURE_SIZE: 762 *last_change = fLastCaptureSizeChange; 763 *size = sizeof(uint32); 764 *((uint32*)value) = fCaptureSize; 765 break; 766 case P_CAPTURE_FORMAT: 767 *last_change = fLastCaptureFormatChange; 768 *size = sizeof(uint32); 769 *((uint32*)value) = fCaptureFormat; 770 break; 771 case P_STANDART: 772 *last_change = fLastStandardChange; 773 *size = sizeof(uint32); 774 *((uint32*)value) = fStandard; 775 break; 776 case P_BANDWIDTH: 777 *last_change = fLastBandwidthChange; 778 *size = sizeof(float); 779 *((float *)value) = fBandwidth; 780 break; 781 case P_LOCALE: 782 *last_change = fLastLocaleChange; 783 *size = sizeof(uint32); 784 *((uint32*)value) = fLocale; 785 break; 786 case P_VERT_OFFSET: 787 *last_change = fLastVertOffsetChange; 788 *size = sizeof(float); 789 *((float*)value) = fVertOffset; 790 break; 791 case P_HORZ_OFFSET: 792 *last_change = fLastHorzOffsetChange; 793 *size = sizeof(float); 794 *((float*)value) = fHorzOffset; 795 break; 796 case P_COLOR: 797 *last_change = fLastColorChange; 798 *size = sizeof(uint32); 799 *((uint32 *)value) = fColor; 800 break; 801 default: 802 return B_BAD_VALUE; 803 } 804 return B_OK; 805 } 806 807 void 808 VideoProducer::SetParameterValue( 809 int32 id, bigtime_t when, const void *value, size_t size) 810 { 811 switch(id){ 812 case P_CHANNEL: 813 if (*(uint32 *)value != fChannel){ 814 fChannel = *(uint32 *)value; 815 fLastChannelChange = when; 816 BroadcastNewParameterValue( 817 fLastChannelChange, P_CHANNEL, &fChannel, sizeof(fChannel)); 818 } 819 break; 820 case P_VIDEO_INPUT: 821 if (*(uint32 *)value != fVideoInput){ 822 fVideoInput = *(uint32 *)value; 823 fLastVideoInputChange = when; 824 BroadcastNewParameterValue( 825 fLastVideoInputChange, P_VIDEO_INPUT, &fVideoInput, sizeof(fVideoInput)); 826 } 827 break; 828 case P_AUDIO_INPUT: 829 if (*(uint32 *)value != fAudioInput){ 830 fAudioInput = *(uint32 *)value; 831 fLastAudioInputChange = when; 832 BroadcastNewParameterValue( 833 fLastAudioInputChange, P_AUDIO_INPUT, &fAudioInput, sizeof(fAudioInput)); 834 } 835 break; 836 case P_BRIGHTNESS: 837 if (*(float *)value != fBrightness){ 838 fBrightness = *(float *)value; 839 fLastBrightnessChange = when; 840 BroadcastNewParameterValue( 841 fLastBrightnessChange, P_BRIGHTNESS, &fBrightness, sizeof(fBrightness)); 842 } 843 break; 844 case P_CONTRAST: 845 if (*(float *)value != fContrast){ 846 fContrast = *(float *)value; 847 fLastContrastChange = when; 848 BroadcastNewParameterValue( 849 fLastContrastChange, P_CONTRAST, &fContrast, sizeof(fContrast)); 850 } 851 break; 852 case P_SATURATION: 853 if (*(float *)value != fSaturation){ 854 fSaturation = *(float *)value; 855 fLastSaturationChange = when; 856 BroadcastNewParameterValue( 857 fLastSaturationChange, P_SATURATION, &fSaturation, sizeof(fSaturation)); 858 } 859 break; 860 case P_HUE: 861 if (*(float *)value != fHue){ 862 fHue = *(float *)value; 863 fLastHueChange = when; 864 BroadcastNewParameterValue( 865 fLastHueChange, P_HUE, &fHue, sizeof(fHue)); 866 } 867 break; 868 case P_CAPTURE_SIZE: 869 if (*(uint32 *)value != fCaptureSize){ 870 fCaptureSize = *(uint32*)value; 871 fLastCaptureSizeChange = when; 872 BroadcastNewParameterValue( 873 fLastCaptureSizeChange, P_CAPTURE_SIZE, &fCaptureSize, sizeof(fCaptureSize)); 874 } 875 break; 876 case P_CAPTURE_FORMAT: 877 if (*(uint32 *)value != fCaptureFormat){ 878 fCaptureFormat = *(uint32*)value; 879 fLastCaptureFormatChange = when; 880 BroadcastNewParameterValue( 881 fLastCaptureFormatChange, P_CAPTURE_FORMAT, &fCaptureFormat, sizeof(fCaptureFormat)); 882 } 883 break; 884 case P_STANDART: 885 if (*(uint32 *)value != fStandard){ 886 fStandard = *(uint32*)value; 887 fLastStandardChange = when; 888 BroadcastNewParameterValue( 889 fLastStandardChange, P_STANDART, &fStandard, sizeof(fStandard)); 890 } 891 break; 892 case P_BANDWIDTH: 893 if (*(float *)value != fBandwidth){ 894 fBandwidth = *(float *)value; 895 fLastBandwidthChange = when; 896 BroadcastNewParameterValue( 897 fLastBandwidthChange, P_BANDWIDTH, &fBandwidth, sizeof(fBandwidth)); 898 } 899 break; 900 case P_LOCALE: 901 if (*(uint32 *)value != fLocale){ 902 fLocale = *(uint32 *)value; 903 fLastLocaleChange = when; 904 BroadcastNewParameterValue( 905 fLastLocaleChange, P_LOCALE, &fLocale, sizeof(fLocale)); 906 } 907 break; 908 case P_VERT_OFFSET: 909 if (*(float*)value != fVertOffset){ 910 fVertOffset = *(float *)value; 911 fLastVertOffsetChange = when; 912 BroadcastNewParameterValue( 913 fLastVertOffsetChange, P_VERT_OFFSET, &fVertOffset, sizeof(fVertOffset)); 914 } 915 break; 916 case P_HORZ_OFFSET: 917 if (*(float*)value != fHorzOffset){ 918 fHorzOffset = *(float *)value; 919 fLastHorzOffsetChange = when; 920 BroadcastNewParameterValue( 921 fLastHorzOffsetChange, P_HORZ_OFFSET, &fHorzOffset, sizeof(fHorzOffset)); 922 } 923 break; 924 case P_COLOR: 925 if (*(int32 *)value != fColor){ 926 fColor = *(uint32 *)value; 927 fLastColorChange = when; 928 BroadcastNewParameterValue( 929 fLastColorChange, P_COLOR, &fColor, sizeof(fColor)); 930 } 931 break; 932 } 933 934 EventQueue()->AddEvent(media_timed_event(when, 935 BTimedEventQueue::B_PARAMETER, NULL, 936 BTimedEventQueue::B_NO_CLEANUP, id, 0, NULL, 0)); 937 938 } 939 940 status_t 941 VideoProducer::StartControlPanel(BMessenger *out_messenger) 942 { 943 return BControllable::StartControlPanel(out_messenger); 944 } 945 946 /* VideoProducer */ 947 948 void 949 VideoProducer::HandleStart(bigtime_t performance_time) 950 { 951 /* Start producing frames, even if the output hasn't been connected yet. */ 952 953 PRINTF(1, ("HandleStart(%Ld)\n", performance_time)); 954 955 if (fRunning) { 956 PRINTF(-1, ("HandleStart: Node already started\n")); 957 return; 958 } 959 960 fFrame = 0; 961 fFrameBase = 0; 962 fPerformanceTimeBase = performance_time; 963 964 fFrameSync = create_sem(0, "frame synchronization"); 965 if (fFrameSync < B_OK) 966 goto err1; 967 968 fThread = spawn_thread(_frame_generator_, "frame generator", 969 B_NORMAL_PRIORITY, this); 970 if (fThread < B_OK) 971 goto err2; 972 973 resume_thread(fThread); 974 975 fRunning = true; 976 return; 977 978 err2: 979 delete_sem(fFrameSync); 980 err1: 981 return; 982 } 983 984 void 985 VideoProducer::HandleStop(void) 986 { 987 PRINTF(1, ("HandleStop()\n")); 988 989 if (!fRunning) { 990 PRINTF(-1, ("HandleStop: Node isn't running\n")); 991 return; 992 } 993 994 delete_sem(fFrameSync); 995 wait_for_thread(fThread, &fThread); 996 997 fRunning = false; 998 } 999 1000 void 1001 VideoProducer::HandleTimeWarp(bigtime_t performance_time) 1002 { 1003 fPerformanceTimeBase = performance_time; 1004 fFrameBase = fFrame; 1005 1006 /* Tell frame generation thread to recalculate delay value */ 1007 release_sem(fFrameSync); 1008 } 1009 1010 void 1011 VideoProducer::HandleSeek(bigtime_t performance_time) 1012 { 1013 fPerformanceTimeBase = performance_time; 1014 fFrameBase = fFrame; 1015 1016 /* Tell frame generation thread to recalculate delay value */ 1017 release_sem(fFrameSync); 1018 } 1019 1020 void 1021 VideoProducer::HandleParameter(uint32 parameter) 1022 { 1023 switch(parameter){ 1024 case P_CHANNEL: 1025 break; 1026 case P_VIDEO_INPUT: 1027 break; 1028 case P_AUDIO_INPUT: 1029 break; 1030 case P_BRIGHTNESS: 1031 break; 1032 case P_CONTRAST: 1033 break; 1034 case P_SATURATION: 1035 break; 1036 case P_HUE: 1037 break; 1038 case P_CAPTURE_SIZE: 1039 break; 1040 case P_CAPTURE_FORMAT: 1041 break; 1042 case P_STANDART: 1043 break; 1044 case P_BANDWIDTH: 1045 break; 1046 case P_LOCALE: 1047 { 1048 //debugger("stop"); 1049 BParameterWeb *web = Web(); 1050 int nCount = web->CountParameters(); 1051 for(int idx = 0; idx < nCount; idx++){ 1052 BParameter *parameter = web->ParameterAt(idx); 1053 if(parameter && parameter->Type() == BParameter::B_DISCRETE_PARAMETER && 1054 parameter->ID() == P_CHANNEL){ 1055 BDiscreteParameter * d_parameter = dynamic_cast<BDiscreteParameter *>(parameter); 1056 d_parameter->MakeEmpty(); 1057 for(int i = 0; i < fLocales[fLocale]->ChannelsCount(); i ++){ 1058 d_parameter->AddItem(i, (fLocales[fLocale]->GetChannel(i)).Name().c_str()); 1059 } 1060 /*status_t st = BroadcastChangedParameter(P_CHANNEL); 1061 if(st != B_OK) 1062 debugger("kk");*/ 1063 break; 1064 } 1065 } 1066 } 1067 break; 1068 case P_VERT_OFFSET: 1069 break; 1070 case P_HORZ_OFFSET: 1071 break; 1072 } 1073 } 1074 1075 /* The following functions form the thread that generates frames. You should 1076 * replace this with the code that interfaces to your hardware. */ 1077 int32 1078 VideoProducer::FrameGenerator() 1079 { 1080 bigtime_t wait_until = system_time(); 1081 1082 while (1) { 1083 status_t err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT, 1084 wait_until); 1085 1086 /* The only acceptable responses are B_OK and B_TIMED_OUT. Everything 1087 * else means the thread should quit. Deleting the semaphore, as in 1088 * VideoProducer::HandleStop(), will trigger this behavior. */ 1089 if ((err != B_OK) && (err != B_TIMED_OUT)) 1090 break; 1091 1092 fFrame++; 1093 1094 /* Recalculate the time until the thread should wake up to begin 1095 * processing the next frame. Subtract fProcessingLatency so that 1096 * the frame is sent in time. */ 1097 wait_until = TimeSource()->RealTimeFor(fPerformanceTimeBase + 1098 (bigtime_t) 1099 ((fFrame - fFrameBase) * 1100 (1000000 / fConnectedFormat.field_rate)), 0) - 1101 fProcessingLatency; 1102 1103 /* Drop frame if it's at least a frame late */ 1104 if (wait_until < system_time()) 1105 continue; 1106 1107 /* If the semaphore was acquired successfully, it means something 1108 * changed the timing information (see VideoProducer::Connect()) and 1109 * so the thread should go back to sleep until the newly-calculated 1110 * wait_until time. */ 1111 if (err == B_OK) 1112 continue; 1113 1114 /* Send buffers only if the node is running and the output has been 1115 * enabled */ 1116 if (!fRunning || !fEnabled) 1117 continue; 1118 1119 BAutolock _(fLock); 1120 1121 /* Fetch a buffer from the buffer group */ 1122 BBuffer *buffer = fBufferGroup->RequestBuffer( 1123 4 * fConnectedFormat.display.line_width * 1124 fConnectedFormat.display.line_count, 0LL); 1125 if (!buffer) 1126 continue; 1127 1128 /* Fill out the details about this buffer. */ 1129 media_header *h = buffer->Header(); 1130 h->type = B_MEDIA_RAW_VIDEO; 1131 h->time_source = TimeSource()->ID(); 1132 h->size_used = 4 * fConnectedFormat.display.line_width * 1133 fConnectedFormat.display.line_count; 1134 /* For a buffer originating from a device, you might want to calculate 1135 * this based on the PerformanceTimeFor the time your buffer arrived at 1136 * the hardware (plus any applicable adjustments). */ 1137 h->start_time = fPerformanceTimeBase + 1138 (bigtime_t) 1139 ((fFrame - fFrameBase) * 1140 (1000000 / fConnectedFormat.field_rate)); 1141 h->file_pos = 0; 1142 h->orig_size = 0; 1143 h->data_offset = 0; 1144 h->u.raw_video.field_gamma = 1.0; 1145 h->u.raw_video.field_sequence = fFrame; 1146 h->u.raw_video.field_number = 0; 1147 h->u.raw_video.pulldown_number = 0; 1148 h->u.raw_video.first_active_line = 1; 1149 h->u.raw_video.line_count = fConnectedFormat.display.line_count; 1150 1151 /* Fill in a pattern */ 1152 uint32 *p = (uint32 *)buffer->Data(); 1153 for (int y=0;y<fConnectedFormat.display.line_count;y++) 1154 for (int x=0;x<fConnectedFormat.display.line_width;x++) 1155 *(p++) = ((((x+y)^0^x)+fFrame) & 0xff) * (0x01010101 & fColor); 1156 1157 /* Send the buffer on down to the consumer */ 1158 if (SendBuffer(buffer, fOutput.destination) < B_OK) { 1159 PRINTF(-1, ("FrameGenerator: Error sending buffer\n")); 1160 /* If there is a problem sending the buffer, return it to its 1161 * buffer group. */ 1162 buffer->Recycle(); 1163 } 1164 } 1165 1166 return B_OK; 1167 } 1168 1169 int32 1170 VideoProducer::_frame_generator_(void *data) 1171 { 1172 return ((VideoProducer *)data)->FrameGenerator(); 1173 } 1174