1ffec4cb1Sshadow/******************************************************************************
2ffec4cb1Sshadow/
3ffec4cb1Sshadow/	File:			RadeonProducer.cpp
4ffec4cb1Sshadow/
5ffec4cb1Sshadow/	Description:	ATI Radeon Video Producer media node.
6ffec4cb1Sshadow/
7ffec4cb1Sshadow/	Copyright 2001, Carlos Hasan
8ffec4cb1Sshadow/
9ffec4cb1Sshadow*******************************************************************************/
10ffec4cb1Sshadow
11ffec4cb1Sshadow#include <fcntl.h>
12ffec4cb1Sshadow#include <malloc.h>
13ffec4cb1Sshadow#include <math.h>
14ffec4cb1Sshadow#include <stdio.h>
15ffec4cb1Sshadow#include <string.h>
16ffec4cb1Sshadow#include <sys/uio.h>
17ffec4cb1Sshadow#include <unistd.h>
18ffec4cb1Sshadow#include <scheduler.h>
19ffec4cb1Sshadow
20ffec4cb1Sshadow#include <media/Buffer.h>
21ffec4cb1Sshadow#include <media/BufferGroup.h>
22ffec4cb1Sshadow#include <media/ParameterWeb.h>
23ffec4cb1Sshadow#include <media/TimeSource.h>
24ffec4cb1Sshadow
25ffec4cb1Sshadow#include <support/Autolock.h>
26ffec4cb1Sshadow#include <support/Debug.h>
27ffec4cb1Sshadow
28ffec4cb1Sshadow#include <app/Message.h>
29ffec4cb1Sshadow
30ffec4cb1Sshadow#include "RadeonAddOn.h"
31863634b8SAxel Dörfler#include "VideoIn.h"
32ffec4cb1Sshadow
33ffec4cb1Sshadow#define DPRINT(args)	{ PRINT(("\x1b[0;30;35m")); PRINT(args); PRINT(("\x1b[0;30;47m")); }
34ffec4cb1Sshadow
35ffec4cb1Sshadow#define TOUCH(x) ((void)(x))
36ffec4cb1Sshadow
37ffec4cb1Sshadow#define PRINTF(a,b) \
38ffec4cb1Sshadow		do { \
39ffec4cb1Sshadow			if (a < 2) { \
40ffec4cb1Sshadow				printf("CRadeonProducer::"); \
41ffec4cb1Sshadow				printf b; \
42ffec4cb1Sshadow			} \
43ffec4cb1Sshadow		} while (0)
44ffec4cb1Sshadow
45ffec4cb1Sshadow#include "RadeonProducer.h"
46ffec4cb1Sshadow
47ffec4cb1Sshadow// convert Be video standard to video-in standard;
48ffec4cb1Sshadow// Be forgot some standards and define code 7 and 8 to be MPEG1/2, i.e.
49ffec4cb1Sshadow// didn't leave any space for enhancements, so I chose to use 101 and up;
50ffec4cb1Sshadow// this way, we get a scattered list of video standards, needing special
51ffec4cb1Sshadow// functions to convert to scattered Be-code to the compact video-in-code
52ffec4cb1Sshadowvideo_in_standard BeToVideoInStandard( int32 be_standard )
53ffec4cb1Sshadow{
54863634b8SAxel Dörfler
55863634b8SAxel Dörfler	DPRINT(("BeToVideoInStandard %d \n", be_standard));
56ffec4cb1Sshadow	switch( be_standard ) {
57ffec4cb1Sshadow	case 1:	return C_VIDEO_IN_NTSC;
58ffec4cb1Sshadow	case 2:	return C_VIDEO_IN_NTSC_JAPAN;
59ffec4cb1Sshadow	case 3:	return C_VIDEO_IN_PAL_BDGHI;
60ffec4cb1Sshadow	case 4:	return C_VIDEO_IN_PAL_M;
61ffec4cb1Sshadow	case 5:	return C_VIDEO_IN_PAL_N;
62ffec4cb1Sshadow	case 6:	return C_VIDEO_IN_SECAM;
63ffec4cb1Sshadow	case 101:	return C_VIDEO_IN_NTSC_443;
64ffec4cb1Sshadow	case 102:	return C_VIDEO_IN_PAL_60;
65ffec4cb1Sshadow	case 103:	return C_VIDEO_IN_PAL_NC;
66ffec4cb1Sshadow	default:	return C_VIDEO_IN_NTSC;
67ffec4cb1Sshadow	}
68ffec4cb1Sshadow}
69ffec4cb1Sshadow
70ffec4cb1Sshadowint32 VideoInStandardToBe( video_in_standard standard )
71ffec4cb1Sshadow{
72863634b8SAxel Dörfler	DPRINT(("VideoInStandardToBe %d \n", standard));
73863634b8SAxel Dörfler	switch( standard ) {
74863634b8SAxel Dörfler		case C_VIDEO_IN_NTSC:		return 1;
75863634b8SAxel Dörfler		case C_VIDEO_IN_NTSC_JAPAN:	return 2;
76863634b8SAxel Dörfler		case C_VIDEO_IN_PAL_BDGHI:	return 3;
77863634b8SAxel Dörfler		case C_VIDEO_IN_PAL_M:		return 4;
78863634b8SAxel Dörfler		case C_VIDEO_IN_PAL_N:		return 5;
79863634b8SAxel Dörfler		case C_VIDEO_IN_SECAM:		return 6;
80863634b8SAxel Dörfler		case C_VIDEO_IN_NTSC_443:	return 101;
81863634b8SAxel Dörfler		case C_VIDEO_IN_PAL_60:		return 102;
82863634b8SAxel Dörfler		case C_VIDEO_IN_PAL_NC:		return 103;
83863634b8SAxel Dörfler		default: return 1;
84863634b8SAxel Dörfler	}
85ffec4cb1Sshadow}
86ffec4cb1Sshadow
87ffec4cb1Sshadowstatus_t CRadeonProducer::FindInt32(
88ffec4cb1Sshadow	BMessage *config, EOptions option, int32 min_value, int32 max_value,
89ffec4cb1Sshadow	int32 default_value, int32 *value )
90ffec4cb1Sshadow{
91ffec4cb1Sshadow	char name[5];
92ffec4cb1Sshadow	status_t res;
93ffec4cb1Sshadow
94ffec4cb1Sshadow	*value = default_value;
95ffec4cb1Sshadow
96ffec4cb1Sshadow	*(int32 *)name = option;
97ffec4cb1Sshadow	name[4] = 0;
98ffec4cb1Sshadow
99ffec4cb1Sshadow	res = config->FindInt32( name, value );
100ffec4cb1Sshadow	if( res == B_NAME_NOT_FOUND )
101ffec4cb1Sshadow		return B_OK;
102ffec4cb1Sshadow
103ffec4cb1Sshadow	if( res != B_OK )
104ffec4cb1Sshadow		return res;
105ffec4cb1Sshadow
106ffec4cb1Sshadow	*value = MAX( *value, min_value );
107ffec4cb1Sshadow	*value = MIN( *value, max_value );
108ffec4cb1Sshadow	return B_OK;
109ffec4cb1Sshadow}
110ffec4cb1Sshadow
111ffec4cb1SshadowCRadeonProducer::CRadeonProducer(
112ffec4cb1Sshadow		CRadeonAddOn *addon, const char *name, const char *device_name, int32 internal_id,
113ffec4cb1Sshadow		BMessage *config )
114ffec4cb1Sshadow  :	BMediaNode(name),
115ffec4cb1Sshadow	BMediaEventLooper(),
116ffec4cb1Sshadow	BBufferProducer(B_MEDIA_RAW_VIDEO),
117ffec4cb1Sshadow	BControllable(),
118ffec4cb1Sshadow	fVideoIn( device_name )
119ffec4cb1Sshadow{
120ffec4cb1Sshadow	DPRINT(("CRadeonProducer::CRadeonProducer()\n"));
121ffec4cb1Sshadow
122ffec4cb1Sshadow	fInitStatus = B_NO_INIT;
123ffec4cb1Sshadow
124ffec4cb1Sshadow	fInternalID = internal_id;
125ffec4cb1Sshadow	fAddOn = addon;
126ffec4cb1Sshadow
127ffec4cb1Sshadow	fBufferGroup = NULL;
128ffec4cb1Sshadow	//fUsedBufferGroup = NULL;
129ffec4cb1Sshadow
130ffec4cb1Sshadow	fProcessingLatency = 0LL;
131ffec4cb1Sshadow
132ffec4cb1Sshadow	//fConnected = false;
133ffec4cb1Sshadow	fEnabled = true;
134ffec4cb1Sshadow
135ffec4cb1Sshadow	AddNodeKind(B_PHYSICAL_INPUT);
136ffec4cb1Sshadow
137ffec4cb1Sshadow	if( fVideoIn.InitCheck() == B_OK )
138ffec4cb1Sshadow		fInitStatus = B_OK;
139ffec4cb1Sshadow
140ffec4cb1Sshadow	fSource = ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0 ? C_VIDEO_IN_TUNER : C_VIDEO_IN_COMPOSITE);
141863634b8SAxel Dörfler	fStandard = C_VIDEO_IN_NTSC;
142ffec4cb1Sshadow	fMode = C_VIDEO_IN_WEAVE;
143ffec4cb1Sshadow	fFormat = B_RGB32;
144ffec4cb1Sshadow	fResolution = 4;
145ffec4cb1Sshadow	fTuner = 25;
146ffec4cb1Sshadow	fBrightness = 0;
147ffec4cb1Sshadow	fContrast = 0;
148ffec4cb1Sshadow	fSaturation = 0;
149ffec4cb1Sshadow	fHue = 0;
150ffec4cb1Sshadow	fSharpness = 0;
151ffec4cb1Sshadow
152ffec4cb1Sshadow	if( config != NULL ) {
153ffec4cb1Sshadow		status_t res;
154ffec4cb1Sshadow		int32 standard;
155ffec4cb1Sshadow
156ffec4cb1Sshadow		if( (res = FindInt32( config, P_SOURCE, 0, C_VIDEO_IN_SOURCE_MAX,
157ffec4cb1Sshadow			 (fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0 ? C_VIDEO_IN_TUNER : C_VIDEO_IN_COMPOSITE,
158ffec4cb1Sshadow			 &fSource )) != B_OK ||
159ffec4cb1Sshadow			(res = FindInt32( config, P_STANDARD, 0, C_VIDEO_IN_STANDARD_MAX,
160ffec4cb1Sshadow				C_VIDEO_IN_NTSC, &standard )) != B_OK ||
161ffec4cb1Sshadow			(res = FindInt32( config, P_MODE, 0, C_VIDEO_IN_CAPTURE_MODE_MAX,
162ffec4cb1Sshadow				C_VIDEO_IN_FIELD, &fMode )) != B_OK ||
163ffec4cb1Sshadow			(res = FindInt32( config, P_FORMAT, -2147483647L-1, 2147483647L,
164ffec4cb1Sshadow				B_RGB16, &fFormat )) != B_OK ||
165ffec4cb1Sshadow			(res = FindInt32( config, P_RESOLUTION, 0, C_RESOLUTION_MAX,
166ffec4cb1Sshadow				4, &fResolution )) != B_OK ||
167ffec4cb1Sshadow			(res = FindInt32( config, P_TUNER, 0, C_CHANNEL_MAX,
168ffec4cb1Sshadow				25, &fTuner )) != B_OK ||
169ffec4cb1Sshadow			(res = FindInt32( config, P_BRIGHTNESS, -100, +100,
170ffec4cb1Sshadow				0, &fBrightness )) != B_OK ||
171ffec4cb1Sshadow			(res = FindInt32( config, P_CONTRAST, 0, 100,
172ffec4cb1Sshadow				0, &fContrast )) != B_OK ||
173ffec4cb1Sshadow			(res = FindInt32( config, P_SATURATION, -100, +100,
174ffec4cb1Sshadow				0, &fSaturation )) != B_OK ||
175ffec4cb1Sshadow			(res = FindInt32( config, P_HUE, -90, +90,
176ffec4cb1Sshadow				0, &fHue )) != B_OK ||
177ffec4cb1Sshadow			(res = FindInt32( config, P_SHARPNESS, 0, 15,
178ffec4cb1Sshadow				0, &fSharpness )) != B_OK )
179ffec4cb1Sshadow		{
180ffec4cb1Sshadow			DPRINT(("Corrupted settings (%s)\n", strerror( res )));
181ffec4cb1Sshadow		}
182ffec4cb1Sshadow
183ffec4cb1Sshadow		// standard is stored as internal code (which has no "holes" in its numbering);
184ffec4cb1Sshadow		// time to convert it
185863634b8SAxel Dörfler		// if this value comes from our setup web is it not already linear?
186ffec4cb1Sshadow		fStandard = VideoInStandardToBe( (video_in_standard)standard );
187ffec4cb1Sshadow
188ffec4cb1Sshadow		// if there is no tuner, force composite input
189ffec4cb1Sshadow		if( (fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) == 0 )
190ffec4cb1Sshadow			fSource = C_VIDEO_IN_COMPOSITE;
191ffec4cb1Sshadow
192ffec4cb1Sshadow		// format ids are scattered, so we must verify them manually
193ffec4cb1Sshadow		switch( fFormat ) {
194ffec4cb1Sshadow		case B_YCbCr422:
195ffec4cb1Sshadow		case B_GRAY8:
196ffec4cb1Sshadow		case B_RGB15:
197ffec4cb1Sshadow		case B_RGB16:
198ffec4cb1Sshadow		case B_RGB32:
199ffec4cb1Sshadow			break;
200ffec4cb1Sshadow		default:
201ffec4cb1Sshadow			fFormat = B_RGB16;
202ffec4cb1Sshadow		}
203ffec4cb1Sshadow	}
204ffec4cb1Sshadow
205ffec4cb1Sshadow	fSourceLastChange =
206ffec4cb1Sshadow	fStandardLastChange =
207ffec4cb1Sshadow	fModeLastChange =
208ffec4cb1Sshadow	fFormatLastChange =
209ffec4cb1Sshadow	fResolutionLastChange =
210ffec4cb1Sshadow	fTunerLastChange =
211ffec4cb1Sshadow	fBrightnessLastChange =
212ffec4cb1Sshadow	fContrastLastChange =
213ffec4cb1Sshadow	fSaturationLastChange =
214ffec4cb1Sshadow	fHueLastChange =
215ffec4cb1Sshadow	fSharpnessLastChange = system_time();
216ffec4cb1Sshadow
217ffec4cb1Sshadow	fOutput.destination = media_destination::null;
218ffec4cb1Sshadow	strcpy(fOutput.name, Name());
219ffec4cb1Sshadow
220ffec4cb1Sshadow	// we provide interlaced raw video in any format
221ffec4cb1Sshadow	fOutput.format.type = B_MEDIA_RAW_VIDEO;
222ffec4cb1Sshadow	fOutput.format.u.raw_video = media_raw_video_format::wildcard;
223ffec4cb1Sshadow}
224ffec4cb1Sshadow
225ffec4cb1Sshadow
226ffec4cb1Sshadowvoid CRadeonProducer::setupWeb()
227ffec4cb1Sshadow{
228ffec4cb1Sshadow	///////////
229ffec4cb1Sshadow	/* Set up the parameter web */
230ffec4cb1Sshadow
231ffec4cb1Sshadow	// in "kind" value of parameters is "stampTV-compatible", i.e.
232ffec4cb1Sshadow	// if not defined, we use the name used in stampTV
233ffec4cb1Sshadow	BParameterWeb *web = new BParameterWeb();
234ffec4cb1Sshadow	BParameterGroup *controls = web->MakeGroup("Controls");
235ffec4cb1Sshadow	BParameterGroup *options = web->MakeGroup("Video");
236ffec4cb1Sshadow	/*BParameterGroup *audio = web->MakeGroup("Audio");*/
237ffec4cb1Sshadow
238ffec4cb1Sshadow	BParameterGroup *controls1 = controls->MakeGroup("Controls1");
239ffec4cb1Sshadow	BParameterGroup *controls2 = controls->MakeGroup("Controls2");
240ffec4cb1Sshadow	BParameterGroup *controls3 = controls->MakeGroup("Controls3");
241ffec4cb1Sshadow
242ffec4cb1Sshadow	BParameterGroup *options1 = options->MakeGroup("Options1");
243ffec4cb1Sshadow	BParameterGroup *options2 = options->MakeGroup("Options2");
244ffec4cb1Sshadow
245ffec4cb1Sshadow	/*BParameterGroup *audio1 = audio->MakeGroup("Audio1");
246ffec4cb1Sshadow	BParameterGroup *audio2 = audio->MakeGroup("Audio2");*/
247ffec4cb1Sshadow
248ffec4cb1Sshadow
249ffec4cb1Sshadow	// Controls
250ffec4cb1Sshadow	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0) {
251ffec4cb1Sshadow		// Controls.Channel
252ffec4cb1Sshadow		BDiscreteParameter *tuner = controls1->MakeDiscreteParameter(
253ffec4cb1Sshadow			P_TUNER, B_MEDIA_NO_TYPE, "Channel:", B_TUNER_CHANNEL);
254ffec4cb1Sshadow
255ffec4cb1Sshadow		for (int channel = 0; channel <= 125; channel++) {
256ffec4cb1Sshadow			char buffer[32];
257ffec4cb1Sshadow			sprintf(buffer, "%d", channel);
258ffec4cb1Sshadow			tuner->AddItem(channel, buffer);
259ffec4cb1Sshadow		}
260ffec4cb1Sshadow	}
261ffec4cb1Sshadow
262ffec4cb1Sshadow	// Controls.Source
263ffec4cb1Sshadow	BDiscreteParameter *source = controls1->MakeDiscreteParameter(
264ffec4cb1Sshadow		P_SOURCE, B_MEDIA_RAW_VIDEO, "Video Input:", "Video Input:");
265ffec4cb1Sshadow
266ffec4cb1Sshadow	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0)
267ffec4cb1Sshadow		source->AddItem(C_VIDEO_IN_TUNER, "Tuner");
268ffec4cb1Sshadow	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_COMPOSITE) != 0)
269ffec4cb1Sshadow		source->AddItem(C_VIDEO_IN_COMPOSITE, "Composite");
270ffec4cb1Sshadow	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_SVIDEO) != 0)
271ffec4cb1Sshadow		source->AddItem(C_VIDEO_IN_SVIDEO, "SVideo");
272ffec4cb1Sshadow
273ffec4cb1Sshadow	// TODO:
274ffec4cb1Sshadow	BDiscreteParameter *source2 = controls1->MakeDiscreteParameter(
275ffec4cb1Sshadow		P_AUDIO_SOURCE, B_MEDIA_RAW_VIDEO, "Audio Input:", "Audio Input:");
276ffec4cb1Sshadow	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0)
277ffec4cb1Sshadow		source2->AddItem(C_VIDEO_IN_TUNER, "Tuner");
278863634b8SAxel Dörfler/*	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_COMPOSITE) != 0)
279ffec4cb1Sshadow		source2->AddItem(C_VIDEO_IN_COMPOSITE, "Composite");
280ffec4cb1Sshadow	if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_SVIDEO) != 0)
281ffec4cb1Sshadow		source2->AddItem(C_VIDEO_IN_SVIDEO, "SVideo");
282863634b8SAxel Dörfler*/
283ffec4cb1Sshadow
284ffec4cb1Sshadow	// Controls.Brightness/Contrast/Saturation/Hue
285ffec4cb1Sshadow	controls2->MakeContinuousParameter(P_BRIGHTNESS, B_MEDIA_RAW_VIDEO,"Brightness", "BRIGHTNESS", "", -100, 100, 1);
286ffec4cb1Sshadow	controls2->MakeContinuousParameter(P_CONTRAST, B_MEDIA_RAW_VIDEO, "Contrast", "CONTRAST", "", 0, 100, 1);
287ffec4cb1Sshadow	controls2->MakeContinuousParameter(P_SHARPNESS, B_MEDIA_RAW_VIDEO, "Sharpness", B_LEVEL, "dB", 0, 15, 1);
288ffec4cb1Sshadow
289ffec4cb1Sshadow	controls3->MakeContinuousParameter(P_SATURATION, B_MEDIA_RAW_VIDEO, "Saturation", "SATURATION", "", -100, 100, 1);
290ffec4cb1Sshadow	controls3->MakeContinuousParameter(P_HUE, B_MEDIA_RAW_VIDEO, "Hue", B_LEVEL, "��", -90, 90, 1);
291ffec4cb1Sshadow
292ffec4cb1Sshadow
293ffec4cb1Sshadow	// Options.Resolution
294ffec4cb1Sshadow	BDiscreteParameter *resolution = options1->MakeDiscreteParameter(
295ffec4cb1Sshadow		P_RESOLUTION, B_MEDIA_RAW_VIDEO, "Default Image Size:", B_RESOLUTION);
296ffec4cb1Sshadow
297ffec4cb1Sshadow	resolution->AddItem(6, "768x576");
298ffec4cb1Sshadow	resolution->AddItem(5, "720x576");
299ffec4cb1Sshadow	resolution->AddItem(4, "720x480");
300ffec4cb1Sshadow	resolution->AddItem(0, "640x480");
301ffec4cb1Sshadow	resolution->AddItem(3, "480x360");
302ffec4cb1Sshadow	resolution->AddItem(1, "320x240");
303ffec4cb1Sshadow	resolution->AddItem(2, "160x120");
304ffec4cb1Sshadow
305ffec4cb1Sshadow	// Options.Format
306ffec4cb1Sshadow	BDiscreteParameter *format = options1->MakeDiscreteParameter(
307ffec4cb1Sshadow		P_FORMAT, B_MEDIA_RAW_VIDEO, "Default Colors:", B_COLOR_SPACE);
308ffec4cb1Sshadow
309ffec4cb1Sshadow	format->AddItem(B_YCbCr422, "YCbCr422 (fastest)");
310ffec4cb1Sshadow	format->AddItem(B_GRAY8, "8 Bits/Pixel (gray)");
311ffec4cb1Sshadow	format->AddItem(B_RGB15, "15 Bits/Pixel");
312ffec4cb1Sshadow	format->AddItem(B_RGB16, "16 Bits/Pixel");
313ffec4cb1Sshadow	format->AddItem(B_RGB32, "32 Bits/Pixel");
314ffec4cb1Sshadow
315ffec4cb1Sshadow	// Options.Standard
316ffec4cb1Sshadow	BDiscreteParameter *standard = options2->MakeDiscreteParameter(
317ffec4cb1Sshadow		P_STANDARD, B_MEDIA_RAW_VIDEO, "Video Format:", B_VIDEO_FORMAT);
318ffec4cb1Sshadow
319ffec4cb1Sshadow	standard->AddItem(1, "NTSC");
320ffec4cb1Sshadow	standard->AddItem(2, "NTSC Japan");
321ffec4cb1Sshadow	standard->AddItem(101, "NTSC 443");
322ffec4cb1Sshadow	standard->AddItem(4, "PAL M");
323ffec4cb1Sshadow	standard->AddItem(3, "PAL BDGHI");
324ffec4cb1Sshadow	standard->AddItem(5, "PAL N");
325ffec4cb1Sshadow	standard->AddItem(102, "PAL 60");
326ffec4cb1Sshadow	standard->AddItem(103, "PAL NC");
327ffec4cb1Sshadow	standard->AddItem(6, "SECAM");
328ffec4cb1Sshadow
329ffec4cb1Sshadow	// Options.Mode
330ffec4cb1Sshadow	BDiscreteParameter *mode = options2->MakeDiscreteParameter(
331ffec4cb1Sshadow		P_MODE, B_MEDIA_RAW_VIDEO, "Video Interlace:", B_GENERIC);
332ffec4cb1Sshadow
333ffec4cb1Sshadow	mode->AddItem(C_VIDEO_IN_FIELD, "Field");
334ffec4cb1Sshadow	mode->AddItem(C_VIDEO_IN_BOB, "Bob");
335ffec4cb1Sshadow	mode->AddItem(C_VIDEO_IN_WEAVE, "Weave");
336ffec4cb1Sshadow
337ffec4cb1Sshadow
338ffec4cb1Sshadow	// TODO:
339ffec4cb1Sshadow	/*
340ffec4cb1Sshadow	BDiscreteParameter *standard2 = audio1->MakeDiscreteParameter(
341ffec4cb1Sshadow		P_AUDIO_FORMAT, B_MEDIA_RAW_VIDEO, "Audio Format:", B_VIDEO_FORMAT);
342ffec4cb1Sshadow	standard2->AddItem(0, "Stereo");
343ffec4cb1Sshadow	standard2->AddItem(1, "Mono");
344ffec4cb1Sshadow	standard2->AddItem(2, "NICAM");
345ffec4cb1Sshadow
346ffec4cb1Sshadow	BDiscreteParameter *audioSource = audio1->MakeDiscreteParameter(
347ffec4cb1Sshadow		P_AUDIO_FORMAT, B_MEDIA_RAW_VIDEO, "Audio Source:", B_VIDEO_FORMAT);
348ffec4cb1Sshadow	audioSource->AddItem(0, "FM");
349ffec4cb1Sshadow	audioSource->AddItem(1, "Stereo");
350ffec4cb1Sshadow	audioSource->AddItem(2, "SCART");
351ffec4cb1Sshadow	audioSource->AddItem(3, "Language A");
352ffec4cb1Sshadow	audioSource->AddItem(4, "Language B");
353ffec4cb1Sshadow
354ffec4cb1Sshadow	BDiscreteParameter *matrix= audio2->MakeDiscreteParameter(
355ffec4cb1Sshadow		P_AUDIO_FORMAT, B_MEDIA_RAW_VIDEO, "Audio Matrix:", B_VIDEO_FORMAT);
356ffec4cb1Sshadow	matrix->AddItem(0, "Sound A");
357ffec4cb1Sshadow	matrix->AddItem(1, "Sound B");
358ffec4cb1Sshadow	matrix->AddItem(2, "Stereo");
359ffec4cb1Sshadow	matrix->AddItem(3, "Mono");*/
360ffec4cb1Sshadow
361ffec4cb1Sshadow	/* After this call, the BControllable owns the BParameterWeb object and
362ffec4cb1Sshadow	 * will delete it for you */
363ffec4cb1Sshadow	SetParameterWeb(web);
364ffec4cb1Sshadow	/////////
365ffec4cb1Sshadow}
366ffec4cb1Sshadow
367ffec4cb1SshadowCRadeonProducer::~CRadeonProducer()
368ffec4cb1Sshadow{
369ffec4cb1Sshadow	DPRINT(("CRadeonProducer::~CRadeonProducer()\n"));
370ffec4cb1Sshadow
371ffec4cb1Sshadow	if (fInitStatus == B_OK) {
372ffec4cb1Sshadow		/* Clean up after ourselves, in case the application didn't make us
373ffec4cb1Sshadow		 * do so. */
374ffec4cb1Sshadow		/*if (fConnected)
375ffec4cb1Sshadow			Disconnect(fOutput.source, fOutput.destination);*/
376ffec4cb1Sshadow
377ffec4cb1Sshadow		HandleStop();
378ffec4cb1Sshadow	}
379ffec4cb1Sshadow
380ffec4cb1Sshadow	delete fBufferGroup;
381ffec4cb1Sshadow	fBufferGroup = NULL;
382ffec4cb1Sshadow
383ffec4cb1Sshadow	BMessage settings;
384ffec4cb1Sshadow
385ffec4cb1Sshadow	GetConfiguration( &settings );
386ffec4cb1Sshadow
387ffec4cb1Sshadow	fAddOn->UnregisterNode( this, &settings );
388ffec4cb1Sshadow
389ffec4cb1Sshadow	Quit();
390ffec4cb1Sshadow}
391ffec4cb1Sshadow
392ffec4cb1Sshadow/* BMediaNode */
393ffec4cb1Sshadow
394ffec4cb1Sshadowport_id
395ffec4cb1SshadowCRadeonProducer::ControlPort() const
396ffec4cb1Sshadow{
397ffec4cb1Sshadow	return BMediaNode::ControlPort();
398ffec4cb1Sshadow}
399ffec4cb1Sshadow
400ffec4cb1SshadowBMediaAddOn *
401ffec4cb1SshadowCRadeonProducer::AddOn(int32 *internal_id) const
402ffec4cb1Sshadow{
403ffec4cb1Sshadow	if (internal_id)
404ffec4cb1Sshadow		*internal_id = fInternalID;
405ffec4cb1Sshadow	return fAddOn;
406ffec4cb1Sshadow}
407ffec4cb1Sshadow
408ffec4cb1Sshadowstatus_t
409ffec4cb1SshadowCRadeonProducer::HandleMessage(int32 message, const void *data, size_t size)
410ffec4cb1Sshadow{
411ffec4cb1Sshadow	//DPRINT(("CRadeonProducer::HandleMessage()\n"));
412ffec4cb1Sshadow
413ffec4cb1Sshadow	switch( message ) {
414ffec4cb1Sshadow		case C_GET_CONFIGURATION: {
415ffec4cb1Sshadow			const configuration_msg *request = (const configuration_msg *)data;
416ffec4cb1Sshadow			BMessage msg;
417ffec4cb1Sshadow			configuration_msg_reply *reply;
418ffec4cb1Sshadow			size_t reply_size, config_size;
419ffec4cb1Sshadow			status_t res;
420ffec4cb1Sshadow
421ffec4cb1Sshadow			if( size < sizeof( configuration_msg ))
422ffec4cb1Sshadow				return B_ERROR;
423ffec4cb1Sshadow
424ffec4cb1Sshadow			res = GetConfiguration( &msg );
425ffec4cb1Sshadow
426ffec4cb1Sshadow			config_size = msg.FlattenedSize();
427ffec4cb1Sshadow			reply_size = sizeof( *reply ) + config_size;
428ffec4cb1Sshadow			reply = (configuration_msg_reply *)malloc( reply_size );
429ffec4cb1Sshadow			if( reply == NULL )
430ffec4cb1Sshadow				return B_NO_MEMORY;
431ffec4cb1Sshadow
432ffec4cb1Sshadow			reply->res = res;
433ffec4cb1Sshadow			reply->config_size = config_size;
434ffec4cb1Sshadow			msg.Flatten( &reply->config, config_size );
435ffec4cb1Sshadow
436ffec4cb1Sshadow			write_port_etc( request->reply_port, C_GET_CONFIGURATION_REPLY,
437ffec4cb1Sshadow				reply, reply_size, B_TIMEOUT, 0 );
438ffec4cb1Sshadow
439ffec4cb1Sshadow			free( reply );
440ffec4cb1Sshadow			return B_OK;
441ffec4cb1Sshadow		}
442ffec4cb1Sshadow		default:
443ffec4cb1Sshadow			return B_ERROR;
444ffec4cb1Sshadow	//	return BControllable::HandleMessage(message, data, size);
445ffec4cb1Sshadow	}
446ffec4cb1Sshadow}
447ffec4cb1Sshadow
448ffec4cb1Sshadowvoid
449ffec4cb1SshadowCRadeonProducer::Preroll()
450ffec4cb1Sshadow{
451ffec4cb1Sshadow	/* This hook may be called before the node is started to give the hardware
452ffec4cb1Sshadow	 * a chance to start. */
453ffec4cb1Sshadow	DPRINT(("CRadeonProducer::Preroll()\n"));
454ffec4cb1Sshadow}
455ffec4cb1Sshadow
456ffec4cb1Sshadowvoid
457ffec4cb1SshadowCRadeonProducer::SetTimeSource(BTimeSource *time_source)
458ffec4cb1Sshadow{
459ffec4cb1Sshadow	DPRINT(("CRadeonProducer::SetTimeSource()\n"));
460ffec4cb1Sshadow
461ffec4cb1Sshadow	/* Tell frame generation thread to recalculate delay value */
462ffec4cb1Sshadow	//release_sem(fFrameSync);
463ffec4cb1Sshadow}
464ffec4cb1Sshadow
465ffec4cb1Sshadowstatus_t
466ffec4cb1SshadowCRadeonProducer::RequestCompleted(const media_request_info &info)
467ffec4cb1Sshadow{
468ffec4cb1Sshadow	DPRINT(("CRadeonProducer::RequestCompleted()\n"));
469ffec4cb1Sshadow
470ffec4cb1Sshadow	return BMediaNode::RequestCompleted(info);
471ffec4cb1Sshadow}
472ffec4cb1Sshadow
473ffec4cb1Sshadow/* BMediaEventLooper */
474ffec4cb1Sshadow
475ffec4cb1Sshadowvoid
476ffec4cb1SshadowCRadeonProducer::NodeRegistered()
477ffec4cb1Sshadow{
478ffec4cb1Sshadow	DPRINT(("CRadeonProducer::NodeRegistered()\n"));
479ffec4cb1Sshadow
480ffec4cb1Sshadow	if (fInitStatus != B_OK) {
481ffec4cb1Sshadow		ReportError(B_NODE_IN_DISTRESS);
482ffec4cb1Sshadow		return;
483ffec4cb1Sshadow	}
484ffec4cb1Sshadow
485ffec4cb1Sshadow	setupWeb();
486ffec4cb1Sshadow//!!//
487ffec4cb1Sshadow
488ffec4cb1Sshadow	fOutput.node = Node();
489ffec4cb1Sshadow	fOutput.source.port = ControlPort();
490ffec4cb1Sshadow	fOutput.source.id = 0;
491ffec4cb1Sshadow
492ffec4cb1Sshadow	/* Tailor these for the output of your device */
493ffec4cb1Sshadow	/********
494ffec4cb1Sshadow	fOutput.format.type = B_MEDIA_RAW_VIDEO;
495ffec4cb1Sshadow	fOutput.format.u.raw_video = media_raw_video_format::wildcard;
496ffec4cb1Sshadow//	fOutput.format.u.raw_video.interlace = 1;
497ffec4cb1Sshadow	fOutput.format.u.raw_video.display.format = B_RGB32;
498ffec4cb1Sshadow	********/
499ffec4cb1Sshadow
500ffec4cb1Sshadow	// up to 60 frames (NTSC); jitter less then half a frame; processing time
501ffec4cb1Sshadow	// depends on whether colour space conversion is required, let's say half
502ffec4cb1Sshadow	// a frame in worst case
503ffec4cb1Sshadow	SetPriority( suggest_thread_priority( B_VIDEO_RECORDING, 60, 8000, 8000 ));
504ffec4cb1Sshadow
505ffec4cb1Sshadow	/* Start the BMediaEventLooper control loop running */
506ffec4cb1Sshadow	Run();
507ffec4cb1Sshadow}
508ffec4cb1Sshadow
509ffec4cb1Sshadowvoid
510ffec4cb1SshadowCRadeonProducer::Start(bigtime_t performance_time)
511ffec4cb1Sshadow{
512ffec4cb1Sshadow	DPRINT(("CRadeonProducer::Start()\n"));
513ffec4cb1Sshadow
514ffec4cb1Sshadow	BMediaEventLooper::Start(performance_time);
515ffec4cb1Sshadow}
516ffec4cb1Sshadow
517ffec4cb1Sshadowvoid
518ffec4cb1SshadowCRadeonProducer::Stop(bigtime_t performance_time, bool immediate)
519ffec4cb1Sshadow{
520ffec4cb1Sshadow	DPRINT(("CRadeonProducer::Stop()\n"));
521ffec4cb1Sshadow
522ffec4cb1Sshadow	BMediaEventLooper::Stop(performance_time, immediate);
523ffec4cb1Sshadow}
524ffec4cb1Sshadow
525ffec4cb1Sshadowvoid
526ffec4cb1SshadowCRadeonProducer::Seek(bigtime_t media_time, bigtime_t performance_time)
527ffec4cb1Sshadow{
528ffec4cb1Sshadow	DPRINT(("CRadeonProducer::Seek()\n"));
529ffec4cb1Sshadow
530ffec4cb1Sshadow	BMediaEventLooper::Seek(media_time, performance_time);
531ffec4cb1Sshadow}
532ffec4cb1Sshadow
533ffec4cb1Sshadowvoid
534ffec4cb1SshadowCRadeonProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
535ffec4cb1Sshadow{
536ffec4cb1Sshadow	DPRINT(("CRadeonProducer::TimeWarp()\n"));
537ffec4cb1Sshadow
538ffec4cb1Sshadow	BMediaEventLooper::TimeWarp(at_real_time, to_performance_time);
539ffec4cb1Sshadow}
540ffec4cb1Sshadow
541ffec4cb1Sshadowstatus_t
542ffec4cb1SshadowCRadeonProducer::AddTimer(bigtime_t at_performance_time, int32 cookie)
543ffec4cb1Sshadow{
544ffec4cb1Sshadow	DPRINT(("CRadeonProducer::AddTimer()\n"));
545ffec4cb1Sshadow
546ffec4cb1Sshadow	return BMediaEventLooper::AddTimer(at_performance_time, cookie);
547ffec4cb1Sshadow}
548ffec4cb1Sshadow
549ffec4cb1Sshadowvoid
550ffec4cb1SshadowCRadeonProducer::SetRunMode(run_mode mode)
551ffec4cb1Sshadow{
552ffec4cb1Sshadow	DPRINT(("CRadeonProducer::SetRunMode()\n"));
553ffec4cb1Sshadow
554ffec4cb1Sshadow	BMediaEventLooper::SetRunMode(mode);
555ffec4cb1Sshadow}
556ffec4cb1Sshadow
557ffec4cb1Sshadowvoid
558ffec4cb1SshadowCRadeonProducer::HandleEvent(const media_timed_event *event,
559ffec4cb1Sshadow		bigtime_t lateness, bool realTimeEvent)
560ffec4cb1Sshadow{
561ffec4cb1Sshadow	//DPRINT(("CRadeonProducer::HandleEvent()\n"));
562ffec4cb1Sshadow
563ffec4cb1Sshadow	TOUCH(lateness); TOUCH(realTimeEvent);
564ffec4cb1Sshadow
565ffec4cb1Sshadow	switch(event->type)
566ffec4cb1Sshadow	{
567ffec4cb1Sshadow		case BTimedEventQueue::B_START:
568ffec4cb1Sshadow			HandleStart(event->event_time);
569ffec4cb1Sshadow			break;
570ffec4cb1Sshadow		case BTimedEventQueue::B_STOP:
571ffec4cb1Sshadow			HandleStop();
572ffec4cb1Sshadow			break;
573ffec4cb1Sshadow		case BTimedEventQueue::B_WARP:
574ffec4cb1Sshadow			HandleTimeWarp(event->bigdata);
575ffec4cb1Sshadow			break;
576ffec4cb1Sshadow		case BTimedEventQueue::B_SEEK:
577ffec4cb1Sshadow			HandleSeek(event->bigdata);
578ffec4cb1Sshadow			break;
579ffec4cb1Sshadow		case BTimedEventQueue::B_HANDLE_BUFFER:
580ffec4cb1Sshadow		case BTimedEventQueue::B_DATA_STATUS:
581ffec4cb1Sshadow		case BTimedEventQueue::B_PARAMETER:
582ffec4cb1Sshadow		default:
583ffec4cb1Sshadow			PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type));
584ffec4cb1Sshadow			break;
585ffec4cb1Sshadow		case BTimedEventQueue::B_HARDWARE:
586ffec4cb1Sshadow			HandleHardware();
587ffec4cb1Sshadow			break;
588ffec4cb1Sshadow	}
589ffec4cb1Sshadow
590ffec4cb1Sshadow	//DPRINT(("CRadeonProducer::HandleEvent() done\n"));
591ffec4cb1Sshadow}
592ffec4cb1Sshadow
593ffec4cb1Sshadowvoid
594ffec4cb1SshadowCRadeonProducer::CleanUpEvent(const media_timed_event *event)
595ffec4cb1Sshadow{
596ffec4cb1Sshadow	DPRINT(("CRadeonProducer::CleanUpEvent()\n"));
597ffec4cb1Sshadow
598ffec4cb1Sshadow	BMediaEventLooper::CleanUpEvent(event);
599ffec4cb1Sshadow}
600ffec4cb1Sshadow
601ffec4cb1Sshadowbigtime_t
602ffec4cb1SshadowCRadeonProducer::OfflineTime()
603ffec4cb1Sshadow{
604ffec4cb1Sshadow	return BMediaEventLooper::OfflineTime();
605ffec4cb1Sshadow}
606ffec4cb1Sshadow
607ffec4cb1Sshadowvoid
608ffec4cb1SshadowCRadeonProducer::ControlLoop()
609ffec4cb1Sshadow{
610ffec4cb1Sshadow	BMediaEventLooper::ControlLoop();
611ffec4cb1Sshadow}
612ffec4cb1Sshadow
613ffec4cb1Sshadowstatus_t
614ffec4cb1SshadowCRadeonProducer::DeleteHook(BMediaNode * node)
615ffec4cb1Sshadow{
616ffec4cb1Sshadow	DPRINT(("CRadeonProducer::DeleteHook()\n"));
617ffec4cb1Sshadow
618ffec4cb1Sshadow	return BMediaEventLooper::DeleteHook(node);
619ffec4cb1Sshadow}
620ffec4cb1Sshadow
621ffec4cb1Sshadow
622ffec4cb1Sshadow
623ffec4cb1Sshadow/* BBufferProducer */
624ffec4cb1Sshadow
625ffec4cb1Sshadow// choose capture mode according to format and update format according to that
626ffec4cb1Sshadowstatus_t
627ffec4cb1SshadowCRadeonProducer::verifySetMode( media_format *format )
628ffec4cb1Sshadow{
629ffec4cb1Sshadow	float frame_rate = fVideoIn.getFrameRate(
630ffec4cb1Sshadow		BeToVideoInStandard( fStandard )) / 1000.0f;
631ffec4cb1Sshadow
632ffec4cb1Sshadow	if( format->u.raw_video.interlace == media_raw_video_format::wildcard.interlace ) {
633ffec4cb1Sshadow		if( format->u.raw_video.field_rate == media_raw_video_format::wildcard.field_rate ) {
634ffec4cb1Sshadow			format->u.raw_video.interlace = fMode == C_VIDEO_IN_BOB ? 2 : 1;
635ffec4cb1Sshadow			format->u.raw_video.field_rate = frame_rate * format->u.raw_video.interlace;
636ffec4cb1Sshadow		} else {
637ffec4cb1Sshadow			if( format->u.raw_video.field_rate == frame_rate )
638ffec4cb1Sshadow				format->u.raw_video.interlace = 1;
639ffec4cb1Sshadow			else if( format->u.raw_video.field_rate == frame_rate * 2 )
640ffec4cb1Sshadow				format->u.raw_video.interlace = 2;
641ffec4cb1Sshadow			else {
642ffec4cb1Sshadow				DPRINT(( "Unsupported field rate for active TV standard (%f)\n",
643ffec4cb1Sshadow					format->u.raw_video.field_rate ));
644ffec4cb1Sshadow				return B_MEDIA_BAD_FORMAT;
645ffec4cb1Sshadow			}
646ffec4cb1Sshadow		}
647ffec4cb1Sshadow
648ffec4cb1Sshadow	} else if( format->u.raw_video.interlace == 1 ) {
649ffec4cb1Sshadow		if( format->u.raw_video.field_rate == media_raw_video_format::wildcard.field_rate )
650ffec4cb1Sshadow			format->u.raw_video.field_rate = frame_rate;
651ffec4cb1Sshadow		else {
652ffec4cb1Sshadow			// don't compare directly - there are rounding errors
653ffec4cb1Sshadow			if( fabs(format->u.raw_video.field_rate - frame_rate) > 0.001 ) {
654ffec4cb1Sshadow				DPRINT(( "Wrong field rate for active TV standard (%f) in progressive mode (expected %f)\n",
655ffec4cb1Sshadow					format->u.raw_video.field_rate - 29.976,
656ffec4cb1Sshadow					frame_rate - 29.976 ));
657ffec4cb1Sshadow				return B_MEDIA_BAD_FORMAT;
658ffec4cb1Sshadow			}
659ffec4cb1Sshadow		}
660ffec4cb1Sshadow
661ffec4cb1Sshadow	} else if( format->u.raw_video.interlace == 2 ) {
662ffec4cb1Sshadow		if( format->u.raw_video.field_rate == media_raw_video_format::wildcard.field_rate )
663ffec4cb1Sshadow			format->u.raw_video.field_rate = frame_rate * 2;
664ffec4cb1Sshadow		else {
665ffec4cb1Sshadow			if( fabs(format->u.raw_video.field_rate - frame_rate * 2) > 0.001 ) {
666ffec4cb1Sshadow				DPRINT(( "Wrong field rate for active TV standard (%f) in interlace mode\n",
667ffec4cb1Sshadow					format->u.raw_video.field_rate ));
668ffec4cb1Sshadow				return B_MEDIA_BAD_FORMAT;
669ffec4cb1Sshadow			}
670ffec4cb1Sshadow		}
671ffec4cb1Sshadow
672ffec4cb1Sshadow	} else {
673ffec4cb1Sshadow		DPRINT(( "Invalid interlace mode (%d)\n", format->u.raw_video.interlace ));
674ffec4cb1Sshadow		return B_MEDIA_BAD_FORMAT;
675ffec4cb1Sshadow	}
676ffec4cb1Sshadow
677ffec4cb1Sshadow	return B_OK;
678ffec4cb1Sshadow}
679ffec4cb1Sshadow
680ffec4cb1Sshadow/*
681ffec4cb1Sshadow	Map BeOS capture mode to internal capture mode.
682ffec4cb1Sshadow*/
683ffec4cb1Sshadowint32
684ffec4cb1SshadowCRadeonProducer::extractCaptureMode( const media_format *format )
685ffec4cb1Sshadow{
686ffec4cb1Sshadow	// if application requests interlace, it always gets BOB;
687ffec4cb1Sshadow	// if is requests non-interlace, it may get WEAVE or FIELD -
688ffec4cb1Sshadow	// if the user selected one of them, we are fine; else,
689ffec4cb1Sshadow	// we always choose WEAVE (could choose FIELD as well, make
690ffec4cb1Sshadow	// it dependant on resolution, but the more magic the more problems)
691ffec4cb1Sshadow	if( format->u.raw_video.interlace == 2 )
692ffec4cb1Sshadow		return C_VIDEO_IN_BOB;
693ffec4cb1Sshadow	else if( fMode == C_VIDEO_IN_BOB )
694ffec4cb1Sshadow		return C_VIDEO_IN_WEAVE;
695ffec4cb1Sshadow	else
696ffec4cb1Sshadow		return fMode;
697ffec4cb1Sshadow}
698ffec4cb1Sshadow
699ffec4cb1Sshadow// check pixel aspect of format and set it if it's wildcarded
700ffec4cb1Sshadowstatus_t
701ffec4cb1SshadowCRadeonProducer::verifySetPixelAspect( media_format *format )
702ffec4cb1Sshadow{
703ffec4cb1Sshadow	// for simplicity, we always assume 1:1 aspect
704ffec4cb1Sshadow	if( format->u.raw_video.pixel_width_aspect != media_raw_video_format::wildcard.pixel_width_aspect ||
705ffec4cb1Sshadow		format->u.raw_video.pixel_height_aspect != media_raw_video_format::wildcard.pixel_height_aspect )
706ffec4cb1Sshadow	{
707ffec4cb1Sshadow		if( format->u.raw_video.pixel_width_aspect !=
708ffec4cb1Sshadow			format->u.raw_video.pixel_height_aspect )
709ffec4cb1Sshadow		{
710ffec4cb1Sshadow			DPRINT(( "Unsupported pixel aspect (%d:%d)\n",
711ffec4cb1Sshadow				format->u.raw_video.pixel_width_aspect,
712ffec4cb1Sshadow				format->u.raw_video.pixel_height_aspect ));
713ffec4cb1Sshadow			return B_MEDIA_BAD_FORMAT;
714ffec4cb1Sshadow		}
715ffec4cb1Sshadow	} else {
716ffec4cb1Sshadow		format->u.raw_video.pixel_width_aspect = 1;
717ffec4cb1Sshadow		format->u.raw_video.pixel_height_aspect = 1;
718ffec4cb1Sshadow	}
719ffec4cb1Sshadow
720ffec4cb1Sshadow	return B_OK;
721ffec4cb1Sshadow
722ffec4cb1Sshadow#if 0
723ffec4cb1Sshadow	// we assume 1:2 for interlaced and 1:1 for deinterlaced video
724ffec4cb1Sshadow	// (this is not really true as it depends on TV standard and
725ffec4cb1Sshadow	// resolution, but it should be enough for start)
726ffec4cb1Sshadow	if( format->u.raw_video.pixel_width_aspect != media_raw_video_format::wildcard.pixel_width_aspect ||
727ffec4cb1Sshadow		format->u.raw_video.pixel_height_aspect != media_raw_video_format::wildcard.pixel_height_aspect )
728ffec4cb1Sshadow	{
729ffec4cb1Sshadow		double ratio = mode == C_VIDEO_IN_WEAVE ? 1 : 0.5;
730ffec4cb1Sshadow
731ffec4cb1Sshadow		if( (float)format->u.raw_video.pixel_width_aspect /
732ffec4cb1Sshadow			format->u.raw_video.pixel_height_aspect != ratio )
733ffec4cb1Sshadow		{
734ffec4cb1Sshadow			DPRINT(( "Unsupported pixel aspect (%d:%d)\n",
735ffec4cb1Sshadow				format->u.raw_video.pixel_width_aspect,
736ffec4cb1Sshadow				format->u.raw_video.pixel_height_aspect ));
737ffec4cb1Sshadow			return B_MEDIA_BAD_FORMAT;
738ffec4cb1Sshadow		}
739ffec4cb1Sshadow	} else {
740ffec4cb1Sshadow		format->u.raw_video.pixel_width_aspect = 1;
741ffec4cb1Sshadow		format->u.raw_video.pixel_height_aspect =
742ffec4cb1Sshadow			mode == C_VIDEO_IN_WEAVE ? 1 : 2;
743ffec4cb1Sshadow	}
744ffec4cb1Sshadow
745ffec4cb1Sshadow	return B_OK;
746ffec4cb1Sshadow#endif
747ffec4cb1Sshadow}
748ffec4cb1Sshadow
749ffec4cb1Sshadow// verify active range defined as format
750ffec4cb1Sshadowstatus_t
751ffec4cb1SshadowCRadeonProducer::verifyActiveRange( media_format *format )
752ffec4cb1Sshadow{
753ffec4cb1Sshadow	CRadeonRect active_rect;
754ffec4cb1Sshadow
755ffec4cb1Sshadow	fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
756ffec4cb1Sshadow
757ffec4cb1Sshadow	if( format->u.raw_video.first_active != media_raw_video_format::wildcard.first_active ) {
758ffec4cb1Sshadow		if( (int32)format->u.raw_video.first_active < 0 ) {
759ffec4cb1Sshadow			DPRINT(( "Unsupported first_active (%d)\n", format->u.raw_video.first_active ));
760ffec4cb1Sshadow			return B_MEDIA_BAD_FORMAT;
761ffec4cb1Sshadow		}
762ffec4cb1Sshadow	}
763ffec4cb1Sshadow
764ffec4cb1Sshadow	// don't care about last_active much - some programs set it to number of
765ffec4cb1Sshadow	// captured lines, which is really something different
766ffec4cb1Sshadow	// (I have the feeling, noone really knows how to use this value properly)
767ffec4cb1Sshadow	if( format->u.raw_video.last_active != media_raw_video_format::wildcard.last_active ) {
768ffec4cb1Sshadow		if( format->u.raw_video.last_active >= (uint32)active_rect.Height() ) {
769ffec4cb1Sshadow			DPRINT(( "Unsupported last_active (%d)\n", format->u.raw_video.last_active ));
770ffec4cb1Sshadow			return B_MEDIA_BAD_FORMAT;
771ffec4cb1Sshadow		}
772ffec4cb1Sshadow	}
773ffec4cb1Sshadow
774ffec4cb1Sshadow	return B_OK;
775ffec4cb1Sshadow}
776ffec4cb1Sshadow
777ffec4cb1Sshadow
778ffec4cb1Sshadow// set active range in format if yet undefined
779ffec4cb1Sshadowvoid
780ffec4cb1SshadowCRadeonProducer::setActiveRange( media_format *format )
781ffec4cb1Sshadow{
782ffec4cb1Sshadow	CRadeonRect active_rect;
783ffec4cb1Sshadow
784ffec4cb1Sshadow	fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
785ffec4cb1Sshadow
786ffec4cb1Sshadow	if( format->u.raw_video.first_active == media_raw_video_format::wildcard.first_active )
787ffec4cb1Sshadow		format->u.raw_video.first_active = 0;
788ffec4cb1Sshadow
789ffec4cb1Sshadow	if( format->u.raw_video.last_active == media_raw_video_format::wildcard.last_active )
790ffec4cb1Sshadow		format->u.raw_video.last_active = (uint32)active_rect.Height() - 1;
791ffec4cb1Sshadow}
792ffec4cb1Sshadow
793ffec4cb1Sshadow
794ffec4cb1Sshadow// verify requested orientation
795ffec4cb1Sshadowstatus_t
796ffec4cb1SshadowCRadeonProducer::verifyOrientation( media_format *format )
797ffec4cb1Sshadow{
798ffec4cb1Sshadow	if( format->u.raw_video.orientation != media_raw_video_format::wildcard.orientation ) {
799ffec4cb1Sshadow		if( format->u.raw_video.orientation != B_VIDEO_TOP_LEFT_RIGHT ) {
800ffec4cb1Sshadow			DPRINT(( "Unsupported orientation (%d)\n", format->u.raw_video.orientation ));
801ffec4cb1Sshadow			return B_MEDIA_BAD_FORMAT;
802ffec4cb1Sshadow		}
803ffec4cb1Sshadow	}
804ffec4cb1Sshadow
805ffec4cb1Sshadow	return B_OK;
806ffec4cb1Sshadow}
807ffec4cb1Sshadow
808ffec4cb1Sshadow
809ffec4cb1Sshadow// set image orientation if yet undefined
810ffec4cb1Sshadowvoid
811ffec4cb1SshadowCRadeonProducer::setOrientation( media_format *format )
812ffec4cb1Sshadow{
813ffec4cb1Sshadow	if( format->u.raw_video.orientation == media_raw_video_format::wildcard.orientation )
814ffec4cb1Sshadow		format->u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
815ffec4cb1Sshadow}
816ffec4cb1Sshadow
817ffec4cb1Sshadow
818ffec4cb1Sshadow// verify requested pixel format
819ffec4cb1Sshadowstatus_t
820ffec4cb1SshadowCRadeonProducer::verifyPixelFormat( media_format *format )
821ffec4cb1Sshadow{
822ffec4cb1Sshadow	if(	format->u.raw_video.display.format !=
823ffec4cb1Sshadow		media_raw_video_format::wildcard.display.format )
824ffec4cb1Sshadow	{
825ffec4cb1Sshadow		switch( format->u.raw_video.display.format ) {
826ffec4cb1Sshadow		case B_RGB32:
827ffec4cb1Sshadow		case B_RGB16:
828ffec4cb1Sshadow		case B_RGB15:
829ffec4cb1Sshadow		case B_YCbCr422:
830ffec4cb1Sshadow		case B_GRAY8:
831ffec4cb1Sshadow			break;
832ffec4cb1Sshadow
833ffec4cb1Sshadow		default:
834ffec4cb1Sshadow			DPRINT(("Unsupported colour space (%x)\n",
835ffec4cb1Sshadow				format->u.raw_video.display.format ));
836ffec4cb1Sshadow			return B_MEDIA_BAD_FORMAT;
837ffec4cb1Sshadow		}
838ffec4cb1Sshadow	}
839ffec4cb1Sshadow
840ffec4cb1Sshadow	return B_OK;
841ffec4cb1Sshadow}
842ffec4cb1Sshadow
843ffec4cb1Sshadow
844ffec4cb1Sshadow// set pixel format to user-defined default if not set yet
845ffec4cb1Sshadowvoid
846ffec4cb1SshadowCRadeonProducer::setPixelFormat( media_format *format )
847ffec4cb1Sshadow{
848ffec4cb1Sshadow	if(	format->u.raw_video.display.format ==
849ffec4cb1Sshadow		media_raw_video_format::wildcard.display.format )
850ffec4cb1Sshadow		format->u.raw_video.display.format = (color_space)fFormat;
851ffec4cb1Sshadow}
852ffec4cb1Sshadow
853ffec4cb1Sshadow/*
854ffec4cb1Sshadow	Verify video size and set it if undefined.
855ffec4cb1Sshadow*/
856ffec4cb1Sshadowstatus_t
857ffec4cb1SshadowCRadeonProducer::verifySetSize(
858ffec4cb1Sshadow	media_format *format, int32 mode, bool set_bytes_per_row )
859ffec4cb1Sshadow{
860ffec4cb1Sshadow	CRadeonRect active_rect;
861ffec4cb1Sshadow
862ffec4cb1Sshadow	fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
863ffec4cb1Sshadow
864ffec4cb1Sshadow	// width and height must both be defined, else we define it ourself,
865ffec4cb1Sshadow	// i.e. if the application leaves one of them wildcarded, we
866ffec4cb1Sshadow	// set both
867ffec4cb1Sshadow	if( format->u.raw_video.display.line_width !=
868ffec4cb1Sshadow		media_raw_video_format::wildcard.display.line_width &&
869ffec4cb1Sshadow		format->u.raw_video.display.line_count !=
870ffec4cb1Sshadow		media_raw_video_format::wildcard.display.line_count )
871ffec4cb1Sshadow	{
872ffec4cb1Sshadow		uint32 max_height = active_rect.Height();
873ffec4cb1Sshadow
874ffec4cb1Sshadow		if( mode != C_VIDEO_IN_WEAVE )
875ffec4cb1Sshadow			max_height /= 2;
876ffec4cb1Sshadow
877ffec4cb1Sshadow		if( format->u.raw_video.display.line_width > (uint32)active_rect.Width() ||
878ffec4cb1Sshadow			format->u.raw_video.display.line_count > max_height )
879ffec4cb1Sshadow		{
880