1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/codec/video_encoder_vpx.h"
6
7#include <limits>
8#include <vector>
9
10#include "base/memory/scoped_ptr.h"
11#include "remoting/codec/codec_test.h"
12#include "remoting/proto/video.pb.h"
13#include "testing/gtest/include/gtest/gtest.h"
14#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
15
16namespace remoting {
17
18// xRGB pixel colors for use by tests.
19const uint32 kBlueColor = 0x0000ff;
20const uint32 kGreenColor = 0x00ff00;
21
22// Creates a frame stippled between blue and red pixels, which is useful for
23// lossy/lossless encode and color tests.
24static scoped_ptr<webrtc::DesktopFrame> CreateTestFrame(
25    const webrtc::DesktopSize& frame_size) {
26  scoped_ptr<webrtc::DesktopFrame> frame(
27      new webrtc::BasicDesktopFrame(frame_size));
28  for (int x = 0; x < frame_size.width(); ++x) {
29    for (int y = 0; y < frame_size.height(); ++y) {
30      uint8* pixel_u8 = frame->data() + (y * frame->stride()) +
31          (x * webrtc::DesktopFrame::kBytesPerPixel);
32      *(reinterpret_cast<uint32*>(pixel_u8)) =
33          ((x + y) & 1) ? kGreenColor : kBlueColor;
34    }
35  }
36  return frame.Pass();
37}
38
39TEST(VideoEncoderVpxTest, TestVp8VideoEncoder) {
40  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
41  TestVideoEncoder(encoder.get(), false);
42}
43
44TEST(VideoEncoderVpxTest, TestVp9VideoEncoder) {
45  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
46  // VP9 encoder defaults to lossless encode and lossy (I420) color.
47  TestVideoEncoder(encoder.get(), false);
48}
49
50// Test that the VP9 encoder can switch between lossy & lossless encode.
51TEST(VideoEncoderVpxTest, TestVp9VideoEncoderLossyEncode) {
52  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
53
54  webrtc::DesktopSize frame_size(1024, 768);
55  scoped_ptr<webrtc::DesktopFrame> frame(CreateTestFrame(frame_size));
56  frame->mutable_updated_region()->SetRect(
57      webrtc::DesktopRect::MakeSize(frame_size));
58
59  // Lossy encode the first frame.
60  encoder->SetLosslessEncode(false);
61  scoped_ptr<VideoPacket> lossy_packet = encoder->Encode(*frame);
62
63  // Lossless encode the second frame.
64  encoder->SetLosslessEncode(true);
65  scoped_ptr<VideoPacket> lossless_packet = encoder->Encode(*frame);
66  EXPECT_GT(lossless_packet->data().size(), lossy_packet->data().size());
67
68  // Lossy encode one more frame.
69  encoder->SetLosslessEncode(false);
70  lossy_packet = encoder->Encode(*frame);
71  EXPECT_LT(lossy_packet->data().size(), lossless_packet->data().size());
72}
73
74// Test that the VP9 encoder can switch between lossy & lossless color.
75TEST(VideoEncoderVpxTest, TestVp9VideoEncoderLossyColor) {
76  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
77
78  webrtc::DesktopSize frame_size(1024, 768);
79  scoped_ptr<webrtc::DesktopFrame> frame(CreateTestFrame(frame_size));
80  frame->mutable_updated_region()->SetRect(
81      webrtc::DesktopRect::MakeSize(frame_size));
82
83  // Lossy encode the first frame.
84  encoder->SetLosslessColor(false);
85  scoped_ptr<VideoPacket> lossy_packet = encoder->Encode(*frame);
86
87  // Lossless encode the second frame.
88  encoder->SetLosslessColor(true);
89  scoped_ptr<VideoPacket> lossless_packet = encoder->Encode(*frame);
90  EXPECT_GT(lossless_packet->data().size(), lossy_packet->data().size());
91
92  // Lossy encode one more frame.
93  encoder->SetLosslessColor(false);
94  lossy_packet = encoder->Encode(*frame);
95  EXPECT_LT(lossy_packet->data().size(), lossless_packet->data().size());
96}
97
98// Test that the VP8 encoder ignores lossless modes without crashing.
99TEST(VideoEncoderVpxTest, TestVp8VideoEncoderIgnoreLossy) {
100  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
101
102  webrtc::DesktopSize frame_size(1024, 768);
103  scoped_ptr<webrtc::DesktopFrame> frame(CreateTestFrame(frame_size));
104  frame->mutable_updated_region()->SetRect(
105      webrtc::DesktopRect::MakeSize(frame_size));
106
107  // Encode a frame, to give the encoder a chance to crash if misconfigured.
108  encoder->SetLosslessEncode(true);
109  encoder->SetLosslessColor(true);
110  scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
111  EXPECT_TRUE(packet);
112}
113
114// Test that calling Encode with a differently-sized media::ScreenCaptureData
115// does not leak memory.
116TEST(VideoEncoderVpxTest, TestSizeChangeNoLeak) {
117  webrtc::DesktopSize frame_size(1000, 1000);
118
119  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
120
121  // Create first frame & encode it.
122  scoped_ptr<webrtc::DesktopFrame> frame(CreateTestFrame(frame_size));
123  frame->mutable_updated_region()->SetRect(
124      webrtc::DesktopRect::MakeSize(frame_size));
125  scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
126  EXPECT_TRUE(packet);
127
128  // Halve the size of the frame, and updated region, and encode again.
129  frame_size.set(frame_size.width(), frame_size.height() / 2);
130  frame = CreateTestFrame(frame_size);
131  frame->mutable_updated_region()->SetRect(
132      webrtc::DesktopRect::MakeSize(frame_size));
133  packet = encoder->Encode(*frame);
134  EXPECT_TRUE(packet);
135}
136
137// Test that the DPI information is correctly propagated from the
138// media::ScreenCaptureData to the VideoPacket.
139TEST(VideoEncoderVpxTest, TestDpiPropagation) {
140  webrtc::DesktopSize frame_size(32, 32);
141
142  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
143
144  scoped_ptr<webrtc::DesktopFrame> frame(CreateTestFrame(frame_size));
145  frame->set_dpi(webrtc::DesktopVector(96, 97));
146  scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
147  EXPECT_EQ(packet->format().x_dpi(), 96);
148  EXPECT_EQ(packet->format().y_dpi(), 97);
149}
150
151}  // namespace remoting
152