1a1830cbdSFrançois Revol/*
2a1830cbdSFrançois Revol * Copyright 2004-2008, Fran��ois Revol, <revol@free.fr>.
3a1830cbdSFrançois Revol * Distributed under the terms of the MIT License.
4a1830cbdSFrançois Revol */
5a1830cbdSFrançois Revol
62c9bd703SFrançois Revol#include <fcntl.h>
72c9bd703SFrançois Revol#include <malloc.h>
82c9bd703SFrançois Revol#include <math.h>
92c9bd703SFrançois Revol#include <stdio.h>
102c9bd703SFrançois Revol#include <string.h>
112c9bd703SFrançois Revol#include <sys/uio.h>
122c9bd703SFrançois Revol#include <unistd.h>
132c9bd703SFrançois Revol
142c9bd703SFrançois Revol#include <media/Buffer.h>
152c9bd703SFrançois Revol#include <media/BufferGroup.h>
162c9bd703SFrançois Revol#include <media/ParameterWeb.h>
172c9bd703SFrançois Revol#include <media/TimeSource.h>
182c9bd703SFrançois Revol
192c9bd703SFrançois Revol#include <support/Autolock.h>
202c9bd703SFrançois Revol#include <support/Debug.h>
212c9bd703SFrançois Revol
222c9bd703SFrançois Revol//XXX: change interface
232c9bd703SFrançois Revol#include <interface/Bitmap.h>
242c9bd703SFrançois Revol
252c9bd703SFrançois Revol#include "CamDevice.h"
26a486abdcSFrançois Revol#include "CamSensor.h"
272c9bd703SFrançois Revol
280866ac7eSFrançois Revol// don't separate parameters from addon, device and sensor
290866ac7eSFrançois Revol#define SINGLE_PARAMETER_GROUP 1
300866ac7eSFrançois Revol
310866ac7eSFrançois Revol// CodyCam and eXposer prefer 320x240
322c4e929fSFrançois Revol#define FORCE_320_240 1
330866ac7eSFrançois Revol//#define FORCE_160_120 1
340866ac7eSFrançois Revol//#define FORCE_MAX_FRAME 1
350866ac7eSFrançois Revol
362c9bd703SFrançois Revol#define TOUCH(x) ((void)(x))
372c9bd703SFrançois Revol
382c9bd703SFrançois Revol#define PRINTF(a,b) \
392c9bd703SFrançois Revol		do { \
402c9bd703SFrançois Revol			if (a < 2) { \
412c9bd703SFrançois Revol				printf("VideoProducer::"); \
422c9bd703SFrançois Revol				printf b; \
432c9bd703SFrançois Revol			} \
442c9bd703SFrançois Revol		} while (0)
452c9bd703SFrançois Revol
462c9bd703SFrançois Revol#include "Producer.h"
472c9bd703SFrançois Revol
480866ac7eSFrançois Revol//#define FIELD_RATE 30.f
490866ac7eSFrançois Revol//#define FIELD_RATE 29.97f
500866ac7eSFrançois Revol#define FIELD_RATE 5.f
512c9bd703SFrançois Revol
5202af02f9SJérôme Duval
532c9bd703SFrançois Revolint32 VideoProducer::fInstances = 0;
542c9bd703SFrançois Revol
5502af02f9SJérôme Duval
562c9bd703SFrançois RevolVideoProducer::VideoProducer(
572c9bd703SFrançois Revol		BMediaAddOn *addon, CamDevice *dev, const char *name, int32 internal_id)
5802af02f9SJérôme Duval	: BMediaNode(name),
592c9bd703SFrançois Revol	BMediaEventLooper(),
602c9bd703SFrançois Revol	BBufferProducer(B_MEDIA_RAW_VIDEO),
612c9bd703SFrançois Revol	BControllable()
622c9bd703SFrançois Revol{
632c9bd703SFrançois Revol//	status_t err;
642c9bd703SFrançois Revol
652c9bd703SFrançois Revol	fInitStatus = B_NO_INIT;
662c9bd703SFrançois Revol
672c9bd703SFrançois Revol	/* Only allow one instance of the node to exist at any time */
682c9bd703SFrançois Revol	if (atomic_add(&fInstances, 1) != 0)
692c9bd703SFrançois Revol		return;
702c9bd703SFrançois Revol
712c9bd703SFrançois Revol	fInternalID = internal_id;
722c9bd703SFrançois Revol	fAddOn = addon;
732c9bd703SFrançois Revol	fCamDevice = dev;
742c9bd703SFrançois Revol
752c9bd703SFrançois Revol	fBufferGroup = NULL;
762c9bd703SFrançois Revol
772c9bd703SFrançois Revol	fThread = -1;
782c9bd703SFrançois Revol	fFrameSync = -1;
792c9bd703SFrançois Revol	fProcessingLatency = 0LL;
802c9bd703SFrançois Revol
812c9bd703SFrançois Revol	fRunning = false;
822c9bd703SFrançois Revol	fConnected = false;
832c9bd703SFrançois Revol	fEnabled = false;
842c9bd703SFrançois Revol
852c9bd703SFrançois Revol	fOutput.destination = media_destination::null;
862c9bd703SFrançois Revol
872c9bd703SFrançois Revol	AddNodeKind(B_PHYSICAL_INPUT);
882c9bd703SFrançois Revol
892c9bd703SFrançois Revol	fInitStatus = B_OK;
902c9bd703SFrançois Revol	return;
912c9bd703SFrançois Revol}
922c9bd703SFrançois Revol
9302af02f9SJérôme Duval
942c9bd703SFrançois RevolVideoProducer::~VideoProducer()
952c9bd703SFrançois Revol{
962c9bd703SFrançois Revol	if (fInitStatus == B_OK) {
972c9bd703SFrançois Revol		/* Clean up after ourselves, in case the application didn't make us
982c9bd703SFrançois Revol		 * do so. */
992c9bd703SFrançois Revol		if (fConnected)
1002c9bd703SFrançois Revol			Disconnect(fOutput.source, fOutput.destination);
1012c9bd703SFrançois Revol		if (fRunning)
1022c9bd703SFrançois Revol			HandleStop();
1032c9bd703SFrançois Revol	}
1042c9bd703SFrançois Revol
1052c9bd703SFrançois Revol	atomic_add(&fInstances, -1);
1062c9bd703SFrançois Revol}
1072c9bd703SFrançois Revol
1082c9bd703SFrançois Revol
10902af02f9SJérôme Duval/* BMediaNode */
1102c9bd703SFrançois Revolport_id
1112c9bd703SFrançois RevolVideoProducer::ControlPort() const
1122c9bd703SFrançois Revol{
1132c9bd703SFrançois Revol	return BMediaNode::ControlPort();
1142c9bd703SFrançois Revol}
1152c9bd703SFrançois Revol
11602af02f9SJérôme Duval
1172c9bd703SFrançois RevolBMediaAddOn *
1182c9bd703SFrançois RevolVideoProducer::AddOn(int32 *internal_id) const
1192c9bd703SFrançois Revol{
1202c9bd703SFrançois Revol	if (internal_id)
1212c9bd703SFrançois Revol		*internal_id = fInternalID;
1222c9bd703SFrançois Revol	return fAddOn;
1232c9bd703SFrançois Revol}
1242c9bd703SFrançois Revol
12502af02f9SJérôme Duval
12602af02f9SJérôme Duvalstatus_t
1272c9bd703SFrançois RevolVideoProducer::HandleMessage(int32 /*message*/, const void* /*data*/, size_t /*size*/)
1282c9bd703SFrançois Revol{
1292c9bd703SFrançois Revol	return B_ERROR;
1302c9bd703SFrançois Revol}
1312c9bd703SFrançois Revol
13202af02f9SJérôme Duval
13302af02f9SJérôme Duvalvoid
1342c9bd703SFrançois RevolVideoProducer::Preroll()
1352c9bd703SFrançois Revol{
1362c9bd703SFrançois Revol	/* This hook may be called before the node is started to give the hardware
1372c9bd703SFrançois Revol	 * a chance to start. */
1382c9bd703SFrançois Revol}
1392c9bd703SFrançois Revol
14002af02f9SJérôme Duval
1412c9bd703SFrançois Revolvoid
1422c9bd703SFrançois RevolVideoProducer::SetTimeSource(BTimeSource* /*time_source*/)
1432c9bd703SFrançois Revol{
1442c9bd703SFrançois Revol	/* Tell frame generation thread to recalculate delay value */
1452c9bd703SFrançois Revol	release_sem(fFrameSync);
1462c9bd703SFrançois Revol}
1472c9bd703SFrançois Revol
14802af02f9SJérôme Duval
1492c9bd703SFrançois Revolstatus_t
1502c9bd703SFrançois RevolVideoProducer::RequestCompleted(const media_request_info &info)
1512c9bd703SFrançois Revol{
1522c9bd703SFrançois Revol	return BMediaNode::RequestCompleted(info);
1532c9bd703SFrançois Revol}
1542c9bd703SFrançois Revol
15502af02f9SJérôme Duval
1562c9bd703SFrançois Revol/* BMediaEventLooper */
1572c9bd703SFrançois Revol
15802af02f9SJérôme Duval
15902af02f9SJérôme Duvalvoid
1602c9bd703SFrançois RevolVideoProducer::NodeRegistered()
1612c9bd703SFrançois Revol{
1622c9bd703SFrançois Revol	if (fInitStatus != B_OK) {
1632c9bd703SFrançois Revol		ReportError(B_NODE_IN_DISTRESS);
1642c9bd703SFrançois Revol		return;
1652c9bd703SFrançois Revol	}
1662c9bd703SFrançois Revol
1672c9bd703SFrançois Revol	/* Set up the parameter web */
16802af02f9SJérôme Duval
169a486abdcSFrançois Revol	//TODO: remove and put sensible stuff there
1702c9bd703SFrançois Revol	BParameterWeb *web = new BParameterWeb();
1712c9bd703SFrançois Revol	BParameterGroup *main = web->MakeGroup(Name());
1720866ac7eSFrançois Revol	BParameterGroup *g;
1730866ac7eSFrançois Revol
1740866ac7eSFrançois Revol	/*
1750866ac7eSFrançois Revol	g = main->MakeGroup("Color");
1760866ac7eSFrançois Revol	BDiscreteParameter *state = g->MakeDiscreteParameter(
1772c9bd703SFrançois Revol			P_COLOR, B_MEDIA_RAW_VIDEO, "Color", "Color");
1780866ac7eSFrançois Revol	state->AddItem(B_HOST_TO_LENDIAN_INT32(0x00ff0000), "Red");
1790866ac7eSFrançois Revol	state->AddItem(B_HOST_TO_LENDIAN_INT32(0x0000ff00), "Green");
1800866ac7eSFrançois Revol	state->AddItem(B_HOST_TO_LENDIAN_INT32(0x000000ff), "Blue");
1810866ac7eSFrançois Revol	*/
182a486abdcSFrançois Revol
1830866ac7eSFrançois Revol	BParameter *p;
1840866ac7eSFrançois Revol	g = main->MakeGroup("Info");
1850866ac7eSFrançois Revol	p = g->MakeTextParameter(
1860866ac7eSFrançois Revol		P_INFO, B_MEDIA_RAW_VIDEO, "", "Info", 256);
1870866ac7eSFrançois Revol
1880866ac7eSFrançois Revol	int32 id = P_LAST;
189a486abdcSFrançois Revol	if (fCamDevice) {
1900866ac7eSFrançois Revol#ifndef SINGLE_PARAMETER_GROUP
1910866ac7eSFrançois Revol		main = web->MakeGroup("Device");
1920866ac7eSFrançois Revol#endif
1930866ac7eSFrançois Revol		fCamDevice->AddParameters(main, id);
194a486abdcSFrançois Revol		if (fCamDevice->Sensor()) {
1950866ac7eSFrançois Revol#ifndef SINGLE_PARAMETER_GROUP
1960866ac7eSFrançois Revol			main = web->MakeGroup("Sensor");
1970866ac7eSFrançois Revol#endif
1980866ac7eSFrançois Revol			fCamDevice->Sensor()->AddParameters(main, id);
199a486abdcSFrançois Revol		}
200a486abdcSFrançois Revol	}
2012c9bd703SFrançois Revol
2022c9bd703SFrançois Revol	fColor = B_HOST_TO_LENDIAN_INT32(0x00ff0000);
2032c9bd703SFrançois Revol	fLastColorChange = system_time();
2042c9bd703SFrançois Revol
2052c9bd703SFrançois Revol	/* After this call, the BControllable owns the BParameterWeb object and
2062c9bd703SFrançois Revol	 * will delete it for you */
2072c9bd703SFrançois Revol	SetParameterWeb(web);
2082c9bd703SFrançois Revol
2092c9bd703SFrançois Revol	fOutput.node = Node();
2102c9bd703SFrançois Revol	fOutput.source.port = ControlPort();
2112c9bd703SFrançois Revol	fOutput.source.id = 0;
2122c9bd703SFrançois Revol	fOutput.destination = media_destination::null;
21302af02f9SJérôme Duval	strcpy(fOutput.name, Name());
2142c9bd703SFrançois Revol
2152c9bd703SFrançois Revol	/* Tailor these for the output of your device */
2162c9bd703SFrançois Revol	fOutput.format.type = B_MEDIA_RAW_VIDEO;
2172c9bd703SFrançois Revol	fOutput.format.u.raw_video = media_raw_video_format::wildcard;
2182c9bd703SFrançois Revol	fOutput.format.u.raw_video.interlace = 1;
2192c9bd703SFrançois Revol	fOutput.format.u.raw_video.display.format = B_RGB32;
2200866ac7eSFrançois Revol	fOutput.format.u.raw_video.field_rate = FIELD_RATE; // XXX: mmu
2212c9bd703SFrançois Revol
2222c9bd703SFrançois Revol	/* Start the BMediaEventLooper control loop running */
2232c9bd703SFrançois Revol	Run();
2242c9bd703SFrançois Revol}
2252c9bd703SFrançois Revol
22602af02f9SJérôme Duval
2272c9bd703SFrançois Revolvoid
2282c9bd703SFrançois RevolVideoProducer::Start(bigtime_t performance_time)
2292c9bd703SFrançois Revol{
2302c9bd703SFrançois Revol	BMediaEventLooper::Start(performance_time);
2312c9bd703SFrançois Revol}
2322c9bd703SFrançois Revol
23302af02f9SJérôme Duval
2342c9bd703SFrançois Revolvoid
2352c9bd703SFrançois RevolVideoProducer::Stop(bigtime_t performance_time, bool immediate)
2362c9bd703SFrançois Revol{
2372c9bd703SFrançois Revol	BMediaEventLooper::Stop(performance_time, immediate);
2382c9bd703SFrançois Revol}
2392c9bd703SFrançois Revol
24002af02f9SJérôme Duval
2412c9bd703SFrançois Revolvoid
2422c9bd703SFrançois RevolVideoProducer::Seek(bigtime_t media_time, bigtime_t performance_time)
2432c9bd703SFrançois Revol{
2442c9bd703SFrançois Revol	BMediaEventLooper::Seek(media_time, performance_time);
2452c9bd703SFrançois Revol}
2462c9bd703SFrançois Revol
24702af02f9SJérôme Duval
2482c9bd703SFrançois Revolvoid
2492c9bd703SFrançois RevolVideoProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
2502c9bd703SFrançois Revol{
2512c9bd703SFrançois Revol	BMediaEventLooper::TimeWarp(at_real_time, to_performance_time);
2522c9bd703SFrançois Revol}
2532c9bd703SFrançois Revol
25402af02f9SJérôme Duval
2552c9bd703SFrançois Revolstatus_t
2562c9bd703SFrançois RevolVideoProducer::AddTimer(bigtime_t at_performance_time, int32 cookie)
2572c9bd703SFrançois Revol{
2582c9bd703SFrançois Revol	return BMediaEventLooper::AddTimer(at_performance_time, cookie);
2592c9bd703SFrançois Revol}
2602c9bd703SFrançois Revol
26102af02f9SJérôme Duval
2622c9bd703SFrançois Revolvoid
2632c9bd703SFrançois RevolVideoProducer::SetRunMode(run_mode mode)
2642c9bd703SFrançois Revol{
2652c9bd703SFrançois Revol	BMediaEventLooper::SetRunMode(mode);
2662c9bd703SFrançois Revol}
2672c9bd703SFrançois Revol
26802af02f9SJérôme Duval
26902af02f9SJérôme Duvalvoid
2702c9bd703SFrançois RevolVideoProducer::HandleEvent(const media_timed_event *event,
2712c9bd703SFrançois Revol		bigtime_t lateness, bool realTimeEvent)
2722c9bd703SFrançois Revol{
2732c9bd703SFrançois Revol	TOUCH(lateness); TOUCH(realTimeEvent);
2742c9bd703SFrançois Revol
27502af02f9SJérôme Duval	switch(event->type) {
2762c9bd703SFrançois Revol		case BTimedEventQueue::B_START:
2772c9bd703SFrançois Revol			HandleStart(event->event_time);
2782c9bd703SFrançois Revol			break;
2792c9bd703SFrançois Revol		case BTimedEventQueue::B_STOP:
2802c9bd703SFrançois Revol			HandleStop();
2812c9bd703SFrançois Revol			break;
2822c9bd703SFrançois Revol		case BTimedEventQueue::B_WARP:
2832c9bd703SFrançois Revol			HandleTimeWarp(event->bigdata);
2842c9bd703SFrançois Revol			break;
2852c9bd703SFrançois Revol		case BTimedEventQueue::B_SEEK:
2862c9bd703SFrançois Revol			HandleSeek(event->bigdata);
2872c9bd703SFrançois Revol			break;
2882c9bd703SFrançois Revol		case BTimedEventQueue::B_HANDLE_BUFFER:
2892c9bd703SFrançois Revol		case BTimedEventQueue::B_DATA_STATUS:
2902c9bd703SFrançois Revol		case BTimedEventQueue::B_PARAMETER:
2912c9bd703SFrançois Revol		default:
292103e774dSMurai Takashi			PRINTF(-1, ("HandleEvent: Unhandled event -- %" B_PRIx32 "\n",
293103e774dSMurai Takashi				event->type));
2942c9bd703SFrançois Revol			break;
2952c9bd703SFrançois Revol	}
2962c9bd703SFrançois Revol}
2972c9bd703SFrançois Revol
29802af02f9SJérôme Duval
29902af02f9SJérôme Duvalvoid
3002c9bd703SFrançois RevolVideoProducer::CleanUpEvent(const media_timed_event *event)
3012c9bd703SFrançois Revol{
3022c9bd703SFrançois Revol	BMediaEventLooper::CleanUpEvent(event);
3032c9bd703SFrançois Revol}
3042c9bd703SFrançois Revol
30502af02f9SJérôme Duval
3062c9bd703SFrançois Revolbigtime_t
3072c9bd703SFrançois RevolVideoProducer::OfflineTime()
3082c9bd703SFrançois Revol{
3092c9bd703SFrançois Revol	return BMediaEventLooper::OfflineTime();
3102c9bd703SFrançois Revol}
3112c9bd703SFrançois Revol
31202af02f9SJérôme Duval
3132c9bd703SFrançois Revolvoid
3142c9bd703SFrançois RevolVideoProducer::ControlLoop()
3152c9bd703SFrançois Revol{
3162c9bd703SFrançois Revol	BMediaEventLooper::ControlLoop();
3172c9bd703SFrançois Revol}
3182c9bd703SFrançois Revol
31902af02f9SJérôme Duval
3202c9bd703SFrançois Revolstatus_t
3212c9bd703SFrançois RevolVideoProducer::DeleteHook(BMediaNode * node)
3222c9bd703SFrançois Revol{
3232c9bd703SFrançois Revol	return BMediaEventLooper::DeleteHook(node);
3242c9bd703SFrançois Revol}
3252c9bd703SFrançois Revol
32602af02f9SJérôme Duval
3272c9bd703SFrançois Revol/* BBufferProducer */
3282c9bd703SFrançois Revol
32902af02f9SJérôme Duval
33002af02f9SJérôme Duvalstatus_t
3312c9bd703SFrançois RevolVideoProducer::FormatSuggestionRequested(
3322c9bd703SFrançois Revol		media_type type, int32 quality, media_format *format)
3332c9bd703SFrançois Revol{
3342c9bd703SFrançois Revol	if (type != B_MEDIA_ENCODED_VIDEO)
3352c9bd703SFrançois Revol		return B_MEDIA_BAD_FORMAT;
3362c9bd703SFrançois Revol
3372c9bd703SFrançois Revol	TOUCH(quality);
3382c9bd703SFrançois Revol
339103e774dSMurai Takashi	PRINTF(1, ("FormatSuggestionRequested() %" B_PRIu32 "x%" B_PRIu32 "\n", \
3400866ac7eSFrançois Revol			format->u.raw_video.display.line_width, \
3410866ac7eSFrançois Revol			format->u.raw_video.display.line_count));
3420866ac7eSFrançois Revol
3432c9bd703SFrançois Revol	*format = fOutput.format;
344c5a66905SJérôme Duval	uint32 width, height;
345c5a66905SJérôme Duval	if (fCamDevice && fCamDevice->SuggestVideoFrame(width, height) == B_OK) {
346c5a66905SJérôme Duval		format->u.raw_video.display.line_width = width;
347c5a66905SJérôme Duval		format->u.raw_video.display.line_count = height;
3480866ac7eSFrançois Revol	}
3490866ac7eSFrançois Revol	format->u.raw_video.field_rate = FIELD_RATE;
3502c9bd703SFrançois Revol	return B_OK;
3512c9bd703SFrançois Revol}
3522c9bd703SFrançois Revol
35302af02f9SJérôme Duval
35402af02f9SJérôme Duvalstatus_t
3552c9bd703SFrançois RevolVideoProducer::FormatProposal(const media_source &output, media_format *format)
3562c9bd703SFrançois Revol{
3572c9bd703SFrançois Revol	status_t err;
3582c9bd703SFrançois Revol
3592c9bd703SFrançois Revol	if (!format)
3602c9bd703SFrançois Revol		return B_BAD_VALUE;
3612c9bd703SFrançois Revol
3622c9bd703SFrançois Revol	if (output != fOutput.source)
3632c9bd703SFrançois Revol		return B_MEDIA_BAD_SOURCE;
3642c9bd703SFrançois Revol
365103e774dSMurai Takashi	PRINTF(1, ("FormatProposal() %" B_PRIu32 "x%" B_PRIu32 "\n", \
3660866ac7eSFrançois Revol			format->u.raw_video.display.line_width, \
3670866ac7eSFrançois Revol			format->u.raw_video.display.line_count));
3680866ac7eSFrançois Revol
3692c9bd703SFrançois Revol	err = format_is_compatible(*format, fOutput.format) ?
3702c9bd703SFrançois Revol			B_OK : B_MEDIA_BAD_FORMAT;
3710866ac7eSFrançois Revol
37202af02f9SJérôme Duval	uint32 width = format->u.raw_video.display.line_width;
3730866ac7eSFrançois Revol	uint32 height = format->u.raw_video.display.line_count;
3740866ac7eSFrançois Revol
3752c9bd703SFrançois Revol	*format = fOutput.format;
3760866ac7eSFrançois Revol
3770866ac7eSFrançois Revol	if (err == B_OK && fCamDevice) {
3780866ac7eSFrançois Revol		err = fCamDevice->AcceptVideoFrame(width, height);
3790866ac7eSFrançois Revol		if (err >= B_OK) {
3800866ac7eSFrançois Revol			format->u.raw_video.display.line_width = width;
3810866ac7eSFrançois Revol			format->u.raw_video.display.line_count = height;
3820866ac7eSFrançois Revol		}
3830866ac7eSFrançois Revol	}
3840866ac7eSFrançois Revol
385103e774dSMurai Takashi	PRINTF(1, ("FormatProposal: %" B_PRIu32 "x%" B_PRIu32 "\n", \
3860866ac7eSFrançois Revol			format->u.raw_video.display.line_width, \
3870866ac7eSFrançois Revol			format->u.raw_video.display.line_count));
3880866ac7eSFrançois Revol
3892c9bd703SFrançois Revol	return err;
39002af02f9SJérôme Duval
3912c9bd703SFrançois Revol}
3922c9bd703SFrançois Revol
39302af02f9SJérôme Duval
39402af02f9SJérôme Duvalstatus_t
3952c9bd703SFrançois RevolVideoProducer::FormatChangeRequested(const media_source &source,
3962c9bd703SFrançois Revol		const media_destination &destination, media_format *io_format,
3972c9bd703SFrançois Revol		int32 *_deprecated_)
3982c9bd703SFrançois Revol{
3992c9bd703SFrançois Revol	TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_);
4002c9bd703SFrançois Revol	if (source != fOutput.source)
4012c9bd703SFrançois Revol		return B_MEDIA_BAD_SOURCE;
40202af02f9SJérôme Duval
40302af02f9SJérôme Duval	return B_ERROR;
4042c9bd703SFrançois Revol}
4052c9bd703SFrançois Revol
40602af02f9SJérôme Duval
40702af02f9SJérôme Duvalstatus_t
4082c9bd703SFrançois RevolVideoProducer::GetNextOutput(int32 *cookie, media_output *out_output)
4092c9bd703SFrançois Revol{
4102c9bd703SFrançois Revol	if (!out_output)
4112c9bd703SFrançois Revol		return B_BAD_VALUE;
4122c9bd703SFrançois Revol
4132c9bd703SFrançois Revol	if ((*cookie) != 0)
4142c9bd703SFrançois Revol		return B_BAD_INDEX;
41502af02f9SJérôme Duval
4162c9bd703SFrançois Revol	*out_output = fOutput;
4172c9bd703SFrançois Revol	(*cookie)++;
4182c9bd703SFrançois Revol	return B_OK;
4192c9bd703SFrançois Revol}
4202c9bd703SFrançois Revol
42102af02f9SJérôme Duval
42202af02f9SJérôme Duvalstatus_t
4232c9bd703SFrançois RevolVideoProducer::DisposeOutputCookie(int32 cookie)
4242c9bd703SFrançois Revol{
4252c9bd703SFrançois Revol	TOUCH(cookie);
4262c9bd703SFrançois Revol
4272c9bd703SFrançois Revol	return B_OK;
4282c9bd703SFrançois Revol}
4292c9bd703SFrançois Revol
43002af02f9SJérôme Duval
43102af02f9SJérôme Duvalstatus_t
4322c9bd703SFrançois RevolVideoProducer::SetBufferGroup(const media_source &for_source,
4332c9bd703SFrançois Revol		BBufferGroup *group)
4342c9bd703SFrançois Revol{
4352c9bd703SFrançois Revol	TOUCH(for_source); TOUCH(group);
4362c9bd703SFrançois Revol
4372c9bd703SFrançois Revol	return B_ERROR;
4382c9bd703SFrançois Revol}
4392c9bd703SFrançois Revol
44002af02f9SJérôme Duval
44102af02f9SJérôme Duvalstatus_t
4422c9bd703SFrançois RevolVideoProducer::VideoClippingChanged(const media_source &for_source,
4432c9bd703SFrançois Revol		int16 num_shorts, int16 *clip_data,
4442c9bd703SFrançois Revol		const media_video_display_info &display, int32 *_deprecated_)
4452c9bd703SFrançois Revol{
4462c9bd703SFrançois Revol	TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data);
4472c9bd703SFrançois Revol	TOUCH(display); TOUCH(_deprecated_);
4482c9bd703SFrançois Revol
4492c9bd703SFrançois Revol	return B_ERROR;
4502c9bd703SFrançois Revol}
4512c9bd703SFrançois Revol
45202af02f9SJérôme Duval
45302af02f9SJérôme Duvalstatus_t
4542c9bd703SFrançois RevolVideoProducer::GetLatency(bigtime_t *out_latency)
4552c9bd703SFrançois Revol{
4562c9bd703SFrançois Revol	*out_latency = EventLatency() + SchedulingLatency();
4572c9bd703SFrançois Revol	return B_OK;
4582c9bd703SFrançois Revol}
4592c9bd703SFrançois Revol
46002af02f9SJérôme Duval
46102af02f9SJérôme Duvalstatus_t
4622c9bd703SFrançois RevolVideoProducer::PrepareToConnect(const media_source &source,
4632c9bd703SFrançois Revol		const media_destination &destination, media_format *format,
4642c9bd703SFrançois Revol		media_source *out_source, char *out_name)
4652c9bd703SFrançois Revol{
4660866ac7eSFrançois Revol	status_t err;
4672c9bd703SFrançois Revol
468103e774dSMurai Takashi	PRINTF(1, ("PrepareToConnect() %" B_PRIu32 "x%" B_PRIu32 "\n", \
4692c9bd703SFrançois Revol			format->u.raw_video.display.line_width, \
4702c9bd703SFrançois Revol			format->u.raw_video.display.line_count));
4712c9bd703SFrançois Revol
4722c9bd703SFrançois Revol	if (fConnected) {
4732c9bd703SFrançois Revol		PRINTF(0, ("PrepareToConnect: Already connected\n"));
4742c9bd703SFrançois Revol		return EALREADY;
4752c9bd703SFrançois Revol	}
4762c9bd703SFrançois Revol
4772c9bd703SFrançois Revol	if (source != fOutput.source)
4782c9bd703SFrançois Revol		return B_MEDIA_BAD_SOURCE;
47902af02f9SJérôme Duval
4802c9bd703SFrançois Revol	if (fOutput.destination != media_destination::null)
4812c9bd703SFrançois Revol		return B_MEDIA_ALREADY_CONNECTED;
4822c9bd703SFrançois Revol
4832c9bd703SFrançois Revol	/* The format parameter comes in with the suggested format, and may be
4842c9bd703SFrançois Revol	 * specialized as desired by the node */
4852c9bd703SFrançois Revol	if (!format_is_compatible(*format, fOutput.format)) {
4862c9bd703SFrançois Revol		*format = fOutput.format;
4872c9bd703SFrançois Revol		return B_MEDIA_BAD_FORMAT;
4882c9bd703SFrançois Revol	}
4892c9bd703SFrançois Revol
4902c9bd703SFrançois Revol//XXX:FIXME
4910866ac7eSFrançois Revol#if 0
4922c9bd703SFrançois Revol//	if (format->u.raw_video.display.line_width == 0)
4932c9bd703SFrançois Revol		format->u.raw_video.display.line_width = 352;//320;
4942c9bd703SFrançois Revol		format->u.raw_video.display.line_width = 320;
4952c9bd703SFrançois Revol//	if (format->u.raw_video.display.line_count == 0)
4962c9bd703SFrançois Revol		format->u.raw_video.display.line_count = 288;//240;
4972c9bd703SFrançois Revol		format->u.raw_video.display.line_count = 240;
498a486abdcSFrançois Revol#endif
499a486abdcSFrançois Revol
5000866ac7eSFrançois Revol#ifdef FORCE_320_240
5010866ac7eSFrançois Revol	{
5020866ac7eSFrançois Revol		format->u.raw_video.display.line_width = 320;
5030866ac7eSFrançois Revol		format->u.raw_video.display.line_count = 240;
5040866ac7eSFrançois Revol	}
5050866ac7eSFrançois Revol#endif
5060866ac7eSFrançois Revol#ifdef FORCE_160_120
5070866ac7eSFrançois Revol	{
5080866ac7eSFrançois Revol		format->u.raw_video.display.line_width = 160;
5090866ac7eSFrançois Revol		format->u.raw_video.display.line_count = 120;
5100866ac7eSFrançois Revol	}
5110866ac7eSFrançois Revol#endif
5120866ac7eSFrançois Revol#ifdef FORCE_MAX_FRAME
5130866ac7eSFrançois Revol	{
5140866ac7eSFrançois Revol		format->u.raw_video.display.line_width = 0;
5150866ac7eSFrançois Revol		format->u.raw_video.display.line_count = 0;
5160866ac7eSFrançois Revol	}
5170866ac7eSFrançois Revol#endif
518a486abdcSFrançois Revol	if (fCamDevice) {
5190866ac7eSFrançois Revol		err = fCamDevice->AcceptVideoFrame(
5200866ac7eSFrançois Revol			format->u.raw_video.display.line_width,
5210866ac7eSFrançois Revol			format->u.raw_video.display.line_count);
5220866ac7eSFrançois Revol		if (err < B_OK)
5230866ac7eSFrançois Revol			return err;
524a486abdcSFrançois Revol	}
525a486abdcSFrançois Revol
5262c9bd703SFrançois Revol	if (format->u.raw_video.field_rate == 0)
5270866ac7eSFrançois Revol		format->u.raw_video.field_rate = FIELD_RATE;
5282c9bd703SFrançois Revol
5292c9bd703SFrançois Revol	*out_source = fOutput.source;
5302c9bd703SFrançois Revol	strcpy(out_name, fOutput.name);
5312c9bd703SFrançois Revol
5322c9bd703SFrançois Revol	fOutput.destination = destination;
5332c9bd703SFrançois Revol
5342c9bd703SFrançois Revol	return B_OK;
5352c9bd703SFrançois Revol}
5362c9bd703SFrançois Revol
53702af02f9SJérôme Duval
53802af02f9SJérôme Duvalvoid
5392c9bd703SFrançois RevolVideoProducer::Connect(status_t error, const media_source &source,
5402c9bd703SFrançois Revol		const media_destination &destination, const media_format &format,
5412c9bd703SFrançois Revol		char *io_name)
5422c9bd703SFrançois Revol{
543103e774dSMurai Takashi	PRINTF(1, ("Connect() %" B_PRIu32 "x%" B_PRIu32 "\n", \
5442c9bd703SFrançois Revol			format.u.raw_video.display.line_width, \
5452c9bd703SFrançois Revol			format.u.raw_video.display.line_count));
5462c9bd703SFrançois Revol
5472c9bd703SFrançois Revol	if (fConnected) {
5482c9bd703SFrançois Revol		PRINTF(0, ("Connect: Already connected\n"));
5492c9bd703SFrançois Revol		return;
5502c9bd703SFrançois Revol	}
5512c9bd703SFrançois Revol
5522c9bd703SFrançois Revol	BAutolock lock(fCamDevice->Locker());
5532c9bd703SFrançois Revol	if (!fCamDevice->IsPlugged()) {
5542c9bd703SFrançois Revol		PRINTF(0, ("Connect: Device unplugged\n"));
5552c9bd703SFrançois Revol		return;
5562c9bd703SFrançois Revol	}
5572c9bd703SFrançois Revol
55802af02f9SJérôme Duval	if (source != fOutput.source || error < B_OK
55902af02f9SJérôme Duval		|| !const_cast