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 17 18 // -------------------------------------------------------- // 19 // implemention of BBufferConsumer 20 // -------------------------------------------------------- // 21 22 // Check to make sure the format is okay, then remove 23 // any wildcards corresponding to our requirements. 24 status_t VideoMixerNode::AcceptFormat( 25 const media_destination &dest, 26 media_format *format) 27 { 28 fprintf(stderr,"VideoMixerNode(BBufferConsumer)::AcceptFormat\n"); 29 30 if (fInitialInput.destination != dest) { 31 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION"); 32 return B_MEDIA_BAD_DESTINATION; // none of our inputs matched the dest 33 } 34 35 media_format myFormat; 36 37 GetInputFormat(&myFormat); 38 39 AddRequirements(format); 40 41 return B_OK; 42 } 43 44 status_t VideoMixerNode::GetNextInput( 45 int32 *cookie, 46 media_input *out_input) 47 { 48 fprintf(stderr,"VideoMixerNode(BBufferConsumer)::GetNextInput (%ld)\n",*cookie); 49 50 // Cookie 0 is the connecting input, all others are connected inputs 51 if (uint32(*cookie) == fConnectedInputs.size()) { 52 *out_input = fInitialInput; 53 } else { 54 out_input = GetInput(*cookie); 55 56 if (out_input == NULL) { 57 fprintf(stderr,"<- B_ERROR (no more inputs)\n"); 58 return B_ERROR; 59 } 60 } 61 62 // so next time they won't get the same input again 63 (*cookie)++; 64 65 return B_OK; 66 } 67 68 void VideoMixerNode::DisposeInputCookie( 69 int32 cookie) 70 { 71 fprintf(stderr,"VideoMixerNode(BBufferConsumer)::DisposeInputCookie\n"); 72 // nothing to do since our cookies are just integers 73 } 74 75 void VideoMixerNode::BufferReceived(BBuffer *buffer) 76 { 77 switch (buffer->Header()->type) { 78 // case B_MEDIA_PARAMETERS: 79 // { 80 // status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed()); 81 // if (status != B_OK) { 82 // fprintf(stderr,"ApplyParameterData in MediaDemultiplexerNode::BufferReceived failed\n"); 83 // } 84 // buffer->Recycle(); 85 // } 86 // break; 87 case B_MEDIA_RAW_VIDEO: 88 if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) { 89 fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in VideoMixerNode::BufferReceived\n"); 90 // XXX: implement this part 91 buffer->Recycle(); 92 } else { 93 media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER, 94 buffer, BTimedEventQueue::B_RECYCLE_BUFFER); 95 status_t status = EventQueue()->AddEvent(event); 96 if (status != B_OK) { 97 fprintf(stderr,"EventQueue()->AddEvent(event) in VideoMixerNode::BufferReceived failed\n"); 98 buffer->Recycle(); 99 } 100 } 101 break; 102 default: 103 fprintf(stderr,"unexpected buffer type in VideoMixerNode::BufferReceived\n"); 104 buffer->Recycle(); 105 break; 106 } 107 } 108 109 void VideoMixerNode::ProducerDataStatus( 110 const media_destination &for_whom, 111 int32 status, 112 bigtime_t at_performance_time) 113 { 114 fprintf(stderr,"VideoMixerNode(BBufferConsumer)::ProducerDataStatus\n"); 115 media_input *input = GetInput(for_whom); 116 117 if (input == NULL) { 118 fprintf(stderr,"invalid destination received in VideoMixerNode::ProducerDataStatus\n"); 119 return; 120 } 121 122 media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS, 123 &input, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL); 124 EventQueue()->AddEvent(event); 125 } 126 127 status_t VideoMixerNode::GetLatencyFor( 128 const media_destination &for_whom, 129 bigtime_t *out_latency, 130 media_node_id *out_timesource) 131 { 132 fprintf(stderr,"VideoMixerNode(BBufferConsumer)::GetLatencyFor\n"); 133 if ((out_latency == 0) || (out_timesource == 0)) { 134 fprintf(stderr,"<- B_BAD_VALUE\n"); 135 return B_BAD_VALUE; 136 } 137 138 media_input *input = GetInput(for_whom); 139 140 if (input == NULL) { 141 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 142 return B_MEDIA_BAD_DESTINATION; 143 } 144 145 *out_latency = EventLatency(); 146 *out_timesource = TimeSource()->ID(); 147 148 return B_OK; 149 } 150 151 status_t VideoMixerNode::Connected( 152 const media_source &producer, /* here's a good place to request buffer group usage */ 153 const media_destination &where, 154 const media_format &with_format, 155 media_input *out_input) 156 { 157 fprintf(stderr,"VideoMixerNode(BBufferConsumer)::Connected\n"); 158 159 if (fInitialInput.destination != where) { 160 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 161 return B_MEDIA_BAD_DESTINATION; 162 } 163 164 media_input *input = CreateInput(fConnectedInputs.size()); 165 fConnectedInputs.push_back(input); 166 167 // Specialise the output? 168 169 // compute the latency or just guess 170 fInternalLatency = 500; // just a guess 171 fprintf(stderr," internal latency guessed = %lld\n", fInternalLatency); 172 173 SetEventLatency(fInternalLatency); 174 175 // record the agreed upon values 176 input->destination = where; 177 input->source = producer; 178 input->format = with_format; 179 180 *out_input = *input; 181 182 // Reset the Initial Input 183 ClearInput(&fInitialInput); 184 fInitialInput.destination.id = fConnectedInputs.size(); 185 fInitialInput.destination.port = ControlPort(); 186 187 return B_OK; 188 } 189 190 void VideoMixerNode::Disconnected( 191 const media_source &producer, 192 const media_destination &where) 193 { 194 fprintf(stderr,"VideoMixerNode(BBufferConsumer)::Disconnected\n"); 195 196 media_input *input = GetInput(where); 197 198 if (input == NULL) { 199 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 200 return; 201 } 202 203 if (input->source != producer) { 204 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 205 return; 206 } 207 208 bufferMixer.RemoveBuffer(input->destination.id); 209 210 // disconnected but not deleted (important) 211 input->source = media_source::null; 212 GetInputFormat(&input->format); 213 } 214 215 /* The notification comes from the upstream producer, so he's already cool with */ 216 /* the format; you should not ask him about it in here. */ 217 status_t VideoMixerNode::FormatChanged( 218 const media_source & producer, 219 const media_destination & consumer, 220 int32 change_tag, 221 const media_format & format) 222 { 223 fprintf(stderr,"VideoMixerNode(BBufferConsumer)::FormatChanged\n"); 224 225 media_input *input = GetInput(producer); 226 227 if (input == NULL) { 228 return B_MEDIA_BAD_SOURCE; 229 } 230 231 if (input->destination != consumer) { 232 return B_MEDIA_BAD_DESTINATION; 233 } 234 235 input->format = format; 236 return B_OK; 237 } 238 239 /* Given a performance time of some previous buffer, retrieve the remembered tag */ 240 /* of the closest (previous or exact) performance time. Set *out_flags to 0; the */ 241 /* idea being that flags can be added later, and the understood flags returned in */ 242 /* *out_flags. */ 243 status_t VideoMixerNode::SeekTagRequested( 244 const media_destination & destination, 245 bigtime_t in_target_time, 246 uint32 in_flags, 247 media_seek_tag * out_seek_tag, 248 bigtime_t * out_tagged_time, 249 uint32 * out_flags) 250 { 251 fprintf(stderr,"VideoMixerNode(BBufferConsumer)::SeekTagRequested\n"); 252 // XXX: implement this 253 return BBufferConsumer::SeekTagRequested(destination,in_target_time, in_flags, 254 out_seek_tag, out_tagged_time, out_flags); 255 } 256