18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "remoting/codec/video_encoder_vpx.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/codec/codec_test.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/proto/video.pb.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace remoting {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// xRGB pixel colors for use by tests.
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const uint32 kBlueColor = 0x0000ff;
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const uint32 kGreenColor = 0x00ff00;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Creates a frame stippled between blue and red pixels, which is useful for
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// lossy/lossless encode and color tests.
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)static scoped_ptr<webrtc::DesktopFrame> CreateTestFrame(
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const webrtc::DesktopSize& frame_size) {
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<webrtc::DesktopFrame> frame(
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new webrtc::BasicDesktopFrame(frame_size));
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (int x = 0; x < frame_size.width(); ++x) {
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (int y = 0; y < frame_size.height(); ++y) {
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      uint8* pixel_u8 = frame->data() + (y * frame->stride()) +
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          (x * webrtc::DesktopFrame::kBytesPerPixel);
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      *(reinterpret_cast<uint32*>(pixel_u8)) =
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          ((x + y) & 1) ? kGreenColor : kBlueColor;
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return frame.Pass();
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST(VideoEncoderVpxTest, TestVp8VideoEncoder) {
408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  TestVideoEncoder(encoder.get(), false);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST(VideoEncoderVpxTest, TestVp9VideoEncoder) {
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // VP9 encoder defaults to lossless encode and lossy (I420) color.
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  TestVideoEncoder(encoder.get(), false);
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Test that the VP9 encoder can switch between lossy & lossless encode.
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST(VideoEncoderVpxTest, TestVp9VideoEncoderLossyEncode) {
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  webrtc::DesktopSize frame_size(1024, 768);
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<webrtc::DesktopFrame> frame(CreateTestFrame(frame_size));
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  frame->mutable_updated_region()->SetRect(
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      webrtc::DesktopRect::MakeSize(frame_size));
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Lossy encode the first frame.
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  encoder->SetLosslessEncode(false);
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<VideoPacket> lossy_packet = encoder->Encode(*frame);
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Lossless encode the second frame.
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  encoder->SetLosslessEncode(true);
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<VideoPacket> lossless_packet = encoder->Encode(*frame);
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_GT(lossless_packet->data().size(), lossy_packet->data().size());
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Lossy encode one more frame.
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  encoder->SetLosslessEncode(false);
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  lossy_packet = encoder->Encode(*frame);
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_LT(lossy_packet->data().size(), lossless_packet->data().size());
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Test that the VP9 encoder can switch between lossy & lossless color.
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST(VideoEncoderVpxTest, TestVp9VideoEncoderLossyColor) {
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP9());
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  webrtc::DesktopSize frame_size(1024, 768);
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<webrtc::DesktopFrame> frame(CreateTestFrame(frame_size));
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  frame->mutable_updated_region()->SetRect(
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      webrtc::DesktopRect::MakeSize(frame_size));
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Lossy encode the first frame.
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  encoder->SetLosslessColor(false);
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<VideoPacket> lossy_packet = encoder->Encode(*frame);
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Lossless encode the second frame.
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  encoder->SetLosslessColor(true);
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<VideoPacket> lossless_packet = encoder->Encode(*frame);
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_GT(lossless_packet->data().size(), lossy_packet->data().size());
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Lossy encode one more frame.
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  encoder->SetLosslessColor(false);
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  lossy_packet = encoder->Encode(*frame);
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_LT(lossy_packet->data().size(), lossless_packet->data().size());
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Test that the VP8 encoder ignores lossless modes without crashing.
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST(VideoEncoderVpxTest, TestVp8VideoEncoderIgnoreLossy) {
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  webrtc::DesktopSize frame_size(1024, 768);
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<webrtc::DesktopFrame> frame(CreateTestFrame(frame_size));
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  frame->mutable_updated_region()->SetRect(
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      webrtc::DesktopRect::MakeSize(frame_size));
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Encode a frame, to give the encoder a chance to crash if misconfigured.
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  encoder->SetLosslessEncode(true);
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  encoder->SetLosslessColor(true);
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(packet);
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Test that calling Encode with a differently-sized media::ScreenCaptureData
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// does not leak memory.
11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST(VideoEncoderVpxTest, TestSizeChangeNoLeak) {
11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  webrtc::DesktopSize frame_size(1000, 1000);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Create first frame & encode it.
12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<webrtc::DesktopFrame> frame(CreateTestFrame(frame_size));
12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  frame->mutable_updated_region()->SetRect(
12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      webrtc::DesktopRect::MakeSize(frame_size));
1258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
126d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_TRUE(packet);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Halve the size of the frame, and updated region, and encode again.
12946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  frame_size.set(frame_size.width(), frame_size.height() / 2);
13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  frame = CreateTestFrame(frame_size);
13146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  frame->mutable_updated_region()->SetRect(
13246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      webrtc::DesktopRect::MakeSize(frame_size));
1338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  packet = encoder->Encode(*frame);
134d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_TRUE(packet);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Test that the DPI information is correctly propagated from the
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// media::ScreenCaptureData to the VideoPacket.
13946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST(VideoEncoderVpxTest, TestDpiPropagation) {
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  webrtc::DesktopSize frame_size(32, 32);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<webrtc::DesktopFrame> frame(CreateTestFrame(frame_size));
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  frame->set_dpi(webrtc::DesktopVector(96, 97));
1468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_EQ(packet->format().x_dpi(), 96);
148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_EQ(packet->format().y_dpi(), 97);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
152