2 * Copyright (C) 2009-2010 David McPaul
4 * All rights reserved. Distributed under the terms of the MIT License.
7 * The VideoMixerNode class takes in multiple video streams and supplies
8 * a single stream as the output.
9 * each stream is converted to the same colourspace and should match
10 * either the primary input OR the requested colourspace from the output
13 * The first input is considered the primary input
14 * subsequent input framesize should match the primary input framesize
15 * The output framerate will be the same as the primary input
22 #include "VideoMixerNode.h"
26 VideoMixerNode::~VideoMixerNode(void)
28 fprintf(stderr
,"VideoMixerNode::~VideoMixerNode\n");
29 // Stop the BMediaEventLooper thread
33 VideoMixerNode::VideoMixerNode(
34 const flavor_info
*info
,
37 : BMediaNode("VideoMixerNode"),
38 BBufferConsumer(B_MEDIA_RAW_VIDEO
), // Raw video buffers in
39 BBufferProducer(B_MEDIA_RAW_VIDEO
), // Raw video buffers out
42 fprintf(stderr
,"VideoMixerNode::VideoMixerNode\n");
43 // keep our creator around for AddOn calls later
45 // NULL out our latency estimates
46 fDownstreamLatency
= 0;
49 // Start with 1 input and 1 output
50 ClearInput(&fInitialInput
);
52 strncpy(fOutput
.name
,"VideoMixer Output", B_MEDIA_NAME_LENGTH
-1);
53 fOutput
.name
[B_MEDIA_NAME_LENGTH
-1] = '\0';
55 // initialize the output
56 fOutput
.node
= media_node::null
; // until registration
57 fOutput
.destination
= media_destination::null
;
58 fOutput
.source
.port
= ControlPort();
59 fOutput
.source
.id
= 0;
61 GetOutputFormat(&fOutput
.format
);
63 fInitCheckStatus
= B_OK
;
66 void VideoMixerNode::NodeRegistered(void)
68 fprintf(stderr
,"VideoMixerNode::NodeRegistered\n");
70 // for every node created so far set to this Node;
71 for (uint32 i
=0;i
<fConnectedInputs
.size();i
++) {
72 fConnectedInputs
[i
]->node
= Node();
73 fConnectedInputs
[i
]->destination
.id
= i
;
74 fConnectedInputs
[i
]->destination
.port
= ControlPort();
77 fInitialInput
.node
= Node();
78 fInitialInput
.destination
.id
= fConnectedInputs
.size();
79 fInitialInput
.destination
.port
= ControlPort();
81 GetOutputFormat(&fOutput
.format
);
82 fOutput
.node
= Node();
84 // start the BMediaEventLooper thread
85 SetPriority(B_REAL_TIME_PRIORITY
);
90 VideoMixerNode::CreateInput(uint32 inputID
) {
91 media_input
*input
= new media_input();
95 // don't overwrite available space, and be sure to terminate
96 sprintf(input
->name
, "VideoMixer Input %ld", inputID
);
102 VideoMixerNode::ClearInput(media_input
*input
) {
104 // initialize the input
105 sprintf(input
->name
, "VideoMixer Input");
106 input
->node
= Node();
107 input
->source
= media_source::null
;
108 input
->destination
= media_destination::null
;
110 GetInputFormat(&input
->format
);
114 VideoMixerNode::GetInput(const media_source
&source
) {
116 vector
<media_input
*>::iterator each
;
118 for (each
=fConnectedInputs
.begin(); each
<fConnectedInputs
.end(); each
++) {
119 if ((*each
)->source
== source
) {
128 VideoMixerNode::GetInput(const media_destination
&destination
) {
130 vector
<media_input
*>::iterator each
;
132 for (each
=fConnectedInputs
.begin(); each
<fConnectedInputs
.end(); each
++) {
133 if ((*each
)->destination
== destination
) {
142 VideoMixerNode::GetInput(const int32 id
) {
144 vector
<media_input
*>::iterator each
;
146 for (each
=fConnectedInputs
.begin(); each
<fConnectedInputs
.end(); each
++) {
147 if ((*each
)->destination
.id
== id
) {
155 status_t
VideoMixerNode::InitCheck(void) const
157 fprintf(stderr
,"VideoMixerNode::InitCheck\n");
158 return fInitCheckStatus
;
161 status_t
VideoMixerNode::GetConfigurationFor(
162 BMessage
*into_message
)
164 fprintf(stderr
,"VideoMixerNode::GetConfigurationFor\n");
168 // -------------------------------------------------------- //
169 // implementation of BMediaNode
170 // -------------------------------------------------------- //
172 BMediaAddOn
*VideoMixerNode::AddOn(
173 int32
*internal_id
) const
175 fprintf(stderr
,"VideoMixerNode::AddOn\n");
176 // BeBook says this only gets called if we were in an add-on.
177 if (fAddOn
!= NULL
) {
178 // If we get a null pointer then we just won't write.
179 if (internal_id
!= NULL
) {
186 void VideoMixerNode::Start(bigtime_t performance_time
)
188 fprintf(stderr
,"VideoMixerNode::Start(pt=%lld)\n", performance_time
);
189 BMediaEventLooper::Start(performance_time
);
192 void VideoMixerNode::Stop(
193 bigtime_t performance_time
,
197 fprintf(stderr
,"VideoMixerNode::Stop(pt=%lld,<immediate>)\n", performance_time
);
199 fprintf(stderr
,"VideoMixerNode::Stop(pt=%lld,<scheduled>)\n", performance_time
);
201 BMediaEventLooper::Stop(performance_time
, immediate
);
204 void VideoMixerNode::Seek(
205 bigtime_t media_time
,
206 bigtime_t performance_time
)
208 fprintf(stderr
,"VideoMixerNode::Seek(mt=%lld,pt=%lld)\n", media_time
,performance_time
);
209 BMediaEventLooper::Seek(media_time
, performance_time
);
212 void VideoMixerNode::SetRunMode(run_mode mode
)
214 fprintf(stderr
,"VideoMixerNode::SetRunMode(%i)\n", mode
);
215 BMediaEventLooper::SetRunMode(mode
);
218 void VideoMixerNode::TimeWarp(
219 bigtime_t at_real_time
,
220 bigtime_t to_performance_time
)
222 fprintf(stderr
,"VideoMixerNode::TimeWarp(rt=%lld,pt=%lld)\n", at_real_time
, to_performance_time
);
223 BMediaEventLooper::TimeWarp(at_real_time
, to_performance_time
);
226 void VideoMixerNode::Preroll(void)
228 fprintf(stderr
,"VideoMixerNode::Preroll\n");
229 // XXX:Performance opportunity
230 BMediaNode::Preroll();
233 void VideoMixerNode::SetTimeSource(BTimeSource
*time_source
)
235 fprintf(stderr
,"VideoMixerNode::SetTimeSource\n");
236 BMediaNode::SetTimeSource(time_source
);
239 status_t
VideoMixerNode::HandleMessage(
244 fprintf(stderr
,"VideoMixerNode::HandleMessage\n");
245 status_t status
= B_OK
;
247 // no special messages for now
249 status
= BBufferConsumer::HandleMessage(message
, data
, size
);
250 if (status
== B_OK
) {
253 status
= BBufferProducer::HandleMessage(message
, data
, size
);
254 if (status
== B_OK
) {
257 status
= BMediaNode::HandleMessage(message
, data
, size
);
258 if (status
== B_OK
) {
261 BMediaNode::HandleBadMessage(message
, data
, size
);
268 status_t
VideoMixerNode::RequestCompleted(const media_request_info
&info
)
270 fprintf(stderr
,"VideoMixerNode::RequestCompleted\n");
271 return BMediaNode::RequestCompleted(info
);
274 status_t
VideoMixerNode::DeleteHook(BMediaNode
*node
)
276 fprintf(stderr
,"VideoMixerNode::DeleteHook\n");
277 return BMediaEventLooper::DeleteHook(node
);
280 status_t
VideoMixerNode::GetNodeAttributes(
281 media_node_attribute
*outAttributes
,
284 fprintf(stderr
,"VideoMixerNode::GetNodeAttributes\n");
285 return BMediaNode::GetNodeAttributes(outAttributes
, inMaxCount
);
288 status_t
VideoMixerNode::AddTimer(
289 bigtime_t at_performance_time
,
292 fprintf(stderr
,"VideoMixerNode::AddTimer\n");
293 return BMediaEventLooper::AddTimer(at_performance_time
, cookie
);
296 // -------------------------------------------------------- //
297 // VideoMixerNode specific functions
298 // -------------------------------------------------------- //
302 void VideoMixerNode::GetFlavor(flavor_info
*outInfo
, int32 id
)
304 fprintf(stderr
,"VideoMixerNode::GetFlavor\n");
306 if (outInfo
!= NULL
) {
307 outInfo
->internal_id
= id
;
308 strcpy(outInfo
->name
, "Haiku VideoMixer");
309 strcpy(outInfo
->info
, "A VideoMixerNode node mixes multiple video"
310 " streams into a single stream.");
311 outInfo
->kinds
= B_BUFFER_CONSUMER
| B_BUFFER_PRODUCER
;
312 outInfo
->flavor_flags
= B_FLAVOR_IS_LOCAL
;
313 outInfo
->possible_count
= INT_MAX
; // no limit
314 outInfo
->in_format_count
= 1;
315 media_format
*inFormats
= new media_format
[outInfo
->in_format_count
];
316 GetInputFormat(&inFormats
[0]);
317 outInfo
->in_formats
= inFormats
;
318 outInfo
->out_format_count
= 1; // single output
319 media_format
*outFormats
= new media_format
[outInfo
->out_format_count
];
320 GetOutputFormat(&outFormats
[0]);
321 outInfo
->out_formats
= outFormats
;
325 void VideoMixerNode::GetInputFormat(media_format
*outFormat
)
327 fprintf(stderr
,"VideoMixerNode::GetInputFormat\n");
329 if (outFormat
!= NULL
) {
330 outFormat
->type
= B_MEDIA_RAW_VIDEO
;
331 outFormat
->require_flags
= B_MEDIA_MAUI_UNDEFINED_FLAGS
;
332 outFormat
->deny_flags
= B_MEDIA_MAUI_UNDEFINED_FLAGS
;
333 outFormat
->u
.raw_video
= media_raw_video_format::wildcard
;
337 void VideoMixerNode::GetOutputFormat(media_format
*outFormat
)
339 fprintf(stderr
,"VideoMixerNode::GetOutputFormat\n");
340 if (outFormat
!= NULL
) {
341 outFormat
->type
= B_MEDIA_RAW_VIDEO
;
342 outFormat
->require_flags
= B_MEDIA_MAUI_UNDEFINED_FLAGS
;
343 outFormat
->deny_flags
= B_MEDIA_MAUI_UNDEFINED_FLAGS
;
344 outFormat
->u
.raw_video
= media_raw_video_format::wildcard
;
350 status_t
VideoMixerNode::AddRequirements(media_format
*format
)
352 fprintf(stderr
,"VideoMixerNode::AddRequirements\n");