10fe9fd36SDavid McPaul/*
20fe9fd36SDavid McPaul* Copyright (C) 2009-2010 David McPaul
30fe9fd36SDavid McPaul*
40fe9fd36SDavid McPaul* All rights reserved. Distributed under the terms of the MIT License.
50fe9fd36SDavid McPaul* VideoMixerNode.cpp
60fe9fd36SDavid McPaul*
70fe9fd36SDavid McPaul* The VideoMixerNode class
80fe9fd36SDavid McPaul* takes in multiple video streams and supplies
90fe9fd36SDavid McPaul* a single stream as the output.
100fe9fd36SDavid McPaul* each stream is converted to the same colourspace
110fe9fd36SDavid McPaul*/
120fe9fd36SDavid McPaul
130fe9fd36SDavid McPaul#include "VideoMixerNode.h"
140fe9fd36SDavid McPaul
15127a93c2SDario Casalinuovo#include <stdio.h>
16127a93c2SDario Casalinuovo
170fe9fd36SDavid McPaul
180fe9fd36SDavid McPaul// -------------------------------------------------------- //
190fe9fd36SDavid McPaul// implemention of BBufferConsumer
200fe9fd36SDavid McPaul// -------------------------------------------------------- //
210fe9fd36SDavid McPaul
220fe9fd36SDavid McPaul// Check to make sure the format is okay, then remove
230fe9fd36SDavid McPaul// any wildcards corresponding to our requirements.
240fe9fd36SDavid McPaulstatus_t VideoMixerNode::AcceptFormat(
250fe9fd36SDavid McPaul				const media_destination &dest,
260fe9fd36SDavid McPaul				media_format *format)
270fe9fd36SDavid McPaul{
280fe9fd36SDavid McPaul	fprintf(stderr,"VideoMixerNode(BBufferConsumer)::AcceptFormat\n");
290fe9fd36SDavid McPaul
300fe9fd36SDavid McPaul	if (fInitialInput.destination != dest) {
310fe9fd36SDavid McPaul		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION");
320fe9fd36SDavid McPaul		return B_MEDIA_BAD_DESTINATION; // none of our inputs matched the dest
330fe9fd36SDavid McPaul	}
340fe9fd36SDavid McPaul
350fe9fd36SDavid McPaul	media_format myFormat;
360fe9fd36SDavid McPaul
370fe9fd36SDavid McPaul	GetInputFormat(&myFormat);
380fe9fd36SDavid McPaul
390fe9fd36SDavid McPaul	AddRequirements(format);
400fe9fd36SDavid McPaul
410fe9fd36SDavid McPaul	return B_OK;
420fe9fd36SDavid McPaul}
430fe9fd36SDavid McPaul
440fe9fd36SDavid McPaulstatus_t VideoMixerNode::GetNextInput(
450fe9fd36SDavid McPaul				int32 *cookie,
460fe9fd36SDavid McPaul				media_input *out_input)
470fe9fd36SDavid McPaul{
480fe9fd36SDavid McPaul	fprintf(stderr,"VideoMixerNode(BBufferConsumer)::GetNextInput (%ld)\n",*cookie);
490fe9fd36SDavid McPaul
500fe9fd36SDavid McPaul	// Cookie 0 is the connecting input, all others are connected inputs
51127a93c2SDario Casalinuovo	if (uint32(*cookie) == fConnectedInputs.size()) {
520fe9fd36SDavid McPaul		*out_input = fInitialInput;
530fe9fd36SDavid McPaul	} else {
540fe9fd36SDavid McPaul		out_input = GetInput(*cookie);
550fe9fd36SDavid McPaul
560fe9fd36SDavid McPaul		if (out_input == NULL) {
570fe9fd36SDavid McPaul			fprintf(stderr,"<- B_ERROR (no more inputs)\n");
580fe9fd36SDavid McPaul			return B_ERROR;
590fe9fd36SDavid McPaul		}
600fe9fd36SDavid McPaul	}
610fe9fd36SDavid McPaul
620fe9fd36SDavid McPaul	// so next time they won't get the same input again
630fe9fd36SDavid McPaul	(*cookie)++;
640fe9fd36SDavid McPaul
650fe9fd36SDavid McPaul	return B_OK;
660fe9fd36SDavid McPaul}
670fe9fd36SDavid McPaul
680fe9fd36SDavid McPaulvoid VideoMixerNode::DisposeInputCookie(
690fe9fd36SDavid McPaul				int32 cookie)
700fe9fd36SDavid McPaul{
710fe9fd36SDavid McPaul	fprintf(stderr,"VideoMixerNode(BBufferConsumer)::DisposeInputCookie\n");
720fe9fd36SDavid McPaul	// nothing to do since our cookies are just integers
730fe9fd36SDavid McPaul}
740fe9fd36SDavid McPaul
750fe9fd36SDavid McPaulvoid VideoMixerNode::BufferReceived(BBuffer *buffer)
760fe9fd36SDavid McPaul{
770fe9fd36SDavid McPaul	switch (buffer->Header()->type) {
780fe9fd36SDavid McPaul//		case B_MEDIA_PARAMETERS:
790fe9fd36SDavid McPaul//			{
800fe9fd36SDavid McPaul//			status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed());
810fe9fd36SDavid McPaul//			if (status != B_OK) {
820fe9fd36SDavid McPaul//				fprintf(stderr,"ApplyParameterData in MediaDemultiplexerNode::BufferReceived failed\n");
830fe9fd36SDavid McPaul//			}
840fe9fd36SDavid McPaul//			buffer->Recycle();
850fe9fd36SDavid McPaul//			}
860fe9fd36SDavid McPaul//			break;
870fe9fd36SDavid McPaul		case B_MEDIA_RAW_VIDEO:
880fe9fd36SDavid McPaul			if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) {
890fe9fd36SDavid McPaul				fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in VideoMixerNode::BufferReceived\n");
900fe9fd36SDavid McPaul				// XXX: implement this part
910fe9fd36SDavid McPaul				buffer->Recycle();
920fe9fd36SDavid McPaul			} else {
930fe9fd36SDavid McPaul				media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER,
940fe9fd36SDavid McPaul										buffer, BTimedEventQueue::B_RECYCLE_BUFFER);
950fe9fd36SDavid McPaul				status_t status = EventQueue()->AddEvent(event);
960fe9fd36SDavid McPaul				if (status != B_OK) {
970fe9fd36SDavid McPaul					fprintf(stderr,"EventQueue()->AddEvent(event) in VideoMixerNode::BufferReceived failed\n");
980fe9fd36SDavid McPaul					buffer->Recycle();
990fe9fd36SDavid McPaul				}
1000fe9fd36SDavid McPaul			}
1010fe9fd36SDavid McPaul			break;
1020fe9fd36SDavid McPaul		default:
1030fe9fd36SDavid McPaul			fprintf(stderr,"unexpected buffer type in VideoMixerNode::BufferReceived\n");
1040fe9fd36SDavid McPaul			buffer->Recycle();
1050fe9fd36SDavid McPaul			break;
1060fe9fd36SDavid McPaul	}
1070fe9fd36SDavid McPaul}
1080fe9fd36SDavid McPaul
1090fe9fd36SDavid McPaulvoid VideoMixerNode::ProducerDataStatus(
1100fe9fd36SDavid McPaul				const media_destination &for_whom,
1110fe9fd36SDavid McPaul				int32 status,
1120fe9fd36SDavid McPaul				bigtime_t at_performance_time)
1130fe9fd36SDavid McPaul{
1140fe9fd36SDavid McPaul	fprintf(stderr,"VideoMixerNode(BBufferConsumer)::ProducerDataStatus\n");
1150fe9fd36SDavid McPaul	media_input *input = GetInput(for_whom);
1160fe9fd36SDavid McPaul
1170fe9fd36SDavid McPaul	if (input == NULL) {
1180fe9fd36SDavid McPaul		fprintf(stderr,"invalid destination received in VideoMixerNode::ProducerDataStatus\n");
1190fe9fd36SDavid McPaul		return;
1200fe9fd36SDavid McPaul	}
1210fe9fd36SDavid McPaul
1220fe9fd36SDavid McPaul	media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS,
1230fe9fd36SDavid McPaul			&input, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL);
1240fe9fd36SDavid McPaul	EventQueue()->AddEvent(event);
1250fe9fd36SDavid McPaul}
1260fe9fd36SDavid McPaul
1270fe9fd36SDavid McPaulstatus_t VideoMixerNode::GetLatencyFor(
1280fe9fd36SDavid McPaul				const media_destination &for_whom,
1290fe9fd36SDavid McPaul				bigtime_t *out_latency,
1300fe9fd36SDavid McPaul				media_node_id *out_timesource)
1310fe9fd36SDavid McPaul{
1320fe9fd36SDavid McPaul	fprintf(stderr,"VideoMixerNode(BBufferConsumer)::GetLatencyFor\n");
1330fe9fd36SDavid McPaul	if ((out_latency == 0) || (out_timesource == 0)) {
1340fe9fd36SDavid McPaul		fprintf(stderr,"<- B_BAD_VALUE\n");
1350fe9fd36SDavid McPaul		return B_BAD_VALUE;
1360fe9fd36SDavid McPaul	}
1370fe9fd36SDavid McPaul
1380fe9fd36SDavid McPaul	media_input *input = GetInput(for_whom);
1390fe9fd36SDavid McPaul
1400fe9fd36SDavid McPaul	if (input == NULL) {
1410fe9fd36SDavid McPaul		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
1420fe9fd36SDavid McPaul		return B_MEDIA_BAD_DESTINATION;
1430fe9fd36SDavid McPaul	}
1440fe9fd36SDavid McPaul
1450fe9fd36SDavid McPaul	*out_latency = EventLatency();
1460fe9fd36SDavid McPaul	*out_timesource = TimeSource()->ID();
1470fe9fd36SDavid McPaul
1480fe9fd36SDavid McPaul	return B_OK;
1490fe9fd36SDavid McPaul}
1500fe9fd36SDavid McPaul
1510fe9fd36SDavid McPaulstatus_t VideoMixerNode::Connected(
1520fe9fd36SDavid McPaul				const media_source &producer,	/* here's a good place to request buffer group usage */
1530fe9fd36SDavid McPaul				const media_destination &where,
1540fe9fd36SDavid McPaul				const media_format &with_format,
1550fe9fd36SDavid McPaul				media_input *out_input)
1560fe9fd36SDavid McPaul{
1570fe9fd36SDavid McPaul	fprintf(stderr,"VideoMixerNode(BBufferConsumer)::Connected\n");
1580fe9fd36SDavid McPaul
1590fe9fd36SDavid McPaul	if (fInitialInput.destination != where) {
1600fe9fd36SDavid McPaul		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
1610fe9fd36SDavid McPaul		return B_MEDIA_BAD_DESTINATION;
1620fe9fd36SDavid McPaul	}
1630fe9fd36SDavid McPaul
1640fe9fd36SDavid McPaul	media_input *input = CreateInput(fConnectedInputs.size());
1650fe9fd36SDavid McPaul	fConnectedInputs.push_back(input);
1660fe9fd36SDavid McPaul
1670fe9fd36SDavid McPaul	// Specialise the output?
1680fe9fd36SDavid McPaul
1690fe9fd36SDavid McPaul	// compute the latency or just guess
1700fe9fd36SDavid McPaul	fInternalLatency = 500; // just a guess
1710fe9fd36SDavid McPaul	fprintf(stderr,"  internal latency guessed = %lld\n", fInternalLatency);
1720fe9fd36SDavid McPaul
1730fe9fd36SDavid McPaul	SetEventLatency(fInternalLatency);
1740fe9fd36SDavid McPaul
1750fe9fd36SDavid McPaul	// record the agreed upon values
1760fe9fd36SDavid McPaul	input->destination = where;
1770fe9fd36SDavid McPaul	input->source = producer;
1780fe9fd36SDavid McPaul	input->format = with_format;
1790fe9fd36SDavid McPaul
1800fe9fd36SDavid McPaul	*out_input = *input;
1810fe9fd36SDavid McPaul
1820fe9fd36SDavid McPaul	// Reset the Initial Input
1830fe9fd36SDavid McPaul	ClearInput(&fInitialInput);
1840fe9fd36SDavid McPaul	fInitialInput.destination.id = fConnectedInputs.size();
1850fe9fd36SDavid McPaul	fInitialInput.destination.port = ControlPort();
1860fe9fd36SDavid McPaul
1870fe9fd36SDavid McPaul	return B_OK;
1880fe9fd36SDavid McPaul}
1890fe9fd36SDavid McPaul
1900fe9fd36SDavid McPaulvoid VideoMixerNode::Disconnected(
1910fe9fd36SDavid McPaul				const media_source &producer,
1920fe9fd36SDavid McPaul				const media_destination &where)
1930fe9fd36SDavid McPaul{
1940fe9fd36SDavid McPaul	fprintf(stderr,"VideoMixerNode(BBufferConsumer)::Disconnected\n");
1950fe9fd36SDavid McPaul
1960fe9fd36SDavid McPaul	media_input *input = GetInput(where);
1970fe9fd36SDavid McPaul
1980fe9fd36SDavid McPaul	if (input == NULL) {
1990fe9fd36SDavid McPaul		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
2000fe9fd36SDavid McPaul		return;
2010fe9fd36SDavid McPaul	}
2020fe9fd36SDavid McPaul
2030fe9fd36SDavid McPaul	if (input->source != producer) {
2040fe9fd36SDavid McPaul		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
2050fe9fd36SDavid McPaul		return;
2060fe9fd36SDavid McPaul	}
2070fe9fd36SDavid McPaul
208c436ab31SDavid McPaul	bufferMixer.RemoveBuffer(input->destination.id);
209c436ab31SDavid McPaul
2100fe9fd36SDavid McPaul	// disconnected but not deleted (important)
2110fe9fd36SDavid McPaul	input->source = media_source::null;
2120fe9fd36SDavid McPaul	GetInputFormat(&input->format);
2130fe9fd36SDavid McPaul}
2140fe9fd36SDavid McPaul
2150fe9fd36SDavid McPaul/* The notification comes from the upstream producer, so he's already cool with */
2160fe9fd36SDavid McPaul/* the format; you should not ask him about it in here. */
2170fe9fd36SDavid McPaulstatus_t VideoMixerNode::FormatChanged(
2180fe9fd36SDavid McPaul				const media_source & producer,
2190fe9fd36SDavid McPaul				const media_destination & consumer,
2200fe9fd36SDavid McPaul				int32 change_tag,
2210fe9fd36SDavid McPaul				const media_format & format)
2220fe9fd36SDavid McPaul{
2230fe9fd36SDavid McPaul	fprintf(stderr,"VideoMixerNode(BBufferConsumer)::FormatChanged\n");
2240fe9fd36SDavid McPaul
2250fe9fd36SDavid McPaul	media_input *input = GetInput(producer);
2260fe9fd36SDavid McPaul
2270fe9fd36SDavid McPaul	if (input == NULL) {
2280fe9fd36SDavid McPaul		return B_MEDIA_BAD_SOURCE;
2290fe9fd36SDavid McPaul	}
2300fe9fd36SDavid McPaul
2310fe9fd36SDavid McPaul	if (input->destination != consumer) {
2320fe9fd36SDavid McPaul		return B_MEDIA_BAD_DESTINATION;
2330fe9fd36SDavid McPaul	}
2340fe9fd36SDavid McPaul
2350fe9fd36SDavid McPaul	input->format = format;
2360fe9fd36SDavid McPaul	return B_OK;
2370fe9fd36SDavid McPaul}
2380fe9fd36SDavid McPaul
2390fe9fd36SDavid McPaul/* Given a performance time of some previous buffer, retrieve the remembered tag */
2400fe9fd36SDavid McPaul/* of the closest (previous or exact) performance time. Set *out_flags to 0; the */
2410fe9fd36SDavid McPaul/* idea being that flags can be added later, and the understood flags returned in */
2420fe9fd36SDavid McPaul/* *out_flags. */
2430fe9fd36SDavid McPaulstatus_t VideoMixerNode::SeekTagRequested(
2440fe9fd36SDavid McPaul				const media_destination & destination,
2450fe9fd36SDavid McPaul				bigtime_t in_target_time,
2460fe9fd36SDavid McPaul				uint32 in_flags,
2470fe9fd36SDavid McPaul				media_seek_tag * out_seek_tag,
2480fe9fd36SDavid McPaul				bigtime_t * out_tagged_time,
2490fe9fd36SDavid McPaul				uint32 * out_flags)
2500fe9fd36SDavid McPaul{
2510fe9fd36SDavid McPaul	fprintf(stderr,"VideoMixerNode(BBufferConsumer)::SeekTagRequested\n");
2520fe9fd36SDavid McPaul	// XXX: implement this
2530fe9fd36SDavid McPaul	return BBufferConsumer::SeekTagRequested(destination,in_target_time, in_flags,
2540fe9fd36SDavid McPaul											out_seek_tag, out_tagged_time, out_flags);
2550fe9fd36SDavid McPaul}
256