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