xref: /haiku/src/add-ons/media/media-add-ons/video_mixer/VideoMixerNodeConsumer.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
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