xref: /haiku/src/add-ons/media/media-add-ons/radeon/RadeonProducer.cpp (revision 863634b83f627a5950315df1added5f754d42c23)
1 /******************************************************************************
2 /
3 /	File:			RadeonProducer.cpp
4 /
5 /	Description:	ATI Radeon Video Producer media node.
6 /
7 /	Copyright 2001, Carlos Hasan
8 /
9 *******************************************************************************/
10 
11 #include <fcntl.h>
12 #include <malloc.h>
13 #include <math.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/uio.h>
17 #include <unistd.h>
18 #include <scheduler.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 #include <app/Message.h>
29 
30 #include "RadeonAddOn.h"
31 #include "VideoIn.h"
32 
33 #define DPRINT(args)	{ PRINT(("\x1b[0;30;35m")); PRINT(args); PRINT(("\x1b[0;30;47m")); }
34 
35 #define TOUCH(x) ((void)(x))
36 
37 #define PRINTF(a,b) \
38 		do { \
39 			if (a < 2) { \
40 				printf("CRadeonProducer::"); \
41 				printf b; \
42 			} \
43 		} while (0)
44 
45 #include "RadeonProducer.h"
46 
47 // convert Be video standard to video-in standard;
48 // Be forgot some standards and define code 7 and 8 to be MPEG1/2, i.e.
49 // didn't leave any space for enhancements, so I chose to use 101 and up;
50 // this way, we get a scattered list of video standards, needing special
51 // functions to convert to scattered Be-code to the compact video-in-code
BeToVideoInStandard(int32 be_standard)52 video_in_standard BeToVideoInStandard( int32 be_standard )
53 {
54 
55 	DPRINT(("BeToVideoInStandard %d \n", be_standard));
56 	switch( be_standard ) {
57 	case 1:	return C_VIDEO_IN_NTSC;
58 	case 2:	return C_VIDEO_IN_NTSC_JAPAN;
59 	case 3:	return C_VIDEO_IN_PAL_BDGHI;
60 	case 4:	return C_VIDEO_IN_PAL_M;
61 	case 5:	return C_VIDEO_IN_PAL_N;
62 	case 6:	return C_VIDEO_IN_SECAM;
63 	case 101:	return C_VIDEO_IN_NTSC_443;
64 	case 102:	return C_VIDEO_IN_PAL_60;
65 	case 103:	return C_VIDEO_IN_PAL_NC;
66 	default:	return C_VIDEO_IN_NTSC;
67 	}
68 }
69 
VideoInStandardToBe(video_in_standard standard)70 int32 VideoInStandardToBe( video_in_standard standard )
71 {
72 	DPRINT(("VideoInStandardToBe %d \n", standard));
73 	switch( standard ) {
74 		case C_VIDEO_IN_NTSC:		return 1;
75 		case C_VIDEO_IN_NTSC_JAPAN:	return 2;
76 		case C_VIDEO_IN_PAL_BDGHI:	return 3;
77 		case C_VIDEO_IN_PAL_M:		return 4;
78 		case C_VIDEO_IN_PAL_N:		return 5;
79 		case C_VIDEO_IN_SECAM:		return 6;
80 		case C_VIDEO_IN_NTSC_443:	return 101;
81 		case C_VIDEO_IN_PAL_60:		return 102;
82 		case C_VIDEO_IN_PAL_NC:		return 103;
83 		default: return 1;
84 	}
85 }
86 
FindInt32(BMessage * config,EOptions option,int32 min_value,int32 max_value,int32 default_value,int32 * value)87 status_t CRadeonProducer::FindInt32(
88 	BMessage *config, EOptions option, int32 min_value, int32 max_value,
89 	int32 default_value, int32 *value )
90 {
91 	char name[5];
92 	status_t res;
93 
94 	*value = default_value;
95 
96 	*(int32 *)name = option;
97 	name[4] = 0;
98 
99 	res = config->FindInt32( name, value );
100 	if( res == B_NAME_NOT_FOUND )
101 		return B_OK;
102 
103 	if( res != B_OK )
104 		return res;
105 
106 	*value = MAX( *value, min_value );
107 	*value = MIN( *value, max_value );
108 	return B_OK;
109 }
110 
CRadeonProducer(CRadeonAddOn * addon,const char * name,const char * device_name,int32 internal_id,BMessage * config)111 CRadeonProducer::CRadeonProducer(
112 		CRadeonAddOn *addon, const char *name, const char *device_name, int32 internal_id,
113 		BMessage *config )
114   :	BMediaNode(name),
115 	BMediaEventLooper(),
116 	BBufferProducer(B_MEDIA_RAW_VIDEO),
117 	BControllable(),
118 	fVideoIn( device_name )
119 {
120 	DPRINT(("CRadeonProducer::CRadeonProducer()\n"));
121 
122 	fInitStatus = B_NO_INIT;
123 
124 	fInternalID = internal_id;
125 	fAddOn = addon;
126 
127 	fBufferGroup = NULL;
128 	//fUsedBufferGroup = NULL;
129 
130 	fProcessingLatency = 0LL;
131 
132 	//fConnected = false;
133 	fEnabled = true;
134 
135 	AddNodeKind(B_PHYSICAL_INPUT);
136 
137 	if( fVideoIn.InitCheck() == B_OK )
138 		fInitStatus = B_OK;
139 
140 	fSource = ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0 ? C_VIDEO_IN_TUNER : C_VIDEO_IN_COMPOSITE);
141 	fStandard = C_VIDEO_IN_NTSC;
142 	fMode = C_VIDEO_IN_WEAVE;
143 	fFormat = B_RGB32;
144 	fResolution = 4;
145 	fTuner = 25;
146 	fBrightness = 0;
147 	fContrast = 0;
148 	fSaturation = 0;
149 	fHue = 0;
150 	fSharpness = 0;
151 
152 	if( config != NULL ) {
153 		status_t res;
154 		int32 standard;
155 
156 		if( (res = FindInt32( config, P_SOURCE, 0, C_VIDEO_IN_SOURCE_MAX,
157 			 (fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0 ? C_VIDEO_IN_TUNER : C_VIDEO_IN_COMPOSITE,
158 			 &fSource )) != B_OK ||
159 			(res = FindInt32( config, P_STANDARD, 0, C_VIDEO_IN_STANDARD_MAX,
160 				C_VIDEO_IN_NTSC, &standard )) != B_OK ||
161 			(res = FindInt32( config, P_MODE, 0, C_VIDEO_IN_CAPTURE_MODE_MAX,
162 				C_VIDEO_IN_FIELD, &fMode )) != B_OK ||
163 			(res = FindInt32( config, P_FORMAT, -2147483647L-1, 2147483647L,
164 				B_RGB16, &fFormat )) != B_OK ||
165 			(res = FindInt32( config, P_RESOLUTION, 0, C_RESOLUTION_MAX,
166 				4, &fResolution )) != B_OK ||
167 			(res = FindInt32( config, P_TUNER, 0, C_CHANNEL_MAX,
168 				25, &fTuner )) != B_OK ||
169 			(res = FindInt32( config, P_BRIGHTNESS, -100, +100,
170 				0, &fBrightness )) != B_OK ||
171 			(res = FindInt32( config, P_CONTRAST, 0, 100,
172 				0, &fContrast )) != B_OK ||
173 			(res = FindInt32( config, P_SATURATION, -100, +100,
174 				0, &fSaturation )) != B_OK ||
175 			(res = FindInt32( config, P_HUE, -90, +90,
176 				0, &fHue )) != B_OK ||
177 			(res = FindInt32( config, P_SHARPNESS, 0, 15,
178 				0, &fSharpness )) != B_OK )
179 		{
180 			DPRINT(("Corrupted settings (%s)\n", strerror( res )));
181 		}
182 
183 		// standard is stored as internal code (which has no "holes" in its numbering);
184 		// time to convert it
185 		// if this value comes from our setup web is it not already linear?
186 		fStandard = VideoInStandardToBe( (video_in_standard)standard );
187 
188 		// if there is no tuner, force composite input
189 		if( (fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) == 0 )
190 			fSource = C_VIDEO_IN_COMPOSITE;
191 
192 		// format ids are scattered, so we must verify them manually
193 		switch( fFormat ) {
194 		case B_YCbCr422:
195 		case B_GRAY8:
196 		case B_RGB15:
197 		case B_RGB16:
198 		case B_RGB32:
199 			break;
200 		default:
201 			fFormat = B_RGB16;
202 		}
203 	}
204 
205 	fSourceLastChange =
206 	fStandardLastChange =
207 	fModeLastChange =
208 	fFormatLastChange =
209 	fResolutionLastChange =
210 	fTunerLastChange =
211 	fBrightnessLastChange =
212 	fContrastLastChange =
213 	fSaturationLastChange =
214 	fHueLastChange =
215 	fSharpnessLastChange = system_time();
216 
217 	fOutput.destination = media_destination::null;
218 	strcpy(fOutput.name, Name());
219 
220 	// we provide interlaced raw video in any format
221 	fOutput.format.type = B_MEDIA_RAW_VIDEO;
222 	fOutput.format.u.raw_video = media_raw_video_format::wildcard;
223 }
224 
225 
setupWeb()226 void CRadeonProducer::setupWeb()
227 {
228 	///////////
229 	/* Set up the parameter web */
230 
231 	// in "kind" value of parameters is "stampTV-compatible", i.e.
232 	// if not defined, we use the name used in stampTV
233 	BParameterWeb *web = new BParameterWeb();
234 	BParameterGroup *controls = web->MakeGroup("Controls");
235 	BParameterGroup *options = web->MakeGroup("Video");
236 	/*BParameterGroup *audio = web->MakeGroup("Audio");*/
237 
238 	BParameterGroup *controls1 = controls->MakeGroup("Controls1");
239 	BParameterGroup *controls2 = controls->MakeGroup("Controls2");
240 	BParameterGroup *controls3 = controls->MakeGroup("Controls3");
241 
242 	BParameterGroup *options1 = options->MakeGroup("Options1");
243 	BParameterGroup *options2 = options->MakeGroup("Options2");
244 
245 	/*BParameterGroup *audio1 = audio->MakeGroup("Audio1");
246 	BParameterGroup *audio2 = audio->MakeGroup("Audio2");*/
247 
248 
249 	// Controls
250 	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0) {
251 		// Controls.Channel
252 		BDiscreteParameter *tuner = controls1->MakeDiscreteParameter(
253 			P_TUNER, B_MEDIA_NO_TYPE, "Channel:", B_TUNER_CHANNEL);
254 
255 		for (int channel = 0; channel <= 125; channel++) {
256 			char buffer[32];
257 			sprintf(buffer, "%d", channel);
258 			tuner->AddItem(channel, buffer);
259 		}
260 	}
261 
262 	// Controls.Source
263 	BDiscreteParameter *source = controls1->MakeDiscreteParameter(
264 		P_SOURCE, B_MEDIA_RAW_VIDEO, "Video Input:", "Video Input:");
265 
266 	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0)
267 		source->AddItem(C_VIDEO_IN_TUNER, "Tuner");
268 	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_COMPOSITE) != 0)
269 		source->AddItem(C_VIDEO_IN_COMPOSITE, "Composite");
270 	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_SVIDEO) != 0)
271 		source->AddItem(C_VIDEO_IN_SVIDEO, "SVideo");
272 
273 	// TODO:
274 	BDiscreteParameter *source2 = controls1->MakeDiscreteParameter(
275 		P_AUDIO_SOURCE, B_MEDIA_RAW_VIDEO, "Audio Input:", "Audio Input:");
276 	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0)
277 		source2->AddItem(C_VIDEO_IN_TUNER, "Tuner");
278 /*	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_COMPOSITE) != 0)
279 		source2->AddItem(C_VIDEO_IN_COMPOSITE, "Composite");
280 	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_SVIDEO) != 0)
281 		source2->AddItem(C_VIDEO_IN_SVIDEO, "SVideo");
282 */
283 
284 	// Controls.Brightness/Contrast/Saturation/Hue
285 	controls2->MakeContinuousParameter(P_BRIGHTNESS, B_MEDIA_RAW_VIDEO,"Brightness", "BRIGHTNESS", "", -100, 100, 1);
286 	controls2->MakeContinuousParameter(P_CONTRAST, B_MEDIA_RAW_VIDEO, "Contrast", "CONTRAST", "", 0, 100, 1);
287 	controls2->MakeContinuousParameter(P_SHARPNESS, B_MEDIA_RAW_VIDEO, "Sharpness", B_LEVEL, "dB", 0, 15, 1);
288 
289 	controls3->MakeContinuousParameter(P_SATURATION, B_MEDIA_RAW_VIDEO, "Saturation", "SATURATION", "", -100, 100, 1);
290 	controls3->MakeContinuousParameter(P_HUE, B_MEDIA_RAW_VIDEO, "Hue", B_LEVEL, "°", -90, 90, 1);
291 
292 
293 	// Options.Resolution
294 	BDiscreteParameter *resolution = options1->MakeDiscreteParameter(
295 		P_RESOLUTION, B_MEDIA_RAW_VIDEO, "Default Image Size:", B_RESOLUTION);
296 
297 	resolution->AddItem(6, "768x576");
298 	resolution->AddItem(5, "720x576");
299 	resolution->AddItem(4, "720x480");
300 	resolution->AddItem(0, "640x480");
301 	resolution->AddItem(3, "480x360");
302 	resolution->AddItem(1, "320x240");
303 	resolution->AddItem(2, "160x120");
304 
305 	// Options.Format
306 	BDiscreteParameter *format = options1->MakeDiscreteParameter(
307 		P_FORMAT, B_MEDIA_RAW_VIDEO, "Default Colors:", B_COLOR_SPACE);
308 
309 	format->AddItem(B_YCbCr422, "YCbCr422 (fastest)");
310 	format->AddItem(B_GRAY8, "8 Bits/Pixel (gray)");
311 	format->AddItem(B_RGB15, "15 Bits/Pixel");
312 	format->AddItem(B_RGB16, "16 Bits/Pixel");
313 	format->AddItem(B_RGB32, "32 Bits/Pixel");
314 
315 	// Options.Standard
316 	BDiscreteParameter *standard = options2->MakeDiscreteParameter(
317 		P_STANDARD, B_MEDIA_RAW_VIDEO, "Video Format:", B_VIDEO_FORMAT);
318 
319 	standard->AddItem(1, "NTSC");
320 	standard->AddItem(2, "NTSC Japan");
321 	standard->AddItem(101, "NTSC 443");
322 	standard->AddItem(4, "PAL M");
323 	standard->AddItem(3, "PAL BDGHI");
324 	standard->AddItem(5, "PAL N");
325 	standard->AddItem(102, "PAL 60");
326 	standard->AddItem(103, "PAL NC");
327 	standard->AddItem(6, "SECAM");
328 
329 	// Options.Mode
330 	BDiscreteParameter *mode = options2->MakeDiscreteParameter(
331 		P_MODE, B_MEDIA_RAW_VIDEO, "Video Interlace:", B_GENERIC);
332 
333 	mode->AddItem(C_VIDEO_IN_FIELD, "Field");
334 	mode->AddItem(C_VIDEO_IN_BOB, "Bob");
335 	mode->AddItem(C_VIDEO_IN_WEAVE, "Weave");
336 
337 
338 	// TODO:
339 	/*
340 	BDiscreteParameter *standard2 = audio1->MakeDiscreteParameter(
341 		P_AUDIO_FORMAT, B_MEDIA_RAW_VIDEO, "Audio Format:", B_VIDEO_FORMAT);
342 	standard2->AddItem(0, "Stereo");
343 	standard2->AddItem(1, "Mono");
344 	standard2->AddItem(2, "NICAM");
345 
346 	BDiscreteParameter *audioSource = audio1->MakeDiscreteParameter(
347 		P_AUDIO_FORMAT, B_MEDIA_RAW_VIDEO, "Audio Source:", B_VIDEO_FORMAT);
348 	audioSource->AddItem(0, "FM");
349 	audioSource->AddItem(1, "Stereo");
350 	audioSource->AddItem(2, "SCART");
351 	audioSource->AddItem(3, "Language A");
352 	audioSource->AddItem(4, "Language B");
353 
354 	BDiscreteParameter *matrix= audio2->MakeDiscreteParameter(
355 		P_AUDIO_FORMAT, B_MEDIA_RAW_VIDEO, "Audio Matrix:", B_VIDEO_FORMAT);
356 	matrix->AddItem(0, "Sound A");
357 	matrix->AddItem(1, "Sound B");
358 	matrix->AddItem(2, "Stereo");
359 	matrix->AddItem(3, "Mono");*/
360 
361 	/* After this call, the BControllable owns the BParameterWeb object and
362 	 * will delete it for you */
363 	SetParameterWeb(web);
364 	/////////
365 }
366 
~CRadeonProducer()367 CRadeonProducer::~CRadeonProducer()
368 {
369 	DPRINT(("CRadeonProducer::~CRadeonProducer()\n"));
370 
371 	if (fInitStatus == B_OK) {
372 		/* Clean up after ourselves, in case the application didn't make us
373 		 * do so. */
374 		/*if (fConnected)
375 			Disconnect(fOutput.source, fOutput.destination);*/
376 
377 		HandleStop();
378 	}
379 
380 	delete fBufferGroup;
381 	fBufferGroup = NULL;
382 
383 	BMessage settings;
384 
385 	GetConfiguration( &settings );
386 
387 	fAddOn->UnregisterNode( this, &settings );
388 
389 	Quit();
390 }
391 
392 /* BMediaNode */
393 
394 port_id
ControlPort() const395 CRadeonProducer::ControlPort() const
396 {
397 	return BMediaNode::ControlPort();
398 }
399 
400 BMediaAddOn *
AddOn(int32 * internal_id) const401 CRadeonProducer::AddOn(int32 *internal_id) const
402 {
403 	if (internal_id)
404 		*internal_id = fInternalID;
405 	return fAddOn;
406 }
407 
408 status_t
HandleMessage(int32 message,const void * data,size_t size)409 CRadeonProducer::HandleMessage(int32 message, const void *data, size_t size)
410 {
411 	//DPRINT(("CRadeonProducer::HandleMessage()\n"));
412 
413 	switch( message ) {
414 		case C_GET_CONFIGURATION: {
415 			const configuration_msg *request = (const configuration_msg *)data;
416 			BMessage msg;
417 			configuration_msg_reply *reply;
418 			size_t reply_size, config_size;
419 			status_t res;
420 
421 			if( size < sizeof( configuration_msg ))
422 				return B_ERROR;
423 
424 			res = GetConfiguration( &msg );
425 
426 			config_size = msg.FlattenedSize();
427 			reply_size = sizeof( *reply ) + config_size;
428 			reply = (configuration_msg_reply *)malloc( reply_size );
429 			if( reply == NULL )
430 				return B_NO_MEMORY;
431 
432 			reply->res = res;
433 			reply->config_size = config_size;
434 			msg.Flatten( &reply->config, config_size );
435 
436 			write_port_etc( request->reply_port, C_GET_CONFIGURATION_REPLY,
437 				reply, reply_size, B_TIMEOUT, 0 );
438 
439 			free( reply );
440 			return B_OK;
441 		}
442 		default:
443 			return B_ERROR;
444 	//	return BControllable::HandleMessage(message, data, size);
445 	}
446 }
447 
448 void
Preroll()449 CRadeonProducer::Preroll()
450 {
451 	/* This hook may be called before the node is started to give the hardware
452 	 * a chance to start. */
453 	DPRINT(("CRadeonProducer::Preroll()\n"));
454 }
455 
456 void
SetTimeSource(BTimeSource * time_source)457 CRadeonProducer::SetTimeSource(BTimeSource *time_source)
458 {
459 	DPRINT(("CRadeonProducer::SetTimeSource()\n"));
460 
461 	/* Tell frame generation thread to recalculate delay value */
462 	//release_sem(fFrameSync);
463 }
464 
465 status_t
RequestCompleted(const media_request_info & info)466 CRadeonProducer::RequestCompleted(const media_request_info &info)
467 {
468 	DPRINT(("CRadeonProducer::RequestCompleted()\n"));
469 
470 	return BMediaNode::RequestCompleted(info);
471 }
472 
473 /* BMediaEventLooper */
474 
475 void
NodeRegistered()476 CRadeonProducer::NodeRegistered()
477 {
478 	DPRINT(("CRadeonProducer::NodeRegistered()\n"));
479 
480 	if (fInitStatus != B_OK) {
481 		ReportError(B_NODE_IN_DISTRESS);
482 		return;
483 	}
484 
485 	setupWeb();
486 //!!//
487 
488 	fOutput.node = Node();
489 	fOutput.source.port = ControlPort();
490 	fOutput.source.id = 0;
491 
492 	/* Tailor these for the output of your device */
493 	/********
494 	fOutput.format.type = B_MEDIA_RAW_VIDEO;
495 	fOutput.format.u.raw_video = media_raw_video_format::wildcard;
496 //	fOutput.format.u.raw_video.interlace = 1;
497 	fOutput.format.u.raw_video.display.format = B_RGB32;
498 	********/
499 
500 	// up to 60 frames (NTSC); jitter less then half a frame; processing time
501 	// depends on whether colour space conversion is required, let's say half
502 	// a frame in worst case
503 	SetPriority( suggest_thread_priority( B_VIDEO_RECORDING, 60, 8000, 8000 ));
504 
505 	/* Start the BMediaEventLooper control loop running */
506 	Run();
507 }
508 
509 void
Start(bigtime_t performance_time)510 CRadeonProducer::Start(bigtime_t performance_time)
511 {
512 	DPRINT(("CRadeonProducer::Start()\n"));
513 
514 	BMediaEventLooper::Start(performance_time);
515 }
516 
517 void
Stop(bigtime_t performance_time,bool immediate)518 CRadeonProducer::Stop(bigtime_t performance_time, bool immediate)
519 {
520 	DPRINT(("CRadeonProducer::Stop()\n"));
521 
522 	BMediaEventLooper::Stop(performance_time, immediate);
523 }
524 
525 void
Seek(bigtime_t media_time,bigtime_t performance_time)526 CRadeonProducer::Seek(bigtime_t media_time, bigtime_t performance_time)
527 {
528 	DPRINT(("CRadeonProducer::Seek()\n"));
529 
530 	BMediaEventLooper::Seek(media_time, performance_time);
531 }
532 
533 void
TimeWarp(bigtime_t at_real_time,bigtime_t to_performance_time)534 CRadeonProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
535 {
536 	DPRINT(("CRadeonProducer::TimeWarp()\n"));
537 
538 	BMediaEventLooper::TimeWarp(at_real_time, to_performance_time);
539 }
540 
541 status_t
AddTimer(bigtime_t at_performance_time,int32 cookie)542 CRadeonProducer::AddTimer(bigtime_t at_performance_time, int32 cookie)
543 {
544 	DPRINT(("CRadeonProducer::AddTimer()\n"));
545 
546 	return BMediaEventLooper::AddTimer(at_performance_time, cookie);
547 }
548 
549 void
SetRunMode(run_mode mode)550 CRadeonProducer::SetRunMode(run_mode mode)
551 {
552 	DPRINT(("CRadeonProducer::SetRunMode()\n"));
553 
554 	BMediaEventLooper::SetRunMode(mode);
555 }
556 
557 void
HandleEvent(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)558 CRadeonProducer::HandleEvent(const media_timed_event *event,
559 		bigtime_t lateness, bool realTimeEvent)
560 {
561 	//DPRINT(("CRadeonProducer::HandleEvent()\n"));
562 
563 	TOUCH(lateness); TOUCH(realTimeEvent);
564 
565 	switch(event->type)
566 	{
567 		case BTimedEventQueue::B_START:
568 			HandleStart(event->event_time);
569 			break;
570 		case BTimedEventQueue::B_STOP:
571 			HandleStop();
572 			break;
573 		case BTimedEventQueue::B_WARP:
574 			HandleTimeWarp(event->bigdata);
575 			break;
576 		case BTimedEventQueue::B_SEEK:
577 			HandleSeek(event->bigdata);
578 			break;
579 		case BTimedEventQueue::B_HANDLE_BUFFER:
580 		case BTimedEventQueue::B_DATA_STATUS:
581 		case BTimedEventQueue::B_PARAMETER:
582 		default:
583 			PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type));
584 			break;
585 		case BTimedEventQueue::B_HARDWARE:
586 			HandleHardware();
587 			break;
588 	}
589 
590 	//DPRINT(("CRadeonProducer::HandleEvent() done\n"));
591 }
592 
593 void
CleanUpEvent(const media_timed_event * event)594 CRadeonProducer::CleanUpEvent(const media_timed_event *event)
595 {
596 	DPRINT(("CRadeonProducer::CleanUpEvent()\n"));
597 
598 	BMediaEventLooper::CleanUpEvent(event);
599 }
600 
601 bigtime_t
OfflineTime()602 CRadeonProducer::OfflineTime()
603 {
604 	return BMediaEventLooper::OfflineTime();
605 }
606 
607 void
ControlLoop()608 CRadeonProducer::ControlLoop()
609 {
610 	BMediaEventLooper::ControlLoop();
611 }
612 
613 status_t
DeleteHook(BMediaNode * node)614 CRadeonProducer::DeleteHook(BMediaNode * node)
615 {
616 	DPRINT(("CRadeonProducer::DeleteHook()\n"));
617 
618 	return BMediaEventLooper::DeleteHook(node);
619 }
620 
621 
622 
623 /* BBufferProducer */
624 
625 // choose capture mode according to format and update format according to that
626 status_t
verifySetMode(media_format * format)627 CRadeonProducer::verifySetMode( media_format *format )
628 {
629 	float frame_rate = fVideoIn.getFrameRate(
630 		BeToVideoInStandard( fStandard )) / 1000.0f;
631 
632 	if( format->u.raw_video.interlace == media_raw_video_format::wildcard.interlace ) {
633 		if( format->u.raw_video.field_rate == media_raw_video_format::wildcard.field_rate ) {
634 			format->u.raw_video.interlace = fMode == C_VIDEO_IN_BOB ? 2 : 1;
635 			format->u.raw_video.field_rate = frame_rate * format->u.raw_video.interlace;
636 		} else {
637 			if( format->u.raw_video.field_rate == frame_rate )
638 				format->u.raw_video.interlace = 1;
639 			else if( format->u.raw_video.field_rate == frame_rate * 2 )
640 				format->u.raw_video.interlace = 2;
641 			else {
642 				DPRINT(( "Unsupported field rate for active TV standard (%f)\n",
643 					format->u.raw_video.field_rate ));
644 				return B_MEDIA_BAD_FORMAT;
645 			}
646 		}
647 
648 	} else if( format->u.raw_video.interlace == 1 ) {
649 		if( format->u.raw_video.field_rate == media_raw_video_format::wildcard.field_rate )
650 			format->u.raw_video.field_rate = frame_rate;
651 		else {
652 			// don't compare directly - there are rounding errors
653 			if( fabs(format->u.raw_video.field_rate - frame_rate) > 0.001 ) {
654 				DPRINT(( "Wrong field rate for active TV standard (%f) in progressive mode (expected %f)\n",
655 					format->u.raw_video.field_rate - 29.976,
656 					frame_rate - 29.976 ));
657 				return B_MEDIA_BAD_FORMAT;
658 			}
659 		}
660 
661 	} else if( format->u.raw_video.interlace == 2 ) {
662 		if( format->u.raw_video.field_rate == media_raw_video_format::wildcard.field_rate )
663 			format->u.raw_video.field_rate = frame_rate * 2;
664 		else {
665 			if( fabs(format->u.raw_video.field_rate - frame_rate * 2) > 0.001 ) {
666 				DPRINT(( "Wrong field rate for active TV standard (%f) in interlace mode\n",
667 					format->u.raw_video.field_rate ));
668 				return B_MEDIA_BAD_FORMAT;
669 			}
670 		}
671 
672 	} else {
673 		DPRINT(( "Invalid interlace mode (%d)\n", format->u.raw_video.interlace ));
674 		return B_MEDIA_BAD_FORMAT;
675 	}
676 
677 	return B_OK;
678 }
679 
680 /*
681 	Map BeOS capture mode to internal capture mode.
682 */
683 int32
extractCaptureMode(const media_format * format)684 CRadeonProducer::extractCaptureMode( const media_format *format )
685 {
686 	// if application requests interlace, it always gets BOB;
687 	// if is requests non-interlace, it may get WEAVE or FIELD -
688 	// if the user selected one of them, we are fine; else,
689 	// we always choose WEAVE (could choose FIELD as well, make
690 	// it dependant on resolution, but the more magic the more problems)
691 	if( format->u.raw_video.interlace == 2 )
692 		return C_VIDEO_IN_BOB;
693 	else if( fMode == C_VIDEO_IN_BOB )
694 		return C_VIDEO_IN_WEAVE;
695 	else
696 		return fMode;
697 }
698 
699 // check pixel aspect of format and set it if it's wildcarded
700 status_t
verifySetPixelAspect(media_format * format)701 CRadeonProducer::verifySetPixelAspect( media_format *format )
702 {
703 	// for simplicity, we always assume 1:1 aspect
704 	if( format->u.raw_video.pixel_width_aspect != media_raw_video_format::wildcard.pixel_width_aspect ||
705 		format->u.raw_video.pixel_height_aspect != media_raw_video_format::wildcard.pixel_height_aspect )
706 	{
707 		if( format->u.raw_video.pixel_width_aspect !=
708 			format->u.raw_video.pixel_height_aspect )
709 		{
710 			DPRINT(( "Unsupported pixel aspect (%d:%d)\n",
711 				format->u.raw_video.pixel_width_aspect,
712 				format->u.raw_video.pixel_height_aspect ));
713 			return B_MEDIA_BAD_FORMAT;
714 		}
715 	} else {
716 		format->u.raw_video.pixel_width_aspect = 1;
717 		format->u.raw_video.pixel_height_aspect = 1;
718 	}
719 
720 	return B_OK;
721 
722 #if 0
723 	// we assume 1:2 for interlaced and 1:1 for deinterlaced video
724 	// (this is not really true as it depends on TV standard and
725 	// resolution, but it should be enough for start)
726 	if( format->u.raw_video.pixel_width_aspect != media_raw_video_format::wildcard.pixel_width_aspect ||
727 		format->u.raw_video.pixel_height_aspect != media_raw_video_format::wildcard.pixel_height_aspect )
728 	{
729 		double ratio = mode == C_VIDEO_IN_WEAVE ? 1 : 0.5;
730 
731 		if( (float)format->u.raw_video.pixel_width_aspect /
732 			format->u.raw_video.pixel_height_aspect != ratio )
733 		{
734 			DPRINT(( "Unsupported pixel aspect (%d:%d)\n",
735 				format->u.raw_video.pixel_width_aspect,
736 				format->u.raw_video.pixel_height_aspect ));
737 			return B_MEDIA_BAD_FORMAT;
738 		}
739 	} else {
740 		format->u.raw_video.pixel_width_aspect = 1;
741 		format->u.raw_video.pixel_height_aspect =
742 			mode == C_VIDEO_IN_WEAVE ? 1 : 2;
743 	}
744 
745 	return B_OK;
746 #endif
747 }
748 
749 // verify active range defined as format
750 status_t
verifyActiveRange(media_format * format)751 CRadeonProducer::verifyActiveRange( media_format *format )
752 {
753 	CRadeonRect active_rect;
754 
755 	fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
756 
757 	if( format->u.raw_video.first_active != media_raw_video_format::wildcard.first_active ) {
758 		if( (int32)format->u.raw_video.first_active < 0 ) {
759 			DPRINT(( "Unsupported first_active (%d)\n", format->u.raw_video.first_active ));
760 			return B_MEDIA_BAD_FORMAT;
761 		}
762 	}
763 
764 	// don't care about last_active much - some programs set it to number of
765 	// captured lines, which is really something different
766 	// (I have the feeling, noone really knows how to use this value properly)
767 	if( format->u.raw_video.last_active != media_raw_video_format::wildcard.last_active ) {
768 		if( format->u.raw_video.last_active >= (uint32)active_rect.Height() ) {
769 			DPRINT(( "Unsupported last_active (%d)\n", format->u.raw_video.last_active ));
770 			return B_MEDIA_BAD_FORMAT;
771 		}
772 	}
773 
774 	return B_OK;
775 }
776 
777 
778 // set active range in format if yet undefined
779 void
setActiveRange(media_format * format)780 CRadeonProducer::setActiveRange( media_format *format )
781 {
782 	CRadeonRect active_rect;
783 
784 	fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
785 
786 	if( format->u.raw_video.first_active == media_raw_video_format::wildcard.first_active )
787 		format->u.raw_video.first_active = 0;
788 
789 	if( format->u.raw_video.last_active == media_raw_video_format::wildcard.last_active )
790 		format->u.raw_video.last_active = (uint32)active_rect.Height() - 1;
791 }
792 
793 
794 // verify requested orientation
795 status_t
verifyOrientation(media_format * format)796 CRadeonProducer::verifyOrientation( media_format *format )
797 {
798 	if( format->u.raw_video.orientation != media_raw_video_format::wildcard.orientation ) {
799 		if( format->u.raw_video.orientation != B_VIDEO_TOP_LEFT_RIGHT ) {
800 			DPRINT(( "Unsupported orientation (%d)\n", format->u.raw_video.orientation ));
801 			return B_MEDIA_BAD_FORMAT;
802 		}
803 	}
804 
805 	return B_OK;
806 }
807 
808 
809 // set image orientation if yet undefined
810 void
setOrientation(media_format * format)811 CRadeonProducer::setOrientation( media_format *format )
812 {
813 	if( format->u.raw_video.orientation == media_raw_video_format::wildcard.orientation )
814 		format->u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
815 }
816 
817 
818 // verify requested pixel format
819 status_t
verifyPixelFormat(media_format * format)820 CRadeonProducer::verifyPixelFormat( media_format *format )
821 {
822 	if(	format->u.raw_video.display.format !=
823 		media_raw_video_format::wildcard.display.format )
824 	{
825 		switch( format->u.raw_video.display.format ) {
826 		case B_RGB32:
827 		case B_RGB16:
828 		case B_RGB15:
829 		case B_YCbCr422:
830 		case B_GRAY8:
831 			break;
832 
833 		default:
834 			DPRINT(("Unsupported colour space (%x)\n",
835 				format->u.raw_video.display.format ));
836 			return B_MEDIA_BAD_FORMAT;
837 		}
838 	}
839 
840 	return B_OK;
841 }
842 
843 
844 // set pixel format to user-defined default if not set yet
845 void
setPixelFormat(media_format * format)846 CRadeonProducer::setPixelFormat( media_format *format )
847 {
848 	if(	format->u.raw_video.display.format ==
849 		media_raw_video_format::wildcard.display.format )
850 		format->u.raw_video.display.format = (color_space)fFormat;
851 }
852 
853 /*
854 	Verify video size and set it if undefined.
855 */
856 status_t
verifySetSize(media_format * format,int32 mode,bool set_bytes_per_row)857 CRadeonProducer::verifySetSize(
858 	media_format *format, int32 mode, bool set_bytes_per_row )
859 {
860 	CRadeonRect active_rect;
861 
862 	fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
863 
864 	// width and height must both be defined, else we define it ourself,
865 	// i.e. if the application leaves one of them wildcarded, we
866 	// set both
867 	if( format->u.raw_video.display.line_width !=
868 		media_raw_video_format::wildcard.display.line_width &&
869 		format->u.raw_video.display.line_count !=
870 		media_raw_video_format::wildcard.display.line_count )
871 	{
872 		uint32 max_height = active_rect.Height();
873 
874 		if( mode != C_VIDEO_IN_WEAVE )
875 			max_height /= 2;
876 
877 		if( format->u.raw_video.display.line_width > (uint32)active_rect.Width() ||
878 			format->u.raw_video.display.line_count > max_height )
879 		{
880 			DPRINT(("Requested image size is too high (%dx%d)\n",
881 				format->u.raw_video.display.line_width,
882 				format->u.raw_video.display.line_count));
883 			return B_MEDIA_BAD_FORMAT;
884 		}
885 
886 		// our format converters do up to 8 pixels at a time (grey8);
887 		// to be absolutely sure we don't get trouble there, refuse
888 		// any width that is not a multiple of 8
889 
890 		if( (format->u.raw_video.display.line_width & 7) != 0 ) {
891 			DPRINT(( "Request image width is not multiple of 8 (%d)\n",
892 				format->u.raw_video.display.line_width ));
893 			return B_MEDIA_BAD_FORMAT;
894 		}
895 
896 	} else {
897 		switch (fResolution) {
898 		case 0:
899 			format->u.raw_video.display.line_width = 640;
900 			format->u.raw_video.display.line_count = 480;
901 			break;
902 		case 3:
903 			format->u.raw_video.display.line_width = 480;
904 			format->u.raw_video.display.line_count = 360;
905 			break;
906 		case 4:
907 			format->u.raw_video.display.line_width = 720;
908 			format->u.raw_video.display.line_count = 480;
909 			break;
910 		case 5:
911 			format->u.raw_video.display.line_width = 720;
912 			format->u.raw_video.display.line_count = 576;
913 			break;
914 		case 6:
915 			format->u.raw_video.display.line_width = 768;
916 			format->u.raw_video.display.line_count = 576;
917 			break;
918 		case 1:
919 			format->u.raw_video.display.line_width = 320;
920 			format->u.raw_video.display.line_count = 240;
921 			break;
922 		case 2:
923 			format->u.raw_video.display.line_width = 160;
924 			format->u.raw_video.display.line_count = 120;
925 			break;
926 		}
927 
928 		if( format->u.raw_video.display.line_width > (uint32)active_rect.Width() )
929 			format->u.raw_video.display.line_width = (uint32)active_rect.Width() & ~7;
930 
931 		if( format->u.raw_video.display.line_count > (uint32)active_rect.Height() )
932 			format->u.raw_video.display.line_count = (uint32)active_rect.Height();
933 
934 		// BOB and FIELD modes provide only field, which has half height
935 		if( mode != C_VIDEO_IN_WEAVE ) {
936 			if( format->u.raw_video.display.line_count > (uint32)active_rect.Height() / 2 )
937 				format->u.raw_video.display.line_count = (uint32)active_rect.Height() / 2;
938 		}
939 	}
940 
941 	if( format->u.raw_video.display.format != media_raw_video_format::wildcard.display.format ) {
942 		uint32 bytes_per_row;
943 
944 		switch( format->u.raw_video.display.format ) {
945 		case B_RGB32:
946 			bytes_per_row =
947 				format->u.raw_video.display.line_width * 4;
948 			break;
949 
950 		case B_RGB15:
951 		case B_RGB16:
952 		case B_YCbCr422:
953 			bytes_per_row =
954 				format->u.raw_video.display.line_width * 2;
955 			break;
956 
957 		default:
958 			bytes_per_row =
959 				format->u.raw_video.display.line_width;
960 		}
961 
962 		if( format->u.raw_video.display.bytes_per_row !=
963 			media_raw_video_format::wildcard.display.bytes_per_row )
964 		{
965 			if( format->u.raw_video.display.bytes_per_row < bytes_per_row ) {
966 				DPRINT(( "Requested bytes per row are too small",
967 					format->u.raw_video.display.bytes_per_row ));
968 				return B_MEDIA_BAD_FORMAT;
969 			}
970 		} else if( set_bytes_per_row )
971 			format->u.raw_video.display.bytes_per_row = bytes_per_row;
972 	}
973 
974 
975 	return B_OK;
976 }
977 
978 
979 // verify "offset" parameters of format
980 status_t
verifyFormatOffsets(media_format * format)981 CRadeonProducer::verifyFormatOffsets( media_format *format )
982 {
983 	if( format->u.raw_video.display.pixel_offset !=
984 		media_raw_video_format::wildcard.display.pixel_offset &&
985 		format->u.raw_video.display.pixel_offset != 0 )
986 	{
987 		DPRINT(( "Requested pixel offset is not zero" ));
988 		return B_MEDIA_BAD_FORMAT;
989 	}
990 
991 	if( format->u.raw_video.display.line_offset !=
992 		media_raw_video_format::wildcard.display.line_offset &&
993 		format->u.raw_video.display.line_offset != 0 )
994 	{
995 		DPRINT(( "Requested line offset is not zero" ));
996 		return B_MEDIA_BAD_FORMAT;
997 	}
998 
999 	return B_OK;
1000 }
1001 
1002 
1003 // set "offset" parameters of format if not set yet
1004 void
setFormatOffsets(media_format * format)1005 CRadeonProducer::setFormatOffsets( media_format *format )
1006 {
1007 	if( format->u.raw_video.display.pixel_offset ==
1008 		media_raw_video_format::wildcard.display.pixel_offset )
1009 		format->u.raw_video.display.pixel_offset = 0;
1010 
1011 	if( format->u.raw_video.display.line_offset ==
1012 		media_raw_video_format::wildcard.display.line_offset )
1013 		format->u.raw_video.display.line_offset = 0;
1014 }
1015 
1016 
1017 // verify "flags" parameter of format
1018 status_t
verifyFormatFlags(media_format * format)1019 CRadeonProducer::verifyFormatFlags( media_format *format )
1020 {
1021 	if( format->u.raw_video.display.flags !=
1022 		media_raw_video_format::wildcard.display.flags &&
1023 		format->u.raw_video.display.flags != 0 )
1024 	{
1025 		DPRINT(( "Requested display flags are not zero" ));
1026 		return B_MEDIA_BAD_FORMAT;
1027 	}
1028 
1029 	return B_OK;
1030 }
1031 
1032 
1033 // set "flags" parameter of format if not set yet
1034 void
setFormatFlags(media_format * format)1035 CRadeonProducer::setFormatFlags( media_format *format )
1036 {
1037 	if( format->u.raw_video.display.flags ==
1038 		media_raw_video_format::wildcard.display.flags )
1039 		format->u.raw_video.display.flags = 0;
1040 }
1041 
1042 
1043 /*
1044  *	Fill out all wildcards in a format descriptor.
1045  */
1046 status_t
finalizeFormat(media_format * format)1047 CRadeonProducer::finalizeFormat( media_format *format )
1048 {
1049 	if (format->type != B_MEDIA_RAW_VIDEO)
1050 		return B_MEDIA_BAD_FORMAT;
1051 
1052 	status_t res;
1053 
1054 	res = verifySetMode( format );
1055 	if( res != B_OK )
1056 		return res;
1057 
1058 	int32 mode = extractCaptureMode( format );
1059 
1060 	res = verifyActiveRange( format );
1061 	if( res != B_OK )
1062 		return res;
1063 
1064 	setActiveRange( format );
1065 
1066 	res = verifyOrientation( format );
1067 	if( res != B_OK )
1068 		return res;
1069 
1070 	res = verifySetPixelAspect( format );
1071 	if( res != B_OK )
1072 		return res;
1073 
1074 	res = verifyPixelFormat( format );
1075 	if( res != B_OK )
1076 		return res;
1077 
1078 	setPixelFormat( format);
1079 
1080 	res = verifySetSize( format, mode, true );
1081 	if( res != B_OK )
1082 		return res;
1083 
1084 	res = verifyFormatOffsets( format );
1085 	if( res != B_OK )
1086 		return res;
1087 
1088 	setFormatOffsets( format );
1089 
1090 	res = verifyFormatFlags( format );
1091 	if( res != B_OK )
1092 		return res;
1093 
1094 	setFormatFlags( format );
1095 	return res;
1096 }
1097 
1098 
1099 /*
1100  *	Someone has no idea what format we usually provide and asks us.
1101  *
1102  *	It's not really clear whether we are allowed to return wildcards.
1103  */
1104 status_t
FormatSuggestionRequested(media_type type,int32 quality,media_format * format)1105 CRadeonProducer::FormatSuggestionRequested(
1106 	media_type type, int32 quality, media_format *format)
1107 {
1108 	DPRINT(("CRadeonProducer::FormatSuggestionRequested()\n"));
1109 
1110 	if (type != B_MEDIA_RAW_VIDEO)
1111 		return B_MEDIA_BAD_FORMAT;
1112 
1113 	TOUCH(quality);
1114 
1115 	format->type = B_MEDIA_RAW_VIDEO;
1116 
1117 	format->u.raw_video = media_raw_video_format::wildcard;
1118 
1119 	finalizeFormat( format );
1120 
1121 	return B_OK;
1122 }
1123 
1124 
1125 /*
1126 	Initial format proposal as part of a connection establishment.
1127 
1128 	First, the application defines a format with many wildcards in it;
1129 	this format is passed to us, so we can restrict it if necessary;
1130 	we should leave as many wildcards as possible, because in the next
1131 	step the consumer is asked, and he will not be happy if he has no choice left .
1132 */
1133 status_t
FormatProposal(const media_source & output,media_format * format)1134 CRadeonProducer::FormatProposal(const media_source &output, media_format *format)
1135 {
1136 	char buffer[256];
1137 
1138 	DPRINT(("CRadeonProducer::FormatProposal()\n"));
1139 
1140 	if( format == NULL )
1141 		return B_BAD_VALUE;
1142 
1143 	if( output != fOutput.source )
1144 		return B_MEDIA_BAD_SOURCE;
1145 
1146 	string_for_format(*format, buffer, sizeof(buffer));
1147 
1148 	DPRINT(("CRadeonProducer::FormatProposal() - in=%s\n", buffer));
1149 
1150 	if( format->type == B_MEDIA_NO_TYPE ) {
1151 		// if there is not even a type, set raw video
1152 		format->type = B_MEDIA_RAW_VIDEO;
1153 		format->u.raw_video = media_raw_video_format::wildcard;
1154 	}
1155 
1156 	if (format->type != B_MEDIA_RAW_VIDEO)
1157 		return B_MEDIA_BAD_FORMAT;
1158 
1159 	status_t res;
1160 
1161 	// first, choose capture mode, so we know the maximum video size
1162 	res = verifySetMode( format );
1163 	if( res != B_OK )
1164 		return res;
1165 
1166 	int32 mode = extractCaptureMode( format );
1167 
1168 	res = verifyActiveRange( format );
1169 	if( res != B_OK )
1170 		return res;
1171 
1172 	res = verifyOrientation( format );
1173 	if( res != B_OK )
1174 		return res;
1175 
1176 	setOrientation( format );
1177 
1178 	// simple aspect calculation: we always use 1:1, so setting this is easy
1179 	res = verifySetPixelAspect( format );
1180 	if( res != B_OK )
1181 		return res;
1182 
1183 	res = verifyPixelFormat( format );
1184 	if( res != B_OK )
1185 		return res;
1186 
1187 	// if we don't set it, the consumer usually chooses a stupid format
1188 	setPixelFormat( format );
1189 
1190 	// verify size and set if if undefined;
1191 	// do that now, else the consumer will set it (making the defaults
1192 	// set via preferences useless)
1193 	// leave bytes_per_lines untouched, though
1194 	// (we don't really care but the consumer may have some alignment restrictions)
1195 	res = verifySetSize( format, mode, false );
1196 	if( res != B_OK )
1197 		return res;
1198 
1199 	res = verifyFormatOffsets( format );
1200 	if( res != B_OK )
1201 		return res;
1202 
1203 	res = verifyFormatFlags( format );
1204 	if( res != B_OK )
1205 		return res;
1206 
1207 	string_for_format(*format, buffer, sizeof(buffer));
1208 
1209 	DPRINT(("CRadeonProducer::FormatProposal() - out=%s\n", buffer));
1210 
1211 	return B_OK;
1212 }
1213 
1214 status_t
FormatChangeRequested(const media_source & source,const media_destination & destination,media_format * io_format,int32 * _deprecated_)1215 CRadeonProducer::FormatChangeRequested(const media_source &source,
1216 		const media_destination &destination, media_format *io_format,
1217 		int32 *_deprecated_)
1218 {
1219 	DPRINT(("CRadeonProducer::FormatChangeRequested()\n"));
1220 
1221 	TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_);
1222 	if (source != fOutput.source)
1223 		return B_MEDIA_BAD_SOURCE;
1224 
1225 	return B_ERROR;
1226 }
1227 
1228 status_t
GetNextOutput(int32 * cookie,media_output * out_output)1229 CRadeonProducer::GetNextOutput(int32 *cookie, media_output *out_output)
1230 {
1231 	DPRINT(("CRadeonProducer::GetNextOutput()\n"));
1232 
1233 	if (!out_output)
1234 		return B_BAD_VALUE;
1235 
1236 	if ((*cookie) != 0)
1237 		return B_BAD_INDEX;
1238 
1239 	*out_output = fOutput;
1240 	(*cookie)++;
1241 	return B_OK;
1242 }
1243 
1244 status_t
DisposeOutputCookie(int32 cookie)1245 CRadeonProducer::DisposeOutputCookie(int32 cookie)
1246 {
1247 	DPRINT(("CRadeonProducer::DisposeOutputCookie()\n"));
1248 
1249 	TOUCH(cookie);
1250 
1251 	return B_OK;
1252 }
1253 
1254 status_t
SetBufferGroup(const media_source & for_source,BBufferGroup * group)1255 CRadeonProducer::SetBufferGroup(const media_source &for_source,
1256 		BBufferGroup *group)
1257 {
1258 	DPRINT(("CRadeonProducer::SetBufferGroup()\n"));
1259 
1260 	if( for_source != fOutput.source )
1261 		return B_MEDIA_BAD_SOURCE;
1262 
1263 	if( group != NULL ) {
1264 		delete fBufferGroup;
1265 		fBufferGroup = group;
1266 	}
1267 
1268 	return B_OK;
1269 }
1270 
1271 status_t
VideoClippingChanged(const media_source & for_source,int16 num_shorts,int16 * clip_data,const media_video_display_info & display,int32 * _deprecated_)1272 CRadeonProducer::VideoClippingChanged(const media_source &for_source,
1273 		int16 num_shorts, int16 *clip_data,
1274 		const media_video_display_info &display, int32 *_deprecated_)
1275 {
1276 	DPRINT(("CRadeonProducer::VideoClippingChanged()\n"));
1277 
1278 	TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data);
1279 	TOUCH(display); TOUCH(_deprecated_);
1280 
1281 	return B_ERROR;
1282 }
1283 
1284 status_t
GetLatency(bigtime_t * out_latency)1285 CRadeonProducer::GetLatency(bigtime_t *out_latency)
1286 {
1287 	DPRINT(("CRadeonProducer::GetLatency()\n"));
1288 
1289 	// delay is one frame for capturing, a scheduling latency, the
1290 	// DMA copying, the format conversion and the output nodes latency;
1291 	// scheduling, DMA copying and format conversion is summed up in
1292 	// fProcessingLatency
1293 	bigtime_t capture_latency = (bigtime_t)(1000000.0 / fOutput.format.u.raw_video.field_rate);
1294 
1295 	// HACK: (see HandleHardware())
1296 	// to be compatible to existing software, we write the ending time of
1297 	// capture instead of the beginning time into buffers, thus we
1298 	// have no capture delay
1299 	capture_latency = 0;
1300 
1301 	bigtime_t buffer_latency = fProcessingLatency;
1302 	BBufferProducer::GetLatency( &buffer_latency );
1303 
1304 	*out_latency = SchedulingLatency() + capture_latency + fProcessingLatency +
1305 		buffer_latency;
1306 
1307 	DPRINT(("latency=%lld\n", *out_latency));
1308 
1309 	return B_OK;
1310 }
1311 
1312 
1313 status_t
PrepareToConnect(const media_source & source,const media_destination & destination,media_format * format,media_source * out_source,char * out_name)1314 CRadeonProducer::PrepareToConnect(const media_source &source,
1315 		const media_destination &destination, media_format *format,
1316 		media_source *out_source, char *out_name)
1317 {
1318 	DPRINT(("CRadeonProducer::PrepareToConnect()\n"));
1319 
1320 	PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \
1321 			format->u.raw_video.display.line_width, \
1322 			format->u.raw_video.display.line_count));
1323 
1324 	if (source != fOutput.source) {
1325 		DPRINT(("bad source\n"));
1326 		return B_MEDIA_BAD_SOURCE;
1327 	}
1328 
1329 	if (fOutput.destination != media_destination::null) {
1330 		DPRINT(("already connected\n"));
1331 		return B_MEDIA_ALREADY_CONNECTED;
1332 	}
1333 
1334 	char buffer[256];
1335 	string_for_format(*format, buffer, sizeof(buffer));
1336 	DPRINT(("CRadeonProducer::PrepareToConnect() - in=%s\n", buffer));
1337 
1338 	status_t res = finalizeFormat( format );
1339 	if( res != B_OK )
1340 		return res;
1341 
1342 	*out_source = fOutput.source;
1343 	strcpy(out_name, fOutput.name);
1344 
1345 	string_for_format(*format, buffer, sizeof(buffer));
1346 	DPRINT(("CRadeonProducer::PrepareToConnect() - out=%s\n", buffer));
1347 
1348 	// reserve connection
1349 	fOutput.destination = destination;
1350 
1351 	DPRINT(("finished\n"));
1352 
1353 	return B_OK;
1354 }
1355 
1356 void
setDefaultBufferGroup()1357 CRadeonProducer::setDefaultBufferGroup()
1358 {
1359 	DPRINT(("CRadeonProducer::setDefaultBufferGroup()\n"));
1360 	/*delete fBufferGroup;
1361 	fBufferGroup = NULL;*/
1362 	if( fBufferGroup != NULL ) {
1363 		DPRINT(("Buffer already set\n"));
1364 		return;
1365 	}
1366 
1367 	fBufferGroup = new BBufferGroup(
1368 		fOutput.format.u.raw_video.display.bytes_per_row *
1369 		fOutput.format.u.raw_video.display.line_count,
1370 		3, B_ANY_ADDRESS, B_FULL_LOCK );
1371 
1372 	if (fBufferGroup->InitCheck() < B_OK) {
1373 		delete fBufferGroup;
1374 		fBufferGroup = NULL;
1375 		return;
1376 	}
1377 }
1378 
1379 void
startCapturing()1380 CRadeonProducer::startCapturing()
1381 {
1382 	if( RunState() != BMediaEventLooper::B_STARTED ||
1383 		fOutput.destination == media_destination::null )
1384 		return;
1385 
1386 	fVideoIn.SetChannel(fTuner, C_VIDEO_IN_NTSC); // was hardcoded to NTSC
1387 	fVideoIn.SetBrightness(fBrightness);
1388 	fVideoIn.SetContrast(fContrast);
1389 	fVideoIn.SetSaturation(fSaturation);
1390 	fVideoIn.SetHue(fHue);
1391 	fVideoIn.SetSharpness(fSharpness);
1392 
1393 	fVideoIn.Start(video_in_source(fSource), BeToVideoInStandard( fStandard ),
1394 		video_in_capture_mode(fCurMode),
1395 		fOutput.format.u.raw_video.display.line_width,
1396 		fOutput.format.u.raw_video.display.line_count);
1397 
1398 	char *tmp_buffer;
1399 	tmp_buffer = (char *)malloc(
1400 		fOutput.format.u.raw_video.display.bytes_per_row *
1401 		fOutput.format.u.raw_video.display.line_count );
1402 
1403 	int field_sequence;
1404 	short field_number;
1405 	bigtime_t capture_time;
1406 
1407 	// do a real capturing to prime everything
1408 	fVideoIn.Capture(
1409 		tmp_buffer != NULL ? fOutput.format.u.raw_video.display.format : B_NO_COLOR_SPACE,
1410 		tmp_buffer,
1411 		fOutput.format.u.raw_video.display.bytes_per_row * fOutput.format.u.raw_video.display.line_count,
1412 		fOutput.format.u.raw_video.display.bytes_per_row,
1413 		&field_sequence, &field_number, &capture_time );
1414 
1415 	// capture some frames to be sure there are no pending buffers;
1416 	// discard captured data to safe time (we want to catch up and not fall behind)
1417 	for( int i = 0; i < 3; ++i ) {
1418 		fVideoIn.Capture(
1419 			B_NO_COLOR_SPACE,
1420 			NULL,
1421 			fOutput.format.u.raw_video.display.bytes_per_row * fOutput.format.u.raw_video.display.line_count,
1422 			fOutput.format.u.raw_video.display.bytes_per_row,
1423 			&field_sequence, &field_number, &capture_time );
1424 
1425 		DPRINT(("Captured: %lld, current: %lld\n", capture_time, system_time() ));
1426 	}
1427 
1428 	// do a real capturing to see how long it takes until the
1429 	// buffer is ready, i.e. including DMA and colour conversion
1430 	fVideoIn.Capture(
1431 		tmp_buffer != NULL ? fOutput.format.u.raw_video.display.format : B_NO_COLOR_SPACE,
1432 		tmp_buffer,
1433 		fOutput.format.u.raw_video.display.bytes_per_row * fOutput.format.u.raw_video.display.line_count,
1434 		fOutput.format.u.raw_video.display.bytes_per_row,
1435 		&field_sequence, &field_number, &capture_time );
1436 
1437 	DPRINT(("Captured: %lld, current: %lld\n", capture_time, system_time() ));
1438 
1439 	// now we know our internal latency
1440 	fProcessingLatency = system_time() - capture_time;
1441 
1442 	DPRINT(("Processing latency: %dµs\n", fProcessingLatency ));
1443 
1444 	// store field sequence to start with zero
1445 	// (capture-internal field sequence always counts up)
1446 	fFieldSequenceBase = field_sequence;
1447 
1448 	if( tmp_buffer != NULL )
1449 		free(tmp_buffer);
1450 
1451 	// tell latence MediaEventLooper so it can schedule events properly ahead
1452 	bigtime_t total_latency;
1453 
1454 	GetLatency( &total_latency );
1455 	SetEventLatency( total_latency );
1456 
1457 	// Create the buffer group
1458 	setDefaultBufferGroup();
1459 
1460 	//fUsedBufferGroup = fBufferGroup;
1461 
1462 	// schedule a capture event after one field's time
1463 	RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HARDWARE );
1464 
1465 	media_timed_event event(
1466 		capture_time + 1000000 / fOutput.format.u.raw_video.field_rate,
1467 		BTimedEventQueue::B_HARDWARE);
1468 
1469 	RealTimeQueue()->AddEvent(event);
1470 }
1471 
1472 void
Connect(status_t error,const media_source & source,const media_destination & destination,const media_format & format,char * io_name)1473 CRadeonProducer::Connect(status_t error, const media_source &source,
1474 		const media_destination &destination, const media_format &format,
1475 		char *io_name)
1476 {
1477 	// we even get called if consumer reported error in AcceptFormat;
1478 	// in this case, we must release the source already reserved by
1479 	// PrepareToConnect
1480 	if( error != B_OK ) {
1481 		DPRINT(( "Connect: Consumer returned error (%s) - releasing source",
1482 			strerror( error )));
1483 		fOutput.destination = media_destination::null;
1484 		return;
1485 	}
1486 
1487 	if(	source != fOutput.source ) {
1488 		DPRINT(( "Connect: Wrong source specified\n"));
1489 		return;
1490 	}
1491 
1492 	fOutput.destination = destination;
1493 	fOutput.format = format;
1494 	fCurMode = extractCaptureMode( &format );
1495 
1496 	char buffer[256];
1497 	string_for_format(format, buffer, sizeof(buffer));
1498 
1499 	DPRINT(("CRadeonProducer::Connect() - %s\n", buffer));
1500 
1501 	strcpy(io_name, fOutput.name);
1502 
1503 	startCapturing();
1504 
1505 	DPRINT(("CRadeonProducer::Connect() done\n"));
1506 }
1507 
1508 void
Disconnect(const media_source & source,const media_destination & destination)1509 CRadeonProducer::Disconnect(const media_source &source,
1510 		const media_destination &destination)
1511 {
1512 	DPRINT(("Disconnect()\n"));
1513 
1514 	if( source != fOutput.source || destination != fOutput.destination ) {
1515 		DPRINT(("Disconnect: Bad source and/or destination\n"));
1516 		return;
1517 	}
1518 
1519 	fOutput.destination = media_destination::null;
1520 
1521 	delete fBufferGroup;
1522 	fBufferGroup = NULL;
1523 
1524 	fVideoIn.Stop();
1525 
1526 	RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HARDWARE );
1527 
1528 	// reset format to get rid of any connection left-overs
1529 	fOutput.format.type = B_MEDIA_RAW_VIDEO;
1530 	fOutput.format.u.raw_video = media_raw_video_format::wildcard;
1531 
1532 	DPRINT(("Disconnect() done\n"));
1533 }
1534 
1535 void
LateNoticeReceived(const media_source & source,bigtime_t how_much,bigtime_t performance_time)1536 CRadeonProducer::LateNoticeReceived(const media_source &source,
1537 		bigtime_t how_much, bigtime_t performance_time)
1538 {
1539 	DPRINT(("CRadeonProducer::LateNoticeReceived()\n"));
1540 
1541 	TOUCH(source); TOUCH(how_much); TOUCH(performance_time);
1542 }
1543 
1544 void
EnableOutput(const media_source & source,bool enabled,int32 * _deprecated_)1545 CRadeonProducer::EnableOutput(const media_source &source, bool enabled,
1546 		int32 *_deprecated_)
1547 {
1548 	DPRINT(("CRadeonProducer::EnableOutput()\n"));
1549 
1550 	TOUCH(_deprecated_);
1551 
1552 	if (source != fOutput.source)
1553 		return;
1554 
1555 	fEnabled = enabled;
1556 }
1557 
1558 status_t
SetPlayRate(int32 numer,int32 denom)1559 CRadeonProducer::SetPlayRate(int32 numer, int32 denom)
1560 {
1561 	DPRINT(("CRadeonProducer::SetPlayRate()\n"));
1562 
1563 	TOUCH(numer); TOUCH(denom);
1564 
1565 	return B_ERROR;
1566 }
1567 
1568 void
AdditionalBufferRequested(const media_source & source,media_buffer_id prev_buffer,bigtime_t prev_time,const media_seek_tag * prev_tag)1569 CRadeonProducer::AdditionalBufferRequested(const media_source &source,
1570 		media_buffer_id prev_buffer, bigtime_t prev_time,
1571 		const media_seek_tag *prev_tag)
1572 {
1573 	DPRINT(("CRadeonProducer::AdditionalBufferRequested()\n"));
1574 
1575 	TOUCH(source); TOUCH(prev_buffer); TOUCH(prev_time); TOUCH(prev_tag);
1576 }
1577 
1578 void
LatencyChanged(const media_source & source,const media_destination & destination,bigtime_t new_latency,uint32 flags)1579 CRadeonProducer::LatencyChanged(const media_source &source,
1580 		const media_destination &destination, bigtime_t new_latency,
1581 		uint32 flags)
1582 {
1583 	DPRINT(("CRadeonProducer::LatencyChanged()\n"));
1584 	BBufferProducer::LatencyChanged( source, destination, new_latency, flags );
1585 }
1586 
1587 
1588 
1589 /* BControllable */
1590 
1591 status_t
GetParameterValue(int32 id,bigtime_t * last_change,void * value,size_t * size)1592 CRadeonProducer::GetParameterValue(
1593 	int32 id, bigtime_t *last_change, void *value, size_t *size)
1594 {
1595 	DPRINT(("CRadeonProducer::GetParameterValue(%d)\n", id));
1596 
1597 	switch (id) {
1598 	case P_SOURCE:
1599 		*last_change = fSourceLastChange;
1600 		*size = sizeof(fSource);
1601 		*((uint32 *) value) = fSource;
1602 		break;
1603 	case P_STANDARD:
1604 		*last_change = fStandardLastChange;
1605 		*size = sizeof(fStandard);
1606 		*((uint32 *) value) = fStandard;
1607 		break;
1608 	case P_MODE:
1609 		*last_change = fModeLastChange;
1610 		*size = sizeof(fMode);
1611 		*((uint32 *) value) = fMode;
1612 		break;
1613 	case P_FORMAT:
1614 		*last_change = fFormatLastChange;
1615 		*size = sizeof(fFormat);
1616 		*((uint32 *) value) = fFormat;
1617 		break;
1618 	case P_RESOLUTION:
1619 		*last_change = fResolutionLastChange;
1620 		*size = sizeof(fResolution);
1621 		*((uint32 *) value) = fResolution;
1622 		break;
1623 	case P_TUNER:
1624 		*last_change = fTunerLastChange;
1625 		*size = sizeof(fTuner);
1626 		*((uint32 *) value) = fTuner;
1627 		break;
1628 	case P_BRIGHTNESS:
1629 		*last_change = fBrightnessLastChange;
1630 		*size = sizeof(fBrightness);
1631 		*((float *) value) = fBrightness;
1632 		break;
1633 	case P_CONTRAST:
1634 		*last_change = fContrastLastChange;
1635 		*size = sizeof(fContrast);
1636 		*((float *) value) = fContrast;
1637 		break;
1638 	case P_SATURATION:
1639 		*last_change = fSaturationLastChange;
1640 		*size = sizeof(fSaturation);
1641 		*((float *) value) = fSaturation;
1642 		break;
1643 	case P_HUE:
1644 		*last_change = fHueLastChange;
1645 		*size = sizeof(fHue);
1646 		*((float *) value) = fHue;
1647 		break;
1648 	case P_SHARPNESS:
1649 		*last_change = fSharpnessLastChange;
1650 		*size = sizeof(fSharpness);
1651 		*((float *) value) = fSharpness;
1652 		break;
1653 	default:
1654 		DPRINT(("Unknown parameter\n"));
1655 		return B_BAD_VALUE;
1656 	}
1657 
1658 	return B_OK;
1659 }
1660 
1661 
1662 /*
1663  *	Change video format instantly.
1664  *
1665  *	Used when user changes a settings that affect the video format.
1666  *	The new format must be the current format with some values
1667  *	replaced with wildcards. Don't put too many wildcards:
1668  *	some settings (like video size) are normally chosen by the
1669  *	application, so don't use this function as a secret override.
1670  */
1671 void
instantFormatChange(media_format * new_format)1672 CRadeonProducer::instantFormatChange( media_format *new_format )
1673 {
1674 	if( fOutput.destination == media_destination::null )
1675 		return;
1676 
1677 	if( finalizeFormat( new_format ) != B_OK ) {
1678 		DPRINT(("Current format does not allow to change interlace mode on-the-fly\n"));
1679 		return;
1680 	}
1681 
1682 	if( ChangeFormat( fOutput.source, fOutput.destination, new_format ) != B_OK ) {
1683 		DPRINT(("Consumer does not allow to change interlace mode instantly\n"));
1684 		return;
1685 	}
1686 
1687 	fOutput.format = *new_format;
1688 	fCurMode = extractCaptureMode( new_format );
1689 
1690 	fVideoIn.Stop();
1691 	startCapturing();
1692 }
1693 
1694 void
SetParameterValue(int32 id,bigtime_t when,const void * value,size_t size)1695 CRadeonProducer::SetParameterValue(
1696 	int32 id, bigtime_t when, const void *value, size_t size)
1697 {
1698 	DPRINT(("CRadeonProducer::SetParameterValue()\n"));
1699 
1700 	if (!value || size != sizeof(uint32))
1701 		return;
1702 
1703 	switch (id) {
1704 	case P_SOURCE:
1705 		if (*((const int32 *) value) == fSource)
1706 			return;
1707 		fSource = *((const uint32 *) value);
1708 		fSourceLastChange = when;
1709 
1710 		// if there is no tuner, force composite input
1711 		// (eXposer sets source manually to tuner, even if there is none)
1712 		// if there is no tuner, it isn't in the list and can't be picked!
1713 		//if( (fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) == 0 )
1714 		//	fSource = C_VIDEO_IN_COMPOSITE;
1715 
1716 		break;
1717 	case P_STANDARD: {
1718 		if (*((const int32 *) value) == fStandard)
1719 			return;
1720 
1721 		fStandard = BeToVideoInStandard( *((const int32 *) value) );
1722 
1723 		fStandardLastChange = when;
1724 
1725 		media_format new_format = fOutput.format;
1726 
1727 		new_format.u.raw_video.field_rate = media_raw_video_format::wildcard.field_rate;
1728 		new_format.u.raw_video.interlace = media_raw_video_format::wildcard.interlace;
1729 		new_format.u.raw_video.pixel_width_aspect = media_raw_video_format::wildcard.pixel_width_aspect;
1730 		new_format.u.raw_video.pixel_height_aspect = media_raw_video_format::wildcard.pixel_height_aspect;
1731 		new_format.u.raw_video.first_active = media_raw_video_format::wildcard.first_active;
1732 		new_format.u.raw_video.last_active = media_raw_video_format::wildcard.last_active;
1733 
1734 		instantFormatChange( &new_format );
1735 		break; }
1736 	case P_MODE: {
1737 		if (*((const int32 *) value) == fMode)
1738 			return;
1739 
1740 		fMode = *((const uint32 *) value);
1741 		fModeLastChange = when;
1742 
1743 		media_format new_format = fOutput.format;
1744 
1745 		new_format.u.raw_video.field_rate = media_raw_video_format::wildcard.field_rate;
1746 		new_format.u.raw_video.interlace = media_raw_video_format::wildcard.interlace;
1747 		new_format.u.raw_video.pixel_width_aspect = media_raw_video_format::wildcard.pixel_width_aspect;
1748 		new_format.u.raw_video.pixel_height_aspect = media_raw_video_format::wildcard.pixel_height_aspect;
1749 
1750 		instantFormatChange( &new_format );
1751 
1752 		break; }
1753 	case P_FORMAT: {
1754 		if (*((const int32 *) value) == fFormat)
1755 			return;
1756 		fFormat = *((const uint32 *) value);
1757 		fFormatLastChange = when;
1758 
1759 		media_format new_format = fOutput.format;
1760 
1761 		new_format.u.raw_video.display.format = media_raw_video_format::wildcard.display.format;
1762 		new_format.u.raw_video.display.bytes_per_row = media_raw_video_format::wildcard.display.bytes_per_row;
1763 
1764 		instantFormatChange( &new_format );
1765 		break; }
1766 	case P_RESOLUTION:
1767 		if (*((const int32 *) value) == fResolution)
1768 			return;
1769 		fResolution = *((const uint32 *) value);
1770 		fResolutionLastChange = when;
1771 		// no live update - see instantFormatChange()
1772 		break;
1773 	case P_TUNER:
1774 		if (*((const int32 *) value) == fTuner)
1775 			return;
1776 		fTuner = *((const uint32 *) value);
1777 		fTunerLastChange = when;
1778 		fVideoIn.SetChannel(fTuner, C_VIDEO_IN_NTSC); // was hardcoded to NTSC
1779 		break;
1780 	case P_BRIGHTNESS:
1781 		if (*((const float *) value) == fBrightness)
1782 			return;
1783 		fBrightness = (int32)*((const float *) value);
1784 		fBrightnessLastChange = when;
1785 		fVideoIn.SetBrightness(fBrightness);
1786 		break;
1787 	case P_CONTRAST:
1788 		if (*((const float *) value) == fContrast)
1789 			return;
1790 		fContrast = (int32)*((const float *) value);
1791 		fContrastLastChange = when;
1792 		fVideoIn.SetContrast(fContrast);
1793 		break;
1794 	case P_SATURATION:
1795 		if (*((const float *) value) == fSaturation)
1796 			return;
1797 		fSaturation = (int32)*((const float *) value);
1798 		fSaturationLastChange = when;
1799 		fVideoIn.SetSaturation(fSaturation);
1800 		break;
1801 	case P_HUE:
1802 		if (*((const float *) value) == fHue)
1803 			return;
1804 		fHue = (int32)*((const float *) value);
1805 		fHueLastChange = when;
1806 		fVideoIn.SetHue(fHue);
1807 		break;
1808 	case P_SHARPNESS:
1809 		if (*((const float *) value) == fSharpness)
1810 			return;
1811 		fSharpness = (int32)*((const float *) value);
1812 		fSharpnessLastChange = when;
1813 		fVideoIn.SetSharpness(fSharpness);
1814 		break;
1815 	default:
1816 		return;
1817 	}
1818 
1819 	BroadcastNewParameterValue(when, id, const_cast<void *>(value), sizeof(uint32));
1820 }
1821 
1822 status_t
StartControlPanel(BMessenger * out_messenger)1823 CRadeonProducer::StartControlPanel(BMessenger *out_messenger)
1824 {
1825 	return BControllable::StartControlPanel(out_messenger);
1826 }
1827 
AddInt32(BMessage * msg,EOptions option,int32 value)1828 status_t CRadeonProducer::AddInt32(
1829 	BMessage *msg, EOptions option, int32 value )
1830 {
1831 	char name[5];
1832 
1833 	*(int32 *)name = option;
1834 	name[4] = 0;
1835 
1836 	return msg->AddInt32( name, value );
1837 }
1838 
1839 status_t
GetConfiguration(BMessage * out)1840 CRadeonProducer::GetConfiguration( BMessage *out )
1841 {
1842 	status_t res;
1843 
1844 	if( (res = AddInt32( out, P_SOURCE, fSource )) != B_OK ||
1845 		(res = AddInt32( out, P_STANDARD, BeToVideoInStandard( fStandard ))) != B_OK ||
1846 		(res = AddInt32( out, P_MODE, fMode )) != B_OK ||
1847 		(res = AddInt32( out, P_FORMAT, fFormat )) != B_OK ||
1848 		(res = AddInt32( out, P_RESOLUTION, fResolution )) != B_OK ||
1849 		(res = AddInt32( out, P_TUNER, fTuner )) != B_OK ||
1850 		(res = AddInt32( out, P_BRIGHTNESS, fBrightness )) != B_OK ||
1851 		(res = AddInt32( out, P_CONTRAST, fContrast )) != B_OK ||
1852 		(res = AddInt32( out, P_SATURATION, fSaturation )) != B_OK ||
1853 		(res = AddInt32( out, P_HUE, fHue )) != B_OK ||
1854 		(res = AddInt32( out, P_SHARPNESS, fSharpness )) != B_OK )
1855 		return res;
1856 
1857 	return B_OK;
1858 }
1859 
1860 
1861 /* VideoProducer */
1862 
1863 void
HandleStart(bigtime_t performance_time)1864 CRadeonProducer::HandleStart(bigtime_t performance_time)
1865 {
1866 	/* Start producing frames, even if the output hasn't been connected yet. */
1867 	DPRINT(("CRadeonProducer::HandleStart()\n"));
1868 
1869 	if( RunState() != BMediaEventLooper::B_STOPPED ) {
1870 		DPRINT(("already running\n"));
1871 		return;
1872 	}
1873 
1874 	SetRunState( BMediaEventLooper::B_STARTED );
1875 
1876 	startCapturing();
1877 }
1878 
1879 void
HandleStop(void)1880 CRadeonProducer::HandleStop(void)
1881 {
1882 	DPRINT(("CRadeonProducer::HandleStop()\n"));
1883 
1884 	fVideoIn.Stop();
1885 
1886 	// discard pending capture event
1887 	RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HARDWARE );
1888 }
1889 
1890 void
HandleTimeWarp(bigtime_t performance_time)1891 CRadeonProducer::HandleTimeWarp(bigtime_t performance_time)
1892 {
1893 	DPRINT(("CRadeonProducer::HandleTimeWarp()\n"));
1894 }
1895 
1896 void
HandleSeek(bigtime_t performance_time)1897 CRadeonProducer::HandleSeek(bigtime_t performance_time)
1898 {
1899 	DPRINT(("CRadeonProducer::HandleSeek()\n"));
1900 }
1901 
1902 void
captureField(bigtime_t * capture_time)1903 CRadeonProducer::captureField( bigtime_t *capture_time )
1904 {
1905 	*capture_time = system_time();
1906 
1907 	// don't capture if output is disabled
1908 	if (!fEnabled)
1909 		return;
1910 
1911 	BBuffer *buffer = fBufferGroup->RequestBuffer(
1912 		fOutput.format.u.raw_video.display.bytes_per_row *
1913 		fOutput.format.u.raw_video.display.line_count, 0LL);
1914 
1915 	if (!buffer) {
1916 		DPRINT(( "No buffer\n" ));
1917 		return;
1918 	}
1919 
1920 	media_header *h = buffer->Header();
1921 	h->type = B_MEDIA_RAW_VIDEO;
1922 	h->time_source = TimeSource()->ID();
1923 	h->size_used = fOutput.format.u.raw_video.display.bytes_per_row *
1924 					fOutput.format.u.raw_video.display.line_count;
1925 	h->file_pos = 0;
1926 	h->orig_size = 0;
1927 	h->data_offset = 0;
1928 	h->u.raw_video.field_gamma = 1.0;
1929 	h->u.raw_video.pulldown_number = 0;
1930 	h->u.raw_video.first_active_line = fOutput.format.u.raw_video.first_active;
1931 	h->u.raw_video.line_count = fOutput.format.u.raw_video.display.line_count;
1932 
1933 	int field_sequence;
1934 	short field_number;
1935 
1936 	int dropped=fVideoIn.Capture(
1937 		fOutput.format.u.raw_video.display.format,
1938 		buffer->Data(),
1939 		fOutput.format.u.raw_video.display.bytes_per_row * fOutput.format.u.raw_video.display.line_count,
1940 		fOutput.format.u.raw_video.display.bytes_per_row,
1941 		&field_sequence,
1942 		&field_number,
1943 		capture_time);
1944 
1945 	// HACK: store end instead of start time
1946 	// obviously, the _start_ time of a frame is always in the past by one
1947 	// frame; unfortunately, programs like stamptv expect the start time to
1948 	// be in the present, else they drop the frame; therefore, we write the
1949 	// _end_ time into the start time field, and everyone is happy (though
1950 	// the time is wrong)
1951 	// this leads to many tweaks in the code!
1952 	h->start_time = TimeSource()->PerformanceTimeFor( *capture_time );
1953 
1954 	h->u.raw_video.field_sequence = field_sequence - fFieldSequenceBase;
1955 	h->u.raw_video.field_number = field_number;
1956 
1957 	if (dropped > 1) {
1958 		PRINT(("%d frames dropped\n", dropped-1));
1959 	}
1960 
1961 	if (SendBuffer(buffer, fOutput.destination) < B_OK) {
1962 		PRINTF(-1, ("FrameGenerator: Error sending buffer\n"));
1963 		buffer->Recycle();
1964 	}
1965 }
1966 
1967 void
HandleHardware()1968 CRadeonProducer::HandleHardware()
1969 {
1970 	bigtime_t capture_time;
1971 
1972 	//DPRINT(("Hi\n"));
1973 
1974 	if( RunState() != BMediaEventLooper::B_STARTED )
1975 		return;
1976 
1977 	captureField( &capture_time );
1978 
1979 	// generate next event after next field
1980 	media_timed_event event(
1981 		capture_time + 1000000 / fOutput.format.u.raw_video.field_rate,
1982 		BTimedEventQueue::B_HARDWARE);
1983 
1984 	RealTimeQueue()->AddEvent(event);
1985 }
1986