xref: /haiku/src/add-ons/media/media-add-ons/video_mixer/VideoMixerNodeProducer.cpp (revision 0d452c8f34013b611a54c746a71c05e28796eae2)
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
8 * takes in multiple video streams and supplies
9 * a single stream as the output.
10 * each stream is converted to the same colourspace
11 */
12 
13 #include "VideoMixerNode.h"
14 
15 // -------------------------------------------------------- //
16 // implemention of BBufferProducer
17 // -------------------------------------------------------- //
18 
19 // They are asking us to make the first offering.
20 // So, we get a fresh format and then add requirements
21 status_t VideoMixerNode::FormatSuggestionRequested(
22 				media_type type,
23 				int32 quality,
24 				media_format * format)
25 {
26 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::FormatSuggestionRequested\n");
27 
28 	if (format->type == B_MEDIA_NO_TYPE) {
29 		format->type = B_MEDIA_RAW_VIDEO;
30 	}
31 
32 	if (format->type != B_MEDIA_RAW_VIDEO) {
33 		return B_MEDIA_BAD_FORMAT;
34 	}
35 
36 	GetOutputFormat(format);
37 
38 	return B_OK;
39 }
40 
41 // They made an offer to us.  We should make sure that the offer is
42 // acceptable, and then we can add any requirements we have on top of
43 // that.  We leave wildcards for anything that we don't care about.
44 status_t VideoMixerNode::FormatProposal(
45 				const media_source &output_source,
46 				media_format *format)
47 {
48 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::FormatProposal\n");
49 
50 	fOutput.source = output_source;
51 
52 	// If we have an input then set our output as the same except for color_space
53 	if (fConnectedInputs.size() > 0) {
54 		if (fOutput.format.u.raw_video == media_raw_video_format::wildcard) {
55 			// First proposal
56 			fOutput.format = fConnectedInputs[0]->format;
57 			fOutput.format.u.raw_video.display.format = B_NO_COLOR_SPACE;
58 		} else {
59 			// Second proposal
60 			fOutput.format = fConnectedInputs[0]->format;
61 			fOutput.format.u.raw_video.display.format = B_RGBA32;
62 		}
63 	}
64 
65 	*format = fOutput.format;
66 
67 	return B_OK;
68 }
69 
70 // Presumably we have already agreed with them that this format is
71 // okay.  But just in case, we check the offer. (and complain if it
72 // is invalid)  Then as the last thing we do, we get rid of any
73 // remaining wilcards.
74 status_t VideoMixerNode::FormatChangeRequested(
75 				const media_source &source,
76 				const media_destination &destination,
77 				media_format *io_format,
78 				int32 * _deprecated_)
79 {
80 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::FormatChangeRequested\n");
81 
82 	if (fOutput.source != source) {
83 		// we don't have that output
84 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
85 		return B_MEDIA_BAD_SOURCE;
86 	}
87 
88 	fOutput.destination = destination;
89 	fOutput.format = *io_format;
90 
91 	return B_OK;
92 }
93 
94 status_t VideoMixerNode::GetNextOutput(	/* cookie starts as 0 */
95 				int32 *cookie,
96 				media_output *out_output)
97 {
98 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::GetNextOutput (%ld)\n",*cookie);
99 
100 	// only 1 output
101 	if (*cookie != 0) {
102 		fprintf(stderr,"<- B_ERROR (no more outputs)\n");
103 		return B_ERROR;
104 	}
105 
106 	*out_output = fOutput;
107 	*cookie = 1;
108 
109 	return B_OK;
110 }
111 
112 status_t VideoMixerNode::DisposeOutputCookie(int32 cookie)
113 {
114 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::DisposeOutputCookie\n");
115 	// nothing to do since our cookies are part of the vector iterator
116 	return B_OK;
117 }
118 
119 status_t VideoMixerNode::SetBufferGroup(
120 				const media_source & for_source,
121 				BBufferGroup * group)
122 {
123 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::SetBufferGroup\n");
124 
125 	if (fOutput.source != for_source) {
126 		// we don't have that output
127 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
128 		return B_MEDIA_BAD_SOURCE;
129 	}
130 
131 	return B_OK;
132 }
133 
134 	/* Format of clipping is (as int16-s): <from line> <npairs> <startclip> <endclip>. */
135 	/* Repeat for each line where the clipping is different from the previous line. */
136 	/* If <npairs> is negative, use the data from line -<npairs> (there are 0 pairs after */
137 	/* a negative <npairs>. Yes, we only support 32k*32k frame buffers for clipping. */
138 	/* Any non-0 field of 'display' means that that field changed, and if you don't support */
139 	/* that change, you should return an error and ignore the request. Note that the buffer */
140 	/* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */
141 	/* be adhered to. */
142 status_t VideoMixerNode::VideoClippingChanged(
143 				const media_source & for_source,
144 				int16 num_shorts,
145 				int16 * clip_data,
146 				const media_video_display_info & display,
147 				int32 * _deprecated_)
148 {
149 	return BBufferProducer::VideoClippingChanged(for_source, num_shorts, clip_data, display, _deprecated_);
150 }
151 
152 status_t VideoMixerNode::GetLatency(
153 				bigtime_t *out_latency)
154 {
155 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::GetLatency\n");
156 	if (out_latency == NULL) {
157 		fprintf(stderr,"<- B_BAD_VALUE\n");
158 		return B_BAD_VALUE;
159 	}
160 
161 	*out_latency = EventLatency() + SchedulingLatency();
162 	return B_OK;
163 }
164 
165 status_t VideoMixerNode::PrepareToConnect(
166 				const media_source &what,
167 				const media_destination &where,
168 				media_format *format,
169 				media_source *out_source,
170 				char *out_name)
171 {
172 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::PrepareToConnect\n");
173 
174 	if (fOutput.source != what) {
175 		// we don't have that output
176 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
177 		return B_MEDIA_BAD_SOURCE;
178 	}
179 
180 	*out_source = fOutput.source;
181 	strcpy(out_name, fOutput.name);
182 
183 	fOutput.destination = where;
184 
185 	return B_OK;
186 }
187 
188 void VideoMixerNode::Connect(
189 				status_t error,
190 				const media_source &source,
191 				const media_destination &destination,
192 				const media_format &format,
193 				char *io_name)
194 {
195 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::Connect\n");
196 
197 	if (fOutput.source != source) {
198 		// we don't have that output
199 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
200 		return;
201 	}
202 
203 	if (error != B_OK) {
204 		fprintf(stderr,"<- error already\n");
205 		fOutput.destination = media_destination::null;
206 		fOutput.format.u.raw_video = media_raw_video_format::wildcard;
207 		return;
208 	}
209 
210 	// calculate the downstream latency
211 	// must happen before itr->Connect
212 	bigtime_t downstreamLatency;
213 	media_node_id id;
214 	FindLatencyFor(fOutput.destination, &downstreamLatency, &id);
215 
216 	// record the agreed upon values
217 	fOutput.format = format;
218 	fOutput.destination = destination;
219 	strcpy(io_name, fOutput.name);
220 
221 	// compute the internal latency
222 	// must happen after itr->Connect
223 	if (fInternalLatency == 0) {
224 		fInternalLatency = 100; // temporary until we finish computing it
225 		ComputeInternalLatency();
226 	}
227 
228 	// If the downstream latency for this output is larger
229 	// than our current downstream latency, we have to increase
230 	// our current downstream latency to be the larger value.
231 	if (downstreamLatency > fDownstreamLatency) {
232 		SetEventLatency(fDownstreamLatency + fInternalLatency);
233 	}
234 }
235 
236 void VideoMixerNode::ComputeInternalLatency() {
237 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::ComputeInternalLatency\n");
238 	fInternalLatency = 100; // just guess
239 	fprintf(stderr,"  internal latency guessed = %lld\n",fInternalLatency);
240 }
241 
242 void VideoMixerNode::Disconnect(
243 				const media_source & what,
244 				const media_destination & where)
245 {
246 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::Disconnect\n");
247 
248 	if (fOutput.source != what) {
249 		// we don't have that output
250 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
251 		return;
252 	}
253 
254 	if (fOutput.destination != where) {
255 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
256 		return;
257 	}
258 
259 	fOutput.destination = media_destination::null;
260 	GetOutputFormat(&fOutput.format);
261 }
262 
263 void VideoMixerNode::LateNoticeReceived(
264 				const media_source & what,
265 				bigtime_t how_much,
266 				bigtime_t performance_time)
267 {
268 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::LateNoticeReceived\n");
269 
270 	if (fOutput.source != what) {
271 		// we don't have that output
272 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
273 		return;
274 	}
275 
276 	switch (RunMode()) {
277 		case B_OFFLINE:
278 		    // nothing to do
279 			break;
280 		case B_RECORDING:
281 		    // nothing to do
282 			break;
283 		case B_INCREASE_LATENCY:
284 			fInternalLatency += how_much;
285 			SetEventLatency(fDownstreamLatency + fInternalLatency);
286 			break;
287 		case B_DECREASE_PRECISION:
288 			// XXX: try to catch up by producing buffers faster
289 			break;
290 		case B_DROP_DATA:
291 			// XXX: should we really drop buffers?  just for that output?
292 			break;
293 		default:
294 			fprintf(stderr,"VideoMixerNode::LateNoticeReceived with unexpected run mode.\n");
295 			break;
296 	}
297 }
298 
299 void VideoMixerNode::EnableOutput(
300 				const media_source &what,
301 				bool enabled,
302 				int32 *_deprecated_)
303 {
304 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::EnableOutput\n");
305 
306 	if (fOutput.source != what) {
307 		// we don't have that output
308 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
309 		return;
310 	}
311 
312 	status_t status = B_OK;
313 	if (status != B_OK) {
314 		fprintf(stderr,"  error in itr->EnableOutput\n");
315 	}
316 }
317 
318 status_t VideoMixerNode::SetPlayRate(
319 				int32 numer,
320 				int32 denom)
321 {
322 	BBufferProducer::SetPlayRate(numer, denom); // XXX: do something intelligent later
323 	return B_OK;
324 }
325 
326 void VideoMixerNode::AdditionalBufferRequested(			//	used to be Reserved 0
327 				const media_source & source,
328 				media_buffer_id prev_buffer,
329 				bigtime_t prev_time,
330 				const media_seek_tag * prev_tag)
331 {
332 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::AdditionalBufferRequested\n");
333 
334 	if (fOutput.source != source) {
335 		// we don't have that output
336 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
337 		return;
338 	}
339 
340 //	BBuffer * buffer;
341 //	status_t status = itr->AdditionalBufferRequested(prev_buffer, prev_time, prev_tag);
342 //	if (status != B_OK) {
343 //		fprintf(stderr,"  itr->AdditionalBufferRequested returned an error.\n");
344 //	}
345 }
346 
347 void VideoMixerNode::LatencyChanged(
348 				const media_source & source,
349 				const media_destination & destination,
350 				bigtime_t new_latency,
351 				uint32 flags)
352 {
353 	fprintf(stderr,"VideoMixerNode(BBufferProducer)::LatencyChanged\n");
354 
355 	if (fOutput.source != source) {
356 		// we don't have that output
357 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
358 		return;
359 	}
360 
361 	if (fOutput.destination != destination) {
362 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
363 		return;
364 	}
365 
366 	fDownstreamLatency = new_latency;
367 	SetEventLatency(fDownstreamLatency + fInternalLatency);
368 
369 	// XXX: we may have to recompute the number of buffers that we are using
370 	// see SetBufferGroup
371 }
372