/* Copyright (C) 2014 Mamadou DIOP * * This file is part of Open Source Doubango Framework. * * DOUBANGO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DOUBANGO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DOUBANGO. */ #include "internals/DSGrabber.h" #include "internals/DSDisplay.h" #include "internals/DSUtils.h" #include "tinymedia/tmedia_producer.h" #include "tsk_string.h" #include "tsk_debug.h" #define DSPRODUCER(self) ((plugin_screencast_dshow_producer_t*)(self)) typedef struct plugin_screencast_dshow_producer_s { TMEDIA_DECLARE_PRODUCER; DSGrabber* grabber; INT64 previewHwnd; tsk_bool_t started; tsk_bool_t mute; tsk_bool_t create_on_ui_thread; } plugin_screencast_dshow_producer_t; // Producer callback (From DirectShow Grabber to our plugin) static int plugin_video_dshow_plugin_cb(const void* callback_data, const void* buffer, tsk_size_t size) { const plugin_screencast_dshow_producer_t* producer = (const plugin_screencast_dshow_producer_t*)callback_data; if (producer && TMEDIA_PRODUCER(producer)->enc_cb.callback) { TMEDIA_PRODUCER(producer)->enc_cb.callback(TMEDIA_PRODUCER(producer)->enc_cb.callback_data, buffer, size); } return 0; } /* ============ Media Producer Interface ================= */ static int plugin_screencast_dshow_producer_set(tmedia_producer_t *self, const tmedia_param_t* param) { int ret = 0; plugin_screencast_dshow_producer_t* producer = (plugin_screencast_dshow_producer_t*)self; if(!producer || !param) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(param->value_type == tmedia_pvt_int64) { if(tsk_striequals(param->key, "local-hwnd")) { DSPRODUCER(producer)->previewHwnd = (INT64)*((int64_t*)param->value); if(DSPRODUCER(producer)->grabber && DSPRODUCER(self)->grabber->preview) { DSPRODUCER(producer)->grabber->preview->attach(DSPRODUCER(producer)->previewHwnd); } } } else if(param->value_type == tmedia_pvt_int32) { if(tsk_striequals(param->key, "mute")) { producer->mute = (TSK_TO_INT32((uint8_t*)param->value) != 0); if(producer->started) { if(producer->mute) { producer->grabber->pause(); } else { producer->grabber->start(); } } } else if(tsk_striequals(param->key, "create-on-current-thead")) { producer->create_on_ui_thread = *((int32_t*)param->value) ? tsk_false : tsk_true; } else if(tsk_striequals(param->key, "plugin-firefox")) { TSK_DEBUG_INFO("'plugin-firefox' ignored for screencast"); } } return ret; } static int plugin_screencast_dshow_producer_prepare(tmedia_producer_t* self, const tmedia_codec_t* codec) { plugin_screencast_dshow_producer_t* producer = (plugin_screencast_dshow_producer_t*)self; if(!producer || !codec && codec->plugin) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } TMEDIA_PRODUCER(producer)->video.fps = TMEDIA_CODEC_VIDEO(codec)->out.fps; TMEDIA_PRODUCER(producer)->video.width = TMEDIA_CODEC_VIDEO(codec)->out.width; TMEDIA_PRODUCER(producer)->video.height = TMEDIA_CODEC_VIDEO(codec)->out.height; return 0; } static int plugin_screencast_dshow_producer_start(tmedia_producer_t* self) { plugin_screencast_dshow_producer_t* producer = (plugin_screencast_dshow_producer_t*)self; HRESULT hr = S_OK; if (!producer) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if (producer->started) { return 0; } // create grabber on ALWAYS current thread if (!producer->grabber) { static BOOL __isDisplayFalse = FALSE; static BOOL __isScreenCastTrue = TRUE; if(producer->create_on_ui_thread) { createOnUIThead(reinterpret_cast((void*)DSPRODUCER(producer)->previewHwnd), (void**)&producer->grabber, __isDisplayFalse, __isScreenCastTrue); } else { createOnCurrentThead(reinterpret_cast((void*)DSPRODUCER(producer)->previewHwnd), (void**)&producer->grabber, __isDisplayFalse, __isScreenCastTrue); } if (!producer->grabber) { TSK_DEBUG_ERROR("Failed to create grabber"); return -2; } } // set parameters producer->grabber->setCaptureParameters((int)TMEDIA_PRODUCER(producer)->video.width, (int)TMEDIA_PRODUCER(producer)->video.height, TMEDIA_PRODUCER(producer)->video.fps); // set callback function producer->grabber->setCallback(plugin_video_dshow_plugin_cb, producer); // attach preview if (producer->grabber->preview) { if (producer->previewHwnd) { producer->grabber->preview->attach(producer->previewHwnd); } producer->grabber->preview->setSize((int)TMEDIA_PRODUCER(producer)->video.width, (int)TMEDIA_PRODUCER(producer)->video.height); } // start grabber if (!producer->mute) { producer->grabber->start(); } producer->started = tsk_true; return 0; } static int plugin_screencast_dshow_producer_pause(tmedia_producer_t* self) { plugin_screencast_dshow_producer_t* producer = (plugin_screencast_dshow_producer_t*)self; if(!producer) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(!producer->grabber) { TSK_DEBUG_ERROR("Invalid internal grabber"); return -2; } producer->grabber->pause(); return 0; } static int plugin_screencast_dshow_producer_stop(tmedia_producer_t* self) { plugin_screencast_dshow_producer_t* producer = (plugin_screencast_dshow_producer_t*)self; if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(!producer->started) { return 0; } if(!producer->grabber) { TSK_DEBUG_ERROR("Invalid internal grabber"); return -2; } producer->grabber->stop(); producer->started = tsk_false; return 0; } // // WaveAPI producer object definition // /* constructor */ static tsk_object_t* plugin_screencast_dshow_producer_ctor(tsk_object_t * self, va_list * app) { CoInitializeEx(NULL, COINIT_MULTITHREADED); plugin_screencast_dshow_producer_t *producer = (plugin_screencast_dshow_producer_t *)self; if(producer) { /* init base */ tmedia_producer_init(TMEDIA_PRODUCER(producer)); TMEDIA_PRODUCER(producer)->video.chroma = tmedia_chroma_bgr24; // RGB24 on x86 (little endians) stored as BGR24 /* init self with default values*/ producer->create_on_ui_thread = tsk_true; TMEDIA_PRODUCER(producer)->video.fps = 15; TMEDIA_PRODUCER(producer)->video.width = 352; TMEDIA_PRODUCER(producer)->video.height = 288; } return self; } /* destructor */ static tsk_object_t* plugin_screencast_dshow_producer_dtor(tsk_object_t * self) { plugin_screencast_dshow_producer_t *producer = (plugin_screencast_dshow_producer_t *)self; if(producer) { /* stop */ if(producer->started) { plugin_screencast_dshow_producer_stop((tmedia_producer_t*)self); } /* for safety */ if(producer->grabber) { producer->grabber->setCallback(tsk_null, tsk_null); } /* deinit base */ tmedia_producer_deinit(TMEDIA_PRODUCER(producer)); /* deinit self */ SAFE_DELETE_PTR(producer->grabber); } return self; } /* object definition */ static const tsk_object_def_t plugin_screencast_dshow_producer_def_s = { sizeof(plugin_screencast_dshow_producer_t), plugin_screencast_dshow_producer_ctor, plugin_screencast_dshow_producer_dtor, tsk_null, }; /* plugin definition*/ static const tmedia_producer_plugin_def_t plugin_screencast_dshow_producer_plugin_def_s = { &plugin_screencast_dshow_producer_def_s, tmedia_bfcp_video, "Microsoft DirectShow producer (ScrenCast)", plugin_screencast_dshow_producer_set, plugin_screencast_dshow_producer_prepare, plugin_screencast_dshow_producer_start, plugin_screencast_dshow_producer_pause, plugin_screencast_dshow_producer_stop }; const tmedia_producer_plugin_def_t *plugin_screencast_dshow_producer_plugin_def_t = &plugin_screencast_dshow_producer_plugin_def_s;