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