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