xref: /haiku/src/add-ons/media/media-add-ons/video_mixer/VideoMixerNode.cpp (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
1 /*
2 * Copyright (C) 2009-2010 David McPaul
3 *
4 * All rights reserved. Distributed under the terms of the MIT License.
5 * VideoMixerNode.cpp
6 *
7 * The VideoMixerNode class takes in multiple video streams and supplies
8 * a single stream as the output.
9 * each stream is converted to the same colourspace and should match
10 * either the primary input OR the requested colourspace from the output
11 * destination.
12 *
13 * The first input is considered the primary input
14 * subsequent input framesize should match the primary input framesize
15 * The output framerate will be the same as the primary input
16 *
17 */
18 
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include "VideoMixerNode.h"
23 
24 VideoMixerNode::~VideoMixerNode(void)
25 {
26 	fprintf(stderr,"VideoMixerNode::~VideoMixerNode\n");
27 	// Stop the BMediaEventLooper thread
28 	Quit();
29 }
30 
31 VideoMixerNode::VideoMixerNode(
32 				const flavor_info *info = 0,
33 				BMessage *config = 0,
34 				BMediaAddOn *addOn = 0)
35 	: BMediaNode("VideoMixerNode"),
36   	  BBufferConsumer(B_MEDIA_RAW_VIDEO),	// Raw video buffers in
37   	  BBufferProducer(B_MEDIA_RAW_VIDEO),	// Raw video buffers out
38 	  BMediaEventLooper()
39 {
40 	fprintf(stderr,"VideoMixerNode::VideoMixerNode\n");
41 	// keep our creator around for AddOn calls later
42 	fAddOn = addOn;
43 	// NULL out our latency estimates
44 	fDownstreamLatency = 0;
45 	fInternalLatency = 0;
46 
47 	// Start with 1 input and 1 output
48 	ClearInput(&fInitialInput);
49 
50 	strncpy(fOutput.name,"VideoMixer Output", B_MEDIA_NAME_LENGTH-1);
51 	fOutput.name[B_MEDIA_NAME_LENGTH-1] = '\0';
52 
53 	// initialize the output
54 	fOutput.node = media_node::null;               // until registration
55 	fOutput.destination = media_destination::null;
56 	fOutput.source.port = ControlPort();
57 	fOutput.source.id = 0;
58 
59 	GetOutputFormat(&fOutput.format);
60 
61 	fInitCheckStatus = B_OK;
62 }
63 
64 void VideoMixerNode::NodeRegistered(void)
65 {
66 	fprintf(stderr,"VideoMixerNode::NodeRegistered\n");
67 
68 	// for every node created so far set to this Node;
69 	for (uint32 i=0;i<fConnectedInputs.size();i++) {
70 		fConnectedInputs[i]->node = Node();
71 		fConnectedInputs[i]->destination.id = i;
72 		fConnectedInputs[i]->destination.port = ControlPort();
73 	}
74 
75 	fInitialInput.node = Node();
76 	fInitialInput.destination.id = fConnectedInputs.size();
77 	fInitialInput.destination.port = ControlPort();
78 
79 	GetOutputFormat(&fOutput.format);
80 	fOutput.node = Node();
81 
82 	// start the BMediaEventLooper thread
83 	SetPriority(B_REAL_TIME_PRIORITY);
84 	Run();
85 }
86 
87 media_input *
88 VideoMixerNode::CreateInput(uint32 inputID) {
89 	media_input *input = new media_input();
90 
91 	ClearInput(input);
92 
93 	// don't overwrite available space, and be sure to terminate
94 	sprintf(input->name, "VideoMixer Input %ld", inputID);
95 
96 	return input;
97 }
98 
99 void
100 VideoMixerNode::ClearInput(media_input *input) {
101 
102 	// initialize the input
103 	sprintf(input->name, "VideoMixer Input");
104 	input->node = Node();
105 	input->source = media_source::null;
106 	input->destination = media_destination::null;
107 
108 	GetInputFormat(&input->format);
109 }
110 
111 media_input *
112 VideoMixerNode::GetInput(const media_source &source) {
113 
114 	vector<media_input *>::iterator each;
115 
116 	for (each=fConnectedInputs.begin(); each<fConnectedInputs.end(); each++) {
117 		if ((*each)->source == source) {
118 			return *each;
119 		}
120 	}
121 
122 	return NULL;
123 }
124 
125 media_input *
126 VideoMixerNode::GetInput(const media_destination &destination) {
127 
128 	vector<media_input *>::iterator each;
129 
130 	for (each=fConnectedInputs.begin(); each<fConnectedInputs.end(); each++) {
131 		if ((*each)->destination == destination) {
132 			return *each;
133 		}
134 	}
135 
136 	return NULL;
137 }
138 
139 media_input *
140 VideoMixerNode::GetInput(const int32 id) {
141 
142 	vector<media_input *>::iterator each;
143 
144 	for (each=fConnectedInputs.begin(); each<fConnectedInputs.end(); each++) {
145 		if ((*each)->destination.id == id) {
146 			return *each;
147 		}
148 	}
149 
150 	return NULL;
151 }
152 
153 status_t VideoMixerNode::InitCheck(void) const
154 {
155 	fprintf(stderr,"VideoMixerNode::InitCheck\n");
156 	return fInitCheckStatus;
157 }
158 
159 status_t VideoMixerNode::GetConfigurationFor(
160 				BMessage *into_message)
161 {
162 	fprintf(stderr,"VideoMixerNode::GetConfigurationFor\n");
163 	return B_OK;
164 }
165 
166 // -------------------------------------------------------- //
167 // implementation of BMediaNode
168 // -------------------------------------------------------- //
169 
170 BMediaAddOn *VideoMixerNode::AddOn(
171 				int32 *internal_id) const
172 {
173 	fprintf(stderr,"VideoMixerNode::AddOn\n");
174 	// BeBook says this only gets called if we were in an add-on.
175 	if (fAddOn != NULL) {
176 		// If we get a null pointer then we just won't write.
177 		if (internal_id != NULL) {
178 			internal_id = 0;
179 		}
180 	}
181 	return fAddOn;
182 }
183 
184 void VideoMixerNode::Start(bigtime_t performance_time)
185 {
186 	fprintf(stderr,"VideoMixerNode::Start(pt=%lld)\n", performance_time);
187 	BMediaEventLooper::Start(performance_time);
188 }
189 
190 void VideoMixerNode::Stop(
191 				bigtime_t performance_time,
192 				bool immediate)
193 {
194 	if (immediate) {
195 		fprintf(stderr,"VideoMixerNode::Stop(pt=%lld,<immediate>)\n", performance_time);
196 	} else {
197 		fprintf(stderr,"VideoMixerNode::Stop(pt=%lld,<scheduled>)\n", performance_time);
198 	}
199 	BMediaEventLooper::Stop(performance_time, immediate);
200 }
201 
202 void VideoMixerNode::Seek(
203 				bigtime_t media_time,
204 				bigtime_t performance_time)
205 {
206 	fprintf(stderr,"VideoMixerNode::Seek(mt=%lld,pt=%lld)\n", media_time,performance_time);
207 	BMediaEventLooper::Seek(media_time, performance_time);
208 }
209 
210 void VideoMixerNode::SetRunMode(run_mode mode)
211 {
212 	fprintf(stderr,"VideoMixerNode::SetRunMode(%i)\n", mode);
213 	BMediaEventLooper::SetRunMode(mode);
214 }
215 
216 void VideoMixerNode::TimeWarp(
217 				bigtime_t at_real_time,
218 				bigtime_t to_performance_time)
219 {
220 	fprintf(stderr,"VideoMixerNode::TimeWarp(rt=%lld,pt=%lld)\n", at_real_time, to_performance_time);
221 	BMediaEventLooper::TimeWarp(at_real_time, to_performance_time);
222 }
223 
224 void VideoMixerNode::Preroll(void)
225 {
226 	fprintf(stderr,"VideoMixerNode::Preroll\n");
227 	// XXX:Performance opportunity
228 	BMediaNode::Preroll();
229 }
230 
231 void VideoMixerNode::SetTimeSource(BTimeSource *time_source)
232 {
233 	fprintf(stderr,"VideoMixerNode::SetTimeSource\n");
234 	BMediaNode::SetTimeSource(time_source);
235 }
236 
237 status_t VideoMixerNode::HandleMessage(
238 				int32 message,
239 				const void *data,
240 				size_t size)
241 {
242 	fprintf(stderr,"VideoMixerNode::HandleMessage\n");
243 	status_t status = B_OK;
244 	switch (message) {
245 		// no special messages for now
246 		default:
247 			status = BBufferConsumer::HandleMessage(message, data, size);
248 			if (status == B_OK) {
249 				break;
250 			}
251 			status = BBufferProducer::HandleMessage(message, data, size);
252 			if (status == B_OK) {
253 				break;
254 			}
255 			status = BMediaNode::HandleMessage(message, data, size);
256 			if (status == B_OK) {
257 				break;
258 			}
259 			BMediaNode::HandleBadMessage(message, data, size);
260 			status = B_ERROR;
261 			break;
262 	}
263 	return status;
264 }
265 
266 status_t VideoMixerNode::RequestCompleted(const media_request_info &info)
267 {
268 	fprintf(stderr,"VideoMixerNode::RequestCompleted\n");
269 	return BMediaNode::RequestCompleted(info);
270 }
271 
272 status_t VideoMixerNode::DeleteHook(BMediaNode *node)
273 {
274 	fprintf(stderr,"VideoMixerNode::DeleteHook\n");
275 	return BMediaEventLooper::DeleteHook(node);
276 }
277 
278 status_t VideoMixerNode::GetNodeAttributes(
279 				media_node_attribute *outAttributes,
280 				size_t inMaxCount)
281 {
282 	fprintf(stderr,"VideoMixerNode::GetNodeAttributes\n");
283 	return BMediaNode::GetNodeAttributes(outAttributes, inMaxCount);
284 }
285 
286 status_t VideoMixerNode::AddTimer(
287 					bigtime_t at_performance_time,
288 					int32 cookie)
289 {
290 	fprintf(stderr,"VideoMixerNode::AddTimer\n");
291 	return BMediaEventLooper::AddTimer(at_performance_time, cookie);
292 }
293 
294 // -------------------------------------------------------- //
295 // VideoMixerNode specific functions
296 // -------------------------------------------------------- //
297 
298 // public:
299 
300 void VideoMixerNode::GetFlavor(flavor_info *outInfo, int32 id)
301 {
302 	fprintf(stderr,"VideoMixerNode::GetFlavor\n");
303 
304 	if (outInfo != NULL) {
305 		outInfo->internal_id = id;
306 		outInfo->name = "Haiku VideoMixer";
307 		outInfo->info = "A VideoMixerNode node mixes multiple video streams into a single stream.";
308 		outInfo->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER;
309 		outInfo->flavor_flags = B_FLAVOR_IS_LOCAL;
310 		outInfo->possible_count = INT_MAX;	// no limit
311 		outInfo->in_format_count = 1;
312 		media_format *inFormats = new media_format[outInfo->in_format_count];
313 		GetInputFormat(&inFormats[0]);
314 		outInfo->in_formats = inFormats;
315 		outInfo->out_format_count = 1; // single output
316 		media_format *outFormats = new media_format[outInfo->out_format_count];
317 		GetOutputFormat(&outFormats[0]);
318 		outInfo->out_formats = outFormats;
319 	}
320 }
321 
322 void VideoMixerNode::GetInputFormat(media_format *outFormat)
323 {
324 	fprintf(stderr,"VideoMixerNode::GetInputFormat\n");
325 
326 	if (outFormat != NULL) {
327 		outFormat->type = B_MEDIA_RAW_VIDEO;
328 		outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
329 		outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
330 		outFormat->u.raw_video = media_raw_video_format::wildcard;
331 	}
332 }
333 
334 void VideoMixerNode::GetOutputFormat(media_format *outFormat)
335 {
336 	fprintf(stderr,"VideoMixerNode::GetOutputFormat\n");
337 	if (outFormat != NULL) {
338 		outFormat->type = B_MEDIA_RAW_VIDEO;
339 		outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
340 		outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
341 		outFormat->u.raw_video = media_raw_video_format::wildcard;
342 	}
343 }
344 
345 // protected:
346 
347 status_t VideoMixerNode::AddRequirements(media_format *format)
348 {
349 	fprintf(stderr,"VideoMixerNode::AddRequirements\n");
350 	return B_OK;
351 }
352