1 #include <fcntl.h> 2 #include <malloc.h> 3 #include <math.h> 4 #include <stdio.h> 5 #include <string.h> 6 #include <sys/uio.h> 7 #include <unistd.h> 8 9 #include <media/Buffer.h> 10 #include <media/BufferGroup.h> 11 #include <media/ParameterWeb.h> 12 #include <media/TimeSource.h> 13 14 #include <support/Autolock.h> 15 #include <support/Debug.h> 16 17 #define TOUCH(x) ((void)(x)) 18 19 #define PRINTF(a,b) \ 20 do { \ 21 if (a < 2) { \ 22 printf("FinePixProducer::"); \ 23 printf b; \ 24 } \ 25 } while (0) 26 27 #include "Producer.h" 28 29 #define FIELD_RATE 30.f 30 31 #define MAX_FRAME_SIZE 50000 // bytes (jpeg) 32 #define FPIX_RGB24_WIDTH 320 33 #define FPIX_RGB24_HEIGHT 240 34 #define FPIX_RGB24_FRAME_SIZE FPIX_RGB24_WIDTH * FPIX_RGB24_HEIGHT * 3 35 36 int32 FinePixProducer::fInstances = 0; 37 38 FinePixProducer::FinePixProducer( 39 BMediaAddOn *addon, const char *name, int32 internal_id) 40 : BMediaNode(name), 41 BMediaEventLooper(), 42 BBufferProducer(B_MEDIA_ENCODED_VIDEO), 43 BControllable() 44 { 45 //status_t err; 46 47 fInitStatus = B_NO_INIT; 48 49 /* Only allow one instance of the node to exist at any time */ 50 if (atomic_add(&fInstances, 1) != 0) 51 return; 52 53 fInternalID = internal_id; 54 fAddOn = addon; 55 56 fBufferGroup = NULL; 57 58 fThread = -1; 59 fFrameSync = -1; 60 fProcessingLatency = 0LL; 61 62 fRunning = false; 63 fConnected = false; 64 fEnabled = false; 65 66 fOutput.destination = media_destination::null; 67 68 AddNodeKind(B_PHYSICAL_INPUT); 69 70 fDeltaBuffer = NULL; //øyvind 71 fCam = new FinePix(); 72 73 fInitStatus = B_OK; 74 return; 75 } 76 77 FinePixProducer::~FinePixProducer() 78 { 79 if (fInitStatus == B_OK) { 80 /* Clean up after ourselves, in case the application didn't make us 81 * do so. */ 82 if (fConnected) 83 Disconnect(fOutput.source, fOutput.destination); 84 if (fRunning) 85 HandleStop(); 86 } 87 88 if( fCam ) //øyvind 89 { 90 delete fCam; 91 } 92 93 atomic_add(&fInstances, -1); 94 } 95 96 /* BMediaNode */ 97 98 port_id 99 FinePixProducer::ControlPort() const 100 { 101 return BMediaNode::ControlPort(); 102 } 103 104 BMediaAddOn * 105 FinePixProducer::AddOn(int32 *internal_id) const 106 { 107 if (internal_id) 108 *internal_id = fInternalID; 109 return fAddOn; 110 } 111 112 status_t 113 FinePixProducer::HandleMessage(int32 message, const void *data, size_t size) 114 { 115 return B_ERROR; 116 } 117 118 void 119 FinePixProducer::Preroll() 120 { 121 /* This hook may be called before the node is started to give the hardware 122 * a chance to start. */ 123 } 124 125 void 126 FinePixProducer::SetTimeSource(BTimeSource *time_source) 127 { 128 /* Tell frame generation thread to recalculate delay value */ 129 release_sem(fFrameSync); 130 } 131 132 status_t 133 FinePixProducer::RequestCompleted(const media_request_info &info) 134 { 135 return BMediaNode::RequestCompleted(info); 136 } 137 138 /* BMediaEventLooper */ 139 140 void 141 FinePixProducer::NodeRegistered() 142 { 143 if (fInitStatus != B_OK) { 144 ReportError(B_NODE_IN_DISTRESS); 145 return; 146 } 147 148 fOutput.node = Node(); 149 fOutput.source.port = ControlPort(); 150 fOutput.source.id = 0; 151 fOutput.destination = media_destination::null; 152 strcpy(fOutput.name, Name()); 153 154 /* Tailor these for the output of your device */ 155 fOutput.format.type = B_MEDIA_RAW_VIDEO; 156 fOutput.format.u.raw_video = media_raw_video_format::wildcard; 157 fOutput.format.u.raw_video.interlace = 1; 158 fOutput.format.u.raw_video.display.format = B_RGB32; 159 160 /* Start the BMediaEventLooper control loop running */ 161 Run(); 162 } 163 164 void 165 FinePixProducer::Start(bigtime_t performance_time) 166 { 167 BMediaEventLooper::Start(performance_time); 168 } 169 170 void 171 FinePixProducer::Stop(bigtime_t performance_time, bool immediate) 172 { 173 BMediaEventLooper::Stop(performance_time, immediate); 174 } 175 176 void 177 FinePixProducer::Seek(bigtime_t media_time, bigtime_t performance_time) 178 { 179 BMediaEventLooper::Seek(media_time, performance_time); 180 } 181 182 void 183 FinePixProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time) 184 { 185 BMediaEventLooper::TimeWarp(at_real_time, to_performance_time); 186 } 187 188 status_t 189 FinePixProducer::AddTimer(bigtime_t at_performance_time, int32 cookie) 190 { 191 return BMediaEventLooper::AddTimer(at_performance_time, cookie); 192 } 193 194 void 195 FinePixProducer::SetRunMode(run_mode mode) 196 { 197 BMediaEventLooper::SetRunMode(mode); 198 } 199 200 void 201 FinePixProducer::HandleEvent(const media_timed_event *event, 202 bigtime_t lateness, bool realTimeEvent) 203 { 204 TOUCH(lateness); TOUCH(realTimeEvent); 205 206 switch(event->type) 207 { 208 case BTimedEventQueue::B_START: 209 HandleStart(event->event_time); 210 break; 211 case BTimedEventQueue::B_STOP: 212 HandleStop(); 213 break; 214 case BTimedEventQueue::B_WARP: 215 HandleTimeWarp(event->bigdata); 216 break; 217 case BTimedEventQueue::B_SEEK: 218 HandleSeek(event->bigdata); 219 break; 220 case BTimedEventQueue::B_HANDLE_BUFFER: 221 case BTimedEventQueue::B_DATA_STATUS: 222 case BTimedEventQueue::B_PARAMETER: 223 default: 224 PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type)); 225 break; 226 } 227 } 228 229 void 230 FinePixProducer::CleanUpEvent(const media_timed_event *event) 231 { 232 BMediaEventLooper::CleanUpEvent(event); 233 } 234 235 bigtime_t 236 FinePixProducer::OfflineTime() 237 { 238 return BMediaEventLooper::OfflineTime(); 239 } 240 241 void 242 FinePixProducer::ControlLoop() 243 { 244 BMediaEventLooper::ControlLoop(); 245 } 246 247 status_t 248 FinePixProducer::DeleteHook(BMediaNode * node) 249 { 250 return BMediaEventLooper::DeleteHook(node); 251 } 252 253 /* BBufferProducer */ 254 255 status_t 256 FinePixProducer::FormatSuggestionRequested( 257 media_type type, int32 quality, media_format *format) 258 { 259 if (type != B_MEDIA_ENCODED_VIDEO) 260 return B_MEDIA_BAD_FORMAT; 261 262 TOUCH(quality); 263 264 *format = fOutput.format; 265 return B_OK; 266 } 267 268 status_t 269 FinePixProducer::FormatProposal(const media_source &output, media_format *format) 270 { 271 status_t err; 272 273 if (!format) 274 return B_BAD_VALUE; 275 276 if (output != fOutput.source) 277 return B_MEDIA_BAD_SOURCE; 278 279 err = format_is_compatible(*format, fOutput.format) ? 280 B_OK : B_MEDIA_BAD_FORMAT; 281 *format = fOutput.format; 282 return err; 283 284 } 285 286 status_t 287 FinePixProducer::FormatChangeRequested(const media_source &source, 288 const media_destination &destination, media_format *io_format, 289 int32 *_deprecated_) 290 { 291 TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_); 292 if (source != fOutput.source) 293 return B_MEDIA_BAD_SOURCE; 294 295 return B_ERROR; 296 } 297 298 status_t 299 FinePixProducer::GetNextOutput(int32 *cookie, media_output *out_output) 300 { 301 if (!out_output) 302 return B_BAD_VALUE; 303 304 if ((*cookie) != 0) 305 return B_BAD_INDEX; 306 307 *out_output = fOutput; 308 (*cookie)++; 309 return B_OK; 310 } 311 312 status_t 313 FinePixProducer::DisposeOutputCookie(int32 cookie) 314 { 315 TOUCH(cookie); 316 317 return B_OK; 318 } 319 320 status_t 321 FinePixProducer::SetBufferGroup(const media_source &for_source, 322 BBufferGroup *group) 323 { 324 TOUCH(for_source); TOUCH(group); 325 326 return B_ERROR; 327 } 328 329 status_t 330 FinePixProducer::VideoClippingChanged(const media_source &for_source, 331 int16 num_shorts, int16 *clip_data, 332 const media_video_display_info &display, int32 *_deprecated_) 333 { 334 TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data); 335 TOUCH(display); TOUCH(_deprecated_); 336 337 return B_ERROR; 338 } 339 340 status_t 341 FinePixProducer::GetLatency(bigtime_t *out_latency) 342 { 343 *out_latency = EventLatency() + SchedulingLatency(); 344 return B_OK; 345 } 346 347 status_t 348 FinePixProducer::PrepareToConnect(const media_source &source, 349 const media_destination &destination, media_format *format, 350 media_source *out_source, char *out_name) 351 { 352 //status_t err; 353 354 PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \ 355 format->u.raw_video.display.line_width, \ 356 format->u.raw_video.display.line_count)); 357 358 if (fConnected) { 359 PRINTF(0, ("PrepareToConnect: Already connected\n")); 360 return EALREADY; 361 } 362 363 if (source != fOutput.source) 364 return B_MEDIA_BAD_SOURCE; 365 366 if (fOutput.destination != media_destination::null) 367 return B_MEDIA_ALREADY_CONNECTED; 368 369 /* The format parameter comes in with the suggested format, and may be 370 * specialized as desired by the node */ 371 if (!format_is_compatible(*format, fOutput.format)) { 372 *format = fOutput.format; 373 return B_MEDIA_BAD_FORMAT; 374 } 375 376 if (format->u.raw_video.display.line_width == 0) 377 format->u.raw_video.display.line_width = 320; 378 if (format->u.raw_video.display.line_count == 0) 379 format->u.raw_video.display.line_count = 240; 380 if (format->u.raw_video.field_rate == 0) 381 format->u.raw_video.field_rate = 29.97f; 382 383 *out_source = fOutput.source; 384 strcpy(out_name, fOutput.name); 385 386 fOutput.destination = destination; 387 388 return B_OK; 389 } 390 391 void 392 FinePixProducer::Connect(status_t error, const media_source &source, 393 const media_destination &destination, const media_format &format, 394 char *io_name) 395 { 396 PRINTF(1, ("Connect() %ldx%ld\n", \ 397 format.u.raw_video.display.line_width, \ 398 format.u.raw_video.display.line_count)); 399 400 if (fConnected) { 401 PRINTF(0, ("Connect: Already connected\n")); 402 return; 403 } 404 405 if ( (source != fOutput.source) || (error < B_OK) || 406 !const_cast<media_format *>(&format)->Matches(&fOutput.format)) { 407 PRINTF(1, ("Connect: Connect error\n")); 408 return; 409 } 410 411 fOutput.destination = destination; 412 strcpy(io_name, fOutput.name); 413 414 if (fOutput.format.u.raw_video.field_rate != 0.0f) { 415 fPerformanceTimeBase = fPerformanceTimeBase + 416 (bigtime_t) 417 ((fFrame - fFrameBase) * 418 (1000000 / fOutput.format.u.raw_video.field_rate)); 419 fFrameBase = fFrame; 420 } 421 422 fConnectedFormat = format.u.raw_video; 423 424 fDeltaBuffer = new uint8[MAX_FRAME_SIZE]; //ø in buffer 425 tempInBuffer = new uint8[3 * fConnectedFormat.display.line_width * 426 fConnectedFormat.display.line_count]; // for 24 bit color 427 fCam->SetupCam(); //øyvind 428 429 /* get the latency */ 430 bigtime_t latency = 0; 431 media_node_id tsID = 0; 432 FindLatencyFor(fOutput.destination, &latency, &tsID); 433 #define NODE_LATENCY 1000 434 SetEventLatency(latency + NODE_LATENCY); 435 436 uint8 *tmp24 = (uint8*)tempInBuffer; 437 uint8 *buffer, *dst; 438 dst = buffer = (uint8 *)malloc(4 * fConnectedFormat.display.line_count * 439 fConnectedFormat.display.line_width); 440 if (!buffer) { 441 PRINTF(0, ("Connect: Out of memory\n")); 442 return; 443 } 444 bigtime_t now = system_time(); 445 446 // Get a frame from the camera 447 fCam->GetPic(fDeltaBuffer, frame_size); 448 449 // Convert from jpeg to bitmap 450 if (jpeg_check_size(fDeltaBuffer, 451 FPIX_RGB24_WIDTH, FPIX_RGB24_HEIGHT)) 452 { 453 int n = jpeg_decode(fDeltaBuffer, tmp24, 454 FPIX_RGB24_WIDTH, FPIX_RGB24_HEIGHT, 24, //32 not working 455 &decdata); 456 if (n) 457 { 458 PRINTF(-1, ("ooeps decode jpg result : %d", n)); 459 } 460 } else 461 { 462 PRINTF(-1, ("ooeps check_size failed")); 463 } 464 465 // Convert from 24 bit to 32 bit 466 for (uint y=0; y<fConnectedFormat.display.line_count; y++) 467 for (uint x=0; x<fConnectedFormat.display.line_width; x++) { 468 *(dst++) = *tmp24; //red 469 tmp24++; 470 *(dst++) = *tmp24; //green 471 tmp24++; 472 *(dst++) = *tmp24; //blue 473 tmp24++; 474 dst++; //last 8 bit empty 475 } 476 477 fProcessingLatency = system_time() - now; 478 free(buffer); 479 480 /* Create the buffer group */ 481 fBufferGroup = new BBufferGroup(4 * fConnectedFormat.display.line_width * 482 fConnectedFormat.display.line_count, 8); 483 if (fBufferGroup->InitCheck() < B_OK) { 484 delete fBufferGroup; 485 fBufferGroup = NULL; 486 return; 487 } 488 489 fConnected = true; 490 fEnabled = true; 491 492 /* Tell frame generation thread to recalculate delay value */ 493 release_sem(fFrameSync); 494 } 495 496 void 497 FinePixProducer::Disconnect(const media_source &source, 498 const media_destination &destination) 499 { 500 PRINTF(1, ("Disconnect()\n")); 501 502 if (!fConnected) { 503 PRINTF(0, ("Disconnect: Not connected\n")); 504 return; 505 } 506 507 if ((source != fOutput.source) || (destination != fOutput.destination)) { 508 PRINTF(0, ("Disconnect: Bad source and/or destination\n")); 509 return; 510 } 511 512 fEnabled = false; 513 fOutput.destination = media_destination::null; 514 515 fLock.Lock(); 516 delete fBufferGroup; 517 fBufferGroup = NULL; 518 delete fDeltaBuffer; //ø 519 fDeltaBuffer = NULL; //ø 520 delete tempInBuffer; //Ø 521 tempInBuffer = NULL; //Ø 522 fLock.Unlock(); 523 524 fConnected = false; 525 } 526 527 void 528 FinePixProducer::LateNoticeReceived(const media_source &source, 529 bigtime_t how_much, bigtime_t performance_time) 530 { 531 TOUCH(source); TOUCH(how_much); TOUCH(performance_time); 532 } 533 534 void 535 FinePixProducer::EnableOutput(const media_source &source, bool enabled, 536 int32 *_deprecated_) 537 { 538 TOUCH(_deprecated_); 539 540 if (source != fOutput.source) 541 return; 542 543 fEnabled = enabled; 544 } 545 546 status_t 547 FinePixProducer::SetPlayRate(int32 numer, int32 denom) 548 { 549 TOUCH(numer); TOUCH(denom); 550 551 return B_ERROR; 552 } 553 554 void 555 FinePixProducer::AdditionalBufferRequested(const media_source &source, 556 media_buffer_id prev_buffer, bigtime_t prev_time, 557 const media_seek_tag *prev_tag) 558 { 559 TOUCH(source); TOUCH(prev_buffer); TOUCH(prev_time); TOUCH(prev_tag); 560 } 561 562 void 563 FinePixProducer::LatencyChanged(const media_source &source, 564 const media_destination &destination, bigtime_t new_latency, 565 uint32 flags) 566 { 567 TOUCH(source); TOUCH(destination); TOUCH(new_latency); TOUCH(flags); 568 } 569 570 /* BControllable */ 571 572 status_t 573 FinePixProducer::GetParameterValue( 574 int32 id, bigtime_t *last_change, void *value, size_t *size) 575 { 576 return B_OK; 577 } 578 579 void 580 FinePixProducer::SetParameterValue( 581 int32 id, bigtime_t when, const void *value, size_t size) 582 { 583 } 584 585 status_t 586 FinePixProducer::StartControlPanel(BMessenger *out_messenger) 587 { 588 return BControllable::StartControlPanel(out_messenger); 589 } 590 591 /* FinePixProducer */ 592 593 void 594 FinePixProducer::HandleStart(bigtime_t performance_time) 595 { 596 /* Start producing frames, even if the output hasn't been connected yet. */ 597 598 PRINTF(1, ("HandleStart(%Ld)\n", performance_time)); 599 600 if (fRunning) { 601 PRINTF(-1, ("HandleStart: Node already started\n")); 602 return; 603 } 604 605 fFrame = 0; 606 fFrameBase = 0; 607 fPerformanceTimeBase = performance_time; 608 609 fFrameSync = create_sem(0, "frame synchronization"); 610 if (fFrameSync < B_OK) 611 goto err1; 612 613 fThread = spawn_thread(_frame_generator_, "frame generator", 614 B_NORMAL_PRIORITY, this); 615 if (fThread < B_OK) 616 goto err2; 617 618 resume_thread(fThread); 619 620 fRunning = true; 621 return; 622 623 err2: 624 delete_sem(fFrameSync); 625 err1: 626 return; 627 } 628 629 void 630 FinePixProducer::HandleStop(void) 631 { 632 PRINTF(1, ("HandleStop()\n")); 633 634 if (!fRunning) { 635 PRINTF(-1, ("HandleStop: Node isn't running\n")); 636 return; 637 } 638 639 delete_sem(fFrameSync); 640 wait_for_thread(fThread, &fThread); 641 642 fRunning = false; 643 } 644 645 void 646 FinePixProducer::HandleTimeWarp(bigtime_t performance_time) 647 { 648 fPerformanceTimeBase = performance_time; 649 fFrameBase = fFrame; 650 651 /* Tell frame generation thread to recalculate delay value */ 652 release_sem(fFrameSync); 653 } 654 655 void 656 FinePixProducer::HandleSeek(bigtime_t performance_time) 657 { 658 fPerformanceTimeBase = performance_time; 659 fFrameBase = fFrame; 660 661 /* Tell frame generation thread to recalculate delay value */ 662 release_sem(fFrameSync); 663 } 664 665 /* The following functions form the thread that generates frames. You should 666 * replace this with the code that interfaces to your hardware. */ 667 int32 668 FinePixProducer::FrameGenerator() 669 { 670 bigtime_t wait_until = system_time(); 671 672 while (1) { 673 status_t err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT, 674 wait_until); 675 676 /* The only acceptable responses are B_OK and B_TIMED_OUT. Everything 677 * else means the thread should quit. Deleting the semaphore, as in 678 * FinePixProducer::HandleStop(), will trigger this behavior. */ 679 if ((err != B_OK) && (err != B_TIMED_OUT)) 680 break; 681 682 fFrame++; 683 684 /* Recalculate the time until the thread should wake up to begin 685 * processing the next frame. Subtract fProcessingLatency so that 686 * the frame is sent in time. */ 687 wait_until = TimeSource()->RealTimeFor(fPerformanceTimeBase, 0) + 688 (bigtime_t) 689 ((fFrame - fFrameBase) * 690 (1000000 / fConnectedFormat.field_rate)) - 691 fProcessingLatency; 692 693 /* Drop frame if it's at least a frame late */ 694 if (wait_until < system_time()) 695 continue; 696 697 /* If the semaphore was acquired successfully, it means something 698 * changed the timing information (see FinePixProducer::Connect()) and 699 * so the thread should go back to sleep until the newly-calculated 700 * wait_until time. */ 701 if (err == B_OK) 702 continue; 703 704 /* Send buffers only if the node is running and the output has been 705 * enabled */ 706 if (!fRunning || !fEnabled) 707 continue; 708 709 BAutolock _(fLock); 710 711 // Get the frame from the camera 712 fCam->GetPic(fDeltaBuffer, frame_size); 713 714 /* Fetch a buffer from the buffer group */ 715 BBuffer *buffer = fBufferGroup->RequestBuffer( 716 4 * fConnectedFormat.display.line_width * 717 fConnectedFormat.display.line_count, 0LL); 718 if (!buffer) 719 continue; 720 721 /* Fill out the details about this buffer. */ 722 media_header *h = buffer->Header(); 723 h->type = B_MEDIA_RAW_VIDEO; 724 h->time_source = TimeSource()->ID(); 725 h->size_used = 4 * fConnectedFormat.display.line_width * 726 fConnectedFormat.display.line_count; 727 /* For a buffer originating from a device, you might want to calculate 728 * this based on the PerformanceTimeFor the time your buffer arrived at 729 * the hardware (plus any applicable adjustments). 730 h->start_time = fPerformanceTimeBase + 731 (bigtime_t) 732 ((fFrame - fFrameBase) * 733 (1000000 / fConnectedFormat.field_rate));*/ 734 h->start_time = TimeSource()->Now(); 735 h->file_pos = 0; 736 h->orig_size = 0; 737 h->data_offset = 0; 738 h->u.raw_video.field_gamma = 1.0; 739 h->u.raw_video.field_sequence = fFrame; 740 h->u.raw_video.field_number = 0; 741 h->u.raw_video.pulldown_number = 0; 742 h->u.raw_video.first_active_line = 1; 743 h->u.raw_video.line_count = fConnectedFormat.display.line_count; 744 745 // Frame data pointers 746 uint8 *tmp24 = (uint8*)tempInBuffer; 747 uint8 *dst = (uint8*)buffer->Data(); 748 749 // Convert from jpeg to bitmap 750 if (jpeg_check_size(fDeltaBuffer, 751 FPIX_RGB24_WIDTH, FPIX_RGB24_HEIGHT)) 752 { 753 int n = jpeg_decode(fDeltaBuffer, tmp24, 754 FPIX_RGB24_WIDTH, FPIX_RGB24_HEIGHT, 24, //32 not working 755 &decdata); 756 if (n) 757 { 758 PRINTF(-1, ("ooeps decode jpg result : %d", n)); 759 } 760 } else 761 { 762 PRINTF(-1, ("ooeps check_size failed")); 763 } 764 765 // Convert from 24 bit to 32 bit 766 for (uint y=0; y<fConnectedFormat.display.line_count; y++) 767 for (uint x=0; x<fConnectedFormat.display.line_width; x++) { 768 *(dst++) = *tmp24; //red 769 tmp24++; 770 *(dst++) = *tmp24; //green 771 tmp24++; 772 *(dst++) = *tmp24; //blue 773 tmp24++; 774 dst++; //last 8 bit empty 775 } 776 777 /* Send the buffer on down to the consumer */ 778 if (SendBuffer(buffer, fOutput.destination) < B_OK) { 779 PRINTF(-1, ("FrameGenerator: Error sending buffer\n")); 780 /* If there is a problem sending the buffer, return it to its 781 * buffer group. */ 782 buffer->Recycle(); 783 } 784 } 785 786 return B_OK; 787 } 788 789 int32 790 FinePixProducer::_frame_generator_(void *data) 791 { 792 return ((FinePixProducer *)data)->FrameGenerator(); 793 } 794