/* * Copyright (C) 2020, University of the Basque Country (UPV/EHU) * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com> * * The original file was part of Open Source Doubango Framework * Copyright (C) 2010-2011 Mamadou Diop. * Copyright (C) 2012 Doubango Telecom <http://doubango.org> * * 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. * */ /**@file ProxyConsumer.c * @brief Audio/Video proxy consumers. * * @author Mamadou Diop <diopmamadou(at)doubango.org> * */ #include "ProxyConsumer.h" #include "AudioResampler.h" #include "tsk_memory.h" #include "tsk_debug.h" #include "tinydav/audio/tdav_consumer_audio.h" #include "tinydav/video/tdav_consumer_video.h" /* ============ Audio Consumer Interface ================= */ typedef struct twrap_consumer_proxy_audio_s { TDAV_DECLARE_CONSUMER_AUDIO; uint64_t id; tsk_bool_t started; const ProxyAudioConsumer* pcConsumer; // thread-safe and will be destroyed at the time as the "struct" } twrap_consumer_proxy_audio_t; #define TWRAP_CONSUMER_PROXY_AUDIO(self) ((twrap_consumer_proxy_audio_t*)(self)) int twrap_consumer_proxy_audio_set(tmedia_consumer_t* _self, const tmedia_param_t* param) { twrap_consumer_proxy_audio_t* self = (twrap_consumer_proxy_audio_t*)_self; if(param->plugin_type == tmedia_ppt_consumer){ // specific proxy consumer } return tdav_consumer_audio_set(TDAV_CONSUMER_AUDIO(self), param); } int twrap_consumer_proxy_audio_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec) { twrap_consumer_proxy_audio_t* audio = TWRAP_CONSUMER_PROXY_AUDIO(self); ProxyPluginMgr* manager = NULL; int ret = -1; if(codec && (manager = ProxyPluginMgr::getInstance())){ if((audio->pcConsumer = manager->findAudioConsumer(audio->id)) && audio->pcConsumer->getCallback()){ self->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_DECODING(codec); self->audio.in.channels = TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(codec); self->audio.in.rate = TMEDIA_CODEC_RATE_DECODING(codec); ret = audio->pcConsumer->getCallback()->prepare((int)self->audio.ptime, self->audio.in.rate, self->audio.in.channels); if(ret == 0 && !audio->pcConsumer->getCallback()->isPivotSettings()){ // say consumer can output these params // Out "rate" and "channels" must be defined regardless previous values (already the case in other back-ends) to avoid issues on reINVITE with rate change (e.g. Opus -> PCMA). /*if(!self->audio.out.rate)*/ self->audio.out.rate = self->audio.in.rate; /*if(!self->audio.out.channels)*/ self->audio.out.channels = self->audio.in.channels; } } } else { TSK_DEBUG_ERROR("Invalid parameter/state: codec=%d, manager=%s", codec, manager ? "no-null" : "null"); } return ret; } int twrap_consumer_proxy_audio_start(tmedia_consumer_t* self) { ProxyPluginMgr* manager; int ret = -1; if((manager = ProxyPluginMgr::getInstance())){ const ProxyAudioConsumer* audioConsumer; if((audioConsumer = manager->findAudioConsumer(TWRAP_CONSUMER_PROXY_AUDIO(self)->id)) && audioConsumer->getCallback()){ ret = audioConsumer->getCallback()->start(); } } TWRAP_CONSUMER_PROXY_AUDIO(self)->started = (ret == 0); return ret; } int twrap_consumer_proxy_audio_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr) { twrap_consumer_proxy_audio_t* audio = TWRAP_CONSUMER_PROXY_AUDIO(self); if(!audio->pcConsumer){ ProxyPluginMgr* manager; if((manager = ProxyPluginMgr::getInstance())){ audio->pcConsumer = manager->findAudioConsumer(audio->id); } } ProxyAudioConsumerCallback* callback; int ret = -1; if(audio->pcConsumer && (callback = audio->pcConsumer->getCallback())){ if(callback->putInJitterBuffer()){ ret = tdav_consumer_audio_put(TDAV_CONSUMER_AUDIO(self), buffer, size, proto_hdr); } else{ ret = callback->consume(buffer, size, proto_hdr); } } return ret; } int twrap_consumer_proxy_audio_pause(tmedia_consumer_t* self) { ProxyPluginMgr* manager; int ret = -1; if((manager = ProxyPluginMgr::getInstance())){ const ProxyAudioConsumer* audioConsumer; if((audioConsumer = manager->findAudioConsumer(TWRAP_CONSUMER_PROXY_AUDIO(self)->id)) && audioConsumer->getCallback()){ ret = audioConsumer->getCallback()->pause(); } } return ret; } int twrap_consumer_proxy_audio_stop(tmedia_consumer_t* self) { ProxyPluginMgr* manager; int ret = -1; if((manager = ProxyPluginMgr::getInstance())){ const ProxyAudioConsumer* audioConsumer; if((audioConsumer = manager->findAudioConsumer(TWRAP_CONSUMER_PROXY_AUDIO(self)->id)) && audioConsumer->getCallback()){ ret = audioConsumer->getCallback()->stop(); } } TWRAP_CONSUMER_PROXY_AUDIO(self)->started = (ret == 0) ? tsk_false : tsk_true; return ret; } // // Audio consumer object definition // /* constructor */ static tsk_object_t* twrap_consumer_proxy_audio_ctor(tsk_object_t * self, va_list * app) { twrap_consumer_proxy_audio_t *consumer = (twrap_consumer_proxy_audio_t *)self; if(consumer){ /* init base */ tdav_consumer_audio_init(TDAV_CONSUMER_AUDIO(consumer)); /* init self */ /* Add the plugin to the manager */ ProxyPluginMgr* manager = ProxyPluginMgr::getInstance(); if(manager){ ProxyPlugin* proxyConsumer = new ProxyAudioConsumer(consumer); uint64_t id = proxyConsumer->getId(); manager->addPlugin(&proxyConsumer); manager->getCallback()->OnPluginCreated(id, twrap_proxy_plugin_audio_consumer); } } return self; } /* destructor */ static tsk_object_t* twrap_consumer_proxy_audio_dtor(tsk_object_t * self) { twrap_consumer_proxy_audio_t *consumer = (twrap_consumer_proxy_audio_t *)self; if(consumer){ /* stop */ if(consumer->started){ twrap_consumer_proxy_audio_stop(TMEDIA_CONSUMER(consumer)); } /* deinit base */ tdav_consumer_audio_deinit(TDAV_CONSUMER_AUDIO(consumer)); /* deinit self */ /* Remove plugin from the manager */ ProxyPluginMgr* manager = ProxyPluginMgr::getInstance(); if(manager){ manager->getCallback()->OnPluginDestroyed(consumer->id, twrap_proxy_plugin_audio_consumer); manager->removePlugin(consumer->id); } } return self; } /* object definition */ static const tsk_object_def_t twrap_consumer_proxy_audio_def_s = { sizeof(twrap_consumer_proxy_audio_t), twrap_consumer_proxy_audio_ctor, twrap_consumer_proxy_audio_dtor, tdav_consumer_audio_cmp, }; /* plugin definition*/ static const tmedia_consumer_plugin_def_t twrap_consumer_proxy_audio_plugin_def_s = { &twrap_consumer_proxy_audio_def_s, tmedia_audio, "Audio Proxy Consumer", twrap_consumer_proxy_audio_set, twrap_consumer_proxy_audio_prepare, twrap_consumer_proxy_audio_start, twrap_consumer_proxy_audio_consume, twrap_consumer_proxy_audio_pause, twrap_consumer_proxy_audio_stop }; /*TINYWRAP_GEXTERN*/ const tmedia_consumer_plugin_def_t *twrap_consumer_proxy_audio_plugin_def_t = &twrap_consumer_proxy_audio_plugin_def_s; /* ============ ProxyAudioConsumer Class ================= */ ProxyAudioConsumer::ProxyAudioConsumer(twrap_consumer_proxy_audio_t* pConsumer) :ProxyPlugin(twrap_proxy_plugin_audio_consumer), m_pWrappedPlugin(pConsumer), m_pCallback(tsk_null) { memset(&m_PullBuffer, 0, sizeof(m_PullBuffer)); memset(&m_Resampler, 0, sizeof(m_Resampler)); if(m_pWrappedPlugin){ m_pWrappedPlugin->id = this->getId(); } } ProxyAudioConsumer::~ProxyAudioConsumer() { TSK_FREE(m_Resampler.pInBufferPtr); m_Resampler.nInBufferSizeInByte = 0; if(m_Resampler.pResampler){ delete m_Resampler.pResampler, m_Resampler.pResampler = tsk_null; } } // Use this function to request resampling when your sound card can't honor negotaited record parameters bool ProxyAudioConsumer::setActualSndCardPlaybackParams(int nPtime, int nRate, int nChannels) { if(m_pWrappedPlugin){ TSK_DEBUG_INFO("ProxyAudioConsumer::setActualSndCardRecordParams(ptime=%d, rate=%d, channels=%d)", nPtime, nRate, nChannels); TMEDIA_CONSUMER(m_pWrappedPlugin)->audio.ptime = nPtime; TMEDIA_CONSUMER(m_pWrappedPlugin)->audio.out.rate = nRate; TMEDIA_CONSUMER(m_pWrappedPlugin)->audio.out.channels = nChannels; return true; } else{ TSK_DEBUG_ERROR("Invalid state"); return false; } } bool ProxyAudioConsumer::queryForResampler(uint16_t nInFreq, uint16_t nOutFreq, uint16_t nFrameDuration, uint16_t nChannels, uint16_t nResamplerQuality) { TSK_DEBUG_INFO("queryForResampler(%hu,%hu,%hu,%hu,%hu)", nInFreq, nOutFreq, nFrameDuration, nChannels, nResamplerQuality); if(nResamplerQuality > 10){ TSK_DEBUG_WARN("%d is invalid value for quality", nResamplerQuality); } m_Resampler.pResampler = new AudioResampler(nInFreq, nOutFreq, nFrameDuration, nChannels, nResamplerQuality); if(!m_Resampler.pResampler){ TSK_DEBUG_ERROR("Failed to create new 'AudioResampler' object"); return false; } bool bOK = m_Resampler.pResampler->isValid(); if(!bOK){ goto bail; } m_Resampler.nInBufferSizeInByte = m_Resampler.pResampler->getInputRequiredSizeInShort() * 2; #if HAVE_CRT //Debug memory m_Resampler.pInBufferPtr = calloc(m_Resampler.nInBufferSizeInByte, 1); #else m_Resampler.pInBufferPtr = tsk_calloc(m_Resampler.nInBufferSizeInByte, 1); #endif //HAVE_CRT bOK = (m_Resampler.pInBufferPtr != tsk_null); bail: if(!bOK){ if(m_Resampler.pResampler){ delete m_Resampler.pResampler, m_Resampler.pResampler = tsk_null; } TSK_FREE(m_Resampler.pInBufferPtr); m_Resampler.nInBufferSizeInByte = 0; } return bOK; } bool ProxyAudioConsumer::setPullBuffer(const void* pPullBufferPtr, unsigned nPullBufferSize) { m_PullBuffer.pPullBufferPtr = pPullBufferPtr; m_PullBuffer.nPullBufferSize = nPullBufferSize; return true; } unsigned ProxyAudioConsumer::pull(void* _pOutput/*=tsk_null*/, unsigned _nSize/*=0*/) { if((m_pWrappedPlugin = (twrap_consumer_proxy_audio_t*)tsk_object_ref(m_pWrappedPlugin))){ void* pOutput; unsigned nSize; if(_pOutput && _nSize){ pOutput = _pOutput, nSize = _nSize; } else{ pOutput = (void*)m_PullBuffer.pPullBufferPtr, nSize = m_PullBuffer.nPullBufferSize; } tsk_size_t nRetSize = 0; if(m_Resampler.pResampler && m_Resampler.pInBufferPtr){ nRetSize = tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(m_pWrappedPlugin), m_Resampler.pInBufferPtr, m_Resampler.nInBufferSizeInByte); if(nRetSize){ nRetSize = m_Resampler.pResampler->process(m_Resampler.pInBufferPtr, nRetSize, pOutput, nSize); } } else{ nRetSize = tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(m_pWrappedPlugin), pOutput, nSize); } tdav_consumer_audio_tick(TDAV_CONSUMER_AUDIO(m_pWrappedPlugin)); m_pWrappedPlugin = (twrap_consumer_proxy_audio_t*)tsk_object_unref(m_pWrappedPlugin); return nRetSize; } return 0; } bool ProxyAudioConsumer::setGain(unsigned nGain) { if(m_pWrappedPlugin){ // see also: MediaSessionMgr.consumerSetInt32(org.doubango.tinyWRAP.twrap_media_type_t.twrap_media_audio, "gain", nGain); TMEDIA_CONSUMER(m_pWrappedPlugin)->audio.gain = TSK_MIN(nGain,14); return true; } return false; } unsigned ProxyAudioConsumer::getGain() { if(m_pWrappedPlugin){ return TMEDIA_CONSUMER(m_pWrappedPlugin)->audio.gain; } return 0; } bool ProxyAudioConsumer::reset() { if(m_pWrappedPlugin){ return (tdav_consumer_audio_reset(TDAV_CONSUMER_AUDIO(m_pWrappedPlugin)) == 0); } return false; } bool ProxyAudioConsumer::registerPlugin() { /* HACK: Unregister all other audio plugins */ tmedia_consumer_plugin_unregister_by_type(tmedia_audio); /* Register our proxy plugin */ return (tmedia_consumer_plugin_register(twrap_consumer_proxy_audio_plugin_def_t) == 0); } /* ============ Video Consumer Interface ================= */ typedef struct twrap_consumer_proxy_video_s { TDAV_DECLARE_CONSUMER_VIDEO; uint64_t id; tsk_bool_t started; const ProxyVideoConsumer* pcConsumer; // thread-safe and will be destroyed at the time as the "struct" } twrap_consumer_proxy_video_t; #define TWRAP_CONSUMER_PROXY_VIDEO(self) ((twrap_consumer_proxy_video_t*)(self)) int twrap_consumer_proxy_video_set(tmedia_consumer_t* self, const tmedia_param_t* params) { return 0; } int twrap_consumer_proxy_video_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec) { ProxyPluginMgr* manager; twrap_consumer_proxy_video_t* video = TWRAP_CONSUMER_PROXY_VIDEO(self); int ret = -1; if(codec && (manager = ProxyPluginMgr::getInstance())){ if((video->pcConsumer = manager->findVideoConsumer(video->id)) && video->pcConsumer->getCallback()){ self->video.fps = TMEDIA_CODEC_VIDEO(codec)->in.fps; // in self->video.in.chroma = tmedia_chroma_yuv420p; self->video.in.width = TMEDIA_CODEC_VIDEO(codec)->in.width; self->video.in.height = TMEDIA_CODEC_VIDEO(codec)->in.height; // display (out) self->video.display.chroma = video->pcConsumer->getChroma(); self->video.display.auto_resize = video->pcConsumer->getAutoResizeDisplay(); if(!self->video.display.width){ self->video.display.width = self->video.in.width; } if(!self->video.display.height){ self->video.display.height = self->video.in.height; } ret = video->pcConsumer->getCallback()->prepare(TMEDIA_CODEC_VIDEO(codec)->in.width, TMEDIA_CODEC_VIDEO(codec)->in.height, TMEDIA_CODEC_VIDEO(codec)->in.fps); } } return ret; } int twrap_consumer_proxy_video_start(tmedia_consumer_t* self) { ProxyPluginMgr* manager; int ret = -1; if((manager = ProxyPluginMgr::getInstance())){ const ProxyVideoConsumer* videoConsumer; if((videoConsumer = manager->findVideoConsumer(TWRAP_CONSUMER_PROXY_VIDEO(self)->id)) && videoConsumer->getCallback()){ ret = videoConsumer->getCallback()->start(); } } TWRAP_CONSUMER_PROXY_VIDEO(self)->started = (ret == 0); return ret; } int twrap_consumer_proxy_video_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr) { if(!self || !buffer || !size){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } twrap_consumer_proxy_video_t* video = TWRAP_CONSUMER_PROXY_VIDEO(self); if(!video->pcConsumer){ ProxyPluginMgr* manager; if((manager = ProxyPluginMgr::getInstance())){ video->pcConsumer = manager->findVideoConsumer(video->id); } } int ret = -1; ProxyVideoConsumerCallback* callback; if(video->pcConsumer && (callback = video->pcConsumer->getCallback())){ if(tdav_consumer_video_has_jb(TDAV_CONSUMER_VIDEO(self))){ ret = tdav_consumer_video_put(TDAV_CONSUMER_VIDEO(self), buffer, size, proto_hdr); } else{ if(video->pcConsumer->hasConsumeBuffer()){ unsigned nCopiedSize = video->pcConsumer->copyBuffer(buffer, size); ret = callback->bufferCopied(nCopiedSize, size); } else{ ProxyVideoFrame* frame = new ProxyVideoFrame(buffer, size, const_cast<ProxyVideoConsumer*>(video->pcConsumer)->getDecodedWidth(), const_cast<ProxyVideoConsumer*>(video->pcConsumer)->getDecodedHeight(), proto_hdr); ret = callback->consume(frame); delete frame, frame = tsk_null; } } } else if(!video->pcConsumer){ TSK_DEBUG_ERROR("Cannot find consumer with id=%lld", TWRAP_CONSUMER_PROXY_VIDEO(self)->id); } return ret; } int twrap_consumer_proxy_video_pause(tmedia_consumer_t* self) { ProxyPluginMgr* manager; int ret = -1; if((manager = ProxyPluginMgr::getInstance())){ const ProxyVideoConsumer* videoConsumer; if((videoConsumer = manager->findVideoConsumer(TWRAP_CONSUMER_PROXY_VIDEO(self)->id)) && videoConsumer->getCallback()){ ret = videoConsumer->getCallback()->pause(); } } return ret; } int twrap_consumer_proxy_video_stop(tmedia_consumer_t* self) { ProxyPluginMgr* manager; int ret = -1; if((manager = ProxyPluginMgr::getInstance())){ const ProxyVideoConsumer* videoConsumer; if((videoConsumer = manager->findVideoConsumer(TWRAP_CONSUMER_PROXY_VIDEO(self)->id)) && videoConsumer->getCallback()){ ret = videoConsumer->getCallback()->stop(); } } TWRAP_CONSUMER_PROXY_VIDEO(self)->started = (ret == 0) ? tsk_false : tsk_true; return ret; } // // Video consumer object definition // /* constructor */ static tsk_object_t* twrap_consumer_proxy_video_ctor(tsk_object_t * self, va_list * app) { twrap_consumer_proxy_video_t *consumer = (twrap_consumer_proxy_video_t *)self; if(consumer){ /* init base */ tdav_consumer_video_init(TDAV_CONSUMER_VIDEO(consumer)); /* init self */ /* Add the plugin to the manager */ ProxyPluginMgr* manager = ProxyPluginMgr::getInstance(); if(manager){ ProxyPlugin* proxyConsumer = new ProxyVideoConsumer(ProxyVideoConsumer::getDefaultChroma(), consumer); uint64_t id = proxyConsumer->getId(); manager->addPlugin(&proxyConsumer); manager->getCallback()->OnPluginCreated(id, twrap_proxy_plugin_video_consumer); } } return self; } /* destructor */ static tsk_object_t* twrap_consumer_proxy_video_dtor(tsk_object_t * self) { twrap_consumer_proxy_video_t *consumer = (twrap_consumer_proxy_video_t *)self; if(consumer){ /* stop */ if(consumer->started){ twrap_consumer_proxy_video_stop(TMEDIA_CONSUMER(consumer)); } /* deinit base */ tdav_consumer_video_deinit(TDAV_CONSUMER_VIDEO(consumer)); /* deinit self */ /* Remove plugin from the manager */ ProxyPluginMgr* manager = ProxyPluginMgr::getInstance(); if(manager){ manager->getCallback()->OnPluginDestroyed(consumer->id, twrap_proxy_plugin_video_consumer); manager->removePlugin(consumer->id); } } return self; } /* object definition */ static const tsk_object_def_t twrap_consumer_proxy_video_def_s = { sizeof(twrap_consumer_proxy_video_t), twrap_consumer_proxy_video_ctor, twrap_consumer_proxy_video_dtor, tsk_null, }; /* plugin definition*/ static const tmedia_consumer_plugin_def_t twrap_consumer_proxy_video_plugin_def_s = { &twrap_consumer_proxy_video_def_s, tmedia_video, "Video Proxy Consumer", twrap_consumer_proxy_video_set, twrap_consumer_proxy_video_prepare, twrap_consumer_proxy_video_start, twrap_consumer_proxy_video_consume, twrap_consumer_proxy_video_pause, twrap_consumer_proxy_video_stop }; /*TINYWRAP_GEXTERN*/ const tmedia_consumer_plugin_def_t *twrap_consumer_proxy_video_plugin_def_t = &twrap_consumer_proxy_video_plugin_def_s; /* ============ ProxyVideoConsumer Class ================= */ tmedia_chroma_t ProxyVideoConsumer::s_eDefaultChroma = tmedia_chroma_rgb565le; bool ProxyVideoConsumer::s_bAutoResizeDisplay = false; ProxyVideoConsumer::ProxyVideoConsumer(tmedia_chroma_t eChroma, struct twrap_consumer_proxy_video_s* pConsumer) : m_eChroma(eChroma), m_bAutoResizeDisplay(ProxyVideoConsumer::getDefaultAutoResizeDisplay()), m_pWrappedPlugin(pConsumer), m_pCallback(tsk_null), ProxyPlugin(twrap_proxy_plugin_video_consumer) { m_pWrappedPlugin->id = this->getId(); m_ConsumeBuffer.pConsumeBufferPtr = tsk_null; m_ConsumeBuffer.nConsumeBufferSize = 0; } ProxyVideoConsumer::~ProxyVideoConsumer() { } bool ProxyVideoConsumer::setDisplaySize(unsigned nWidth, unsigned nHeight) { if((m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_ref(m_pWrappedPlugin))){ TMEDIA_CONSUMER(m_pWrappedPlugin)->video.display.width = nWidth; TMEDIA_CONSUMER(m_pWrappedPlugin)->video.display.height = nHeight; m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_unref(m_pWrappedPlugin); return true; } TSK_DEBUG_ERROR("This consumer doesn't wrap any plugin"); return false; } unsigned ProxyVideoConsumer::getDisplayWidth() { unsigned displayWidth = 0; if((m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_ref(m_pWrappedPlugin))){ displayWidth = TMEDIA_CONSUMER(m_pWrappedPlugin)->video.display.width; m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_unref(m_pWrappedPlugin); } else{ TSK_DEBUG_ERROR("This consumer doesn't wrap any plugin"); } return displayWidth; } unsigned ProxyVideoConsumer::getDisplayHeight() { unsigned displayHeight = 0; if((m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_ref(m_pWrappedPlugin))){ displayHeight = TMEDIA_CONSUMER(m_pWrappedPlugin)->video.display.height; m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_unref(m_pWrappedPlugin); } else{ TSK_DEBUG_ERROR("This consumer doesn't wrap any plugin"); } return displayHeight; } unsigned ProxyVideoConsumer::getDecodedWidth() { unsigned width = 0; if((m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_ref(m_pWrappedPlugin))){ width = TMEDIA_CONSUMER(m_pWrappedPlugin)->video.in.width; m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_unref(m_pWrappedPlugin); } else{ TSK_DEBUG_ERROR("This consumer doesn't wrap any plugin"); } return width; } unsigned ProxyVideoConsumer::getDecodedHeight() { unsigned height = 0; if((m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_ref(m_pWrappedPlugin))){ height = TMEDIA_CONSUMER(m_pWrappedPlugin)->video.in.height; m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_unref(m_pWrappedPlugin); } else{ TSK_DEBUG_ERROR("This consumer doesn't wrap any plugin"); } return height; } tmedia_chroma_t ProxyVideoConsumer::getChroma()const { return m_eChroma; } bool ProxyVideoConsumer::setAutoResizeDisplay(bool bAutoResizeDisplay){ if((m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_ref(m_pWrappedPlugin))){ TMEDIA_CONSUMER(m_pWrappedPlugin)->video.display.auto_resize = bAutoResizeDisplay ? tsk_true : tsk_false; m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_unref(m_pWrappedPlugin); m_bAutoResizeDisplay = bAutoResizeDisplay; return true; } TSK_DEBUG_ERROR("This consumer doesn't wrap any plugin"); return false; } bool ProxyVideoConsumer::getAutoResizeDisplay()const { return m_bAutoResizeDisplay; } bool ProxyVideoConsumer::setConsumeBuffer(const void* pConsumeBufferPtr, unsigned nConsumeBufferSize) { m_ConsumeBuffer.pConsumeBufferPtr = pConsumeBufferPtr; m_ConsumeBuffer.nConsumeBufferSize = nConsumeBufferSize; return true; } unsigned ProxyVideoConsumer::copyBuffer(const void* pBuffer, unsigned nSize)const { unsigned nRetsize = 0; if(pBuffer && nSize && m_ConsumeBuffer.pConsumeBufferPtr && m_ConsumeBuffer.nConsumeBufferSize){ nRetsize = (nSize > m_ConsumeBuffer.nConsumeBufferSize) ? m_ConsumeBuffer.nConsumeBufferSize : nSize; memcpy((void*)m_ConsumeBuffer.pConsumeBufferPtr, pBuffer, nRetsize); } return nRetsize; } unsigned ProxyVideoConsumer::pull(void* pOutput, unsigned nSize) { if(pOutput && nSize && (m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_ref(m_pWrappedPlugin))){ tsk_size_t nRetSize = 0; if(!tdav_consumer_video_has_jb(TDAV_CONSUMER_VIDEO(m_pWrappedPlugin))){ TSK_DEBUG_ERROR("This consumer doesn't hold any jitter buffer.\n\nTo pull a buffer you must register a callback ('class ProxyVideoConsumerCallback') and listen for either 'consume' or 'bufferCopied' functions"); goto done; } nRetSize = tdav_consumer_video_get(TDAV_CONSUMER_VIDEO(m_pWrappedPlugin), pOutput, nSize); tdav_consumer_video_tick(TDAV_CONSUMER_VIDEO(m_pWrappedPlugin)); done: m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_unref(m_pWrappedPlugin); return nRetSize; } return 0; } bool ProxyVideoConsumer::reset() { bool ret = false; if((m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_ref(m_pWrappedPlugin))){ if(tdav_consumer_video_has_jb(TDAV_CONSUMER_VIDEO(m_pWrappedPlugin))){ ret = (tdav_consumer_video_reset(TDAV_CONSUMER_VIDEO(m_pWrappedPlugin)) == 0); } else{ TSK_DEBUG_ERROR("This consumer doesn't hold any jitter buffer"); } m_pWrappedPlugin = (twrap_consumer_proxy_video_t*)tsk_object_unref(m_pWrappedPlugin); } TSK_DEBUG_ERROR("This consumer doesn't wrap any plugin"); return ret; } bool ProxyVideoConsumer::registerPlugin() { /* HACK: Unregister all other video plugins */ tmedia_consumer_plugin_unregister_by_type(tmedia_video); /* Register our proxy plugin */ return (tmedia_consumer_plugin_register(twrap_consumer_proxy_video_plugin_def_t) == 0); } ProxyVideoFrame::ProxyVideoFrame(const void* pBufferPtr, unsigned nSize, unsigned nFrameWidth, unsigned nFrameHeight, const tsk_object_t* pProtoHdr) { m_pBufferPtr = pBufferPtr; m_nBufferSize = nSize; m_nFrameWidth = nFrameWidth; m_nFrameHeight = nFrameHeight; m_pProtoHdr = pProtoHdr; } ProxyVideoFrame::~ProxyVideoFrame() { } unsigned ProxyVideoFrame::getSize() { return m_nBufferSize; } unsigned ProxyVideoFrame::getContent(void* pOutput, unsigned nMaxsize) { unsigned nRetsize = 0; if(pOutput && nMaxsize && m_pBufferPtr){ nRetsize = (m_nBufferSize > nMaxsize) ? nMaxsize : m_nBufferSize; memcpy(pOutput, m_pBufferPtr, nRetsize); } return nRetsize; }