// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm #include "projectdefinition.hpp" #include "libvideostitch-gui/caps/signalcompressioncaps.hpp" #include "libvideostitch-gui/mainwindow/msgboxhandlerhelper.hpp" #include "libvideostitch-base/file.hpp" #include "libvideostitch-base/logmanager.hpp" #include "libvideostitch/inputDef.hpp" #include "libvideostitch/geometryDef.hpp" #include "libvideostitch/inputFactory.hpp" #include "libvideostitch/imageMergerFactory.hpp" #include "libvideostitch/imageFlowFactory.hpp" #include "libvideostitch/imageWarperFactory.hpp" #include "libvideostitch/input.hpp" #include "libvideostitch/logging.hpp" #include "libvideostitch/parse.hpp" #include "libvideostitch/projections.hpp" #include "libvideostitch/ptv.hpp" #include "libvideostitch/rigDef.hpp" #include "libvideostitch/config.hpp" #include "version.hpp" #include #include #define VS_MUTEX_LOCK QMutexLocker lock(&mutex); ProjectDefinition::ProjectDefinition() : mutex(QMutex::Recursive), signalCompressor(SignalCompressionCaps::create()), isModified(false), drawInputNumbers(false), displayOrientationGrid(false) {} ProjectDefinition::~ProjectDefinition() { VS_MUTEX_LOCK signalCompressor->autoDelete(); } bool ProjectDefinition::validatePanorama(std::stringstream& errsink) { VS_MUTEX_LOCK if (!getDelegate()) { return false; } else { return getPanoConst()->validate(errsink); } } void ProjectDefinition::setDefaultPtvValues(const VideoStitch::Ptv::Value& value) { VS_MUTEX_LOCK load(value); } QString ProjectDefinition::getInputName(int index) const { VideoStitch::Core::InputDefinition& input = getPano()->getInput(index); const std::string name = input.getDisplayName(); QString formattedName = QString::fromStdString(name); if (formattedName.contains("%0")) { formattedName = formattedName.arg(index); } return formattedName; } void ProjectDefinition::copyValuesIntoVector(std::vector& vector, const QVector inputList) { for (auto value : inputList) { VideoStitch::Ptv::Value* input = VideoStitch::Ptv::Value::emptyObject(); input->asInt() = value; vector.push_back(input); } } bool ProjectDefinition::load(const VideoStitch::Ptv::Value& value) { VS_MUTEX_LOCK bool oldHasImagesOrProceduralsOnly = hasImagesOrProceduralsOnly(); bool oldHasSeveralVideos = hasSeveralVideos(); bool oldHasSeveralVisualInputs = hasSeveralVisualInputs(); // close the current project destroyDelegate(); setModified(false); drawInputNumbers = false; displayOrientationGrid = false; // parse a new project definition createDelegate(value); bool newHasImagesOrProceduralsOnly = hasImagesOrProceduralsOnly(); if (oldHasImagesOrProceduralsOnly != newHasImagesOrProceduralsOnly) { emit imagesOrProceduralsOnlyHasChanged(newHasImagesOrProceduralsOnly); } bool newHasSeveralVideos = hasSeveralVideos(); if (oldHasSeveralVideos != newHasSeveralVideos) { emit severalVideosOnlyHasChanged(newHasSeveralVideos); } bool newHasSeveralVisualInputs = hasSeveralVisualInputs(); if (oldHasSeveralVisualInputs != newHasSeveralVisualInputs) { emit severalVisualInputsHasChanged(newHasSeveralVisualInputs); } return getDelegate() != nullptr; } void ProjectDefinition::close() { destroyDelegate(); } bool ProjectDefinition::isInit() const { VS_MUTEX_LOCK return getDelegate() != nullptr; } VideoStitch::Ptv::Value* ProjectDefinition::serialize() const { VS_MUTEX_LOCK if (!getDelegate()) { return nullptr; } else { return getDelegate()->serialize(); } } PanoDefinitionLocked ProjectDefinition::getPano() const { VS_MUTEX_LOCK if (!getDelegate()) { return PanoDefinitionLocked(nullptr, this); } else { return PanoDefinitionLocked(&getDelegate()->getPanoDefinition(), this); } } const PanoDefinitionLocked ProjectDefinition::getPanoConst() const { VS_MUTEX_LOCK if (!getDelegate()) { return PanoDefinitionLocked(nullptr, this); } else { return PanoDefinitionLocked(&getDelegate()->getPanoDefinition(), this); } } AudioPipeDefinitionLocked ProjectDefinition::getAudioPipe() const { VS_MUTEX_LOCK if (!getDelegate()) { return AudioPipeDefinitionLocked(nullptr, this); } else { return AudioPipeDefinitionLocked(&getDelegate()->getAudioPipe(), this); } } const AudioPipeDefinitionLocked ProjectDefinition::getAudioPipeConst() const { VS_MUTEX_LOCK if (!getDelegate()) { return AudioPipeDefinitionLocked(nullptr, this); } else { return AudioPipeDefinitionLocked(&getDelegate()->getAudioPipe(), this); } } StereoRigDefinitionLocked ProjectDefinition::getStereoRig() const { VS_MUTEX_LOCK if (!getDelegate()) { return StereoRigDefinitionLocked(nullptr, this); } else { return StereoRigDefinitionLocked(getDelegate()->getStereoRigDefinition(), this); } } const StereoRigDefinitionLocked ProjectDefinition::getStereoRigConst() const { VS_MUTEX_LOCK if (!getDelegate()) { return StereoRigDefinitionLocked(nullptr, this); } else { return StereoRigDefinitionLocked(getDelegate()->getStereoRigDefinition(), this); } } ImageMergerFactoryLocked ProjectDefinition::getImageMergerFactory() const { VS_MUTEX_LOCK if (!getDelegate()) { return ImageMergerFactoryLocked(nullptr, this); } else { return ImageMergerFactoryLocked(&getDelegate()->getImageMergerFactory(), this); } } ImageFlowFactoryLocked ProjectDefinition::getImageFlowFactory() const { VS_MUTEX_LOCK if (!getDelegate()) { return ImageFlowFactoryLocked(NULL, this); } else { return ImageFlowFactoryLocked(&getDelegate()->getImageFlowFactory(), this); } } ImageWarperFactoryLocked ProjectDefinition::getImageWarperFactory() const { VS_MUTEX_LOCK if (!getDelegate()) { return ImageWarperFactoryLocked(NULL, this); } else { return ImageWarperFactoryLocked(&getDelegate()->getImageWarperFactory(), this); } } QString ProjectDefinition::getBlender() const { VS_MUTEX_LOCK std::unique_ptr mergerfactory(getImageMergerFactory()->serialize()); std::string blender = mergerfactory->has("type") ? mergerfactory->has("type")->asString() : std::string(); return QString::fromStdString(blender); } int ProjectDefinition::getFeather() const { VS_MUTEX_LOCK std::unique_ptr mergerfactory(getImageMergerFactory()->serialize()); if (mergerfactory->has("feather")) { return mergerfactory->has("feather")->asInt(); } else { return 100; } } double ProjectDefinition::getSphereScale() const { VS_MUTEX_LOCK if (!getDelegate()) { return PTV_DEFAULT_PANODEF_SPHERE_SCALE; } else { return getPanoConst()->getSphereScale(); } } double ProjectDefinition::computeMinimumSphereScale() const { VS_MUTEX_LOCK if (!getDelegate()) { return PTV_DEFAULT_PANODEF_MIN_SPHERE_SCALE; } else { return getPanoConst()->computeMinimumRigSphereRadius(); } } void ProjectDefinition::setSphereScale(double sphereScale) { VS_MUTEX_LOCK if (getDelegate()) { if (getPanoConst()->getSphereScale() != sphereScale) { getPano()->setSphereScale(sphereScale); setModified(true); emit reqReset(signalCompressor->add()); } } } QString ProjectDefinition::getFlow() const { VS_MUTEX_LOCK return QString::fromStdString(getImageFlowFactory()->getImageFlowName()); } QString ProjectDefinition::getWarper() const { VS_MUTEX_LOCK std::string warper = getImageWarperFactory()->getImageWarperName(); return QString::fromStdString(warper); } readerid_t ProjectDefinition::getNumInputs() const { VS_MUTEX_LOCK if (!getDelegate()) { return 0; } else { return getPanoConst()->numInputs(); } } QStringList ProjectDefinition::getInputNames() const { VS_MUTEX_LOCK QStringList inputNames; if (getDelegate()) { for (readerid_t i = 0; i < getPano()->numInputs(); ++i) { QString inputName = getInputName(int(i)); if (!inputName.isEmpty()) { inputNames.append(inputName); } } } return inputNames; } QStringList ProjectDefinition::getAudioInputNames() const { VS_MUTEX_LOCK QStringList inputNames; if (getDelegate()) { for (size_t i = 0; i < getAudioPipeConst()->numAudioMixes(); ++i) { inputNames.append(QString::fromStdString(getAudioPipeConst()->getMix(int(i))->getName())); } } return inputNames; } QStringList ProjectDefinition::getVideoInputNames() const { VS_MUTEX_LOCK QStringList inputNames; if (getDelegate()) { for (VideoStitch::Core::InputDefinition& input : getPano()->getVideoInputs()) { inputNames.append(QString::fromStdString(input.getDisplayName())); } } return inputNames; } VideoStitch::InputFormat::InputFormatEnum ProjectDefinition::getVideoInputType() const { VS_MUTEX_LOCK; for (readerid_t inputIndex = 0; inputIndex < getNumInputs(); ++inputIndex) { const VideoStitch::Core::InputDefinition& input = getPano()->getInput(inputIndex); if (input.getIsVideoEnabled()) { const VideoStitch::Ptv::Value& value = input.getReaderConfig(); if (value.has("type") != nullptr) { return VideoStitch::InputFormat::getEnumFromString(QString::fromStdString(value.has("type")->asString())); } else { const QString name(QString::fromStdString(value.asString())); if (VideoStitch::InputFormat::isVideoStream(name)) { return VideoStitch::InputFormat::InputFormatEnum::NETWORK; } else if (VideoStitch::InputFormat::isVideoFile(name)) { return VideoStitch::InputFormat::InputFormatEnum::MEDIA; } } } } return VideoStitch::InputFormat::InputFormatEnum::INVALID; } bool ProjectDefinition::hasAnInputWithAudioOnly() const { VS_MUTEX_LOCK; for (readerid_t inputIndex = 0; inputIndex < getNumInputs(); ++inputIndex) { const VideoStitch::Core::InputDefinition& input = getPano()->getInput(inputIndex); if (input.getIsAudioEnabled() && !input.getIsVideoEnabled()) { return true; } } return false; } bool ProjectDefinition::hasAudio() const { VS_MUTEX_LOCK; return getAudioPipeConst().get() != nullptr && getAudioPipeConst()->numAudioInputs() > 0; } bool ProjectDefinition::hasImagesOrProceduralsOnly() const { VS_MUTEX_LOCK; for (readerid_t inputIndex = 0; inputIndex < getNumInputs(); ++inputIndex) { const VideoStitch::Core::InputDefinition& input = getPano()->getInput(inputIndex); const VideoStitch::Ptv::Value& value = input.getReaderConfig(); if (input.getIsVideoEnabled() && value.getType() == VideoStitch::Ptv::Value::STRING) { const QString name(QString::fromStdString(value.asString())); bool isAProcedural = name.startsWith("procedural:"); bool isAnImage = File::getTypeFromFile(name) == File::STILL_IMAGE; if (!isAProcedural && !isAnImage) { return false; } } } return true; } bool ProjectDefinition::hasSeveralVideos() const { VS_MUTEX_LOCK; int nbVideoInputs = 0; for (readerid_t inputIndex = 0; inputIndex < getNumInputs(); ++inputIndex) { const VideoStitch::Core::InputDefinition& input = getPano()->getInput(inputIndex); const VideoStitch::Ptv::Value& value = input.getReaderConfig(); const QString name(QString::fromStdString(value.asString())); if (input.getIsVideoEnabled() && value.getType() == VideoStitch::Ptv::Value::STRING) { const QString name(QString::fromStdString(value.asString())); bool isAProcedural = name.startsWith("procedural:"); bool isAnImage = File::getTypeFromFile(name) == File::STILL_IMAGE; if (isAProcedural || isAnImage) { return false; } ++nbVideoInputs; } } return nbVideoInputs >= 2; } bool ProjectDefinition::hasSeveralVisualInputs() const { VS_MUTEX_LOCK; return getPanoConst().get() != nullptr && getPanoConst()->numVideoInputs() >= 2; } InputLensClass::LensType ProjectDefinition::getProjectLensType() const { return InputLensClass::getLensTypeFromInputDefinitionFormat(getPanoConst()->getLensFormatFromInputSources()); } bool ProjectDefinition::hasCroppedArea() const { for (const VideoStitch::Core::InputDefinition& inputDef : getPanoConst()->getVideoInputs()) { if (inputDef.hasCroppedArea()) { return true; } } return false; } QString ProjectDefinition::getProjection() const { VS_MUTEX_LOCK if (!getDelegate()) { return "equirectangular"; } else { return QString(getPanoConst()->getFormatName(getPanoConst()->getProjection())); } } double ProjectDefinition::getHFOV() const { VS_MUTEX_LOCK if (!getDelegate()) { return 160.0; } else { return getPanoConst()->getHFOV(); } } bool ProjectDefinition::hasFileFormatChanged() const { if (getDelegate()) { return getDelegate()->hasFileFormatChanged(); } else { return false; } } void ProjectDefinition::updateFileFormat() { if (getDelegate()) { getDelegate()->updateFileFormat(); } } void ProjectDefinition::setAudioPipe(VideoStitch::Core::AudioPipeDefinition* audioPipeDefinition) { VS_MUTEX_LOCK if (getDelegate() && audioPipeDefinition != nullptr && (&getDelegate()->getAudioPipe() != audioPipeDefinition)) { getDelegate()->setAudioPipe(audioPipeDefinition); setModified(true); } } void ProjectDefinition::setPano(VideoStitch::Core::PanoDefinition* panoDefinition) { VS_MUTEX_LOCK if (getDelegate() && panoDefinition != nullptr && (&getDelegate()->getPanoDefinition() != panoDefinition)) { getDelegate()->setPano(panoDefinition); setModified(true); } } void ProjectDefinition::setMergerFactory(VideoStitch::Core::ImageMergerFactory* merger) { VS_MUTEX_LOCK if (getDelegate() && merger != nullptr && (&getDelegate()->getImageMergerFactory() != merger)) { getDelegate()->setMergerFactory(merger); setModified(true); } } void ProjectDefinition::setFlowFactory(VideoStitch::Core::ImageFlowFactory* flow) { VS_MUTEX_LOCK if (getDelegate() && flow != nullptr && (&getDelegate()->getImageFlowFactory() != flow)) { getDelegate()->setFlowFactory(flow); setModified(true); } } void ProjectDefinition::setWarperFactory(VideoStitch::Core::ImageWarperFactory* warper) { VS_MUTEX_LOCK if (getDelegate() && warper != nullptr && (&getDelegate()->getImageWarperFactory() != warper)) { getDelegate()->setWarperFactory(warper); setModified(true); } } void ProjectDefinition::setStereoRigDefinition(VideoStitch::Core::StereoRigDefinition* rigDefinition) { VS_MUTEX_LOCK if (getDelegate() && rigDefinition != nullptr && (getDelegate()->getStereoRigDefinition() != rigDefinition)) { getDelegate()->setRig(rigDefinition); setModified(true); } } void ProjectDefinition::setModified(const bool modified) { VS_MUTEX_LOCK if (modified != isModified) { emit hasBeenModified(modified); } isModified = modified; } void ProjectDefinition::markAsSaved() { setModified(false); } bool ProjectDefinition::hasLocalModifications() const { VS_MUTEX_LOCK return isModified; } void ProjectDefinition::updateSize(int width, int height) { VS_MUTEX_LOCK if (getDelegate()) { if (getPanoConst()->getWidth() != width || getPanoConst()->getHeight() != height) { getPano()->setWidth(width); getPano()->setHeight(height); setModified(true); } } } void ProjectDefinition::setProjection(QString projection) { VS_MUTEX_LOCK if (getDelegate()) { if (getPanoConst()->getFormatName(getPanoConst()->getProjection()) != projection) { getPano()->setProjection(getPanoConst()->getFormatFromName(projection.toStdString())); setModified(true); } } } bool ProjectDefinition::isDrawingInputNumbers() const { VS_MUTEX_LOCK return drawInputNumbers; } void ProjectDefinition::setHFov(double fov) { VS_MUTEX_LOCK if (getDelegate()) { if (getPanoConst()->getHFOV() != fov) { getPano()->setHFOV(fov); setModified(true); } } } void ProjectDefinition::setDrawInputNumbers(bool draw) { VS_MUTEX_LOCK drawInputNumbers = draw; } void ProjectDefinition::toggleInputNumberDrawing() { VS_MUTEX_LOCK drawInputNumbers = !drawInputNumbers; emit reqToggleInputNumbers(drawInputNumbers); } void ProjectDefinition::changeBlendingParameters(QString merger, int feather) { VS_MUTEX_LOCK std::unique_ptr value(VideoStitch::Ptv::Value::emptyObject()); value->get("type")->asString() = merger.toStdString(); value->get("feather")->asInt() = feather; auto fStatus = VideoStitch::Core::ImageMergerFactory::createMergerFactory(*value); if (!fStatus.ok()) { MsgBoxHandlerHelper::genericErrorMessage({VideoStitch::Origin::Stitcher, VideoStitch::ErrType::SetupFailure, tr("Could not create the image merger").toStdString(), fStatus.status()}); return; } setMergerFactory(fStatus.release()); } void ProjectDefinition::changeAdvancedBlendingParameters(const QString& flow, const QString& warper) { VS_MUTEX_LOCK std::unique_ptr flowValue(VideoStitch::Ptv::Value::emptyObject()); flowValue->get("type")->asString() = flow.toStdString(); auto flowStatus = VideoStitch::Core::ImageFlowFactory::createFlowFactory(flowValue.get()); if (!flowStatus.ok()) { MsgBoxHandlerHelper::genericErrorMessage({VideoStitch::Origin::Stitcher, VideoStitch::ErrType::SetupFailure, tr("Could not create the image flow").toStdString(), flowStatus.status()}); return; } std::unique_ptr warperValue(VideoStitch::Ptv::Value::emptyObject()); warperValue->get("type")->asString() = warper.toStdString(); auto warperStatus = VideoStitch::Core::ImageWarperFactory::createWarperFactory(warperValue.get()); if (!warperStatus.ok()) { MsgBoxHandlerHelper::genericErrorMessage({VideoStitch::Origin::Stitcher, VideoStitch::ErrType::SetupFailure, tr("Could not create the image warper").toStdString(), warperStatus.status()}); return; } setFlowFactory(flowStatus.release()); setWarperFactory(warperStatus.release()); } void ProjectDefinition::setDisplayOrientationGrid(bool display, bool reqRestitch) { VS_MUTEX_LOCK displayOrientationGrid = display; if (reqRestitch) { emit reqDisplayOrientationGrid(displayOrientationGrid); } } bool ProjectDefinition::getDisplayOrientationGrid() const { VS_MUTEX_LOCK return displayOrientationGrid; } void ProjectDefinition::getCroppedImageSize(unsigned& width, unsigned& height) const { VS_MUTEX_LOCK if (!getDelegate()) { width = 0; height = 0; return; } else { width = getPanoConst()->getWidth(); height = getPanoConst()->getHeight(); } } #define INTERACTIVE_FOV 360 #define MAX_STEREOGRAPHIC_FOV 360 #define DEFAULT_RECTILINEAR_FOV 160 #define DEFAULT_STEREOGRAPHIC_FOV 320 #define MAX_RECTILINEAR_FOV 180 void ProjectDefinition::changeProjection(const QString& projName, const double HFOV) { if (!isInit()) { return; } QString projection = projName; VideoStitch::Core::PanoProjection proj = (projName == "interactive") ? VideoStitch::Core::PanoProjection(VideoStitch::Core::PanoProjection::Equirectangular) : getPano()->getFormatFromName(projName.toStdString()); double fov = HFOV; double currHFOV = getPano()->getHFOV(); if (getPano()->getProjection() != proj || (currHFOV != HFOV)) { // particular cases currHFOV = HFOV; if (projName == "interactive") { //"interactive" is "equirectangular" displayed differently if ((getPano()->getHFOV() == INTERACTIVE_FOV) && getPano()->getProjection() == VideoStitch::Core::PanoProjection::Equirectangular) { return; } projection = "equirectangular"; fov = INTERACTIVE_FOV; // FIXME: we modify the user settings to avoid rejection of the PTV but we never set it back, see #232 updateSize(getPano()->getWidth(), getPano()->getWidth() / 2); } else { getPano()->setProjection(getPano()->getFormatFromName(projName.toStdString())); if (proj == VideoStitch::Core::PanoProjection::Stereographic && (currHFOV >= MAX_STEREOGRAPHIC_FOV)) { fov = DEFAULT_STEREOGRAPHIC_FOV; getPano()->setHFOV(DEFAULT_STEREOGRAPHIC_FOV); } else if (proj == VideoStitch::Core::PanoProjection::Rectilinear && (currHFOV >= MAX_RECTILINEAR_FOV)) { fov = DEFAULT_RECTILINEAR_FOV; getPano()->setHFOV(DEFAULT_RECTILINEAR_FOV); } } setHFov(fov); setProjection(projection); emit reqReset(signalCompressor->add()); } } void ProjectDefinition::updateMasks() { if (!isInit()) { Q_ASSERT(0); return; } bool userNeedsToBeWarned = false; for (int i = 0; i < (int)getPano()->numInputs(); i++) { VideoStitch::Core::InputDefinition& inputDef = getPano()->getInput(i); const VideoStitch::Core::InputDefinition::MaskPixelData& mask = inputDef.getMaskPixelData(); int maskSize = mask.getWidth() * mask.getHeight(); if (mask.getData() != nullptr) { if (mask.getWidth() == inputDef.getWidth() && mask.getHeight() == inputDef.getHeight()) { unsigned char* data = new unsigned char[maskSize]; memcpy(data, mask.getData(), maskSize); emit reqUpdateMask(i, data, mask.getWidth(), mask.getHeight()); } else { userNeedsToBeWarned = true; QImage* scaledImage = new QImage(QImage(mask.getData(), mask.getWidth(), mask.getHeight(), QImage::Format_Indexed8) .scaled(inputDef.getWidth(), inputDef.getHeight())); inputDef.setMaskPixelData((char*)scaledImage->bits(), inputDef.getWidth(), inputDef.getHeight()); emit reqUpdateMask(i, scaledImage); } } } emit maskUpdateDone(); if (userNeedsToBeWarned) { emit reqDisplayWarning(tr("The size of your mask doesn't match the input's size.") + QString("
") + tr("Your mask has been scaled to fit the input size.")); } } bool ProjectDefinition::hasRigConfiguration() const { if (!isInit()) { return false; } else { return getDelegate()->getStereoRigDefinition() != nullptr; } } int ProjectDefinition::getAudioDelay() const { if (getAudioPipeConst().get() && getAudioPipeConst()->numAudioInputs() > 0) { return int(getAudioPipeConst()->getDelay(getAudioPipeConst()->getInput(0)->getName()).ref()); } else { return 0; } } void ProjectDefinition::setInputCrop(const unsigned int currentInput, const Crop& crop, const InputLensClass::LensType lensType, const bool applyToAll) { const auto initIndex = applyToAll ? 0 : currentInput; const auto lastIndex = applyToAll ? getPano()->numInputs() : currentInput + 1; VideoStitch::Core::PanoDefinition* clonedPano = getPano()->clone(); for (auto input = initIndex; input < lastIndex; ++input) { // Skip non-video inputs if (!clonedPano->getInput(input).getIsVideoEnabled()) { continue; } clonedPano->getInput(input).setFormat(InputLensClass::getInputDefinitionFormatFromLensType( lensType, getPanoConst()->getLensModelCategoryFromInputSources())); clonedPano->getInput(input).setCrop(crop.crop_left, crop.crop_right, crop.crop_top, crop.crop_bottom); } setPano(clonedPano); } void ProjectDefinition::setRigConfiguration(const VideoStitch::Core::StereoRigDefinition::Orientation orientation, const VideoStitch::Core::StereoRigDefinition::Geometry geometry, const double diameter, const double ipd, const QVector leftInputs, const QVector rightInputs) { VideoStitch::Core::StereoRigDefinition* clonedRig = nullptr; // There's no Rig configuration yet StereoRigDefinitionLocked rig = getStereoRigConst(); if (rig.get() != nullptr) { VideoStitch::Ptv::Value* rigValue = VideoStitch::Ptv::Value::emptyObject(); std::vector leftVector; std::vector rightVector; copyValuesIntoVector(leftVector, leftInputs); copyValuesIntoVector(rightVector, rightInputs); rigValue->get("orientation")->asString() = VideoStitch::Core::StereoRigDefinition::getOrientationName(orientation); rigValue->get("geometry")->asString() = VideoStitch::Core::StereoRigDefinition::getGeometryName(geometry); rigValue->get("diameter")->asDouble() = diameter; rigValue->get("ipd")->asDouble() = ipd; rigValue->get("left_inputs")->asList() = leftVector; rigValue->get("right_inputs")->asList() = rightVector; clonedRig = VideoStitch::Core::StereoRigDefinition::create(*rigValue); // There's an existing rig already } else { clonedRig = getStereoRig()->clone(); clonedRig->setOrientation(orientation); clonedRig->setGeometry(geometry); clonedRig->setDiameter(diameter); clonedRig->setIPD(ipd); clonedRig->setLeftInputs(leftInputs.toStdVector()); clonedRig->setRightInputs(rightInputs.toStdVector()); } setStereoRigDefinition(clonedRig); } void ProjectDefinition::setInterPupillaryDistance(double ipd) { VideoStitch::Core::StereoRigDefinition* clonedRig = getStereoRig()->clone(); clonedRig->setIPD(ipd); setStereoRigDefinition(clonedRig); emit reqResetRig(signalCompressor->add()); } void ProjectDefinition::setAudioDelay(int delay_ms) { VS_MUTEX_LOCK emit reqSetAudioDelay(delay_ms); } void ProjectDefinition::lock() const { mutex.lock(); } void ProjectDefinition::unlock() const { mutex.unlock(); }