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