10fe9fd36SDavid McPaul/*
20fe9fd36SDavid McPaul* Copyright (C) 2009-2010 David McPaul
30fe9fd36SDavid McPaul*
40fe9fd36SDavid McPaul* All rights reserved. Distributed under the terms of the MIT License.
50fe9fd36SDavid McPaul*/
60fe9fd36SDavid McPaul
70fe9fd36SDavid McPaul#ifndef _VIDEO_MIXER_NODE_H
80fe9fd36SDavid McPaul#define _VIDEO_MIXER_NODE_H
90fe9fd36SDavid McPaul
100fe9fd36SDavid McPaul#include <Buffer.h>
110fe9fd36SDavid McPaul#include <BufferConsumer.h>
120fe9fd36SDavid McPaul#include <BufferGroup.h>
130fe9fd36SDavid McPaul#include <BufferProducer.h>
140fe9fd36SDavid McPaul#include <MediaAddOn.h>
150fe9fd36SDavid McPaul#include <MediaDefs.h>
160fe9fd36SDavid McPaul#include <MediaEventLooper.h>
170fe9fd36SDavid McPaul#include <MediaNode.h>
180fe9fd36SDavid McPaul#include <TimeSource.h>
190fe9fd36SDavid McPaul
200fe9fd36SDavid McPaul#include <vector>
210fe9fd36SDavid McPaul
220fe9fd36SDavid McPaul#include "BufferMixer.h"
230fe9fd36SDavid McPaul
240fe9fd36SDavid McPaulclass VideoMixerNode :
250fe9fd36SDavid McPaul	public BBufferConsumer,
260fe9fd36SDavid McPaul	public BBufferProducer,
270fe9fd36SDavid McPaul    public BMediaEventLooper
280fe9fd36SDavid McPaul{
290fe9fd36SDavid McPaulprotected:
300fe9fd36SDavid McPaulvirtual ~VideoMixerNode(void);
310fe9fd36SDavid McPaul
320fe9fd36SDavid McPaulpublic:
330fe9fd36SDavid McPaul
340fe9fd36SDavid McPaulexplicit VideoMixerNode(
350fe9fd36SDavid McPaul				const flavor_info * info = 0,
360fe9fd36SDavid McPaul				BMessage *config = 0,
370fe9fd36SDavid McPaul				BMediaAddOn *addOn = 0);
380fe9fd36SDavid McPaul
390fe9fd36SDavid McPaulvirtual status_t InitCheck(void) const;
400fe9fd36SDavid McPaul
410fe9fd36SDavid McPaul// see BMediaAddOn::GetConfigurationFor
420fe9fd36SDavid McPaulvirtual	status_t GetConfigurationFor(
430fe9fd36SDavid McPaul				BMessage *into_message);
440fe9fd36SDavid McPaul
450fe9fd36SDavid McPaulpublic:
460fe9fd36SDavid McPaul//	/* this port is what a media node listens to for commands */
470fe9fd36SDavid McPaul// virtual port_id ControlPort(void) const;
480fe9fd36SDavid McPaul
490fe9fd36SDavid McPaulvirtual	BMediaAddOn* AddOn(
500fe9fd36SDavid McPaul				int32 *internal_id) const;	/* Who instantiated you -- or NULL for app class */
510fe9fd36SDavid McPaul
520fe9fd36SDavid McPaulprotected:
530fe9fd36SDavid McPaul		/* These don't return errors; instead, they use the global error condition reporter. */
540fe9fd36SDavid McPaul		/* A node is required to have a queue of at least one pending command (plus TimeWarp) */
550fe9fd36SDavid McPaul		/* and is recommended to allow for at least one pending command of each type. */
560fe9fd36SDavid McPaul		/* Allowing an arbitrary number of outstanding commands might be nice, but apps */
570fe9fd36SDavid McPaul		/* cannot depend on that happening. */
580fe9fd36SDavid McPaulvirtual	void Start(
590fe9fd36SDavid McPaul				bigtime_t performance_time);
600fe9fd36SDavid McPaulvirtual	void Stop(
610fe9fd36SDavid McPaul				bigtime_t performance_time,
620fe9fd36SDavid McPaul				bool immediate);
630fe9fd36SDavid McPaulvirtual	void Seek(
640fe9fd36SDavid McPaul				bigtime_t media_time,
650fe9fd36SDavid McPaul				bigtime_t performance_time);
660fe9fd36SDavid McPaulvirtual	void SetRunMode(
670fe9fd36SDavid McPaul				run_mode mode);
680fe9fd36SDavid McPaulvirtual	void TimeWarp(
690fe9fd36SDavid McPaul				bigtime_t at_real_time,
700fe9fd36SDavid McPaul				bigtime_t to_performance_time);
710fe9fd36SDavid McPaulvirtual	void Preroll(void);
720fe9fd36SDavid McPaulvirtual	void SetTimeSource(BTimeSource *time_source);
730fe9fd36SDavid McPaul
740fe9fd36SDavid McPaulpublic:
750fe9fd36SDavid McPaulvirtual	status_t HandleMessage(
760fe9fd36SDavid McPaul				int32 message,
770fe9fd36SDavid McPaul				const void *data,
780fe9fd36SDavid McPaul				size_t size);
790fe9fd36SDavid McPaul
800fe9fd36SDavid McPaulprotected:
810fe9fd36SDavid McPaul		/* Called when requests have completed, or failed. */
820fe9fd36SDavid McPaulvirtual	status_t RequestCompleted(	/* reserved 0 */
830fe9fd36SDavid McPaul				const media_request_info &info);
840fe9fd36SDavid McPaul
850fe9fd36SDavid McPaulprotected:
860fe9fd36SDavid McPaulvirtual		status_t DeleteHook(BMediaNode *node);		/* reserved 1 */
870fe9fd36SDavid McPaul
880fe9fd36SDavid McPaulvirtual		void NodeRegistered(void);	/* reserved 2 */
890fe9fd36SDavid McPaul
900fe9fd36SDavid McPaulpublic:
910fe9fd36SDavid McPaul
920fe9fd36SDavid McPaul		/* fill out your attributes in the provided array, returning however many you have. */
930fe9fd36SDavid McPaulvirtual		status_t GetNodeAttributes(	/* reserved 3 */
940fe9fd36SDavid McPaul					media_node_attribute *outAttributes,
950fe9fd36SDavid McPaul					size_t inMaxCount);
960fe9fd36SDavid McPaul
970fe9fd36SDavid McPaulvirtual		status_t AddTimer(
980fe9fd36SDavid McPaul					bigtime_t at_performance_time,
990fe9fd36SDavid McPaul					int32 cookie);
1000fe9fd36SDavid McPaul
1010fe9fd36SDavid McPaul	/* Someone, probably the producer, is asking you about this format. Give */
1020fe9fd36SDavid McPaul	/* your honest opinion, possibly modifying *format. Do not ask upstream */
1030fe9fd36SDavid McPaul	/* producer about the format, since he's synchronously waiting for your */
1040fe9fd36SDavid McPaul	/* reply. */
1050fe9fd36SDavid McPaulvirtual	status_t AcceptFormat(
1060fe9fd36SDavid McPaul				const media_destination &dest,
1070fe9fd36SDavid McPaul				media_format *format);
1080fe9fd36SDavid McPaulvirtual	status_t GetNextInput(
1090fe9fd36SDavid McPaul				int32 * cookie,
1100fe9fd36SDavid McPaul				media_input *out_input);
1110fe9fd36SDavid McPaulvirtual	void DisposeInputCookie(int32 cookie);
1120fe9fd36SDavid McPaulvirtual	void BufferReceived(BBuffer *buffer);
1130fe9fd36SDavid McPaulvirtual	void ProducerDataStatus(
1140fe9fd36SDavid McPaul				const media_destination &for_whom,
1150fe9fd36SDavid McPaul				int32 status,
1160fe9fd36SDavid McPaul				bigtime_t at_performance_time);
1170fe9fd36SDavid McPaulvirtual	status_t GetLatencyFor(
1180fe9fd36SDavid McPaul				const media_destination &for_whom,
1190fe9fd36SDavid McPaul				bigtime_t *out_latency,
1200fe9fd36SDavid McPaul				media_node_id *out_timesource);
1210fe9fd36SDavid McPaulvirtual	status_t Connected(
1220fe9fd36SDavid McPaul				const media_source &producer,	/* here's a good place to request buffer group usage */
1230fe9fd36SDavid McPaul				const media_destination &where,
1240fe9fd36SDavid McPaul				const media_format &with_format,
1250fe9fd36SDavid McPaul				media_input *out_input);
1260fe9fd36SDavid McPaulvirtual	void Disconnected(
1270fe9fd36SDavid McPaul				const media_source &producer,
1280fe9fd36SDavid McPaul				const media_destination &where);
1290fe9fd36SDavid McPaul	/* The notification comes from the upstream producer, so he's already cool with */
1300fe9fd36SDavid McPaul	/* the format; you should not ask him about it in here. */
1310fe9fd36SDavid McPaulvirtual	status_t FormatChanged(
1320fe9fd36SDavid McPaul				const media_source &producer,
1330fe9fd36SDavid McPaul				const media_destination &consumer,
1340fe9fd36SDavid McPaul				int32 change_tag,
1350fe9fd36SDavid McPaul				const media_format &format);
1360fe9fd36SDavid McPaul
1370fe9fd36SDavid McPaul	/* Given a performance time of some previous buffer, retrieve the remembered tag */
1380fe9fd36SDavid McPaul	/* of the closest (previous or exact) performance time. Set *out_flags to 0; the */
1390fe9fd36SDavid McPaul	/* idea being that flags can be added later, and the understood flags returned in */
1400fe9fd36SDavid McPaul	/* *out_flags. */
1410fe9fd36SDavid McPaulvirtual	status_t SeekTagRequested(
1420fe9fd36SDavid McPaul				const media_destination &destination,
1430fe9fd36SDavid McPaul				bigtime_t in_target_time,
1440fe9fd36SDavid McPaul				uint32 in_flags,
1450fe9fd36SDavid McPaul				media_seek_tag *out_seek_tag,
1460fe9fd36SDavid McPaul				bigtime_t *out_tagged_time,
1470fe9fd36SDavid McPaul				uint32 *out_flags);
1480fe9fd36SDavid McPaul
1490fe9fd36SDavid McPaul
1500fe9fd36SDavid McPaulprotected:
1510fe9fd36SDavid McPaul	/* functionality of BBufferProducer */
1520fe9fd36SDavid McPaulvirtual	status_t FormatSuggestionRequested(
1530fe9fd36SDavid McPaul				media_type type,
1540fe9fd36SDavid McPaul				int32 quality,
1550fe9fd36SDavid McPaul				media_format *format);
1560fe9fd36SDavid McPaulvirtual	status_t FormatProposal(
1570fe9fd36SDavid McPaul				const media_source &output,
1580fe9fd36SDavid McPaul				media_format *format);
1590fe9fd36SDavid McPaul	/* If the format isn't good, put a good format into *io_format and return error */
1600fe9fd36SDavid McPaul	/* If format has wildcard, specialize to what you can do (and change). */
1610fe9fd36SDavid McPaul	/* If you can change the format, return OK. */
1620fe9fd36SDavid McPaul	/* The request comes from your destination sychronously, so you cannot ask it */
1630fe9fd36SDavid McPaul	/* whether it likes it -- you should assume it will since it asked. */
1640fe9fd36SDavid McPaulvirtual	status_t FormatChangeRequested(
1650fe9fd36SDavid McPaul				const media_source &source,
1660fe9fd36SDavid McPaul				const media_destination &destination,
1670fe9fd36SDavid McPaul				media_format *io_format,
1680fe9fd36SDavid McPaul				int32 *_deprecated_);
1690fe9fd36SDavid McPaulvirtual	status_t GetNextOutput(	/* cookie starts as 0 */
1700fe9fd36SDavid McPaul				int32 *cookie,
1710fe9fd36SDavid McPaul				media_output *out_output);
1720fe9fd36SDavid McPaulvirtual	status_t DisposeOutputCookie(
1730fe9fd36SDavid McPaul				int32 cookie);
1740fe9fd36SDavid McPaul	/* In this function, you should either pass on the group to your upstream guy, */
1750fe9fd36SDavid McPaul	/* or delete your current group and hang on to this group. Deleting the previous */
1760fe9fd36SDavid McPaul	/* group (unless you passed it on with the reclaim flag set to false) is very */
1770fe9fd36SDavid McPaul	/* important, else you will 1) leak memory and 2) block someone who may want */
1780fe9fd36SDavid McPaul	/* to reclaim the buffers living in that group. */
1790fe9fd36SDavid McPaulvirtual	status_t SetBufferGroup(
1800fe9fd36SDavid McPaul				const media_source &for_source,
1810fe9fd36SDavid McPaul				BBufferGroup * group);
1820fe9fd36SDavid McPaul	/* Format of clipping is (as int16-s): <from line> <npairs> <startclip> <endclip>. */
1830fe9fd36SDavid McPaul	/* Repeat for each line where the clipping is different from the previous line. */
1840fe9fd36SDavid McPaul	/* If <npairs> is negative, use the data from line -<npairs> (there are 0 pairs after */
1850fe9fd36SDavid McPaul	/* a negative <npairs>. Yes, we only support 32k*32k frame buffers for clipping. */
1860fe9fd36SDavid McPaul	/* Any non-0 field of 'display' means that that field changed, and if you don't support */
1870fe9fd36SDavid McPaul	/* that change, you should return an error and ignore the request. Note that the buffer */
1880fe9fd36SDavid McPaul	/* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */
1890fe9fd36SDavid McPaul	/* be adhered to. */
1900fe9fd36SDavid McPaulvirtual	status_t VideoClippingChanged(
1910fe9fd36SDavid McPaul				const media_source &for_source,
1920fe9fd36SDavid McPaul				int16 num_shorts,
1930fe9fd36SDavid McPaul				int16 *clip_data,
1940fe9fd36SDavid McPaul				const media_video_display_info &display,
1950fe9fd36SDavid McPaul				int32 *_deprecated_);
1960fe9fd36SDavid McPaul	/* Iterates over all outputs and maxes the latency found */
1970fe9fd36SDavid McPaulvirtual	status_t GetLatency(bigtime_t *out_latency);
1980fe9fd36SDavid McPaulvirtual	status_t PrepareToConnect(
1990fe9fd36SDavid McPaul				const media_source &what,
2000fe9fd36SDavid McPaul				const media_destination &where,
2010fe9fd36SDavid McPaul				media_format *format,
2020fe9fd36SDavid McPaul				media_source *out_source,
2030fe9fd36SDavid McPaul				char *out_name);
2040fe9fd36SDavid McPaulvirtual	void Connect(
2050fe9fd36SDavid McPaul				status_t error,
2060fe9fd36SDavid McPaul				const media_source &source,
2070fe9fd36SDavid McPaul				const media_destination &destination,
2080fe9fd36SDavid McPaul				const media_format &format,
2090fe9fd36SDavid McPaul				char *io_name);
2100fe9fd36SDavid McPaulvirtual	void Disconnect(
2110fe9fd36SDavid McPaul				const media_source &what,
2120fe9fd36SDavid McPaul				const media_destination &where);
2130fe9fd36SDavid McPaulvirtual	void LateNoticeReceived(
2140fe9fd36SDavid McPaul				const media_source &what,
2150fe9fd36SDavid McPaul				bigtime_t how_much,
2160fe9fd36SDavid McPaul				bigtime_t performance_time);
2170fe9fd36SDavid McPaulvirtual	void EnableOutput(
2180fe9fd36SDavid McPaul				const media_source &what,
2190fe9fd36SDavid McPaul				bool enabled,
2200fe9fd36SDavid McPaul				int32 *_deprecated_);
2210fe9fd36SDavid McPaulvirtual	status_t SetPlayRate(
2220fe9fd36SDavid McPaul				int32 numer,
2230fe9fd36SDavid McPaul				int32 denom);
2240fe9fd36SDavid McPaul
2250fe9fd36SDavid McPaulvirtual	void AdditionalBufferRequested(			//	used to be Reserved 0
2260fe9fd36SDavid McPaul				const media_source & source,
2270fe9fd36SDavid McPaul				media_buffer_id prev_buffer,
2280fe9fd36SDavid McPaul				bigtime_t prev_time,
2290fe9fd36SDavid McPaul				const media_seek_tag *prev_tag);	//	may be NULL
2300fe9fd36SDavid McPaul
2310fe9fd36SDavid McPaulvirtual	void LatencyChanged(					//	used to be Reserved 1
2320fe9fd36SDavid McPaul				const media_source & source,
2330fe9fd36SDavid McPaul				const media_destination & destination,
2340fe9fd36SDavid McPaul				bigtime_t new_latency,
2350fe9fd36SDavid McPaul				uint32 flags);
2360fe9fd36SDavid McPaul
2370fe9fd36SDavid McPaul
2380fe9fd36SDavid McPaul	protected:
2390fe9fd36SDavid McPaul		/* you must override to handle your events! */
2400fe9fd36SDavid McPaul		/* you should not call HandleEvent directly */
2410fe9fd36SDavid McPaul		virtual void		HandleEvent(	const media_timed_event *event,
2420fe9fd36SDavid McPaul											bigtime_t lateness,
2430fe9fd36SDavid McPaul											bool realTimeEvent = false);
2440fe9fd36SDavid McPaul
2450fe9fd36SDavid McPaul		/* override to clean up custom events you have added to your queue */
2460fe9fd36SDavid McPaul		virtual void		CleanUpEvent(const media_timed_event *event);
2470fe9fd36SDavid McPaul
2480fe9fd36SDavid McPaul		/* called from Offline mode to determine the current time of the node */
2490fe9fd36SDavid McPaul		/* update your internal information whenever it changes */
2500fe9fd36SDavid McPaul		virtual	bigtime_t	OfflineTime();
2510fe9fd36SDavid McPaul
2520fe9fd36SDavid McPaul		/* override only if you know what you are doing! */
2530fe9fd36SDavid McPaul		/* otherwise much badness could occur */
2540fe9fd36SDavid McPaul		/* the actual control loop function: */
2550fe9fd36SDavid McPaul		/* 	waits for messages, Pops events off the queue and calls DispatchEvent */
2560fe9fd36SDavid McPaul		virtual void		ControlLoop();
2570fe9fd36SDavid McPaul
2580fe9fd36SDavid McPaul
2590fe9fd36SDavid McPaulprotected:
2600fe9fd36SDavid McPaul
2610fe9fd36SDavid McPaulvirtual status_t HandleStart(
2620fe9fd36SDavid McPaul						const media_timed_event *event,
2630fe9fd36SDavid McPaul						bigtime_t lateness,
2640fe9fd36SDavid McPaul						bool realTimeEvent = false);
2650fe9fd36SDavid McPaulvirtual status_t HandleSeek(
2660fe9fd36SDavid McPaul						const media_timed_event *event,
2670fe9fd36SDavid McPaul						bigtime_t lateness,
2680fe9fd36SDavid McPaul						bool realTimeEvent = false);
2690fe9fd36SDavid McPaulvirtual status_t HandleWarp(
2700fe9fd36SDavid McPaul						const media_timed_event *event,
2710fe9fd36SDavid McPaul						bigtime_t lateness,
2720fe9fd36SDavid McPaul						bool realTimeEvent = false);
2730fe9fd36SDavid McPaulvirtual status_t HandleStop(
2740fe9fd36SDavid McPaul						const media_timed_event *event,
2750fe9fd36SDavid McPaul						bigtime_t lateness,
2760fe9fd36SDavid McPaul						bool realTimeEvent = false);
2770fe9fd36SDavid McPaulvirtual status_t HandleBuffer(
2780fe9fd36SDavid McPaul						const media_timed_event *event,
2790fe9fd36SDavid McPaul						bigtime_t lateness,
2800fe9fd36SDavid McPaul						bool realTimeEvent = false);
2810fe9fd36SDavid McPaulvirtual status_t HandleDataStatus(
2820fe9fd36SDavid McPaul						const media_timed_event *event,
2830fe9fd36SDavid McPaul						bigtime_t lateness,
2840fe9fd36SDavid McPaul						bool realTimeEvent = false);
2850fe9fd36SDavid McPaulvirtual status_t HandleParameter(
2860fe9fd36SDavid McPaul						const media_timed_event *event,
2870fe9fd36SDavid McPaul						bigtime_t lateness,
2880fe9fd36SDavid McPaul						bool realTimeEvent = false);
2890fe9fd36SDavid McPaul
2900fe9fd36SDavid McPaulprotected:
2910fe9fd36SDavid McPaul
2920fe9fd36SDavid McPaul//void CreateBufferGroup(MediaOutputInfo *output_info);
2930fe9fd36SDavid McPaulvoid ComputeInternalLatency();
2940fe9fd36SDavid McPaul
2950fe9fd36SDavid McPaulpublic:
2960fe9fd36SDavid McPaul
2970fe9fd36SDavid McPaulstatic void GetFlavor(flavor_info *outInfo, int32 id);
2980fe9fd36SDavid McPaul
2990fe9fd36SDavid McPaulprivate:
3000fe9fd36SDavid McPaul	media_input 	*CreateInput(uint32 inputID);
3010fe9fd36SDavid McPaul	void			ClearInput(media_input *input);
3020fe9fd36SDavid McPaul	media_input		*GetInput(const media_source &source);
3030fe9fd36SDavid McPaul	media_input		*GetInput(const media_destination &destination);
3040fe9fd36SDavid McPaul	media_input		*GetInput(const int32 id);
3050fe9fd36SDavid McPaul
3060fe9fd36SDavid McPaulstatic void GetInputFormat(media_format *outFormat);
3070fe9fd36SDavid McPaulstatic void GetOutputFormat(media_format *outFormat);
3080fe9fd36SDavid McPaul
3090fe9fd36SDavid McPaulprotected:
3100fe9fd36SDavid McPaul
3110fe9fd36SDavid McPaulvirtual status_t AddRequirements(media_format *format);
3120fe9fd36SDavid McPaul
3130fe9fd36SDavid McPaulprivate:
3140fe9fd36SDavid McPaul
3150fe9fd36SDavid McPaul		status_t 					fInitCheckStatus;
3160fe9fd36SDavid McPaul
3170fe9fd36SDavid McPaul		BMediaAddOn 				*fAddOn;
3180fe9fd36SDavid McPaul
3190fe9fd36SDavid McPaul		media_input					fInitialInput;
3200fe9fd36SDavid McPaul		std::vector<media_input *>	fConnectedInputs;
3210fe9fd36SDavid McPaul		media_output				fOutput;
3220fe9fd36SDavid McPaul
3230fe9fd36SDavid McPaul		bigtime_t 					fDownstreamLatency;
3240fe9fd36SDavid McPaul		bigtime_t 					fInternalLatency;
3250fe9fd36SDavid McPaul
3260fe9fd36SDavid McPaul		BufferMixer					bufferMixer;
3270fe9fd36SDavid McPaul
3280fe9fd36SDavid McPaul};
3290fe9fd36SDavid McPaul
3300fe9fd36SDavid McPaul#endif /* _VIDEO_MIXER_NODE_H */