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