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 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. 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. 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 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 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 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. */ 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 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 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 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 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 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 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 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 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 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 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