summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-16 10:45:24 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-16 10:45:24 +0000
commitb9ed58f046141b4610c1bdc966d962d5fb95ac6b (patch)
treeb7dc10e49ea765b6ebc99985d3538a2e1363942e /remoting
parentc1c88cf23606dd1ca2bfd9f57496aeec847e713f (diff)
downloadchromium_src-b9ed58f046141b4610c1bdc966d962d5fb95ac6b.zip
chromium_src-b9ed58f046141b4610c1bdc966d962d5fb95ac6b.tar.gz
chromium_src-b9ed58f046141b4610c1bdc966d962d5fb95ac6b.tar.bz2
Use webrtc::DesktopCapturer for screen capturer implementation.
Screen capturers are being moved from media/video/capture/screen to third_party/webrtc. This CL is an intermediate step in that process. Depends on https://webrtc-codereview.appspot.com/1322007/ TBR=brettw@chromium.org (third_party/webrtc dependency) Review URL: https://chromiumcodereview.appspot.com/13983010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@200504 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/codec/DEPS1
-rw-r--r--remoting/codec/codec_test.cc237
-rw-r--r--remoting/codec/codec_test.h10
-rw-r--r--remoting/codec/video_decoder_vp8_unittest.cc10
-rw-r--r--remoting/codec/video_encoder.h27
-rw-r--r--remoting/codec/video_encoder_verbatim.cc65
-rw-r--r--remoting/codec/video_encoder_verbatim.h16
-rw-r--r--remoting/codec/video_encoder_vp8.cc53
-rw-r--r--remoting/codec/video_encoder_vp8.h14
-rw-r--r--remoting/codec/video_encoder_vp8_unittest.cc35
-rw-r--r--remoting/host/DEPS1
-rw-r--r--remoting/host/chromoting_messages.h49
-rw-r--r--remoting/host/chromoting_param_traits.cc127
-rw-r--r--remoting/host/chromoting_param_traits.h49
-rw-r--r--remoting/host/client_session.cc14
-rw-r--r--remoting/host/client_session_unittest.cc1
-rw-r--r--remoting/host/daemon_process.cc15
-rw-r--r--remoting/host/desktop_session_agent.cc150
-rw-r--r--remoting/host/desktop_session_agent.h42
-rw-r--r--remoting/host/desktop_session_proxy.cc152
-rw-r--r--remoting/host/desktop_session_proxy.h20
-rw-r--r--remoting/host/desktop_session_win.cc16
-rw-r--r--remoting/host/ipc_desktop_environment_unittest.cc18
-rw-r--r--remoting/host/ipc_video_frame_capturer.cc34
-rw-r--r--remoting/host/ipc_video_frame_capturer.h22
-rw-r--r--remoting/host/resizing_host_observer.cc12
-rw-r--r--remoting/host/resizing_host_observer_unittest.cc4
-rw-r--r--remoting/host/screen_resolution.cc25
-rw-r--r--remoting/host/screen_resolution.h28
-rw-r--r--remoting/host/screen_resolution_unittest.cc69
-rw-r--r--remoting/host/video_scheduler.cc95
-rw-r--r--remoting/host/video_scheduler.h34
-rw-r--r--remoting/host/video_scheduler_unittest.cc53
-rw-r--r--remoting/remoting.gyp8
34 files changed, 863 insertions, 643 deletions
diff --git a/remoting/codec/DEPS b/remoting/codec/DEPS
index 61e5c26..913ea7d 100644
--- a/remoting/codec/DEPS
+++ b/remoting/codec/DEPS
@@ -5,4 +5,5 @@ include_rules = [
"+google/protobuf",
"+third_party/opus",
"+third_party/speex",
+ "+third_party/webrtc",
]
diff --git a/remoting/codec/codec_test.cc b/remoting/codec/codec_test.cc
index af8b11b..efcc872 100644
--- a/remoting/codec/codec_test.cc
+++ b/remoting/codec/codec_test.cc
@@ -14,27 +14,33 @@
#include "remoting/codec/video_encoder.h"
#include "remoting/base/util.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
+
+using webrtc::DesktopRect;
+using webrtc::DesktopSize;
namespace {
const int kBytesPerPixel = 4;
// Some sample rects for testing.
-std::vector<std::vector<SkIRect> > MakeTestRectLists(const SkISize& size) {
- std::vector<std::vector<SkIRect> > rect_lists;
- std::vector<SkIRect> rects;
- rects.push_back(SkIRect::MakeXYWH(0, 0, size.width(), size.height()));
+std::vector<std::vector<DesktopRect> > MakeTestRectLists(DesktopSize size) {
+ std::vector<std::vector<DesktopRect> > rect_lists;
+ std::vector<DesktopRect> rects;
+ rects.push_back(DesktopRect::MakeXYWH(0, 0, size.width(), size.height()));
rect_lists.push_back(rects);
rects.clear();
- rects.push_back(SkIRect::MakeXYWH(0, 0, size.width() / 2, size.height() / 2));
+ rects.push_back(DesktopRect::MakeXYWH(
+ 0, 0, size.width() / 2, size.height() / 2));
rect_lists.push_back(rects);
rects.clear();
- rects.push_back(SkIRect::MakeXYWH(size.width() / 2, size.height() / 2,
- size.width() / 2, size.height() / 2));
+ rects.push_back(DesktopRect::MakeXYWH(
+ size.width() / 2, size.height() / 2,
+ size.width() / 2, size.height() / 2));
rect_lists.push_back(rects);
rects.clear();
- rects.push_back(SkIRect::MakeXYWH(16, 16, 16, 16));
- rects.push_back(SkIRect::MakeXYWH(128, 64, 32, 32));
+ rects.push_back(DesktopRect::MakeXYWH(16, 16, 16, 16));
+ rects.push_back(DesktopRect::MakeXYWH(128, 64, 32, 32));
rect_lists.push_back(rects);
return rect_lists;
}
@@ -72,10 +78,10 @@ class VideoEncoderMessageTester {
++begin_rect_;
if (strict_) {
- SkIRect rect = rects_.front();
+ DesktopRect rect = rects_.front();
rects_.pop_front();
- EXPECT_EQ(rect.fLeft, packet->format().x());
- EXPECT_EQ(rect.fTop, packet->format().y());
+ EXPECT_EQ(rect.left(), packet->format().x());
+ EXPECT_EQ(rect.top(), packet->format().y());
EXPECT_EQ(rect.width(), packet->format().width());
EXPECT_EQ(rect.height(), packet->format().height());
}
@@ -107,7 +113,7 @@ class VideoEncoderMessageTester {
strict_ = strict;
}
- void AddRects(const SkIRect* rects, int count) {
+ void AddRects(const DesktopRect* rects, int count) {
rects_.insert(rects_.begin() + rects_.size(), rects, rects + count);
added_rects_ += count;
}
@@ -125,15 +131,16 @@ class VideoEncoderMessageTester {
State state_;
bool strict_;
- std::deque<SkIRect> rects_;
+ std::deque<DesktopRect> rects_;
DISALLOW_COPY_AND_ASSIGN(VideoEncoderMessageTester);
};
class VideoDecoderTester {
public:
- VideoDecoderTester(VideoDecoder* decoder, const SkISize& screen_size,
- const SkISize& view_size)
+ VideoDecoderTester(VideoDecoder* decoder,
+ const DesktopSize& screen_size,
+ const DesktopSize& view_size)
: screen_size_(screen_size),
view_size_(view_size),
strict_(false),
@@ -141,11 +148,12 @@ class VideoDecoderTester {
image_data_.reset(new uint8[
view_size_.width() * view_size_.height() * kBytesPerPixel]);
EXPECT_TRUE(image_data_.get());
- decoder_->Initialize(screen_size_);
+ decoder_->Initialize(
+ SkISize::Make(screen_size_.width(), screen_size_.height()));
}
void Reset() {
- expected_region_.setEmpty();
+ expected_region_.Clear();
update_region_.setEmpty();
}
@@ -165,11 +173,12 @@ class VideoDecoderTester {
}
void RenderFrame() {
- decoder_->RenderFrame(view_size_,
- SkIRect::MakeSize(view_size_),
- image_data_.get(),
- view_size_.width() * kBytesPerPixel,
- &update_region_);
+ decoder_->RenderFrame(
+ SkISize::Make(view_size_.width(), view_size_.height()),
+ SkIRect::MakeWH(view_size_.width(), view_size_.height()),
+ image_data_.get(),
+ view_size_.width() * kBytesPerPixel,
+ &update_region_);
}
void ReceivedScopedPacket(scoped_ptr<VideoPacket> packet) {
@@ -180,34 +189,46 @@ class VideoDecoderTester {
strict_ = strict;
}
- void set_capture_data(scoped_refptr<media::ScreenCaptureData> data) {
- capture_data_ = data;
+ void set_frame(webrtc::DesktopFrame* frame) {
+ frame_ = frame;
}
- void AddRects(const SkIRect* rects, int count) {
- SkRegion new_rects;
- new_rects.setRects(rects, count);
- AddRegion(new_rects);
+ void AddRects(const DesktopRect* rects, int count) {
+ for (int i = 0; i < count; ++i) {
+ expected_region_.AddRect(rects[i]);
+ }
}
- void AddRegion(const SkRegion& region) {
- expected_region_.op(region, SkRegion::kUnion_Op);
+ void AddRegion(const webrtc::DesktopRegion& region) {
+ expected_region_.AddRegion(region);
}
void VerifyResults() {
if (!strict_)
return;
- ASSERT_TRUE(capture_data_.get());
+ ASSERT_TRUE(frame_);
// Test the content of the update region.
- EXPECT_EQ(expected_region_, update_region_);
+ //
+ // TODO(sergeyu): Change this to use DesktopRegion when it's capable of
+ // merging the rectangles.
+ SkRegion expected_region;
+ for (webrtc::DesktopRegion::Iterator it(expected_region_);
+ !it.IsAtEnd(); it.Advance()) {
+ expected_region.op(
+ SkIRect::MakeXYWH(it.rect().top(), it.rect().left(),
+ it.rect().width(), it.rect().height()),
+ SkRegion::kUnion_Op);
+ }
+ EXPECT_EQ(expected_region, update_region_);
+
for (SkRegion::Iterator i(update_region_); !i.done(); i.next()) {
const int stride = view_size_.width() * kBytesPerPixel;
- EXPECT_EQ(stride, capture_data_->stride());
+ EXPECT_EQ(stride, frame_->stride());
const int offset = stride * i.rect().top() +
kBytesPerPixel * i.rect().left();
- const uint8* original = capture_data_->data() + offset;
+ const uint8* original = frame_->data() + offset;
const uint8* decoded = image_data_.get() + offset;
const int row_size = kBytesPerPixel * i.rect().width();
for (int y = 0; y < i.rect().height(); ++y) {
@@ -265,14 +286,14 @@ class VideoDecoderTester {
}
private:
- SkISize screen_size_;
- SkISize view_size_;
+ DesktopSize screen_size_;
+ DesktopSize view_size_;
bool strict_;
- SkRegion expected_region_;
+ webrtc::DesktopRegion expected_region_;
SkRegion update_region_;
VideoDecoder* decoder_;
scoped_ptr<uint8[]> image_data_;
- scoped_refptr<media::ScreenCaptureData> capture_data_;
+ webrtc::DesktopFrame* frame_;
DISALLOW_COPY_AND_ASSIGN(VideoDecoderTester);
};
@@ -301,7 +322,7 @@ class VideoEncoderTester {
}
}
- void AddRects(const SkIRect* rects, int count) {
+ void AddRects(const DesktopRect* rects, int count) {
message_tester_->AddRects(rects, count);
}
@@ -317,34 +338,30 @@ class VideoEncoderTester {
DISALLOW_COPY_AND_ASSIGN(VideoEncoderTester);
};
-scoped_refptr<media::ScreenCaptureData> PrepareEncodeData(
- const SkISize& size,
- scoped_ptr<uint8[]>* memory) {
- int memory_size = size.width() * size.height() * kBytesPerPixel;
-
- memory->reset(new uint8[memory_size]);
+scoped_ptr<webrtc::DesktopFrame> PrepareFrame(const DesktopSize& size) {
+ scoped_ptr<webrtc::DesktopFrame> frame(new webrtc::BasicDesktopFrame(size));
srand(0);
+ int memory_size = size.width() * size.height() * kBytesPerPixel;
for (int i = 0; i < memory_size; ++i) {
- (*memory)[i] = rand() % 256;
+ frame->data()[i] = rand() % 256;
}
- scoped_refptr<media::ScreenCaptureData> data = new media::ScreenCaptureData(
- memory->get(), size.width() * kBytesPerPixel, size);
- return data;
+ return frame.Pass();
}
static void TestEncodingRects(VideoEncoder* encoder,
VideoEncoderTester* tester,
- scoped_refptr<media::ScreenCaptureData> data,
- const SkIRect* rects, int count) {
- data->mutable_dirty_region().setEmpty();
+ webrtc::DesktopFrame* frame,
+ const DesktopRect* rects,
+ int count) {
+ frame->mutable_updated_region()->Clear();
for (int i = 0; i < count; ++i) {
- data->mutable_dirty_region().op(rects[i], SkRegion::kUnion_Op);
+ frame->mutable_updated_region()->AddRect(rects[i]);
}
tester->AddRects(rects, count);
- encoder->Encode(data, true, base::Bind(
+ encoder->Encode(frame, base::Bind(
&VideoEncoderTester::DataAvailable, base::Unretained(tester)));
}
@@ -356,18 +373,15 @@ void TestVideoEncoder(VideoEncoder* encoder, bool strict) {
VideoEncoderTester tester(&message_tester);
- scoped_ptr<uint8[]> memory;
-
for (size_t xi = 0; xi < arraysize(kSizes); ++xi) {
for (size_t yi = 0; yi < arraysize(kSizes); ++yi) {
- SkISize size = SkISize::Make(kSizes[xi], kSizes[yi]);
- scoped_refptr<media::ScreenCaptureData> data =
- PrepareEncodeData(size, &memory);
- std::vector<std::vector<SkIRect> > test_rect_lists =
+ DesktopSize size = DesktopSize(kSizes[xi], kSizes[yi]);
+ scoped_ptr<webrtc::DesktopFrame> frame = PrepareFrame(size);
+ std::vector<std::vector<DesktopRect> > test_rect_lists =
MakeTestRectLists(size);
for (size_t i = 0; i < test_rect_lists.size(); ++i) {
- const std::vector<SkIRect>& test_rects = test_rect_lists[i];
- TestEncodingRects(encoder, &tester, data,
+ const std::vector<DesktopRect>& test_rects = test_rect_lists[i];
+ TestEncodingRects(encoder, &tester, frame.get(),
&test_rects[0], test_rects.size());
}
}
@@ -377,68 +391,69 @@ void TestVideoEncoder(VideoEncoder* encoder, bool strict) {
static void TestEncodeDecodeRects(VideoEncoder* encoder,
VideoEncoderTester* encoder_tester,
VideoDecoderTester* decoder_tester,
- scoped_refptr<media::ScreenCaptureData> data,
- const SkIRect* rects, int count) {
- data->mutable_dirty_region().setRects(rects, count);
+ webrtc::DesktopFrame* frame,
+ const DesktopRect* rects, int count) {
+ frame->mutable_updated_region()->Clear();
+ for (int i = 0; i < count; ++i) {
+ frame->mutable_updated_region()->AddRect(rects[i]);
+ }
encoder_tester->AddRects(rects, count);
decoder_tester->AddRects(rects, count);
// Generate random data for the updated region.
srand(0);
for (int i = 0; i < count; ++i) {
- const int bytes_per_pixel = 4; // Because of RGB32 on previous line.
- const int row_size = bytes_per_pixel * rects[i].width();
- uint8* memory = data->data() +
- data->stride() * rects[i].top() +
- bytes_per_pixel * rects[i].left();
+ const int row_size =
+ webrtc::DesktopFrame::kBytesPerPixel * rects[i].width();
+ uint8* memory = frame->data() +
+ frame->stride() * rects[i].top() +
+ webrtc::DesktopFrame::kBytesPerPixel * rects[i].left();
for (int y = 0; y < rects[i].height(); ++y) {
for (int x = 0; x < row_size; ++x)
memory[x] = rand() % 256;
- memory += data->stride();
+ memory += frame->stride();
}
}
- encoder->Encode(data, true, base::Bind(&VideoEncoderTester::DataAvailable,
- base::Unretained(encoder_tester)));
+ encoder->Encode(frame, base::Bind(&VideoEncoderTester::DataAvailable,
+ base::Unretained(encoder_tester)));
decoder_tester->VerifyResults();
decoder_tester->Reset();
}
void TestVideoEncoderDecoder(
VideoEncoder* encoder, VideoDecoder* decoder, bool strict) {
- SkISize kSize = SkISize::Make(320, 240);
+ DesktopSize kSize = DesktopSize(320, 240);
VideoEncoderMessageTester message_tester;
message_tester.set_strict(strict);
VideoEncoderTester encoder_tester(&message_tester);
- scoped_ptr<uint8[]> memory;
- scoped_refptr<media::ScreenCaptureData> data =
- PrepareEncodeData(kSize, &memory);
+ scoped_ptr<webrtc::DesktopFrame> frame = PrepareFrame(kSize);
VideoDecoderTester decoder_tester(decoder, kSize, kSize);
decoder_tester.set_strict(strict);
- decoder_tester.set_capture_data(data);
+ decoder_tester.set_frame(frame.get());
encoder_tester.set_decoder_tester(&decoder_tester);
- std::vector<std::vector<SkIRect> > test_rect_lists = MakeTestRectLists(kSize);
+ std::vector<std::vector<DesktopRect> > test_rect_lists =
+ MakeTestRectLists(kSize);
for (size_t i = 0; i < test_rect_lists.size(); ++i) {
- const std::vector<SkIRect> test_rects = test_rect_lists[i];
- TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester, data,
- &test_rects[0], test_rects.size());
+ const std::vector<DesktopRect> test_rects = test_rect_lists[i];
+ TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester,
+ frame.get(), &test_rects[0], test_rects.size());
}
}
-static void FillWithGradient(uint8* memory, const SkISize& frame_size,
- const SkIRect& rect) {
- for (int j = rect.top(); j < rect.bottom(); ++j) {
- uint8* p = memory + ((j * frame_size.width()) + rect.left()) * 4;
- for (int i = rect.left(); i < rect.right(); ++i) {
- *p++ = static_cast<uint8>((255.0 * i) / frame_size.width());
- *p++ = static_cast<uint8>((164.0 * j) / frame_size.height());
- *p++ = static_cast<uint8>((82.0 * (i + j)) /
- (frame_size.width() + frame_size.height()));
+static void FillWithGradient(webrtc::DesktopFrame* frame) {
+ for (int j = 0; j < frame->size().height(); ++j) {
+ uint8* p = frame->data() + j * frame->stride();
+ for (int i = 0; i < frame->size().width(); ++i) {
+ *p++ = (255.0 * i) / frame->size().width();
+ *p++ = (164.0 * j) / frame->size().height();
+ *p++ = (82.0 * (i + j)) /
+ (frame->size().width() + frame->size().height());
*p++ = 0;
}
}
@@ -446,42 +461,38 @@ static void FillWithGradient(uint8* memory, const SkISize& frame_size,
void TestVideoEncoderDecoderGradient(VideoEncoder* encoder,
VideoDecoder* decoder,
- const SkISize& screen_size,
- const SkISize& view_size,
+ const DesktopSize& screen_size,
+ const DesktopSize& view_size,
double max_error_limit,
double mean_error_limit) {
- SkIRect screen_rect = SkIRect::MakeSize(screen_size);
- scoped_ptr<uint8[]> screen_data(new uint8[
- screen_size.width() * screen_size.height() * kBytesPerPixel]);
- FillWithGradient(screen_data.get(), screen_size, screen_rect);
-
- SkIRect view_rect = SkIRect::MakeSize(view_size);
- scoped_ptr<uint8[]> expected_view_data(new uint8[
- view_size.width() * view_size.height() * kBytesPerPixel]);
- FillWithGradient(expected_view_data.get(), view_size, view_rect);
+ scoped_ptr<webrtc::BasicDesktopFrame> frame(
+ new webrtc::BasicDesktopFrame(screen_size));
+ FillWithGradient(frame.get());
+ frame->mutable_updated_region()->SetRect(DesktopRect::MakeSize(screen_size));
- scoped_refptr<media::ScreenCaptureData> capture_data =
- new media::ScreenCaptureData(
- screen_data.get(), screen_size.width() * kBytesPerPixel, screen_size);
- capture_data->mutable_dirty_region().op(screen_rect, SkRegion::kUnion_Op);
+ scoped_ptr<webrtc::BasicDesktopFrame> expected_result(
+ new webrtc::BasicDesktopFrame(view_size));
+ FillWithGradient(expected_result.get());
VideoDecoderTester decoder_tester(decoder, screen_size, view_size);
- decoder_tester.set_capture_data(capture_data);
- decoder_tester.AddRegion(capture_data->dirty_region());
+ decoder_tester.set_frame(frame.get());
+ decoder_tester.AddRegion(frame->updated_region());
- encoder->Encode(capture_data, true,
+ encoder->Encode(frame.get(),
base::Bind(&VideoDecoderTester::ReceivedScopedPacket,
base::Unretained(&decoder_tester)));
- decoder_tester.VerifyResultsApprox(expected_view_data.get(),
+ decoder_tester.VerifyResultsApprox(expected_result->data(),
max_error_limit, mean_error_limit);
// Check that the decoder correctly re-renders the frame if its client
// invalidates the frame.
decoder_tester.ResetRenderedData();
- decoder->Invalidate(view_size, SkRegion(view_rect));
+ decoder->Invalidate(
+ SkISize::Make(view_size.width(), view_size.height()),
+ SkRegion(SkIRect::MakeWH(view_size.width(), view_size.height())));
decoder_tester.RenderFrame();
- decoder_tester.VerifyResultsApprox(expected_view_data.get(),
+ decoder_tester.VerifyResultsApprox(expected_result->data(),
max_error_limit, mean_error_limit);
}
diff --git a/remoting/codec/codec_test.h b/remoting/codec/codec_test.h
index d2bda83..e7e055f 100644
--- a/remoting/codec/codec_test.h
+++ b/remoting/codec/codec_test.h
@@ -6,8 +6,10 @@
#define REMOTING_CODEC_CODEC_TEST_H_
#include "base/memory/ref_counted.h"
-#include "media/base/video_frame.h"
-#include "media/video/capture/screen/screen_capture_data.h"
+
+namespace webrtc {
+class DesktopSize;
+}
namespace remoting {
@@ -33,8 +35,8 @@ void TestVideoEncoderDecoder(VideoEncoder* encoder,
// pair.
void TestVideoEncoderDecoderGradient(VideoEncoder* encoder,
VideoDecoder* decoder,
- const SkISize& screen_size,
- const SkISize& view_size,
+ const webrtc::DesktopSize& screen_size,
+ const webrtc::DesktopSize& view_size,
double max_error_limit,
double mean_error_limit);
diff --git a/remoting/codec/video_decoder_vp8_unittest.cc b/remoting/codec/video_decoder_vp8_unittest.cc
index d8d36f0..64d30df 100644
--- a/remoting/codec/video_decoder_vp8_unittest.cc
+++ b/remoting/codec/video_decoder_vp8_unittest.cc
@@ -8,6 +8,7 @@
#include "remoting/codec/codec_test.h"
#include "remoting/codec/video_encoder_vp8.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
namespace remoting {
@@ -19,10 +20,11 @@ class VideoDecoderVp8Test : public testing::Test {
void TestGradient(int screen_width, int screen_height,
int view_width, int view_height,
double max_error_limit, double mean_error_limit) {
- TestVideoEncoderDecoderGradient(&encoder_, &decoder_,
- SkISize::Make(screen_width, screen_height),
- SkISize::Make(view_width, view_height),
- max_error_limit, mean_error_limit);
+ TestVideoEncoderDecoderGradient(
+ &encoder_, &decoder_,
+ webrtc::DesktopSize(screen_width, screen_height),
+ webrtc::DesktopSize(view_width, view_height),
+ max_error_limit, mean_error_limit);
}
};
diff --git a/remoting/codec/video_encoder.h b/remoting/codec/video_encoder.h
index 81179c4..a89e1e7 100644
--- a/remoting/codec/video_encoder.h
+++ b/remoting/codec/video_encoder.h
@@ -7,19 +7,19 @@
#include "base/basictypes.h"
#include "base/callback.h"
-#include "media/base/data_buffer.h"
-namespace media {
-class ScreenCaptureData;
-} // namespace media
+class SkRegion;
+
+namespace webrtc {
+class DesktopFrame;
+} // namespace webrtc
namespace remoting {
class VideoPacket;
-// A class to perform the task of encoding a continous stream of
-// images.
-// This class operates asynchronously to enable maximum throughput.
+// A class to perform the task of encoding a continuous stream of images. The
+// interface is asynchronous to enable maximum throughput.
class VideoEncoder {
public:
@@ -29,15 +29,10 @@ class VideoEncoder {
virtual ~VideoEncoder() {}
- // Encode an image stored in |capture_data|.
- //
- // If |key_frame| is true, the encoder should not reference
- // previous encode and encode the full frame.
- //
- // When encoded data is available, partial or full |data_available_callback|
- // is called.
- virtual void Encode(scoped_refptr<media::ScreenCaptureData> capture_data,
- bool key_frame,
+ // Encode an image stored in |frame|. Doesn't take ownership of |frame|. When
+ // encoded data is available, partial or full |data_available_callback| is
+ // called.
+ virtual void Encode(const webrtc::DesktopFrame* frame,
const DataAvailableCallback& data_available_callback) = 0;
};
diff --git a/remoting/codec/video_encoder_verbatim.cc b/remoting/codec/video_encoder_verbatim.cc
index 2e7f6d0..4680362 100644
--- a/remoting/codec/video_encoder_verbatim.cc
+++ b/remoting/codec/video_encoder_verbatim.cc
@@ -5,17 +5,17 @@
#include "remoting/codec/video_encoder_verbatim.h"
#include "base/logging.h"
-#include "media/video/capture/screen/screen_capture_data.h"
+#include "base/stl_util.h"
#include "remoting/base/util.h"
#include "remoting/proto/video.pb.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
namespace remoting {
static const int kPacketSize = 1024 * 1024;
VideoEncoderVerbatim::VideoEncoderVerbatim()
- : screen_size_(SkISize::Make(0,0)),
- max_packet_size_(kPacketSize) {
+ : max_packet_size_(kPacketSize) {
}
void VideoEncoderVerbatim::SetMaxPacketSize(int size) {
@@ -26,35 +26,33 @@ VideoEncoderVerbatim::~VideoEncoderVerbatim() {
}
void VideoEncoderVerbatim::Encode(
- scoped_refptr<media::ScreenCaptureData> capture_data,
- bool key_frame,
+ const webrtc::DesktopFrame* frame,
const DataAvailableCallback& data_available_callback) {
- capture_data_ = capture_data;
callback_ = data_available_callback;
encode_start_time_ = base::Time::Now();
- const SkRegion& region = capture_data->dirty_region();
- SkRegion::Iterator iter(region);
- while (!iter.done()) {
- SkIRect rect = iter.rect();
- iter.next();
- EncodeRect(rect, iter.done());
+ webrtc::DesktopRegion::Iterator iter(frame->updated_region());
+ while (!iter.IsAtEnd()) {
+ const webrtc::DesktopRect& rect = iter.rect();
+ iter.Advance();
+ EncodeRect(frame, rect, iter.IsAtEnd());
}
- capture_data_ = NULL;
callback_.Reset();
}
-void VideoEncoderVerbatim::EncodeRect(const SkIRect& rect, bool last) {
- CHECK(capture_data_->data());
- const int stride = capture_data_->stride();
+void VideoEncoderVerbatim::EncodeRect(const webrtc::DesktopFrame* frame,
+ const webrtc::DesktopRect& rect,
+ bool last) {
+ CHECK(frame->data());
+ const int stride = frame->stride();
const int bytes_per_pixel = 4;
const int row_size = bytes_per_pixel * rect.width();
scoped_ptr<VideoPacket> packet(new VideoPacket());
- PrepareUpdateStart(rect, packet.get());
- const uint8* in = capture_data_->data() +
- rect.fTop * stride + rect.fLeft * bytes_per_pixel;
+ PrepareUpdateStart(frame, rect, packet.get());
+ const uint8* in = frame->data() +
+ rect.top() * stride + rect.left() * bytes_per_pixel;
// TODO(hclam): Fill in the sequence number.
uint8* out = GetOutputBuffer(packet.get(), max_packet_size_);
int filled = 0;
@@ -88,16 +86,14 @@ void VideoEncoderVerbatim::EncodeRect(const SkIRect& rect, bool last) {
packet->mutable_data()->resize(filled);
packet->set_flags(packet->flags() | VideoPacket::LAST_PACKET);
- packet->set_capture_time_ms(capture_data_->capture_time_ms());
+
+ packet->set_capture_time_ms(frame->capture_time_ms());
packet->set_encode_time_ms(
(base::Time::Now() - encode_start_time_).InMillisecondsRoundedUp());
- packet->set_client_sequence_number(
- capture_data_->client_sequence_number());
- SkIPoint dpi(capture_data_->dpi());
- if (dpi.x())
- packet->mutable_format()->set_x_dpi(dpi.x());
- if (dpi.y())
- packet->mutable_format()->set_y_dpi(dpi.y());
+ if (!frame->dpi().is_zero()) {
+ packet->mutable_format()->set_x_dpi(frame->dpi().x());
+ packet->mutable_format()->set_y_dpi(frame->dpi().y());
+ }
if (last)
packet->set_flags(packet->flags() | VideoPacket::LAST_PARTITION);
}
@@ -110,18 +106,19 @@ void VideoEncoderVerbatim::EncodeRect(const SkIRect& rect, bool last) {
}
}
-void VideoEncoderVerbatim::PrepareUpdateStart(const SkIRect& rect,
+void VideoEncoderVerbatim::PrepareUpdateStart(const webrtc::DesktopFrame* frame,
+ const webrtc::DesktopRect& rect,
VideoPacket* packet) {
packet->set_flags(packet->flags() | VideoPacket::FIRST_PACKET);
VideoPacketFormat* format = packet->mutable_format();
- format->set_x(rect.fLeft);
- format->set_y(rect.fTop);
+ format->set_x(rect.left());
+ format->set_y(rect.top());
format->set_width(rect.width());
format->set_height(rect.height());
format->set_encoding(VideoPacketFormat::ENCODING_VERBATIM);
- if (capture_data_->size() != screen_size_) {
- screen_size_ = capture_data_->size();
+ if (frame->size().equals(screen_size_)) {
+ screen_size_ = frame->size();
format->set_screen_width(screen_size_.width());
format->set_screen_height(screen_size_.height());
}
@@ -129,9 +126,7 @@ void VideoEncoderVerbatim::PrepareUpdateStart(const SkIRect& rect,
uint8* VideoEncoderVerbatim::GetOutputBuffer(VideoPacket* packet, size_t size) {
packet->mutable_data()->resize(size);
- // TODO(ajwong): Is there a better way to do this at all???
- return const_cast<uint8*>(reinterpret_cast<const uint8*>(
- packet->mutable_data()->data()));
+ return reinterpret_cast<uint8*>(string_as_array(packet->mutable_data()));
}
} // namespace remoting
diff --git a/remoting/codec/video_encoder_verbatim.h b/remoting/codec/video_encoder_verbatim.h
index 2b6250b..bf8e901 100644
--- a/remoting/codec/video_encoder_verbatim.h
+++ b/remoting/codec/video_encoder_verbatim.h
@@ -8,7 +8,7 @@
#include "base/time.h"
#include "remoting/codec/video_encoder.h"
#include "remoting/proto/video.pb.h"
-#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
namespace remoting {
@@ -24,17 +24,20 @@ class VideoEncoderVerbatim : public VideoEncoder {
// VideoEncoder interface.
virtual void Encode(
- scoped_refptr<media::ScreenCaptureData> capture_data,
- bool key_frame,
+ const webrtc::DesktopFrame* frame,
const DataAvailableCallback& data_available_callback) OVERRIDE;
private:
// Encode a single dirty |rect|.
- void EncodeRect(const SkIRect& rect, bool last);
+ void EncodeRect(const webrtc::DesktopFrame* frame,
+ const webrtc::DesktopRect& rect,
+ bool last);
// Initializes first packet in a sequence of video packets to update screen
// rectangle |rect|.
- void PrepareUpdateStart(const SkIRect& rect, VideoPacket* packet);
+ void PrepareUpdateStart(const webrtc::DesktopFrame* frame,
+ const webrtc::DesktopRect& rect,
+ VideoPacket* packet);
// Allocates a buffer of the specified |size| inside |packet| and returns the
// pointer to it.
@@ -43,12 +46,11 @@ class VideoEncoderVerbatim : public VideoEncoder {
// Submit |packet| to |callback_|.
void SubmitMessage(VideoPacket* packet, size_t rect_index);
- scoped_refptr<media::ScreenCaptureData> capture_data_;
DataAvailableCallback callback_;
base::Time encode_start_time_;
// The most recent screen size.
- SkISize screen_size_;
+ webrtc::DesktopSize screen_size_;
int max_packet_size_;
};
diff --git a/remoting/codec/video_encoder_vp8.cc b/remoting/codec/video_encoder_vp8.cc
index a4e4d1a..7824065 100644
--- a/remoting/codec/video_encoder_vp8.cc
+++ b/remoting/codec/video_encoder_vp8.cc
@@ -8,9 +8,10 @@
#include "base/sys_info.h"
#include "base/time.h"
#include "media/base/yuv_convert.h"
-#include "media/video/capture/screen/screen_capture_data.h"
#include "remoting/base/util.h"
#include "remoting/proto/video.pb.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
extern "C" {
#define VPX_CODEC_DISABLE_COMPAT 1
@@ -49,7 +50,7 @@ void VideoEncoderVp8::Destroy() {
}
}
-bool VideoEncoderVp8::Init(const SkISize& size) {
+bool VideoEncoderVp8::Init(const webrtc::DesktopSize& size) {
Destroy();
codec_.reset(new vpx_codec_ctx_t());
image_.reset(new vpx_image_t());
@@ -146,11 +147,9 @@ bool VideoEncoderVp8::Init(const SkISize& size) {
return true;
}
-void VideoEncoderVp8::PrepareImage(
- scoped_refptr<media::ScreenCaptureData> capture_data,
- SkRegion* updated_region) {
- const SkRegion& region = capture_data->dirty_region();
- if (region.isEmpty()) {
+void VideoEncoderVp8::PrepareImage(const webrtc::DesktopFrame* frame,
+ SkRegion* updated_region) {
+ if (frame->updated_region().is_empty()) {
updated_region->setEmpty();
return;
}
@@ -159,8 +158,11 @@ void VideoEncoderVp8::PrepareImage(
// This also ensures that all rectangles have even-aligned top-left, which
// is required for ConvertRGBToYUVWithRect() to work.
std::vector<SkIRect> aligned_rects;
- for (SkRegion::Iterator r(region); !r.done(); r.next()) {
- aligned_rects.push_back(AlignRect(r.rect()));
+ for (webrtc::DesktopRegion::Iterator r(frame->updated_region());
+ !r.IsAtEnd(); r.Advance()) {
+ const webrtc::DesktopRect& rect = r.rect();
+ aligned_rects.push_back(AlignRect(
+ SkIRect::MakeLTRB(rect.left(), rect.top(), rect.right(), rect.bottom())));
}
DCHECK(!aligned_rects.empty());
updated_region->setRects(&aligned_rects[0], aligned_rects.size());
@@ -172,8 +174,8 @@ void VideoEncoderVp8::PrepareImage(
SkRegion::kIntersect_Op);
// Convert the updated region to YUV ready for encoding.
- const uint8* rgb_data = capture_data->data();
- const int rgb_stride = capture_data->stride();
+ const uint8* rgb_data = frame->data();
+ const int rgb_stride = frame->stride();
const int y_stride = image_->stride[0];
DCHECK_EQ(image_->stride[1], image_->stride[2]);
const int uv_stride = image_->stride[1];
@@ -213,17 +215,16 @@ void VideoEncoderVp8::PrepareActiveMap(const SkRegion& updated_region) {
}
void VideoEncoderVp8::Encode(
- scoped_refptr<media::ScreenCaptureData> capture_data,
- bool key_frame,
+ const webrtc::DesktopFrame* frame,
const DataAvailableCallback& data_available_callback) {
- DCHECK_LE(32, capture_data->size().width());
- DCHECK_LE(32, capture_data->size().height());
+ DCHECK_LE(32, frame->size().width());
+ DCHECK_LE(32, frame->size().height());
base::Time encode_start_time = base::Time::Now();
if (!initialized_ ||
- (capture_data->size() != SkISize::Make(image_->w, image_->h))) {
- bool ret = Init(capture_data->size());
+ !frame->size().equals(webrtc::DesktopSize(image_->w, image_->h))) {
+ bool ret = Init(frame->size());
// TODO(hclam): Handle error better.
CHECK(ret) << "Initialization of encoder failed";
initialized_ = ret;
@@ -231,7 +232,7 @@ void VideoEncoderVp8::Encode(
// Convert the updated capture data ready for encode.
SkRegion updated_region;
- PrepareImage(capture_data, &updated_region);
+ PrepareImage(frame, &updated_region);
// Update active map based on updated region.
PrepareActiveMap(updated_region);
@@ -286,17 +287,15 @@ void VideoEncoderVp8::Encode(
packet->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8);
packet->set_flags(VideoPacket::FIRST_PACKET | VideoPacket::LAST_PACKET |
VideoPacket::LAST_PARTITION);
- packet->mutable_format()->set_screen_width(capture_data->size().width());
- packet->mutable_format()->set_screen_height(capture_data->size().height());
- packet->set_capture_time_ms(capture_data->capture_time_ms());
+ packet->mutable_format()->set_screen_width(frame->size().width());
+ packet->mutable_format()->set_screen_height(frame->size().height());
+ packet->set_capture_time_ms(frame->capture_time_ms());
packet->set_encode_time_ms(
(base::Time::Now() - encode_start_time).InMillisecondsRoundedUp());
- packet->set_client_sequence_number(capture_data->client_sequence_number());
- SkIPoint dpi(capture_data->dpi());
- if (dpi.x())
- packet->mutable_format()->set_x_dpi(dpi.x());
- if (dpi.y())
- packet->mutable_format()->set_y_dpi(dpi.y());
+ if (!frame->dpi().is_zero()) {
+ packet->mutable_format()->set_x_dpi(frame->dpi().x());
+ packet->mutable_format()->set_y_dpi(frame->dpi().y());
+ }
for (SkRegion::Iterator r(updated_region); !r.done(); r.next()) {
Rect* rect = packet->add_dirty_rects();
rect->set_x(r.rect().x());
diff --git a/remoting/codec/video_encoder_vp8.h b/remoting/codec/video_encoder_vp8.h
index f26fad3..912c845 100644
--- a/remoting/codec/video_encoder_vp8.h
+++ b/remoting/codec/video_encoder_vp8.h
@@ -12,6 +12,10 @@
typedef struct vpx_codec_ctx vpx_codec_ctx_t;
typedef struct vpx_image vpx_image_t;
+namespace webrtc {
+class DesktopSize;
+} // namespace webrtc
+
namespace remoting {
// A class that uses VP8 to perform encoding.
@@ -20,23 +24,25 @@ class VideoEncoderVp8 : public VideoEncoder {
VideoEncoderVp8();
virtual ~VideoEncoderVp8();
+ // VideoEncoder interface.
virtual void Encode(
- scoped_refptr<media::ScreenCaptureData> capture_data,
- bool key_frame,
+ const webrtc::DesktopFrame* frame,
const DataAvailableCallback& data_available_callback) OVERRIDE;
private:
FRIEND_TEST_ALL_PREFIXES(VideoEncoderVp8Test, AlignAndClipRect);
// Initialize the encoder. Returns true if successful.
- bool Init(const SkISize& size);
+ bool Init(const webrtc::DesktopSize& size);
// Destroy the encoder.
void Destroy();
// Prepare |image_| for encoding. Write updated rectangles into
// |updated_region|.
- void PrepareImage(scoped_refptr<media::ScreenCaptureData> capture_data,
+ //
+ // TODO(sergeyu): Update this code to use webrtc::DesktopRegion.
+ void PrepareImage(const webrtc::DesktopFrame* frame,
SkRegion* updated_region);
// Update the active map according to |updated_region|. Active map is then
diff --git a/remoting/codec/video_encoder_vp8_unittest.cc b/remoting/codec/video_encoder_vp8_unittest.cc
index 9a32fe2..684910d 100644
--- a/remoting/codec/video_encoder_vp8_unittest.cc
+++ b/remoting/codec/video_encoder_vp8_unittest.cc
@@ -10,10 +10,10 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
-#include "media/video/capture/screen/screen_capture_data.h"
#include "remoting/codec/codec_test.h"
#include "remoting/proto/video.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
namespace {
@@ -39,25 +39,21 @@ class VideoEncoderCallback {
TEST(VideoEncoderVp8Test, TestSizeChangeNoLeak) {
int height = 1000;
int width = 1000;
- const int kBytesPerPixel = 4;
VideoEncoderVp8 encoder;
VideoEncoderCallback callback;
- std::vector<uint8> buffer(width * height * kBytesPerPixel);
- scoped_refptr<media::ScreenCaptureData> capture_data(
- new media::ScreenCaptureData(&buffer.front(), width * kBytesPerPixel,
- SkISize::Make(width, height)));
- encoder.Encode(capture_data, false,
- base::Bind(&VideoEncoderCallback::DataAvailable,
- base::Unretained(&callback)));
+ scoped_ptr<webrtc::DesktopFrame> frame(new webrtc::BasicDesktopFrame(
+ webrtc::DesktopSize(width, height)));
+
+ encoder.Encode(frame.get(), base::Bind(&VideoEncoderCallback::DataAvailable,
+ base::Unretained(&callback)));
height /= 2;
- capture_data = new media::ScreenCaptureData(
- &buffer.front(), width * kBytesPerPixel, SkISize::Make(width, height));
- encoder.Encode(capture_data, false,
- base::Bind(&VideoEncoderCallback::DataAvailable,
- base::Unretained(&callback)));
+ frame.reset(new webrtc::BasicDesktopFrame(
+ webrtc::DesktopSize(width, height)));
+ encoder.Encode(frame.get(), base::Bind(&VideoEncoderCallback::DataAvailable,
+ base::Unretained(&callback)));
}
class VideoEncoderDpiCallback {
@@ -73,17 +69,14 @@ class VideoEncoderDpiCallback {
TEST(VideoEncoderVp8Test, TestDpiPropagation) {
int height = 32;
int width = 32;
- const int kBytesPerPixel = 4;
VideoEncoderVp8 encoder;
VideoEncoderDpiCallback callback;
- std::vector<uint8> buffer(width * height * kBytesPerPixel);
- scoped_refptr<media::ScreenCaptureData> capture_data(
- new media::ScreenCaptureData(&buffer.front(), width * kBytesPerPixel,
- SkISize::Make(width, height)));
- capture_data->set_dpi(SkIPoint::Make(96, 97));
- encoder.Encode(capture_data, false,
+ scoped_ptr<webrtc::DesktopFrame> frame(new webrtc::BasicDesktopFrame(
+ webrtc::DesktopSize(width, height)));
+ frame->set_dpi(webrtc::DesktopVector(96, 97));
+ encoder.Encode(frame.get(),
base::Bind(&VideoEncoderDpiCallback::DataAvailable,
base::Unretained(&callback)));
}
diff --git a/remoting/host/DEPS b/remoting/host/DEPS
index dbdf6ac..cadbcd3 100644
--- a/remoting/host/DEPS
+++ b/remoting/host/DEPS
@@ -7,5 +7,6 @@ include_rules = [
"+third_party/jsoncpp",
"+third_party/modp_b64",
"+third_party/npapi",
+ "+third_party/webrtc",
"+ui",
]
diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h
index 0c640ea..7a032d0 100644
--- a/remoting/host/chromoting_messages.h
+++ b/remoting/host/chromoting_messages.h
@@ -8,11 +8,10 @@
#include "ipc/ipc_platform_file.h"
#include "media/video/capture/screen/mouse_cursor_shape.h"
#include "net/base/ip_endpoint.h"
+#include "remoting/host/chromoting_param_traits.h"
#include "remoting/host/screen_resolution.h"
#include "remoting/protocol/transport.h"
-#include "third_party/skia/include/core/SkPoint.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "third_party/skia/include/core/SkSize.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
#endif // REMOTING_HOST_CHROMOTING_MESSAGES_H_
@@ -64,11 +63,6 @@ IPC_MESSAGE_CONTROL3(ChromotingDaemonNetworkMsg_DesktopAttached,
// console session.
IPC_MESSAGE_CONTROL0(ChromotingNetworkDaemonMsg_SendSasToConsole)
-IPC_STRUCT_TRAITS_BEGIN(remoting::ScreenResolution)
- IPC_STRUCT_TRAITS_MEMBER(dimensions_)
- IPC_STRUCT_TRAITS_MEMBER(dpi_)
-IPC_STRUCT_TRAITS_END()
-
// Connects the terminal |terminal_id| (i.e. a remote client) to a desktop
// session.
IPC_MESSAGE_CONTROL3(ChromotingNetworkHostMsg_ConnectTerminal,
@@ -138,9 +132,7 @@ IPC_MESSAGE_CONTROL0(ChromotingDesktopDaemonMsg_InjectSas)
//-----------------------------------------------------------------------------
// Chromoting messages sent from the desktop to the network process.
-// Notifies the network process that a shared buffer has been created. Receipt
-// of this message must be confirmed by replying with
-// ChromotingNetworkDesktopMsg_SharedBufferCreated message.
+// Notifies the network process that a shared buffer has been created.
IPC_MESSAGE_CONTROL3(ChromotingDesktopNetworkMsg_CreateSharedBuffer,
int /* id */,
IPC::PlatformFileForTransit /* handle */,
@@ -150,31 +142,14 @@ IPC_MESSAGE_CONTROL3(ChromotingDesktopNetworkMsg_CreateSharedBuffer,
IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_ReleaseSharedBuffer,
int /* id */)
-IPC_STRUCT_TRAITS_BEGIN(SkIPoint)
- IPC_STRUCT_TRAITS_MEMBER(fX)
- IPC_STRUCT_TRAITS_MEMBER(fY)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(SkIRect)
- IPC_STRUCT_TRAITS_MEMBER(fLeft)
- IPC_STRUCT_TRAITS_MEMBER(fTop)
- IPC_STRUCT_TRAITS_MEMBER(fRight)
- IPC_STRUCT_TRAITS_MEMBER(fBottom)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(SkISize)
- IPC_STRUCT_TRAITS_MEMBER(fWidth)
- IPC_STRUCT_TRAITS_MEMBER(fHeight)
-IPC_STRUCT_TRAITS_END()
-
IPC_STRUCT_TRAITS_BEGIN(media::MouseCursorShape)
IPC_STRUCT_TRAITS_MEMBER(size)
IPC_STRUCT_TRAITS_MEMBER(hotspot)
IPC_STRUCT_TRAITS_MEMBER(data)
IPC_STRUCT_TRAITS_END()
-// Serialized media::ScreenCaptureData structure.
-IPC_STRUCT_BEGIN(SerializedCapturedData)
+// Serialized webrtc::DesktopFrame.
+IPC_STRUCT_BEGIN(SerializedDesktopFrame)
// ID of the shared memory buffer containing the pixels.
IPC_STRUCT_MEMBER(int, shared_buffer_id)
@@ -182,10 +157,10 @@ IPC_STRUCT_BEGIN(SerializedCapturedData)
IPC_STRUCT_MEMBER(int, bytes_per_row)
// Captured region.
- IPC_STRUCT_MEMBER(std::vector<SkIRect>, dirty_region)
+ IPC_STRUCT_MEMBER(std::vector<webrtc::DesktopRect>, dirty_region)
// Dimensions of the buffer in pixels.
- IPC_STRUCT_MEMBER(SkISize, dimensions)
+ IPC_STRUCT_MEMBER(webrtc::DesktopSize, dimensions)
// Time spent in capture. Unit is in milliseconds.
IPC_STRUCT_MEMBER(int, capture_time_ms)
@@ -194,12 +169,12 @@ IPC_STRUCT_BEGIN(SerializedCapturedData)
IPC_STRUCT_MEMBER(int64, client_sequence_number)
// DPI for this frame.
- IPC_STRUCT_MEMBER(SkIPoint, dpi)
+ IPC_STRUCT_MEMBER(webrtc::DesktopVector, dpi)
IPC_STRUCT_END()
// Notifies the network process that a shared buffer has been created.
IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_CaptureCompleted,
- SerializedCapturedData /* capture_data */ )
+ SerializedDesktopFrame /* frame */ )
// Carries a cursor share update from the desktop session agent to the client.
IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_CursorShapeChanged,
@@ -228,12 +203,6 @@ IPC_MESSAGE_CONTROL3(ChromotingNetworkDesktopMsg_StartSessionAgent,
remoting::ScreenResolution /* resolution */,
bool /* virtual_terminal */)
-// Notifies the desktop process that the shared memory buffer has been mapped to
-// the memory of the network process and so it can be safely dropped by
-// the network process at any time.
-IPC_MESSAGE_CONTROL1(ChromotingNetworkDesktopMsg_SharedBufferCreated,
- int /* id */)
-
IPC_MESSAGE_CONTROL0(ChromotingNetworkDesktopMsg_CaptureFrame)
// Carries a clipboard event from the client to the desktop session agent.
diff --git a/remoting/host/chromoting_param_traits.cc b/remoting/host/chromoting_param_traits.cc
new file mode 100644
index 0000000..d1c794c
--- /dev/null
+++ b/remoting/host/chromoting_param_traits.cc
@@ -0,0 +1,127 @@
+// Copyright 2013 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/host/chromoting_param_traits.h"
+
+#include "base/stringprintf.h"
+
+namespace IPC {
+
+// static
+void ParamTraits<webrtc::DesktopVector>::Write(Message* m,
+ const webrtc::DesktopVector& p) {
+ m->WriteInt(p.x());
+ m->WriteInt(p.y());
+}
+
+// static
+bool ParamTraits<webrtc::DesktopVector>::Read(const Message* m,
+ PickleIterator* iter,
+ webrtc::DesktopVector* r) {
+ int x, y;
+ if (!m->ReadInt(iter, &x) || !m->ReadInt(iter, &y))
+ return false;
+ *r = webrtc::DesktopVector(x, y);
+ return true;
+}
+
+// static
+void ParamTraits<webrtc::DesktopVector>::Log(const webrtc::DesktopVector& p,
+ std::string* l) {
+ l->append(base::StringPrintf("webrtc::DesktopVector(%d, %d)",
+ p.x(), p.y()));
+}
+
+// static
+void ParamTraits<webrtc::DesktopSize>::Write(Message* m,
+ const webrtc::DesktopSize& p) {
+ m->WriteInt(p.width());
+ m->WriteInt(p.height());
+}
+
+// static
+bool ParamTraits<webrtc::DesktopSize>::Read(const Message* m,
+ PickleIterator* iter,
+ webrtc::DesktopSize* r) {
+ int width, height;
+ if (!m->ReadInt(iter, &width) || !m->ReadInt(iter, &height))
+ return false;
+ *r = webrtc::DesktopSize(width, height);
+ return true;
+}
+
+// static
+void ParamTraits<webrtc::DesktopSize>::Log(const webrtc::DesktopSize& p,
+ std::string* l) {
+ l->append(base::StringPrintf("webrtc::DesktopSize(%d, %d)",
+ p.width(), p.height()));
+}
+
+// static
+void ParamTraits<webrtc::DesktopRect>::Write(Message* m,
+ const webrtc::DesktopRect& p) {
+ m->WriteInt(p.left());
+ m->WriteInt(p.top());
+ m->WriteInt(p.right());
+ m->WriteInt(p.bottom());
+}
+
+// static
+bool ParamTraits<webrtc::DesktopRect>::Read(const Message* m,
+ PickleIterator* iter,
+ webrtc::DesktopRect* r) {
+ int left, right, top, bottom;
+ if (!m->ReadInt(iter, &left) || !m->ReadInt(iter, &top) ||
+ !m->ReadInt(iter, &right) || !m->ReadInt(iter, &bottom)) {
+ return false;
+ }
+ *r = webrtc::DesktopRect::MakeLTRB(left, top, right, bottom);
+ return true;
+}
+
+// static
+void ParamTraits<webrtc::DesktopRect>::Log(const webrtc::DesktopRect& p,
+ std::string* l) {
+ l->append(base::StringPrintf("webrtc::DesktopRect(%d, %d, %d, %d)",
+ p.left(), p.top(), p.right(), p.bottom()));
+}
+
+// static
+void ParamTraits<remoting::ScreenResolution>::Write(
+ Message* m,
+ const remoting::ScreenResolution& p) {
+ ParamTraits<webrtc::DesktopSize>::Write(m, p.dimensions());
+ ParamTraits<webrtc::DesktopVector>::Write(m, p.dpi());
+}
+
+// static
+bool ParamTraits<remoting::ScreenResolution>::Read(
+ const Message* m,
+ PickleIterator* iter,
+ remoting::ScreenResolution* r) {
+ webrtc::DesktopSize size;
+ webrtc::DesktopVector dpi;
+ if (!ParamTraits<webrtc::DesktopSize>::Read(m, iter, &size) ||
+ !ParamTraits<webrtc::DesktopVector>::Read(m, iter, &dpi)) {
+ return false;
+ }
+ if (size.width() < 0 || size.height() < 0 ||
+ dpi.x() < 0 || dpi.y() < 0) {
+ return false;
+ }
+ *r = remoting::ScreenResolution(size, dpi);
+ return true;
+}
+
+// static
+void ParamTraits<remoting::ScreenResolution>::Log(
+ const remoting::ScreenResolution& p,
+ std::string* l) {
+ l->append(base::StringPrintf("webrtc::ScreenResolution(%d, %d, %d, %d)",
+ p.dimensions().width(), p.dimensions().height(),
+ p.dpi().x(), p.dpi().y()));
+}
+
+} // namespace IPC
+
diff --git a/remoting/host/chromoting_param_traits.h b/remoting/host/chromoting_param_traits.h
new file mode 100644
index 0000000..7925918
--- /dev/null
+++ b/remoting/host/chromoting_param_traits.h
@@ -0,0 +1,49 @@
+// Copyright 2013 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.
+
+#ifndef REMOTING_HOST_CHROMOTING_PARAM_TRAITS_H_
+#define REMOTING_HOST_CHROMOTING_PARAM_TRAITS_H_
+
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_param_traits.h"
+#include "remoting/host/screen_resolution.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
+
+namespace IPC {
+
+template <>
+struct ParamTraits<webrtc::DesktopVector> {
+ typedef webrtc::DesktopVector param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<webrtc::DesktopSize> {
+ typedef webrtc::DesktopSize param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<webrtc::DesktopRect> {
+ typedef webrtc::DesktopRect param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<remoting::ScreenResolution> {
+ typedef remoting::ScreenResolution param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+#endif // REMOTING_HOST_CHROMOTING_PARAM_TRAITS_H_
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index 8636b7a..38ec520 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -99,8 +99,13 @@ void ClientSession::NotifyClientResolution(
const protocol::ClientResolution& resolution) {
DCHECK(CalledOnValidThread());
- if (!resolution.has_dips_width() || !resolution.has_dips_height())
+ // TODO(sergeyu): Move these checks to protocol layer.
+ if (!resolution.has_dips_width() || !resolution.has_dips_height() ||
+ resolution.dips_width() < 0 || resolution.dips_height() < 0 ||
+ resolution.width() <= 0 || resolution.height() <= 0) {
+ LOG(ERROR) << "Received invalid ClientResolution message.";
return;
+ }
VLOG(1) << "Received ClientResolution (dips_width="
<< resolution.dips_width() << ", dips_height="
@@ -110,12 +115,11 @@ void ClientSession::NotifyClientResolution(
return;
ScreenResolution client_resolution(
- SkISize::Make(resolution.dips_width(), resolution.dips_height()),
- SkIPoint::Make(kDefaultDPI, kDefaultDPI));
+ webrtc::DesktopSize(resolution.dips_width(), resolution.dips_height()),
+ webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
// Try to match the client's resolution.
- if (client_resolution.IsValid())
- screen_controls_->SetScreenResolution(client_resolution);
+ screen_controls_->SetScreenResolution(client_resolution);
}
void ClientSession::ControlVideo(const protocol::VideoControl& video_control) {
diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc
index 3d92da7e..314c716 100644
--- a/remoting/host/client_session_unittest.cc
+++ b/remoting/host/client_session_unittest.cc
@@ -13,6 +13,7 @@
#include "remoting/host/host_mock_objects.h"
#include "remoting/protocol/protocol_mock_objects.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
namespace remoting {
diff --git a/remoting/host/daemon_process.cc b/remoting/host/daemon_process.cc
index faf5e60..b7a0336 100644
--- a/remoting/host/daemon_process.cc
+++ b/remoting/host/daemon_process.cc
@@ -29,9 +29,9 @@ namespace {
const char kApplicationName[] = "chromoting";
std::ostream& operator<<(std::ostream& os, const ScreenResolution& resolution) {
- return os << resolution.dimensions_.width() << "x"
- << resolution.dimensions_.height() << " at "
- << resolution.dpi_.x() << "x" << resolution.dpi_.y() << " DPI";
+ return os << resolution.dimensions().width() << "x"
+ << resolution.dimensions().height() << " at "
+ << resolution.dpi().x() << "x" << resolution.dpi().y() << " DPI";
}
} // namespace
@@ -188,13 +188,6 @@ void DaemonProcess::CreateDesktopSession(int terminal_id,
// Terminal IDs cannot be reused. Update the expected next terminal ID.
next_terminal_id_ = std::max(next_terminal_id_, terminal_id + 1);
- // Validate |resolution| and restart the sender if it is not valid.
- if (!resolution.IsValid()) {
- LOG(ERROR) << "Invalid resolution specified: " << resolution;
- CrashNetworkProcess(FROM_HERE);
- return;
- }
-
// Create the desktop session.
scoped_ptr<DesktopSession> session = DoCreateDesktopSession(
terminal_id, resolution, virtual_terminal);
@@ -223,7 +216,7 @@ void DaemonProcess::SetScreenResolution(int terminal_id,
}
// Validate |resolution| and restart the sender if it is not valid.
- if (!resolution.IsValid()) {
+ if (resolution.IsEmpty()) {
LOG(ERROR) << "Invalid resolution specified: " << resolution;
CrashNetworkProcess(FROM_HERE);
return;
diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc
index 6dd811c..025f6e9 100644
--- a/remoting/host/desktop_session_agent.cc
+++ b/remoting/host/desktop_session_agent.cc
@@ -6,10 +6,10 @@
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/memory/shared_memory.h"
#include "ipc/ipc_channel_proxy.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
-#include "media/video/capture/screen/screen_capture_data.h"
#include "remoting/base/auto_thread_task_runner.h"
#include "remoting/base/constants.h"
#include "remoting/host/audio_capturer.h"
@@ -24,7 +24,8 @@
#include "remoting/proto/event.pb.h"
#include "remoting/protocol/clipboard_stub.h"
#include "remoting/protocol/input_event_tracker.h"
-#include "third_party/skia/include/core/SkRegion.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
+#include "third_party/webrtc/modules/desktop_capture/shared_memory.h"
namespace remoting {
@@ -62,6 +63,46 @@ void DesktopSesssionClipboardStub::InjectClipboardEvent(
} // namespace
+// webrtc::SharedMemory implementation that notifies creating
+// DesktopSessionAgent when it's deleted.
+class DesktopSessionAgent::SharedBuffer : public webrtc::SharedMemory {
+ public:
+ static scoped_ptr<SharedBuffer> Create(DesktopSessionAgent* agent,
+ size_t size,
+ int id) {
+ scoped_ptr<base::SharedMemory> memory(new base::SharedMemory());
+ if (!memory->CreateAndMapAnonymous(size))
+ return scoped_ptr<SharedBuffer>();
+ return scoped_ptr<SharedBuffer>(
+ new SharedBuffer(agent, memory.Pass(), size, id));
+ }
+
+ virtual ~SharedBuffer() {
+ agent_->OnSharedBufferDeleted(id());
+ }
+
+ private:
+ SharedBuffer(DesktopSessionAgent* agent,
+ scoped_ptr<base::SharedMemory> memory,
+ size_t size,
+ int id)
+ : SharedMemory(memory->memory(), size,
+#if defined(OS_WIN)
+ memory->handle(),
+#else
+ memory->handle().fd,
+#endif
+ id),
+ agent_(agent),
+ shared_memory_(memory.Pass()) {
+ }
+
+ DesktopSessionAgent* agent_;
+ scoped_ptr<base::SharedMemory> shared_memory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SharedBuffer);
+};
+
DesktopSessionAgent::Delegate::~Delegate() {
}
@@ -83,8 +124,6 @@ bool DesktopSessionAgent::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(DesktopSessionAgent, message)
IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_CaptureFrame,
OnCaptureFrame)
- IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_SharedBufferCreated,
- OnSharedBufferCreated)
IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectClipboardEvent,
OnInjectClipboardEvent)
IPC_MESSAGE_HANDLER(ChromotingNetworkDesktopMsg_InjectKeyEvent,
@@ -127,14 +166,13 @@ void DesktopSessionAgent::OnChannelError() {
delegate_->OnNetworkProcessDisconnected();
}
-scoped_refptr<media::SharedBuffer> DesktopSessionAgent::CreateSharedBuffer(
- uint32 size) {
+webrtc::SharedMemory* DesktopSessionAgent::CreateSharedMemory(size_t size) {
DCHECK(video_capture_task_runner()->BelongsToCurrentThread());
- scoped_refptr<media::SharedBuffer> buffer = new media::SharedBuffer(size);
- if (buffer->ptr() != NULL) {
- buffer->set_id(next_shared_buffer_id_);
- shared_buffers_.push_back(buffer);
+ scoped_ptr<SharedBuffer> buffer =
+ SharedBuffer::Create(this, size, next_shared_buffer_id_);
+ if (buffer) {
+ shared_buffers_++;
// |next_shared_buffer_id_| starts from 1 and incrementing it by 2 makes
// sure it is always odd and therefore zero is never used as a valid buffer
@@ -146,20 +184,17 @@ scoped_refptr<media::SharedBuffer> DesktopSessionAgent::CreateSharedBuffer(
// speaking it never happens.
next_shared_buffer_id_ += 2;
+ IPC::PlatformFileForTransit handle;
+#if defined(OS_WIN)
+ handle = buffer->handle();
+#else
+ handle = base::FileDescriptor(buffer->handle(), false);
+#endif
SendToNetwork(new ChromotingDesktopNetworkMsg_CreateSharedBuffer(
- buffer->id(), buffer->handle(), buffer->size()));
+ buffer->id(), handle, buffer->size()));
}
- return buffer;
-}
-
-void DesktopSessionAgent::ReleaseSharedBuffer(
- scoped_refptr<media::SharedBuffer> buffer) {
- DCHECK(video_capture_task_runner()->BelongsToCurrentThread());
- DCHECK(buffer->id() != 0);
-
- SendToNetwork(
- new ChromotingDesktopNetworkMsg_ReleaseSharedBuffer(buffer->id()));
+ return buffer.release();
}
const std::string& DesktopSessionAgent::client_jid() const {
@@ -241,26 +276,27 @@ void DesktopSessionAgent::OnStartSessionAgent(
FROM_HERE, base::Bind(&DesktopSessionAgent::StartVideoCapturer, this));
}
-void DesktopSessionAgent::OnCaptureCompleted(
- scoped_refptr<media::ScreenCaptureData> capture_data) {
+void DesktopSessionAgent::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
DCHECK(video_capture_task_runner()->BelongsToCurrentThread());
- current_size_ = capture_data->size();
+ last_frame_.reset(frame);
+
+ current_size_ = frame->size();
- // Serialize media::ScreenCaptureData
- SerializedCapturedData serialized_data;
- serialized_data.shared_buffer_id = capture_data->shared_buffer()->id();
- serialized_data.bytes_per_row = capture_data->stride();
- serialized_data.dimensions = capture_data->size();
- serialized_data.capture_time_ms = capture_data->capture_time_ms();
- serialized_data.client_sequence_number =
- capture_data->client_sequence_number();
- serialized_data.dpi = capture_data->dpi();
- for (SkRegion::Iterator i(capture_data->dirty_region()); !i.done(); i.next())
- serialized_data.dirty_region.push_back(i.rect());
+ // Serialize webrtc::DesktopFrame.
+ SerializedDesktopFrame serialized_frame;
+ serialized_frame.shared_buffer_id = frame->shared_memory()->id();
+ serialized_frame.bytes_per_row = frame->stride();
+ serialized_frame.dimensions = frame->size();
+ serialized_frame.capture_time_ms = frame->capture_time_ms();
+ serialized_frame.dpi = frame->dpi();
+ for (webrtc::DesktopRegion::Iterator i(frame->updated_region());
+ !i.IsAtEnd(); i.Advance()) {
+ serialized_frame.dirty_region.push_back(i.rect());
+ }
SendToNetwork(
- new ChromotingDesktopNetworkMsg_CaptureCompleted(serialized_data));
+ new ChromotingDesktopNetworkMsg_CaptureCompleted(serialized_frame));
}
void DesktopSessionAgent::OnCursorShapeChanged(
@@ -359,25 +395,7 @@ void DesktopSessionAgent::OnCaptureFrame() {
// runner. If the client issues more requests, pixel data in captured frames
// will likely be corrupted but stability of media::ScreenCapturer will not be
// affected.
- video_capturer_->CaptureFrame();
-}
-
-void DesktopSessionAgent::OnSharedBufferCreated(int id) {
- if (!video_capture_task_runner()->BelongsToCurrentThread()) {
- video_capture_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&DesktopSessionAgent::OnSharedBufferCreated, this, id));
- return;
- }
-
- // Drop the cached reference to the buffer.
- SharedBuffers::iterator i = shared_buffers_.begin();
- for (; i != shared_buffers_.end(); ++i) {
- if ((*i)->id() == id) {
- shared_buffers_.erase(i);
- break;
- }
- }
+ video_capturer_->Capture(webrtc::DesktopRegion());
}
void DesktopSessionAgent::OnInjectClipboardEvent(
@@ -434,7 +452,7 @@ void DesktopSessionAgent::SetScreenResolution(
const ScreenResolution& resolution) {
DCHECK(caller_task_runner()->BelongsToCurrentThread());
- if (screen_controls_ && resolution.IsValid())
+ if (screen_controls_ && resolution.IsEmpty())
screen_controls_->SetScreenResolution(resolution);
}
@@ -471,17 +489,20 @@ void DesktopSessionAgent::StopAudioCapturer() {
void DesktopSessionAgent::StartVideoCapturer() {
DCHECK(video_capture_task_runner()->BelongsToCurrentThread());
- if (video_capturer_)
+ if (video_capturer_) {
+ video_capturer_->SetMouseShapeObserver(this);
video_capturer_->Start(this);
+ }
}
void DesktopSessionAgent::StopVideoCapturer() {
DCHECK(video_capture_task_runner()->BelongsToCurrentThread());
video_capturer_.reset();
+ last_frame_.reset();
- // Free any shared buffers left.
- shared_buffers_.clear();
+ // Video capturer must delete all buffers.
+ DCHECK_EQ(shared_buffers_, 0);
}
DesktopSessionAgent::DesktopSessionAgent(
@@ -497,12 +518,21 @@ DesktopSessionAgent::DesktopSessionAgent(
video_capture_task_runner_(video_capture_task_runner),
control_factory_(this),
desktop_pipe_(IPC::InvalidPlatformFileForTransit()),
- current_size_(SkISize::Make(0, 0)),
next_shared_buffer_id_(1),
+ shared_buffers_(0),
started_(false) {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
}
+void DesktopSessionAgent::OnSharedBufferDeleted(int id) {
+ DCHECK(video_capture_task_runner()->BelongsToCurrentThread());
+ DCHECK(id != 0);
+
+ shared_buffers_--;
+ DCHECK_GE(shared_buffers_, 0);
+ SendToNetwork(new ChromotingDesktopNetworkMsg_ReleaseSharedBuffer(id));
+}
+
void DesktopSessionAgent::CloseDesktopPipeHandle() {
if (!(desktop_pipe_ == IPC::InvalidPlatformFileForTransit())) {
#if defined(OS_WIN)
diff --git a/remoting/host/desktop_session_agent.h b/remoting/host/desktop_session_agent.h
index a993520..91320ab 100644
--- a/remoting/host/desktop_session_agent.h
+++ b/remoting/host/desktop_session_agent.h
@@ -5,7 +5,7 @@
#ifndef REMOTING_HOST_DESKTOP_SESSION_AGENT_H_
#define REMOTING_HOST_DESKTOP_SESSION_AGENT_H_
-#include <list>
+#include <map>
#include "base/basictypes.h"
#include "base/callback.h"
@@ -16,11 +16,9 @@
#include "ipc/ipc_listener.h"
#include "ipc/ipc_platform_file.h"
#include "media/video/capture/screen/screen_capturer.h"
-#include "media/video/capture/screen/shared_buffer.h"
#include "remoting/host/client_session_control.h"
#include "remoting/protocol/clipboard_stub.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "third_party/skia/include/core/SkSize.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
namespace IPC {
class ChannelProxy;
@@ -48,7 +46,8 @@ class InputEventTracker;
class DesktopSessionAgent
: public base::RefCountedThreadSafe<DesktopSessionAgent>,
public IPC::Listener,
- public media::ScreenCapturer::Delegate,
+ public webrtc::DesktopCapturer::Callback,
+ public media::ScreenCapturer::MouseShapeObserver,
public ClientSessionControl {
public:
class Delegate {
@@ -75,13 +74,11 @@ class DesktopSessionAgent
virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
virtual void OnChannelError() OVERRIDE;
- // media::ScreenCapturer::Delegate implementation.
- virtual scoped_refptr<media::SharedBuffer> CreateSharedBuffer(
- uint32 size) OVERRIDE;
- virtual void ReleaseSharedBuffer(
- scoped_refptr<media::SharedBuffer> buffer) OVERRIDE;
- virtual void OnCaptureCompleted(
- scoped_refptr<media::ScreenCaptureData> capture_data) OVERRIDE;
+ // webrtc::DesktopCapturer::Callback implementation.
+ virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE;
+ virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE;
+
+ // media::ScreenCapturer::MouseShapeObserver implementation.
virtual void OnCursorShapeChanged(
scoped_ptr<media::MouseCursorShape> cursor_shape) OVERRIDE;
@@ -102,14 +99,14 @@ class DesktopSessionAgent
void Stop();
protected:
+ friend class base::RefCountedThreadSafe<DesktopSessionAgent>;
+
DesktopSessionAgent(
scoped_refptr<AutoThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<AutoThreadTaskRunner> caller_task_runner,
scoped_refptr<AutoThreadTaskRunner> input_task_runner,
scoped_refptr<AutoThreadTaskRunner> io_task_runner,
scoped_refptr<AutoThreadTaskRunner> video_capture_task_runner);
-
- friend class base::RefCountedThreadSafe<DesktopSessionAgent>;
virtual ~DesktopSessionAgent();
// ClientSessionControl interface.
@@ -186,6 +183,12 @@ class DesktopSessionAgent
}
private:
+ class SharedBuffer;
+ friend class SharedBuffer;
+
+ // Called by SharedBuffer when it's destroyed.
+ void OnSharedBufferDeleted(int id);
+
// Closes |desktop_pipe_| if it is open.
void CloseDesktopPipeHandle();
@@ -237,14 +240,13 @@ class DesktopSessionAgent
IPC::PlatformFileForTransit desktop_pipe_;
// Size of the most recent captured video frame.
- SkISize current_size_;
+ webrtc::DesktopSize current_size_;
// Next shared buffer ID to be used.
int next_shared_buffer_id_;
- // List of the shared buffers.
- typedef std::list<scoped_refptr<media::SharedBuffer> > SharedBuffers;
- SharedBuffers shared_buffers_;
+ // The number of currently allocated shared buffers.
+ int shared_buffers_;
// True if the desktop session agent has been started.
bool started_;
@@ -252,6 +254,10 @@ class DesktopSessionAgent
// Captures the screen.
scoped_ptr<media::ScreenCapturer> video_capturer_;
+ // Keep reference to the last frame sent to make sure shared buffer is alive
+ // before it's received.
+ scoped_ptr<webrtc::DesktopFrame> last_frame_;
+
DISALLOW_COPY_AND_ASSIGN(DesktopSessionAgent);
};
diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc
index 63fcbd0..27e6c41 100644
--- a/remoting/host/desktop_session_proxy.cc
+++ b/remoting/host/desktop_session_proxy.cc
@@ -8,10 +8,10 @@
#include "base/logging.h"
#include "base/platform_file.h"
#include "base/process_util.h"
+#include "base/memory/shared_memory.h"
#include "base/single_thread_task_runner.h"
#include "ipc/ipc_channel_proxy.h"
#include "ipc/ipc_message_macros.h"
-#include "media/video/capture/screen/screen_capture_data.h"
#include "remoting/base/capabilities.h"
#include "remoting/host/chromoting_messages.h"
#include "remoting/host/client_session.h"
@@ -24,15 +24,80 @@
#include "remoting/proto/audio.pb.h"
#include "remoting/proto/control.pb.h"
#include "remoting/proto/event.pb.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
+#include "third_party/webrtc/modules/desktop_capture/shared_memory.h"
#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
#endif // defined(OS_WIN)
+const bool kReadOnly = true;
const char kSendInitialResolution[] = "sendInitialResolution";
namespace remoting {
+class DesktopSessionProxy::IpcSharedBufferCore
+ : public base::RefCountedThreadSafe<IpcSharedBufferCore> {
+ public:
+ IpcSharedBufferCore(int id,
+ base::SharedMemoryHandle handle,
+ base::ProcessHandle process,
+ size_t size)
+ : id_(id),
+#if defined(OS_WIN)
+ shared_memory_(handle, kReadOnly, process),
+#else // !defined(OS_WIN)
+ shared_memory_(handle, kReadOnly),
+#endif // !defined(OS_WIN)
+ size_(size) {
+ if (!shared_memory_.Map(size)) {
+ LOG(ERROR) << "Failed to map a shared buffer: id=" << id
+#if defined(OS_WIN)
+ << ", handle=" << handle
+#else
+ << ", handle.fd=" << handle.fd
+#endif
+ << ", size=" << size;
+ }
+ }
+
+ int id() { return id_; }
+ size_t size() { return size_; }
+ void* memory() { return shared_memory_.memory(); }
+ webrtc::SharedMemory::Handle handle() {
+#if defined(OS_WIN)
+ return shared_memory_.handle();
+#else
+ return shared_memory_.handle().fd;
+#endif
+ }
+
+ private:
+ virtual ~IpcSharedBufferCore() {}
+ friend class base::RefCountedThreadSafe<IpcSharedBufferCore>;
+
+ int id_;
+ base::SharedMemory shared_memory_;
+ size_t size_;
+
+ DISALLOW_COPY_AND_ASSIGN(IpcSharedBufferCore);
+};
+
+class DesktopSessionProxy::IpcSharedBuffer : public webrtc::SharedMemory {
+ public:
+ IpcSharedBuffer(scoped_refptr<IpcSharedBufferCore> core)
+ : SharedMemory(core->memory(), core->size(),
+ core->handle(), core->id()),
+ core_(core) {
+ }
+
+ private:
+ scoped_refptr<IpcSharedBufferCore> core_;
+
+ DISALLOW_COPY_AND_ASSIGN(IpcSharedBuffer);
+};
+
DesktopSessionProxy::DesktopSessionProxy(
scoped_refptr<base::SingleThreadTaskRunner> audio_capture_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
@@ -215,7 +280,7 @@ void DesktopSessionProxy::DetachFromDesktop() {
// Generate fake responses to keep the video capturer in sync.
while (pending_capture_frame_requests_) {
--pending_capture_frame_requests_;
- PostCaptureCompleted(scoped_refptr<media::ScreenCaptureData>());
+ PostCaptureCompleted(scoped_ptr<webrtc::DesktopFrame>());
}
}
@@ -237,7 +302,7 @@ void DesktopSessionProxy::CaptureFrame() {
++pending_capture_frame_requests_;
SendToDesktop(new ChromotingNetworkDesktopMsg_CaptureFrame());
} else {
- PostCaptureCompleted(scoped_refptr<media::ScreenCaptureData>());
+ PostCaptureCompleted(scoped_ptr<webrtc::DesktopFrame>());
}
}
@@ -307,7 +372,7 @@ void DesktopSessionProxy::SetScreenResolution(
const ScreenResolution& resolution) {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
- if (!resolution.IsValid())
+ if (!resolution.IsEmpty())
return;
screen_resolution_ = resolution;
@@ -344,8 +409,8 @@ DesktopSessionProxy::~DesktopSessionProxy() {
}
}
-scoped_refptr<media::SharedBuffer> DesktopSessionProxy::GetSharedBuffer(
- int id) {
+scoped_refptr<DesktopSessionProxy::IpcSharedBufferCore>
+DesktopSessionProxy::GetSharedBufferCore(int id) {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
SharedBuffers::const_iterator i = shared_buffers_.find(id);
@@ -353,7 +418,7 @@ scoped_refptr<media::SharedBuffer> DesktopSessionProxy::GetSharedBuffer(
return i->second;
} else {
LOG(ERROR) << "Failed to find the shared buffer " << id;
- return scoped_refptr<media::SharedBuffer>();
+ return NULL;
}
}
@@ -380,38 +445,13 @@ void DesktopSessionProxy::OnCreateSharedBuffer(
uint32 size) {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
- scoped_refptr<media::SharedBuffer> shared_buffer;
+ scoped_refptr<IpcSharedBufferCore> shared_buffer =
+ new IpcSharedBufferCore(id, handle, desktop_process_, size);
-#if defined(OS_WIN)
- shared_buffer = new media::SharedBuffer(id, handle, desktop_process_, size);
-#elif defined(OS_POSIX)
- shared_buffer = new media::SharedBuffer(id, handle, size);
-#else
-#error Unsupported platform.
-#endif
-
- // Check if the buffer has been successfully mapped.
- bool mapped = shared_buffer->ptr() != NULL;
- if (!mapped) {
-#if defined(OS_WIN)
- LOG(ERROR) << "Failed to map a shared buffer: id=" << id
- << ", handle=" << handle
- << ", size=" << size;
-#elif defined(OS_POSIX)
- LOG(ERROR) << "Failed to map a shared buffer: id=" << id
- << ", handle.fd=" << handle.fd
- << ", size=" << size;
-#endif
- }
-
- if (mapped &&
+ if (shared_buffer->memory() != NULL &&
!shared_buffers_.insert(std::make_pair(id, shared_buffer)).second) {
LOG(ERROR) << "Duplicate shared buffer id " << id << " encountered";
}
-
- // Notify the desktop process that the buffer has been seen and can now be
- // safely deleted if needed.
- SendToDesktop(new ChromotingNetworkDesktopMsg_SharedBufferCreated(id));
}
void DesktopSessionProxy::OnReleaseSharedBuffer(int id) {
@@ -422,34 +462,28 @@ void DesktopSessionProxy::OnReleaseSharedBuffer(int id) {
}
void DesktopSessionProxy::OnCaptureCompleted(
- const SerializedCapturedData& serialized_data) {
+ const SerializedDesktopFrame& serialized_frame) {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
- // Assume that |serialized_data| is well formed because it was received from
+ // Assume that |serialized_frame| is well-formed because it was received from
// a more privileged process.
- scoped_refptr<media::ScreenCaptureData> capture_data;
- scoped_refptr<media::SharedBuffer> shared_buffer =
- GetSharedBuffer(serialized_data.shared_buffer_id);
- CHECK(shared_buffer);
-
- capture_data = new media::ScreenCaptureData(
- reinterpret_cast<uint8*>(shared_buffer->ptr()),
- serialized_data.bytes_per_row,
- serialized_data.dimensions);
- capture_data->set_capture_time_ms(serialized_data.capture_time_ms);
- capture_data->set_client_sequence_number(
- serialized_data.client_sequence_number);
- capture_data->set_dpi(serialized_data.dpi);
- capture_data->set_shared_buffer(shared_buffer);
-
- if (!serialized_data.dirty_region.empty()) {
- capture_data->mutable_dirty_region().setRects(
- &serialized_data.dirty_region[0],
- serialized_data.dirty_region.size());
+ scoped_refptr<IpcSharedBufferCore> shared_buffer_core =
+ GetSharedBufferCore(serialized_frame.shared_buffer_id);
+ CHECK(shared_buffer_core);
+
+ scoped_ptr<webrtc::DesktopFrame> frame(
+ new webrtc::SharedMemoryDesktopFrame(
+ serialized_frame.dimensions, serialized_frame.bytes_per_row,
+ new IpcSharedBuffer(shared_buffer_core)));
+ frame->set_capture_time_ms(serialized_frame.capture_time_ms);
+ frame->set_dpi(serialized_frame.dpi);
+
+ for (size_t i = 0; i < serialized_frame.dirty_region.size(); ++i) {
+ frame->mutable_updated_region()->AddRect(serialized_frame.dirty_region[i]);
}
--pending_capture_frame_requests_;
- PostCaptureCompleted(capture_data);
+ PostCaptureCompleted(frame.Pass());
}
void DesktopSessionProxy::OnCursorShapeChanged(
@@ -475,13 +509,13 @@ void DesktopSessionProxy::OnInjectClipboardEvent(
}
void DesktopSessionProxy::PostCaptureCompleted(
- scoped_refptr<media::ScreenCaptureData> capture_data) {
+ scoped_ptr<webrtc::DesktopFrame> frame) {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
video_capture_task_runner_->PostTask(
FROM_HERE,
base::Bind(&IpcVideoFrameCapturer::OnCaptureCompleted, video_capturer_,
- capture_data));
+ base::Passed(&frame)));
}
void DesktopSessionProxy::PostCursorShape(
diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h
index 34eac55..198bd6f 100644
--- a/remoting/host/desktop_session_proxy.h
+++ b/remoting/host/desktop_session_proxy.h
@@ -16,7 +16,6 @@
#include "ipc/ipc_listener.h"
#include "ipc/ipc_platform_file.h"
#include "media/video/capture/screen/screen_capturer.h"
-#include "media/video/capture/screen/shared_buffer.h"
#include "remoting/host/audio_capturer.h"
#include "remoting/host/desktop_environment.h"
#include "remoting/host/screen_resolution.h"
@@ -33,7 +32,7 @@ class ChannelProxy;
class Message;
} // namespace IPC
-struct SerializedCapturedData;
+struct SerializedDesktopFrame;
namespace remoting {
@@ -124,10 +123,15 @@ class DesktopSessionProxy
private:
friend class base::DeleteHelper<DesktopSessionProxy>;
friend struct DesktopSessionProxyTraits;
+
+ class IpcSharedBufferCore;
+ class IpcSharedBuffer;
+ typedef std::map<int, scoped_refptr<IpcSharedBufferCore> > SharedBuffers;
+
virtual ~DesktopSessionProxy();
// Returns a shared buffer from the list of known buffers.
- scoped_refptr<media::SharedBuffer> GetSharedBuffer(int id);
+ scoped_refptr<IpcSharedBufferCore> GetSharedBufferCore(int id);
// Handles AudioPacket notification from the desktop session agent.
void OnAudioPacket(const std::string& serialized_packet);
@@ -141,7 +145,7 @@ class DesktopSessionProxy
void OnReleaseSharedBuffer(int id);
// Handles CaptureCompleted notification from the desktop session agent.
- void OnCaptureCompleted(const SerializedCapturedData& serialized_data);
+ void OnCaptureCompleted(const SerializedDesktopFrame& serialized_frame);
// Handles CursorShapeChanged notification from the desktop session agent.
void OnCursorShapeChanged(const media::MouseCursorShape& cursor_shape);
@@ -150,9 +154,8 @@ class DesktopSessionProxy
void OnInjectClipboardEvent(const std::string& serialized_event);
// Posts OnCaptureCompleted() to |video_capturer_| on the video thread,
- // passing |capture_data|.
- void PostCaptureCompleted(
- scoped_refptr<media::ScreenCaptureData> capture_data);
+ // passing |frame|.
+ void PostCaptureCompleted(scoped_ptr<webrtc::DesktopFrame> frame);
// Posts OnCursorShapeChanged() to |video_capturer_| on the video thread,
// passing |cursor_shape|.
@@ -197,7 +200,8 @@ class DesktopSessionProxy
int pending_capture_frame_requests_;
- typedef std::map<int, scoped_refptr<media::SharedBuffer> > SharedBuffers;
+ // Shared memory buffers by Id. Each buffer is owned by the corresponding
+ // frame.
SharedBuffers shared_buffers_;
// Keeps the desired screen resolution so it can be passed to a newly attached
diff --git a/remoting/host/desktop_session_win.cc b/remoting/host/desktop_session_win.cc
index f263e82..36d7fb1 100644
--- a/remoting/host/desktop_session_win.cc
+++ b/remoting/host/desktop_session_win.cc
@@ -226,26 +226,22 @@ bool RdpSession::Initialize(const ScreenResolution& resolution) {
return false;
}
- // DaemonProcess::CreateDesktopSession() verifies that the resolution is
- // valid.
- DCHECK(resolution.IsValid());
-
ScreenResolution local_resolution = resolution;
// If the screen resolution is not specified, use the default screen
// resolution.
if (local_resolution.IsEmpty()) {
- local_resolution.dimensions_.set(kDefaultRdpScreenWidth,
- kDefaultRdpScreenHeight);
- local_resolution.dpi_.set(kDefaultRdpDpi, kDefaultRdpDpi);
+ local_resolution = ScreenResolution(
+ webrtc::DesktopSize(kDefaultRdpScreenWidth, kDefaultRdpScreenHeight),
+ webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
}
// Get the screen dimensions assuming the default DPI.
- SkISize host_size = local_resolution.ScaleDimensionsToDpi(
- SkIPoint::Make(kDefaultRdpDpi, kDefaultRdpDpi));
+ webrtc::DesktopSize host_size = local_resolution.ScaleDimensionsToDpi(
+ webrtc::DesktopVector(kDefaultRdpDpi, kDefaultRdpDpi));
// Make sure that the host resolution is within the limits supported by RDP.
- host_size = SkISize::Make(
+ host_size = webrtc::DesktopSize(
std::min(kMaxRdpScreenWidth,
std::max(kMinRdpScreenWidth, host_size.width())),
std::min(kMaxRdpScreenHeight,
diff --git a/remoting/host/ipc_desktop_environment_unittest.cc b/remoting/host/ipc_desktop_environment_unittest.cc
index 1318091..4e54b1d 100644
--- a/remoting/host/ipc_desktop_environment_unittest.cc
+++ b/remoting/host/ipc_desktop_environment_unittest.cc
@@ -32,6 +32,8 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkRegion.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
using testing::_;
using testing::AnyNumber;
@@ -199,7 +201,7 @@ class IpcDesktopEnvironmentTest : public testing::Test {
// The last |terminal_id| passed to ConnectTermina();
int terminal_id_;
- media::MockScreenCapturerDelegate screen_capturer_delegate_;
+ media::MockScreenCapturerCallback screen_capturer_callback_;
MockClientSessionControl client_session_control_;
base::WeakPtrFactory<ClientSessionControl> client_session_control_factory_;
@@ -440,7 +442,7 @@ TEST_F(IpcDesktopEnvironmentTest, CaptureFrame) {
// Start the input injector and screen capturer.
input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
- video_capturer_->Start(&screen_capturer_delegate_);
+ video_capturer_->Start(&screen_capturer_callback_);
// Run the message loop until the desktop is attached.
setup_run_loop_->Run();
@@ -454,12 +456,12 @@ TEST_F(IpcDesktopEnvironmentTest, CaptureFrame) {
.Times(0);
// Stop the test when the first frame is captured.
- EXPECT_CALL(screen_capturer_delegate_, OnCaptureCompleted(_))
+ EXPECT_CALL(screen_capturer_callback_, OnCaptureCompleted(_))
.WillOnce(InvokeWithoutArgs(
this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment));
// Capture a single frame.
- video_capturer_->CaptureFrame();
+ video_capturer_->Capture(webrtc::DesktopRegion());
task_runner_ = NULL;
io_task_runner_ = NULL;
@@ -475,7 +477,7 @@ TEST_F(IpcDesktopEnvironmentTest, Reattach) {
// Start the input injector and screen capturer.
input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
- video_capturer_->Start(&screen_capturer_delegate_);
+ video_capturer_->Start(&screen_capturer_callback_);
// Run the message loop until the desktop is attached.
setup_run_loop_->Run();
@@ -516,7 +518,7 @@ TEST_F(IpcDesktopEnvironmentTest, InjectClipboardEvent) {
// Start the input injector and screen capturer.
input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
- video_capturer_->Start(&screen_capturer_delegate_);
+ video_capturer_->Start(&screen_capturer_callback_);
// Run the message loop until the desktop is attached.
setup_run_loop_->Run();
@@ -551,7 +553,7 @@ TEST_F(IpcDesktopEnvironmentTest, InjectKeyEvent) {
// Start the input injector and screen capturer.
input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
- video_capturer_->Start(&screen_capturer_delegate_);
+ video_capturer_->Start(&screen_capturer_callback_);
// Run the message loop until the desktop is attached.
setup_run_loop_->Run();
@@ -586,7 +588,7 @@ TEST_F(IpcDesktopEnvironmentTest, InjectMouseEvent) {
// Start the input injector and screen capturer.
input_injector_->Start(clipboard_stub.PassAs<protocol::ClipboardStub>());
- video_capturer_->Start(&screen_capturer_delegate_);
+ video_capturer_->Start(&screen_capturer_callback_);
// Run the message loop until the desktop is attached.
setup_run_loop_->Run();
diff --git a/remoting/host/ipc_video_frame_capturer.cc b/remoting/host/ipc_video_frame_capturer.cc
index ccf72fb..695bf3c 100644
--- a/remoting/host/ipc_video_frame_capturer.cc
+++ b/remoting/host/ipc_video_frame_capturer.cc
@@ -5,40 +5,54 @@
#include "remoting/host/ipc_video_frame_capturer.h"
#include "media/video/capture/screen/mouse_cursor_shape.h"
-#include "media/video/capture/screen/screen_capture_data.h"
#include "remoting/host/desktop_session_proxy.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
namespace remoting {
IpcVideoFrameCapturer::IpcVideoFrameCapturer(
scoped_refptr<DesktopSessionProxy> desktop_session_proxy)
- : delegate_(NULL),
+ : callback_(NULL),
+ mouse_shape_observer_(NULL),
desktop_session_proxy_(desktop_session_proxy),
+ capture_pending_(false),
weak_factory_(this) {
}
IpcVideoFrameCapturer::~IpcVideoFrameCapturer() {
}
-void IpcVideoFrameCapturer::Start(Delegate* delegate) {
- delegate_ = delegate;
+void IpcVideoFrameCapturer::Start(Callback* callback) {
+ DCHECK(!callback_);
+ DCHECK(callback);
+ callback_ = callback;
desktop_session_proxy_->SetVideoCapturer(weak_factory_.GetWeakPtr());
}
-void IpcVideoFrameCapturer::CaptureFrame() {
+void IpcVideoFrameCapturer::SetMouseShapeObserver(
+ MouseShapeObserver* mouse_shape_observer) {
+ DCHECK(!mouse_shape_observer_);
+ DCHECK(mouse_shape_observer);
+ mouse_shape_observer_ = mouse_shape_observer;
+}
+
+void IpcVideoFrameCapturer::Capture(const webrtc::DesktopRegion& region) {
+ DCHECK(!capture_pending_);
+ capture_pending_ = true;
desktop_session_proxy_->CaptureFrame();
}
void IpcVideoFrameCapturer::OnCaptureCompleted(
- scoped_refptr<media::ScreenCaptureData> capture_data) {
- if (delegate_)
- delegate_->OnCaptureCompleted(capture_data);
+ scoped_ptr<webrtc::DesktopFrame> frame) {
+ DCHECK(capture_pending_);
+ capture_pending_ = false;
+ callback_->OnCaptureCompleted(frame.release());
}
void IpcVideoFrameCapturer::OnCursorShapeChanged(
scoped_ptr<media::MouseCursorShape> cursor_shape) {
- if (delegate_)
- delegate_->OnCursorShapeChanged(cursor_shape.Pass());
+ if (mouse_shape_observer_)
+ mouse_shape_observer_->OnCursorShapeChanged(cursor_shape.Pass());
}
} // namespace remoting
diff --git a/remoting/host/ipc_video_frame_capturer.h b/remoting/host/ipc_video_frame_capturer.h
index 8d6b90a..48ed750 100644
--- a/remoting/host/ipc_video_frame_capturer.h
+++ b/remoting/host/ipc_video_frame_capturer.h
@@ -29,24 +29,32 @@ class IpcVideoFrameCapturer : public media::ScreenCapturer {
scoped_refptr<DesktopSessionProxy> desktop_session_proxy);
virtual ~IpcVideoFrameCapturer();
+ // webrtc::DesktopCapturer interface.
+ virtual void Start(Callback* callback) OVERRIDE;
+ virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE;
+
// media::ScreenCapturer interface.
- virtual void Start(Delegate* delegate) OVERRIDE;
- virtual void CaptureFrame() OVERRIDE;
+ virtual void SetMouseShapeObserver(
+ MouseShapeObserver* mouse_shape_observer) OVERRIDE;
- // Called when a video frame has been captured. |capture_data| describes
- // a captured frame.
- void OnCaptureCompleted(scoped_refptr<media::ScreenCaptureData> capture_data);
+ // Called when a video |frame| has been captured.
+ void OnCaptureCompleted(scoped_ptr<webrtc::DesktopFrame> frame);
// Called when the cursor shape has changed.
void OnCursorShapeChanged(scoped_ptr<media::MouseCursorShape> cursor_shape);
private:
- // Points to the delegate passed to media::ScreenCapturer::Start().
- media::ScreenCapturer::Delegate* delegate_;
+ // Points to the callback passed to media::ScreenCapturer::Start().
+ media::ScreenCapturer::Callback* callback_;
+
+ MouseShapeObserver* mouse_shape_observer_;
// Wraps the IPC channel to the desktop session agent.
scoped_refptr<DesktopSessionProxy> desktop_session_proxy_;
+ // Set to true when a frame is being captured.
+ bool capture_pending_;
+
// Used to cancel tasks pending on the capturer when it is stopped.
base::WeakPtrFactory<IpcVideoFrameCapturer> weak_factory_;
diff --git a/remoting/host/resizing_host_observer.cc b/remoting/host/resizing_host_observer.cc
index 658a39b..ccb141f 100644
--- a/remoting/host/resizing_host_observer.cc
+++ b/remoting/host/resizing_host_observer.cc
@@ -116,15 +116,15 @@ void ResizingHostObserver::SetScreenResolution(
// If the implementation returns any sizes, pick the best one according to
// the algorithm described in CandidateSize::IsBetterThen.
- std::list<SkISize> sizes =
- desktop_resizer_->GetSupportedSizes(resolution.dimensions_);
- if (sizes.empty()) {
+ SkISize dimentions = SkISize::Make(
+ resolution.dimensions().width(), resolution.dimensions().height());
+ std::list<SkISize> sizes = desktop_resizer_->GetSupportedSizes(dimentions);
+ if (sizes.empty())
return;
- }
- CandidateSize best_size(sizes.front(), resolution.dimensions_);
+ CandidateSize best_size(sizes.front(), dimentions);
for (std::list<SkISize>::const_iterator i = ++sizes.begin();
i != sizes.end(); ++i) {
- CandidateSize candidate_size(*i, resolution.dimensions_);
+ CandidateSize candidate_size(*i, dimentions);
if (candidate_size.IsBetterThan(best_size)) {
best_size = candidate_size;
}
diff --git a/remoting/host/resizing_host_observer_unittest.cc b/remoting/host/resizing_host_observer_unittest.cc
index cc4019a..2d61e5e 100644
--- a/remoting/host/resizing_host_observer_unittest.cc
+++ b/remoting/host/resizing_host_observer_unittest.cc
@@ -11,6 +11,7 @@
#include "remoting/host/screen_resolution.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkSize.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
std::ostream& operator<<(std::ostream& os, const SkISize& size) {
return os << size.width() << "x" << size.height();
@@ -83,7 +84,8 @@ class ResizingHostObserverTest : public testing::Test {
SkISize GetBestSize(const SkISize& client_size) {
resizing_host_observer_->SetScreenResolution(ScreenResolution(
- client_size, SkIPoint::Make(kDefaultDPI, kDefaultDPI)));
+ webrtc::DesktopSize(client_size.width(), client_size.height()),
+ webrtc::DesktopVector(kDefaultDPI, kDefaultDPI)));
return desktop_resizer_->GetCurrentSize();
}
diff --git a/remoting/host/screen_resolution.cc b/remoting/host/screen_resolution.cc
index a8a7e68..b792cef 100644
--- a/remoting/host/screen_resolution.cc
+++ b/remoting/host/screen_resolution.cc
@@ -7,20 +7,27 @@
#include <algorithm>
#include <limits>
+#include "base/logging.h"
+
namespace remoting {
ScreenResolution::ScreenResolution()
- : dimensions_(SkISize::Make(0, 0)),
- dpi_(SkIPoint::Make(0, 0)) {
+ : dimensions_(webrtc::DesktopSize(0, 0)),
+ dpi_(webrtc::DesktopVector(0, 0)) {
}
-ScreenResolution::ScreenResolution(const SkISize& dimensions,
- const SkIPoint& dpi)
+ScreenResolution::ScreenResolution(const webrtc::DesktopSize& dimensions,
+ const webrtc::DesktopVector& dpi)
: dimensions_(dimensions),
dpi_(dpi) {
+ // Check that dimensions are not negative.
+ DCHECK(!dimensions.is_empty() || dimensions.equals(webrtc::DesktopSize()));
+ DCHECK_GE(dpi.x(), 0);
+ DCHECK_GE(dpi.y(), 0);
}
-SkISize ScreenResolution::ScaleDimensionsToDpi(const SkIPoint& new_dpi) const {
+webrtc::DesktopSize ScreenResolution::ScaleDimensionsToDpi(
+ const webrtc::DesktopVector& new_dpi) const {
int64 width = dimensions_.width();
int64 height = dimensions_.height();
@@ -29,15 +36,11 @@ SkISize ScreenResolution::ScaleDimensionsToDpi(const SkIPoint& new_dpi) const {
static_cast<int64>(std::numeric_limits<int32>::max()));
height = std::min(height * new_dpi.y() / dpi_.y(),
static_cast<int64>(std::numeric_limits<int32>::max()));
- return SkISize::Make(static_cast<int32>(width), static_cast<int32>(height));
+ return webrtc::DesktopSize(width, height);
}
bool ScreenResolution::IsEmpty() const {
- return dimensions_.isEmpty() || dpi_.x() <= 0 || dpi_.y() <= 0;
-}
-
-bool ScreenResolution::IsValid() const {
- return !IsEmpty() || dimensions_.isZero();
+ return dimensions_.is_empty() || dpi_.is_zero();
}
} // namespace remoting
diff --git a/remoting/host/screen_resolution.h b/remoting/host/screen_resolution.h
index d09eb64..81690db 100644
--- a/remoting/host/screen_resolution.h
+++ b/remoting/host/screen_resolution.h
@@ -7,8 +7,7 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "third_party/skia/include/core/SkPoint.h"
-#include "third_party/skia/include/core/SkSize.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
namespace remoting {
@@ -16,25 +15,26 @@ namespace remoting {
class ScreenResolution {
public:
ScreenResolution();
-
- ScreenResolution(const SkISize& dimensions, const SkIPoint& dpi);
+ ScreenResolution(const webrtc::DesktopSize& dimensions,
+ const webrtc::DesktopVector& dpi);
// Returns the screen dimensions scaled according to the passed |new_dpi|.
- SkISize ScaleDimensionsToDpi(const SkIPoint& new_dpi) const;
+ webrtc::DesktopSize ScaleDimensionsToDpi(
+ const webrtc::DesktopVector& new_dpi) const;
+
+ // Dimensions of the screen in pixels.
+ const webrtc::DesktopSize& dimensions() const { return dimensions_; }
+
+ // The vertical and horizontal DPI of the screen.
+ const webrtc::DesktopVector& dpi() const { return dpi_; }
// Returns true if |dimensions_| specifies an empty rectangle or when
// IsValid() returns false.
bool IsEmpty() const;
- // Returns true if both |dimensions_| and |dpi_| are valid. |dimensions_|
- // specifying an empty rectangle is considered to be valid.
- bool IsValid() const;
-
- // Dimensions of the screen in pixels.
- SkISize dimensions_;
-
- // The vertical and horizontal DPI of the screen.
- SkIPoint dpi_;
+ private:
+ webrtc::DesktopSize dimensions_;
+ webrtc::DesktopVector dpi_;
};
} // namespace remoting
diff --git a/remoting/host/screen_resolution_unittest.cc b/remoting/host/screen_resolution_unittest.cc
index dce7bc0..01de134 100644
--- a/remoting/host/screen_resolution_unittest.cc
+++ b/remoting/host/screen_resolution_unittest.cc
@@ -12,69 +12,38 @@
namespace remoting {
TEST(ScreenResolutionTest, Empty) {
- ScreenResolution resolution;
- EXPECT_TRUE(resolution.IsEmpty());
+ ScreenResolution resolution1(
+ webrtc::DesktopSize(100, 100), webrtc::DesktopVector(10, 10));
+ EXPECT_FALSE(resolution1.IsEmpty());
- resolution.dimensions_.set(-1, 0);
- EXPECT_TRUE(resolution.IsEmpty());
+ ScreenResolution resolution2(
+ webrtc::DesktopSize(), webrtc::DesktopVector(10, 10));
+ EXPECT_TRUE(resolution2.IsEmpty());
- resolution.dimensions_.set(0, -1);
- EXPECT_TRUE(resolution.IsEmpty());
-
- resolution.dimensions_.set(-1, -1);
- EXPECT_TRUE(resolution.IsEmpty());
-
- resolution.dpi_.set(-1, 0);
- EXPECT_TRUE(resolution.IsEmpty());
-
- resolution.dpi_.set(0, -1);
- EXPECT_TRUE(resolution.IsEmpty());
-
- resolution.dpi_.set(-1, -1);
- EXPECT_TRUE(resolution.IsEmpty());
-}
-
-TEST(ScreenResolutionTest, Invalid) {
- ScreenResolution resolution;
- EXPECT_TRUE(resolution.IsValid());
-
- resolution.dimensions_.set(-1, 0);
- EXPECT_FALSE(resolution.IsValid());
-
- resolution.dimensions_.set(0, -1);
- EXPECT_FALSE(resolution.IsValid());
-
- resolution.dimensions_.set(-1, -1);
- EXPECT_FALSE(resolution.IsValid());
-
- resolution.dpi_.set(-1, 0);
- EXPECT_FALSE(resolution.IsValid());
-
- resolution.dpi_.set(0, -1);
- EXPECT_FALSE(resolution.IsValid());
-
- resolution.dpi_.set(-1, -1);
- EXPECT_FALSE(resolution.IsValid());
+ ScreenResolution resolution3(
+ webrtc::DesktopSize(1, 1), webrtc::DesktopVector(0, 0));
+ EXPECT_TRUE(resolution3.IsEmpty());
}
TEST(ScreenResolutionTest, Scaling) {
ScreenResolution resolution(
- SkISize::Make(100, 100), SkIPoint::Make(10, 10));
+ webrtc::DesktopSize(100, 100), webrtc::DesktopVector(10, 10));
- EXPECT_EQ(resolution.ScaleDimensionsToDpi(SkIPoint::Make(5, 5)),
- SkISize::Make(50, 50));
+ EXPECT_TRUE(webrtc::DesktopSize(50, 50).equals(
+ resolution.ScaleDimensionsToDpi(webrtc::DesktopVector(5, 5))));
- EXPECT_EQ(resolution.ScaleDimensionsToDpi(SkIPoint::Make(20, 20)),
- SkISize::Make(200, 200));
+ EXPECT_TRUE(webrtc::DesktopSize(200, 200).equals(
+ resolution.ScaleDimensionsToDpi(webrtc::DesktopVector(20, 20))));
}
TEST(ScreenResolutionTest, ScalingSaturation) {
ScreenResolution resolution(
- SkISize::Make(10000000, 1000000), SkIPoint::Make(1, 1));
+ webrtc::DesktopSize(10000000, 1000000), webrtc::DesktopVector(1, 1));
- EXPECT_EQ(resolution.ScaleDimensionsToDpi(SkIPoint::Make(1000000, 1000000)),
- SkISize::Make(std::numeric_limits<int32>::max(),
- std::numeric_limits<int32>::max()));
+ int32 max_int = std::numeric_limits<int32>::max();
+ EXPECT_TRUE(webrtc::DesktopSize(max_int, max_int).equals(
+ resolution.ScaleDimensionsToDpi(
+ webrtc::DesktopVector(1000000, 1000000))));
}
} // namespace remoting
diff --git a/remoting/host/video_scheduler.cc b/remoting/host/video_scheduler.cc
index 41c3dcc..f7db4c2 100644
--- a/remoting/host/video_scheduler.cc
+++ b/remoting/host/video_scheduler.cc
@@ -15,7 +15,6 @@
#include "base/sys_info.h"
#include "base/time.h"
#include "media/video/capture/screen/mouse_cursor_shape.h"
-#include "media/video/capture/screen/screen_capture_data.h"
#include "media/video/capture/screen/screen_capturer.h"
#include "remoting/proto/control.pb.h"
#include "remoting/proto/internal.pb.h"
@@ -24,12 +23,13 @@
#include "remoting/protocol/message_decoder.h"
#include "remoting/protocol/video_stub.h"
#include "remoting/protocol/util.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
namespace remoting {
// Maximum number of frames that can be processed simultaneously.
// TODO(hclam): Move this value to CaptureScheduler.
-static const int kMaxPendingCaptures = 2;
+static const int kMaxPendingFrames = 2;
VideoScheduler::VideoScheduler(
scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner,
@@ -46,7 +46,8 @@ VideoScheduler::VideoScheduler(
encoder_(encoder.Pass()),
cursor_stub_(cursor_stub),
video_stub_(video_stub),
- pending_captures_(0),
+ pending_frames_(0),
+ capture_pending_(false),
did_skip_frame_(false),
is_paused_(false),
sequence_number_(0) {
@@ -59,28 +60,31 @@ VideoScheduler::VideoScheduler(
// Public methods --------------------------------------------------------------
-void VideoScheduler::OnCaptureCompleted(
- scoped_refptr<media::ScreenCaptureData> capture_data) {
+webrtc::SharedMemory* VideoScheduler::CreateSharedMemory(size_t size) {
+ return NULL;
+}
+
+void VideoScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
DCHECK(capture_task_runner_->BelongsToCurrentThread());
- // Do nothing if the scheduler is being stopped.
- if (!capturer_)
- return;
+ capture_pending_ = false;
- if (capture_data) {
+ scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
+
+ if (frame) {
scheduler_.RecordCaptureTime(
- base::TimeDelta::FromMilliseconds(capture_data->capture_time_ms()));
-
- // The best way to get this value is by binding the sequence number to
- // the callback when calling CaptureInvalidRects(). However the callback
- // system doesn't allow this. Reading from the member variable is
- // accurate as long as capture is synchronous as the following statement
- // will obtain the most recent sequence number received.
- capture_data->set_client_sequence_number(sequence_number_);
+ base::TimeDelta::FromMilliseconds(frame->capture_time_ms()));
}
encode_task_runner_->PostTask(
- FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this, capture_data));
+ FROM_HERE, base::Bind(&VideoScheduler::EncodeFrame, this,
+ base::Passed(&owned_frame), sequence_number_));
+
+ // If a frame was skipped, try to capture it again.
+ if (did_skip_frame_) {
+ capture_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VideoScheduler::CaptureNextFrame, this));
+ }
}
void VideoScheduler::OnCursorShapeChanged(
@@ -163,6 +167,7 @@ void VideoScheduler::StartOnCaptureThread() {
DCHECK(!capture_timer_);
// Start the capturer and let it notify us if cursor shape changes.
+ capturer_->SetMouseShapeObserver(this);
capturer_->Start(this);
capture_timer_.reset(new base::OneShotTimer<VideoScheduler>());
@@ -174,17 +179,12 @@ void VideoScheduler::StartOnCaptureThread() {
void VideoScheduler::StopOnCaptureThread() {
DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ // This doesn't deleted already captured frames, so encoder can keep using the
+ // frames that were captured previously.
+ capturer_.reset();
+
// |capture_timer_| must be destroyed on the thread on which it is used.
capture_timer_.reset();
-
- // Schedule deletion of |capturer_| once the encode thread is no longer
- // processing capture data. See http://crbug.com/163641. This also clears
- // |capturer_| pointer to prevent pending tasks from using it.
- // TODO(wez): Make it safe to tear down capturer while buffers remain, and
- // remove this work-around.
- encode_task_runner_->PostTask(
- FROM_HERE, base::Bind(&VideoScheduler::StopOnEncodeThread, this,
- base::Passed(&capturer_)));
}
void VideoScheduler::ScheduleNextCapture() {
@@ -203,10 +203,10 @@ void VideoScheduler::CaptureNextFrame() {
if (!capturer_ || is_paused_)
return;
- // Make sure we have at most two oustanding recordings. We can simply return
+ // Make sure we have at most two outstanding recordings. We can simply return
// if we can't make a capture now, the next capture will be started by the
// end of an encode operation.
- if (pending_captures_ >= kMaxPendingCaptures) {
+ if (pending_frames_ >= kMaxPendingFrames || capture_pending_) {
did_skip_frame_ = true;
return;
}
@@ -214,22 +214,24 @@ void VideoScheduler::CaptureNextFrame() {
did_skip_frame_ = false;
// At this point we are going to perform one capture so save the current time.
- pending_captures_++;
- DCHECK_LE(pending_captures_, kMaxPendingCaptures);
+ pending_frames_++;
+ DCHECK_LE(pending_frames_, kMaxPendingFrames);
// Before doing a capture schedule for the next one.
ScheduleNextCapture();
+ capture_pending_ = true;
+
// And finally perform one capture.
- capturer_->CaptureFrame();
+ capturer_->Capture(webrtc::DesktopRegion());
}
void VideoScheduler::FrameCaptureCompleted() {
DCHECK(capture_task_runner_->BelongsToCurrentThread());
// Decrement the pending capture count.
- pending_captures_--;
- DCHECK_GE(pending_captures_, 0);
+ pending_frames_--;
+ DCHECK_GE(pending_frames_, 0);
// If we've skipped a frame capture because too we had too many captures
// pending then schedule one now.
@@ -275,28 +277,35 @@ void VideoScheduler::SendCursorShape(
// Encoder thread --------------------------------------------------------------
void VideoScheduler::EncodeFrame(
- scoped_refptr<media::ScreenCaptureData> capture_data) {
+ scoped_ptr<webrtc::DesktopFrame> frame,
+ int sequence_number) {
DCHECK(encode_task_runner_->BelongsToCurrentThread());
// If there is nothing to encode then send an empty keep-alive packet.
- if (!capture_data || capture_data->dirty_region().isEmpty()) {
+ if (!frame || frame->updated_region().is_empty()) {
scoped_ptr<VideoPacket> packet(new VideoPacket());
packet->set_flags(VideoPacket::LAST_PARTITION);
+ packet->set_sequence_number(sequence_number);
network_task_runner_->PostTask(
FROM_HERE, base::Bind(&VideoScheduler::SendVideoPacket, this,
base::Passed(&packet)));
+ capture_task_runner_->DeleteSoon(FROM_HERE, frame.release());
return;
}
encoder_->Encode(
- capture_data, false,
- base::Bind(&VideoScheduler::EncodedDataAvailableCallback, this));
+ frame.get(), base::Bind(&VideoScheduler::EncodedDataAvailableCallback,
+ this, sequence_number));
+ capture_task_runner_->DeleteSoon(FROM_HERE, frame.release());
}
void VideoScheduler::EncodedDataAvailableCallback(
+ int sequence_number,
scoped_ptr<VideoPacket> packet) {
DCHECK(encode_task_runner_->BelongsToCurrentThread());
+ packet->set_sequence_number(sequence_number);
+
bool last = (packet->flags() & VideoPacket::LAST_PACKET) != 0;
if (last) {
scheduler_.RecordEncodeTime(
@@ -308,14 +317,4 @@ void VideoScheduler::EncodedDataAvailableCallback(
base::Passed(&packet)));
}
-void VideoScheduler::StopOnEncodeThread(
- scoped_ptr<media::ScreenCapturer> capturer) {
- DCHECK(encode_task_runner_->BelongsToCurrentThread());
-
- // This is posted by StopOnCaptureThread, so we know that by the time we
- // process it there are no more encode tasks queued. Pass |capturer| for
- // deletion on the capture thread.
- capture_task_runner_->DeleteSoon(FROM_HERE, capturer.release());
-}
-
} // namespace remoting
diff --git a/remoting/host/video_scheduler.h b/remoting/host/video_scheduler.h
index d26c394..16f6247 100644
--- a/remoting/host/video_scheduler.h
+++ b/remoting/host/video_scheduler.h
@@ -23,7 +23,6 @@ class SingleThreadTaskRunner;
} // namespace base
namespace media {
-class ScreenCaptureData;
class ScreenCapturer;
} // namespace media
@@ -74,7 +73,8 @@ class VideoStub;
// too much CPU, or hogging the host's graphics subsystem.
class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>,
- public media::ScreenCapturer::Delegate {
+ public webrtc::DesktopCapturer::Callback,
+ public media::ScreenCapturer::MouseShapeObserver {
public:
// Creates a VideoScheduler running capture, encode and network tasks on the
// supplied TaskRunners. Video and cursor shape updates will be pumped to
@@ -89,9 +89,11 @@ class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>,
protocol::CursorShapeStub* cursor_stub,
protocol::VideoStub* video_stub);
- // media::ScreenCapturer::Delegate implementation.
- virtual void OnCaptureCompleted(
- scoped_refptr<media::ScreenCaptureData> capture_data) OVERRIDE;
+ // webrtc::DesktopCapturer::Callback implementation.
+ virtual webrtc::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE;
+ virtual void OnCaptureCompleted(webrtc::DesktopFrame* frame) OVERRIDE;
+
+ // media::ScreenCapturer::MouseShapeObserver implementation.
virtual void OnCursorShapeChanged(
scoped_ptr<media::MouseCursorShape> cursor_shape) OVERRIDE;
@@ -119,8 +121,7 @@ class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>,
// Starts the capturer on the capture thread.
void StartOnCaptureThread();
- // Stops scheduling frame captures on the capture thread, and posts
- // StopOnEncodeThread() to the network thread when done.
+ // Stops scheduling frame captures on the capture thread.
void StopOnCaptureThread();
// Schedules the next call to CaptureNextFrame.
@@ -147,13 +148,11 @@ class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>,
// Encoder thread -----------------------------------------------------------
// Encode a frame, passing generated VideoPackets to SendVideoPacket().
- void EncodeFrame(scoped_refptr<media::ScreenCaptureData> capture_data);
-
- void EncodedDataAvailableCallback(scoped_ptr<VideoPacket> packet);
+ void EncodeFrame(scoped_ptr<webrtc::DesktopFrame> frame,
+ int sequence_number);
- // Used to synchronize capture and encode thread teardown, notifying the
- // network thread when done.
- void StopOnEncodeThread(scoped_ptr<media::ScreenCapturer> capturer);
+ void EncodedDataAvailableCallback(int sequence_number,
+ scoped_ptr<VideoPacket> packet);
// Task runners used by this class.
scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_;
@@ -174,8 +173,13 @@ class VideoScheduler : public base::RefCountedThreadSafe<VideoScheduler>,
// Timer used to schedule CaptureNextFrame().
scoped_ptr<base::OneShotTimer<VideoScheduler> > capture_timer_;
- // Count the number of recordings (i.e. capture or encode) happening.
- int pending_captures_;
+ // The number of frames being processed, i.e. frames that we are currently
+ // capturing, encoding or sending. The value is capped at 2 to minimize
+ // latency.
+ int pending_frames_;
+
+ // Set when the capturer is capturing a frame.
+ bool capture_pending_;
// True if the previous scheduled capture was skipped.
bool did_skip_frame_;
diff --git a/remoting/host/video_scheduler_unittest.cc b/remoting/host/video_scheduler_unittest.cc
index 44010af..7bf17fc 100644
--- a/remoting/host/video_scheduler_unittest.cc
+++ b/remoting/host/video_scheduler_unittest.cc
@@ -7,7 +7,6 @@
#include "base/bind.h"
#include "base/message_loop.h"
#include "base/run_loop.h"
-#include "media/video/capture/screen/screen_capture_data.h"
#include "media/video/capture/screen/screen_capturer_mock_objects.h"
#include "remoting/base/auto_thread_task_runner.h"
#include "remoting/codec/video_encoder.h"
@@ -15,6 +14,7 @@
#include "remoting/protocol/protocol_mock_objects.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
using ::remoting::protocol::MockClientStub;
using ::remoting::protocol::MockVideoStub;
@@ -38,7 +38,7 @@ namespace {
ACTION(FinishEncode) {
scoped_ptr<VideoPacket> packet(new VideoPacket());
packet->set_flags(VideoPacket::LAST_PACKET | VideoPacket::LAST_PARTITION);
- arg2.Run(packet.Pass());
+ arg1.Run(packet.Pass());
}
ACTION(FinishSend) {
@@ -55,9 +55,8 @@ class MockVideoEncoder : public VideoEncoder {
MockVideoEncoder();
virtual ~MockVideoEncoder();
- MOCK_METHOD3(Encode, void(
- scoped_refptr<media::ScreenCaptureData> capture_data,
- bool key_frame,
+ MOCK_METHOD2(Encode, void(
+ const webrtc::DesktopFrame* frame,
const DataAvailableCallback& data_available_callback));
private:
@@ -78,9 +77,8 @@ class VideoSchedulerTest : public testing::Test {
void StopVideoScheduler();
// media::ScreenCapturer mocks.
- void OnCapturerStart(media::ScreenCapturer::Delegate* delegate);
- void OnCapturerStop();
- void OnCaptureFrame();
+ void OnCapturerStart(media::ScreenCapturer::Callback* callback);
+ void OnCaptureFrame(const webrtc::DesktopRegion& region);
protected:
base::MessageLoop message_loop_;
@@ -94,10 +92,10 @@ class VideoSchedulerTest : public testing::Test {
// The following mock objects are owned by VideoScheduler.
MockVideoEncoder* encoder_;
- scoped_refptr<media::ScreenCaptureData> data_;
+ scoped_ptr<webrtc::DesktopFrame> frame_;
- // Points to the delegate passed to media::ScreenCapturer::Start().
- media::ScreenCapturer::Delegate* capturer_delegate_;
+ // Points to the callback passed to media::ScreenCapturer::Start().
+ media::ScreenCapturer::Callback* capturer_callback_;
private:
DISALLOW_COPY_AND_ASSIGN(VideoSchedulerTest);
@@ -105,7 +103,7 @@ class VideoSchedulerTest : public testing::Test {
VideoSchedulerTest::VideoSchedulerTest()
: encoder_(NULL),
- capturer_delegate_(NULL) {
+ capturer_callback_(NULL) {
}
void VideoSchedulerTest::SetUp() {
@@ -134,22 +132,17 @@ void VideoSchedulerTest::StopVideoScheduler() {
}
void VideoSchedulerTest::OnCapturerStart(
- media::ScreenCapturer::Delegate* delegate) {
- EXPECT_FALSE(capturer_delegate_);
- EXPECT_TRUE(delegate);
+ media::ScreenCapturer::Callback* callback) {
+ EXPECT_FALSE(capturer_callback_);
+ EXPECT_TRUE(callback);
- capturer_delegate_ = delegate;
+ capturer_callback_ = callback;
}
-void VideoSchedulerTest::OnCapturerStop() {
- capturer_delegate_ = NULL;
-}
-
-void VideoSchedulerTest::OnCaptureFrame() {
- SkRegion update_region(SkIRect::MakeXYWH(0, 0, 10, 10));
- data_->mutable_dirty_region().op(update_region, SkRegion::kUnion_Op);
-
- capturer_delegate_->OnCaptureCompleted(data_);
+void VideoSchedulerTest::OnCaptureFrame(const webrtc::DesktopRegion& region) {
+ frame_->mutable_updated_region()->SetRect(
+ webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10));
+ capturer_callback_->OnCaptureCompleted(frame_.release());
}
// This test mocks capturer, encoder and network layer to simulate one capture
@@ -163,17 +156,17 @@ TEST_F(VideoSchedulerTest, StartAndStop) {
EXPECT_CALL(*capturer, Start(_))
.WillOnce(Invoke(this, &VideoSchedulerTest::OnCapturerStart));
- data_ = new media::ScreenCaptureData(
- NULL, kWidth * media::ScreenCaptureData::kBytesPerPixel,
- SkISize::Make(kWidth, kHeight));
+ frame_.reset(new webrtc::BasicDesktopFrame(
+ webrtc::DesktopSize(kWidth, kHeight)));
+ webrtc::DesktopFrame* frame_ptr = frame_.get();
// First the capturer is called.
- Expectation capturer_capture = EXPECT_CALL(*capturer, CaptureFrame())
+ Expectation capturer_capture = EXPECT_CALL(*capturer, Capture(_))
.After(capturer_start)
.WillRepeatedly(Invoke(this, &VideoSchedulerTest::OnCaptureFrame));
// Expect the encoder be called.
- EXPECT_CALL(*encoder_, Encode(data_, false, _))
+ EXPECT_CALL(*encoder_, Encode(frame_ptr, _))
.WillRepeatedly(FinishEncode());
// By default delete the arguments when ProcessVideoPacket is received.
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 1c4a1d0..b185270 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -300,6 +300,7 @@
'../google_apis/google_apis.gyp:google_apis',
'../media/media.gyp:media',
'../ipc/ipc.gyp:ipc',
+ '../third_party/webrtc/modules/modules.gyp:desktop_capture',
],
'defines': [
'VERSION=<(version_full)',
@@ -326,6 +327,8 @@
'host/chromoting_host_context.h',
'host/chromoting_messages.cc',
'host/chromoting_messages.h',
+ 'host/chromoting_param_traits.cc',
+ 'host/chromoting_param_traits.h',
'host/client_session.cc',
'host/client_session.h',
'host/client_session_control.h',
@@ -358,7 +361,7 @@
'host/dns_blackhole_checker.h',
'host/heartbeat_sender.cc',
'host/heartbeat_sender.h',
- 'host/host_change_notification_listener.cc',
+ 'host/host_change_notification_listener.cc',
'host/host_change_notification_listener.h',
'host/host_config.cc',
'host/host_config.h',
@@ -1429,6 +1432,7 @@
'remoting_me2me_host_static',
'remoting_protocol',
'remoting_version_resources',
+ '../third_party/webrtc/modules/modules.gyp:desktop_capture',
],
'sources': [
'<(SHARED_INTERMEDIATE_DIR)/remoting/host/chromoting_lib.rc',
@@ -2263,6 +2267,7 @@
'remoting_jingle_glue',
'remoting_resources',
'proto/chromotocol.gyp:chromotocol_proto_lib',
+ '../third_party/webrtc/modules/modules.gyp:desktop_capture',
],
'export_dependent_settings': [
'../base/base.gyp:base',
@@ -2558,6 +2563,7 @@
'remoting_jingle_glue',
'remoting_protocol',
'remoting_resources',
+ '../third_party/webrtc/modules/modules.gyp:desktop_capture',
],
'defines': [
'VERSION=<(version_full)',