1/*
2* Copyright (C) 2009-2010 David McPaul
3*
4* All rights reserved. Distributed under the terms of the MIT License.
5*/
6
7#ifndef _VIDEO_MIXER_NODE_H
8#define _VIDEO_MIXER_NODE_H
9
10#include <Buffer.h>
11#include <BufferConsumer.h>
12#include <BufferGroup.h>
13#include <BufferProducer.h>
14#include <MediaAddOn.h>
15#include <MediaDefs.h>
16#include <MediaEventLooper.h>
17#include <MediaNode.h>
18#include <TimeSource.h>
19
20#include <vector>
21
22#include "BufferMixer.h"
23
24class VideoMixerNode :
25	public BBufferConsumer,
26	public BBufferProducer,
27    public BMediaEventLooper
28{
29protected:
30virtual ~VideoMixerNode(void);
31
32public:
33
34explicit VideoMixerNode(
35				const flavor_info * info = 0,
36				BMessage *config = 0,
37				BMediaAddOn *addOn = 0);
38
39virtual status_t InitCheck(void) const;
40
41// see BMediaAddOn::GetConfigurationFor
42virtual	status_t GetConfigurationFor(
43				BMessage *into_message);
44
45public:
46//	/* this port is what a media node listens to for commands */
47// virtual port_id ControlPort(void) const;
48
49virtual	BMediaAddOn* AddOn(
50				int32 *internal_id) const;	/* Who instantiated you -- or NULL for app class */
51
52protected:
53		/* These don't return errors; instead, they use the global error condition reporter. */
54		/* A node is required to have a queue of at least one pending command (plus TimeWarp) */
55		/* and is recommended to allow for at least one pending command of each type. */
56		/* Allowing an arbitrary number of outstanding commands might be nice, but apps */
57		/* cannot depend on that happening. */
58virtual	void Start(
59				bigtime_t performance_time);
60virtual	void Stop(
61				bigtime_t performance_time,
62				bool immediate);
63virtual	void Seek(
64				bigtime_t media_time,
65				bigtime_t performance_time);
66virtual	void SetRunMode(
67				run_mode mode);
68virtual	void TimeWarp(
69				bigtime_t at_real_time,
70				bigtime_t to_performance_time);
71virtual	void Preroll(void);
72virtual	void SetTimeSource(BTimeSource *time_source);
73
74public:
75virtual	status_t HandleMessage(
76				int32 message,
77				const void *data,
78				size_t size);
79
80protected:
81		/* Called when requests have completed, or failed. */
82virtual	status_t RequestCompleted(	/* reserved 0 */
83				const media_request_info &info);
84
85protected:
86virtual		status_t DeleteHook(BMediaNode *node);		/* reserved 1 */
87
88virtual		void NodeRegistered(void);	/* reserved 2 */
89
90public:
91
92		/* fill out your attributes in the provided array, returning however many you have. */
93virtual		status_t GetNodeAttributes(	/* reserved 3 */
94					media_node_attribute *outAttributes,
95					size_t inMaxCount);
96
97virtual		status_t AddTimer(
98					bigtime_t at_performance_time,
99					int32 cookie);
100
101	/* Someone, probably the producer, is asking you about this format. Give */
102	/* your honest opinion, possibly modifying *format. Do not ask upstream */
103	/* producer about the format, since he's synchronously waiting for your */
104	/* reply. */
105virtual	status_t AcceptFormat(
106				const media_destination &dest,
107				media_format *format);
108virtual	status_t GetNextInput(
109				int32 * cookie,
110				media_input *out_input);
111virtual	void DisposeInputCookie(int32 cookie);
112virtual	void BufferReceived(BBuffer *buffer);
113virtual	void ProducerDataStatus(
114				const media_destination &for_whom,
115				int32 status,
116				bigtime_t at_performance_time);
117virtual	status_t GetLatencyFor(
118				const media_destination &for_whom,
119				bigtime_t *out_latency,
120				media_node_id *out_timesource);
121virtual	status_t Connected(
122				const media_source &producer,	/* here's a good place to request buffer group usage */
123				const media_destination &where,
124				const media_format &with_format,
125				media_input *out_input);
126virtual	void Disconnected(
127				const media_source &producer,
128				const media_destination &where);
129	/* The notification comes from the upstream producer, so he's already cool with */
130	/* the format; you should not ask him about it in here. */
131virtual	status_t FormatChanged(
132				const media_source &producer,
133				const media_destination &consumer,
134				int32 change_tag,
135				const media_format &format);
136
137	/* Given a performance time of some previous buffer, retrieve the remembered tag */
138	/* of the closest (previous or exact) performance time. Set *out_flags to 0; the */
139	/* idea being that flags can be added later, and the understood flags returned in */
140	/* *out_flags. */
141virtual	status_t SeekTagRequested(
142				const media_destination &destination,
143				bigtime_t in_target_time,
144				uint32 in_flags,
145				media_seek_tag *out_seek_tag,
146				bigtime_t *out_tagged_time,
147				uint32 *out_flags);
148
149
150protected:
151	/* functionality of BBufferProducer */
152virtual	status_t FormatSuggestionRequested(
153				media_type type,
154				int32 quality,
155				media_format *format);
156virtual	status_t FormatProposal(
157				const media_source &output,
158				media_format *format);
159	/* If the format isn't good, put a good format into *io_format and return error */
160	/* If format has wildcard, specialize to what you can do (and change). */
161	/* If you can change the format, return OK. */
162	/* The request comes from your destination sychronously, so you cannot ask it */
163	/* whether it likes it -- you should assume it will since it asked. */
164virtual	status_t FormatChangeRequested(
165				const media_source &source,
166				const media_destination &destination,
167				media_format *io_format,
168				int32 *_deprecated_);
169virtual	status_t GetNextOutput(	/* cookie starts as 0 */
170				int32 *cookie,
171				media_output *out_output);
172virtual	status_t DisposeOutputCookie(
173				int32 cookie);
174	/* In this function, you should either pass on the group to your upstream guy, */
175	/* or delete your current group and hang on to this group. Deleting the previous */
176	/* group (unless you passed it on with the reclaim flag set to false) is very */
177	/* important, else you will 1) leak memory and 2) block someone who may want */
178	/* to reclaim the buffers living in that group. */
179virtual	status_t SetBufferGroup(
180				const media_source &for_source,
181				BBufferGroup * group);
182	/* Format of clipping is (as int16-s): <from line> <npairs> <startclip> <endclip>. */
183	/* Repeat for each line where the clipping is different from the previous line. */
184	/* If <npairs> is negative, use the data from line -<npairs> (there are 0 pairs after */
185	/* a negative <npairs>. Yes, we only support 32k*32k frame buffers for clipping. */
186	/* Any non-0 field of 'display' means that that field changed, and if you don't support */
187	/* that change, you should return an error and ignore the request. Note that the buffer */
188	/* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */
189	/* be adhered to. */
190virtual	status_t VideoClippingChanged(
191				const media_source &for_source,
192				int16 num_shorts,
193				int16 *clip_data,
194				const media_video_display_info &display,
195				int32 *_deprecated_);
196	/* Iterates over all outputs and maxes the latency found */
197virtual	status_t GetLatency(bigtime_t *out_latency);
198virtual	status_t PrepareToConnect(
199				const media_source &what,
200				const media_destination &where,
201				media_format *format,
202				media_source *out_source,
203				char *out_name);
204virtual	void Connect(
205				status_t error,
206				const media_source &source,
207				const media_destination &destination,
208				const media_format &format,
209				char *io_name);
210virtual	void Disconnect(
211				const media_source &what,
212				const media_destination &where);
213virtual	void LateNoticeReceived(
214				const media_source &what,
215				bigtime_t how_much,
216				bigtime_t performance_time);
217virtual	void EnableOutput(
218				const media_source &what,
219				bool enabled,
220				int32 *_deprecated_);
221virtual	status_t SetPlayRate(
222				int32 numer,
223				int32 denom);
224
225virtual	void AdditionalBufferRequested(			//	used to be Reserved 0
226				const media_source & source,
227				media_buffer_id prev_buffer,
228				bigtime_t prev_time,
229				const media_seek_tag *prev_tag);	//	may be NULL
230
231virtual	void LatencyChanged(					//	used to be Reserved 1
232				const media_source & source,
233				const media_destination & destination,
234				bigtime_t new_latency,
235				uint32 flags);
236
237
238	protected:
239		/* you must override to handle your events! */
240		/* you should not call HandleEvent directly */
241		virtual void		HandleEvent(	const media_timed_event *event,
242											bigtime_t lateness,
243											bool realTimeEvent = false);
244
245		/* override to clean up custom events you have added to your queue */
246		virtual void		CleanUpEvent(const media_timed_event *event);
247
248		/* called from Offline mode to determine the current time of the node */
249		/* update your internal information whenever it changes */
250		virtual	bigtime_t	OfflineTime();
251
252		/* override only if you know what you are doing! */
253		/* otherwise much badness could occur */
254		/* the actual control loop function: */
255		/* 	waits for messages, Pops events off the queue and calls DispatchEvent */
256		virtual void		ControlLoop();
257
258
259protected:
260
261virtual status_t HandleStart(
262						const media_timed_event *event,
263						bigtime_t lateness,
264						bool realTimeEvent = false);
265virtual status_t HandleSeek(
266						const media_timed_event *event,
267						bigtime_t lateness,
268						bool realTimeEvent = false);
269virtual status_t HandleWarp(
270						const media_timed_event *event,
271						bigtime_t lateness,
272						bool realTimeEvent = false);
273virtual status_t HandleStop(
274						const media_timed_event *event,
275						bigtime_t lateness,
276						bool realTimeEvent = false);
277virtual status_t HandleBuffer(
278						const media_timed_event *event,
279						bigtime_t lateness,
280						bool realTimeEvent = false);
281virtual status_t HandleDataStatus(
282						const media_timed_event *event,
283						bigtime_t lateness,
284						bool realTimeEvent = false);
285virtual status_t HandleParameter(
286						const media_timed_event *event,
287						bigtime_t lateness,
288						bool realTimeEvent = false);
289
290protected:
291
292//void CreateBufferGroup(MediaOutputInfo *output_info);
293void ComputeInternalLatency();
294
295public:
296
297static void GetFlavor(flavor_info *outInfo, int32 id);
298
299private:
300	media_input 	*CreateInput(uint32 inputID);
301	void			ClearInput(media_input *input);
302	media_input		*GetInput(const media_source &source);
303	media_input		*GetInput(const media_destination &destination);
304	media_input		*GetInput(const int32 id);
305
306static void GetInputFormat(media_format *outFormat);
307static void GetOutputFormat(media_format *outFormat);
308
309protected:
310
311virtual status_t AddRequirements(media_format *format);
312
313private:
314
315		status_t 					fInitCheckStatus;
316
317		BMediaAddOn 				*fAddOn;
318
319		media_input					fInitialInput;
320		std::vector<media_input *>	fConnectedInputs;
321		media_output				fOutput;
322
323		bigtime_t 					fDownstreamLatency;
324		bigtime_t 					fInternalLatency;
325
326		BufferMixer					bufferMixer;
327
328};
329
330#endif /* _VIDEO_MIXER_NODE_H */
331