imageMapping.hpp 7.54 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
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm

#pragma once

#include "textureTarget.hpp"

#include "core/rect.hpp"

#include "gpu/allocator.hpp"
#include "gpu/hostBuffer.hpp"
#include "gpu/uniqueBuffer.hpp"
#include "gpu/stream.hpp"
#include "gpu/surface.hpp"

namespace VideoStitch {
namespace Input {
class VideoReader;
struct PotentialFrame;
}  // namespace Input

namespace Core {

class InputDefinition;
class PanoDefinition;
class PreProcessor;
class Transform;
class ImageMerger;
class ImageWarper;
class ImageWarperFactory;
class ImageFlow;
class ImageFlowFactory;
class ImageMergerFactory;
class InputsMap;
class InputsMapCubemap;
class MergerPair;
class StereoRigDefinition;

class Buffer;

class ImageMapping {
 public:
  /**
   * Creates an ImageMapping for the @a imId th input of @a pano.
   * @param imId The input id.
   */
  explicit ImageMapping(videoreaderid_t imId);
  virtual ~ImageMapping();

  Status setup(ImageMapping* prevMapping, const PanoDefinition&, const ImageMergerFactory&, std::shared_ptr<InputsMap>,
               GPU::Stream, bool progressive = false);

  /**
   * Remap the next frame in @a reader asynchronously in stream @a stream.
   * @param frame Current frame id.
   * @param pano the pano definition
   * @param progressivePbo the progessive output panorama in case of other merger
   * @param panoSurf the output panorama to avoid memcopy in case of gradient merger
   * @param stream Where to do the computations.
   */
  virtual Status warp(frameid_t frame, const PanoDefinition& pano, GPU::Buffer<uint32_t> progressivePbo,
                      GPU::Surface& panoSurf, GPU::Stream& stream);
  Status warpCubemap(frameid_t frame, const PanoDefinition& pano, bool equiangular, GPU::Stream& stream);

  virtual Status reconstruct(TextureTarget, const PanoDefinition&, GPU::Buffer<uint32_t>, bool final,
                             GPU::Stream&) const;

  /**
   * Precomputed the wrapped coordinate asynchronously in stream @a stream.
   * @param frame Current frame id.
   * @param pano the pano definition
   * @param stream Where to do the computations.
   * @param reader The input reader. If null, remap the contents of the current devArray.
   * @param preprocessor If not NULL, a preprocessor that will be applied before mapping.
   */
  Status precomputedCoord(frameid_t frame, const PanoDefinition& pano, GPU::Stream& stream);

  /**
   * Sets up the texture array from the given reader.
   * @param inputDef the input definition
   * @param stream Where to do the computations.
   * @param reader The input reader. If null, don't read.
   * @param preprocessor If not NULL, a preprocessor that will be applied before mapping.
   */
  Status setupTexArrayAsync(frameid_t frame1, const Input::PotentialFrame& inputFrame, const InputDefinition& inputDef,
                            GPU::Stream& stream, Input::VideoReader* reader, const PreProcessor* preprocessor);
  /**
   * Allocates all host and device buffers.
   */
  Status allocateUnpackBuffer(int64_t frameDataSize);
  Status allocateBuffers(TextureTarget, int64_t width, int64_t height);

  /**
   * Allocates device buffers, and use the passed-in buffer as host input buffer. This is used for re-setup.
   * The input buffer already contains data from the previous frame.
   * @param readerSpec Spec for the reader that this mapper reads from.
   * @param hostInputBuffer Input buffer. Destroyed.
   * @param allocPrecomputedCoordinate Whether to allocate the precomputed coordinate buffer.
   */
  Status allocateBuffersPartial(TextureTarget, int64_t width, int64_t height, SourceSurface* hostInputBuffer);

  void setHBounds(TextureTarget, int64_t l, int64_t r, int64_t panoCroppedWidth);

  void setVBounds(TextureTarget, int64_t t, int64_t b);

  const Rect& getOutputRect(TextureTarget t) const { return outputBounds[t]; }
  Rect& getOutputRect(TextureTarget t) { return outputBounds[t]; }

  frameid_t getFrameId() const { return frameId; }

  void setFrameId(const frameid_t frameId) { this->frameId = frameId; }

  /**
   * Give away our input buffers. This is used when re-setupping to keep the last input frame.
   * This invalidates *this, and must be the last operation before deletion.
   * @param buffers The buffers are given to this object.
   * @return The input buffer. The caller is responsible for releasing the result.
   */
  void releaseInputBuffers(SourceSurface** sourceSurf) {
    *sourceSurf = surface;
    surface = nullptr;
  }

  /**
   * returns the input buffer after unpacking (stored on the GPU)
   */
  GPU::Surface& getSurface() { return *surface->pimpl->surface; }

  /**
   * returns the precomputed buffer coordinate for mapping
   */
  GPU::Surface& getSurfaceCoord() { return *devCoord->pimpl->surface; }

  const ImageMerger& getMerger() const { return *merger; }
  ImageMerger& getMerger() { return *merger; }

  /**
   * returns a buffer of size inputArea() * 4,
   * correctly allocated for efficient CUDA transmission.
   */
  GPU::Buffer<const uint32_t> getDeviceOutputBuffer(TextureTarget t) const { return devWork[t].borrow_const(); }

  videoreaderid_t getImId() const { return imId; }

  bool wraps() const {
    assert(wrapsAround >= 0);  // <0 means not computed.
    return wrapsAround > 0 ? true : false;
  }

 protected:
  // Common part of allocateBuffers() and allocateBuffersPartial().
  virtual Status allocateOutputBuffers(TextureTarget, int64_t width, int64_t height);

  // bounding box
  frameid_t frameId;
  std::array<Rect, TEXTURE_TARGET_SIZE> outputBounds;
  int wrapsAround;

  std::array<GPU::UniqueBuffer<uint32_t>, TEXTURE_TARGET_SIZE>
      devWork;  // input buffer for no-flow, mapped output buffer

  const videoreaderid_t imId;
  SourceSurface* surface = nullptr;

  ImageMerger* merger = nullptr;
  Transform* transform = nullptr;

  GPU::UniqueBuffer<unsigned char> devUnpackTmp;  // array to hold intermediate data before unpacking
  Core::SourceSurface* devCoord = nullptr;        // array to hold precomputed coordinate for mapping
};

class ImageMappingFlow : public ImageMapping {
 public:
  explicit ImageMappingFlow(unsigned imId) : ImageMapping(imId), warper(nullptr), flow(nullptr) {}

  virtual ~ImageMappingFlow();

  Status setup(ImageMappingFlow* prevMapping, const PanoDefinition&, const StereoRigDefinition* rigDef,
               const ImageMergerFactory&, std::vector<readerid_t> alreadyWarped, std::shared_ptr<InputsMap>,
               const ImageWarperFactory&, const ImageFlowFactory&, GPU::Stream);

  /**
   * Remap the next frame in @a reader synchronously in stream @a stream using flow-based warper.
   * @param frame Current frame id.
   * @param pano the pano definition
   * @param progressivePbo the progessive output panorama in case of other merger
   * @param panoSurf the output panorama to avoid memcopy in case of gradient merger
   * @param stream Where to do the computations.
   */
  Status warp(frameid_t frame, const PanoDefinition& pano, GPU::Buffer<uint32_t> progressivePbo, GPU::Surface& panoSurf,
              GPU::Stream& stream) override;
  Status reconstruct(TextureTarget, const PanoDefinition&, GPU::Buffer<uint32_t> progressivePbo, bool final,
                     GPU::Stream&) const override;

  Status allocateOutputBuffers(TextureTarget, int64_t width, int64_t height) override;

 private:
  GPU::UniqueBuffer<uint32_t> devFlowIn;  // input image buffer when using flow based blending

  ImageWarper* warper;
  ImageFlow* flow;
  std::shared_ptr<MergerPair> mergerPair;

  ImageMappingFlow(const ImageMappingFlow&) = delete;
  ImageMappingFlow& operator=(const ImageMappingFlow&) = delete;
};

}  // namespace Core
}  // namespace VideoStitch