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