Chromium Code Reviews| Index: remoting/client/dual_buffer_frame_consumer.cc |
| diff --git a/remoting/client/dual_buffer_frame_consumer.cc b/remoting/client/dual_buffer_frame_consumer.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3d2115806fb2aab3ba4a0fc8a4cc59bb70c37d33 |
| --- /dev/null |
| +++ b/remoting/client/dual_buffer_frame_consumer.cc |
| @@ -0,0 +1,127 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "remoting/client/dual_buffer_frame_consumer.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/bind_helpers.h" |
| +#include "base/location.h" |
| +#include "base/memory/ptr_util.h" |
| +#include "remoting/base/util.h" |
| +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| +#include "third_party/webrtc/modules/desktop_capture/shared_desktop_frame.h" |
| + |
| +namespace remoting { |
| + |
| +DualBufferFrameConsumer::DualBufferFrameConsumer( |
| + base::Callback<void(std::unique_ptr<webrtc::DesktopFrame>)> callback, |
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| + protocol::FrameConsumer::PixelFormat format) |
| + : callback_(callback), |
| + task_runner_(task_runner), |
| + pixel_format_(format), |
| + weak_factory_(this) { |
| + weak_ptr_ = weak_factory_.GetWeakPtr(); |
| + thread_checker_.DetachFromThread(); |
| +} |
| + |
| +DualBufferFrameConsumer::~DualBufferFrameConsumer() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| +} |
| + |
| +void DualBufferFrameConsumer::RequestFullDesktopFrame() { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + if (!buffers_[0]) { |
| + return; |
| + } |
| + DCHECK(buffers_[0]->size().equals(buffers_[1]->size())); |
| + std::unique_ptr<webrtc::DesktopFrame> full_frame( |
|
Sergey Ulanov
2016/07/21 19:14:25
Add some comments to explain what happens here.
Yuwei
2016/07/22 03:38:22
Done.
|
| + webrtc::BasicDesktopFrame::CopyOf(*buffers_[0])); |
| + webrtc::DesktopRect desktop_rect = |
| + webrtc::DesktopRect::MakeSize(buffers_[0]->size()); |
| + for (webrtc::DesktopRegion::Iterator i(buffer_1_mask_); !i.IsAtEnd(); |
| + i.Advance()) { |
| + CopyRGB32Rect(buffers_[0]->data(), buffers_[1]->stride(), desktop_rect, |
|
Sergey Ulanov
2016/07/21 19:14:26
Please use DesktopFrame::CopyPixelsFrom().
Yuwei
2016/07/22 03:38:22
Done.
|
| + full_frame->data(), full_frame->stride(), desktop_rect, |
| + i.rect()); |
| + } |
| + full_frame->mutable_updated_region()->SetRect(desktop_rect); |
| + |
| + RunRenderCallback(std::move(full_frame), base::Closure()); |
| +} |
| + |
| +std::unique_ptr<webrtc::DesktopFrame> DualBufferFrameConsumer::AllocateFrame( |
| + const webrtc::DesktopSize& size) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + // Both buffers are reallocated whenever screen size changes. |
| + if (!buffers_[0] || !buffers_[0]->size().equals(size)) { |
| + buffers_[0] = webrtc::SharedDesktopFrame::Wrap( |
| + base::WrapUnique(new webrtc::BasicDesktopFrame(size))); |
| + buffers_[1] = webrtc::SharedDesktopFrame::Wrap( |
| + base::WrapUnique(new webrtc::BasicDesktopFrame(size))); |
| + buffer_1_mask_.Clear(); |
| + current_buffer_ = 0; |
| + } else { |
| + current_buffer_ = (current_buffer_ + 1) % 2; |
| + } |
| + return buffers_[current_buffer_]->Share(); |
| +} |
| + |
| +void DualBufferFrameConsumer::DrawFrame( |
| + std::unique_ptr<webrtc::DesktopFrame> frame, |
| + const base::Closure& done) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + webrtc::SharedDesktopFrame* shared_frame = |
| + reinterpret_cast<webrtc::SharedDesktopFrame*> (frame.get()); |
| + if (shared_frame->GetUnderlyingFrame() == buffers_[1]->GetUnderlyingFrame()) { |
| + buffer_1_mask_.AddRegion(frame->updated_region()); |
| + } else if (shared_frame->GetUnderlyingFrame() == |
| + buffers_[0]->GetUnderlyingFrame()) { |
| + buffer_1_mask_.Subtract(frame->updated_region()); |
| + } else { |
| + // This may happen if the resolution is changed but a previous shared frame |
|
Sergey Ulanov
2016/07/21 19:14:25
Currently SoftwareVideoRenderer never processes mo
Yuwei
2016/07/22 03:38:22
Removed the else branch.
The problem is that Soft
Sergey Ulanov
2016/07/22 18:04:19
Ugh. I was wrong when I wrote that SoftwareVideoRe
Yuwei
2016/07/22 18:35:15
I think the fact is that multiple frames can be pr
|
| + // with different resolution is received. In this case it is save to ignore |
| + // the frame since a new full desktop frame will be received soon. |
| + if (done) { |
| + done.Run(); |
| + } |
| + return; |
| + } |
| + RunRenderCallback(std::move(frame), done); |
| +} |
| + |
| +protocol::FrameConsumer::PixelFormat |
| +DualBufferFrameConsumer::GetPixelFormat() { |
| + return pixel_format_; |
| +} |
| + |
| +base::WeakPtr<DualBufferFrameConsumer> DualBufferFrameConsumer::GetWeakPtr() { |
| + return weak_ptr_; |
| +} |
| + |
| +void DualBufferFrameConsumer::RunRenderCallback( |
| + std::unique_ptr<webrtc::DesktopFrame> frame, |
| + const base::Closure& done) { |
| + if (!task_runner_) { |
| + callback_.Run(std::move(frame)); |
| + if (done) { |
|
Sergey Ulanov
2016/07/21 19:14:26
I don't think you need this check. DrawFrame() sho
Yuwei
2016/07/22 03:38:22
Done. Removed.
|
| + done.Run(); |
|
Sergey Ulanov
2016/07/21 19:14:26
We cannot assume that the frame have been rendered
Yuwei
2016/07/21 20:00:41
I guess the measurement will be messed up if anoth
Sergey Ulanov
2016/07/21 20:22:48
To make it work correctly the renderer will need t
Yuwei
2016/07/22 03:38:22
Done.
|
| + } |
| + return; |
| + } |
| + task_runner_->PostTaskAndReply( |
| + FROM_HERE, base::Bind(callback_, base::Passed(&frame)), |
| + base::Bind(&DualBufferFrameConsumer::OnFrameRendered, GetWeakPtr(), |
| + done)); |
| +} |
| + |
| +void DualBufferFrameConsumer::OnFrameRendered(const base::Closure& done) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + if (done) { |
| + done.Run(); |
| + } |
| +} |
| + |
| +} // namespace remoting |