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
42const float kUSBBandWidthMin = 0.5f;
43const float kUSBBandWidthMax = 7.5f;
44const float kUSBBandWidthStep = 0.5f;
45
46const float kVScreenOffsetMin = 0.f;
47const float kVScreenOffsetMax = 4.f;
48const float kVScreenOffsetStep = 1.f;
49const float kHScreenOffsetMin = 0.f;
50const float kHScreenOffsetMax = 4.f;
51const float kHScreenOffsetStep = 1.f;
52
53const float kEffectMin = 0.f;
54const float kEffectMax = 31.f;
55const float kEffectStep = 1.f;
56
57const float kBrightnessMin = kEffectMin;
58const float kBrightnessMax = kEffectMax;
59const float kBrightnessStep = kEffectStep;
60
61const float kContrastMin = kEffectMin;
62const float kContrastMax = kEffectMax;
63const float kContrastStep = kEffectStep;
64
65const float kHueMin = kEffectMin;
66const float kHueMax = kEffectMax;
67const float kHueStep = kEffectStep;
68
69const float kSaturationMin = kEffectMin;
70const float kSaturationMax = kEffectMax;
71const float kSaturationStep = kEffectStep;
72
73const uint32        kDefChannel = 0;
74//const VideoInput    kDefVideoInput = P_VI_TUNER;
75const uint32        kDefAudioInput = 0;
76const uint32        kDefBrightness = 20;
77const uint32        kDefContrast = 22;
78const uint32        kDefSaturation = 15;
79const uint32        kDefHue = 20;
80const uint32        kDefCaptureSize = 0;
81const uint32        kDefCaptureFormat = 0;
82//const VideoStandard kDefStandard = P_VF_PAL_BDGHI;
83const float         kDefBandwidth = 7.0;
84const uint32        kDefLocale = 0;
85const uint32        kDefVertOffset = 1;
86const uint32        kDefHorzOffset = 2;
87
88int32 VideoProducer::fInstances = 0;
89
90VideoProducer::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
165VideoProducer::~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
183port_id
184VideoProducer::ControlPort() const
185{
186	return BMediaNode::ControlPort();
187}
188
189BMediaAddOn *
190VideoProducer::AddOn(int32 *internal_id) const
191{
192	if (internal_id)
193		*internal_id = fInternalID;
194	return fAddOn;
195}
196
197status_t
198VideoProducer::HandleMessage(int32 message, const void *data, size_t size)
199{
200	return B_ERROR;
201}
202
203void
204VideoProducer::Preroll()
205{
206	/* This hook may be called before the node is started to give the hardware
207	 * a chance to start. */
208}
209
210void
211VideoProducer::SetTimeSource(BTimeSource *time_source)
212{
213	/* Tell frame generation thread to recalculate delay value */
214	release_sem(fFrameSync);
215}
216
217status_t
218VideoProducer::RequestCompleted(const media_request_info &info)
219{
220	return BMediaNode::RequestCompleted(info);
221}
222
223/* BMediaEventLooper */
224
225void
226VideoProducer::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
253BParameterWeb  *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
350void
351VideoProducer::Start(bigtime_t performance_time)
352{
353	BMediaEventLooper::Start(performance_time);
354}
355
356void
357VideoProducer::Stop(bigtime_t performance_time, bool immediate)
358{
359	BMediaEventLooper::Stop(performance_time, immediate);
360}
361
362void
363VideoProducer::Seek(bigtime_t media_time, bigtime_t performance_time)
364{
365	BMediaEventLooper::Seek(media_time, performance_time);
366}
367
368void
369VideoProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
370{
371	BMediaEventLooper::TimeWarp(at_real_time, to_performance_time);
372}
373
374status_t
375VideoProducer::AddTimer(bigtime_t at_performance_time, int32 cookie)
376{
377	return BMediaEventLooper::AddTimer(at_performance_time, cookie);
378}
379
380void
381VideoProducer::SetRunMode(run_mode mode)
382{
383	BMediaEventLooper::SetRunMode(mode);
384}
385
386void
387VideoProducer::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
417void
418VideoProducer::CleanUpEvent(const media_timed_event *event)
419{
420	BMediaEventLooper::CleanUpEvent(event);
421}
422
423bigtime_t
424VideoProducer::OfflineTime()
425{
426	return BMediaEventLooper::OfflineTime();
427}
428
429void
430VideoProducer::ControlLoop()
431{
432	BMediaEventLooper::ControlLoop();
433}
434
435status_t
436VideoProducer::DeleteHook(BMediaNode * node)
437{
438	return BMediaEventLooper::DeleteHook(node);
439}
440
441/* BBufferProducer */
442
443status_t
444VideoProducer::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
456status_t
457VideoProducer::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
474status_t
475VideoProducer::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
486status_t
487VideoProducer::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
500status_t
501VideoProducer::DisposeOutputCookie(int32 cookie)
502{
503	TOUCH(cookie);
504
505	return B_OK;
506}
507
508status_t
509VideoProducer::SetBufferGroup(const media_source &for_source,
510		BBufferGroup *group)
511{
512	TOUCH(for_source); TOUCH(group);
513
514	return B_ERROR;
515}
516
517status_t
518VideoProducer::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
528status_t
529VideoProducer::GetLatency(bigtime_t *out_latency)
530{
531	*out_latency = EventLatency() + SchedulingLatency();
532	return B_OK;
533}
534
535status_t
536VideoProducer::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
579void
580VideoProducer::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
649void
650VideoProducer::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
676void
677VideoProducer::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
683void
684VideoProducer::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
695status_t
696VideoProducer::SetPlayRate(int32 numer, int32 denom)
697{
698	TOUCH(numer); TOUCH(denom);
699
700	return B_ERROR;
701}
702
703void
704VideoProducer::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
711void
712VideoProducer::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
721status_t
722VideoProducer::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
807void
808VideoProducer::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
940status_t
941VideoProducer::StartControlPanel(BMessenger *out_messenger)
942{
943	return BControllable::StartControlPanel(out_messenger);
944}
945
946/* VideoProducer */
947
948void
949VideoProducer::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
978err2:
979	delete_sem(fFrameSync);
980err1:
981	return;
982}
983
984void
985VideoProducer::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
1000void
1001VideoProducer::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
1010void
1011VideoProducer::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
1020void
1021VideoProducer::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. */
1077int32
1078VideoProducer::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
1169int32
1170VideoProducer::_frame_generator_(void *data)
1171{
1172	return ((VideoProducer *)data)->FrameGenerator();
1173}
1174