// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "libcef/browser/osr/video_consumer_osr.h"

#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/osr/render_widget_host_view_osr.h"

#include "media/base/video_frame_metadata.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "ui/gfx/skbitmap_operations.h"

namespace {

// Helper to always call Done() at the end of OnFrameCaptured().
class ScopedVideoFrameDone {
 public:
  explicit ScopedVideoFrameDone(
      mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
          callbacks)
      : callbacks_(std::move(callbacks)) {}
  ~ScopedVideoFrameDone() { callbacks_->Done(); }

 private:
  mojo::Remote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks> callbacks_;
};

}  // namespace

CefVideoConsumerOSR::CefVideoConsumerOSR(CefRenderWidgetHostViewOSR* view)
    : view_(view), video_capturer_(view->CreateVideoCapturer()) {
  video_capturer_->SetFormat(media::PIXEL_FORMAT_ARGB,
                             gfx::ColorSpace::CreateREC709());

  // Always use the highest resolution within constraints that doesn't exceed
  // the source size.
  video_capturer_->SetAutoThrottlingEnabled(false);
  video_capturer_->SetMinSizeChangePeriod(base::TimeDelta());

  SizeChanged(view_->SizeInPixels());
  SetActive(true);
}

CefVideoConsumerOSR::~CefVideoConsumerOSR() = default;

void CefVideoConsumerOSR::SetActive(bool active) {
  if (active) {
    video_capturer_->Start(this);
  } else {
    video_capturer_->Stop();
  }
}

void CefVideoConsumerOSR::SetFrameRate(base::TimeDelta frame_rate) {
  video_capturer_->SetMinCapturePeriod(frame_rate);
}

void CefVideoConsumerOSR::SizeChanged(const gfx::Size& size_in_pixels) {
  if (size_in_pixels_ == size_in_pixels)
    return;
  size_in_pixels_ = size_in_pixels;

  // Capture resolution will be held constant.
  video_capturer_->SetResolutionConstraints(size_in_pixels, size_in_pixels,
                                            true /* use_fixed_aspect_ratio */);
}

void CefVideoConsumerOSR::RequestRefreshFrame(
    const base::Optional<gfx::Rect>& bounds_in_pixels) {
  bounds_in_pixels_ = bounds_in_pixels;
  video_capturer_->RequestRefreshFrame();
}

// Frame size values are as follows:
//   info->coded_size = Width and height of the video frame. Not all pixels in
//   this region are valid.
//   info->visible_rect = Region of coded_size that contains image data, also
//   known as the clean aperture.
//   content_rect = Region of the frame that contains the captured content, with
//   the rest of the frame having been letterboxed to adhere to resolution
//   constraints.
void CefVideoConsumerOSR::OnFrameCaptured(
    base::ReadOnlySharedMemoryRegion data,
    ::media::mojom::VideoFrameInfoPtr info,
    const gfx::Rect& content_rect,
    mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
        callbacks) {
  ScopedVideoFrameDone scoped_done(std::move(callbacks));

  if (!data.IsValid())
    return;

  base::ReadOnlySharedMemoryMapping mapping = data.Map();
  if (!mapping.IsValid()) {
    DLOG(ERROR) << "Shared memory mapping failed.";
    return;
  }
  if (mapping.size() <
      media::VideoFrame::AllocationSize(info->pixel_format, info->coded_size)) {
    DLOG(ERROR) << "Shared memory size was less than expected.";
    return;
  }

  // The SkBitmap's pixels will be marked as immutable, but the installPixels()
  // API requires a non-const pointer. So, cast away the const.
  void* const pixels = const_cast<void*>(mapping.memory());

  media::VideoFrameMetadata metadata;
  metadata.MergeInternalValuesFrom(info->metadata);
  gfx::Rect damage_rect;

  if (bounds_in_pixels_) {
    // Use the bounds passed to RequestRefreshFrame().
    damage_rect = gfx::Rect(info->coded_size);
    damage_rect.Intersect(*bounds_in_pixels_);
    bounds_in_pixels_ = base::nullopt;
  } else {
    // Retrieve the rectangular region of the frame that has changed since the
    // frame with the directly preceding CAPTURE_COUNTER. If that frame was not
    // received, typically because it was dropped during transport from the
    // producer, clients must assume that the entire frame has changed.
    // This rectangle is relative to the full frame data, i.e. [0, 0,
    // coded_size.width(), coded_size.height()]. It does not have to be
    // fully contained within visible_rect.
    if (!metadata.GetRect(media::VideoFrameMetadata::CAPTURE_UPDATE_RECT,
                          &damage_rect) ||
        damage_rect.IsEmpty()) {
      damage_rect = gfx::Rect(info->coded_size);
    }
  }

  view_->OnPaint(damage_rect, info->coded_size, pixels);
}

void CefVideoConsumerOSR::OnStopped() {}
