123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- // 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 <memory>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/check.h"
- #include "base/location.h"
- #include "base/threading/thread_task_runner_handle.h"
- namespace remoting {
- namespace {
- // The implementation is mostly the same as webrtc::BasicDesktopFrame, except
- // that it has an extra padding of one row at the end of the buffer. This is
- // to workaround a bug in iOS' implementation of glTexSubimage2D that causes
- // occasional SIGSEGV.
- //
- // glTexSubimage2D is supposed to only read
- // kBytesPerPixel * width * (height - 1) bytes from the buffer but it seems to
- // be reading more than that, which may end up reading protected memory.
- //
- // See details in crbug.com/778550
- class PaddedDesktopFrame : public webrtc::DesktopFrame {
- public:
- explicit PaddedDesktopFrame(webrtc::DesktopSize size);
- PaddedDesktopFrame(const PaddedDesktopFrame&) = delete;
- PaddedDesktopFrame& operator=(const PaddedDesktopFrame&) = delete;
- ~PaddedDesktopFrame() override;
- // Creates a PaddedDesktopFrame that contains copy of |frame|.
- static std::unique_ptr<webrtc::DesktopFrame> CopyOf(
- const webrtc::DesktopFrame& frame);
- };
- PaddedDesktopFrame::PaddedDesktopFrame(webrtc::DesktopSize size)
- : DesktopFrame(
- size,
- kBytesPerPixel * size.width(),
- new uint8_t[kBytesPerPixel * size.width() * (size.height() + 1)],
- nullptr) {}
- PaddedDesktopFrame::~PaddedDesktopFrame() {
- delete[] data_;
- }
- // static
- std::unique_ptr<webrtc::DesktopFrame> PaddedDesktopFrame::CopyOf(
- const webrtc::DesktopFrame& frame) {
- std::unique_ptr<PaddedDesktopFrame> result =
- std::make_unique<PaddedDesktopFrame>(frame.size());
- for (int y = 0; y < frame.size().height(); ++y) {
- memcpy(result->data() + y * result->stride(),
- frame.data() + y * frame.stride(),
- frame.size().width() * kBytesPerPixel);
- }
- result->CopyFrameInfoFrom(frame);
- return result;
- }
- } // namespace
- DualBufferFrameConsumer::DualBufferFrameConsumer(
- RenderCallback callback,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- protocol::FrameConsumer::PixelFormat format)
- : callback_(std::move(callback)),
- task_runner_(task_runner),
- pixel_format_(format) {
- 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 =
- PaddedDesktopFrame::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::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(
- std::make_unique<PaddedDesktopFrame>(size));
- buffers_[1] = webrtc::SharedDesktopFrame::Wrap(
- std::make_unique<PaddedDesktopFrame>(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,
- base::OnceClosure 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), std::move(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,
- base::OnceClosure done) {
- if (!task_runner_) {
- callback_.Run(std::move(frame), std::move(done));
- return;
- }
- task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- callback_, std::move(frame),
- base::BindOnce(base::IgnoreResult(&base::TaskRunner::PostTask),
- base::ThreadTaskRunnerHandle::Get(), FROM_HERE,
- std::move(done))));
- }
- } // namespace remoting
|