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
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/video_memory_utils.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/memory/writable_shared_memory_region.h"
#endif
namespace remoting {
//////////////////////////////////////////////////////////////////////////////
// SharedVideoMemory
// static
std::unique_ptr<SharedVideoMemory> SharedVideoMemory::Create(
size_t size,
int id,
base::OnceClosure on_deleted_callback) {
webrtc::SharedMemory::Handle handle = webrtc::SharedMemory::kInvalidHandle;
#if BUILDFLAG(IS_WIN)
// webrtc::ScreenCapturer uses webrtc::SharedMemory::handle() only on
// windows. This handle must be writable. A WritableSharedMemoryRegion is
// created, and then it is converted to read-only. On the windows platform,
// it happens to be the case that converting a region to read-only does not
// change the status of existing handles. This is not true on all other
// platforms, so please don't emulate this behavior!
base::WritableSharedMemoryRegion region =
base::WritableSharedMemoryRegion::Create(size);
if (!region.IsValid()) {
return nullptr;
}
base::WritableSharedMemoryMapping mapping = region.Map();
// Converting |region| to read-only will close its associated handle, so we
// must duplicate it into the handle used for |webrtc::ScreenCapturer|.
HANDLE process = ::GetCurrentProcess();
BOOL success =
::DuplicateHandle(process, region.UnsafeGetPlatformHandle(), process,
&handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
if (!success) {
return nullptr;
}
base::ReadOnlySharedMemoryRegion read_only_region =
base::WritableSharedMemoryRegion::ConvertToReadOnly(std::move(region));
#else
base::MappedReadOnlyRegion region_mapping =
base::ReadOnlySharedMemoryRegion::Create(size);
base::ReadOnlySharedMemoryRegion read_only_region =
std::move(region_mapping.region);
base::WritableSharedMemoryMapping mapping = std::move(region_mapping.mapping);
#endif
if (!mapping.IsValid()) {
return nullptr;
}
// The SharedVideoMemory ctor is private, so std::make_unique can't be
// used.
return base::WrapUnique(
new SharedVideoMemory(std::move(read_only_region), std::move(mapping),
handle, id, std::move(on_deleted_callback)));
}
SharedVideoMemory::~SharedVideoMemory() {
std::move(on_deleted_callback_).Run();
}
SharedVideoMemory::SharedVideoMemory(base::ReadOnlySharedMemoryRegion region,
base::WritableSharedMemoryMapping mapping,
webrtc::SharedMemory::Handle handle,
int id,
base::OnceClosure on_deleted_callback)
: SharedMemory(mapping.memory(), mapping.size(), handle, id),
on_deleted_callback_(std::move(on_deleted_callback))
#if BUILDFLAG(IS_WIN)
,
writable_handle_(handle)
#endif
{
region_ = std::move(region);
mapping_ = std::move(mapping);
}
//////////////////////////////////////////////////////////////////////////////
// SharedVideoMemoryFactory
SharedVideoMemoryFactory::SharedVideoMemoryFactory(
SharedMemoryCreatedCallback shared_memory_created_callback,
SharedMemoryReleasedCallback shared_memory_released_callback)
: shared_memory_created_callback_(
std::move(shared_memory_created_callback)),
shared_memory_released_callback_(
std::move(shared_memory_released_callback)) {}
SharedVideoMemoryFactory::~SharedVideoMemoryFactory() = default;
std::unique_ptr<webrtc::SharedMemory>
SharedVideoMemoryFactory::CreateSharedMemory(size_t size) {
base::OnceClosure release_buffer_callback =
base::BindOnce(shared_memory_released_callback_, next_shared_buffer_id_);
std::unique_ptr<SharedVideoMemory> buffer = SharedVideoMemory::Create(
size, next_shared_buffer_id_, std::move(release_buffer_callback));
if (buffer) {
// |next_shared_buffer_id_| starts from 1 and incrementing it by 2 makes
// sure it is always odd and therefore zero is never used as a valid
// buffer ID.
//
// It is very unlikely (though theoretically possible) to allocate the
// same ID for two different buffers due to integer overflow. It should
// take about a year of allocating 100 new buffers every second.
// Practically speaking it never happens.
next_shared_buffer_id_ += 2;
shared_memory_created_callback_.Run(
buffer->id(), buffer->region().Duplicate(), buffer->size());
}
return buffer;
}
//////////////////////////////////////////////////////////////////////////////
// IpcSharedBufferCore
IpcSharedBufferCore::IpcSharedBufferCore(
int id,
base::ReadOnlySharedMemoryRegion region)
: id_(id) {
mapping_ = region.Map();
if (!mapping_.IsValid()) {
LOG(ERROR) << "Failed to map a shared buffer: id=" << id
<< ", size=" << region.GetSize();
}
// After being mapped, |region| is no longer needed and can be discarded.
}
IpcSharedBufferCore::~IpcSharedBufferCore() = default;
//////////////////////////////////////////////////////////////////////////////
// IpcSharedBuffer
IpcSharedBuffer::IpcSharedBuffer(scoped_refptr<IpcSharedBufferCore> core)
: SharedMemory(const_cast<void*>(core->memory()),
core->size(),
0,
core->id()),
core_(core) {}
IpcSharedBuffer::~IpcSharedBuffer() = default;
} // namespace remoting
|