Index: content/renderer/media/video_capture_impl.cc |
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc |
index 9dd906b39ba4563771519ea4cd13f0ee8159e73b..077b53a0227e1a3109e068312d9ac14a712451ae 100644 |
--- a/content/renderer/media/video_capture_impl.cc |
+++ b/content/renderer/media/video_capture_impl.cc |
@@ -15,6 +15,7 @@ |
#include "base/stl_util.h" |
#include "base/thread_task_runner_handle.h" |
#include "content/child/child_process.h" |
+#include "content/common/gpu/client/gpu_memory_buffer_impl.h" |
#include "content/common/media/video_capture_messages.h" |
#include "media/base/bind_to_current_loop.h" |
#include "media/base/limits.h" |
@@ -38,6 +39,7 @@ void SaveReleaseSyncPoint(uint32* storage, uint32 release_sync_point) { |
} // namespace |
+// A holder of a memory-backed buffer and accessors to it. |
class VideoCaptureImpl::ClientBuffer |
: public base::RefCountedThreadSafe<ClientBuffer> { |
public: |
@@ -56,6 +58,63 @@ class VideoCaptureImpl::ClientBuffer |
DISALLOW_COPY_AND_ASSIGN(ClientBuffer); |
}; |
+// A holder of a GpuMemoryBuffer-backed buffer, Map()ed on ctor and Unmap()ed on |
+// dtor. Creates and owns GpuMemoryBuffer instances. |
+class VideoCaptureImpl::ClientGpuMemoryBuffer |
+ : public base::RefCountedThreadSafe<ClientGpuMemoryBuffer> { |
+ public: |
+ ClientGpuMemoryBuffer( |
+ const std::vector<gfx::GpuMemoryBufferHandle>& client_gmb_handles, |
+ const gfx::Size& size) |
+ : gmb_handles_(client_gmb_handles), |
+ size_(size), |
+ format_(media::PIXEL_FORMAT_I420) { |
+ Init(); |
+ } |
+ uint8* data(int plane) { return data_[plane]; } |
mcasas
2015/08/21 03:57:25
const method?
Here an l.75, 76.
emircan
2015/08/22 03:13:26
Done.
|
+ int32 stride(int plane) { return strides_[plane]; } |
+ std::vector<gfx::GpuMemoryBufferHandle> gpu_memory_buffer_handles() { |
+ return gmb_handles_; |
+ } |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<ClientGpuMemoryBuffer>; |
+ |
+ virtual ~ClientGpuMemoryBuffer() { |
+ for (auto& gmb : gmbs_) |
+ gmb->Unmap(); |
+ } |
mcasas
2015/08/21 03:57:25
Insert blank line.
emircan
2015/08/22 03:13:26
Done.
|
+ void Init() { |
+ for (size_t i = 0; i < gmb_handles_.size(); ++i) { |
+ const size_t width = |
+ media::VideoFrame::Columns(i, format_, size_.width()); |
+ const size_t height = media::VideoFrame::Rows(i, format_, size_.height()); |
+ gmbs_.push_back(GpuMemoryBufferImpl::CreateFromHandle( |
+ gmb_handles_[i], |
+ gfx::Size(width, height), |
+ gfx::BufferFormat::R_8, |
+ gfx::BufferUsage::MAP, |
+ base::Bind(&ClientGpuMemoryBuffer::DestroyGpuMemoryBuffer, |
+ base::Unretained(this)))); |
+ void* data_ptr = NULL; |
mcasas
2015/08/21 03:57:25
s/NULL/nullptr/
emircan
2015/08/22 03:13:26
Done.
|
+ gmbs_[i]->Map(&data_ptr); |
+ data_[i] = reinterpret_cast<uint8*>(data_ptr); |
+ strides_[i] = width; |
+ } |
+ } |
+ void DestroyGpuMemoryBuffer(uint32 sync_point) {} |
+ |
+ const std::vector<gfx::GpuMemoryBufferHandle> gmb_handles_; |
+ const gfx::Size size_; |
+ const media::VideoPixelFormat format_; |
+ // Owned instances of GMBs. |
+ ScopedVector<gfx::GpuMemoryBuffer> gmbs_; |
+ uint8* data_[media::VideoFrame::kMaxPlanes]; |
+ int32 strides_[media::VideoFrame::kMaxPlanes]; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ClientGpuMemoryBuffer); |
+}; |
+ |
VideoCaptureImpl::VideoCaptureImpl( |
const media::VideoCaptureSessionId session_id, |
VideoCaptureMessageFilter* filter) |
@@ -146,6 +205,7 @@ void VideoCaptureImpl::StopCapture() { |
state_update_cb_.Run(VIDEO_CAPTURE_STATE_STOPPED); |
StopDevice(); |
client_buffers_.clear(); |
+ client_gmb_buffers_.clear(); |
ResetClient(); |
weak_factory_.InvalidateWeakPtrs(); |
} |
@@ -168,9 +228,10 @@ void VideoCaptureImpl::GetDeviceFormatsInUse( |
new VideoCaptureHostMsg_GetDeviceFormatsInUse(device_id_, session_id_)); |
} |
-void VideoCaptureImpl::OnBufferCreated(base::SharedMemoryHandle handle, |
- int length, |
- int buffer_id) { |
+void VideoCaptureImpl::OnBufferCreated( |
+ base::SharedMemoryHandle handle, |
mcasas
2015/08/21 03:57:25
Revert to old indent.
emircan
2015/08/22 03:13:26
Done.
|
+ int length, |
+ int buffer_id) { |
DCHECK(io_task_runner_->BelongsToCurrentThread()); |
// In case client calls StopCapture before the arrival of created buffer, |
@@ -185,7 +246,6 @@ void VideoCaptureImpl::OnBufferCreated(base::SharedMemoryHandle handle, |
DLOG(ERROR) << "OnBufferCreated: Map failed."; |
return; |
} |
- |
const bool inserted = |
client_buffers_.insert(std::make_pair(buffer_id, new ClientBuffer( |
shm.Pass(), length))) |
@@ -193,16 +253,39 @@ void VideoCaptureImpl::OnBufferCreated(base::SharedMemoryHandle handle, |
DCHECK(inserted); |
} |
-void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { |
+void VideoCaptureImpl::OnGpuMemoryBufferCreated( |
+ const std::vector<gfx::GpuMemoryBufferHandle>& gmb_handles, |
+ const gfx::Size& size, |
+ int buffer_id) { |
DCHECK(io_task_runner_->BelongsToCurrentThread()); |
- const ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); |
- if (iter == client_buffers_.end()) |
+ // In case client calls StopCapture before the arrival of created buffer, |
+ // just close this buffer and return. |
+ if (state_ != VIDEO_CAPTURE_STATE_STARTED) |
return; |
- DCHECK(!iter->second.get() || iter->second->HasOneRef()) |
- << "Instructed to delete buffer we are still using."; |
- client_buffers_.erase(iter); |
+ const bool inserted = |
+ client_gmb_buffers_.insert(std::make_pair(buffer_id, |
+ new ClientGpuMemoryBuffer( |
+ gmb_handles, size))) |
+ .second; |
+ DCHECK(inserted); |
+} |
+ |
+void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { |
+ DCHECK(io_task_runner_->BelongsToCurrentThread()); |
+ |
+ const auto& cb_iter = client_buffers_.find(buffer_id); |
+ const auto& cgmb_iter = client_gmb_buffers_.find(buffer_id); |
+ if (cb_iter != client_buffers_.end()) { |
+ DCHECK(!cb_iter->second.get() || cb_iter->second->HasOneRef()) |
+ << "Instructed to delete buffer we are still using."; |
+ client_buffers_.erase(cb_iter); |
+ } else if (cgmb_iter != client_gmb_buffers_.end()) { |
+ DCHECK(!cgmb_iter->second.get() || cgmb_iter->second->HasOneRef()) |
+ << "Instructed to delete buffer we are still using."; |
+ client_gmb_buffers_.erase(cgmb_iter); |
+ } |
} |
void VideoCaptureImpl::OnBufferReceived( |
@@ -213,8 +296,9 @@ void VideoCaptureImpl::OnBufferReceived( |
media::VideoFrame::StorageType storage_type, |
const gfx::Size& coded_size, |
const gfx::Rect& visible_rect, |
- const gpu::MailboxHolder& mailbox_holder) { |
+ const std::vector<gpu::MailboxHolder>& mailbox_holders) { |
DCHECK(io_task_runner_->BelongsToCurrentThread()); |
+ DCHECK_EQ(media::PIXEL_FORMAT_I420, pixel_format); |
if (state_ != VIDEO_CAPTURE_STATE_STARTED) { |
Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0, -1.0)); |
return; |
@@ -230,46 +314,45 @@ void VideoCaptureImpl::OnBufferReceived( |
scoped_refptr<media::VideoFrame> frame; |
uint32* release_sync_point_storage = nullptr; |
- scoped_refptr<ClientBuffer> buffer; |
- |
- if (mailbox_holder.mailbox.IsZero()) { |
- DCHECK_EQ(media::PIXEL_FORMAT_I420, pixel_format); |
- const ClientBufferMap::const_iterator iter = |
- client_buffers_.find(buffer_id); |
+ if (mailbox_holders.empty()) { |
+ const auto& iter = client_buffers_.find(buffer_id); |
DCHECK(iter != client_buffers_.end()); |
- buffer = iter->second; |
+ const scoped_refptr<ClientBuffer> buffer = iter->second; |
frame = media::VideoFrame::WrapExternalSharedMemory( |
- pixel_format, |
- coded_size, |
- visible_rect, |
+ pixel_format, coded_size, visible_rect, |
gfx::Size(visible_rect.width(), visible_rect.height()), |
- reinterpret_cast<uint8*>(buffer->buffer->memory()), |
- buffer->buffer_size, |
- buffer->buffer->handle(), |
- 0 /* shared_memory_offset */, |
+ reinterpret_cast<uint8*>(buffer->buffer->memory()), buffer->buffer_size, |
+ buffer->buffer->handle(), 0 /* shared_memory_offset */, |
timestamp - first_frame_timestamp_); |
- |
- } else { |
- DCHECK_EQ(media::PIXEL_FORMAT_ARGB, pixel_format); |
- DCHECK(mailbox_holder.mailbox.Verify()); // Paranoia? |
- // To be deleted in DidFinishConsumingFrame(). |
+ frame->AddDestructionObserver( |
+ base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame, |
+ frame->metadata(), release_sync_point_storage, |
+ media::BindToCurrentLoop(base::Bind( |
+ &VideoCaptureImpl::OnClientBufferFinished, |
+ weak_factory_.GetWeakPtr(), buffer_id, buffer)))); |
+ } else if (storage_type == media::VideoFrame::STORAGE_OPAQUE) { |
+ for (const auto& mailbox_holder : mailbox_holders) |
+ DCHECK(mailbox_holder.mailbox.Verify()); // Paranoia? |
+ |
+ const auto& gmb_iter = client_gmb_buffers_.find(buffer_id); |
+ DCHECK(gmb_iter != client_gmb_buffers_.end()); |
+ const scoped_refptr<ClientGpuMemoryBuffer> gpu_memory_buffer = |
+ gmb_iter->second; |
release_sync_point_storage = new uint32(0); |
- frame = media::VideoFrame::WrapNativeTexture( |
- pixel_format, |
- mailbox_holder, |
+ frame = media::VideoFrame::WrapYUV420NativeTextures( |
+ mailbox_holders[media::VideoFrame::kYPlane], |
+ mailbox_holders[media::VideoFrame::kUPlane], |
+ mailbox_holders[media::VideoFrame::kVPlane], |
base::Bind(&SaveReleaseSyncPoint, release_sync_point_storage), |
- coded_size, |
- gfx::Rect(coded_size), |
- coded_size, |
+ coded_size, gfx::Rect(coded_size), coded_size, |
timestamp - first_frame_timestamp_); |
+ frame->AddDestructionObserver(base::Bind( |
+ &VideoCaptureImpl::DidFinishConsumingFrame, frame->metadata(), |
+ release_sync_point_storage, |
+ media::BindToCurrentLoop(base::Bind( |
+ &VideoCaptureImpl::OnClientGpuMemoryBufferFinished, |
+ weak_factory_.GetWeakPtr(), buffer_id, gpu_memory_buffer)))); |
} |
- frame->AddDestructionObserver( |
- base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame, frame->metadata(), |
- release_sync_point_storage, |
- media::BindToCurrentLoop(base::Bind( |
- &VideoCaptureImpl::OnClientBufferFinished, |
- weak_factory_.GetWeakPtr(), buffer_id, buffer)))); |
- |
frame->metadata()->MergeInternalValuesFrom(metadata); |
deliver_frame_cb_.Run(frame, timestamp); |
} |
@@ -284,6 +367,14 @@ void VideoCaptureImpl::OnClientBufferFinished( |
release_sync_point, |
consumer_resource_utilization)); |
} |
+void VideoCaptureImpl::OnClientGpuMemoryBufferFinished( |
+ int buffer_id, |
+ const scoped_refptr<ClientGpuMemoryBuffer>& gpu_memory_buffer, |
+ uint32 release_sync_point, |
+ double consumer_resource_utilization) { |
+ OnClientBufferFinished(buffer_id, scoped_refptr<ClientBuffer>(), |
+ release_sync_point, consumer_resource_utilization); |
+} |
void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) { |
// TODO(ajose): http://crbug.com/522155 improve this state machine. |
@@ -293,6 +384,7 @@ void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) { |
if (state == VIDEO_CAPTURE_STATE_STOPPED) { |
DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; |
client_buffers_.clear(); |
+ client_gmb_buffers_.clear(); |
weak_factory_.InvalidateWeakPtrs(); |
return; |
} |