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