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 3e30834feb2ca8a17788ddd94cf3b0ade2147eb9..f6486a5405128c6006329a2462a794fbf7c4a38c 100644 |
--- a/content/browser/renderer_host/media/video_capture_buffer_pool.cc |
+++ b/content/browser/renderer_host/media/video_capture_buffer_pool.cc |
@@ -7,71 +7,54 @@ |
#include "base/bind.h" |
#include "base/callback.h" |
#include "base/logging.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/stl_util.h" |
#include "media/base/video_frame.h" |
#include "media/base/video_util.h" |
namespace content { |
-VideoCaptureBufferPool::VideoCaptureBufferPool(size_t size, int count) |
- : size_(size), |
- count_(count) { |
-} |
+const int VideoCaptureBufferPool::kInvalidId = -1; |
-VideoCaptureBufferPool::~VideoCaptureBufferPool() { |
+VideoCaptureBufferPool::VideoCaptureBufferPool(int count) |
+ : count_(count), |
+ next_buffer_id_(0) { |
} |
-bool VideoCaptureBufferPool::Allocate() { |
- base::AutoLock lock(lock_); |
- DCHECK(!IsAllocated()); |
- buffers_.resize(count_); |
- for (int buffer_id = 0; buffer_id < count(); ++buffer_id) { |
- Buffer* buffer = new Buffer(); |
- buffers_[buffer_id] = buffer; |
- if (!buffer->shared_memory.CreateAndMapAnonymous(GetMemorySize())) |
- return false; |
- } |
- return true; |
+VideoCaptureBufferPool::~VideoCaptureBufferPool() { |
+ STLDeleteValues(&buffers_); |
} |
base::SharedMemoryHandle VideoCaptureBufferPool::ShareToProcess( |
int buffer_id, |
- base::ProcessHandle process_handle) { |
+ base::ProcessHandle process_handle, |
+ size_t* memory_size) { |
base::AutoLock lock(lock_); |
- DCHECK(IsAllocated()); |
- DCHECK(buffer_id >= 0); |
- DCHECK(buffer_id < count_); |
- Buffer* buffer = buffers_[buffer_id]; |
+ |
+ Buffer* buffer = GetBuffer(buffer_id); |
+ if (!buffer) { |
+ NOTREACHED() << "Invalid buffer_id."; |
+ return base::SharedMemory::NULLHandle(); |
+ } |
base::SharedMemoryHandle remote_handle; |
buffer->shared_memory.ShareToProcess(process_handle, &remote_handle); |
+ *memory_size = buffer->shared_memory.requested_size(); |
return remote_handle; |
} |
-base::SharedMemoryHandle VideoCaptureBufferPool::GetHandle(int buffer_id) { |
+int VideoCaptureBufferPool::ReserveForProducer(size_t size, |
+ int* buffer_id_to_drop) { |
base::AutoLock lock(lock_); |
- DCHECK(IsAllocated()); |
- DCHECK(buffer_id >= 0); |
- DCHECK(buffer_id < count_); |
- return buffers_[buffer_id]->shared_memory.handle(); |
-} |
- |
-void* VideoCaptureBufferPool::GetMemory(int buffer_id) { |
- base::AutoLock lock(lock_); |
- DCHECK(IsAllocated()); |
- DCHECK(buffer_id >= 0); |
- DCHECK(buffer_id < count_); |
- return buffers_[buffer_id]->shared_memory.memory(); |
-} |
- |
-int VideoCaptureBufferPool::ReserveForProducer() { |
- base::AutoLock lock(lock_); |
- return ReserveForProducerInternal(); |
+ return ReserveForProducerInternal(size, buffer_id_to_drop); |
} |
void VideoCaptureBufferPool::RelinquishProducerReservation(int buffer_id) { |
base::AutoLock lock(lock_); |
- DCHECK(buffer_id >= 0); |
- DCHECK(buffer_id < count()); |
- Buffer* buffer = buffers_[buffer_id]; |
+ Buffer* buffer = GetBuffer(buffer_id); |
+ if (!buffer) { |
+ NOTREACHED() << "Invalid buffer_id."; |
+ return; |
+ } |
DCHECK(buffer->held_by_producer); |
buffer->held_by_producer = false; |
} |
@@ -80,65 +63,56 @@ void VideoCaptureBufferPool::HoldForConsumers( |
int buffer_id, |
int num_clients) { |
base::AutoLock lock(lock_); |
- DCHECK(buffer_id >= 0); |
- DCHECK(buffer_id < count()); |
- DCHECK(IsAllocated()); |
- Buffer* buffer = buffers_[buffer_id]; |
+ Buffer* buffer = GetBuffer(buffer_id); |
+ if (!buffer) { |
+ NOTREACHED() << "Invalid buffer_id."; |
+ return; |
+ } |
DCHECK(buffer->held_by_producer); |
DCHECK(!buffer->consumer_hold_count); |
buffer->consumer_hold_count = num_clients; |
// Note: |held_by_producer| will stay true until |
// RelinquishProducerReservation() (usually called by destructor of the object |
- // wrapping this buffer, e.g. a media::VideoFrame |
+ // wrapping this buffer, e.g. a media::VideoFrame). |
} |
void VideoCaptureBufferPool::RelinquishConsumerHold(int buffer_id, |
int num_clients) { |
base::AutoLock lock(lock_); |
- DCHECK(buffer_id >= 0); |
- DCHECK(buffer_id < count()); |
- DCHECK_GT(num_clients, 0); |
- DCHECK(IsAllocated()); |
- Buffer* buffer = buffers_[buffer_id]; |
+ Buffer* buffer = GetBuffer(buffer_id); |
+ if (!buffer) { |
+ NOTREACHED() << "Invalid buffer_id."; |
+ return; |
+ } |
DCHECK_GE(buffer->consumer_hold_count, num_clients); |
buffer->consumer_hold_count -= num_clients; |
} |
-// State query functions. |
-size_t VideoCaptureBufferPool::GetMemorySize() const { |
- // No need to take |lock_| currently. |
- return size_; |
-} |
- |
int VideoCaptureBufferPool::RecognizeReservedBuffer( |
base::SharedMemoryHandle maybe_belongs_to_pool) { |
base::AutoLock lock(lock_); |
- for (int buffer_id = 0; buffer_id < count(); ++buffer_id) { |
- Buffer* buffer = buffers_[buffer_id]; |
- if (buffer->shared_memory.handle() == maybe_belongs_to_pool) { |
- DCHECK(buffer->held_by_producer); |
- return buffer_id; |
+ for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { |
+ if (it->second->shared_memory.handle() == maybe_belongs_to_pool) { |
+ DCHECK(it->second->held_by_producer); |
+ return it->first; |
} |
} |
- return -1; // Buffer is not from our pool. |
+ return kInvalidId; // Buffer is not from our pool. |
} |
scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame( |
const gfx::Size& size, |
- int rotation) { |
- if (GetMemorySize() != |
- media::VideoFrame::AllocationSize(media::VideoFrame::I420, size)) { |
- DCHECK_EQ(GetMemorySize(), |
- media::VideoFrame::AllocationSize(media::VideoFrame::I420, size)); |
- return NULL; |
- } |
- |
+ int rotation, |
+ int* buffer_id_to_drop) { |
base::AutoLock lock(lock_); |
- int buffer_id = ReserveForProducerInternal(); |
- if (buffer_id < 0) |
+ size_t frame_bytes = |
+ media::VideoFrame::AllocationSize(media::VideoFrame::I420, size); |
+ |
+ int buffer_id = ReserveForProducerInternal(frame_bytes, buffer_id_to_drop); |
+ if (buffer_id == kInvalidId) |
return NULL; |
base::Closure disposal_handler = base::Bind( |
@@ -146,7 +120,7 @@ scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame( |
this, |
buffer_id); |
- Buffer* buffer = buffers_[buffer_id]; |
+ Buffer* buffer = GetBuffer(buffer_id); |
// Wrap the buffer in a VideoFrame container. |
scoped_refptr<media::VideoFrame> frame = |
media::VideoFrame::WrapExternalSharedMemory( |
@@ -155,13 +129,13 @@ scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame( |
gfx::Rect(size), |
size, |
static_cast<uint8*>(buffer->shared_memory.memory()), |
- GetMemorySize(), |
+ frame_bytes, |
buffer->shared_memory.handle(), |
base::TimeDelta(), |
disposal_handler); |
if (buffer->rotation != rotation) { |
- // TODO(nick): Generalize the |rotation| mechanism. |
+ // TODO(jiayl): Generalize the |rotation| mechanism. |
media::FillYUV(frame.get(), 0, 128, 128); |
buffer->rotation = rotation; |
} |
@@ -169,45 +143,62 @@ scoped_refptr<media::VideoFrame> VideoCaptureBufferPool::ReserveI420VideoFrame( |
return frame; |
} |
-bool VideoCaptureBufferPool::IsAnyBufferHeldForConsumers() { |
- base::AutoLock lock(lock_); |
- for (int buffer_id = 0; buffer_id < count(); ++buffer_id) { |
- Buffer* buffer = buffers_[buffer_id]; |
- if (buffer->consumer_hold_count > 0) |
- return true; |
- } |
- return false; |
-} |
- |
VideoCaptureBufferPool::Buffer::Buffer() |
: rotation(0), |
held_by_producer(false), |
consumer_hold_count(0) {} |
-int VideoCaptureBufferPool::ReserveForProducerInternal() { |
+int VideoCaptureBufferPool::ReserveForProducerInternal(size_t size, |
+ int* buffer_id_to_drop) { |
lock_.AssertAcquired(); |
- DCHECK(IsAllocated()); |
- int buffer_id = -1; |
- for (int candidate_id = 0; candidate_id < count(); ++candidate_id) { |
- Buffer* candidate = buffers_[candidate_id]; |
- if (!candidate->consumer_hold_count && !candidate->held_by_producer) { |
- buffer_id = candidate_id; |
+ // Look for a buffer that's allocated, big enough, and not in use. |
+ *buffer_id_to_drop = kInvalidId; |
+ for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { |
+ Buffer* buffer = it->second; |
+ if (!buffer->consumer_hold_count && !buffer->held_by_producer) { |
+ if (buffer->shared_memory.requested_size() >= size) { |
+ // Existing buffer is big enough. Reuse it. |
+ buffer->held_by_producer = true; |
+ return it->first; |
+ } |
+ } |
+ } |
+ |
+ // Look for a buffer that's not in use, that we can reallocate. |
+ for (BufferMap::iterator it = buffers_.begin(); it != buffers_.end(); it++) { |
+ Buffer* buffer = it->second; |
+ if (!buffer->consumer_hold_count && !buffer->held_by_producer) { |
+ // Existing buffer is too small. Free it so we can allocate a new one |
+ // after the loop. |
+ *buffer_id_to_drop = it->first; |
+ buffers_.erase(it); |
+ delete buffer; |
break; |
} |
} |
- if (buffer_id == -1) |
- return -1; |
- Buffer* buffer = buffers_[buffer_id]; |
- CHECK_GE(buffer->shared_memory.requested_size(), size_); |
- buffer->held_by_producer = true; |
- return buffer_id; |
+ // If possible, grow the pool by creating a new buffer. |
+ if (static_cast<int>(buffers_.size()) < count_) { |
+ int buffer_id = next_buffer_id_++; |
+ scoped_ptr<Buffer> buffer(new Buffer()); |
+ if (!buffer->shared_memory.CreateAndMapAnonymous(size)) |
+ return kInvalidId; |
+ buffer->held_by_producer = true; |
+ buffers_[buffer_id] = buffer.release(); |
+ return buffer_id; |
+ } |
+ |
+ // The pool is at its size limit, and all buffers are in use. |
+ return kInvalidId; |
} |
-bool VideoCaptureBufferPool::IsAllocated() const { |
- lock_.AssertAcquired(); |
- return !buffers_.empty(); |
+VideoCaptureBufferPool::Buffer* VideoCaptureBufferPool::GetBuffer( |
+ int buffer_id) { |
+ BufferMap::iterator it = buffers_.find(buffer_id); |
+ if (it == buffers_.end()) |
+ return NULL; |
+ return it->second; |
} |
} // namespace content |