| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" | 5 #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "build/build_config.h" | 10 #include "build/build_config.h" |
| 11 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h" | 11 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h" |
| 12 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
| 13 #include "ui/gfx/buffer_format_util.h" | 13 #include "ui/gfx/buffer_format_util.h" |
| 14 | 14 |
| 15 namespace content { | 15 namespace content { |
| 16 | 16 |
| 17 const int VideoCaptureBufferPool::kInvalidId = -1; | 17 const int VideoCaptureBufferPool::kInvalidId = -1; |
| 18 | 18 |
| 19 // A simple holder of a memory-backed buffer and accessors to it. | |
| 20 class SimpleBufferHandle final : public VideoCaptureBufferPool::BufferHandle { | |
| 21 public: | |
| 22 SimpleBufferHandle(void* data, | |
| 23 size_t mapped_size, | |
| 24 base::SharedMemoryHandle handle) | |
| 25 : data_(data), | |
| 26 mapped_size_(mapped_size) | |
| 27 #if defined(OS_POSIX) && !defined(OS_MACOSX) | |
| 28 , | |
| 29 handle_(handle) | |
| 30 #endif | |
| 31 { | |
| 32 } | |
| 33 ~SimpleBufferHandle() override {} | |
| 34 | |
| 35 gfx::Size dimensions() const override { | |
| 36 NOTREACHED(); | |
| 37 return gfx::Size(); | |
| 38 } | |
| 39 size_t mapped_size() const override { return mapped_size_; } | |
| 40 void* data(int plane) override { | |
| 41 DCHECK_EQ(plane, 0); | |
| 42 return data_; | |
| 43 } | |
| 44 ClientBuffer AsClientBuffer(int plane) override { | |
| 45 NOTREACHED(); | |
| 46 return nullptr; | |
| 47 } | |
| 48 #if defined(OS_POSIX) && !defined(OS_MACOSX) | |
| 49 base::FileDescriptor AsPlatformFile() override { | |
| 50 return handle_; | |
| 51 } | |
| 52 #endif | |
| 53 | |
| 54 private: | |
| 55 void* const data_; | |
| 56 const size_t mapped_size_; | |
| 57 #if defined(OS_POSIX) && !defined(OS_MACOSX) | |
| 58 const base::SharedMemoryHandle handle_; | |
| 59 #endif | |
| 60 }; | |
| 61 | |
| 62 // A holder of a GpuMemoryBuffer-backed buffer. Holds weak references to | |
| 63 // GpuMemoryBuffer-backed buffers and provides accessors to their data. | |
| 64 class GpuMemoryBufferBufferHandle final | |
| 65 : public VideoCaptureBufferPool::BufferHandle { | |
| 66 public: | |
| 67 GpuMemoryBufferBufferHandle(const gfx::Size& dimensions, | |
| 68 std::vector< | |
| 69 scoped_ptr<gfx::GpuMemoryBuffer>>* gmbs) | |
| 70 : dimensions_(dimensions), gmbs_(gmbs) { | |
| 71 DCHECK(gmbs); | |
| 72 } | |
| 73 ~GpuMemoryBufferBufferHandle() override {} | |
| 74 | |
| 75 gfx::Size dimensions() const override { return dimensions_; } | |
| 76 size_t mapped_size() const override { return dimensions_.GetArea(); } | |
| 77 void* data(int plane) override { | |
| 78 DCHECK_GE(plane, 0); | |
| 79 DCHECK_LT(plane, static_cast<int>(gmbs_->size())); | |
| 80 DCHECK((*gmbs_)[plane]); | |
| 81 return (*gmbs_)[plane]->memory(0); | |
| 82 } | |
| 83 ClientBuffer AsClientBuffer(int plane) override { | |
| 84 DCHECK_GE(plane, 0); | |
| 85 DCHECK_LT(plane, static_cast<int>(gmbs_->size())); | |
| 86 return (*gmbs_)[plane]->AsClientBuffer(); | |
| 87 } | |
| 88 #if defined(OS_POSIX) && !defined(OS_MACOSX) | |
| 89 base::FileDescriptor AsPlatformFile() override { | |
| 90 NOTREACHED(); | |
| 91 return base::FileDescriptor(); | |
| 92 } | |
| 93 #endif | |
| 94 | |
| 95 private: | |
| 96 const gfx::Size dimensions_; | |
| 97 std::vector<scoped_ptr<gfx::GpuMemoryBuffer>>* const gmbs_; | |
| 98 }; | |
| 99 | |
| 100 // Tracker specifics for SharedMemory. | 19 // Tracker specifics for SharedMemory. |
| 101 class VideoCaptureBufferPool::SharedMemTracker final : public Tracker { | 20 class VideoCaptureBufferPool::SharedMemTracker final : public Tracker { |
| 102 public: | 21 public: |
| 103 SharedMemTracker(); | 22 SharedMemTracker() : Tracker() {} |
| 104 bool Init(media::VideoPixelFormat format, | 23 |
| 24 bool Init(const gfx::Size& dimensions, |
| 25 media::VideoPixelFormat format, |
| 105 media::VideoPixelStorage storage_type, | 26 media::VideoPixelStorage storage_type, |
| 106 const gfx::Size& dimensions, | 27 base::Lock* lock) override { |
| 107 base::Lock* lock) override; | 28 DVLOG(2) << "allocating ShMem of " << dimensions.ToString(); |
| 29 set_dimensions(dimensions); |
| 30 // |dimensions| can be 0x0 for trackers that do not require memory backing. |
| 31 set_max_pixel_count(dimensions.GetArea()); |
| 32 set_pixel_format(format); |
| 33 set_storage_type(storage_type); |
| 34 mapped_size_ = |
| 35 media::VideoCaptureFormat(dimensions, 0.0f, format, storage_type) |
| 36 .ImageAllocationSize(); |
| 37 if (!mapped_size_) |
| 38 return true; |
| 39 return shared_memory_.CreateAndMapAnonymous(mapped_size_); |
| 40 } |
| 108 | 41 |
| 109 scoped_ptr<BufferHandle> GetBufferHandle() override { | 42 scoped_ptr<BufferHandle> GetBufferHandle() override { |
| 110 return make_scoped_ptr(new SimpleBufferHandle( | 43 return make_scoped_ptr(new SharedMemBufferHandle(this)); |
| 111 shared_memory_.memory(), mapped_size_, shared_memory_.handle())); | |
| 112 } | 44 } |
| 113 bool ShareToProcess(base::ProcessHandle process_handle, | 45 bool ShareToProcess(base::ProcessHandle process_handle, |
| 114 base::SharedMemoryHandle* new_handle) override { | 46 base::SharedMemoryHandle* new_handle) override { |
| 115 return shared_memory_.ShareToProcess(process_handle, new_handle); | 47 return shared_memory_.ShareToProcess(process_handle, new_handle); |
| 116 } | 48 } |
| 117 bool ShareToProcess2(int plane, | 49 bool ShareToProcess2(int plane, |
| 118 base::ProcessHandle process_handle, | 50 base::ProcessHandle process_handle, |
| 119 gfx::GpuMemoryBufferHandle* new_handle) override { | 51 gfx::GpuMemoryBufferHandle* new_handle) override { |
| 120 NOTREACHED(); | 52 NOTREACHED(); |
| 121 return false; | 53 return false; |
| 122 } | 54 } |
| 123 | 55 |
| 124 private: | 56 private: |
| 57 // A simple proxy that implements the BufferHandle interface, providing |
| 58 // accessors to SharedMemTracker's memory and properties. |
| 59 class SharedMemBufferHandle : public VideoCaptureBufferPool::BufferHandle { |
| 60 public: |
| 61 // |tracker| must outlive SimpleBufferHandle. This is ensured since a |
| 62 // tracker is pinned until ownership of this SimpleBufferHandle is returned |
| 63 // to VideoCaptureBufferPool. |
| 64 explicit SharedMemBufferHandle(SharedMemTracker* tracker) |
| 65 : tracker_(tracker) {} |
| 66 ~SharedMemBufferHandle() override {} |
| 67 |
| 68 gfx::Size dimensions() const override { return tracker_->dimensions(); } |
| 69 size_t mapped_size() const override { return tracker_->mapped_size_; } |
| 70 void* data(int plane) override { |
| 71 DCHECK_EQ(plane, 0); |
| 72 return tracker_->shared_memory_.memory(); |
| 73 } |
| 74 ClientBuffer AsClientBuffer(int plane) override { |
| 75 NOTREACHED(); |
| 76 return nullptr; |
| 77 } |
| 78 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
| 79 base::FileDescriptor AsPlatformFile() override { |
| 80 return tracker_->shared_memory_.handle(); |
| 81 } |
| 82 #endif |
| 83 |
| 84 private: |
| 85 SharedMemTracker* const tracker_; |
| 86 }; |
| 87 |
| 125 // The memory created to be shared with renderer processes. | 88 // The memory created to be shared with renderer processes. |
| 126 base::SharedMemory shared_memory_; | 89 base::SharedMemory shared_memory_; |
| 127 size_t mapped_size_; | 90 size_t mapped_size_; |
| 128 }; | 91 }; |
| 129 | 92 |
| 130 // Tracker specifics for GpuMemoryBuffer. Owns GpuMemoryBuffers and its | 93 // Tracker specifics for GpuMemoryBuffer. Owns GpuMemoryBuffers and its |
| 131 // associated pixel dimensions. | 94 // associated pixel dimensions. |
| 132 class VideoCaptureBufferPool::GpuMemoryBufferTracker final : public Tracker { | 95 class VideoCaptureBufferPool::GpuMemoryBufferTracker final : public Tracker { |
| 133 public: | 96 public: |
| 134 GpuMemoryBufferTracker(); | 97 GpuMemoryBufferTracker() : Tracker() {} |
| 135 bool Init(media::VideoPixelFormat format, | 98 |
| 99 ~GpuMemoryBufferTracker() override { |
| 100 for (const auto& gmb : gpu_memory_buffers_) |
| 101 gmb->Unmap(); |
| 102 } |
| 103 |
| 104 bool Init(const gfx::Size& dimensions, |
| 105 media::VideoPixelFormat format, |
| 136 media::VideoPixelStorage storage_type, | 106 media::VideoPixelStorage storage_type, |
| 137 const gfx::Size& dimensions, | 107 base::Lock* lock) override { |
| 138 base::Lock* lock) override; | 108 DVLOG(2) << "allocating GMB for " << dimensions.ToString(); |
| 139 ~GpuMemoryBufferTracker() override; | 109 // BrowserGpuMemoryBufferManager::current() may not be accessed on IO |
| 110 // Thread. |
| 111 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 112 DCHECK(BrowserGpuMemoryBufferManager::current()); |
| 113 // This class is only expected to be called with I420 buffer requests at |
| 114 // this point. |
| 115 DCHECK_EQ(format, media::PIXEL_FORMAT_I420); |
| 116 set_dimensions(dimensions); |
| 117 set_max_pixel_count(dimensions.GetArea()); |
| 118 set_pixel_format(format); |
| 119 set_storage_type(storage_type); |
| 120 // |dimensions| can be 0x0 for trackers that do not require memory backing. |
| 121 if (dimensions.GetArea() == 0u) |
| 122 return true; |
| 123 |
| 124 base::AutoUnlock auto_unlock(*lock); |
| 125 const size_t num_planes = media::VideoFrame::NumPlanes(pixel_format()); |
| 126 for (size_t i = 0; i < num_planes; ++i) { |
| 127 const gfx::Size& size = |
| 128 media::VideoFrame::PlaneSize(pixel_format(), i, dimensions); |
| 129 gpu_memory_buffers_.push_back( |
| 130 BrowserGpuMemoryBufferManager::current()->AllocateGpuMemoryBuffer( |
| 131 size, gfx::BufferFormat::R_8, |
| 132 gfx::BufferUsage::GPU_READ_CPU_READ_WRITE)); |
| 133 |
| 134 DLOG_IF(ERROR, !gpu_memory_buffers_[i]) << "Allocating GpuMemoryBuffer"; |
| 135 if (!gpu_memory_buffers_[i] || !gpu_memory_buffers_[i]->Map()) |
| 136 return false; |
| 137 } |
| 138 return true; |
| 139 } |
| 140 | 140 |
| 141 scoped_ptr<BufferHandle> GetBufferHandle() override { | 141 scoped_ptr<BufferHandle> GetBufferHandle() override { |
| 142 DCHECK_EQ(gpu_memory_buffers_.size(), | 142 DCHECK_EQ(gpu_memory_buffers_.size(), |
| 143 media::VideoFrame::NumPlanes(pixel_format())); | 143 media::VideoFrame::NumPlanes(pixel_format())); |
| 144 return make_scoped_ptr( | 144 return make_scoped_ptr(new GpuMemoryBufferBufferHandle(this)); |
| 145 new GpuMemoryBufferBufferHandle(dimensions_, &gpu_memory_buffers_)); | |
| 146 } | 145 } |
| 146 |
| 147 bool ShareToProcess(base::ProcessHandle process_handle, | 147 bool ShareToProcess(base::ProcessHandle process_handle, |
| 148 base::SharedMemoryHandle* new_handle) override { | 148 base::SharedMemoryHandle* new_handle) override { |
| 149 NOTREACHED(); | 149 NOTREACHED(); |
| 150 return false; | 150 return false; |
| 151 } | 151 } |
| 152 |
| 152 bool ShareToProcess2(int plane, | 153 bool ShareToProcess2(int plane, |
| 153 base::ProcessHandle process_handle, | 154 base::ProcessHandle process_handle, |
| 154 gfx::GpuMemoryBufferHandle* new_handle) override; | 155 gfx::GpuMemoryBufferHandle* new_handle) override { |
| 156 DCHECK_LE(plane, static_cast<int>(gpu_memory_buffers_.size())); |
| 157 |
| 158 const auto& current_gmb_handle = gpu_memory_buffers_[plane]->GetHandle(); |
| 159 switch (current_gmb_handle.type) { |
| 160 case gfx::EMPTY_BUFFER: |
| 161 NOTREACHED(); |
| 162 return false; |
| 163 case gfx::SHARED_MEMORY_BUFFER: { |
| 164 DCHECK(base::SharedMemory::IsHandleValid(current_gmb_handle.handle)); |
| 165 base::SharedMemory shared_memory( |
| 166 base::SharedMemory::DuplicateHandle(current_gmb_handle.handle), |
| 167 false); |
| 168 shared_memory.ShareToProcess(process_handle, &new_handle->handle); |
| 169 DCHECK(base::SharedMemory::IsHandleValid(new_handle->handle)); |
| 170 new_handle->type = gfx::SHARED_MEMORY_BUFFER; |
| 171 return true; |
| 172 } |
| 173 case gfx::IO_SURFACE_BUFFER: |
| 174 case gfx::SURFACE_TEXTURE_BUFFER: |
| 175 case gfx::OZONE_NATIVE_PIXMAP: |
| 176 *new_handle = current_gmb_handle; |
| 177 return true; |
| 178 } |
| 179 NOTREACHED(); |
| 180 return true; |
| 181 } |
| 155 | 182 |
| 156 private: | 183 private: |
| 157 gfx::Size dimensions_; | 184 // A simple proxy that implements the BufferHandle interface, providing |
| 185 // accessors to GpuMemoryBufferTracker's memory and properties. |
| 186 class GpuMemoryBufferBufferHandle |
| 187 : public VideoCaptureBufferPool::BufferHandle { |
| 188 public: |
| 189 // |tracker| must outlive GpuMemoryBufferBufferHandle. This is ensured since |
| 190 // a tracker is pinned until ownership of this GpuMemoryBufferBufferHandle |
| 191 // is returned to VideoCaptureBufferPool. |
| 192 explicit GpuMemoryBufferBufferHandle(GpuMemoryBufferTracker* tracker) |
| 193 : tracker_(tracker) {} |
| 194 ~GpuMemoryBufferBufferHandle() override {} |
| 195 |
| 196 gfx::Size dimensions() const override { return tracker_->dimensions(); } |
| 197 size_t mapped_size() const override { |
| 198 return tracker_->dimensions().GetArea(); |
| 199 } |
| 200 void* data(int plane) override { |
| 201 DCHECK_GE(plane, 0); |
| 202 DCHECK_LT(plane, static_cast<int>(tracker_->gpu_memory_buffers_.size())); |
| 203 DCHECK(tracker_->gpu_memory_buffers_[plane]); |
| 204 return tracker_->gpu_memory_buffers_[plane]->memory(0); |
| 205 } |
| 206 ClientBuffer AsClientBuffer(int plane) override { |
| 207 DCHECK_GE(plane, 0); |
| 208 DCHECK_LT(plane, static_cast<int>(tracker_->gpu_memory_buffers_.size())); |
| 209 return tracker_->gpu_memory_buffers_[plane]->AsClientBuffer(); |
| 210 } |
| 211 #if defined(OS_POSIX) && !defined(OS_MACOSX) |
| 212 base::FileDescriptor AsPlatformFile() override { |
| 213 NOTREACHED(); |
| 214 return base::FileDescriptor(); |
| 215 } |
| 216 #endif |
| 217 |
| 218 private: |
| 219 GpuMemoryBufferTracker* const tracker_; |
| 220 }; |
| 221 |
| 158 // Owned references to GpuMemoryBuffers. | 222 // Owned references to GpuMemoryBuffers. |
| 159 std::vector<scoped_ptr<gfx::GpuMemoryBuffer>> gpu_memory_buffers_; | 223 std::vector<scoped_ptr<gfx::GpuMemoryBuffer>> gpu_memory_buffers_; |
| 160 }; | 224 }; |
| 161 | 225 |
| 162 VideoCaptureBufferPool::SharedMemTracker::SharedMemTracker() : Tracker() {} | |
| 163 | |
| 164 bool VideoCaptureBufferPool::SharedMemTracker::Init( | |
| 165 media::VideoPixelFormat format, | |
| 166 media::VideoPixelStorage storage_type, | |
| 167 const gfx::Size& dimensions, | |
| 168 base::Lock* lock) { | |
| 169 DVLOG(2) << "allocating ShMem of " << dimensions.ToString(); | |
| 170 set_pixel_format(format); | |
| 171 set_storage_type(storage_type); | |
| 172 // |dimensions| can be 0x0 for trackers that do not require memory backing. | |
| 173 set_pixel_count(dimensions.GetArea()); | |
| 174 mapped_size_ = | |
| 175 media::VideoCaptureFormat(dimensions, 0.0f, format, storage_type) | |
| 176 .ImageAllocationSize(); | |
| 177 if (!mapped_size_) | |
| 178 return true; | |
| 179 return shared_memory_.CreateAndMapAnonymous(mapped_size_); | |
| 180 } | |
| 181 | |
| 182 VideoCaptureBufferPool::GpuMemoryBufferTracker::GpuMemoryBufferTracker() | |
| 183 : Tracker() { | |
| 184 } | |
| 185 | |
| 186 VideoCaptureBufferPool::GpuMemoryBufferTracker::~GpuMemoryBufferTracker() { | |
| 187 for (const auto& gmb : gpu_memory_buffers_) | |
| 188 gmb->Unmap(); | |
| 189 } | |
| 190 | |
| 191 bool VideoCaptureBufferPool::GpuMemoryBufferTracker::Init( | |
| 192 media::VideoPixelFormat format, | |
| 193 media::VideoPixelStorage storage_type, | |
| 194 const gfx::Size& dimensions, | |
| 195 base::Lock* lock) { | |
| 196 DVLOG(2) << "allocating GMB for " << dimensions.ToString(); | |
| 197 // BrowserGpuMemoryBufferManager::current() may not be accessed on IO Thread. | |
| 198 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 199 DCHECK(BrowserGpuMemoryBufferManager::current()); | |
| 200 // This class is only expected to be called with I420 buffer requests at this | |
| 201 // point. | |
| 202 DCHECK_EQ(format, media::PIXEL_FORMAT_I420); | |
| 203 set_pixel_format(format); | |
| 204 set_storage_type(storage_type); | |
| 205 set_pixel_count(dimensions.GetArea()); | |
| 206 // |dimensions| can be 0x0 for trackers that do not require memory backing. | |
| 207 if (dimensions.GetArea() == 0u) | |
| 208 return true; | |
| 209 dimensions_ = dimensions; | |
| 210 | |
| 211 lock->Release(); | |
| 212 const size_t num_planes = media::VideoFrame::NumPlanes(pixel_format()); | |
| 213 for (size_t i = 0; i < num_planes; ++i) { | |
| 214 const gfx::Size& size = | |
| 215 media::VideoFrame::PlaneSize(pixel_format(), i, dimensions); | |
| 216 gpu_memory_buffers_.push_back( | |
| 217 BrowserGpuMemoryBufferManager::current()->AllocateGpuMemoryBuffer( | |
| 218 size, gfx::BufferFormat::R_8, | |
| 219 gfx::BufferUsage::GPU_READ_CPU_READ_WRITE)); | |
| 220 | |
| 221 DLOG_IF(ERROR, !gpu_memory_buffers_[i]) << "Allocating GpuMemoryBuffer"; | |
| 222 if (!gpu_memory_buffers_[i] || !gpu_memory_buffers_[i]->Map()) | |
| 223 return false; | |
| 224 } | |
| 225 lock->Acquire(); | |
| 226 return true; | |
| 227 } | |
| 228 | |
| 229 bool VideoCaptureBufferPool::GpuMemoryBufferTracker::ShareToProcess2( | |
| 230 int plane, | |
| 231 base::ProcessHandle process_handle, | |
| 232 gfx::GpuMemoryBufferHandle* new_handle) { | |
| 233 DCHECK_LE(plane, static_cast<int>(gpu_memory_buffers_.size())); | |
| 234 | |
| 235 const auto& current_gmb_handle = gpu_memory_buffers_[plane]->GetHandle(); | |
| 236 switch (current_gmb_handle.type) { | |
| 237 case gfx::EMPTY_BUFFER: | |
| 238 NOTREACHED(); | |
| 239 return false; | |
| 240 case gfx::SHARED_MEMORY_BUFFER: { | |
| 241 DCHECK(base::SharedMemory::IsHandleValid(current_gmb_handle.handle)); | |
| 242 base::SharedMemory shared_memory( | |
| 243 base::SharedMemory::DuplicateHandle(current_gmb_handle.handle), | |
| 244 false); | |
| 245 shared_memory.ShareToProcess(process_handle, &new_handle->handle); | |
| 246 DCHECK(base::SharedMemory::IsHandleValid(new_handle->handle)); | |
| 247 new_handle->type = gfx::SHARED_MEMORY_BUFFER; | |
| 248 return true; | |
| 249 } | |
| 250 case gfx::IO_SURFACE_BUFFER: | |
| 251 case gfx::SURFACE_TEXTURE_BUFFER: | |
| 252 case gfx::OZONE_NATIVE_PIXMAP: | |
| 253 *new_handle = current_gmb_handle; | |
| 254 return true; | |
| 255 } | |
| 256 NOTREACHED(); | |
| 257 return true; | |
| 258 } | |
| 259 | |
| 260 // static | 226 // static |
| 261 scoped_ptr<VideoCaptureBufferPool::Tracker> | 227 scoped_ptr<VideoCaptureBufferPool::Tracker> |
| 262 VideoCaptureBufferPool::Tracker::CreateTracker( | 228 VideoCaptureBufferPool::Tracker::CreateTracker( |
| 263 media::VideoPixelStorage storage) { | 229 media::VideoPixelStorage storage) { |
| 264 switch (storage) { | 230 switch (storage) { |
| 265 case media::PIXEL_STORAGE_GPUMEMORYBUFFER: | 231 case media::PIXEL_STORAGE_GPUMEMORYBUFFER: |
| 266 return make_scoped_ptr(new GpuMemoryBufferTracker()); | 232 return make_scoped_ptr(new GpuMemoryBufferTracker()); |
| 267 case media::PIXEL_STORAGE_CPU: | 233 case media::PIXEL_STORAGE_CPU: |
| 268 return make_scoped_ptr(new SharedMemTracker()); | 234 return make_scoped_ptr(new SharedMemTracker()); |
| 269 } | 235 } |
| 270 NOTREACHED(); | 236 NOTREACHED(); |
| 271 return scoped_ptr<VideoCaptureBufferPool::Tracker>(); | 237 return scoped_ptr<VideoCaptureBufferPool::Tracker>(); |
| 272 } | 238 } |
| 273 | 239 |
| 274 VideoCaptureBufferPool::Tracker::~Tracker() {} | 240 VideoCaptureBufferPool::Tracker::~Tracker() {} |
| 275 | 241 |
| 276 VideoCaptureBufferPool::VideoCaptureBufferPool(int count) | 242 VideoCaptureBufferPool::VideoCaptureBufferPool(int count) |
| 277 : count_(count), | 243 : count_(count), |
| 278 next_buffer_id_(0) { | 244 next_buffer_id_(0), |
| 245 last_relinquished_buffer_id_(kInvalidId) { |
| 279 DCHECK_GT(count, 0); | 246 DCHECK_GT(count, 0); |
| 280 } | 247 } |
| 281 | 248 |
| 282 VideoCaptureBufferPool::~VideoCaptureBufferPool() { | 249 VideoCaptureBufferPool::~VideoCaptureBufferPool() { |
| 283 STLDeleteValues(&trackers_); | 250 STLDeleteValues(&trackers_); |
| 284 } | 251 } |
| 285 | 252 |
| 286 bool VideoCaptureBufferPool::ShareToProcess( | 253 bool VideoCaptureBufferPool::ShareToProcess( |
| 287 int buffer_id, | 254 int buffer_id, |
| 288 base::ProcessHandle process_handle, | 255 base::ProcessHandle process_handle, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 Tracker* tracker = GetTracker(buffer_id); | 292 Tracker* tracker = GetTracker(buffer_id); |
| 326 if (!tracker) { | 293 if (!tracker) { |
| 327 NOTREACHED() << "Invalid buffer_id."; | 294 NOTREACHED() << "Invalid buffer_id."; |
| 328 return scoped_ptr<BufferHandle>(); | 295 return scoped_ptr<BufferHandle>(); |
| 329 } | 296 } |
| 330 | 297 |
| 331 DCHECK(tracker->held_by_producer()); | 298 DCHECK(tracker->held_by_producer()); |
| 332 return tracker->GetBufferHandle(); | 299 return tracker->GetBufferHandle(); |
| 333 } | 300 } |
| 334 | 301 |
| 335 int VideoCaptureBufferPool::ReserveForProducer( | 302 int VideoCaptureBufferPool::ReserveForProducer(const gfx::Size& dimensions, |
| 336 media::VideoPixelFormat format, | 303 media::VideoPixelFormat format, |
| 337 media::VideoPixelStorage storage, | 304 media::VideoPixelStorage storage, |
| 338 const gfx::Size& dimensions, | 305 int* buffer_id_to_drop) { |
| 339 int* buffer_id_to_drop) { | |
| 340 base::AutoLock lock(lock_); | 306 base::AutoLock lock(lock_); |
| 341 return ReserveForProducerInternal(format, storage, dimensions, | 307 return ReserveForProducerInternal(dimensions, format, storage, |
| 342 buffer_id_to_drop); | 308 buffer_id_to_drop); |
| 343 } | 309 } |
| 344 | 310 |
| 345 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { | 311 void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { |
| 346 base::AutoLock lock(lock_); | 312 base::AutoLock lock(lock_); |
| 347 Tracker* tracker = GetTracker(buffer_id); | 313 Tracker* tracker = GetTracker(buffer_id); |
| 348 if (!tracker) { | 314 if (!tracker) { |
| 349 NOTREACHED() << "Invalid buffer_id."; | 315 NOTREACHED() << "Invalid buffer_id."; |
| 350 return; | 316 return; |
| 351 } | 317 } |
| 352 DCHECK(tracker->held_by_producer()); | 318 DCHECK(tracker->held_by_producer()); |
| 353 tracker->set_held_by_producer(false); | 319 tracker->set_held_by_producer(false); |
| 320 last_relinquished_buffer_id_ = buffer_id; |
| 354 } | 321 } |
| 355 | 322 |
| 356 void VideoCaptureBufferPool::HoldForConsumers( | 323 void VideoCaptureBufferPool::HoldForConsumers( |
| 357 int buffer_id, | 324 int buffer_id, |
| 358 int num_clients) { | 325 int num_clients) { |
| 359 base::AutoLock lock(lock_); | 326 base::AutoLock lock(lock_); |
| 360 Tracker* tracker = GetTracker(buffer_id); | 327 Tracker* tracker = GetTracker(buffer_id); |
| 361 if (!tracker) { | 328 if (!tracker) { |
| 362 NOTREACHED() << "Invalid buffer_id."; | 329 NOTREACHED() << "Invalid buffer_id."; |
| 363 return; | 330 return; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 378 if (!tracker) { | 345 if (!tracker) { |
| 379 NOTREACHED() << "Invalid buffer_id."; | 346 NOTREACHED() << "Invalid buffer_id."; |
| 380 return; | 347 return; |
| 381 } | 348 } |
| 382 DCHECK_GE(tracker->consumer_hold_count(), num_clients); | 349 DCHECK_GE(tracker->consumer_hold_count(), num_clients); |
| 383 | 350 |
| 384 tracker->set_consumer_hold_count(tracker->consumer_hold_count() - | 351 tracker->set_consumer_hold_count(tracker->consumer_hold_count() - |
| 385 num_clients); | 352 num_clients); |
| 386 } | 353 } |
| 387 | 354 |
| 355 int VideoCaptureBufferPool::ResurrectLastForProducer( |
| 356 const gfx::Size& dimensions, |
| 357 media::VideoPixelFormat format, |
| 358 media::VideoPixelStorage storage) { |
| 359 base::AutoLock lock(lock_); |
| 360 |
| 361 // Return early if the last relinquished buffer has been re-used already. |
| 362 if (last_relinquished_buffer_id_ == kInvalidId) |
| 363 return kInvalidId; |
| 364 |
| 365 // If there are no consumers reading from this buffer, then it's safe to |
| 366 // provide this buffer back to the producer (because the producer may |
| 367 // potentially modify the content). Check that the expected dimensions, |
| 368 // format, and storage match. |
| 369 TrackerMap::iterator it = trackers_.find(last_relinquished_buffer_id_); |
| 370 DCHECK(it != trackers_.end()); |
| 371 DCHECK(!it->second->held_by_producer()); |
| 372 if (it->second->consumer_hold_count() == 0 && |
| 373 it->second->dimensions() == dimensions && |
| 374 it->second->pixel_format() == format && |
| 375 it->second->storage_type() == storage) { |
| 376 it->second->set_held_by_producer(true); |
| 377 return last_relinquished_buffer_id_; |
| 378 } |
| 379 |
| 380 return kInvalidId; |
| 381 } |
| 382 |
| 388 double VideoCaptureBufferPool::GetBufferPoolUtilization() const { | 383 double VideoCaptureBufferPool::GetBufferPoolUtilization() const { |
| 389 base::AutoLock lock(lock_); | 384 base::AutoLock lock(lock_); |
| 390 int num_buffers_held = 0; | 385 int num_buffers_held = 0; |
| 391 for (const auto& entry : trackers_) { | 386 for (const auto& entry : trackers_) { |
| 392 Tracker* const tracker = entry.second; | 387 Tracker* const tracker = entry.second; |
| 393 if (tracker->held_by_producer() || tracker->consumer_hold_count() > 0) | 388 if (tracker->held_by_producer() || tracker->consumer_hold_count() > 0) |
| 394 ++num_buffers_held; | 389 ++num_buffers_held; |
| 395 } | 390 } |
| 396 return static_cast<double>(num_buffers_held) / count_; | 391 return static_cast<double>(num_buffers_held) / count_; |
| 397 } | 392 } |
| 398 | 393 |
| 399 int VideoCaptureBufferPool::ReserveForProducerInternal( | 394 int VideoCaptureBufferPool::ReserveForProducerInternal( |
| 395 const gfx::Size& dimensions, |
| 400 media::VideoPixelFormat pixel_format, | 396 media::VideoPixelFormat pixel_format, |
| 401 media::VideoPixelStorage storage_type, | 397 media::VideoPixelStorage storage_type, |
| 402 const gfx::Size& dimensions, | |
| 403 int* buffer_id_to_drop) { | 398 int* buffer_id_to_drop) { |
| 404 lock_.AssertAcquired(); | 399 lock_.AssertAcquired(); |
| 405 | 400 |
| 406 const size_t size_in_pixels = dimensions.GetArea(); | 401 const size_t size_in_pixels = dimensions.GetArea(); |
| 407 // Look for a tracker that's allocated, big enough, and not in use. Track the | 402 // Look for a tracker that's allocated, big enough, and not in use. Track the |
| 408 // largest one that's not big enough, in case we have to reallocate a tracker. | 403 // largest one that's not big enough, in case we have to reallocate a tracker. |
| 409 *buffer_id_to_drop = kInvalidId; | 404 *buffer_id_to_drop = kInvalidId; |
| 410 size_t largest_size_in_pixels = 0; | 405 size_t largest_size_in_pixels = 0; |
| 406 TrackerMap::iterator tracker_of_last_resort = trackers_.end(); |
| 411 TrackerMap::iterator tracker_to_drop = trackers_.end(); | 407 TrackerMap::iterator tracker_to_drop = trackers_.end(); |
| 412 for (TrackerMap::iterator it = trackers_.begin(); it != trackers_.end(); | 408 for (TrackerMap::iterator it = trackers_.begin(); it != trackers_.end(); |
| 413 ++it) { | 409 ++it) { |
| 414 Tracker* const tracker = it->second; | 410 Tracker* const tracker = it->second; |
| 415 if (!tracker->consumer_hold_count() && !tracker->held_by_producer()) { | 411 if (!tracker->consumer_hold_count() && !tracker->held_by_producer()) { |
| 416 if (tracker->pixel_count() >= size_in_pixels && | 412 if (tracker->max_pixel_count() >= size_in_pixels && |
| 417 (tracker->pixel_format() == pixel_format) && | 413 (tracker->pixel_format() == pixel_format) && |
| 418 (tracker->storage_type() == storage_type)) { | 414 (tracker->storage_type() == storage_type)) { |
| 415 if (it->first == last_relinquished_buffer_id_) { |
| 416 // This buffer would do just fine, but avoid returning it because the |
| 417 // client may want to resurrect it. It will be returned perforce if |
| 418 // the pool has reached it's maximum limit (see code below). |
| 419 tracker_of_last_resort = it; |
| 420 continue; |
| 421 } |
| 419 // Existing tracker is big enough and has correct format. Reuse it. | 422 // Existing tracker is big enough and has correct format. Reuse it. |
| 423 tracker->set_dimensions(dimensions); |
| 420 tracker->set_held_by_producer(true); | 424 tracker->set_held_by_producer(true); |
| 421 return it->first; | 425 return it->first; |
| 422 } | 426 } |
| 423 if (tracker->pixel_count() > largest_size_in_pixels) { | 427 if (tracker->max_pixel_count() > largest_size_in_pixels) { |
| 424 largest_size_in_pixels = tracker->pixel_count(); | 428 largest_size_in_pixels = tracker->max_pixel_count(); |
| 425 tracker_to_drop = it; | 429 tracker_to_drop = it; |
| 426 } | 430 } |
| 427 } | 431 } |
| 428 } | 432 } |
| 429 | 433 |
| 430 // Preferably grow the pool by creating a new tracker. If we're at maximum | 434 // Preferably grow the pool by creating a new tracker. If we're at maximum |
| 431 // size, then reallocate by deleting an existing one instead. | 435 // size, then try using |tracker_of_last_resort| or reallocate by deleting an |
| 436 // existing one instead. |
| 432 if (trackers_.size() == static_cast<size_t>(count_)) { | 437 if (trackers_.size() == static_cast<size_t>(count_)) { |
| 438 if (tracker_of_last_resort != trackers_.end()) { |
| 439 last_relinquished_buffer_id_ = kInvalidId; |
| 440 tracker_of_last_resort->second->set_dimensions(dimensions); |
| 441 tracker_of_last_resort->second->set_held_by_producer(true); |
| 442 return tracker_of_last_resort->first; |
| 443 } |
| 433 if (tracker_to_drop == trackers_.end()) { | 444 if (tracker_to_drop == trackers_.end()) { |
| 434 // We're out of space, and can't find an unused tracker to reallocate. | 445 // We're out of space, and can't find an unused tracker to reallocate. |
| 435 return kInvalidId; | 446 return kInvalidId; |
| 436 } | 447 } |
| 448 if (tracker_to_drop->first == last_relinquished_buffer_id_) |
| 449 last_relinquished_buffer_id_ = kInvalidId; |
| 437 *buffer_id_to_drop = tracker_to_drop->first; | 450 *buffer_id_to_drop = tracker_to_drop->first; |
| 438 delete tracker_to_drop->second; | 451 delete tracker_to_drop->second; |
| 439 trackers_.erase(tracker_to_drop); | 452 trackers_.erase(tracker_to_drop); |
| 440 } | 453 } |
| 441 | 454 |
| 442 // Create the new tracker. | 455 // Create the new tracker. |
| 443 const int buffer_id = next_buffer_id_++; | 456 const int buffer_id = next_buffer_id_++; |
| 444 | 457 |
| 445 scoped_ptr<Tracker> tracker = Tracker::CreateTracker(storage_type); | 458 scoped_ptr<Tracker> tracker = Tracker::CreateTracker(storage_type); |
| 446 // TODO(emircan): We pass the lock here to solve GMB allocation issue, see | 459 // TODO(emircan): We pass the lock here to solve GMB allocation issue, see |
| 447 // crbug.com/545238. | 460 // crbug.com/545238. |
| 448 if (!tracker->Init(pixel_format, storage_type, dimensions, &lock_)) { | 461 if (!tracker->Init(dimensions, pixel_format, storage_type, &lock_)) { |
| 449 DLOG(ERROR) << "Error initializing Tracker"; | 462 DLOG(ERROR) << "Error initializing Tracker"; |
| 450 return kInvalidId; | 463 return kInvalidId; |
| 451 } | 464 } |
| 452 | 465 |
| 453 tracker->set_held_by_producer(true); | 466 tracker->set_held_by_producer(true); |
| 454 trackers_[buffer_id] = tracker.release(); | 467 trackers_[buffer_id] = tracker.release(); |
| 455 | 468 |
| 456 return buffer_id; | 469 return buffer_id; |
| 457 } | 470 } |
| 458 | 471 |
| 459 VideoCaptureBufferPool::Tracker* VideoCaptureBufferPool::GetTracker( | 472 VideoCaptureBufferPool::Tracker* VideoCaptureBufferPool::GetTracker( |
| 460 int buffer_id) { | 473 int buffer_id) { |
| 461 TrackerMap::const_iterator it = trackers_.find(buffer_id); | 474 TrackerMap::const_iterator it = trackers_.find(buffer_id); |
| 462 return (it == trackers_.end()) ? NULL : it->second; | 475 return (it == trackers_.end()) ? NULL : it->second; |
| 463 } | 476 } |
| 464 | 477 |
| 465 } // namespace content | 478 } // namespace content |
| OLD | NEW |