dual_buffer_frame_consumer.cc 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/client/dual_buffer_frame_consumer.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/check.h"
  9. #include "base/location.h"
  10. #include "base/threading/thread_task_runner_handle.h"
  11. namespace remoting {
  12. namespace {
  13. // The implementation is mostly the same as webrtc::BasicDesktopFrame, except
  14. // that it has an extra padding of one row at the end of the buffer. This is
  15. // to workaround a bug in iOS' implementation of glTexSubimage2D that causes
  16. // occasional SIGSEGV.
  17. //
  18. // glTexSubimage2D is supposed to only read
  19. // kBytesPerPixel * width * (height - 1) bytes from the buffer but it seems to
  20. // be reading more than that, which may end up reading protected memory.
  21. //
  22. // See details in crbug.com/778550
  23. class PaddedDesktopFrame : public webrtc::DesktopFrame {
  24. public:
  25. explicit PaddedDesktopFrame(webrtc::DesktopSize size);
  26. PaddedDesktopFrame(const PaddedDesktopFrame&) = delete;
  27. PaddedDesktopFrame& operator=(const PaddedDesktopFrame&) = delete;
  28. ~PaddedDesktopFrame() override;
  29. // Creates a PaddedDesktopFrame that contains copy of |frame|.
  30. static std::unique_ptr<webrtc::DesktopFrame> CopyOf(
  31. const webrtc::DesktopFrame& frame);
  32. };
  33. PaddedDesktopFrame::PaddedDesktopFrame(webrtc::DesktopSize size)
  34. : DesktopFrame(
  35. size,
  36. kBytesPerPixel * size.width(),
  37. new uint8_t[kBytesPerPixel * size.width() * (size.height() + 1)],
  38. nullptr) {}
  39. PaddedDesktopFrame::~PaddedDesktopFrame() {
  40. delete[] data_;
  41. }
  42. // static
  43. std::unique_ptr<webrtc::DesktopFrame> PaddedDesktopFrame::CopyOf(
  44. const webrtc::DesktopFrame& frame) {
  45. std::unique_ptr<PaddedDesktopFrame> result =
  46. std::make_unique<PaddedDesktopFrame>(frame.size());
  47. for (int y = 0; y < frame.size().height(); ++y) {
  48. memcpy(result->data() + y * result->stride(),
  49. frame.data() + y * frame.stride(),
  50. frame.size().width() * kBytesPerPixel);
  51. }
  52. result->CopyFrameInfoFrom(frame);
  53. return result;
  54. }
  55. } // namespace
  56. DualBufferFrameConsumer::DualBufferFrameConsumer(
  57. RenderCallback callback,
  58. scoped_refptr<base::SingleThreadTaskRunner> task_runner,
  59. protocol::FrameConsumer::PixelFormat format)
  60. : callback_(std::move(callback)),
  61. task_runner_(task_runner),
  62. pixel_format_(format) {
  63. weak_ptr_ = weak_factory_.GetWeakPtr();
  64. thread_checker_.DetachFromThread();
  65. }
  66. DualBufferFrameConsumer::~DualBufferFrameConsumer() {
  67. DCHECK(thread_checker_.CalledOnValidThread());
  68. }
  69. void DualBufferFrameConsumer::RequestFullDesktopFrame() {
  70. DCHECK(thread_checker_.CalledOnValidThread());
  71. if (!buffers_[0]) {
  72. return;
  73. }
  74. DCHECK(buffers_[0]->size().equals(buffers_[1]->size()));
  75. // This creates a copy of buffers_[0] and merges area defined in
  76. // |buffer_1_mask_| from buffers_[1] into the copy.
  77. std::unique_ptr<webrtc::DesktopFrame> full_frame =
  78. PaddedDesktopFrame::CopyOf(*buffers_[0]);
  79. webrtc::DesktopRect desktop_rect =
  80. webrtc::DesktopRect::MakeSize(buffers_[0]->size());
  81. for (webrtc::DesktopRegion::Iterator i(buffer_1_mask_); !i.IsAtEnd();
  82. i.Advance()) {
  83. full_frame->CopyPixelsFrom(*buffers_[1], i.rect().top_left(),
  84. i.rect());
  85. }
  86. full_frame->mutable_updated_region()->SetRect(desktop_rect);
  87. RunRenderCallback(std::move(full_frame), base::DoNothing());
  88. }
  89. std::unique_ptr<webrtc::DesktopFrame> DualBufferFrameConsumer::AllocateFrame(
  90. const webrtc::DesktopSize& size) {
  91. DCHECK(thread_checker_.CalledOnValidThread());
  92. // Both buffers are reallocated whenever screen size changes.
  93. if (!buffers_[0] || !buffers_[0]->size().equals(size)) {
  94. buffers_[0] = webrtc::SharedDesktopFrame::Wrap(
  95. std::make_unique<PaddedDesktopFrame>(size));
  96. buffers_[1] = webrtc::SharedDesktopFrame::Wrap(
  97. std::make_unique<PaddedDesktopFrame>(size));
  98. buffer_1_mask_.Clear();
  99. current_buffer_ = 0;
  100. } else {
  101. current_buffer_ = (current_buffer_ + 1) % 2;
  102. }
  103. return buffers_[current_buffer_]->Share();
  104. }
  105. void DualBufferFrameConsumer::DrawFrame(
  106. std::unique_ptr<webrtc::DesktopFrame> frame,
  107. base::OnceClosure done) {
  108. DCHECK(thread_checker_.CalledOnValidThread());
  109. webrtc::SharedDesktopFrame* shared_frame =
  110. reinterpret_cast<webrtc::SharedDesktopFrame*> (frame.get());
  111. if (shared_frame->GetUnderlyingFrame() == buffers_[1]->GetUnderlyingFrame()) {
  112. buffer_1_mask_.AddRegion(frame->updated_region());
  113. } else if (shared_frame->GetUnderlyingFrame() ==
  114. buffers_[0]->GetUnderlyingFrame()) {
  115. buffer_1_mask_.Subtract(frame->updated_region());
  116. }
  117. RunRenderCallback(std::move(frame), std::move(done));
  118. }
  119. protocol::FrameConsumer::PixelFormat
  120. DualBufferFrameConsumer::GetPixelFormat() {
  121. return pixel_format_;
  122. }
  123. base::WeakPtr<DualBufferFrameConsumer> DualBufferFrameConsumer::GetWeakPtr() {
  124. return weak_ptr_;
  125. }
  126. void DualBufferFrameConsumer::RunRenderCallback(
  127. std::unique_ptr<webrtc::DesktopFrame> frame,
  128. base::OnceClosure done) {
  129. if (!task_runner_) {
  130. callback_.Run(std::move(frame), std::move(done));
  131. return;
  132. }
  133. task_runner_->PostTask(
  134. FROM_HERE,
  135. base::BindOnce(
  136. callback_, std::move(frame),
  137. base::BindOnce(base::IgnoreResult(&base::TaskRunner::PostTask),
  138. base::ThreadTaskRunnerHandle::Get(), FROM_HERE,
  139. std::move(done))));
  140. }
  141. } // namespace remoting