2 * Copyright (C) 2009-2010 David McPaul
4 * All rights reserved. Distributed under the terms of the MIT License.
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
13 #include "VideoMixerNode.h"
19 // -------------------------------------------------------- //
20 // implemention of BBufferProducer
21 // -------------------------------------------------------- //
23 // They are asking us to make the first offering.
24 // So, we get a fresh format and then add requirements
25 status_t
VideoMixerNode::FormatSuggestionRequested(
28 media_format
* format
)
30 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::FormatSuggestionRequested\n");
32 if (format
->type
== B_MEDIA_NO_TYPE
) {
33 format
->type
= B_MEDIA_RAW_VIDEO
;
36 if (format
->type
!= B_MEDIA_RAW_VIDEO
) {
37 return B_MEDIA_BAD_FORMAT
;
40 GetOutputFormat(format
);
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.
48 status_t
VideoMixerNode::FormatProposal(
49 const media_source
&output_source
,
52 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::FormatProposal\n");
54 fOutput
.source
= output_source
;
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
) {
60 fOutput
.format
= fConnectedInputs
[0]->format
;
61 fOutput
.format
.u
.raw_video
.display
.format
= B_NO_COLOR_SPACE
;
64 fOutput
.format
= fConnectedInputs
[0]->format
;
65 fOutput
.format
.u
.raw_video
.display
.format
= B_RGBA32
;
69 *format
= fOutput
.format
;
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.
78 status_t
VideoMixerNode::FormatChangeRequested(
79 const media_source
&source
,
80 const media_destination
&destination
,
81 media_format
*io_format
,
84 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::FormatChangeRequested\n");
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
;
92 fOutput
.destination
= destination
;
93 fOutput
.format
= *io_format
;
98 status_t
VideoMixerNode::GetNextOutput( /* cookie starts as 0 */
100 media_output
*out_output
)
102 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::GetNextOutput (%ld)\n",*cookie
);
106 fprintf(stderr
,"<- B_ERROR (no more outputs)\n");
110 *out_output
= fOutput
;
116 status_t
VideoMixerNode::DisposeOutputCookie(int32 cookie
)
118 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::DisposeOutputCookie\n");
119 // nothing to do since our cookies are part of the vector iterator
123 status_t
VideoMixerNode::SetBufferGroup(
124 const media_source
& for_source
,
125 BBufferGroup
* group
)
127 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::SetBufferGroup\n");
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
;
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 */
146 status_t
VideoMixerNode::VideoClippingChanged(
147 const media_source
& for_source
,
150 const media_video_display_info
& display
,
151 int32
* _deprecated_
)
153 return BBufferProducer::VideoClippingChanged(for_source
, num_shorts
, clip_data
, display
, _deprecated_
);
156 status_t
VideoMixerNode::GetLatency(
157 bigtime_t
*out_latency
)
159 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::GetLatency\n");
160 if (out_latency
== NULL
) {
161 fprintf(stderr
,"<- B_BAD_VALUE\n");
165 *out_latency
= EventLatency() + SchedulingLatency();
169 status_t
VideoMixerNode::PrepareToConnect(
170 const media_source
&what
,
171 const media_destination
&where
,
172 media_format
*format
,
173 media_source
*out_source
,
176 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::PrepareToConnect\n");
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
;
184 *out_source
= fOutput
.source
;
185 strcpy(out_name
, fOutput
.name
);
187 fOutput
.destination
= where
;
192 void VideoMixerNode::Connect(
194 const media_source
&source
,
195 const media_destination
&destination
,
196 const media_format
&format
,
199 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::Connect\n");
201 if (fOutput
.source
!= source
) {
202 // we don't have that output
203 fprintf(stderr
,"<- B_MEDIA_BAD_SOURCE\n");
208 fprintf(stderr
,"<- error already\n");
209 fOutput
.destination
= media_destination::null
;
210 fOutput
.format
.u
.raw_video
= media_raw_video_format::wildcard
;
214 // calculate the downstream latency
215 // must happen before itr->Connect
216 bigtime_t downstreamLatency
;
218 FindLatencyFor(fOutput
.destination
, &downstreamLatency
, &id
);
220 // record the agreed upon values
221 fOutput
.format
= format
;
222 fOutput
.destination
= destination
;
223 strcpy(io_name
, fOutput
.name
);
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();
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
);
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
);
246 void VideoMixerNode::Disconnect(
247 const media_source
& what
,
248 const media_destination
& where
)
250 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::Disconnect\n");
252 if (fOutput
.source
!= what
) {
253 // we don't have that output
254 fprintf(stderr
,"<- B_MEDIA_BAD_SOURCE\n");
258 if (fOutput
.destination
!= where
) {
259 fprintf(stderr
,"<- B_MEDIA_BAD_DESTINATION\n");
263 fOutput
.destination
= media_destination::null
;
264 GetOutputFormat(&fOutput
.format
);
267 void VideoMixerNode::LateNoticeReceived(
268 const media_source
& what
,
270 bigtime_t performance_time
)
272 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::LateNoticeReceived\n");
274 if (fOutput
.source
!= what
) {
275 // we don't have that output
276 fprintf(stderr
,"<- B_MEDIA_BAD_SOURCE\n");
287 case B_INCREASE_LATENCY
:
288 fInternalLatency
+= how_much
;
289 SetEventLatency(fDownstreamLatency
+ fInternalLatency
);
291 case B_DECREASE_PRECISION
:
292 // XXX: try to catch up by producing buffers faster
295 // XXX: should we really drop buffers? just for that output?
298 fprintf(stderr
,"VideoMixerNode::LateNoticeReceived with unexpected run mode.\n");
303 void VideoMixerNode::EnableOutput(
304 const media_source
&what
,
308 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::EnableOutput\n");
310 if (fOutput
.source
!= what
) {
311 // we don't have that output
312 fprintf(stderr
,"<- B_MEDIA_BAD_SOURCE\n");
316 status_t status
= B_OK
;
317 if (status
!= B_OK
) {
318 fprintf(stderr
," error in itr->EnableOutput\n");
322 status_t
VideoMixerNode::SetPlayRate(
326 BBufferProducer::SetPlayRate(numer
, denom
); // XXX: do something intelligent later
330 void VideoMixerNode::AdditionalBufferRequested( // used to be Reserved 0
331 const media_source
& source
,
332 media_buffer_id prev_buffer
,
334 const media_seek_tag
* prev_tag
)
336 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::AdditionalBufferRequested\n");
338 if (fOutput
.source
!= source
) {
339 // we don't have that output
340 fprintf(stderr
,"<- B_MEDIA_BAD_SOURCE\n");
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");
351 void VideoMixerNode::LatencyChanged(
352 const media_source
& source
,
353 const media_destination
& destination
,
354 bigtime_t new_latency
,
357 fprintf(stderr
,"VideoMixerNode(BBufferProducer)::LatencyChanged\n");
359 if (fOutput
.source
!= source
) {
360 // we don't have that output
361 fprintf(stderr
,"<- B_MEDIA_BAD_SOURCE\n");
365 if (fOutput
.destination
!= destination
) {
366 fprintf(stderr
,"<- B_MEDIA_BAD_DESTINATION\n");
370 fDownstreamLatency
= new_latency
;
371 SetEventLatency(fDownstreamLatency
+ fInternalLatency
);
373 // XXX: we may have to recompute the number of buffers that we are using
374 // see SetBufferGroup