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 takes in multiple video streams and supplies 80fe9fd36SDavid McPaul * a single stream as the output. 90fe9fd36SDavid McPaul * each stream is converted to the same colourspace and should match 100fe9fd36SDavid McPaul * either the primary input OR the requested colourspace from the output 110fe9fd36SDavid McPaul * destination. 120fe9fd36SDavid McPaul * 130fe9fd36SDavid McPaul * The first input is considered the primary input 140fe9fd36SDavid McPaul * subsequent input framesize should match the primary input framesize 150fe9fd36SDavid McPaul * The output framerate will be the same as the primary input 160fe9fd36SDavid McPaul * 170fe9fd36SDavid McPaul */ 180fe9fd36SDavid McPaul 190fe9fd36SDavid McPaul #include <stdio.h> 200fe9fd36SDavid McPaul #include <string.h> 210fe9fd36SDavid McPaul 220fe9fd36SDavid McPaul #include "VideoMixerNode.h" 230fe9fd36SDavid McPaul 24*127a93c2SDario Casalinuovo using std::vector; 25*127a93c2SDario Casalinuovo 260fe9fd36SDavid McPaul VideoMixerNode::~VideoMixerNode(void) 270fe9fd36SDavid McPaul { 280fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::~VideoMixerNode\n"); 290fe9fd36SDavid McPaul // Stop the BMediaEventLooper thread 300fe9fd36SDavid McPaul Quit(); 310fe9fd36SDavid McPaul } 320fe9fd36SDavid McPaul 330fe9fd36SDavid McPaul VideoMixerNode::VideoMixerNode( 34*127a93c2SDario Casalinuovo const flavor_info *info, 35*127a93c2SDario Casalinuovo BMessage *config, 36*127a93c2SDario Casalinuovo BMediaAddOn *addOn) 370fe9fd36SDavid McPaul : BMediaNode("VideoMixerNode"), 380fe9fd36SDavid McPaul BBufferConsumer(B_MEDIA_RAW_VIDEO), // Raw video buffers in 390fe9fd36SDavid McPaul BBufferProducer(B_MEDIA_RAW_VIDEO), // Raw video buffers out 400fe9fd36SDavid McPaul BMediaEventLooper() 410fe9fd36SDavid McPaul { 420fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::VideoMixerNode\n"); 430fe9fd36SDavid McPaul // keep our creator around for AddOn calls later 440fe9fd36SDavid McPaul fAddOn = addOn; 450fe9fd36SDavid McPaul // NULL out our latency estimates 460fe9fd36SDavid McPaul fDownstreamLatency = 0; 470fe9fd36SDavid McPaul fInternalLatency = 0; 480fe9fd36SDavid McPaul 490fe9fd36SDavid McPaul // Start with 1 input and 1 output 500fe9fd36SDavid McPaul ClearInput(&fInitialInput); 510fe9fd36SDavid McPaul 520fe9fd36SDavid McPaul strncpy(fOutput.name,"VideoMixer Output", B_MEDIA_NAME_LENGTH-1); 530fe9fd36SDavid McPaul fOutput.name[B_MEDIA_NAME_LENGTH-1] = '\0'; 540fe9fd36SDavid McPaul 550fe9fd36SDavid McPaul // initialize the output 560fe9fd36SDavid McPaul fOutput.node = media_node::null; // until registration 570fe9fd36SDavid McPaul fOutput.destination = media_destination::null; 580fe9fd36SDavid McPaul fOutput.source.port = ControlPort(); 590fe9fd36SDavid McPaul fOutput.source.id = 0; 600fe9fd36SDavid McPaul 610fe9fd36SDavid McPaul GetOutputFormat(&fOutput.format); 620fe9fd36SDavid McPaul 630fe9fd36SDavid McPaul fInitCheckStatus = B_OK; 640fe9fd36SDavid McPaul } 650fe9fd36SDavid McPaul 660fe9fd36SDavid McPaul void VideoMixerNode::NodeRegistered(void) 670fe9fd36SDavid McPaul { 680fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::NodeRegistered\n"); 690fe9fd36SDavid McPaul 700fe9fd36SDavid McPaul // for every node created so far set to this Node; 710fe9fd36SDavid McPaul for (uint32 i=0;i<fConnectedInputs.size();i++) { 720fe9fd36SDavid McPaul fConnectedInputs[i]->node = Node(); 730fe9fd36SDavid McPaul fConnectedInputs[i]->destination.id = i; 740fe9fd36SDavid McPaul fConnectedInputs[i]->destination.port = ControlPort(); 750fe9fd36SDavid McPaul } 760fe9fd36SDavid McPaul 770fe9fd36SDavid McPaul fInitialInput.node = Node(); 780fe9fd36SDavid McPaul fInitialInput.destination.id = fConnectedInputs.size(); 790fe9fd36SDavid McPaul fInitialInput.destination.port = ControlPort(); 800fe9fd36SDavid McPaul 810fe9fd36SDavid McPaul GetOutputFormat(&fOutput.format); 820fe9fd36SDavid McPaul fOutput.node = Node(); 830fe9fd36SDavid McPaul 840fe9fd36SDavid McPaul // start the BMediaEventLooper thread 850fe9fd36SDavid McPaul SetPriority(B_REAL_TIME_PRIORITY); 860fe9fd36SDavid McPaul Run(); 870fe9fd36SDavid McPaul } 880fe9fd36SDavid McPaul 890fe9fd36SDavid McPaul media_input * 900fe9fd36SDavid McPaul VideoMixerNode::CreateInput(uint32 inputID) { 910fe9fd36SDavid McPaul media_input *input = new media_input(); 920fe9fd36SDavid McPaul 930fe9fd36SDavid McPaul ClearInput(input); 940fe9fd36SDavid McPaul 950fe9fd36SDavid McPaul // don't overwrite available space, and be sure to terminate 960fe9fd36SDavid McPaul sprintf(input->name, "VideoMixer Input %ld", inputID); 970fe9fd36SDavid McPaul 980fe9fd36SDavid McPaul return input; 990fe9fd36SDavid McPaul } 1000fe9fd36SDavid McPaul 1010fe9fd36SDavid McPaul void 1020fe9fd36SDavid McPaul VideoMixerNode::ClearInput(media_input *input) { 1030fe9fd36SDavid McPaul 1040fe9fd36SDavid McPaul // initialize the input 1050fe9fd36SDavid McPaul sprintf(input->name, "VideoMixer Input"); 1060fe9fd36SDavid McPaul input->node = Node(); 1070fe9fd36SDavid McPaul input->source = media_source::null; 1080fe9fd36SDavid McPaul input->destination = media_destination::null; 1090fe9fd36SDavid McPaul 1100fe9fd36SDavid McPaul GetInputFormat(&input->format); 1110fe9fd36SDavid McPaul } 1120fe9fd36SDavid McPaul 1130fe9fd36SDavid McPaul media_input * 1140fe9fd36SDavid McPaul VideoMixerNode::GetInput(const media_source &source) { 1150fe9fd36SDavid McPaul 1160fe9fd36SDavid McPaul vector<media_input *>::iterator each; 1170fe9fd36SDavid McPaul 1180fe9fd36SDavid McPaul for (each=fConnectedInputs.begin(); each<fConnectedInputs.end(); each++) { 1190fe9fd36SDavid McPaul if ((*each)->source == source) { 1200fe9fd36SDavid McPaul return *each; 1210fe9fd36SDavid McPaul } 1220fe9fd36SDavid McPaul } 1230fe9fd36SDavid McPaul 1240fe9fd36SDavid McPaul return NULL; 1250fe9fd36SDavid McPaul } 1260fe9fd36SDavid McPaul 1270fe9fd36SDavid McPaul media_input * 1280fe9fd36SDavid McPaul VideoMixerNode::GetInput(const media_destination &destination) { 1290fe9fd36SDavid McPaul 1300fe9fd36SDavid McPaul vector<media_input *>::iterator each; 1310fe9fd36SDavid McPaul 1320fe9fd36SDavid McPaul for (each=fConnectedInputs.begin(); each<fConnectedInputs.end(); each++) { 1330fe9fd36SDavid McPaul if ((*each)->destination == destination) { 1340fe9fd36SDavid McPaul return *each; 1350fe9fd36SDavid McPaul } 1360fe9fd36SDavid McPaul } 1370fe9fd36SDavid McPaul 1380fe9fd36SDavid McPaul return NULL; 1390fe9fd36SDavid McPaul } 1400fe9fd36SDavid McPaul 1410fe9fd36SDavid McPaul media_input * 1420fe9fd36SDavid McPaul VideoMixerNode::GetInput(const int32 id) { 1430fe9fd36SDavid McPaul 1440fe9fd36SDavid McPaul vector<media_input *>::iterator each; 1450fe9fd36SDavid McPaul 1460fe9fd36SDavid McPaul for (each=fConnectedInputs.begin(); each<fConnectedInputs.end(); each++) { 1470fe9fd36SDavid McPaul if ((*each)->destination.id == id) { 1480fe9fd36SDavid McPaul return *each; 1490fe9fd36SDavid McPaul } 1500fe9fd36SDavid McPaul } 1510fe9fd36SDavid McPaul 1520fe9fd36SDavid McPaul return NULL; 1530fe9fd36SDavid McPaul } 1540fe9fd36SDavid McPaul 1550fe9fd36SDavid McPaul status_t VideoMixerNode::InitCheck(void) const 1560fe9fd36SDavid McPaul { 1570fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::InitCheck\n"); 1580fe9fd36SDavid McPaul return fInitCheckStatus; 1590fe9fd36SDavid McPaul } 1600fe9fd36SDavid McPaul 1610fe9fd36SDavid McPaul status_t VideoMixerNode::GetConfigurationFor( 1620fe9fd36SDavid McPaul BMessage *into_message) 1630fe9fd36SDavid McPaul { 1640fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::GetConfigurationFor\n"); 1650fe9fd36SDavid McPaul return B_OK; 1660fe9fd36SDavid McPaul } 1670fe9fd36SDavid McPaul 1680fe9fd36SDavid McPaul // -------------------------------------------------------- // 1690fe9fd36SDavid McPaul // implementation of BMediaNode 1700fe9fd36SDavid McPaul // -------------------------------------------------------- // 1710fe9fd36SDavid McPaul 1720fe9fd36SDavid McPaul BMediaAddOn *VideoMixerNode::AddOn( 1730fe9fd36SDavid McPaul int32 *internal_id) const 1740fe9fd36SDavid McPaul { 1750fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::AddOn\n"); 1760fe9fd36SDavid McPaul // BeBook says this only gets called if we were in an add-on. 1770fe9fd36SDavid McPaul if (fAddOn != NULL) { 1780fe9fd36SDavid McPaul // If we get a null pointer then we just won't write. 1790fe9fd36SDavid McPaul if (internal_id != NULL) { 1800fe9fd36SDavid McPaul internal_id = 0; 1810fe9fd36SDavid McPaul } 1820fe9fd36SDavid McPaul } 1830fe9fd36SDavid McPaul return fAddOn; 1840fe9fd36SDavid McPaul } 1850fe9fd36SDavid McPaul 1860fe9fd36SDavid McPaul void VideoMixerNode::Start(bigtime_t performance_time) 1870fe9fd36SDavid McPaul { 1880fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::Start(pt=%lld)\n", performance_time); 1890fe9fd36SDavid McPaul BMediaEventLooper::Start(performance_time); 1900fe9fd36SDavid McPaul } 1910fe9fd36SDavid McPaul 1920fe9fd36SDavid McPaul void VideoMixerNode::Stop( 1930fe9fd36SDavid McPaul bigtime_t performance_time, 1940fe9fd36SDavid McPaul bool immediate) 1950fe9fd36SDavid McPaul { 1960fe9fd36SDavid McPaul if (immediate) { 1970fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::Stop(pt=%lld,<immediate>)\n", performance_time); 1980fe9fd36SDavid McPaul } else { 1990fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::Stop(pt=%lld,<scheduled>)\n", performance_time); 2000fe9fd36SDavid McPaul } 2010fe9fd36SDavid McPaul BMediaEventLooper::Stop(performance_time, immediate); 2020fe9fd36SDavid McPaul } 2030fe9fd36SDavid McPaul 2040fe9fd36SDavid McPaul void VideoMixerNode::Seek( 2050fe9fd36SDavid McPaul bigtime_t media_time, 2060fe9fd36SDavid McPaul bigtime_t performance_time) 2070fe9fd36SDavid McPaul { 2080fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::Seek(mt=%lld,pt=%lld)\n", media_time,performance_time); 2090fe9fd36SDavid McPaul BMediaEventLooper::Seek(media_time, performance_time); 2100fe9fd36SDavid McPaul } 2110fe9fd36SDavid McPaul 2120fe9fd36SDavid McPaul void VideoMixerNode::SetRunMode(run_mode mode) 2130fe9fd36SDavid McPaul { 2140fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::SetRunMode(%i)\n", mode); 2150fe9fd36SDavid McPaul BMediaEventLooper::SetRunMode(mode); 2160fe9fd36SDavid McPaul } 2170fe9fd36SDavid McPaul 2180fe9fd36SDavid McPaul void VideoMixerNode::TimeWarp( 2190fe9fd36SDavid McPaul bigtime_t at_real_time, 2200fe9fd36SDavid McPaul bigtime_t to_performance_time) 2210fe9fd36SDavid McPaul { 2220fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::TimeWarp(rt=%lld,pt=%lld)\n", at_real_time, to_performance_time); 2230fe9fd36SDavid McPaul BMediaEventLooper::TimeWarp(at_real_time, to_performance_time); 2240fe9fd36SDavid McPaul } 2250fe9fd36SDavid McPaul 2260fe9fd36SDavid McPaul void VideoMixerNode::Preroll(void) 2270fe9fd36SDavid McPaul { 2280fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::Preroll\n"); 2290fe9fd36SDavid McPaul // XXX:Performance opportunity 2300fe9fd36SDavid McPaul BMediaNode::Preroll(); 2310fe9fd36SDavid McPaul } 2320fe9fd36SDavid McPaul 2330fe9fd36SDavid McPaul void VideoMixerNode::SetTimeSource(BTimeSource *time_source) 2340fe9fd36SDavid McPaul { 2350fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::SetTimeSource\n"); 2360fe9fd36SDavid McPaul BMediaNode::SetTimeSource(time_source); 2370fe9fd36SDavid McPaul } 2380fe9fd36SDavid McPaul 2390fe9fd36SDavid McPaul status_t VideoMixerNode::HandleMessage( 2400fe9fd36SDavid McPaul int32 message, 2410fe9fd36SDavid McPaul const void *data, 2420fe9fd36SDavid McPaul size_t size) 2430fe9fd36SDavid McPaul { 2440fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::HandleMessage\n"); 2450fe9fd36SDavid McPaul status_t status = B_OK; 2460fe9fd36SDavid McPaul switch (message) { 2470fe9fd36SDavid McPaul // no special messages for now 2480fe9fd36SDavid McPaul default: 2490fe9fd36SDavid McPaul status = BBufferConsumer::HandleMessage(message, data, size); 2500fe9fd36SDavid McPaul if (status == B_OK) { 2510fe9fd36SDavid McPaul break; 2520fe9fd36SDavid McPaul } 2530fe9fd36SDavid McPaul status = BBufferProducer::HandleMessage(message, data, size); 2540fe9fd36SDavid McPaul if (status == B_OK) { 2550fe9fd36SDavid McPaul break; 2560fe9fd36SDavid McPaul } 2570fe9fd36SDavid McPaul status = BMediaNode::HandleMessage(message, data, size); 2580fe9fd36SDavid McPaul if (status == B_OK) { 2590fe9fd36SDavid McPaul break; 2600fe9fd36SDavid McPaul } 2610fe9fd36SDavid McPaul BMediaNode::HandleBadMessage(message, data, size); 2620fe9fd36SDavid McPaul status = B_ERROR; 2630fe9fd36SDavid McPaul break; 2640fe9fd36SDavid McPaul } 2650fe9fd36SDavid McPaul return status; 2660fe9fd36SDavid McPaul } 2670fe9fd36SDavid McPaul 2680fe9fd36SDavid McPaul status_t VideoMixerNode::RequestCompleted(const media_request_info &info) 2690fe9fd36SDavid McPaul { 2700fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::RequestCompleted\n"); 2710fe9fd36SDavid McPaul return BMediaNode::RequestCompleted(info); 2720fe9fd36SDavid McPaul } 2730fe9fd36SDavid McPaul 2740fe9fd36SDavid McPaul status_t VideoMixerNode::DeleteHook(BMediaNode *node) 2750fe9fd36SDavid McPaul { 2760fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::DeleteHook\n"); 2770fe9fd36SDavid McPaul return BMediaEventLooper::DeleteHook(node); 2780fe9fd36SDavid McPaul } 2790fe9fd36SDavid McPaul 2800fe9fd36SDavid McPaul status_t VideoMixerNode::GetNodeAttributes( 2810fe9fd36SDavid McPaul media_node_attribute *outAttributes, 2820fe9fd36SDavid McPaul size_t inMaxCount) 2830fe9fd36SDavid McPaul { 2840fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::GetNodeAttributes\n"); 2850fe9fd36SDavid McPaul return BMediaNode::GetNodeAttributes(outAttributes, inMaxCount); 2860fe9fd36SDavid McPaul } 2870fe9fd36SDavid McPaul 2880fe9fd36SDavid McPaul status_t VideoMixerNode::AddTimer( 2890fe9fd36SDavid McPaul bigtime_t at_performance_time, 2900fe9fd36SDavid McPaul int32 cookie) 2910fe9fd36SDavid McPaul { 2920fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::AddTimer\n"); 2930fe9fd36SDavid McPaul return BMediaEventLooper::AddTimer(at_performance_time, cookie); 2940fe9fd36SDavid McPaul } 2950fe9fd36SDavid McPaul 2960fe9fd36SDavid McPaul // -------------------------------------------------------- // 2970fe9fd36SDavid McPaul // VideoMixerNode specific functions 2980fe9fd36SDavid McPaul // -------------------------------------------------------- // 2990fe9fd36SDavid McPaul 3000fe9fd36SDavid McPaul // public: 3010fe9fd36SDavid McPaul 3020fe9fd36SDavid McPaul void VideoMixerNode::GetFlavor(flavor_info *outInfo, int32 id) 3030fe9fd36SDavid McPaul { 3040fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::GetFlavor\n"); 3050fe9fd36SDavid McPaul 3060fe9fd36SDavid McPaul if (outInfo != NULL) { 3070fe9fd36SDavid McPaul outInfo->internal_id = id; 308*127a93c2SDario Casalinuovo strcpy(outInfo->name, "Haiku VideoMixer"); 309*127a93c2SDario Casalinuovo strcpy(outInfo->info, "A VideoMixerNode node mixes multiple video" 310*127a93c2SDario Casalinuovo " streams into a single stream."); 3110fe9fd36SDavid McPaul outInfo->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER; 3120fe9fd36SDavid McPaul outInfo->flavor_flags = B_FLAVOR_IS_LOCAL; 3130fe9fd36SDavid McPaul outInfo->possible_count = INT_MAX; // no limit 3140fe9fd36SDavid McPaul outInfo->in_format_count = 1; 3150fe9fd36SDavid McPaul media_format *inFormats = new media_format[outInfo->in_format_count]; 3160fe9fd36SDavid McPaul GetInputFormat(&inFormats[0]); 3170fe9fd36SDavid McPaul outInfo->in_formats = inFormats; 3180fe9fd36SDavid McPaul outInfo->out_format_count = 1; // single output 3190fe9fd36SDavid McPaul media_format *outFormats = new media_format[outInfo->out_format_count]; 3200fe9fd36SDavid McPaul GetOutputFormat(&outFormats[0]); 3210fe9fd36SDavid McPaul outInfo->out_formats = outFormats; 3220fe9fd36SDavid McPaul } 3230fe9fd36SDavid McPaul } 3240fe9fd36SDavid McPaul 3250fe9fd36SDavid McPaul void VideoMixerNode::GetInputFormat(media_format *outFormat) 3260fe9fd36SDavid McPaul { 3270fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::GetInputFormat\n"); 3280fe9fd36SDavid McPaul 3290fe9fd36SDavid McPaul if (outFormat != NULL) { 3300fe9fd36SDavid McPaul outFormat->type = B_MEDIA_RAW_VIDEO; 3310fe9fd36SDavid McPaul outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 3320fe9fd36SDavid McPaul outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 3330fe9fd36SDavid McPaul outFormat->u.raw_video = media_raw_video_format::wildcard; 3340fe9fd36SDavid McPaul } 3350fe9fd36SDavid McPaul } 3360fe9fd36SDavid McPaul 3370fe9fd36SDavid McPaul void VideoMixerNode::GetOutputFormat(media_format *outFormat) 3380fe9fd36SDavid McPaul { 3390fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::GetOutputFormat\n"); 3400fe9fd36SDavid McPaul if (outFormat != NULL) { 3410fe9fd36SDavid McPaul outFormat->type = B_MEDIA_RAW_VIDEO; 3420fe9fd36SDavid McPaul outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 3430fe9fd36SDavid McPaul outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 3440fe9fd36SDavid McPaul outFormat->u.raw_video = media_raw_video_format::wildcard; 3450fe9fd36SDavid McPaul } 3460fe9fd36SDavid McPaul } 3470fe9fd36SDavid McPaul 3480fe9fd36SDavid McPaul // protected: 3490fe9fd36SDavid McPaul 3500fe9fd36SDavid McPaul status_t VideoMixerNode::AddRequirements(media_format *format) 3510fe9fd36SDavid McPaul { 3520fe9fd36SDavid McPaul fprintf(stderr,"VideoMixerNode::AddRequirements\n"); 3530fe9fd36SDavid McPaul return B_OK; 3540fe9fd36SDavid McPaul } 355