blob: 662e726411e8b1dcde14aa36ee6c0787c6331355 [file] [log] [blame]
// 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/logging.h"
#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
namespace remoting {
DualBufferFrameConsumer::DualBufferFrameConsumer(
const RenderCallback& 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()));
// This creates a copy of buffers_[0] and merges area defined in
// |buffer_1_mask_| from buffers_[1] into the copy.
std::unique_ptr<webrtc::DesktopFrame> full_frame(
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()) {
full_frame->CopyPixelsFrom(*buffers_[1], i.rect().top_left(),
i.rect());
}
full_frame->mutable_updated_region()->SetRect(desktop_rect);
RunRenderCallback(std::move(full_frame), base::Bind(&base::DoNothing));
}
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::MakeUnique<webrtc::BasicDesktopFrame>(size));
buffers_[1] = webrtc::SharedDesktopFrame::Wrap(
base::MakeUnique<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());
}
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), done);
return;
}
task_runner_->PostTask(
FROM_HERE, base::Bind(callback_, base::Passed(&frame), base::Bind(
base::IgnoreResult(&base::TaskRunner::PostTask),
base::ThreadTaskRunnerHandle::Get(), FROM_HERE, done)));
}
} // namespace remoting