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
VideoProducer(BMediaAddOn * addon,const char * name,int32 internal_id)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
~VideoProducer()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
ControlPort() const184 VideoProducer::ControlPort() const
185 {
186 return BMediaNode::ControlPort();
187 }
188
189 BMediaAddOn *
AddOn(int32 * internal_id) const190 VideoProducer::AddOn(int32 *internal_id) const
191 {
192 if (internal_id)
193 *internal_id = fInternalID;
194 return fAddOn;
195 }
196
197 status_t
HandleMessage(int32 message,const void * data,size_t size)198 VideoProducer::HandleMessage(int32 message, const void *data, size_t size)
199 {
200 return B_ERROR;
201 }
202
203 void
Preroll()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
SetTimeSource(BTimeSource * time_source)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
RequestCompleted(const media_request_info & info)218 VideoProducer::RequestCompleted(const media_request_info &info)
219 {
220 return BMediaNode::RequestCompleted(info);
221 }
222
223 /* BMediaEventLooper */
224
225 void
NodeRegistered()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
CreateParameterWeb()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
Start(bigtime_t performance_time)351 VideoProducer::Start(bigtime_t performance_time)
352 {
353 BMediaEventLooper::Start(performance_time);
354 }
355
356 void
Stop(bigtime_t performance_time,bool immediate)357 VideoProducer::Stop(bigtime_t performance_time, bool immediate)
358 {
359 BMediaEventLooper::Stop(performance_time, immediate);
360 }
361
362 void
Seek(bigtime_t media_time,bigtime_t performance_time)363 VideoProducer::Seek(bigtime_t media_time, bigtime_t performance_time)
364 {
365 BMediaEventLooper::Seek(media_time, performance_time);
366 }
367
368 void
TimeWarp(bigtime_t at_real_time,bigtime_t to_performance_time)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
AddTimer(bigtime_t at_performance_time,int32 cookie)375 VideoProducer::AddTimer(bigtime_t at_performance_time, int32 cookie)
376 {
377 return BMediaEventLooper::AddTimer(at_performance_time, cookie);
378 }
379
380 void
SetRunMode(run_mode mode)381 VideoProducer::SetRunMode(run_mode mode)
382 {
383 BMediaEventLooper::SetRunMode(mode);
384 }
385
386 void
HandleEvent(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)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
CleanUpEvent(const media_timed_event * event)418 VideoProducer::CleanUpEvent(const media_timed_event *event)
419 {
420 BMediaEventLooper::CleanUpEvent(event);
421 }
422
423 bigtime_t
OfflineTime()424 VideoProducer::OfflineTime()
425 {
426 return BMediaEventLooper::OfflineTime();
427 }
428
429 void
ControlLoop()430 VideoProducer::ControlLoop()
431 {
432 BMediaEventLooper::ControlLoop();
433 }
434
435 status_t
DeleteHook(BMediaNode * node)436 VideoProducer::DeleteHook(BMediaNode * node)
437 {
438 return BMediaEventLooper::DeleteHook(node);
439 }
440
441 /* BBufferProducer */
442
443 status_t
FormatSuggestionRequested(media_type type,int32 quality,media_format * format)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
FormatProposal(const media_source & output,media_format * format)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
FormatChangeRequested(const media_source & source,const media_destination & destination,media_format * io_format,int32 * _deprecated_)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
GetNextOutput(int32 * cookie,media_output * out_output)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
DisposeOutputCookie(int32 cookie)501 VideoProducer::DisposeOutputCookie(int32 cookie)
502 {
503 TOUCH(cookie);
504
505 return B_OK;
506 }
507
508 status_t
SetBufferGroup(const media_source & for_source,BBufferGroup * group)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
VideoClippingChanged(const media_source & for_source,int16 num_shorts,int16 * clip_data,const media_video_display_info & display,int32 * _deprecated_)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
GetLatency(bigtime_t * out_latency)529 VideoProducer::GetLatency(bigtime_t *out_latency)
530 {
531 *out_latency = EventLatency() + SchedulingLatency();
532 return B_OK;
533 }
534
535 status_t
PrepareToConnect(const media_source & source,const media_destination & destination,media_format * format,media_source * out_source,char * out_name)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
Connect(status_t error,const media_source & source,const media_destination & destination,const media_format & format,char * io_name)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
Disconnect(const media_source & source,const media_destination & destination)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
LateNoticeReceived(const media_source & source,bigtime_t how_much,bigtime_t performance_time)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
EnableOutput(const media_source & source,bool enabled,int32 * _deprecated_)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
SetPlayRate(int32 numer,int32 denom)696 VideoProducer::SetPlayRate(int32 numer, int32 denom)
697 {
698 TOUCH(numer); TOUCH(denom);
699
700 return B_ERROR;
701 }
702
703 void
AdditionalBufferRequested(const media_source & source,media_buffer_id prev_buffer,bigtime_t prev_time,const media_seek_tag * prev_tag)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
LatencyChanged(const media_source & source,const media_destination & destination,bigtime_t new_latency,uint32 flags)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
GetParameterValue(int32 id,bigtime_t * last_change,void * value,size_t * size)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
SetParameterValue(int32 id,bigtime_t when,const void * value,size_t size)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
StartControlPanel(BMessenger * out_messenger)941 VideoProducer::StartControlPanel(BMessenger *out_messenger)
942 {
943 return BControllable::StartControlPanel(out_messenger);
944 }
945
946 /* VideoProducer */
947
948 void
HandleStart(bigtime_t performance_time)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(%lld)\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
HandleStop(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
HandleTimeWarp(bigtime_t performance_time)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
HandleSeek(bigtime_t performance_time)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
HandleParameter(uint32 parameter)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
FrameGenerator()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
_frame_generator_(void * data)1170 VideoProducer::_frame_generator_(void *data)
1171 {
1172 return ((VideoProducer *)data)->FrameGenerator();
1173 }
1174