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