Chromium Code Reviews| Index: content/browser/renderer_host/media/video_capture_buffer_pool.cc |
| diff --git a/content/browser/renderer_host/media/video_capture_buffer_pool.cc b/content/browser/renderer_host/media/video_capture_buffer_pool.cc |
| index a336a7efc7896563a19f2ec8bf29cad0625f7354..741a441910913b6fb700cc15d3ebfd9a0241c2d7 100644 |
| --- a/content/browser/renderer_host/media/video_capture_buffer_pool.cc |
| +++ b/content/browser/renderer_host/media/video_capture_buffer_pool.cc |
| @@ -7,6 +7,9 @@ |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/stl_util.h" |
| +#include "content/browser/gpu/browser_gpu_memory_buffer_manager.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "media/base/video_frame.h" |
| using media::VideoFrame; |
| @@ -21,8 +24,8 @@ VideoFrame::Format VideoPixelFormatToVideoFrameFormat( |
| VideoFrame::Format frame_format; |
| } const kVideoPixelFormatToVideoFrameFormat[] = { |
| {media::PIXEL_FORMAT_I420, VideoFrame::I420}, |
| - {media::PIXEL_FORMAT_ARGB, VideoFrame::ARGB}, |
| {media::PIXEL_FORMAT_TEXTURE, VideoFrame::NATIVE_TEXTURE}, |
| + {media::PIXEL_FORMAT_GPUMEMORYBUFFER, VideoFrame::NATIVE_TEXTURE}, |
| }; |
| for (const auto& format_pair : kVideoPixelFormatToVideoFrameFormat) { |
| @@ -34,15 +37,83 @@ VideoFrame::Format VideoPixelFormatToVideoFrameFormat( |
| return VideoFrame::UNKNOWN; |
| } |
| +// A trivial holder of a void* |data_| member and accessor. |
| +class SimpleDataHandle : public media::DataHandle { |
| + public: |
| + explicit SimpleDataHandle(void* data) : data_(data) {} |
| + void* data() override { return data_; } |
| + private: |
| + void* data_; |
| +}; |
| + |
| +// A Handle to a GpuMemoryBuffer, Map()ed on construction and Unmap()ed on |
| +// destruction. |
| +class GpuMemoryBufferDataHandle : public media::DataHandle { |
| + public: |
| + explicit GpuMemoryBufferDataHandle(gfx::GpuMemoryBuffer* gmb) : gmb_(gmb) { |
| + DCHECK(!gmb_->IsMapped()); |
| + gmb_->Map(&data_); |
|
emircan
2015/04/13 21:31:30
Map() can fill multiple ptrs. Since you are creati
mcasas
2015/04/16 03:11:21
Done.
|
| + } |
| + ~GpuMemoryBufferDataHandle() override { gmb_->Unmap(); } |
| + void* data() override { return data_; } |
| + |
| + private: |
| + gfx::GpuMemoryBuffer* const gmb_; |
| + void* data_; |
| +}; |
| + |
| +// A simple holder of a memory-backed buffer and a factory of SimpleDataHandles |
| +// to it. |
| +class SimpleBufferHandle : public VideoCaptureBufferPool::BufferHandle { |
| + public: |
| + SimpleBufferHandle(void* data, size_t size) : data_(data), size_(size) {} |
| + ~SimpleBufferHandle() override {} |
| + |
| + size_t size() const override { return size_; } |
| + scoped_ptr<media::DataHandle> GetDataHandle() override { |
| + return make_scoped_ptr(new SimpleDataHandle(data_)); |
| + } |
| + ClientBuffer AsClientBuffer() override { return nullptr; } |
| + |
| + private: |
| + void* const data_; |
| + const size_t size_; |
| +}; |
| + |
| +// A holder of a GpuMemoryBuffer-backed buffer with a factory of specific |
| +// DataHandles to it. HOlds a weak reference to its GpuMemoryBuffer. |
| +class GpuMemoryBufferBufferHandle |
| + : public VideoCaptureBufferPool::BufferHandle { |
| + public: |
| + GpuMemoryBufferBufferHandle(gfx::GpuMemoryBuffer* gmb, size_t size) |
| + : gmb_(gmb), |
| + size_(size) { |
| + DCHECK(gmb && !gmb_->IsMapped()); |
| + } |
| + |
| + size_t size() const override { return size_; } |
| + scoped_ptr<media::DataHandle> GetDataHandle() override { |
| + return make_scoped_ptr(new GpuMemoryBufferDataHandle(gmb_)); |
| + } |
| + ClientBuffer AsClientBuffer() override { return gmb_->AsClientBuffer(); } |
| + |
| + private: |
| + gfx::GpuMemoryBuffer* const gmb_; |
| + const size_t size_; |
| +}; |
| + |
| // Tracker specifics for SharedMemory. |
| class VideoCaptureBufferPool::SharedMemTracker final : public Tracker { |
| public: |
| SharedMemTracker(); |
| - |
| bool Init(VideoFrame::Format format, const gfx::Size& dimensions) override; |
| - void* storage() override { return shared_memory_.memory(); } |
| - size_t requested_size() override { return shared_memory_.requested_size(); } |
| - size_t mapped_size() override { return shared_memory_.mapped_size(); } |
| + |
| + size_t mapped_size() const override { return shared_memory_.mapped_size(); } |
| + |
| + scoped_ptr<BufferHandle> GetBufferHandle() override { |
| + return make_scoped_ptr( |
| + new SimpleBufferHandle(shared_memory_.memory(), mapped_size())); |
| + } |
| bool ShareToProcess(base::ProcessHandle process_handle, |
| base::SharedMemoryHandle* new_handle) override { |
| @@ -54,8 +125,32 @@ class VideoCaptureBufferPool::SharedMemTracker final : public Tracker { |
| base::SharedMemory shared_memory_; |
| }; |
| -VideoCaptureBufferPool::SharedMemTracker::SharedMemTracker() |
| - : Tracker() {} |
| +// Tracker specifics for GpuMemoryBuffer. Owns one GpuMemoryBuffer and its |
| +// associated pixel dimensions. |
| +class VideoCaptureBufferPool::GpuMemoryBufferTracker final : public Tracker { |
| + public: |
| + GpuMemoryBufferTracker(); |
| + bool Init(VideoFrame::Format format, const gfx::Size& dimensions) override; |
| + ~GpuMemoryBufferTracker() override; |
| + |
| + size_t mapped_size() const override { return packed_size_; } |
| + scoped_ptr<BufferHandle> GetBufferHandle() override { |
| + return make_scoped_ptr(new GpuMemoryBufferBufferHandle( |
| + gpu_memory_buffer_.get(), packed_size_)); |
| + } |
| + |
| + bool ShareToProcess(base::ProcessHandle process_handle, |
| + base::SharedMemoryHandle* new_handle) override { |
| + return true; |
| + } |
| + |
| + private: |
| + size_t packed_size_; |
| + scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_; |
| +}; |
| + |
| +VideoCaptureBufferPool::SharedMemTracker::SharedMemTracker() : Tracker() { |
| +} |
| bool VideoCaptureBufferPool::SharedMemTracker::Init( |
| VideoFrame::Format format, |
| @@ -63,14 +158,47 @@ bool VideoCaptureBufferPool::SharedMemTracker::Init( |
| // Input |dimensions| can be 0x0 for trackers that do not require memory |
| // backing. The allocated size is calculated using VideoFrame methods since |
| // this will be the abstraction used to wrap the underlying data. |
| - return shared_memory_.CreateAndMapAnonymous( |
| - VideoFrame::AllocationSize(format, dimensions)); |
| + set_pixel_count(dimensions.GetArea()); |
| + const size_t byte_count = VideoFrame::AllocationSize(format, dimensions); |
| + DVLOG(1) << "allocating ShMem of " << byte_count << "B"; |
| + if (!byte_count) |
| + return true; |
| + return shared_memory_.CreateAndMapAnonymous(byte_count); |
| +} |
| + |
| +VideoCaptureBufferPool::GpuMemoryBufferTracker::GpuMemoryBufferTracker() |
| + : Tracker(), gpu_memory_buffer_(nullptr) {} |
| + |
| +VideoCaptureBufferPool::GpuMemoryBufferTracker::~GpuMemoryBufferTracker() { |
| + if (gpu_memory_buffer_->IsMapped()) |
| + gpu_memory_buffer_->Unmap(); |
| +} |
| + |
| +bool VideoCaptureBufferPool::GpuMemoryBufferTracker::Init( |
| + VideoFrame::Format format, |
| + const gfx::Size& dimensions) { |
| + // BrowserGpuMemoryBufferManager::current() may not be accessed on IO Thread. |
| + DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + set_pixel_count(dimensions.GetArea()); |
| + packed_size_ = media::VideoFrame::AllocationSize(VideoFrame::ARGB, |
| + dimensions); |
|
emircan
2015/04/13 21:31:30
How is this guaranteed to correspond to the alloca
mcasas
2015/04/16 03:11:21
Changed to calculating using GpuMemoryBuffer metho
|
| + DVLOG(1) << "allocating GMB for " << packed_size_ << "B"; |
| + DCHECK(BrowserGpuMemoryBufferManager::current()); |
| + gpu_memory_buffer_ = |
| + BrowserGpuMemoryBufferManager::current()->AllocateGpuMemoryBuffer( |
| + dimensions, gfx::GpuMemoryBuffer::BGRA_8888, |
| + gfx::GpuMemoryBuffer::MAP); |
| + DLOG_IF(ERROR, !gpu_memory_buffer_.get()) << "Allocating GpuMemoryBuffer"; |
| + return (gpu_memory_buffer_.get() != nullptr); // Verbose evaluation for Win. |
| } |
| //static |
| scoped_ptr<VideoCaptureBufferPool::Tracker> |
| -VideoCaptureBufferPool::Tracker::CreateTracker() { |
| - return make_scoped_ptr(new SharedMemTracker()); |
| +VideoCaptureBufferPool::Tracker::CreateTracker(bool use_gmb) { |
| + if (!use_gmb) |
| + return make_scoped_ptr(new SharedMemTracker()); |
| + else |
| + return make_scoped_ptr(new GpuMemoryBufferTracker()); |
| } |
| VideoCaptureBufferPool::Tracker::~Tracker() {} |
| @@ -101,25 +229,22 @@ base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess( |
| *memory_size = tracker->mapped_size(); |
| return remote_handle; |
| } |
| - DPLOG(ERROR) << "Error mapping Shared Memory."; |
| + DPLOG(ERROR) << "Error mapping Shared Memory"; |
| return base::SharedMemoryHandle(); |
| } |
| -bool VideoCaptureBufferPool::GetBufferInfo(int buffer_id, |
| - void** storage, |
| - size_t* size) { |
| +scoped_ptr<VideoCaptureBufferPool::BufferHandle> |
| +VideoCaptureBufferPool::GetBufferHandle(int buffer_id) { |
| base::AutoLock lock(lock_); |
| Tracker* tracker = GetTracker(buffer_id); |
| if (!tracker) { |
| NOTREACHED() << "Invalid buffer_id."; |
| - return false; |
| + return scoped_ptr<BufferHandle>(); |
| } |
| DCHECK(tracker->held_by_producer()); |
| - *storage = tracker->storage(); |
| - *size = tracker->mapped_size(); |
| - return true; |
| + return tracker->GetBufferHandle(); |
| } |
| int VideoCaptureBufferPool::ReserveForProducer(media::VideoPixelFormat format, |
| @@ -177,30 +302,28 @@ int VideoCaptureBufferPool::ReserveForProducerInternal( |
| const gfx::Size& dimensions, |
| int* buffer_id_to_drop) { |
| DCHECK(format == media::PIXEL_FORMAT_I420 || |
| - format == media::PIXEL_FORMAT_ARGB || |
| - format == media::PIXEL_FORMAT_TEXTURE); |
| + format == media::PIXEL_FORMAT_TEXTURE || |
| + format == media::PIXEL_FORMAT_GPUMEMORYBUFFER ); |
| lock_.AssertAcquired(); |
| - const media::VideoFrame::Format frame_format = |
| - VideoPixelFormatToVideoFrameFormat(format); |
| - const size_t size_in_bytes = |
| - VideoFrame::AllocationSize(frame_format, dimensions); |
| + *buffer_id_to_drop = kInvalidId; |
| + const size_t size_in_pixels = dimensions.GetArea(); |
| // Look for a tracker that's allocated, big enough, and not in use. Track the |
| // largest one that's not big enough, in case we have to reallocate a tracker. |
| *buffer_id_to_drop = kInvalidId; |
| - size_t realloc_size = 0; |
| + size_t largest_size_in_pixels = 0; |
| TrackerMap::iterator tracker_to_drop = trackers_.end(); |
| for (TrackerMap::iterator it = trackers_.begin(); it != trackers_.end(); |
| ++it) { |
| Tracker* const tracker = it->second; |
| if (!tracker->consumer_hold_count() && !tracker->held_by_producer()) { |
| - if (tracker->requested_size() >= size_in_bytes) { |
| + if (tracker->pixel_count() >= size_in_pixels) { |
| // Existing tracker is big enough. Reuse it. |
| tracker->set_held_by_producer(true); |
| return it->first; |
| } |
| - if (tracker->requested_size() > realloc_size) { |
| - realloc_size = tracker->requested_size(); |
| + if (tracker->pixel_count() > largest_size_in_pixels) { |
| + largest_size_in_pixels = tracker->pixel_count(); |
| tracker_to_drop = it; |
| } |
| } |
| @@ -220,9 +343,13 @@ int VideoCaptureBufferPool::ReserveForProducerInternal( |
| // Create the new tracker. |
| const int buffer_id = next_buffer_id_++; |
| - scoped_ptr<Tracker> tracker = Tracker::CreateTracker(); |
| - if (!tracker->Init(frame_format, dimensions)) |
| + |
| + scoped_ptr<Tracker> tracker = |
| + Tracker::CreateTracker(format == media::PIXEL_FORMAT_GPUMEMORYBUFFER); |
| + if (!tracker->Init(VideoPixelFormatToVideoFrameFormat(format), dimensions)) { |
| + DLOG(ERROR) << "Error initializing Tracker"; |
| return kInvalidId; |
| + } |
| tracker->set_held_by_producer(true); |
| trackers_[buffer_id] = tracker.release(); |