controller.hpp 10.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm

#pragma once

#include "inputControllerImpl.hpp"

#include "audio/audioPipeline.hpp"
#include "exposure/metadataProcessor.hpp"

#include "libvideostitch/orah/imuStabilization.hpp"
#include "libvideostitch/controller.hpp"
#include "libvideostitch/preprocessor.hpp"
#include "libvideostitch/postprocessor.hpp"

#include <list>
#include <mutex>

#ifdef ANDROID__GNUSTL
#define timed_mutex mutex
#define try_lock_for(a) try_lock()
#endif

#ifdef _MSC_VER
#pragma warning(push)
// using virtual inheritance of InputController on purpose
#pragma warning(disable : 4250)
#endif

namespace VideoStitch {

namespace Core {

class ImageMergerFactory;
class Mutex;
class PreProcessor;

/**
 * @brief Controller implementation.
 */
template <typename VideoPipeline>
class ControllerImpl
    : public InputControllerImpl,
      public StitcherController<typename VideoPipeline::Output, typename VideoPipeline::DeviceDefinition> {
  using typename StitcherController<typename VideoPipeline::Output, typename VideoPipeline::DeviceDefinition>::Output;
  using typename StitcherController<typename VideoPipeline::Output,
                                    typename VideoPipeline::DeviceDefinition>::DeviceDefinition;
  typedef typename Output::Writer Writer;

  using typename StitcherController<Output, DeviceDefinition>::PotentialOutput;
  using typename StitcherController<Output, DeviceDefinition>::PotentialController;

 public:
  /**
   * Factory function to create a Controller with the @pano PanoDefinition and the @readerFactory input ReaderFactory.
   * @param pano The panorama to stitch.
   * @param mergerFactory Factory to create mergers.
   * @param readerFactory The factory for reader. We take ownership.
   * @param preprocessors Vector of the preprocessors.
   * @param rig Stereo rig definition.
   */
  static PotentialController create(const PanoDefinition& pano, const AudioPipeDefinition& audioPipe,
                                    const ImageMergerFactory& mergerFactory, const ImageWarperFactory& warperFactory,
                                    const ImageFlowFactory& flowFactory, Input::ReaderFactory* readerFactory,
                                    const StereoRigDefinition* rig = nullptr);

  virtual ~ControllerImpl();

  virtual Status createStitcher() override;
  virtual void deleteStitcher() override;

  virtual bool addAudioOutput(std::shared_ptr<VideoStitch::Output::AudioWriter>) override;
  virtual bool removeAudioOutput(const std::string&) override;
  virtual void setAudioInput(const std::string& inputName) override;

  virtual Potential<ExtractOutput> createBlockingExtractOutput(
      int source, std::shared_ptr<SourceSurface>, std::shared_ptr<SourceRenderer> renderer,
      std::shared_ptr<VideoStitch::Output::VideoWriter> writer) override;

  virtual Potential<ExtractOutput> createAsyncExtractOutput(
      int source, const std::vector<std::shared_ptr<SourceSurface>>&, std::shared_ptr<SourceRenderer> renderer,
      std::shared_ptr<VideoStitch::Output::VideoWriter> writer) const override;

  virtual PotentialOutput createBlockingStitchOutput(std::shared_ptr<PanoSurface>,
                                                     const std::vector<std::shared_ptr<PanoRenderer>>& renderer,
                                                     const std::vector<std::shared_ptr<Writer>>& writers) override;

  virtual PotentialOutput createAsyncStitchOutput(const std::vector<std::shared_ptr<PanoSurface>>&,
                                                  const std::vector<std::shared_ptr<PanoRenderer>>& renderer,
                                                  const std::vector<std::shared_ptr<Writer>>& writers) const override;

  virtual ControllerStatus stitch(Output* output, bool readFrame) override;

  virtual ControllerStatus extract(ExtractOutput* output, bool readFrame) override;

  virtual ControllerStatus extract(std::vector<ExtractOutput*> extracts, AlgorithmOutput* algo,
                                   bool readFrame) override;

  virtual ControllerStatus stitchAndExtract(Output* output, std::vector<ExtractOutput*> extracts, AlgorithmOutput* algo,
                                            bool readFrame) override;

  virtual const PanoDefinition& getPano() const override { return *pano; }

  virtual const StereoRigDefinition* getRig() const override { return rig; }

  virtual bool isPanoChangeCompatible(const PanoDefinition& newPano) const override;

  virtual const ImageMergerFactory& getMergerFactory() const override { return *mergerFactory; }

  virtual const ImageWarperFactory& getWarperFactory() const override { return *warperFactory; }

  virtual const ImageFlowFactory& getFlowFactory() const override { return *flowFactory; }

  virtual int getCurrentFrame() const override { return readerController->getCurrentFrame(); }

  virtual Status updatePanorama(
      const std::function<Potential<PanoDefinition>(const PanoDefinition&)>& panoramaUpdater) override;
  virtual Status updatePanorama(const PanoDefinition& panorama) override;

  virtual Status resetRig(const StereoRigDefinition& newRig) override;
  virtual Status applyAudioProcessorParam(const AudioPipeDefinition& newAudioPipe) override;

  virtual Status resetMergerFactory(const ImageMergerFactory& newMergerFactory, bool redoSetupNow) override;

  virtual Status resetWarperFactory(const ImageWarperFactory& newWarperFactory, bool redoSetupNow) override;

  virtual Status resetFlowFactory(const ImageFlowFactory& newFlowFactory, bool redoSetupNow) override;

  virtual void applyRotation(double yaw, double pitch, double roll) override;

  virtual void resetRotation() override;
  virtual Quaternion<double> getRotation() const override;

  virtual void setSphereScale(const double sphereScale) override;

  ReaderController& getReaderCtrl() const { return *readerController; }

  std::vector<PreProcessor*> getPreProcessors() const { return preprocessors; }

  /**
   * Preprocessor accessor.
   * @returns The i-th preprocessor, or NULL if no preprocessor.
   * @note Inputs must be locked by the calling thread.
   */
  PreProcessor* getPreProcessor(int i) const;

  /**
   * Preprocessor setter.
   * @note Inputs must be locked by the calling thread.
   * @note The current i-th preprocessor will be deleted and replaced by @p.
   * @note @p ownership is tranferred to the ControllerImpl.
   */
  void setPreProcessor(int i, PreProcessor* p) override;

  /**
   * @brief enablePreProcessing
   * @param value enables preprocessing according to boolean value
   */
  void enablePreProcessing(bool value) override;

  /**
   * Enables/disables metadata processing.
   */
  virtual void enableMetadataProcessing(bool value) override;

  /**
   * Postprocessor accessor.
   */
  PostProcessor* getPostProcessor() const;

  /**
   * Returns true if preprocessing is enabled.
   */
  bool isPreProcessingEnabled() const { return preProcessingEnabled; }

  /**
   * Postprocessor setter.
   * @note The current postprocessor will be deleted and replaced by @p.
   * @note @p ownership is tranferred to the ControllerImpl.
   */
  void setPostProcessor(PostProcessor* p) override;

  /**
   * AudioPreprocessor setter.
   * @param name Name of the audio preprocessor to setup.
   * @param gr Group  id of the audio preprocessor to be applied.
   */
  void setAudioPreProcessor(const std::string& name, groupid_t gr) override {
    readerController->setupAudioPreProc(name, gr);
  }

  /**
   * Audio accessors.
   */
  bool hasAudio() const override { return audioPipe->hasAudio(); }

  Status seekFrame(frameid_t date) override { return readerController->seekFrame(date); }

  virtual bool hasVuMeter(const std::string& inputName) const override;

  virtual std::vector<double> getPeakValues(const std::string& inputName) const override;

  virtual std::vector<double> getRMSValues(const std::string& inputName) const override;

  virtual Status setAudioDelay(double delay_ms) override;

  /**
   * IMU Stabilization accessors
   */
  const Quaternion<double> getUserOrientation() override;
  void setUserOrientation(const Quaternion<double>& q) override;
  void updateUserOrientation(const Quaternion<double>& q) override;
  void resetUserOrientation() override;

  /**
   * @brief enables (true) or disables (false) the IMU stabilization
   *  It always resets previous user defined orientation
   */
  void enableStabilization(bool value) override;
  virtual bool isStabilizationEnabled() override;

  Stab::IMUStabilization& getStabilizationIMU() override;

  virtual mtime_t getLatency() const override;

  virtual Status addSink(const Ptv::Value* config) override;
  virtual void removeSink() override;

 protected:
  /**
   * Create a controller. Call init() after creation.
   * @param pano The panorama to stitch.
   * @param mergerFactory The factory for mergers.
   * @param readers Vector of the intput readers.
   * @param preprocessors Vector of the preprocessors.
   * @param maxStitchers Maximum number of stitchers that can live in parallel.
   * @param options controller options.
   * @param frameid_t Initial frame offset.
   */
  ControllerImpl(const PanoDefinition& pano, Audio::AudioPipeline* audioPipe, const ImageMergerFactory& mergerFactory,
                 const ImageWarperFactory& warperFactory, const ImageFlowFactory& flowFactory,
                 ReaderController* readerController, std::vector<PreProcessor*> preprocessors, PostProcessor* postproc,
                 const StereoRigDefinition*);

  virtual Status resetPano(const PanoDefinition& newPano) override;

 private:
  PanoDefinition* pano;
  const StereoRigDefinition* rig;

  std::timed_mutex panoramaUpdateLock;

  const ImageMergerFactory* mergerFactory;
  const ImageWarperFactory* warperFactory;
  const ImageFlowFactory* flowFactory;

  bool setupPending;

  std::vector<PreProcessor*> preprocessors;
  std::atomic<bool> preProcessingEnabled;
  std::atomic<bool> metadataProcessingEnabled;

  PostProcessor* postprocessor;

  mutable std::mutex stitcherMutex;  // protects pipeline.
  Audio::AudioPipeline* audioPipe;
  VideoPipeline* videoPipe;

  Stab::IMUStabilization stabilizationAlgorithm;
  Quaternion<double> qUserOrientation;
  bool stabilizationEnabled;

  Exposure::MetadataProcessor exposureProcessor;
};

#define PROPAGATE_CONTROLLER_FAILURE_STATUS(call) \
  {                                               \
    const ControllerStatus status = (call);       \
    if (!status.ok()) {                           \
      return status;                              \
    }                                             \
  }
#define FAIL_CONTROLLER_RETURN PROPAGATE_CONTROLLER_FAILURE_STATUS
}  // namespace Core
}  // namespace VideoStitch

#ifdef _MSC_VER
#pragma warning(pop)
#endif