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// implementation for BMediaEventLooper
17// -------------------------------------------------------- //
18
19void VideoMixerNode::HandleEvent(
20				const media_timed_event *event,
21				bigtime_t lateness,
22				bool realTimeEvent = false)
23{
24	switch (event->type) {
25		case BTimedEventQueue::B_START:
26			HandleStart(event,lateness,realTimeEvent);
27			break;
28		case BTimedEventQueue::B_SEEK:
29			HandleSeek(event,lateness,realTimeEvent);
30			break;
31		case BTimedEventQueue::B_WARP:
32			HandleWarp(event,lateness,realTimeEvent);
33			break;
34		case BTimedEventQueue::B_STOP:
35			HandleStop(event,lateness,realTimeEvent);
36			break;
37		case BTimedEventQueue::B_HANDLE_BUFFER:
38			if (RunState() == BMediaEventLooper::B_STARTED) {
39				HandleBuffer(event,lateness,realTimeEvent);
40			}
41			break;
42		case BTimedEventQueue::B_DATA_STATUS:
43			HandleDataStatus(event, lateness, realTimeEvent);
44			break;
45		case BTimedEventQueue::B_PARAMETER:
46			HandleParameter(event,lateness,realTimeEvent);
47			break;
48		default:
49			fprintf(stderr,"  unknown event type: %ld\n",event->type);
50			break;
51	}
52}
53
54/* override to clean up custom events you have added to your queue */
55void VideoMixerNode::CleanUpEvent(
56				const media_timed_event *event)
57{
58	BMediaEventLooper::CleanUpEvent(event);
59}
60
61/* called from Offline mode to determine the current time of the node */
62/* update your internal information whenever it changes */
63bigtime_t VideoMixerNode::OfflineTime()
64{
65	fprintf(stderr,"VideoMixerNode(BMediaEventLooper)::OfflineTime\n");
66	return BMediaEventLooper::OfflineTime();
67// XXX: do something else?
68}
69
70/* override only if you know what you are doing! */
71/* otherwise much badness could occur */
72/* the actual control loop function: */
73/* 	waits for messages, Pops events off the queue and calls DispatchEvent */
74void VideoMixerNode::ControlLoop() {
75	BMediaEventLooper::ControlLoop();
76}
77
78// protected:
79
80status_t VideoMixerNode::HandleStart(
81						const media_timed_event *event,
82						bigtime_t lateness,
83						bool realTimeEvent = false)
84{
85	fprintf(stderr,"VideoMixerNode(BMediaEventLooper)::HandleStart()\n");
86	if (RunState() != B_STARTED) {
87		media_timed_event firstBufferEvent(event->event_time, BTimedEventQueue::B_HANDLE_BUFFER);
88		HandleEvent(&firstBufferEvent, 0, false);
89		EventQueue()->AddEvent(firstBufferEvent);
90	}
91	return B_OK;
92}
93
94status_t VideoMixerNode::HandleSeek(
95						const media_timed_event *event,
96						bigtime_t lateness,
97						bool realTimeEvent = false)
98{
99	fprintf(stderr,"VideoMixerNode(BMediaEventLooper)::HandleSeek(t=%lld,d=%ld,bd=%lld)\n",event->event_time, event->data, event->bigdata);
100	return B_OK;
101}
102
103status_t VideoMixerNode::HandleWarp(
104						const media_timed_event *event,
105						bigtime_t lateness,
106						bool realTimeEvent = false)
107{
108	fprintf(stderr,"VideoMixerNode(BMediaEventLooper)::HandleWarp\n");
109	return B_OK;
110}
111
112status_t VideoMixerNode::HandleStop(
113						const media_timed_event *event,
114						bigtime_t lateness,
115						bool realTimeEvent = false)
116{
117	fprintf(stderr,"VideoMixerNode(BMediaEventLooper)::HandleStop\n");
118	// flush the queue so downstreamers don't get any more
119	EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER);
120	return B_OK;
121}
122
123status_t VideoMixerNode::HandleBuffer(
124				const media_timed_event *event,
125				bigtime_t lateness,
126				bool realTimeEvent = false)
127{
128	if (event->type != BTimedEventQueue::B_HANDLE_BUFFER) {
129		fprintf(stderr,"HandleBuffer called on non buffer event type\n");
130		return B_BAD_VALUE;
131	}
132
133	BBuffer *buffer = const_cast<BBuffer*>((BBuffer*)event->pointer);
134	if (buffer == NULL) {
135		fprintf(stderr,"NO BUFFER PASSED\n");
136		return B_BAD_VALUE;
137	}
138
139	media_input *input = GetInput(buffer->Header()->destination);
140
141	if (input == NULL) {
142		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
143		return B_MEDIA_BAD_DESTINATION;
144	}
145
146	if (fOutput.format.u.raw_video == media_raw_video_format::wildcard) {
147		fprintf(stderr,"<- B_MEDIA_NOT_CONNECTED\n");
148		return B_MEDIA_NOT_CONNECTED;
149	}
150
151	status_t status = B_OK;
152
153	if (input == *fConnectedInputs.begin()) {
154		if (bufferMixer.isBufferAvailable()) {
155			status = SendBuffer(bufferMixer.GetOutputBuffer(), fOutput.source, fOutput.destination);
156		}
157		bufferMixer.AddBuffer(input->destination.id, buffer, true);
158	} else {
159		bufferMixer.AddBuffer(input->destination.id, buffer, false);
160	}
161
162	return status;
163}
164
165status_t VideoMixerNode::HandleDataStatus(
166						const media_timed_event *event,
167						bigtime_t lateness,
168						bool realTimeEvent = false)
169{
170	fprintf(stderr,"VideoMixerNode(BMediaEventLooper)::HandleDataStatus");
171	SendDataStatus(event->data, fOutput.destination, event->event_time);
172	return B_OK;
173}
174
175status_t VideoMixerNode::HandleParameter(
176				const media_timed_event *event,
177				bigtime_t lateness,
178				bool realTimeEvent = false)
179{
180	fprintf(stderr,"VideoMixerNode(BMediaEventLooper)::HandleParameter");
181	return B_OK;
182}
183