1b3d94504SStephan Aßmus/*
2b3d94504SStephan Aßmus * This file is a part of BeOS USBVision driver project.
3b3d94504SStephan Aßmus * Copyright (c) 2003 by Siarzuk Zharski <imker@gmx.li>
4b3d94504SStephan Aßmus *
5b3d94504SStephan Aßmus * This file may be used under the terms of the BSD License
6b3d94504SStephan Aßmus *
7b3d94504SStephan Aßmus * Skeletal part of this code was inherired from original BeOS sample code,
8b3d94504SStephan Aßmus * that is distributed under the terms of the Be Sample Code License.
9b3d94504SStephan Aßmus *
10b3d94504SStephan Aßmus */
11b3d94504SStephan Aßmus
12b3d94504SStephan Aßmus#include <fcntl.h>
13b3d94504SStephan Aßmus#include <malloc.h>
14b3d94504SStephan Aßmus#include <math.h>
15b3d94504SStephan Aßmus#include <stdio.h>
16b3d94504SStephan Aßmus#include <string.h>
17b3d94504SStephan Aßmus#include <sys/uio.h>
18b3d94504SStephan Aßmus#include <unistd.h>
19b3d94504SStephan Aßmus
20b3d94504SStephan Aßmus#include <media/Buffer.h>
21b3d94504SStephan Aßmus#include <media/BufferGroup.h>
22b3d94504SStephan Aßmus#include <media/ParameterWeb.h>
23b3d94504SStephan Aßmus#include <media/TimeSource.h>
24b3d94504SStephan Aßmus
25b3d94504SStephan Aßmus#include <support/Autolock.h>
26b3d94504SStephan Aßmus#include <support/Debug.h>
27b3d94504SStephan Aßmus
28b3d94504SStephan Aßmus#define TOUCH(x) ((void)(x))
29b3d94504SStephan Aßmus
30b3d94504SStephan Aßmus#define PRINTF(a,b) \
31b3d94504SStephan Aßmus		do { \
32b3d94504SStephan Aßmus			if (a < 2) { \
33b3d94504SStephan Aßmus				printf("VideoProducer::"); \
34b3d94504SStephan Aßmus				printf b; \
35b3d94504SStephan Aßmus			} \
36b3d94504SStephan Aßmus		} while (0)
37b3d94504SStephan Aßmus
38b3d94504SStephan Aßmus#include "Producer.h"
39b3d94504SStephan Aßmus
40b3d94504SStephan Aßmus#define FIELD_RATE 30.f
41b3d94504SStephan Aßmus
42b3d94504SStephan Aßmusconst float kUSBBandWidthMin = 0.5f;
43b3d94504SStephan Aßmusconst float kUSBBandWidthMax = 7.5f;
44b3d94504SStephan Aßmusconst float kUSBBandWidthStep = 0.5f;
45b3d94504SStephan Aßmus
46b3d94504SStephan Aßmusconst float kVScreenOffsetMin = 0.f;
47b3d94504SStephan Aßmusconst float kVScreenOffsetMax = 4.f;
48b3d94504SStephan Aßmusconst float kVScreenOffsetStep = 1.f;
49b3d94504SStephan Aßmusconst float kHScreenOffsetMin = 0.f;
50b3d94504SStephan Aßmusconst float kHScreenOffsetMax = 4.f;
51b3d94504SStephan Aßmusconst float kHScreenOffsetStep = 1.f;
52b3d94504SStephan Aßmus
53b3d94504SStephan Aßmusconst float kEffectMin = 0.f;
54b3d94504SStephan Aßmusconst float kEffectMax = 31.f;
55b3d94504SStephan Aßmusconst float kEffectStep = 1.f;
56b3d94504SStephan Aßmus
57b3d94504SStephan Aßmusconst float kBrightnessMin = kEffectMin;
58b3d94504SStephan Aßmusconst float kBrightnessMax = kEffectMax;
59b3d94504SStephan Aßmusconst float kBrightnessStep = kEffectStep;
60b3d94504SStephan Aßmus
61b3d94504SStephan Aßmusconst float kContrastMin = kEffectMin;
62b3d94504SStephan Aßmusconst float kContrastMax = kEffectMax;
63b3d94504SStephan Aßmusconst float kContrastStep = kEffectStep;
64b3d94504SStephan Aßmus
65b3d94504SStephan Aßmusconst float kHueMin = kEffectMin;
66b3d94504SStephan Aßmusconst float kHueMax = kEffectMax;
67b3d94504SStephan Aßmusconst float kHueStep = kEffectStep;
68b3d94504SStephan Aßmus
69b3d94504SStephan Aßmusconst float kSaturationMin = kEffectMin;
70b3d94504SStephan Aßmusconst float kSaturationMax = kEffectMax;
71b3d94504SStephan Aßmusconst float kSaturationStep = kEffectStep;
72b3d94504SStephan Aßmus
73b3d94504SStephan Aßmusconst uint32        kDefChannel = 0;
74b3d94504SStephan Aßmus//const VideoInput    kDefVideoInput = P_VI_TUNER;
75b3d94504SStephan Aßmusconst uint32        kDefAudioInput = 0;
76b3d94504SStephan Aßmusconst uint32        kDefBrightness = 20;
77b3d94504SStephan Aßmusconst uint32        kDefContrast = 22;
78b3d94504SStephan Aßmusconst uint32        kDefSaturation = 15;
79b3d94504SStephan Aßmusconst uint32        kDefHue = 20;
80b3d94504SStephan Aßmusconst uint32        kDefCaptureSize = 0;
81b3d94504SStephan Aßmusconst uint32        kDefCaptureFormat = 0;
82b3d94504SStephan Aßmus//const VideoStandard kDefStandard = P_VF_PAL_BDGHI;
83b3d94504SStephan Aßmusconst float         kDefBandwidth = 7.0;
84b3d94504SStephan Aßmusconst uint32        kDefLocale = 0;
85b3d94504SStephan Aßmusconst uint32        kDefVertOffset = 1;
86b3d94504SStephan Aßmusconst uint32        kDefHorzOffset = 2;
87b3d94504SStephan Aßmus
88b3d94504SStephan Aßmusint32 VideoProducer::fInstances = 0;
89b3d94504SStephan Aßmus
90b3d94504SStephan AßmusVideoProducer::VideoProducer(
91b3d94504SStephan Aßmus		BMediaAddOn *addon, const char *name, int32 internal_id)
92b3d94504SStephan Aßmus  :	BMediaNode(name),
93b3d94504SStephan Aßmus	BMediaEventLooper(),
94b3d94504SStephan Aßmus	BBufferProducer(B_MEDIA_RAW_VIDEO),
95b3d94504SStephan Aßmus	BControllable()
96b3d94504SStephan Aßmus{
97b3d94504SStephan Aßmus	status_t err;
98b3d94504SStephan Aßmus
99b3d94504SStephan Aßmus	fInitStatus = B_NO_INIT;
100b3d94504SStephan Aßmus
101b3d94504SStephan Aßmus	/* Only allow one instance of the node to exist at any time */
102b3d94504SStephan Aßmus	if (atomic_add(&fInstances, 1) != 0)
103b3d94504SStephan Aßmus		return;
104b3d94504SStephan Aßmus
105b3d94504SStephan Aßmus	fInternalID = internal_id;
106b3d94504SStephan Aßmus	fAddOn = addon;
107b3d94504SStephan Aßmus
108b3d94504SStephan Aßmus	fBufferGroup = NULL;
109b3d94504SStephan Aßmus
110b3d94504SStephan Aßmus	fThread = -1;
111b3d94504SStephan Aßmus	fFrameSync = -1;
112b3d94504SStephan Aßmus	fProcessingLatency = 0LL;
113b3d94504SStephan Aßmus
114b3d94504SStephan Aßmus	fRunning = false;
115b3d94504SStephan Aßmus	fConnected = false;
116b3d94504SStephan Aßmus	fEnabled = false;
117b3d94504SStephan Aßmus
118b3d94504SStephan Aßmus	fOutput.destination = media_destination::null;
119b3d94504SStephan Aßmus
120b3d94504SStephan Aßmus	AddNodeKind(B_PHYSICAL_INPUT);
121b3d94504SStephan Aßmus
122b3d94504SStephan Aßmus	fInitStatus = B_OK;
123b3d94504SStephan Aßmus
124b3d94504SStephan Aßmus    //debugger("op-op");
125b3d94504SStephan Aßmus
126b3d94504SStephan Aßmus    status_t status = Locale::TunerLocale::LoadLocales(fLocales);
127b3d94504SStephan Aßmus
128b3d94504SStephan Aßmus    printf("LoadLocales:%08x\n", status);
129b3d94504SStephan Aßmus
130b3d94504SStephan Aßmus	fChannel = kDefChannel;
131b3d94504SStephan Aßmus    fVideoInput = P_VI_TUNER;
132b3d94504SStephan Aßmus	fAudioInput = kDefAudioInput;
133b3d94504SStephan Aßmus    fBrightness = kDefBrightness;
134b3d94504SStephan Aßmus	fContrast = kDefContrast;
135b3d94504SStephan Aßmus	fSaturation = kDefSaturation;
136b3d94504SStephan Aßmus	fHue = kDefHue;
137b3d94504SStephan Aßmus    fCaptureSize = kDefCaptureSize;
138b3d94504SStephan Aßmus    fCaptureFormat = kDefCaptureFormat;
139b3d94504SStephan Aßmus    fStandard = P_VF_PAL_BDGHI;
140b3d94504SStephan Aßmus	fLocale = kDefLocale;
141b3d94504SStephan Aßmus    fBandwidth = kDefBandwidth;
142b3d94504SStephan Aßmus    fVertOffset = kDefVertOffset;
143b3d94504SStephan Aßmus	fHorzOffset = kDefHorzOffset;
144b3d94504SStephan Aßmus    fColor = B_HOST_TO_LENDIAN_INT32(0x00ff0000);
145b3d94504SStephan Aßmus
146b3d94504SStephan Aßmus	fLastChannelChange =
147b3d94504SStephan Aßmus	fLastVideoInputChange =
148b3d94504SStephan Aßmus	fLastAudioInputChange =
149b3d94504SStephan Aßmus	fLastBrightnessChange =
150b3d94504SStephan Aßmus	fLastContrastChange =
151b3d94504SStephan Aßmus	fLastSaturationChange =
152b3d94504SStephan Aßmus	fLastHueChange =
153b3d94504SStephan Aßmus	fLastCaptureSizeChange =
154b3d94504SStephan Aßmus	fLastCaptureFormatChange =
155b3d94504SStephan Aßmus	fLastStandardChange =
156b3d94504SStephan Aßmus	fLastLocaleChange =
157b3d94504SStephan Aßmus	fLastBandwidthChange =
158b3d94504SStephan Aßmus	fLastVertOffsetChange =
159b3d94504SStephan Aßmus	fLastHorzOffsetChange =
160b3d94504SStephan Aßmus	fLastColorChange = system_time();
161b3d94504SStephan Aßmus
162b3d94504SStephan Aßmus	return;
163b3d94504SStephan Aßmus}
164b3d94504SStephan Aßmus
165b3d94504SStephan AßmusVideoProducer::~VideoProducer()
166b3d94504SStephan Aßmus{
167b3d94504SStephan Aßmus	if (fInitStatus == B_OK) {
168b3d94504SStephan Aßmus		/* Clean up after ourselves, in case the application didn't make us
169b3d94504SStephan Aßmus		 * do so. */
170b3d94504SStephan Aßmus		if (fConnected)
171b3d94504SStephan Aßmus			Disconnect(fOutput.source, fOutput.destination);
172b3d94504SStephan Aßmus		if (fRunning)
173b3d94504SStephan Aßmus			HandleStop();
174b3d94504SStephan Aßmus	}
175b3d94504SStephan Aßmus
176b3d94504SStephan Aßmus	atomic_add(&fInstances, -1);
177b3d94504SStephan Aßmus
178b3d94504SStephan Aßmus    Locale::TunerLocale::ReleaseLocales(fLocales);
179b3d94504SStephan Aßmus}
180b3d94504SStephan Aßmus
181b3d94504SStephan Aßmus/* BMediaNode */
182b3d94504SStephan Aßmus
183b3d94504SStephan Aßmusport_id
184b3d94504SStephan AßmusVideoProducer::ControlPort() const
185b3d94504SStephan Aßmus{
186b3d94504SStephan Aßmus	return BMediaNode::ControlPort();
187b3d94504SStephan Aßmus}
188b3d94504SStephan Aßmus
189b3d94504SStephan AßmusBMediaAddOn *
190b3d94504SStephan AßmusVideoProducer::AddOn(int32 *internal_id) const
191b3d94504SStephan Aßmus{
192b3d94504SStephan Aßmus	if (internal_id)
193b3d94504SStephan Aßmus		*internal_id = fInternalID;
194b3d94504SStephan Aßmus	return fAddOn;
195b3d94504SStephan Aßmus}
196b3d94504SStephan Aßmus
197b3d94504SStephan Aßmusstatus_t
198b3d94504SStephan AßmusVideoProducer::HandleMessage(int32 message, const void *data, size_t size)
199b3d94504SStephan Aßmus{
200b3d94504SStephan Aßmus	return B_ERROR;
201b3d94504SStephan Aßmus}
202b3d94504SStephan Aßmus
203b3d94504SStephan Aßmusvoid
204b3d94504SStephan AßmusVideoProducer::Preroll()
205b3d94504SStephan Aßmus{
206b3d94504SStephan Aßmus	/* This hook may be called before the node is started to give the hardware
207b3d94504SStephan Aßmus	 * a chance to start. */
208b3d94504SStephan Aßmus}
209b3d94504SStephan Aßmus
210b3d94504SStephan Aßmusvoid
211b3d94504SStephan AßmusVideoProducer::SetTimeSource(BTimeSource *time_source)
212b3d94504SStephan Aßmus{
213b3d94504SStephan Aßmus	/* Tell frame generation thread to recalculate delay value */
214b3d94504SStephan Aßmus	release_sem(fFrameSync);
215b3d94504SStephan Aßmus}
216b3d94504SStephan Aßmus
217b3d94504SStephan Aßmusstatus_t
218b3d94504SStephan AßmusVideoProducer::RequestCompleted(const media_request_info &info)
219b3d94504SStephan Aßmus{
220b3d94504SStephan Aßmus	return BMediaNode::RequestCompleted(info);
221b3d94504SStephan Aßmus}
222b3d94504SStephan Aßmus
223b3d94504SStephan Aßmus/* BMediaEventLooper */
224b3d94504SStephan Aßmus
225b3d94504SStephan Aßmusvoid
226b3d94504SStephan AßmusVideoProducer::NodeRegistered()
227b3d94504SStephan Aßmus{
228b3d94504SStephan Aßmus	if (fInitStatus != B_OK) {
229b3d94504SStephan Aßmus		ReportError(B_NODE_IN_DISTRESS);
230b3d94504SStephan Aßmus		return;
231b3d94504SStephan Aßmus	}
232b3d94504SStephan Aßmus
233b3d94504SStephan Aßmus	/* After this call, the BControllable owns the BParameterWeb object and
234b3d94504SStephan Aßmus	 * will delete it for you */
235b3d94504SStephan Aßmus	SetParameterWeb(CreateParameterWeb());
236b3d94504SStephan Aßmus
237b3d94504SStephan Aßmus	fOutput.node = Node();
238b3d94504SStephan Aßmus	fOutput.source.port = ControlPort();
239b3d94504SStephan Aßmus	fOutput.source.id = 0;
240b3d94504SStephan Aßmus	fOutput.destination = media_destination::null;
241b3d94504SStephan Aßmus	strcpy(fOutput.name, Name());
242b3d94504SStephan Aßmus
243b3d94504SStephan Aßmus	/* Tailor these for the output of your device */
244b3d94504SStephan Aßmus	fOutput.format.type = B_MEDIA_RAW_VIDEO;
245b3d94504SStephan Aßmus	fOutput.format.u.raw_video = media_raw_video_format::wildcard;
246b3d94504SStephan Aßmus	fOutput.format.u.raw_video.interlace = 1;
247b3d94504SStephan Aßmus	fOutput.format.u.raw_video.display.format = B_RGB32;
248b3d94504SStephan Aßmus
249b3d94504SStephan Aßmus	/* Start the BMediaEventLooper control loop running */
250