// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm #include "stitchOutput.hpp" #include "common/container.hpp" #include "libvideostitch/overlay.hpp" namespace VideoStitch { namespace Core { /** * ExtractOutput implementation */ ExtractOutput::ExtractOutput(Pimpl* pimplVal) : pimpl(pimplVal) {} ExtractOutput::~ExtractOutput() { delete pimpl; } bool ExtractOutput::setRenderers(const std::vector>& r) { return pimpl->setRenderers(r); } bool ExtractOutput::addRenderer(std::shared_ptr r) { return pimpl->addRenderer(r); } bool ExtractOutput::removeRenderer(const std::string& name) { return pimpl->removeRenderer(name); } bool ExtractOutput::setWriters(const std::vector>& w) { return pimpl->setWriters(w); } bool ExtractOutput::addWriter(std::shared_ptr w) { return pimpl->addWriter(w); } bool ExtractOutput::removeWriter(const std::string& name) { return pimpl->removeWriter(name); } bool ExtractOutput::updateWriter(const std::string& name, const Ptv::Value& config) { return pimpl->updateWriter(name, config); } /** * StitchOutput implementation */ template StitcherOutput::StitcherOutput(Pimpl* pimplVal) : pimpl(pimplVal) {} template StitcherOutput::~StitcherOutput() { delete pimpl; } template bool StitcherOutput::setRenderers(const std::vector>& r) { return pimpl->setRenderers(r); } template bool StitcherOutput::addRenderer(std::shared_ptr r) { return pimpl->addRenderer(r); } template bool StitcherOutput::removeRenderer(const std::string& name) { return pimpl->removeRenderer(name); } template void StitcherOutput::setCompositor(const std::shared_ptr& c) { pimpl->setCompositor(c); } template bool StitcherOutput::setWriters(const std::vector>& w) { return pimpl->setWriters(w); } template bool StitcherOutput::addWriter(std::shared_ptr w) { return pimpl->addWriter(w); } template bool StitcherOutput::removeWriter(const std::string& name) { return pimpl->removeWriter(name); } template bool StitcherOutput::updateWriter(const std::string& name, const Ptv::Value& config) { return pimpl->updateWriter(name, config); } template class StitcherOutput; /** * PanoWriterPusher implementation */ template WriterPusher::WriterPusher(size_t w, size_t /*h*/, const std::vector>& writersIn) : width(w), compositor(nullptr) { setWriters(writersIn); } template WriterPusher::~WriterPusher() { { std::lock_guard lk(writersLock); writers.clear(); } { std::lock_guard lk(renderersLock); renderers.clear(); } } template bool WriterPusher::setRenderers( const std::vector>& newRenderers) { std::lock_guard lk(renderersLock); // delete the old renderers renderers.clear(); // register the new ones bool res = true; for (auto& r : newRenderers) { if (!r) { continue; } auto p = renderers.insert(std::make_pair(r->getName(), std::shared_ptr(r))); if (!p.second) { res = false; } } return res; } template bool WriterPusher::addRenderer(std::shared_ptr r) { std::lock_guard lk(renderersLock); auto res = renderers.insert(std::make_pair(r->getName(), r)); if (!res.second) { return false; } return true; } template bool WriterPusher::removeRenderer(const std::string& name) { { std::lock_guard lk(renderersLock); auto renderer = renderers.find(name); if (renderer == renderers.end()) { return false; } renderers.erase(name); } return true; } template void WriterPusher::setCompositor(const std::shared_ptr& c) { std::lock_guard lk(compositorLock); compositor = c; } template bool WriterPusher::setWriters(const std::vector>& newWriters) { std::lock_guard lk(writersLock); // delete the old writers writers.clear(); // register the new ones bool r = true; for (auto& w : newWriters) { if (!w) { continue; } auto res = writers.insert(std::make_pair(w->getName(), w)); if (!res.second) { r = false; } } // downsampling setup downsamplingFactors.clear(); for (auto& w : writers) { assert((int)width % (int)w.second->getPanoWidth() == 0); // This should have been caught in Writer::create. Crash in debug. downsamplingFactors[w.first] = (int)width % (int)w.second->getPanoWidth() == 0 ? (int)width / (int)w.second->getPanoWidth() : 1; } return r; } template bool WriterPusher::addWriter(std::shared_ptr w) { std::lock_guard lk(writersLock); auto res = writers.insert(std::make_pair(w->getName(), w)); if (!res.second) { return false; } downsamplingFactors[w->getName()] = (int)width % (int)w->getPanoWidth() == 0 ? (int)width / (int)w->getPanoWidth() : 1; return true; } template bool WriterPusher::removeWriter(const std::string& name) { { std::lock_guard lk(writersLock); auto writer = writers.find(name); if (writer == writers.end()) { return false; } writers.erase(name); } return true; } template bool WriterPusher::updateWriter(const std::string& name, const Ptv::Value& config) { std::lock_guard lk(writersLock); auto writer = writers.find(name); if (writer == writers.end()) { return false; } writer->second->updateConfig(config); return true; } template void WriterPusher::pushVideoToWriters(mtime_t date, FrameBuffer* delegate) const { { std::lock_guard lk(compositorLock); if (compositor) { compositor->attachContext(); if (!delegate->getOpenGLSurface()) { assert(false); } delegate->getSurface()->accept(compositor, delegate->getOpenGLSurface(), date); delegate->pushOpenGLVideo(); delegate->streamOpenGLSynchronize(); compositor->detachContext(); for (auto& r : renderers) { delegate->getOpenGLSurface()->accept(r.second, date); } } else { delegate->pushVideo(); delegate->streamSynchronize(); std::lock_guard lk(renderersLock); for (auto& r : renderers) { delegate->getSurface()->accept(r.second, date); } } } std::lock_guard lk(writersLock); for (auto& w : writers) { auto dsf = downsamplingFactors.find(w.first); assert(dsf != downsamplingFactors.end()); Frame frame = delegate->getFrame(w.second->getPixelFormat(), w.second->getExpectedOutputBufferType(), dsf->second); frame.pts = date; w.second->pushVideo(frame); } } template <> void WriterPusher::pushVideoToWriters(mtime_t date, SourceFrameBuffer* delegate) const { delegate->pushVideo(); delegate->streamSynchronize(); { std::lock_guard lk(renderersLock); for (auto& r : renderers) { delegate->getSurface()->accept(r.second, date); } } std::lock_guard lk(writersLock); for (auto& w : writers) { auto dsf = downsamplingFactors.find(w.first); assert(dsf != downsamplingFactors.end()); Frame frame = delegate->getFrame(w.second->getPixelFormat(), w.second->getExpectedOutputBufferType(), dsf->second); frame.pts = date; w.second->pushVideo(frame); } } template class WriterPusher; template class WriterPusher; } // namespace Core } // namespace VideoStitch