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(); |