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. 24status_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 44status_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 68void 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 75void 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 109void 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 127status_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 151status_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 190void 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. */ 217status_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. */ 243status_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