15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 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)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <deque>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/video_frame.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/codec/codec_test.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/codec/video_decoder.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/codec/video_encoder.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/base/util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing webrtc::BasicDesktopFrame;
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing webrtc::DesktopFrame;
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using webrtc::DesktopRect;
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using webrtc::DesktopRegion;
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)using webrtc::DesktopSize;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBytesPerPixel = 4;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Some sample rects for testing.
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)std::vector<std::vector<DesktopRect> > MakeTestRectLists(DesktopSize size) {
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<std::vector<DesktopRect> > rect_lists;
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<DesktopRect> rects;
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  rects.push_back(DesktopRect::MakeXYWH(0, 0, size.width(), size.height()));
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rect_lists.push_back(rects);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rects.clear();
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  rects.push_back(DesktopRect::MakeXYWH(
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      0, 0, size.width() / 2, size.height() / 2));
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rect_lists.push_back(rects);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rects.clear();
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  rects.push_back(DesktopRect::MakeXYWH(
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      size.width() / 2, size.height() / 2,
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      size.width() / 2, size.height() / 2));
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rect_lists.push_back(rects);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rects.clear();
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  rects.push_back(DesktopRect::MakeXYWH(16, 16, 16, 16));
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  rects.push_back(DesktopRect::MakeXYWH(128, 64, 32, 32));
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rect_lists.push_back(rects);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rect_lists;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VideoDecoderTester {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  VideoDecoderTester(VideoDecoder* decoder,
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     const DesktopSize& screen_size,
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     const DesktopSize& view_size)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : screen_size_(screen_size),
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        view_size_(view_size),
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        strict_(false),
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        decoder_(decoder),
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        frame_(NULL) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    image_data_.reset(new uint8[
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        view_size_.width() * view_size_.height() * kBytesPerPixel]);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(image_data_.get());
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    decoder_->Initialize(
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        DesktopSize(screen_size_.width(), screen_size_.height()));
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Reset() {
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    expected_region_.Clear();
74d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    update_region_.Clear();
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ResetRenderedData() {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(image_data_.get(), 0,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           view_size_.width() * view_size_.height() * kBytesPerPixel);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ReceivedPacket(VideoPacket* packet) {
8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    ASSERT_TRUE(decoder_->DecodePacket(*packet));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    RenderFrame();
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RenderFrame() {
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    decoder_->RenderFrame(
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        DesktopSize(view_size_.width(), view_size_.height()),
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        DesktopRect::MakeWH(view_size_.width(), view_size_.height()),
92d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        image_data_.get(), view_size_.width() * kBytesPerPixel,
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        &update_region_);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ReceivedScopedPacket(scoped_ptr<VideoPacket> packet) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReceivedPacket(packet.get());
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_strict(bool strict) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strict_ = strict;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  void set_frame(DesktopFrame* frame) {
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    frame_ = frame;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  void AddRects(const DesktopRect* rects, int count) {
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (int i = 0; i < count; ++i) {
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      expected_region_.AddRect(rects[i]);
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  void AddRegion(const DesktopRegion& region) {
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    expected_region_.AddRegion(region);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void VerifyResults() {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!strict_)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ASSERT_TRUE(frame_);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Test the content of the update region.
125d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    EXPECT_TRUE(expected_region_.Equals(update_region_));
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (DesktopRegion::Iterator i(update_region_); !i.IsAtEnd();
128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)         i.Advance()) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int stride = view_size_.width() * kBytesPerPixel;
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(stride, frame_->stride());
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int offset =  stride * i.rect().top() +
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kBytesPerPixel * i.rect().left();
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      const uint8* original = frame_->data() + offset;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const uint8* decoded = image_data_.get() + offset;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int row_size = kBytesPerPixel * i.rect().width();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int y = 0; y < i.rect().height(); ++y) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        EXPECT_EQ(0, memcmp(original, decoded, row_size))
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << "Row " << y << " is different";
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        original += stride;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        decoded += stride;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The error at each pixel is the root mean square of the errors in
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the R, G, and B components, each normalized to [0, 1]. This routine
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // checks that the maximum and mean pixel errors do not exceed given limits.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void VerifyResultsApprox(const uint8* expected_view_data,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           double max_error_limit, double mean_error_limit) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double max_error = 0.0;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double sum_error = 0.0;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int error_num = 0;
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for (DesktopRegion::Iterator i(update_region_); !i.IsAtEnd();
154d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)         i.Advance()) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int stride = view_size_.width() * kBytesPerPixel;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const int offset =  stride * i.rect().top() +
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kBytesPerPixel * i.rect().left();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const uint8* expected = expected_view_data + offset;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const uint8* actual = image_data_.get() + offset;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int y = 0; y < i.rect().height(); ++y) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (int x = 0; x < i.rect().width(); ++x) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          double error = CalculateError(expected, actual);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          max_error = std::max(max_error, error);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sum_error += error;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ++error_num;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          expected += 4;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          actual += 4;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_LE(max_error, max_error_limit);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double mean_error = sum_error / error_num;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_LE(mean_error, mean_error_limit);
174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    VLOG(0) << "Max error: " << max_error;
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    VLOG(0) << "Mean error: " << mean_error;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double CalculateError(const uint8* original, const uint8* decoded) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double error_sum_squares = 0.0;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < 3; i++) {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      double error = static_cast<double>(*original++) -
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     static_cast<double>(*decoded++);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error /= 255.0;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_sum_squares += error * error;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    original++;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    decoded++;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return sqrt(error_sum_squares / 3.0);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DesktopSize screen_size_;
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DesktopSize view_size_;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool strict_;
195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DesktopRegion expected_region_;
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DesktopRegion update_region_;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VideoDecoder* decoder_;
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<uint8[]> image_data_;
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DesktopFrame* frame_;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(VideoDecoderTester);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The VideoEncoderTester provides a hook for retrieving the data, and passing
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the message to other subprograms for validaton.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VideoEncoderTester {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
208d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  VideoEncoderTester()
209d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      : decoder_tester_(NULL),
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        data_available_(0) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~VideoEncoderTester() {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_GT(data_available_, 0);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DataAvailable(scoped_ptr<VideoPacket> packet) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++data_available_;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Send the message to the VideoDecoderTester.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (decoder_tester_) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      decoder_tester_->ReceivedPacket(packet.get());
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_decoder_tester(VideoDecoderTester* decoder_tester) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    decoder_tester_ = decoder_tester;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VideoDecoderTester* decoder_tester_;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int data_available_;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(VideoEncoderTester);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdochscoped_ptr<DesktopFrame> PrepareFrame(const DesktopSize& size) {
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<DesktopFrame> frame(new BasicDesktopFrame(size));
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  srand(0);
24090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int memory_size = size.width() * size.height() * kBytesPerPixel;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < memory_size; ++i) {
24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    frame->data()[i] = rand() % 256;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return frame.Pass();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void TestEncodingRects(VideoEncoder* encoder,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              VideoEncoderTester* tester,
25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                              webrtc::DesktopFrame* frame,
25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                              const DesktopRect* rects,
25290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                              int count) {
25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  frame->mutable_updated_region()->Clear();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < count; ++i) {
25590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    frame->mutable_updated_region()->AddRect(rects[i]);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
258d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
259d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  tester->DataAvailable(packet.Pass());
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestVideoEncoder(VideoEncoder* encoder, bool strict) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kSizes[] = {320, 319, 317, 150};
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  VideoEncoderTester tester;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t xi = 0; xi < arraysize(kSizes); ++xi) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t yi = 0; yi < arraysize(kSizes); ++yi) {
26990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      DesktopSize size = DesktopSize(kSizes[xi], kSizes[yi]);
27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      scoped_ptr<webrtc::DesktopFrame> frame = PrepareFrame(size);
27190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::vector<std::vector<DesktopRect> > test_rect_lists =
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          MakeTestRectLists(size);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (size_t i = 0; i < test_rect_lists.size(); ++i) {
27490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        const std::vector<DesktopRect>& test_rects = test_rect_lists[i];
27590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        TestEncodingRects(encoder, &tester, frame.get(),
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &test_rects[0], test_rects.size());
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void TestEncodeDecodeRects(VideoEncoder* encoder,
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  VideoEncoderTester* encoder_tester,
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  VideoDecoderTester* decoder_tester,
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  DesktopFrame* frame,
28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  const DesktopRect* rects, int count) {
28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  frame->mutable_updated_region()->Clear();
28890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (int i = 0; i < count; ++i) {
28990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    frame->mutable_updated_region()->AddRect(rects[i]);
29090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  decoder_tester->AddRects(rects, count);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Generate random data for the updated region.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  srand(0);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < count; ++i) {
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const int row_size =
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        DesktopFrame::kBytesPerPixel * rects[i].width();
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    uint8* memory = frame->data() +
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      frame->stride() * rects[i].top() +
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      DesktopFrame::kBytesPerPixel * rects[i].left();
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int y = 0; y < rects[i].height(); ++y) {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (int x = 0; x < row_size; ++x)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memory[x] = rand() % 256;
30490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      memory += frame->stride();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
308d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
309d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  encoder_tester->DataAvailable(packet.Pass());
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  decoder_tester->VerifyResults();
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  decoder_tester->Reset();
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestVideoEncoderDecoder(
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VideoEncoder* encoder, VideoDecoder* decoder, bool strict) {
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DesktopSize kSize = DesktopSize(320, 240);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
318d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  VideoEncoderTester encoder_tester;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<DesktopFrame> frame = PrepareFrame(kSize);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VideoDecoderTester decoder_tester(decoder, kSize, kSize);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  decoder_tester.set_strict(strict);
32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  decoder_tester.set_frame(frame.get());
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  encoder_tester.set_decoder_tester(&decoder_tester);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::vector<std::vector<DesktopRect> > test_rect_lists =
32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      MakeTestRectLists(kSize);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < test_rect_lists.size(); ++i) {
33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::vector<DesktopRect> test_rects = test_rect_lists[i];
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester,
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                          frame.get(), &test_rects[0], test_rects.size());
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
336116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic void FillWithGradient(DesktopFrame* frame) {
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (int j = 0; j < frame->size().height(); ++j) {
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    uint8* p = frame->data() + j * frame->stride();
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    for (int i = 0; i < frame->size().width(); ++i) {
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      *p++ = (255.0 * i) / frame->size().width();
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      *p++ = (164.0 * j) / frame->size().height();
34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      *p++ = (82.0 * (i + j)) /
34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          (frame->size().width() + frame->size().height());
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *p++ = 0;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestVideoEncoderDecoderGradient(VideoEncoder* encoder,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     VideoDecoder* decoder,
35190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                     const DesktopSize& screen_size,
35290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                     const DesktopSize& view_size,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     double max_error_limit,
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     double mean_error_limit) {
355116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<BasicDesktopFrame> frame(
356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new BasicDesktopFrame(screen_size));
35790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FillWithGradient(frame.get());
35890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  frame->mutable_updated_region()->SetRect(DesktopRect::MakeSize(screen_size));
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<BasicDesktopFrame> expected_result(
361116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new BasicDesktopFrame(view_size));
36290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FillWithGradient(expected_result.get());
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VideoDecoderTester decoder_tester(decoder, screen_size, view_size);
36590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  decoder_tester.set_frame(frame.get());
36690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  decoder_tester.AddRegion(frame->updated_region());
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
368d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
369d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  decoder_tester.ReceivedScopedPacket(packet.Pass());
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  decoder_tester.VerifyResultsApprox(expected_result->data(),
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     max_error_limit, mean_error_limit);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that the decoder correctly re-renders the frame if its client
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // invalidates the frame.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  decoder_tester.ResetRenderedData();
37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  decoder->Invalidate(
378116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      DesktopSize(view_size.width(), view_size.height()),
379116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      DesktopRegion(
380116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          DesktopRect::MakeWH(view_size.width(), view_size.height())));
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  decoder_tester.RenderFrame();
38290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  decoder_tester.VerifyResultsApprox(expected_result->data(),
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     max_error_limit, mean_error_limit);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
386116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfloat MeasureVideoEncoderFpsWithSize(VideoEncoder* encoder,
387116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                     const DesktopSize& size) {
388116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<DesktopFrame> frame(PrepareFrame(size));
389116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  frame->mutable_updated_region()->SetRect(DesktopRect::MakeSize(size));
390116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::list<DesktopFrame*> frames;
391116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  frames.push_back(frame.get());
392116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return MeasureVideoEncoderFpsWithFrames(encoder, frames);
393116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
394116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
395116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfloat MeasureVideoEncoderFpsWithFrames(VideoEncoder* encoder,
396116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                       const std::list<DesktopFrame*>& frames) {
397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const base::TimeDelta kTestTime = base::TimeDelta::FromSeconds(1);
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
399116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Encode some frames to "warm up" the encoder (i.e. to let it set up initial
400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // structures, establish a stable working set, etc), then encode at least
401116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // kMinimumFrameCount frames to measure the encoder's performance.
402116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const int kWarmUpFrameCount = 10;
403116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const int kMinimumFrameCount = 10;
404116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::TimeTicks start_time;
405116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::TimeDelta elapsed;
406116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::list<DesktopFrame*> test_frames;
407116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int frame_count;
408116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (frame_count = 0;
409116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       (frame_count < kMinimumFrameCount + kWarmUpFrameCount ||
410116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            elapsed < kTestTime);
411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++frame_count) {
412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (frame_count == kWarmUpFrameCount) {
413116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      start_time = base::TimeTicks::Now();
414116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
415116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
416116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (test_frames.empty()) {
417116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      test_frames = frames;
418116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
419116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<VideoPacket> packet = encoder->Encode(*test_frames.front());
420116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    test_frames.pop_front();
421116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
422116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (frame_count >= kWarmUpFrameCount) {
423116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      elapsed = base::TimeTicks::Now() - start_time;
424116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
425116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
426116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
427116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return (frame_count * base::TimeDelta::FromSeconds(1)) / elapsed;
428116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
429116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
431