10fc56ed5SStephan Aßmus/*	Copyright (c) 1998-99, Be Incorporated, All Rights Reserved.
20fc56ed5SStephan Aßmus *	Distributed under the terms of the Be Sample Code license.
30fc56ed5SStephan Aßmus *
40fc56ed5SStephan Aßmus *	Copyright (c) 2000-2008, Ingo Weinhold <ingo_weinhold@gmx.de>,
50fc56ed5SStephan Aßmus *	Copyright (c) 2000-2008, Stephan A��mus <superstippi@gmx.de>,
60fc56ed5SStephan Aßmus *	All Rights Reserved. Distributed under the terms of the MIT license.
70fc56ed5SStephan Aßmus */
8b289aaf6SAxel Dörfler
9b289aaf6SAxel Dörfler
100fc56ed5SStephan Aßmus#include "VideoProducer.h"
110fc56ed5SStephan Aßmus
120fc56ed5SStephan Aßmus#include <stdio.h>
130fc56ed5SStephan Aßmus#include <string.h>
140fc56ed5SStephan Aßmus
150fc56ed5SStephan Aßmus#include <Autolock.h>
160fc56ed5SStephan Aßmus#include <Buffer.h>
170fc56ed5SStephan Aßmus#include <BufferGroup.h>
180fc56ed5SStephan Aßmus#include <TimeSource.h>
190fc56ed5SStephan Aßmus
200fc56ed5SStephan Aßmus#include "NodeManager.h"
210fc56ed5SStephan Aßmus#include "VideoSupplier.h"
220fc56ed5SStephan Aßmus
230fc56ed5SStephan Aßmus
240fc56ed5SStephan Aßmus// debugging
250fc56ed5SStephan Aßmus//#define TRACE_VIDEO_PRODUCER
260fc56ed5SStephan Aßmus#ifdef TRACE_VIDEO_PRODUCER
270fc56ed5SStephan Aßmus# define	TRACE(x...) printf("VideoProducer::"); printf(x)
280fc56ed5SStephan Aßmus# define	FUNCTION(x...) TRACE(x)
290fc56ed5SStephan Aßmus# define	ERROR(x...) fprintf(stderr, "VideoProducer::"); fprintf(stderr, x)
300fc56ed5SStephan Aßmus#else
310fc56ed5SStephan Aßmus# define	TRACE(x...)
320fc56ed5SStephan Aßmus# define	FUNCTION(x...)
330fc56ed5SStephan Aßmus# define	ERROR(x...) fprintf(stderr, "VideoProducer::"); fprintf(stderr, x)
340fc56ed5SStephan Aßmus#endif
350fc56ed5SStephan Aßmus
360fc56ed5SStephan Aßmus
370fc56ed5SStephan Aßmus#define BUFFER_COUNT 3
380fc56ed5SStephan Aßmus
390fc56ed5SStephan Aßmus#define TOUCH(x) ((void)(x))
400fc56ed5SStephan Aßmus
410fc56ed5SStephan Aßmus
420fc56ed5SStephan AßmusVideoProducer::VideoProducer(BMediaAddOn* addon, const char* name,
430fc56ed5SStephan Aßmus		int32 internalId, NodeManager* manager, VideoSupplier* supplier)
440fc56ed5SStephan Aßmus	: BMediaNode(name),
450fc56ed5SStephan Aßmus	  BMediaEventLooper(),
460fc56ed5SStephan Aßmus	  BBufferProducer(B_MEDIA_RAW_VIDEO),
470fc56ed5SStephan Aßmus	  fInitStatus(B_NO_INIT),
480fc56ed5SStephan Aßmus	  fInternalID(internalId),
490fc56ed5SStephan Aßmus	  fAddOn(addon),
500fc56ed5SStephan Aßmus	  fBufferGroup(NULL),
510fc56ed5SStephan Aßmus	  fUsedBufferGroup(NULL),
520fc56ed5SStephan Aßmus	  fThread(-1),
530fc56ed5SStephan Aßmus	  fFrameSync(-1),
54f7eb8be9SStephan Aßmus	  fFrame(0),
55f7eb8be9SStephan Aßmus	  fFrameBase(0),
56f7eb8be9SStephan Aßmus	  fPerformanceTimeBase(0),
57f7eb8be9SStephan Aßmus	  fBufferLatency(0),
580fc56ed5SStephan Aßmus	  fRunning(false),
590fc56ed5SStephan Aßmus	  fConnected(false),
600fc56ed5SStephan Aßmus	  fEnabled(false),
610fc56ed5SStephan Aßmus	  fManager(manager),
620fc56ed5SStephan Aßmus	  fSupplier(supplier)
630fc56ed5SStephan Aßmus{
640fc56ed5SStephan Aßmus	fOutput.destination = media_destination::null;
650fc56ed5SStephan Aßmus	fInitStatus = B_OK;
660fc56ed5SStephan Aßmus}
670fc56ed5SStephan Aßmus
680fc56ed5SStephan Aßmus
690fc56ed5SStephan AßmusVideoProducer::~VideoProducer()
700fc56ed5SStephan Aßmus{
710fc56ed5SStephan Aßmus	if (fInitStatus == B_OK) {
720fc56ed5SStephan Aßmus		// Clean up after ourselves, in case the application didn't make us
730fc56ed5SStephan Aßmus		// do so.
740fc56ed5SStephan Aßmus		if (fConnected)
750fc56ed5SStephan Aßmus			Disconnect(fOutput.source, fOutput.destination);
760fc56ed5SStephan Aßmus		if (fRunning)
770fc56ed5SStephan Aßmus			_HandleStop();
780fc56ed5SStephan Aßmus	}
790fc56ed5SStephan Aßmus	Quit();
800fc56ed5SStephan Aßmus}
810fc56ed5SStephan Aßmus
820fc56ed5SStephan Aßmus
830fc56ed5SStephan AßmusBMediaAddOn*
840fc56ed5SStephan AßmusVideoProducer::AddOn(int32* _internalId) const
850fc56ed5SStephan Aßmus{
860fc56ed5SStephan Aßmus	if (_internalId)
870fc56ed5SStephan Aßmus		*_internalId = fInternalID;
880fc56ed5SStephan Aßmus	return fAddOn;
890fc56ed5SStephan Aßmus}
900fc56ed5SStephan Aßmus
910fc56ed5SStephan Aßmus
9236c08853SStephan Aßmusstatus_t
930fc56ed5SStephan AßmusVideoProducer::HandleMessage(int32 message, const void* data, size_t size)
940fc56ed5SStephan Aßmus{
950fc56ed5SStephan Aßmus	return B_ERROR;
960fc56ed5SStephan Aßmus}
970fc56ed5SStephan Aßmus
980fc56ed5SStephan Aßmus
990fc56ed5SStephan Aßmusvoid
1000fc56ed5SStephan AßmusVideoProducer::SetTimeSource(BTimeSource* timeSource)
1010fc56ed5SStephan Aßmus{
1020fc56ed5SStephan Aßmus	// Tell frame generation thread to recalculate delay value
1030fc56ed5SStephan Aßmus	release_sem(fFrameSync);
1040fc56ed5SStephan Aßmus}
1050fc56ed5SStephan Aßmus
1060fc56ed5SStephan Aßmus
10736c08853SStephan Aßmusvoid
1080fc56ed5SStephan AßmusVideoProducer::NodeRegistered()
1090fc56ed5SStephan Aßmus{
1100fc56ed5SStephan Aßmus	if (fInitStatus != B_OK) {
1110fc56ed5SStephan Aßmus		ReportError(B_NODE_IN_DISTRESS);
1120fc56ed5SStephan Aßmus		return;
1130fc56ed5SStephan Aßmus	}
1140fc56ed5SStephan Aßmus
1150fc56ed5SStephan Aßmus	fOutput.node = Node();
1160fc56ed5SStephan Aßmus	fOutput.source.port = ControlPort();
1170fc56ed5SStephan Aßmus	fOutput.source.id = 0;
1180fc56ed5SStephan Aßmus	fOutput.destination = media_destination::null;
11936c08853SStephan Aßmus	strcpy(fOutput.name, Name());
1200fc56ed5SStephan Aßmus
1210fc56ed5SStephan Aßmus	// fill with wild cards at this point in time
1220fc56ed5SStephan Aßmus	fOutput.format.type = B_MEDIA_RAW_VIDEO;
1230fc56ed5SStephan Aßmus	fOutput.format.u.raw_video = media_raw_video_format::wildcard;
1240fc56ed5SStephan Aßmus	fOutput.format.u.raw_video.interlace = 1;
1250fc56ed5SStephan Aßmus	fOutput.format.u.raw_video.display.format = B_NO_COLOR_SPACE;
1260fc56ed5SStephan Aßmus	fOutput.format.u.raw_video.display.bytes_per_row = 0;
1270fc56ed5SStephan Aßmus	fOutput.format.u.raw_video.display.line_width = 0;
1280fc56ed5SStephan Aßmus	fOutput.format.u.raw_video.display.line_count = 0;
1290fc56ed5SStephan Aßmus
1300fc56ed5SStephan Aßmus	// start the BMediaEventLooper control loop running
1310fc56ed5SStephan Aßmus	Run();
1320fc56ed5SStephan Aßmus}
1330fc56ed5SStephan Aßmus
1340fc56ed5SStephan Aßmus
1350fc56ed5SStephan Aßmusvoid
1360fc56ed5SStephan AßmusVideoProducer::Start(bigtime_t performanceTime)
1370fc56ed5SStephan Aßmus{
1380fc56ed5SStephan Aßmus	// notify the manager in case we were started from the outside world
1390fc56ed5SStephan Aßmus//	fManager->StartPlaying();
1400fc56ed5SStephan Aßmus
1410fc56ed5SStephan Aßmus	BMediaEventLooper::Start(performanceTime);
1420fc56ed5SStephan Aßmus}
1430fc56ed5SStephan Aßmus
1440fc56ed5SStephan Aßmus
1450fc56ed5SStephan Aßmusvoid
1460fc56ed5SStephan AßmusVideoProducer::Stop(bigtime_t performanceTime, bool immediate)
1470fc56ed5SStephan Aßmus{
1480fc56ed5SStephan Aßmus	// notify the manager in case we were stopped from the outside world
1490fc56ed5SStephan Aßmus//	fManager->StopPlaying();
1500fc56ed5SStephan Aßmus
1510fc56ed5SStephan Aßmus	BMediaEventLooper::Stop(performanceTime, immediate);
1520fc56ed5SStephan Aßmus}
1530fc56ed5SStephan Aßmus
1540fc56ed5SStephan Aßmus
1550fc56ed5SStephan Aßmusvoid
1560fc56ed5SStephan AßmusVideoProducer::Seek(bigtime_t media_time, bigtime_t performanceTime)
1570fc56ed5SStephan Aßmus{
1580fc56ed5SStephan Aßmus	BMediaEventLooper::Seek(media_time, performanceTime);
1590fc56ed5SStephan Aßmus}
1600fc56ed5SStephan Aßmus
1610fc56ed5SStephan Aßmus
16236c08853SStephan Aßmusvoid
1630fc56ed5SStephan AßmusVideoProducer::HandleEvent(const media_timed_event* event,
1640fc56ed5SStephan Aßmus		bigtime_t lateness, bool realTimeEvent)
1650fc56ed5SStephan Aßmus{
1660fc56ed5SStephan Aßmus	TOUCH(lateness); TOUCH(realTimeEvent);
1670fc56ed5SStephan Aßmus
168c6ffa94fSAdrien Destugues	switch (event->type) {
1690fc56ed5SStephan Aßmus		case BTimedEventQueue::B_START:
1700fc56ed5SStephan Aßmus			_HandleStart(event->event_time);
1710fc56ed5SStephan Aßmus			break;
1720fc56ed5SStephan Aßmus		case BTimedEventQueue::B_STOP:
1737e74eb0fSDario Casalinuovo		{
1747e74eb0fSDario Casalinuovo			EventQueue()->FlushEvents(event->event_time,
1757e74eb0fSDario Casalinuovo				BTimedEventQueue::B_ALWAYS,
1767e74eb0fSDario Casalinuovo				true, BTimedEventQueue::B_HANDLE_BUFFER);
1770fc56ed5SStephan Aßmus			_HandleStop();
1780fc56ed5SStephan Aßmus			break;
1797e74eb0fSDario Casalinuovo		}
1800fc56ed5SStephan Aßmus		case BTimedEventQueue::B_WARP:
1810fc56ed5SStephan Aßmus			_HandleTimeWarp(event->bigdata);
1820fc56ed5SStephan Aßmus			break;
1830fc56ed5SStephan Aßmus		case BTimedEventQueue::B_SEEK:
1840fc56ed5SStephan Aßmus			_HandleSeek(event->bigdata);
1850fc56ed5SStephan Aßmus			break;
1860fc56ed5SStephan Aßmus		case BTimedEventQueue::B_HANDLE_BUFFER:
1870fc56ed5SStephan Aßmus		case BTimedEventQueue::B_DATA_STATUS:
1880fc56ed5SStephan Aßmus		case BTimedEventQueue::B_PARAMETER:
1890fc56ed5SStephan Aßmus		default:
1900fc56ed5SStephan Aßmus			TRACE("HandleEvent: Unhandled event -- %lx\n", event->type);
1910fc56ed5SStephan Aßmus			break;
1920fc56ed5SStephan Aßmus	}
1930fc56ed5SStephan Aßmus}
1940fc56ed5SStephan Aßmus
1950fc56ed5SStephan Aßmus
1960fc56ed5SStephan Aßmusstatus_t
1970fc56ed5SStephan AßmusVideoProducer::DeleteHook(BMediaNode* node)
1980fc56ed5SStephan Aßmus{
1990fc56ed5SStephan Aßmus	return BMediaEventLooper::DeleteHook(node);
2000fc56ed5SStephan Aßmus}
2010fc56ed5SStephan Aßmus
2020fc56ed5SStephan Aßmus
20336c08853SStephan Aßmusstatus_t
2040fc56ed5SStephan AßmusVideoProducer::FormatSuggestionRequested(media_type type, int32 quality,
2050fc56ed5SStephan Aßmus	media_format* _format)
2060fc56ed5SStephan Aßmus{
2070fc56ed5SStephan Aßmus	FUNCTION("FormatSuggestionRequested\n");
2080fc56ed5SStephan Aßmus
2090fc56ed5SStephan Aßmus	if (type != B_MEDIA_ENCODED_VIDEO)
2100fc56ed5SStephan Aßmus		return B_MEDIA_BAD_FORMAT;
2110fc56ed5SStephan Aßmus
2120fc56ed5SStephan Aßmus	TOUCH(quality);
2130fc56ed5SStephan Aßmus
2140fc56ed5SStephan Aßmus	*_format = fOutput.format;
2150fc56ed5SStephan Aßmus	return B_OK;
2160fc56ed5SStephan Aßmus}
2170fc56ed5SStephan Aßmus
2180fc56ed5SStephan Aßmus
21936c08853SStephan Aßmusstatus_t
2200fc56ed5SStephan AßmusVideoProducer::FormatProposal(const media_source& output, media_format* format)
2210fc56ed5SStephan Aßmus{
2220fc56ed5SStephan Aßmus	#ifdef TRACE_VIDEO_PRODUCER
22336c08853SStephan Aßmus		char string[256];
2240fc56ed5SStephan Aßmus		string_for_format(*format, string, 256);
2250fc56ed5SStephan Aßmus		FUNCTION("FormatProposal(%s)\n", string);
2260fc56ed5SStephan Aßmus	#endif
2270fc56ed5SStephan Aßmus
2280fc56ed5SStephan Aßmus	if (!format)
2290fc56ed5SStephan Aßmus		return B_BAD_VALUE;
2300fc56ed5SStephan Aßmus
2310fc56ed5SStephan Aßmus	if (output != fOutput.source)
2320fc56ed5SStephan Aßmus		return B_MEDIA_BAD_SOURCE;
2330fc56ed5SStephan Aßmus
2340fc56ed5SStephan Aßmus	status_t ret = format_is_compatible(*format, fOutput.format) ?
2350fc56ed5SStephan Aßmus		B_OK : B_MEDIA_BAD_FORMAT;
236591ce51aSStephan Aßmus	if (ret != B_OK) {
237591ce51aSStephan Aßmus		ERROR("FormatProposal() error: %s\n", strerror(ret));
238591ce51aSStephan Aßmus		char string[512];
239591ce51aSStephan Aßmus		string_for_format(*format, string, sizeof(string));
240591ce51aSStephan Aßmus		ERROR("  requested: %s\n", string);
241591ce51aSStephan Aßmus		string_for_format(fOutput.format, string, sizeof(string));
242591ce51aSStephan Aßmus		ERROR("  output:    %s\n", string);
243591ce51aSStephan Aßmus	}
244591ce51aSStephan Aßmus
2450fc56ed5SStephan Aßmus	// change any wild cards to specific values
2460fc56ed5SStephan Aßmus
2470fc56ed5SStephan Aßmus	return ret;
24836c08853SStephan Aßmus
2490fc56ed5SStephan Aßmus}
2500fc56ed5SStephan Aßmus
2510fc56ed5SStephan Aßmus
25236c08853SStephan Aßmusstatus_t
2530fc56ed5SStephan AßmusVideoProducer::FormatChangeRequested(const media_source& source,
2540fc56ed5SStephan Aßmus	const media_destination& destination, media_format* ioFormat,
2550fc56ed5SStephan Aßmus	int32 *_deprecated_)
2560fc56ed5SStephan Aßmus{
2570fc56ed5SStephan Aßmus	TOUCH(destination); TOUCH(ioFormat); TOUCH(_deprecated_);
2580fc56ed5SStephan Aßmus
2590fc56ed5SStephan Aßmus	if (source != fOutput.source)
2600fc56ed5SStephan Aßmus		return B_MEDIA_BAD_SOURCE;
26136c08853SStephan Aßmus
26236c08853SStephan Aßmus	return B_ERROR;
2630fc56ed5SStephan Aßmus}
2640fc56ed5SStephan Aßmus
2650fc56ed5SStephan Aßmus
26636c08853SStephan Aßmusstatus_t
2670fc56ed5SStephan AßmusVideoProducer::GetNextOutput(int32* cookie, media_output* outOutput)
2680fc56ed5SStephan Aßmus{
2690fc56ed5SStephan Aßmus	if (!outOutput)
2700fc56ed5SStephan Aßmus		return B_BAD_VALUE;
2710fc56ed5SStephan Aßmus
2720fc56ed5SStephan Aßmus	if ((*cookie) != 0)
2730fc56ed5SStephan Aßmus		return B_BAD_INDEX;
27436c08853SStephan Aßmus
2750fc56ed5SStephan Aßmus	*outOutput = fOutput;
2760fc56ed5SStephan Aßmus	(*cookie)++;
2770fc56ed5SStephan Aßmus
2780fc56ed5SStephan Aßmus	return B_OK;
2790fc56ed5SStephan Aßmus}
2800fc56ed5SStephan Aßmus
2810fc56ed5SStephan Aßmus
28236c08853SStephan Aßmusstatus_t
2830fc56ed5SStephan AßmusVideoProducer::DisposeOutputCookie(int32 cookie)
2840fc56ed5SStephan Aßmus{
2850fc56ed5SStephan Aßmus	TOUCH(cookie);
2860fc56ed5SStephan Aßmus
2870fc56ed5SStephan Aßmus	return B_OK;
2880fc56ed5SStephan Aßmus}
2890fc56ed5SStephan Aßmus
2900fc56ed5SStephan Aßmus
29136c08853SStephan Aßmusstatus_t
2920fc56ed5SStephan AßmusVideoProducer::SetBufferGroup(const media_source& forSource,
2930fc56ed5SStephan Aßmus	BBufferGroup *group)
2940fc56ed5SStephan Aßmus{
2950fc56ed5SStephan Aßmus	if (forSource != fOutput.source)
2960fc56ed5SStephan Aßmus		return B_MEDIA_BAD_SOURCE;
2970fc56ed5SStephan Aßmus
2980fc56ed5SStephan Aßmus	TRACE("VideoProducer::SetBufferGroup() - using buffer group of "
2990fc56ed5SStephan Aßmus		"consumer.\n");
3000fc56ed5SStephan Aßmus	fUsedBufferGroup = group;
3010fc56ed5SStephan Aßmus
3020fc56ed5SStephan Aßmus	return B_OK;
3030fc56ed5SStephan Aßmus}
3040fc56ed5SStephan Aßmus
3050fc56ed5SStephan Aßmus
30636c08853SStephan Aßmusstatus_t
3070fc56ed5SStephan AßmusVideoProducer::VideoClippingChanged(const media_source& forSource,
3080fc56ed5SStephan Aßmus	int16 numShorts, int16* clipData, const media_video_display_info& display,
3090fc56ed5SStephan Aßmus	int32* _deprecated_)
3100fc56ed5SStephan Aßmus{
3110fc56ed5SStephan Aßmus	TOUCH(forSource); TOUCH(numShorts); TOUCH(clipData);
3120fc56ed5SStephan Aßmus	TOUCH(display); TOUCH(_deprecated_);
3130fc56ed5SStephan Aßmus
3140fc56ed5SStephan Aßmus	return B_ERROR;
3150fc56ed5SStephan Aßmus}
3160fc56ed5SStephan Aßmus
3170fc56ed5SStephan Aßmus
31836c08853SStephan Aßmusstatus_t
3190fc56ed5SStephan AßmusVideoProducer::GetLatency(bigtime_t* _latency)
3200fc56ed5SStephan Aßmus{
3210fc56ed5SStephan Aßmus	if (!_latency)
3220fc56ed5SStephan Aßmus		return B_BAD_VALUE;
3230fc56ed5SStephan Aßmus
3240fc56ed5SStephan Aßmus	*_latency = EventLatency() + SchedulingLatency();
3250fc56ed5SStephan Aßmus
3260fc56ed5SStephan Aßmus	return B_OK;
3270fc56ed5SStephan Aßmus}
3280fc56ed5SStephan Aßmus
3290fc56ed5SStephan Aßmus
33036c08853SStephan Aßmusstatus_t
3310fc56ed5SStephan AßmusVideoProducer::PrepareToConnect(const media_source& source,
3320fc56ed5S