Commit 336a7d28 authored by Christian Fremerey's avatar Christian Fremerey Committed by Commit Bot

[Video Capture Service] Add support for raw file descriptors as buffer handles

There is an incompatibility in the serialization of shared memory handles
between the Mojo libraries used in Chromium vs. the older ones used in
ChromiumOS. As a workaround, this CL allows clients of the video capture service
to ask it to use raw file descriptors for sharing shared memory handles instead.
Note, this is only supported on platforms that use file descriptors for
base::SharedMemoryHandle, i.e. Posix platforms.

Design Doc: https://docs.google.com/document/d/1cmtWA8yua5sqjZC0tswVUZwJeQR-KSZBr3Mj1jUagKk/edit?usp=sharing

Bug: 847598
Change-Id: Ie269231b98149cbbc104ea62c1ff522c665cf187
Reviewed-on: https://chromium-review.googlesource.com/1043646
Commit-Queue: Christian Fremerey <chfremer@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarEmircan Uysaler <emircan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#572295}
parent 941a9593
......@@ -78,6 +78,7 @@ void FakeVideoCaptureDeviceLauncher::LaunchDeviceAsync(
std::make_unique<media::VideoCaptureBufferTrackerFactoryImpl>(),
kMaxBufferCount));
auto device_client = std::make_unique<media::VideoCaptureDeviceClient>(
media::VideoCaptureBufferType::kSharedMemory,
std::make_unique<media::VideoFrameReceiverOnTaskRunner>(
receiver, base::ThreadTaskRunnerHandle::Get()),
std::move(buffer_pool), std::move(empty_jpeg_decoder_factory_cb));
......
......@@ -114,7 +114,8 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
&InProcessVideoCaptureDeviceLauncher::
DoStartDeviceCaptureOnDeviceThread,
base::Unretained(this), device_id, params,
CreateDeviceClient(kMaxNumberOfBuffers, std::move(receiver),
CreateDeviceClient(media::VideoCaptureBufferType::kSharedMemory,
kMaxNumberOfBuffers, std::move(receiver),
std::move(receiver_on_io_thread)),
std::move(after_start_capture_callback));
break;
......@@ -181,7 +182,8 @@ void InProcessVideoCaptureDeviceLauncher::LaunchDeviceAsync(
&InProcessVideoCaptureDeviceLauncher::
DoStartDesktopCaptureOnDeviceThread,
base::Unretained(this), desktop_id, params,
CreateDeviceClient(kMaxNumberOfBuffers, std::move(receiver),
CreateDeviceClient(media::VideoCaptureBufferType::kSharedMemory,
kMaxNumberOfBuffers, std::move(receiver),
std::move(receiver_on_io_thread)),
std::move(after_start_capture_callback));
break;
......@@ -207,6 +209,7 @@ void InProcessVideoCaptureDeviceLauncher::AbortLaunch() {
std::unique_ptr<media::VideoCaptureDeviceClient>
InProcessVideoCaptureDeviceLauncher::CreateDeviceClient(
media::VideoCaptureBufferType requested_buffer_type,
int buffer_pool_max_buffer_count,
std::unique_ptr<media::VideoFrameReceiver> receiver,
base::WeakPtr<media::VideoFrameReceiver> receiver_on_io_thread) {
......@@ -218,7 +221,7 @@ InProcessVideoCaptureDeviceLauncher::CreateDeviceClient(
buffer_pool_max_buffer_count);
return std::make_unique<media::VideoCaptureDeviceClient>(
std::move(receiver), std::move(buffer_pool),
requested_buffer_type, std::move(receiver), std::move(buffer_pool),
base::BindRepeating(
&CreateGpuJpegDecoder,
base::BindRepeating(&media::VideoFrameReceiver::OnFrameReadyInBuffer,
......
......@@ -51,6 +51,7 @@ class InProcessVideoCaptureDeviceLauncher : public VideoCaptureDeviceLauncher {
};
std::unique_ptr<media::VideoCaptureDeviceClient> CreateDeviceClient(
media::VideoCaptureBufferType requested_buffer_type,
int buffer_pool_max_buffer_count,
std::unique_ptr<media::VideoFrameReceiver> receiver,
base::WeakPtr<media::VideoFrameReceiver> receiver_on_io_thread);
......
......@@ -154,6 +154,7 @@ class VideoCaptureControllerTest
std::make_unique<media::VideoCaptureBufferTrackerFactoryImpl>(),
kPoolSize);
device_client_.reset(new media::VideoCaptureDeviceClient(
media::VideoCaptureBufferType::kSharedMemory,
std::make_unique<media::VideoFrameReceiverOnTaskRunner>(
controller_->GetWeakPtrForIOThread(),
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)),
......
......@@ -41,6 +41,9 @@ struct VideoCaptureImpl::BufferContext
InitializeFromSharedMemory(
std::move(buffer_handle->get_shared_buffer_handle()));
break;
case VideoFrameBufferHandleType::SHARED_MEMORY_VIA_RAW_FILE_DESCRIPTOR:
NOTREACHED();
break;
case VideoFrameBufferHandleType::MAILBOX_HANDLES:
InitializeFromMailbox(std::move(buffer_handle->get_mailbox_handles()));
break;
......@@ -346,6 +349,9 @@ void VideoCaptureImpl::OnBufferReady(int32_t buffer_id,
buffer_context->shared_memory()->handle(),
0 /* shared_memory_offset */, info->timestamp);
break;
case VideoFrameBufferHandleType::SHARED_MEMORY_VIA_RAW_FILE_DESCRIPTOR:
NOTREACHED();
break;
case VideoFrameBufferHandleType::MAILBOX_HANDLES:
gpu::MailboxHolder mailbox_holder_array[media::VideoFrame::kMaxPlanes];
CHECK_EQ(media::VideoFrame::kMaxPlanes,
......
......@@ -71,6 +71,18 @@ enum VideoCaptureTransportType {
OTHER_TRANSPORT
};
enum VideoCaptureBufferType {
kSharedMemory,
// Warning: This case is a workaround for compatibility with an older version
// of Mojo only and will be deleted as soon as the Mojo version of ChromiumOS
// becomes compatible with the |kSharedMemory|.
// TODO(chfremer): Remove this when https://crbug.com/857537 is resolved.
kSharedMemoryViaRawFileDescriptor,
kMailboxHolder
};
struct VideoCaptureFormat {
gfx.mojom.Size frame_size;
float frame_rate;
......@@ -79,6 +91,7 @@ struct VideoCaptureFormat {
struct VideoCaptureParams {
VideoCaptureFormat requested_format;
VideoCaptureBufferType buffer_type;
ResolutionChangePolicy resolution_change_policy;
PowerLineFrequency power_line_frequency;
};
......@@ -117,8 +130,14 @@ struct MailboxBufferHandleSet {
array<gpu.mojom.MailboxHolder, 4> mailbox_holder;
};
struct SharedMemoryViaRawFileDescriptor {
handle file_descriptor_handle;
uint32 shared_memory_size_in_bytes;
};
union VideoBufferHandle {
handle<shared_buffer> shared_buffer_handle;
SharedMemoryViaRawFileDescriptor shared_memory_via_raw_file_descriptor;
MailboxBufferHandleSet mailbox_handles;
};
......@@ -33,6 +33,7 @@ type_mappings = [
"media.mojom.ResolutionChangePolicy=media::ResolutionChangePolicy",
"media.mojom.PowerLineFrequency=media::PowerLineFrequency",
"media.mojom.VideoCapturePixelFormat=media::VideoPixelFormat",
"media.mojom.VideoCaptureBufferType=media::VideoCaptureBufferType",
"media.mojom.VideoCaptureFormat=media::VideoCaptureFormat",
"media.mojom.VideoCaptureParams=media::VideoCaptureParams",
"media.mojom.VideoCaptureDeviceDescriptorCameraCalibration=media::VideoCaptureDeviceDescriptor::CameraCalibration",
......
......@@ -233,6 +233,46 @@ bool EnumTraits<media::mojom::VideoCapturePixelFormat,
return false;
}
// static
media::mojom::VideoCaptureBufferType
EnumTraits<media::mojom::VideoCaptureBufferType,
media::VideoCaptureBufferType>::ToMojom(media::VideoCaptureBufferType
input) {
switch (input) {
case media::VideoCaptureBufferType::kSharedMemory:
return media::mojom::VideoCaptureBufferType::kSharedMemory;
case media::VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor:
return media::mojom::VideoCaptureBufferType::
kSharedMemoryViaRawFileDescriptor;
case media::VideoCaptureBufferType::kMailboxHolder:
return media::mojom::VideoCaptureBufferType::kMailboxHolder;
}
NOTREACHED();
return media::mojom::VideoCaptureBufferType::kSharedMemory;
}
// static
bool EnumTraits<media::mojom::VideoCaptureBufferType,
media::VideoCaptureBufferType>::
FromMojom(media::mojom::VideoCaptureBufferType input,
media::VideoCaptureBufferType* output) {
switch (input) {
case media::mojom::VideoCaptureBufferType::kSharedMemory:
*output = media::VideoCaptureBufferType::kSharedMemory;
return true;
case media::mojom::VideoCaptureBufferType::
kSharedMemoryViaRawFileDescriptor:
*output =
media::VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor;
return true;
case media::mojom::VideoCaptureBufferType::kMailboxHolder:
*output = media::VideoCaptureBufferType::kMailboxHolder;
return true;
}
NOTREACHED();
return false;
}
// static
media::mojom::VideoCaptureApi
EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi>::ToMojom(
......@@ -365,6 +405,8 @@ bool StructTraits<media::mojom::VideoCaptureParamsDataView,
media::VideoCaptureParams* out) {
if (!data.ReadRequestedFormat(&out->requested_format))
return false;
if (!data.ReadBufferType(&out->buffer_type))
return false;
if (!data.ReadResolutionChangePolicy(&out->resolution_change_policy))
return false;
if (!data.ReadPowerLineFrequency(&out->power_line_frequency))
......
......@@ -40,6 +40,16 @@ struct EnumTraits<media::mojom::VideoCapturePixelFormat,
media::VideoPixelFormat* output);
};
template <>
struct EnumTraits<media::mojom::VideoCaptureBufferType,
media::VideoCaptureBufferType> {
static media::mojom::VideoCaptureBufferType ToMojom(
media::VideoCaptureBufferType buffer_type);
static bool FromMojom(media::mojom::VideoCaptureBufferType input,
media::VideoCaptureBufferType* out);
};
template <>
struct EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi> {
static media::mojom::VideoCaptureApi ToMojom(media::VideoCaptureApi input);
......@@ -84,6 +94,11 @@ struct StructTraits<media::mojom::VideoCaptureParamsDataView,
return params.requested_format;
}
static media::VideoCaptureBufferType buffer_type(
const media::VideoCaptureParams& params) {
return params.buffer_type;
}
static media::ResolutionChangePolicy resolution_change_policy(
const media::VideoCaptureParams& params) {
return params.resolution_change_policy;
......
......@@ -68,6 +68,10 @@ class StubBufferHandleProvider
return base::SharedMemoryHandle();
}
uint32_t GetMemorySizeInBytes() override {
return static_cast<uint32_t>(mapped_size_);
}
std::unique_ptr<VideoCaptureBufferHandle> GetHandleForInProcessAccess()
override {
return std::make_unique<StubBufferHandle>(mapped_size_, data_);
......
......@@ -39,4 +39,8 @@ SharedMemoryBufferTracker::GetNonOwnedSharedMemoryHandleForLegacyIPC() {
return provider_.GetNonOwnedSharedMemoryHandleForLegacyIPC();
}
uint32_t SharedMemoryBufferTracker::GetMemorySizeInBytes() {
return provider_.GetMemorySizeInBytes();
}
} // namespace media
......@@ -27,6 +27,7 @@ class SharedMemoryBufferTracker final : public VideoCaptureBufferTracker {
std::unique_ptr<VideoCaptureBufferHandle> GetMemoryMappedAccess() override;
mojo::ScopedSharedBufferHandle GetHandleForTransit(bool read_only) override;
base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC() override;
uint32_t GetMemorySizeInBytes() override;
private:
SharedMemoryHandleProvider provider_;
......
......@@ -63,6 +63,25 @@ bool SharedMemoryHandleProvider::InitFromMojoHandle(
return true;
}
#if defined(OS_LINUX)
bool SharedMemoryHandleProvider::InitAsReadOnlyFromRawFileDescriptor(
mojo::ScopedHandle fd_handle,
uint32_t memory_size_in_bytes) {
base::PlatformFile platform_file;
const MojoResult result =
mojo::UnwrapPlatformFile(std::move(fd_handle), &platform_file);
if (result != MOJO_RESULT_OK)
return false;
base::UnguessableToken guid = base::UnguessableToken::Create();
base::SharedMemoryHandle memory_handle(
base::FileDescriptor(platform_file, true), 0u, guid);
mapped_size_ = memory_size_in_bytes;
read_only_flag_ = true;
shared_memory_.emplace(memory_handle, read_only_flag_);
return true;
}
#endif // defined(OS_LINUX)
mojo::ScopedSharedBufferHandle
SharedMemoryHandleProvider::GetHandleForInterProcessTransit(bool read_only) {
if (read_only_flag_ && !read_only) {
......@@ -88,6 +107,10 @@ SharedMemoryHandleProvider::GetNonOwnedSharedMemoryHandleForLegacyIPC() {
return shared_memory_->handle();
}
uint32_t SharedMemoryHandleProvider::GetMemorySizeInBytes() {
return static_cast<uint32_t>(mapped_size_);
}
std::unique_ptr<VideoCaptureBufferHandle>
SharedMemoryHandleProvider::GetHandleForInProcessAccess() {
{
......
......@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/memory/shared_memory.h"
#include "base/optional.h"
#include "build/build_config.h"
#include "media/capture/capture_export.h"
#include "media/capture/video/video_capture_buffer_handle.h"
#include "media/capture/video/video_capture_device.h"
......@@ -35,10 +36,18 @@ class CAPTURE_EXPORT SharedMemoryHandleProvider
// if the operation failed.
bool InitFromMojoHandle(mojo::ScopedSharedBufferHandle buffer_handle);
// This requires platforms where base::SharedMemoryHandle is backed by a
// file descriptor.
#if defined(OS_LINUX)
bool InitAsReadOnlyFromRawFileDescriptor(mojo::ScopedHandle fd_handle,
uint32_t memory_size_in_bytes);
#endif // defined(OS_LINUX)
// Implementation of Buffer::HandleProvider:
mojo::ScopedSharedBufferHandle GetHandleForInterProcessTransit(
bool read_only) override;
base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC() override;
uint32_t GetMemorySizeInBytes() override;
std::unique_ptr<VideoCaptureBufferHandle> GetHandleForInProcessAccess()
override;
......
......@@ -50,6 +50,8 @@ class CAPTURE_EXPORT VideoCaptureBufferPool
virtual base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC(
int buffer_id) = 0;
virtual uint32_t GetMemorySizeInBytes(int buffer_id) = 0;
// Try and obtain a read/write access to the buffer.
virtual std::unique_ptr<VideoCaptureBufferHandle> GetHandleForInProcessAccess(
int buffer_id) = 0;
......
......@@ -53,6 +53,18 @@ VideoCaptureBufferPoolImpl::GetNonOwnedSharedMemoryHandleForLegacyIPC(
return tracker->GetNonOwnedSharedMemoryHandleForLegacyIPC();
}
uint32_t VideoCaptureBufferPoolImpl::GetMemorySizeInBytes(int buffer_id) {
base::AutoLock lock(lock_);
VideoCaptureBufferTracker* tracker = GetTracker(buffer_id);
if (!tracker) {
NOTREACHED() << "Invalid buffer_id.";
return 0u;
}
return tracker->GetMemorySizeInBytes();
}
std::unique_ptr<VideoCaptureBufferHandle>
VideoCaptureBufferPoolImpl::GetHandleForInProcessAccess(int buffer_id) {
base::AutoLock lock(lock_);
......
......@@ -40,6 +40,7 @@ class CAPTURE_EXPORT VideoCaptureBufferPoolImpl
bool read_only) override;
base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC(
int buffer_id) override;
uint32_t GetMemorySizeInBytes(int buffer_id) override;
std::unique_ptr<VideoCaptureBufferHandle> GetHandleForInProcessAccess(
int buffer_id) override;
int ReserveForProducer(const gfx::Size& dimensions,
......
......@@ -44,6 +44,7 @@ class CAPTURE_EXPORT VideoCaptureBufferTracker {
bool read_only) = 0;
virtual base::SharedMemoryHandle
GetNonOwnedSharedMemoryHandleForLegacyIPC() = 0;
virtual uint32_t GetMemorySizeInBytes() = 0;
private:
// |dimensions_| may change as a VideoCaptureBufferTracker is re-used, but
......
......@@ -99,6 +99,7 @@ class CAPTURE_EXPORT VideoCaptureDevice
bool read_only) = 0;
virtual base::SharedMemoryHandle
GetNonOwnedSharedMemoryHandleForLegacyIPC() = 0;
virtual uint32_t GetMemorySizeInBytes() = 0;
virtual std::unique_ptr<VideoCaptureBufferHandle>
GetHandleForInProcessAccess() = 0;
};
......
......@@ -22,6 +22,7 @@
#include "media/capture/video/video_capture_jpeg_decoder.h"
#include "media/capture/video/video_frame_receiver.h"
#include "media/capture/video_capture_types.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "third_party/libyuv/include/libyuv.h"
namespace {
......@@ -86,6 +87,9 @@ class BufferPoolBufferHandleProvider
override {
return buffer_pool_->GetNonOwnedSharedMemoryHandleForLegacyIPC(buffer_id_);
}
uint32_t GetMemorySizeInBytes() override {
return buffer_pool_->GetMemorySizeInBytes(buffer_id_);
}
std::unique_ptr<VideoCaptureBufferHandle> GetHandleForInProcessAccess()
override {
return buffer_pool_->GetHandleForInProcessAccess(buffer_id_);
......@@ -97,10 +101,12 @@ class BufferPoolBufferHandleProvider
};
VideoCaptureDeviceClient::VideoCaptureDeviceClient(
VideoCaptureBufferType target_buffer_type,
std::unique_ptr<VideoFrameReceiver> receiver,
scoped_refptr<VideoCaptureBufferPool> buffer_pool,
VideoCaptureJpegDecoderFactoryCB optional_jpeg_decoder_factory_callback)
: receiver_(std::move(receiver)),
: target_buffer_type_(target_buffer_type),
receiver_(std::move(receiver)),
optional_jpeg_decoder_factory_callback_(
std::move(optional_jpeg_decoder_factory_callback)),
buffer_pool_(std::move(buffer_pool)),
......@@ -402,9 +408,20 @@ VideoCaptureDeviceClient::ReserveOutputBuffer(const gfx::Size& frame_size,
if (!base::ContainsValue(buffer_ids_known_by_receiver_, buffer_id)) {
media::mojom::VideoBufferHandlePtr buffer_handle =
media::mojom::VideoBufferHandle::New();
switch (target_buffer_type_) {
case VideoCaptureBufferType::kSharedMemory:
buffer_handle->set_shared_buffer_handle(
buffer_pool_->GetHandleForInterProcessTransit(buffer_id,
true /*read_only*/));
break;
case VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor:
buffer_handle->set_shared_memory_via_raw_file_descriptor(
CreateSharedMemoryViaRawFileDescriptorStruct(buffer_id));
break;
case VideoCaptureBufferType::kMailboxHolder:
NOTREACHED();
break;
}
receiver_->OnNewBuffer(buffer_id, std::move(buffer_handle));
buffer_ids_known_by_receiver_.push_back(buffer_id);
}
......@@ -412,6 +429,26 @@ VideoCaptureDeviceClient::ReserveOutputBuffer(const gfx::Size& frame_size,
return MakeBufferStruct(buffer_pool_, buffer_id, frame_feedback_id);
}
mojom::SharedMemoryViaRawFileDescriptorPtr
VideoCaptureDeviceClient::CreateSharedMemoryViaRawFileDescriptorStruct(
int buffer_id) {
// This requires platforms where base::SharedMemoryHandle is backed by a
// file descriptor.
#if defined(OS_LINUX)
auto result = mojom::SharedMemoryViaRawFileDescriptor::New();
result->file_descriptor_handle = mojo::WrapPlatformFile(
base::SharedMemory::DuplicateHandle(
buffer_pool_->GetNonOwnedSharedMemoryHandleForLegacyIPC(buffer_id))
.GetHandle());
result->shared_memory_size_in_bytes =
buffer_pool_->GetMemorySizeInBytes(buffer_id);
return result;
#else
NOTREACHED();
return mojom::SharedMemoryViaRawFileDescriptorPtr();
#endif
}
void VideoCaptureDeviceClient::OnIncomingCapturedBuffer(
Buffer buffer,
const VideoCaptureFormat& format,
......
......@@ -15,6 +15,7 @@
#include "base/memory/ref_counted.h"
#include "base/threading/thread_collision_warner.h"
#include "media/capture/capture_export.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "media/capture/video/video_capture_device.h"
namespace media {
......@@ -43,6 +44,7 @@ class CAPTURE_EXPORT VideoCaptureDeviceClient
: public VideoCaptureDevice::Client {
public:
VideoCaptureDeviceClient(
VideoCaptureBufferType target_buffer_type,
std::unique_ptr<VideoFrameReceiver> receiver,
scoped_refptr<VideoCaptureBufferPool> buffer_pool,
VideoCaptureJpegDecoderFactoryCB optional_jpeg_decoder_factory_callback);
......@@ -99,6 +101,11 @@ class CAPTURE_EXPORT VideoCaptureDeviceClient
base::TimeDelta timestamp,
int frame_feedback_id);
mojom::SharedMemoryViaRawFileDescriptorPtr
CreateSharedMemoryViaRawFileDescriptorStruct(int buffer_id);
const VideoCaptureBufferType target_buffer_type_;
// The receiver to which we post events.
const std::unique_ptr<VideoFrameReceiver> receiver_;
std::vector<int> buffer_ids_known_by_receiver_;
......
......@@ -54,8 +54,8 @@ class VideoCaptureDeviceClientTest : public ::testing::Test {
gpu_memory_buffer_manager_ =
std::make_unique<unittest_internal::MockGpuMemoryBufferManager>();
device_client_ = std::make_unique<VideoCaptureDeviceClient>(
std::move(controller), buffer_pool,
base::Bind(&ReturnNullPtrAsJpecDecoder));
VideoCaptureBufferType::kSharedMemory, std::move(controller),
buffer_pool, base::BindRepeating(&ReturnNullPtrAsJpecDecoder));
}
~VideoCaptureDeviceClientTest() override = default;
......
......@@ -70,7 +70,8 @@ bool VideoCaptureFormat::ComparePixelFormatPreference(
}
VideoCaptureParams::VideoCaptureParams()
: resolution_change_policy(ResolutionChangePolicy::FIXED_RESOLUTION),
: buffer_type(VideoCaptureBufferType::kSharedMemory),
resolution_change_policy(ResolutionChangePolicy::FIXED_RESOLUTION),
power_line_frequency(PowerLineFrequency::FREQUENCY_DEFAULT) {}
bool VideoCaptureParams::IsValid() const {
......
......@@ -54,6 +54,12 @@ enum class PowerLineFrequency {
FREQUENCY_MAX = FREQUENCY_60HZ
};
enum class VideoCaptureBufferType {
kSharedMemory,
kSharedMemoryViaRawFileDescriptor,
kMailboxHolder
};
// Assert that the int:frequency mapping is correct.
static_assert(static_cast<int>(PowerLineFrequency::FREQUENCY_DEFAULT) == 0,
"static_cast<int>(FREQUENCY_DEFAULT) must equal 0.");
......@@ -135,6 +141,8 @@ struct CAPTURE_EXPORT VideoCaptureParams {
// Requests a resolution and format at which the capture will occur.
VideoCaptureFormat requested_format;
VideoCaptureBufferType buffer_type;
// Policy for resolution change.
ResolutionChangePolicy resolution_change_policy;
......
......@@ -59,6 +59,15 @@ void DeviceMediaToMojoAdapter::Start(
auto media_receiver = std::make_unique<media::VideoFrameReceiverOnTaskRunner>(
receiver_->GetWeakPtr(), base::ThreadTaskRunnerHandle::Get());
if (requested_settings.buffer_type !=
media::VideoCaptureBufferType::kSharedMemory &&
requested_settings.buffer_type !=
media::VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor) {
// Buffer types other than shared memory are not supported.
media_receiver->OnError();
return;
}
// Create a dedicated buffer pool for the device usage session.
auto buffer_tracker_factory =
std::make_unique<media::VideoCaptureBufferTrackerFactoryImpl>();
......@@ -67,7 +76,7 @@ void DeviceMediaToMojoAdapter::Start(
max_buffer_pool_buffer_count()));
auto device_client = std::make_unique<media::VideoCaptureDeviceClient>(
std::move(media_receiver), buffer_pool,
requested_settings.buffer_type, std::move(media_receiver), buffer_pool,
base::BindRepeating(
&CreateGpuJpegDecoder, jpeg_decoder_task_runner_,
jpeg_decoder_factory_callback_,
......
......@@ -4,7 +4,9 @@
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "media/base/video_frame.h"
#include "media/capture/video/shared_memory_handle_provider.h"
#include "media/mojo/common/media_type_converters.h"
#include "services/video_capture/device_media_to_mojo_adapter.h"
#include "services/video_capture/public/mojom/constants.mojom.h"
......@@ -76,4 +78,74 @@ TEST_F(FakeVideoCaptureDeviceTest, BuffersGetReused) {
ASSERT_LE(num_buffers_created, kMaxBufferPoolBuffers);
}
// This requires platforms where base::SharedMemoryHandle is backed by a
// file descriptor.
#if defined(OS_LINUX)
TEST_F(FakeVideoCaptureDeviceTest,
ReceiveFramesViaFileDescriptorHandlesForSharedMemory) {
base::RunLoop wait_loop;
static const int kNumFramesToWaitFor = 3;
int num_frames_arrived = 0;
std::map<int32_t, std::unique_ptr<media::SharedMemoryHandleProvider>>
buffers_by_id;
mojom::ReceiverPtr receiver_proxy;
MockReceiver receiver(mojo::MakeRequest(&receiver_proxy));
EXPECT_CALL(receiver, DoOnNewBuffer(_, _))
.Times(AtLeast(1))
.WillRepeatedly(Invoke(
[&buffers_by_id](int32_t buffer_id,
media::mojom::VideoBufferHandlePtr* buffer_handle) {
ASSERT_TRUE(
(*buffer_handle)->is_shared_memory_via_raw_file_descriptor());
auto provider =
std::make_unique<media::SharedMemoryHandleProvider>();
provider->InitAsReadOnlyFromRawFileDescriptor(
std::move((*buffer_handle)
->get_shared_memory_via_raw_file_descriptor()
->file_descriptor_handle),
(*buffer_handle)
->get_shared_memory_via_raw_file_descriptor()
->shared_memory_size_in_bytes);
buffers_by_id.insert(
std::make_pair(buffer_id, std::move(provider)));
}));
bool found_unexpected_all_zero_frame = false;
EXPECT_CALL(receiver, DoOnFrameReadyInBuffer(_, _, _, _))
.WillRepeatedly(Invoke([&wait_loop, &num_frames_arrived, &buffers_by_id,
&found_unexpected_all_zero_frame](
int32_t buffer_id, int32_t frame_feedback_id,
mojom::ScopedAccessPermissionPtr*,
media::mojom::VideoFrameInfoPtr*) {
auto buffer_access =
buffers_by_id[buffer_id]->GetHandleForInProcessAccess();
// Check that there is at least one non-zero byte in the frame data.
bool found_non_zero_byte = false;
for (uint32_t i = 0; i < buffer_access->mapped_size(); i++) {
if (buffer_access->const_data()[i] != 0u) {
found_non_zero_byte = true;
break;
}
}
if (!found_non_zero_byte) {
found_unexpected_all_zero_frame = true;
wait_loop.Quit();
return;
}
num_frames_arrived += 1;
if (num_frames_arrived >= kNumFramesToWaitFor) {
wait_loop.Quit();
}
}));
// Make a copy of |requestable_settings_| and change it to ask for
// |kSharedMemoryViaRawFileDescriptor|.
media::VideoCaptureParams settings_to_request = requestable_settings_;
settings_to_request.buffer_type =
media::VideoCaptureBufferType::kSharedMemoryViaRawFileDescriptor;
fake_device_proxy_->Start(settings_to_request, std::move(receiver_proxy));
wait_loop.Run();
EXPECT_FALSE(found_unexpected_all_zero_frame);
}
#endif // defined(OS_LINUX)
} // namespace video_capture
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment