chromium/media/capture/video/chromeos/request_builder.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/capture/video/chromeos/request_builder.h"

#include <utility>

#include "media/capture/video/chromeos/camera_device_context.h"
#include "mojo/public/cpp/platform/platform_handle.h"
#include "mojo/public/cpp/system/platform_handle.h"

namespace media {

RequestBuilder::RequestBuilder(CameraDeviceContext* device_context,
                               RequestBufferCallback request_buffer_callback,
                               bool use_buffer_management_apis)
    : device_context_(device_context),
      frame_number_(0),
      request_buffer_callback_(std::move(request_buffer_callback)),
      use_buffer_management_apis_(use_buffer_management_apis) {}

RequestBuilder::~RequestBuilder() = default;

cros::mojom::Camera3CaptureRequestPtr RequestBuilder::BuildRequest(
    std::set<StreamType> stream_types,
    cros::mojom::CameraMetadataPtr settings) {
  auto capture_request = cros::mojom::Camera3CaptureRequest::New();
  for (StreamType stream_type : stream_types) {
    // If the buffer management APIs are enabled, capture requests do not
    // contain buffer handles.
    if (use_buffer_management_apis_) {
      capture_request->output_buffers.push_back(
          CreateStreamBuffer(stream_type, std::nullopt));
      continue;
    }

    std::optional<BufferInfo> buffer_info =
        request_buffer_callback_.Run(stream_type);
    if (!buffer_info) {
      return capture_request;
    }
    capture_request->output_buffers.push_back(
        CreateStreamBuffer(stream_type, std::move(*buffer_info)));
  }
  capture_request->settings = std::move(settings);
  capture_request->frame_number = frame_number_++;

  return capture_request;
}

cros::mojom::Camera3StreamBufferPtr RequestBuilder::CreateStreamBuffer(
    StreamType stream_type,
    std::optional<BufferInfo> buffer_info) {
  cros::mojom::Camera3StreamBufferPtr buffer =
      cros::mojom::Camera3StreamBuffer::New();
  buffer->stream_id = static_cast<uint64_t>(stream_type);
  buffer->status = cros::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_OK;
  if (buffer_info.has_value()) {
    buffer->buffer_id = buffer_info->ipc_id;
    buffer->buffer_handle =
        CreateCameraBufferHandle(stream_type, std::move(*buffer_info));
  } else {
    buffer->buffer_id = cros::mojom::NO_BUFFER_BUFFER_ID;
    buffer->buffer_handle = nullptr;
  }
  return buffer;
}

cros::mojom::CameraBufferHandlePtr RequestBuilder::CreateCameraBufferHandle(
    StreamType stream_type,
    BufferInfo buffer_info) {
  auto buffer_handle = cros::mojom::CameraBufferHandle::New();

  buffer_handle->buffer_id = buffer_info.ipc_id;
  buffer_handle->drm_format = buffer_info.drm_format;
  buffer_handle->hal_pixel_format = buffer_info.hal_pixel_format;
  buffer_handle->has_modifier = true;
  buffer_handle->modifier = buffer_info.modifier;
  buffer_handle->width = buffer_info.dimension.width();
  buffer_handle->height = buffer_info.dimension.height();

  gfx::NativePixmapHandle& native_pixmap_handle =
      buffer_info.gpu_memory_buffer_handle.native_pixmap_handle;

  size_t num_planes = native_pixmap_handle.planes.size();
  std::vector<StreamCaptureInterface::Plane> planes(num_planes);
  for (size_t i = 0; i < num_planes; ++i) {
    mojo::ScopedHandle mojo_fd = mojo::WrapPlatformHandle(
        mojo::PlatformHandle(std::move(native_pixmap_handle.planes[i].fd)));
    if (!mojo_fd.is_valid()) {
      device_context_->SetErrorState(
          media::VideoCaptureError::
              kCrosHalV3BufferManagerFailedToWrapGpuMemoryHandle,
          FROM_HERE, "Failed to wrap gpu memory handle");
      return nullptr;
    }
    buffer_handle->fds.push_back(std::move(mojo_fd));
    buffer_handle->strides.push_back(native_pixmap_handle.planes[i].stride);
    buffer_handle->offsets.push_back(native_pixmap_handle.planes[i].offset);
  }

  return buffer_handle;
}

}  // namespace media