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 16 namespace remoting { 17 18 // xRGB pixel colors for use by tests. 19 const uint32 kBlueColor = 0x0000ff; 20 const 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. 24 static 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 39 TEST(VideoEncoderVpxTest, TestVp8VideoEncoder) { 40 scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8()); 41 TestVideoEncoder(encoder.get(), false); 42 } 43 44 TEST(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. 51 TEST(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. 75 TEST(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. 99 TEST(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. 116 TEST(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. 139 TEST(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