vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / media-add-ons / usb_webcam / Producer.cpp
blob2ef797c8f521c6062bb22d2824667434c4de7bdf
1 /*
2 * Copyright 2004-2008, François Revol, <revol@free.fr>.
3 * Distributed under the terms of the MIT License.
4 */
6 #include <fcntl.h>
7 #include <malloc.h>
8 #include <math.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/uio.h>
12 #include <unistd.h>
14 #include <media/Buffer.h>
15 #include <media/BufferGroup.h>
16 #include <media/ParameterWeb.h>
17 #include <media/TimeSource.h>
19 #include <support/Autolock.h>
20 #include <support/Debug.h>
22 //XXX: change interface
23 #include <interface/Bitmap.h>
25 #include "CamDevice.h"
26 #include "CamSensor.h"
28 // don't separate parameters from addon, device and sensor
29 #define SINGLE_PARAMETER_GROUP 1
31 // CodyCam and eXposer prefer 320x240
32 #define FORCE_320_240 1
33 //#define FORCE_160_120 1
34 //#define FORCE_MAX_FRAME 1
36 #define TOUCH(x) ((void)(x))
38 #define PRINTF(a,b) \
39 do { \
40 if (a < 2) { \
41 printf("VideoProducer::"); \
42 printf b; \
43 } \
44 } while (0)
46 #include "Producer.h"
48 //#define FIELD_RATE 30.f
49 //#define FIELD_RATE 29.97f
50 #define FIELD_RATE 5.f
53 int32 VideoProducer::fInstances = 0;
56 VideoProducer::VideoProducer(
57 BMediaAddOn *addon, CamDevice *dev, const char *name, int32 internal_id)
58 : BMediaNode(name),
59 BMediaEventLooper(),
60 BBufferProducer(B_MEDIA_RAW_VIDEO),
61 BControllable()
63 // status_t err;
65 fInitStatus = B_NO_INIT;
67 /* Only allow one instance of the node to exist at any time */
68 if (atomic_add(&fInstances, 1) != 0)
69 return;
71 fInternalID = internal_id;
72 fAddOn = addon;
73 fCamDevice = dev;
75 fBufferGroup = NULL;
77 fThread = -1;
78 fFrameSync = -1;
79 fProcessingLatency = 0LL;
81 fRunning = false;
82 fConnected = false;
83 fEnabled = false;
85 fOutput.destination = media_destination::null;
87 AddNodeKind(B_PHYSICAL_INPUT);
89 fInitStatus = B_OK;
90 return;
94 VideoProducer::~VideoProducer()
96 if (fInitStatus == B_OK) {
97 /* Clean up after ourselves, in case the application didn't make us
98 * do so. */
99 if (fConnected)
100 Disconnect(fOutput.source, fOutput.destination);
101 if (fRunning)
102 HandleStop();
105 atomic_add(&fInstances, -1);
109 /* BMediaNode */
110 port_id
111 VideoProducer::ControlPort() const
113 return BMediaNode::ControlPort();
117 BMediaAddOn *
118 VideoProducer::AddOn(int32 *internal_id) const
120 if (internal_id)
121 *internal_id = fInternalID;
122 return fAddOn;
126 status_t
127 VideoProducer::HandleMessage(int32 /*message*/, const void* /*data*/, size_t /*size*/)
129 return B_ERROR;
133 void
134 VideoProducer::Preroll()
136 /* This hook may be called before the node is started to give the hardware
137 * a chance to start. */
141 void
142 VideoProducer::SetTimeSource(BTimeSource* /*time_source*/)
144 /* Tell frame generation thread to recalculate delay value */
145 release_sem(fFrameSync);
149 status_t
150 VideoProducer::RequestCompleted(const media_request_info &info)
152 return BMediaNode::RequestCompleted(info);
156 /* BMediaEventLooper */
159 void
160 VideoProducer::NodeRegistered()
162 if (fInitStatus != B_OK) {
163 ReportError(B_NODE_IN_DISTRESS);
164 return;
167 /* Set up the parameter web */
169 //TODO: remove and put sensible stuff there
170 BParameterWeb *web = new BParameterWeb();
171 BParameterGroup *main = web->MakeGroup(Name());
172 BParameterGroup *g;
175 g = main->MakeGroup("Color");
176 BDiscreteParameter *state = g->MakeDiscreteParameter(
177 P_COLOR, B_MEDIA_RAW_VIDEO, "Color", "Color");
178 state->AddItem(B_HOST_TO_LENDIAN_INT32(0x00ff0000), "Red");
179 state->AddItem(B_HOST_TO_LENDIAN_INT32(0x0000ff00), "Green");
180 state->AddItem(B_HOST_TO_LENDIAN_INT32(0x000000ff), "Blue");
183 BParameter *p;
184 g = main->MakeGroup("Info");
185 p = g->MakeTextParameter(
186 P_INFO, B_MEDIA_RAW_VIDEO, "", "Info", 256);
188 int32 id = P_LAST;
189 if (fCamDevice) {
190 #ifndef SINGLE_PARAMETER_GROUP
191 main = web->MakeGroup("Device");
192 #endif
193 fCamDevice->AddParameters(main, id);
194 if (fCamDevice->Sensor()) {
195 #ifndef SINGLE_PARAMETER_GROUP
196 main = web->MakeGroup("Sensor");
197 #endif
198 fCamDevice->Sensor()->AddParameters(main, id);
202 fColor = B_HOST_TO_LENDIAN_INT32(0x00ff0000);
203 fLastColorChange = system_time();
205 /* After this call, the BControllable owns the BParameterWeb object and
206 * will delete it for you */
207 SetParameterWeb(web);
209 fOutput.node = Node();
210 fOutput.source.port = ControlPort();
211 fOutput.source.id = 0;
212 fOutput.destination = media_destination::null;
213 strcpy(fOutput.name, Name());
215 /* Tailor these for the output of your device */
216 fOutput.format.type = B_MEDIA_RAW_VIDEO;
217 fOutput.format.u.raw_video = media_raw_video_format::wildcard;
218 fOutput.format.u.raw_video.interlace = 1;
219 fOutput.format.u.raw_video.display.format = B_RGB32;
220 fOutput.format.u.raw_video.field_rate = FIELD_RATE; // XXX: mmu
222 /* Start the BMediaEventLooper control loop running */
223 Run();
227 void
228 VideoProducer::Start(bigtime_t performance_time)
230 BMediaEventLooper::Start(performance_time);
234 void
235 VideoProducer::Stop(bigtime_t performance_time, bool immediate)
237 BMediaEventLooper::Stop(performance_time, immediate);
241 void
242 VideoProducer::Seek(bigtime_t media_time, bigtime_t performance_time)
244 BMediaEventLooper::Seek(media_time, performance_time);
248 void
249 VideoProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
251 BMediaEventLooper::TimeWarp(at_real_time, to_performance_time);
255 status_t
256 VideoProducer::AddTimer(bigtime_t at_performance_time, int32 cookie)
258 return BMediaEventLooper::AddTimer(at_performance_time, cookie);
262 void
263 VideoProducer::SetRunMode(run_mode mode)
265 BMediaEventLooper::SetRunMode(mode);
269 void
270 VideoProducer::HandleEvent(const media_timed_event *event,
271 bigtime_t lateness, bool realTimeEvent)
273 TOUCH(lateness); TOUCH(realTimeEvent);
275 switch(event->type) {
276 case BTimedEventQueue::B_START:
277 HandleStart(event->event_time);
278 break;
279 case BTimedEventQueue::B_STOP:
280 HandleStop();
281 break;
282 case BTimedEventQueue::B_WARP:
283 HandleTimeWarp(event->bigdata);
284 break;
285 case BTimedEventQueue::B_SEEK:
286 HandleSeek(event->bigdata);
287 break;
288 case BTimedEventQueue::B_HANDLE_BUFFER:
289 case BTimedEventQueue::B_DATA_STATUS:
290 case BTimedEventQueue::B_PARAMETER:
291 default:
292 PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type));
293 break;
298 void
299 VideoProducer::CleanUpEvent(const media_timed_event *event)
301 BMediaEventLooper::CleanUpEvent(event);
305 bigtime_t
306 VideoProducer::OfflineTime()
308 return BMediaEventLooper::OfflineTime();
312 void
313 VideoProducer::ControlLoop()
315 BMediaEventLooper::ControlLoop();
319 status_t
320 VideoProducer::DeleteHook(BMediaNode * node)
322 return BMediaEventLooper::DeleteHook(node);
326 /* BBufferProducer */
329 status_t
330 VideoProducer::FormatSuggestionRequested(
331 media_type type, int32 quality, media_format *format)
333 if (type != B_MEDIA_ENCODED_VIDEO)
334 return B_MEDIA_BAD_FORMAT;
336 TOUCH(quality);
338 PRINTF(1, ("FormatSuggestionRequested() %ldx%ld\n", \
339 format->u.raw_video.display.line_width, \
340 format->u.raw_video.display.line_count));
342 *format = fOutput.format;
343 uint32 width, height;
344 if (fCamDevice && fCamDevice->SuggestVideoFrame(width, height) == B_OK) {
345 format->u.raw_video.display.line_width = width;
346 format->u.raw_video.display.line_count = height;
348 format->u.raw_video.field_rate = FIELD_RATE;
349 return B_OK;
353 status_t
354 VideoProducer::FormatProposal(const media_source &output, media_format *format)
356 status_t err;
358 if (!format)
359 return B_BAD_VALUE;
361 if (output != fOutput.source)
362 return B_MEDIA_BAD_SOURCE;
364 PRINTF(1, ("FormatProposal() %ldx%ld\n", \
365 format->u.raw_video.display.line_width, \
366 format->u.raw_video.display.line_count));
368 err = format_is_compatible(*format, fOutput.format) ?
369 B_OK : B_MEDIA_BAD_FORMAT;
371 uint32 width = format->u.raw_video.display.line_width;
372 uint32 height = format->u.raw_video.display.line_count;
374 *format = fOutput.format;
376 if (err == B_OK && fCamDevice) {
377 err = fCamDevice->AcceptVideoFrame(width, height);
378 if (err >= B_OK) {
379 format->u.raw_video.display.line_width = width;
380 format->u.raw_video.display.line_count = height;
384 PRINTF(1, ("FormatProposal: %ldx%ld\n", \
385 format->u.raw_video.display.line_width, \
386 format->u.raw_video.display.line_count));
388 return err;
393 status_t
394 VideoProducer::FormatChangeRequested(const media_source &source,
395 const media_destination &destination, media_format *io_format,
396 int32 *_deprecated_)
398 TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_);
399 if (source != fOutput.source)
400 return B_MEDIA_BAD_SOURCE;
402 return B_ERROR;
406 status_t
407 VideoProducer::GetNextOutput(int32 *cookie, media_output *out_output)
409 if (!out_output)
410 return B_BAD_VALUE;
412 if ((*cookie) != 0)
413 return B_BAD_INDEX;
415 *out_output = fOutput;
416 (*cookie)++;
417 return B_OK;
421 status_t
422 VideoProducer::DisposeOutputCookie(int32 cookie)
424 TOUCH(cookie);
426 return B_OK;
430 status_t
431 VideoProducer::SetBufferGroup(const media_source &for_source,
432 BBufferGroup *group)
434 TOUCH(for_source); TOUCH(group);
436 return B_ERROR;
440 status_t
441 VideoProducer::VideoClippingChanged(const media_source &for_source,
442 int16 num_shorts, int16 *clip_data,
443 const media_video_display_info &display, int32 *_deprecated_)
445 TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data);
446 TOUCH(display); TOUCH(_deprecated_);
448 return B_ERROR;
452 status_t
453 VideoProducer::GetLatency(bigtime_t *out_latency)
455 *out_latency = EventLatency() + SchedulingLatency();
456 return B_OK;
460 status_t
461 VideoProducer::PrepareToConnect(const media_source &source,
462 const media_destination &destination, media_format *format,
463 media_source *out_source, char *out_name)
465 status_t err;
467 PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \
468 format->u.raw_video.display.line_width, \
469 format->u.raw_video.display.line_count));
471 if (fConnected) {
472 PRINTF(0, ("PrepareToConnect: Already connected\n"));
473 return EALREADY;
476 if (source != fOutput.source)
477 return B_MEDIA_BAD_SOURCE;
479 if (fOutput.destination != media_destination::null)
480 return B_MEDIA_ALREADY_CONNECTED;
482 /* The format parameter comes in with the suggested format, and may be
483 * specialized as desired by the node */
484 if (!format_is_compatible(*format, fOutput.format)) {
485 *format = fOutput.format;
486 return B_MEDIA_BAD_FORMAT;
489 //XXX:FIXME
490 #if 0
491 // if (format->u.raw_video.display.line_width == 0)
492 format->u.raw_video.display.line_width = 352;//320;
493 format->u.raw_video.display.line_width = 320;
494 // if (format->u.raw_video.display.line_count == 0)
495 format->u.raw_video.display.line_count = 288;//240;
496 format->u.raw_video.display.line_count = 240;
497 #endif
499 #ifdef FORCE_320_240
501 format->u.raw_video.display.line_width = 320;
502 format->u.raw_video.display.line_count = 240;
504 #endif
505 #ifdef FORCE_160_120
507 format->u.raw_video.display.line_width = 160;
508 format->u.raw_video.display.line_count = 120;
510 #endif
511 #ifdef FORCE_MAX_FRAME
513 format->u.raw_video.display.line_width = 0;
514 format->u.raw_video.display.line_count = 0;
516 #endif
517 if (fCamDevice) {
518 err = fCamDevice->AcceptVideoFrame(
519 format->u.raw_video.display.line_width,
520 format->u.raw_video.display.line_count);
521 if (err < B_OK)
522 return err;
525 if (format->u.raw_video.field_rate == 0)
526 format->u.raw_video.field_rate = FIELD_RATE;
528 *out_source = fOutput.source;
529 strcpy(out_name, fOutput.name);
531 fOutput.destination = destination;
533 return B_OK;
537 void
538 VideoProducer::Connect(status_t error, const media_source &source,
539 const media_destination &destination, const media_format &format,
540 char *io_name)
542 PRINTF(1, ("Connect() %ldx%ld\n", \
543 format.u.raw_video.display.line_width, \
544 format.u.raw_video.display.line_count));
546 if (fConnected) {
547 PRINTF(0, ("Connect: Already connected\n"));
548 return;
551 BAutolock lock(fCamDevice->Locker());
552 if (!fCamDevice->IsPlugged()) {
553 PRINTF(0, ("Connect: Device unplugged\n"));
554 return;
557 if (source != fOutput.source || error < B_OK
558 || !const_cast<media_format *>(&format)->Matches(&fOutput.format)) {
559 PRINTF(1, ("Connect: Connect error\n"));
560 return;
563 fOutput.destination = destination;
564 strcpy(io_name, fOutput.name);
566 if (fOutput.format.u.raw_video.field_rate != 0.0f) {
567 fPerformanceTimeBase = fPerformanceTimeBase +
568 (bigtime_t)
569 ((fFrame - fFrameBase) *
570 (1000000 / fOutput.format.u.raw_video.field_rate));
571 fFrameBase = fFrame;
574 fConnectedFormat = format.u.raw_video;
576 /* get the latency */
577 bigtime_t latency = 0;
578 media_node_id tsID = 0;
579 FindLatencyFor(fOutput.destination, &latency, &tsID);
580 #define NODE_LATENCY 1000
581 SetEventLatency(latency + NODE_LATENCY);
583 uint32 *buffer, *p, f = 3;
584 p = buffer = (uint32 *)malloc(4 * fConnectedFormat.display.line_count *
585 fConnectedFormat.display.line_width);
586 if (!buffer) {
587 PRINTF(0, ("Connect: Out of memory\n"));
588 return;
590 bigtime_t now = system_time();
591 for (uint32 y=0;y<fConnectedFormat.display.line_count;y++)
592 for (uint32 x=0;x<fConnectedFormat.display.line_width;x++)
593 *(p++) = ((((x+y)^0^x)+f) & 0xff) * (0x01010101 & fColor);
594 fProcessingLatency = system_time() - now;
595 free(buffer);
597 /* Create the buffer group */
598 fBufferGroup = new BBufferGroup(4 * fConnectedFormat.display.line_width *
599 fConnectedFormat.display.line_count, 8);
600 if (fBufferGroup->InitCheck() < B_OK) {
601 delete fBufferGroup;
602 fBufferGroup = NULL;
603 return;
606 fConnected = true;
607 fEnabled = true;
609 /* Tell frame generation thread to recalculate delay value */
610 release_sem(fFrameSync);
613 void
614 VideoProducer::Disconnect(const media_source &source,
615 const media_destination &destination)
617 PRINTF(1, ("Disconnect()\n"));
619 if (!fConnected) {
620 PRINTF(0, ("Disconnect: Not connected\n"));
621 return;
624 if ((source != fOutput.source) || (destination != fOutput.destination)) {
625 PRINTF(0, ("Disconnect: Bad source and/or destination\n"));
626 return;
629 #if 1
630 /* Some dumb apps don't stop nodes before disconnecting... */
631 if (fRunning)
632 HandleStop();
633 #endif
635 fEnabled = false;
636 fOutput.destination = media_destination::null;
638 fLock.Lock();
639 delete fBufferGroup;
640 fBufferGroup = NULL;
641 fLock.Unlock();
643 fConnected = false;
647 void
648 VideoProducer::LateNoticeReceived(const media_source &source,
649 bigtime_t how_much, bigtime_t performance_time)
651 TOUCH(source); TOUCH(how_much); TOUCH(performance_time);
655 void
656 VideoProducer::EnableOutput(const media_source &source, bool enabled,
657 int32 *_deprecated_)
659 TOUCH(_deprecated_);
661 if (source != fOutput.source)
662 return;
664 fEnabled = enabled;
668 status_t
669 VideoProducer::SetPlayRate(int32 numer, int32 denom)
671 TOUCH(numer); TOUCH(denom);
673 return B_ERROR;
677 void
678 VideoProducer::AdditionalBufferRequested(const media_source &source,
679 media_buffer_id prev_buffer, bigtime_t prev_time,
680 const media_seek_tag *prev_tag)
682 TOUCH(source); TOUCH(prev_buffer); TOUCH(prev_time); TOUCH(prev_tag);
686 void
687 VideoProducer::LatencyChanged(const media_source &source,
688 const media_destination &destination, bigtime_t new_latency,
689 uint32 flags)
691 TOUCH(source); TOUCH(destination); TOUCH(new_latency); TOUCH(flags);
695 /* BControllable */
698 status_t
699 VideoProducer::GetParameterValue(
700 int32 id, bigtime_t *last_change, void *value, size_t *size)
702 status_t err;
704 switch (id) {
705 case P_COLOR:
706 //return B_BAD_VALUE;
708 *last_change = fLastColorChange;
709 *size = sizeof(uint32);
710 *((uint32 *)value) = fColor;
711 return B_OK;
712 case P_INFO:
713 if (*size < fInfoString.Length() + 1)
714 return EINVAL;
715 *last_change = fLastColorChange;
716 *size = fInfoString.Length() + 1;
717 memcpy(value, fInfoString.String(), *size);
718 return B_OK;
721 if (fCamDevice) {
722 BAutolock lock(fCamDevice->Locker());
723 err = fCamDevice->GetParameterValue(id, last_change, value, size);
724 if (err >= B_OK)
725 return err;
726 if (fCamDevice->Sensor()) {
727 err = fCamDevice->Sensor()->GetParameterValue(id, last_change, value, size);
728 if (err >= B_OK)
729 return err;
733 return B_BAD_VALUE;
737 void
738 VideoProducer::SetParameterValue(
739 int32 id, bigtime_t when, const void *value, size_t size)
741 status_t err = B_OK;
743 switch (id) {
744 case P_COLOR:
745 if (!value || (size != sizeof(uint32)))
746 return;
748 if (*(uint32 *)value == fColor)
749 return;
751 fColor = *(uint32 *)value;
752 fLastColorChange = when;
753 break;
754 case P_INFO:
755 // forbidden
756 return;
757 default:
758 if (fCamDevice == NULL)
759 return;
761 BAutolock lock(fCamDevice->Locker());
762 err = fCamDevice->SetParameterValue(id, when, value, size);
763 if ((err < B_OK) && (fCamDevice->Sensor())) {
764 err = fCamDevice->Sensor()->SetParameterValue(id, when, value, size);
768 if (err >= B_OK)
769 BroadcastNewParameterValue(when, id, (void *)value, size);
773 status_t
774 VideoProducer::StartControlPanel(BMessenger *out_messenger)
776 return BControllable::StartControlPanel(out_messenger);
780 /* VideoProducer */
783 void
784 VideoProducer::HandleStart(bigtime_t performance_time)
786 /* Start producing frames, even if the output hasn't been connected yet. */
788 PRINTF(1, ("HandleStart(%Ld)\n", performance_time));
790 if (fRunning) {
791 PRINTF(-1, ("HandleStart: Node already started\n"));
792 return;
795 fFrame = 0;
796 fFrameBase = 0;
797 fPerformanceTimeBase = performance_time;
799 fFrameSync = create_sem(0, "frame synchronization");
800 if (fFrameSync < B_OK)
801 goto err1;
803 fThread = spawn_thread(_frame_generator_, "frame generator",
804 B_NORMAL_PRIORITY, this);
805 if (fThread < B_OK)
806 goto err2;
808 resume_thread(fThread);
811 BAutolock lock(fCamDevice->Locker());
812 fCamDevice->StartTransfer();
815 fRunning = true;
816 return;
818 err2:
819 delete_sem(fFrameSync);
820 err1:
821 return;
825 void
826 VideoProducer::HandleStop(void)
828 PRINTF(1, ("HandleStop()\n"));
830 if (!fRunning) {
831 PRINTF(-1, ("HandleStop: Node isn't running\n"));
832 return;
835 delete_sem(fFrameSync);
836 wait_for_thread(fThread, &fThread);
838 BAutolock lock(fCamDevice->Locker());
839 fCamDevice->StopTransfer();
841 fRunning = false;
845 void
846 VideoProducer::HandleTimeWarp(bigtime_t performance_time)
848 fPerformanceTimeBase = performance_time;
849 fFrameBase = fFrame;
851 /* Tell frame generation thread to recalculate delay value */
852 release_sem(fFrameSync);
856 void
857 VideoProducer::HandleSeek(bigtime_t performance_time)
859 fPerformanceTimeBase = performance_time;
860 fFrameBase = fFrame;
862 /* Tell frame generation thread to recalculate delay value */
863 release_sem(fFrameSync);
867 void
868 VideoProducer::_UpdateStats()
870 float fps = (fStats[0].frames - fStats[1].frames) * 1000000LL
871 / (double)(fStats[0].stamp - fStats[1].stamp);
872 float rfps = (fStats[0].actual - fStats[1].actual) * 1000000LL
873 / (double)(fStats[0].stamp - fStats[1].stamp);
874 fInfoString = "FPS: ";
875 fInfoString << fps << " virt, "
876 << rfps << " real, missed: " << fStats[0].missed;
877 memcpy(&fStats[1], &fStats[0], sizeof(fStats[0]));
878 fLastColorChange = system_time();
879 BroadcastNewParameterValue(fLastColorChange, P_INFO,
880 (void *)fInfoString.String(), fInfoString.Length()+1);
884 /* The following functions form the thread that generates frames. You should
885 * replace this with the code that interfaces to your hardware. */
886 int32
887 VideoProducer::FrameGenerator()
889 bigtime_t wait_until = system_time();
891 while (1) {
892 PRINTF(1, ("FrameGenerator: acquire_sem_etc() until %Ldµs (in %Ldµs)\n", wait_until, wait_until - system_time()));
893 status_t err = acquire_sem_etc(fFrameSync, 1, B_ABSOLUTE_TIMEOUT,
894 wait_until);
896 /* The only acceptable responses are B_OK and B_TIMED_OUT. Everything
897 * else means the thread should quit. Deleting the semaphore, as in
898 * VideoProducer::HandleStop(), will trigger this behavior. */
899 if ((err != B_OK) && (err != B_TIMED_OUT))
900 break;
902 fFrame++;
904 /* Recalculate the time until the thread should wake up to begin
905 * processing the next frame. Subtract fProcessingLatency so that
906 * the frame is sent in time. */
907 wait_until = TimeSource()->RealTimeFor(fPerformanceTimeBase, 0) +
908 (bigtime_t)
909 ((fFrame - fFrameBase) *
910 (1000000 / fConnectedFormat.field_rate)) -
911 fProcessingLatency;
912 PRINT(("PS: %Ld\n", fProcessingLatency));
914 /* Drop frame if it's at least a frame late */
915 if (wait_until < system_time())
916 continue;
918 PRINTF(1, ("FrameGenerator: wait until %Ld, %ctimed out, %crunning, %cenabled.\n",
919 wait_until,
920 (err == B_OK)?'!':' ',
921 (fRunning)?' ':'!',
922 (fEnabled)?' ':'!'));
924 /* If the semaphore was acquired successfully, it means something
925 * changed the timing information (see VideoProducer::Connect()) and
926 * so the thread should go back to sleep until the newly-calculated
927 * wait_until time. */
928 if (err == B_OK)
929 continue;
931 /* Send buffers only if the node is running and the output has been
932 * enabled */
933 if (!fRunning || !fEnabled)
934 continue;
936 BAutolock _(fLock);
938 /* Fetch a buffer from the buffer group */
939 BBuffer *buffer = fBufferGroup->RequestBuffer(
940 4 * fConnectedFormat.display.line_width *
941 fConnectedFormat.display.line_count, 0LL);
942 if (!buffer)
943 continue;
945 /* Fill out the details about this buffer. */
946 media_header *h = buffer->Header();
947 h->type = B_MEDIA_RAW_VIDEO;
948 h->time_source = TimeSource()->ID();
949 h->size_used = 4 * fConnectedFormat.display.line_width *
950 fConnectedFormat.display.line_count;
951 /* For a buffer originating from a device, you might want to calculate
952 * this based on the PerformanceTimeFor the time your buffer arrived at
953 * the hardware (plus any applicable adjustments). */
955 h->start_time = fPerformanceTimeBase +
956 (bigtime_t)
957 ((fFrame - fFrameBase) *
958 (1000000 / fConnectedFormat.field_rate));
960 h->file_pos = 0;
961 h->orig_size = 0;
962 h->data_offset = 0;
963 h->u.raw_video.field_gamma = 1.0;
964 h->u.raw_video.field_sequence = fFrame;
965 h->u.raw_video.field_number = 0;
966 h->u.raw_video.pulldown_number = 0;
967 h->u.raw_video.first_active_line = 1;
968 h->u.raw_video.line_count = fConnectedFormat.display.line_count;
970 // This is where we fill the video buffer.
972 #if 0
973 uint32 *p = (uint32 *)buffer->Data();
974 /* Fill in a pattern */
975 for (uint32 y=0;y<fConnectedFormat.display.line_count;y++)
976 for (uint32 x=0;x<fConnectedFormat.display.line_width;x++)
977 *(p++) = ((((x+y)^0^x)+fFrame) & 0xff) * (0x01010101 & fColor);
978 #endif
980 //NO! must be called without lock!
981 //BAutolock lock(fCamDevice->Locker());
983 bigtime_t now = system_time();
984 bigtime_t stamp;
985 //#ifdef UseFillFrameBuffer
986 err = fCamDevice->FillFrameBuffer(buffer, &stamp);
987 if (err < B_OK) {
988 ;//XXX handle error
989 fStats[0].missed++;
991 //#endif
992 #ifdef UseGetFrameBitmap
993 BBitmap *bm;
994 err = fCamDevice->GetFrameBitmap(&bm, &stamp);
995 if (err >= B_OK) {
996 ;//XXX handle error
997 fStats[0].missed++;
999 #endif
1000 fStats[0].frames = fFrame;
1001 fStats[0].actual++;;
1002 fStats[0].stamp = system_time();
1004 //PRINTF(1, ("FrameGenerator: stamp %Ld vs %Ld\n", stamp, h->start_time));
1005 //XXX: that's what we should be doing, but CodyCam drops all frames as they are late. (maybe add latency ??)
1006 //h->start_time = TimeSource()->PerformanceTimeFor(stamp);
1007 h->start_time = TimeSource()->PerformanceTimeFor(system_time());
1010 // update processing latency
1011 // XXX: should I ??
1012 fProcessingLatency = system_time() - now;
1013 fProcessingLatency /= 10;
1015 PRINTF(1, ("FrameGenerator: SendBuffer...\n"));
1016 /* Send the buffer on down to the consumer */
1017 if (SendBuffer(buffer, fOutput.source, fOutput.destination) < B_OK) {
1018 PRINTF(-1, ("FrameGenerator: Error sending buffer\n"));
1019 /* If there is a problem sending the buffer, return it to its
1020 * buffer group. */
1021 buffer->Recycle();
1024 _UpdateStats();
1027 PRINTF(1, ("FrameGenerator: thread existed.\n"));
1028 return B_OK;
1032 int32
1033 VideoProducer::_frame_generator_(void *data)
1035 return ((VideoProducer *)data)->FrameGenerator();