tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestVideoTrackEncoder.cpp (53354B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include <algorithm>
      8 
      9 #include "DriftCompensation.h"
     10 #include "MediaTrackGraph.h"
     11 #include "MediaTrackListener.h"
     12 #include "VP8TrackEncoder.h"
     13 #include "WebMWriter.h"  // TODO: it's weird to include muxer header to get the class definition of VP8 METADATA
     14 #include "YUVBufferGenerator.h"
     15 #include "gmock/gmock.h"
     16 #include "gtest/gtest.h"
     17 #include "prtime.h"
     18 
     19 #define VIDEO_TRACK_RATE 90000
     20 
     21 using ::testing::_;
     22 using ::testing::Invoke;
     23 using ::testing::NiceMock;
     24 using ::testing::TestWithParam;
     25 using ::testing::Values;
     26 
     27 using namespace mozilla::layers;
     28 using namespace mozilla;
     29 
     30 struct InitParam {
     31  bool mShouldSucceed;  // This parameter should cause success or fail result
     32  int mWidth;           // frame width
     33  int mHeight;          // frame height
     34 };
     35 
     36 class MockDriftCompensator : public DriftCompensator {
     37 public:
     38  MockDriftCompensator()
     39      : DriftCompensator(GetCurrentSerialEventTarget(), VIDEO_TRACK_RATE) {
     40    ON_CALL(*this, GetVideoTime(_, _))
     41        .WillByDefault(Invoke([](TimeStamp, TimeStamp t) { return t; }));
     42  }
     43 
     44  MOCK_METHOD2(GetVideoTime, TimeStamp(TimeStamp, TimeStamp));
     45 };
     46 
     47 class TestVP8TrackEncoder : public VP8TrackEncoder {
     48 public:
     49  explicit TestVP8TrackEncoder(Maybe<float> aKeyFrameIntervalFactor = Nothing())
     50      : VP8TrackEncoder(MakeRefPtr<NiceMock<MockDriftCompensator>>(),
     51                        VIDEO_TRACK_RATE, mEncodedVideoQueue,
     52                        FrameDroppingMode::DISALLOW, aKeyFrameIntervalFactor) {}
     53 
     54  MockDriftCompensator* DriftCompensator() {
     55    return static_cast<MockDriftCompensator*>(mDriftCompensator.get());
     56  }
     57 
     58  ::testing::AssertionResult TestInit(const InitParam& aParam) {
     59    nsresult result =
     60        Init(aParam.mWidth, aParam.mHeight, aParam.mWidth, aParam.mHeight, 30);
     61 
     62    if (((NS_FAILED(result) && aParam.mShouldSucceed)) ||
     63        (NS_SUCCEEDED(result) && !aParam.mShouldSucceed)) {
     64      return ::testing::AssertionFailure()
     65             << " width = " << aParam.mWidth << " height = " << aParam.mHeight;
     66    }
     67 
     68    return ::testing::AssertionSuccess();
     69  }
     70 
     71  MediaQueue<EncodedFrame> mEncodedVideoQueue;
     72 };
     73 
     74 // Init test
     75 TEST(VP8VideoTrackEncoder, Initialization)
     76 {
     77  InitParam params[] = {
     78      // Failure cases.
     79      {false, 0, 0},  // Height/ width should be larger than 1.
     80      {false, 0, 1},  // Height/ width should be larger than 1.
     81      {false, 1, 0},  // Height/ width should be larger than 1.
     82 
     83      // Success cases
     84      {true, 640, 480},  // Standard VGA
     85      {true, 800, 480},  // Standard WVGA
     86      {true, 960, 540},  // Standard qHD
     87      {true, 1280, 720}  // Standard HD
     88  };
     89 
     90  for (const InitParam& param : params) {
     91    TestVP8TrackEncoder encoder;
     92    EXPECT_TRUE(encoder.TestInit(param));
     93  }
     94 }
     95 
     96 // Get MetaData test
     97 TEST(VP8VideoTrackEncoder, FetchMetaData)
     98 {
     99  InitParam params[] = {
    100      // Success cases
    101      {true, 640, 480},  // Standard VGA
    102      {true, 800, 480},  // Standard WVGA
    103      {true, 960, 540},  // Standard qHD
    104      {true, 1280, 720}  // Standard HD
    105  };
    106 
    107  for (const InitParam& param : params) {
    108    TestVP8TrackEncoder encoder;
    109    EXPECT_TRUE(encoder.TestInit(param));
    110 
    111    RefPtr<TrackMetadataBase> meta = encoder.GetMetadata();
    112    RefPtr<VP8Metadata> vp8Meta(static_cast<VP8Metadata*>(meta.get()));
    113 
    114    // METADATA should be depend on how to initiate encoder.
    115    EXPECT_EQ(vp8Meta->mWidth, param.mWidth);
    116    EXPECT_EQ(vp8Meta->mHeight, param.mHeight);
    117  }
    118 }
    119 
    120 // Encode test
    121 TEST(VP8VideoTrackEncoder, FrameEncode)
    122 {
    123  TestVP8TrackEncoder encoder;
    124  TimeStamp now = TimeStamp::Now();
    125 
    126  // Create YUV images as source.
    127  nsTArray<RefPtr<Image>> images;
    128  YUVBufferGenerator generator;
    129  generator.Init(mozilla::gfx::IntSize(640, 480));
    130  images.AppendElement(generator.GenerateI420Image());
    131  images.AppendElement(generator.GenerateNV12Image());
    132  images.AppendElement(generator.GenerateNV21Image());
    133 
    134  // Put generated YUV frame into video segment.
    135  // Duration of each frame is 1 second.
    136  VideoSegment segment;
    137  for (nsTArray<RefPtr<Image>>::size_type i = 0; i < images.Length(); i++) {
    138    RefPtr<Image> image = images[i];
    139    segment.AppendFrame(image.forget(), generator.GetSize(),
    140                        PRINCIPAL_HANDLE_NONE, false,
    141                        now + TimeDuration::FromSeconds(i));
    142  }
    143 
    144  encoder.SetStartOffset(now);
    145  encoder.AppendVideoSegment(std::move(segment));
    146  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(images.Length()));
    147  encoder.NotifyEndOfStream();
    148 
    149  EXPECT_TRUE(encoder.IsEncodingComplete());
    150  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    151  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    152 }
    153 
    154 // Test that encoding a single frame gives useful output.
    155 TEST(VP8VideoTrackEncoder, SingleFrameEncode)
    156 {
    157  TestVP8TrackEncoder encoder;
    158  TimeStamp now = TimeStamp::Now();
    159  YUVBufferGenerator generator;
    160  generator.Init(mozilla::gfx::IntSize(640, 480));
    161 
    162  // Pass a half-second frame to the encoder.
    163  VideoSegment segment;
    164  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    165                      PRINCIPAL_HANDLE_NONE, false, now);
    166 
    167  encoder.SetStartOffset(now);
    168  encoder.AppendVideoSegment(std::move(segment));
    169  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.5));
    170  encoder.NotifyEndOfStream();
    171 
    172  EXPECT_TRUE(encoder.IsEncodingComplete());
    173  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    174  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    175 
    176  // Read out encoded data, and verify.
    177  RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
    178  EXPECT_EQ(EncodedFrame::VP8_I_FRAME, frame->mFrameType)
    179      << "We only have one frame, so it should be a keyframe";
    180 
    181  const uint64_t halfSecond = PR_USEC_PER_SEC / 2;
    182  EXPECT_EQ(halfSecond, frame->mDuration);
    183 
    184  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
    185 }
    186 
    187 // Test that encoding a couple of identical images gives useful output.
    188 TEST(VP8VideoTrackEncoder, SameFrameEncode)
    189 {
    190  TestVP8TrackEncoder encoder;
    191  TimeStamp now = TimeStamp::Now();
    192  YUVBufferGenerator generator;
    193  generator.Init(mozilla::gfx::IntSize(640, 480));
    194 
    195  // Pass 15 100ms frames to the encoder.
    196  RefPtr<Image> image = generator.GenerateI420Image();
    197  VideoSegment segment;
    198  for (uint32_t i = 0; i < 15; ++i) {
    199    segment.AppendFrame(do_AddRef(image), generator.GetSize(),
    200                        PRINCIPAL_HANDLE_NONE, false,
    201                        now + TimeDuration::FromSeconds(i * 0.1));
    202  }
    203 
    204  encoder.SetStartOffset(now);
    205  encoder.AppendVideoSegment(std::move(segment));
    206  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(1.5));
    207  encoder.NotifyEndOfStream();
    208 
    209  EXPECT_TRUE(encoder.IsEncodingComplete());
    210  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    211  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    212 
    213  // Verify total duration being 1.5s.
    214  uint64_t totalDuration = 0;
    215  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    216    totalDuration += frame->mDuration;
    217  }
    218  const uint64_t oneAndAHalf = (PR_USEC_PER_SEC / 2) * 3;
    219  EXPECT_EQ(oneAndAHalf, totalDuration);
    220 }
    221 
    222 // Test encoding a track that has to skip frames.
    223 TEST(VP8VideoTrackEncoder, SkippedFrames)
    224 {
    225  TestVP8TrackEncoder encoder;
    226  YUVBufferGenerator generator;
    227  generator.Init(mozilla::gfx::IntSize(640, 480));
    228  TimeStamp now = TimeStamp::Now();
    229 
    230  // Pass 100 frames of the shortest possible duration where we don't get
    231  // rounding errors between input/output rate.
    232  VideoSegment segment;
    233  for (uint32_t i = 0; i < 100; ++i) {
    234    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    235                        PRINCIPAL_HANDLE_NONE, false,
    236                        now + TimeDuration::FromMilliseconds(i));
    237  }
    238 
    239  encoder.SetStartOffset(now);
    240  encoder.AppendVideoSegment(std::move(segment));
    241  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(100));
    242  encoder.NotifyEndOfStream();
    243 
    244  EXPECT_TRUE(encoder.IsEncodingComplete());
    245  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    246  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    247 
    248  // Verify total duration being 100 * 1ms = 100ms.
    249  uint64_t totalDuration = 0;
    250  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    251    totalDuration += frame->mDuration;
    252  }
    253  const uint64_t hundredMillis = PR_USEC_PER_SEC / 10;
    254  EXPECT_EQ(hundredMillis, totalDuration);
    255 }
    256 
    257 // Test encoding a track with frames subject to rounding errors.
    258 TEST(VP8VideoTrackEncoder, RoundingErrorFramesEncode)
    259 {
    260  TestVP8TrackEncoder encoder;
    261  YUVBufferGenerator generator;
    262  generator.Init(mozilla::gfx::IntSize(640, 480));
    263  TimeStamp now = TimeStamp::Now();
    264 
    265  // Pass nine frames with timestamps not expressable in 90kHz sample rate,
    266  // then one frame to make the total duration close to one second.
    267  VideoSegment segment;
    268  uint32_t usPerFrame = 99999;  // 99.999ms
    269  for (uint32_t i = 0; i < 9; ++i) {
    270    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    271                        PRINCIPAL_HANDLE_NONE, false,
    272                        now + TimeDuration::FromMicroseconds(i * usPerFrame));
    273  }
    274 
    275  // This last frame has timestamp start + 0.9s and duration 0.1s.
    276  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    277                      PRINCIPAL_HANDLE_NONE, false,
    278                      now + TimeDuration::FromSeconds(0.9));
    279 
    280  encoder.SetStartOffset(now);
    281  encoder.AppendVideoSegment(std::move(segment));
    282  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(1));
    283  encoder.NotifyEndOfStream();
    284 
    285  EXPECT_TRUE(encoder.IsEncodingComplete());
    286  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    287  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    288 
    289  // Verify total duration being 1s.
    290  uint64_t totalDuration = 0;
    291  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    292    totalDuration += frame->mDuration;
    293  }
    294  // Not exact, the stream is encoded in time base 90kHz.
    295  const uint64_t oneSecond = PR_USEC_PER_SEC - 1;
    296  EXPECT_EQ(oneSecond, totalDuration);
    297 }
    298 
    299 // Test that we're encoding timestamps rather than durations.
    300 TEST(VP8VideoTrackEncoder, TimestampFrameEncode)
    301 {
    302  TestVP8TrackEncoder encoder;
    303  YUVBufferGenerator generator;
    304  generator.Init(mozilla::gfx::IntSize(640, 480));
    305  TimeStamp now = TimeStamp::Now();
    306 
    307  VideoSegment segment;
    308  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    309                      PRINCIPAL_HANDLE_NONE, false, now);
    310  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    311                      PRINCIPAL_HANDLE_NONE, false,
    312                      now + TimeDuration::FromSeconds(0.05));
    313  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    314                      PRINCIPAL_HANDLE_NONE, false,
    315                      now + TimeDuration::FromSeconds(0.2));
    316 
    317  encoder.SetStartOffset(now);
    318  encoder.AppendVideoSegment(std::move(segment));
    319  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.3));
    320  encoder.NotifyEndOfStream();
    321 
    322  EXPECT_TRUE(encoder.IsEncodingComplete());
    323  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    324  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    325 
    326  // Verify total duration being 0.3s and individual frames being [0.05s, 0.15s,
    327  // 0.1s]
    328  uint64_t expectedDurations[] = {(PR_USEC_PER_SEC / 10) / 2,
    329                                  (PR_USEC_PER_SEC / 10) * 3 / 2,
    330                                  (PR_USEC_PER_SEC / 10)};
    331  uint64_t totalDuration = 0;
    332  size_t i = 0;
    333  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    334    EXPECT_EQ(expectedDurations[i], frame->mDuration);
    335    i++;
    336    totalDuration += frame->mDuration;
    337  }
    338  const uint64_t pointThree = (PR_USEC_PER_SEC / 10) * 3;
    339  EXPECT_EQ(pointThree, totalDuration);
    340 }
    341 
    342 // Test that we're compensating for drift when encoding.
    343 TEST(VP8VideoTrackEncoder, DriftingFrameEncode)
    344 {
    345  TestVP8TrackEncoder encoder;
    346  YUVBufferGenerator generator;
    347  generator.Init(mozilla::gfx::IntSize(640, 480));
    348  TimeStamp now = TimeStamp::Now();
    349 
    350  // Set up major drift -- audio that goes twice as fast as video.
    351  // This should make the given video durations double as they get encoded.
    352  EXPECT_CALL(*encoder.DriftCompensator(), GetVideoTime(_, _))
    353      .WillRepeatedly(Invoke(
    354          [&](TimeStamp, TimeStamp aTime) { return now + (aTime - now) * 2; }));
    355 
    356  VideoSegment segment;
    357  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    358                      PRINCIPAL_HANDLE_NONE, false, now);
    359  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    360                      PRINCIPAL_HANDLE_NONE, false,
    361                      now + TimeDuration::FromSeconds(0.05));
    362  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    363                      PRINCIPAL_HANDLE_NONE, false,
    364                      now + TimeDuration::FromSeconds(0.2));
    365 
    366  encoder.SetStartOffset(now);
    367  encoder.AppendVideoSegment(std::move(segment));
    368  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.3));
    369  encoder.NotifyEndOfStream();
    370 
    371  EXPECT_TRUE(encoder.IsEncodingComplete());
    372  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    373  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    374 
    375  // Verify total duration being 0.6s and individual frames being [0.1s, 0.3s,
    376  // 0.2s]
    377  uint64_t expectedDurations[] = {(PR_USEC_PER_SEC / 10),
    378                                  (PR_USEC_PER_SEC / 10) * 3,
    379                                  (PR_USEC_PER_SEC / 10) * 2};
    380  uint64_t totalDuration = 0;
    381  size_t i = 0;
    382  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    383    EXPECT_EQ(expectedDurations[i], frame->mDuration);
    384    i++;
    385    totalDuration += frame->mDuration;
    386  }
    387  const uint64_t pointSix = (PR_USEC_PER_SEC / 10) * 6;
    388  EXPECT_EQ(pointSix, totalDuration);
    389 }
    390 
    391 // Test that suspending an encoding works.
    392 TEST(VP8VideoTrackEncoder, Suspended)
    393 {
    394  TestVP8TrackEncoder encoder;
    395  TimeStamp now = TimeStamp::Now();
    396  YUVBufferGenerator generator;
    397  generator.Init(mozilla::gfx::IntSize(640, 480));
    398 
    399  // Pass 3 frames with duration 0.1s. We suspend before and resume after the
    400  // second frame.
    401 
    402  {
    403    VideoSegment segment;
    404    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    405                        PRINCIPAL_HANDLE_NONE, false, now);
    406 
    407    encoder.SetStartOffset(now);
    408    encoder.AppendVideoSegment(std::move(segment));
    409    encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.1));
    410  }
    411 
    412  encoder.Suspend(now + TimeDuration::FromSeconds(0.1));
    413 
    414  {
    415    VideoSegment segment;
    416    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    417                        PRINCIPAL_HANDLE_NONE, false,
    418                        now + TimeDuration::FromSeconds(0.1));
    419    encoder.AppendVideoSegment(std::move(segment));
    420    encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.2));
    421  }
    422 
    423  encoder.Resume(now + TimeDuration::FromSeconds(0.2));
    424 
    425  {
    426    VideoSegment segment;
    427    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    428                        PRINCIPAL_HANDLE_NONE, false,
    429                        now + TimeDuration::FromSeconds(0.2));
    430    encoder.AppendVideoSegment(std::move(segment));
    431    encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.3));
    432  }
    433 
    434  encoder.NotifyEndOfStream();
    435 
    436  EXPECT_TRUE(encoder.IsEncodingComplete());
    437  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    438  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    439 
    440  // Verify that we have two encoded frames and a total duration of 0.2s.
    441  uint64_t count = 0;
    442  uint64_t totalDuration = 0;
    443  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    444    ++count;
    445    totalDuration += frame->mDuration;
    446  }
    447  const uint64_t two = 2;
    448  EXPECT_EQ(two, count);
    449  const uint64_t pointTwo = (PR_USEC_PER_SEC / 10) * 2;
    450  EXPECT_EQ(pointTwo, totalDuration);
    451 }
    452 
    453 // Test that ending a track while the video track encoder is suspended works.
    454 TEST(VP8VideoTrackEncoder, SuspendedUntilEnd)
    455 {
    456  TestVP8TrackEncoder encoder;
    457  YUVBufferGenerator generator;
    458  generator.Init(mozilla::gfx::IntSize(640, 480));
    459  TimeStamp now = TimeStamp::Now();
    460 
    461  // Pass 2 frames with duration 0.1s. We suspend before the second frame.
    462 
    463  {
    464    VideoSegment segment;
    465    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    466                        PRINCIPAL_HANDLE_NONE, false, now);
    467 
    468    encoder.SetStartOffset(now);
    469    encoder.AppendVideoSegment(std::move(segment));
    470    encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.1));
    471  }
    472 
    473  encoder.Suspend(now + TimeDuration::FromSeconds(0.1));
    474 
    475  {
    476    VideoSegment segment;
    477    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    478                        PRINCIPAL_HANDLE_NONE, false,
    479                        now + TimeDuration::FromSeconds(0.1));
    480    encoder.AppendVideoSegment(std::move(segment));
    481    encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.2));
    482  }
    483 
    484  encoder.NotifyEndOfStream();
    485 
    486  EXPECT_TRUE(encoder.IsEncodingComplete());
    487  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    488  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    489 
    490  // Verify that we have one encoded frames and a total duration of 0.1s.
    491  uint64_t count = 0;
    492  uint64_t totalDuration = 0;
    493  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    494    ++count;
    495    totalDuration += frame->mDuration;
    496  }
    497  const uint64_t one = 1;
    498  EXPECT_EQ(one, count);
    499  const uint64_t pointOne = PR_USEC_PER_SEC / 10;
    500  EXPECT_EQ(pointOne, totalDuration);
    501 }
    502 
    503 // Test that ending a track that was always suspended works.
    504 TEST(VP8VideoTrackEncoder, AlwaysSuspended)
    505 {
    506  TestVP8TrackEncoder encoder;
    507  YUVBufferGenerator generator;
    508  generator.Init(mozilla::gfx::IntSize(640, 480));
    509  TimeStamp now = TimeStamp::Now();
    510 
    511  // Suspend and then pass a frame with duration 2s.
    512 
    513  encoder.Suspend(now);
    514 
    515  VideoSegment segment;
    516  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    517                      PRINCIPAL_HANDLE_NONE, false, now);
    518 
    519  encoder.SetStartOffset(now);
    520  encoder.AppendVideoSegment(std::move(segment));
    521  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(2));
    522 
    523  encoder.NotifyEndOfStream();
    524 
    525  // Verify that we have no encoded frames.
    526  EXPECT_TRUE(encoder.IsEncodingComplete());
    527  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    528  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
    529 }
    530 
    531 // Test that encoding a track that is suspended in the beginning works.
    532 TEST(VP8VideoTrackEncoder, SuspendedBeginning)
    533 {
    534  TestVP8TrackEncoder encoder;
    535  YUVBufferGenerator generator;
    536  generator.Init(mozilla::gfx::IntSize(640, 480));
    537  TimeStamp now = TimeStamp::Now();
    538 
    539  // Suspend and pass a frame with duration 0.5s. Then resume and pass one more.
    540  encoder.Suspend(now);
    541 
    542  {
    543    VideoSegment segment;
    544    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    545                        PRINCIPAL_HANDLE_NONE, false, now);
    546 
    547    encoder.SetStartOffset(now);
    548    encoder.AppendVideoSegment(std::move(segment));
    549    encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.5));
    550  }
    551 
    552  encoder.Resume(now + TimeDuration::FromSeconds(0.5));
    553 
    554  {
    555    VideoSegment segment;
    556    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    557                        PRINCIPAL_HANDLE_NONE, false,
    558                        now + TimeDuration::FromSeconds(0.5));
    559    encoder.AppendVideoSegment(std::move(segment));
    560    encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(1));
    561  }
    562 
    563  encoder.NotifyEndOfStream();
    564 
    565  EXPECT_TRUE(encoder.IsEncodingComplete());
    566  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    567  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    568 
    569  // Verify that we have one encoded frames and a total duration of 0.1s.
    570  uint64_t count = 0;
    571  uint64_t totalDuration = 0;
    572  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    573    ++count;
    574    totalDuration += frame->mDuration;
    575  }
    576  const uint64_t one = 1;
    577  EXPECT_EQ(one, count);
    578  const uint64_t half = PR_USEC_PER_SEC / 2;
    579  EXPECT_EQ(half, totalDuration);
    580 }
    581 
    582 // Test that suspending and resuming in the middle of already pushed data
    583 // works.
    584 TEST(VP8VideoTrackEncoder, SuspendedOverlap)
    585 {
    586  TestVP8TrackEncoder encoder;
    587  YUVBufferGenerator generator;
    588  generator.Init(mozilla::gfx::IntSize(640, 480));
    589  TimeStamp now = TimeStamp::Now();
    590 
    591  {
    592    // Pass a 1s frame and suspend after 0.5s.
    593    VideoSegment segment;
    594    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    595                        PRINCIPAL_HANDLE_NONE, false, now);
    596 
    597    encoder.SetStartOffset(now);
    598    encoder.AppendVideoSegment(std::move(segment));
    599  }
    600 
    601  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.5));
    602  encoder.Suspend(now + TimeDuration::FromSeconds(0.5));
    603 
    604  {
    605    // Pass another 1s frame and resume after 0.3 of this new frame.
    606    VideoSegment segment;
    607    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    608                        PRINCIPAL_HANDLE_NONE, false,
    609                        now + TimeDuration::FromSeconds(1));
    610    encoder.AppendVideoSegment(std::move(segment));
    611  }
    612 
    613  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(1.3));
    614  encoder.Resume(now + TimeDuration::FromSeconds(1.3));
    615  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(2));
    616  encoder.NotifyEndOfStream();
    617 
    618  EXPECT_TRUE(encoder.IsEncodingComplete());
    619  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    620  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    621 
    622  // Verify that we have two encoded frames and a total duration of 0.1s.
    623  RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
    624  const uint64_t pointFive = (PR_USEC_PER_SEC / 10) * 5;
    625  EXPECT_EQ(pointFive, frame->mDuration);
    626  frame = encoder.mEncodedVideoQueue.PopFront();
    627  const uint64_t pointSeven = (PR_USEC_PER_SEC / 10) * 7;
    628  EXPECT_EQ(pointSeven, frame->mDuration);
    629  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
    630 }
    631 
    632 // Test that ending a track in the middle of already pushed data works.
    633 TEST(VP8VideoTrackEncoder, PrematureEnding)
    634 {
    635  TestVP8TrackEncoder encoder;
    636  YUVBufferGenerator generator;
    637  generator.Init(mozilla::gfx::IntSize(640, 480));
    638  TimeStamp now = TimeStamp::Now();
    639 
    640  // Pass a 1s frame and end the track after 0.5s.
    641  VideoSegment segment;
    642  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    643                      PRINCIPAL_HANDLE_NONE, false, now);
    644 
    645  encoder.SetStartOffset(now);
    646  encoder.AppendVideoSegment(std::move(segment));
    647  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(0.5));
    648  encoder.NotifyEndOfStream();
    649 
    650  EXPECT_TRUE(encoder.IsEncodingComplete());
    651  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    652  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    653 
    654  uint64_t totalDuration = 0;
    655  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    656    totalDuration += frame->mDuration;
    657  }
    658  const uint64_t half = PR_USEC_PER_SEC / 2;
    659  EXPECT_EQ(half, totalDuration);
    660 }
    661 
    662 // Test that a track that starts at t > 0 works as expected.
    663 TEST(VP8VideoTrackEncoder, DelayedStart)
    664 {
    665  TestVP8TrackEncoder encoder;
    666  YUVBufferGenerator generator;
    667  generator.Init(mozilla::gfx::IntSize(640, 480));
    668  TimeStamp now = TimeStamp::Now();
    669 
    670  // Pass a 2s frame, start (pass first CurrentTime) at 0.5s, end at 1s.
    671  // Should result in a 0.5s encoding.
    672  VideoSegment segment;
    673  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    674                      PRINCIPAL_HANDLE_NONE, false, now);
    675 
    676  encoder.SetStartOffset(now + TimeDuration::FromSeconds(0.5));
    677  encoder.AppendVideoSegment(std::move(segment));
    678  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(1));
    679  encoder.NotifyEndOfStream();
    680 
    681  EXPECT_TRUE(encoder.IsEncodingComplete());
    682  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    683  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    684 
    685  uint64_t totalDuration = 0;
    686  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    687    totalDuration += frame->mDuration;
    688  }
    689  const uint64_t half = PR_USEC_PER_SEC / 2;
    690  EXPECT_EQ(half, totalDuration);
    691 }
    692 
    693 // Test that a track that starts at t > 0 works as expected, when
    694 // SetStartOffset comes after AppendVideoSegment.
    695 TEST(VP8VideoTrackEncoder, DelayedStartOtherEventOrder)
    696 {
    697  TestVP8TrackEncoder encoder;
    698  YUVBufferGenerator generator;
    699  generator.Init(mozilla::gfx::IntSize(640, 480));
    700  TimeStamp now = TimeStamp::Now();
    701 
    702  // Pass a 2s frame, start (pass first CurrentTime) at 0.5s, end at 1s.
    703  // Should result in a 0.5s encoding.
    704  VideoSegment segment;
    705  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    706                      PRINCIPAL_HANDLE_NONE, false, now);
    707 
    708  encoder.AppendVideoSegment(std::move(segment));
    709  encoder.SetStartOffset(now + TimeDuration::FromSeconds(0.5));
    710  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(1));
    711  encoder.NotifyEndOfStream();
    712 
    713  EXPECT_TRUE(encoder.IsEncodingComplete());
    714  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    715  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    716 
    717  uint64_t totalDuration = 0;
    718  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    719    totalDuration += frame->mDuration;
    720  }
    721  const uint64_t half = PR_USEC_PER_SEC / 2;
    722  EXPECT_EQ(half, totalDuration);
    723 }
    724 
    725 // Test that a track that starts at t >>> 0 works as expected.
    726 TEST(VP8VideoTrackEncoder, VeryDelayedStart)
    727 {
    728  TestVP8TrackEncoder encoder;
    729  YUVBufferGenerator generator;
    730  generator.Init(mozilla::gfx::IntSize(640, 480));
    731  TimeStamp now = TimeStamp::Now();
    732 
    733  // Pass a 1s frame, start (pass first CurrentTime) at 10s, end at 10.5s.
    734  // Should result in a 0.5s encoding.
    735  VideoSegment segment;
    736  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    737                      PRINCIPAL_HANDLE_NONE, false, now);
    738 
    739  encoder.SetStartOffset(now + TimeDuration::FromSeconds(10));
    740  encoder.AppendVideoSegment(std::move(segment));
    741  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(10.5));
    742  encoder.NotifyEndOfStream();
    743 
    744  EXPECT_TRUE(encoder.IsEncodingComplete());
    745  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    746  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    747 
    748  uint64_t totalDuration = 0;
    749  while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    750    totalDuration += frame->mDuration;
    751  }
    752  const uint64_t half = PR_USEC_PER_SEC / 2;
    753  EXPECT_EQ(half, totalDuration);
    754 }
    755 
    756 // Test that a video frame that hangs around for a long time gets encoded
    757 // every second.
    758 TEST(VP8VideoTrackEncoder, LongFramesReEncoded)
    759 {
    760  TestVP8TrackEncoder encoder;
    761  YUVBufferGenerator generator;
    762  generator.Init(mozilla::gfx::IntSize(640, 480));
    763  TimeStamp now = TimeStamp::Now();
    764 
    765  // Pass a frame at t=0 and start encoding.
    766  // Advancing the current time by 6.5s should encode six 1s frames.
    767  // Advancing the current time by another 5.5s should encode another five 1s
    768  // frames.
    769 
    770  VideoSegment segment;
    771  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    772                      PRINCIPAL_HANDLE_NONE, false, now);
    773 
    774  encoder.SetStartOffset(now);
    775  encoder.AppendVideoSegment(std::move(segment));
    776 
    777  {
    778    encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(6.5));
    779 
    780    EXPECT_FALSE(encoder.IsEncodingComplete());
    781    EXPECT_FALSE(encoder.mEncodedVideoQueue.IsFinished());
    782 
    783    uint64_t count = 0;
    784    uint64_t totalDuration = 0;
    785    while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    786      ++count;
    787      totalDuration += frame->mDuration;
    788    }
    789    const uint64_t sixSec = 6 * PR_USEC_PER_SEC;
    790    EXPECT_EQ(sixSec, totalDuration);
    791    EXPECT_EQ(6U, count);
    792  }
    793 
    794  {
    795    encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(11));
    796    encoder.NotifyEndOfStream();
    797 
    798    EXPECT_TRUE(encoder.IsEncodingComplete());
    799    EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    800 
    801    uint64_t count = 0;
    802    uint64_t totalDuration = 0;
    803    while (RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront()) {
    804      ++count;
    805      totalDuration += frame->mDuration;
    806    }
    807    const uint64_t fiveSec = 5 * PR_USEC_PER_SEC;
    808    EXPECT_EQ(fiveSec, totalDuration);
    809    EXPECT_EQ(5U, count);
    810  }
    811 }
    812 
    813 // Test that an encoding with no defined key frame interval encodes keyframes
    814 // as expected. Default interval should be 10s.
    815 TEST(VP8VideoTrackEncoder, DefaultKeyFrameInterval)
    816 {
    817  // Set the factor high to only test the keyframe-forcing logic
    818  TestVP8TrackEncoder encoder(Some(2.0));
    819  YUVBufferGenerator generator;
    820  generator.Init(mozilla::gfx::IntSize(640, 480));
    821  TimeStamp now = TimeStamp::Now();
    822 
    823  // Pass a frame at t=0, and the frame-duplication logic will encode frames
    824  // every second. Keyframes are expected at t=0, 10s and 20s.
    825  VideoSegment segment;
    826  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    827                      PRINCIPAL_HANDLE_NONE, false, now);
    828 
    829  encoder.SetStartOffset(now);
    830  encoder.AppendVideoSegment(std::move(segment));
    831  encoder.AdvanceCurrentTime(now + TimeDuration::FromSeconds(21.5));
    832  encoder.NotifyEndOfStream();
    833 
    834  EXPECT_TRUE(encoder.IsEncodingComplete());
    835  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    836  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    837 
    838  // Duplication logic ensures no frame duration is longer than 1 second.
    839 
    840  // [0, 1000ms) - key-frame.
    841  RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
    842  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 1000UL, frame->mDuration);
    843  EXPECT_EQ(EncodedFrame::VP8_I_FRAME, frame->mFrameType);
    844 
    845  // [1000ms, 10000ms) - non-key-frames
    846  for (int i = 0; i < 9; ++i) {
    847    frame = encoder.mEncodedVideoQueue.PopFront();
    848    EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 1000UL, frame->mDuration)
    849        << "Start time: " << frame->mTime.ToMicroseconds() << "us";
    850    EXPECT_EQ(EncodedFrame::VP8_P_FRAME, frame->mFrameType)
    851        << "Start time: " << frame->mTime.ToMicroseconds() << "us";
    852  }
    853 
    854  // [10000ms, 11000ms) - key-frame
    855  frame = encoder.mEncodedVideoQueue.PopFront();
    856  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 1000UL, frame->mDuration);
    857  EXPECT_EQ(EncodedFrame::VP8_I_FRAME, frame->mFrameType);
    858 
    859  // [11000ms, 20000ms) - non-key-frames
    860  for (int i = 0; i < 9; ++i) {
    861    frame = encoder.mEncodedVideoQueue.PopFront();
    862    EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 1000UL, frame->mDuration)
    863        << "Start time: " << frame->mTime.ToMicroseconds() << "us";
    864    EXPECT_EQ(EncodedFrame::VP8_P_FRAME, frame->mFrameType)
    865        << "Start time: " << frame->mTime.ToMicroseconds() << "us";
    866  }
    867 
    868  // [20000ms, 21000ms) - key-frame
    869  frame = encoder.mEncodedVideoQueue.PopFront();
    870  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 1000UL, frame->mDuration);
    871  EXPECT_EQ(EncodedFrame::VP8_I_FRAME, frame->mFrameType);
    872 
    873  // [21000ms, 21500ms) - non-key-frame
    874  frame = encoder.mEncodedVideoQueue.PopFront();
    875  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 500UL, frame->mDuration);
    876  EXPECT_EQ(EncodedFrame::VP8_P_FRAME, frame->mFrameType);
    877 
    878  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
    879 }
    880 
    881 // Test that an encoding which is disabled on a frame timestamp encodes
    882 // frames as expected.
    883 TEST(VP8VideoTrackEncoder, DisableOnFrameTime)
    884 {
    885  TestVP8TrackEncoder encoder;
    886  YUVBufferGenerator generator;
    887  generator.Init(mozilla::gfx::IntSize(640, 480));
    888  TimeStamp now = TimeStamp::Now();
    889 
    890  // Pass a frame in at t=0.
    891  // Pass another frame in at t=100ms.
    892  // Disable the track at t=100ms.
    893  // Stop encoding at t=200ms.
    894  // Should yield 2 frames, 1 real; 1 black.
    895 
    896  VideoSegment segment;
    897  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    898                      PRINCIPAL_HANDLE_NONE, false, now);
    899  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    900                      PRINCIPAL_HANDLE_NONE, false,
    901                      now + TimeDuration::FromMilliseconds(100));
    902 
    903  encoder.SetStartOffset(now);
    904  encoder.AppendVideoSegment(std::move(segment));
    905 
    906  // Advancing 100ms, for simplicity.
    907  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(100));
    908 
    909  encoder.Disable(now + TimeDuration::FromMilliseconds(100));
    910  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(200));
    911  encoder.NotifyEndOfStream();
    912 
    913  EXPECT_TRUE(encoder.IsEncodingComplete());
    914  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    915  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    916 
    917  // [0, 100ms)
    918  RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
    919  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
    920 
    921  // [100ms, 200ms)
    922  frame = encoder.mEncodedVideoQueue.PopFront();
    923  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
    924 
    925  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
    926 }
    927 
    928 // Test that an encoding which is disabled between two frame timestamps
    929 // encodes frames as expected.
    930 TEST(VP8VideoTrackEncoder, DisableBetweenFrames)
    931 {
    932  TestVP8TrackEncoder encoder;
    933  YUVBufferGenerator generator;
    934  generator.Init(mozilla::gfx::IntSize(640, 480));
    935  TimeStamp now = TimeStamp::Now();
    936 
    937  // Pass a frame in at t=0.
    938  // Disable the track at t=50ms.
    939  // Pass another frame in at t=100ms.
    940  // Stop encoding at t=200ms.
    941  // Should yield 3 frames, 1 real [0, 50); 2 black [50, 100) and [100, 200).
    942 
    943  VideoSegment segment;
    944  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    945                      PRINCIPAL_HANDLE_NONE, false, now);
    946  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    947                      PRINCIPAL_HANDLE_NONE, false,
    948                      now + TimeDuration::FromMilliseconds(100));
    949 
    950  encoder.SetStartOffset(now);
    951  encoder.AppendVideoSegment(std::move(segment));
    952 
    953  encoder.Disable(now + TimeDuration::FromMilliseconds(50));
    954  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(200));
    955  encoder.NotifyEndOfStream();
    956 
    957  EXPECT_TRUE(encoder.IsEncodingComplete());
    958  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
    959  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
    960 
    961  // [0, 50ms)
    962  RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
    963  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 50UL, frame->mDuration);
    964 
    965  // [50ms, 100ms)
    966  frame = encoder.mEncodedVideoQueue.PopFront();
    967  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 50UL, frame->mDuration);
    968 
    969  // [100ms, 200ms)
    970  frame = encoder.mEncodedVideoQueue.PopFront();
    971  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
    972 
    973  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
    974 }
    975 
    976 // Test that an encoding which is disabled before the first frame becomes
    977 // black immediately.
    978 TEST(VP8VideoTrackEncoder, DisableBeforeFirstFrame)
    979 {
    980  TestVP8TrackEncoder encoder;
    981  YUVBufferGenerator generator;
    982  generator.Init(mozilla::gfx::IntSize(640, 480));
    983  TimeStamp now = TimeStamp::Now();
    984 
    985  // Disable the track at t=0.
    986  // Pass a frame in at t=50ms.
    987  // Enable the track at t=100ms.
    988  // Stop encoding at t=200ms.
    989  // Should yield 2 frames, 1 black [0, 100); 1 real [100, 200).
    990 
    991  VideoSegment segment;
    992  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
    993                      PRINCIPAL_HANDLE_NONE, false,
    994                      now + TimeDuration::FromMilliseconds(50));
    995 
    996  encoder.SetStartOffset(now);
    997  encoder.Disable(now);
    998  encoder.AppendVideoSegment(std::move(segment));
    999 
   1000  encoder.Enable(now + TimeDuration::FromMilliseconds(100));
   1001  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(200));
   1002  encoder.NotifyEndOfStream();
   1003 
   1004  EXPECT_TRUE(encoder.IsEncodingComplete());
   1005  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
   1006  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1007 
   1008  // [0, 100ms)
   1009  RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
   1010  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
   1011 
   1012  // [100ms, 200ms)
   1013  frame = encoder.mEncodedVideoQueue.PopFront();
   1014  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
   1015 
   1016  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1017 }
   1018 
   1019 // Test that an encoding which is enabled on a frame timestamp encodes
   1020 // frames as expected.
   1021 TEST(VP8VideoTrackEncoder, EnableOnFrameTime)
   1022 {
   1023  TestVP8TrackEncoder encoder;
   1024  YUVBufferGenerator generator;
   1025  generator.Init(mozilla::gfx::IntSize(640, 480));
   1026  TimeStamp now = TimeStamp::Now();
   1027 
   1028  // Disable the track at t=0.
   1029  // Pass a frame in at t=0.
   1030  // Pass another frame in at t=100ms.
   1031  // Enable the track at t=100ms.
   1032  // Stop encoding at t=200ms.
   1033  // Should yield 2 frames, 1 black; 1 real.
   1034 
   1035  VideoSegment segment;
   1036  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1037                      PRINCIPAL_HANDLE_NONE, false, now);
   1038  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1039                      PRINCIPAL_HANDLE_NONE, false,
   1040                      now + TimeDuration::FromMilliseconds(100));
   1041 
   1042  encoder.SetStartOffset(now);
   1043  encoder.Disable(now);
   1044  encoder.AppendVideoSegment(std::move(segment));
   1045 
   1046  // Advancing 100ms, for simplicity.
   1047  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(100));
   1048 
   1049  encoder.Enable(now + TimeDuration::FromMilliseconds(100));
   1050  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(200));
   1051  encoder.NotifyEndOfStream();
   1052 
   1053  EXPECT_TRUE(encoder.IsEncodingComplete());
   1054  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
   1055  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1056 
   1057  // [0, 100ms)
   1058  RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
   1059  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
   1060 
   1061  // [100ms, 200ms)
   1062  frame = encoder.mEncodedVideoQueue.PopFront();
   1063  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
   1064 
   1065  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1066 }
   1067 
   1068 // Test that an encoding which is enabled between two frame timestamps encodes
   1069 // frames as expected.
   1070 TEST(VP8VideoTrackEncoder, EnableBetweenFrames)
   1071 {
   1072  TestVP8TrackEncoder encoder;
   1073  YUVBufferGenerator generator;
   1074  generator.Init(mozilla::gfx::IntSize(640, 480));
   1075  TimeStamp now = TimeStamp::Now();
   1076 
   1077  // Disable the track at t=0.
   1078  // Pass a frame in at t=0.
   1079  // Enable the track at t=50ms.
   1080  // Pass another frame in at t=100ms.
   1081  // Stop encoding at t=200ms.
   1082  // Should yield 3 frames, 1 black [0, 50); 2 real [50, 100) and [100, 200).
   1083 
   1084  VideoSegment segment;
   1085  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1086                      PRINCIPAL_HANDLE_NONE, false, now);
   1087  segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1088                      PRINCIPAL_HANDLE_NONE, false,
   1089                      now + TimeDuration::FromMilliseconds(100));
   1090 
   1091  encoder.SetStartOffset(now);
   1092  encoder.Disable(now);
   1093  encoder.AppendVideoSegment(std::move(segment));
   1094 
   1095  encoder.Enable(now + TimeDuration::FromMilliseconds(50));
   1096  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(200));
   1097  encoder.NotifyEndOfStream();
   1098 
   1099  EXPECT_TRUE(encoder.IsEncodingComplete());
   1100  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
   1101  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1102 
   1103  // [0, 50ms)
   1104  RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
   1105  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 50UL, frame->mDuration);
   1106 
   1107  // [50ms, 100ms)
   1108  frame = encoder.mEncodedVideoQueue.PopFront();
   1109  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 50UL, frame->mDuration);
   1110 
   1111  // [100ms, 200ms)
   1112  frame = encoder.mEncodedVideoQueue.PopFront();
   1113  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
   1114 
   1115  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1116 }
   1117 
   1118 // Test that making time go backwards removes any future frames in the
   1119 // encoder.
   1120 TEST(VP8VideoTrackEncoder, BackwardsTimeResets)
   1121 {
   1122  TestVP8TrackEncoder encoder;
   1123  YUVBufferGenerator generator;
   1124  generator.Init(mozilla::gfx::IntSize(640, 480));
   1125  TimeStamp now = TimeStamp::Now();
   1126 
   1127  encoder.SetStartOffset(now);
   1128 
   1129  // Pass frames in at t=0, t=100ms, t=200ms, t=300ms.
   1130  // Advance time to t=125ms.
   1131  // Pass frames in at t=150ms, t=250ms, t=350ms.
   1132  // Stop encoding at t=300ms.
   1133  // Should yield 4 frames, at t=0, t=100ms, t=150ms, t=250ms.
   1134 
   1135  {
   1136    VideoSegment segment;
   1137    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1138                        PRINCIPAL_HANDLE_NONE, false, now);
   1139    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1140                        PRINCIPAL_HANDLE_NONE, false,
   1141                        now + TimeDuration::FromMilliseconds(100));
   1142    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1143                        PRINCIPAL_HANDLE_NONE, false,
   1144                        now + TimeDuration::FromMilliseconds(200));
   1145    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1146                        PRINCIPAL_HANDLE_NONE, false,
   1147                        now + TimeDuration::FromMilliseconds(300));
   1148 
   1149    encoder.AppendVideoSegment(std::move(segment));
   1150  }
   1151 
   1152  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(125));
   1153 
   1154  {
   1155    VideoSegment segment;
   1156    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1157                        PRINCIPAL_HANDLE_NONE, false,
   1158                        now + TimeDuration::FromMilliseconds(150));
   1159    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1160                        PRINCIPAL_HANDLE_NONE, false,
   1161                        now + TimeDuration::FromMilliseconds(250));
   1162    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1163                        PRINCIPAL_HANDLE_NONE, false,
   1164                        now + TimeDuration::FromMilliseconds(350));
   1165 
   1166    encoder.AppendVideoSegment(std::move(segment));
   1167  }
   1168 
   1169  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(300));
   1170  encoder.NotifyEndOfStream();
   1171 
   1172  EXPECT_TRUE(encoder.IsEncodingComplete());
   1173  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
   1174  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1175 
   1176  // [0, 100ms)
   1177  RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
   1178  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
   1179 
   1180  // [100ms, 150ms)
   1181  frame = encoder.mEncodedVideoQueue.PopFront();
   1182  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 50UL, frame->mDuration);
   1183 
   1184  // [150ms, 250ms)
   1185  frame = encoder.mEncodedVideoQueue.PopFront();
   1186  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
   1187 
   1188  // [250ms, 300ms)
   1189  frame = encoder.mEncodedVideoQueue.PopFront();
   1190  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 50UL, frame->mDuration);
   1191 
   1192  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1193 }
   1194 
   1195 // Test that trying to encode a null image removes any future frames in the
   1196 // encoder.
   1197 TEST(VP8VideoTrackEncoder, NullImageResets)
   1198 {
   1199  TestVP8TrackEncoder encoder;
   1200  YUVBufferGenerator generator;
   1201  generator.Init(mozilla::gfx::IntSize(640, 480));
   1202  TimeStamp now = TimeStamp::Now();
   1203 
   1204  encoder.SetStartOffset(now);
   1205 
   1206  // Pass frames in at t=0, t=100ms, t=200ms, t=300ms.
   1207  // Advance time to t=125ms.
   1208  // Pass in a null image at t=125ms.
   1209  // Pass frames in at t=250ms, t=350ms.
   1210  // Stop encoding at t=300ms.
   1211  // Should yield 3 frames, at t=0, t=100ms, t=250ms.
   1212 
   1213  {
   1214    VideoSegment segment;
   1215    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1216                        PRINCIPAL_HANDLE_NONE, false, now);
   1217    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1218                        PRINCIPAL_HANDLE_NONE, false,
   1219                        now + TimeDuration::FromMilliseconds(100));
   1220    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1221                        PRINCIPAL_HANDLE_NONE, false,
   1222                        now + TimeDuration::FromMilliseconds(200));
   1223    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1224                        PRINCIPAL_HANDLE_NONE, false,
   1225                        now + TimeDuration::FromMilliseconds(300));
   1226 
   1227    encoder.AppendVideoSegment(std::move(segment));
   1228  }
   1229 
   1230  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(125));
   1231 
   1232  {
   1233    VideoSegment segment;
   1234    segment.AppendFrame(nullptr, generator.GetSize(), PRINCIPAL_HANDLE_NONE,
   1235                        false, now + TimeDuration::FromMilliseconds(125));
   1236    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1237                        PRINCIPAL_HANDLE_NONE, false,
   1238                        now + TimeDuration::FromMilliseconds(250));
   1239    segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1240                        PRINCIPAL_HANDLE_NONE, false,
   1241                        now + TimeDuration::FromMilliseconds(350));
   1242 
   1243    encoder.AppendVideoSegment(std::move(segment));
   1244  }
   1245 
   1246  encoder.AdvanceCurrentTime(now + TimeDuration::FromMilliseconds(300));
   1247  encoder.NotifyEndOfStream();
   1248 
   1249  EXPECT_TRUE(encoder.IsEncodingComplete());
   1250  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
   1251  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1252 
   1253  // [0, 100ms)
   1254  RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
   1255  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration);
   1256 
   1257  // [100ms, 250ms)
   1258  frame = encoder.mEncodedVideoQueue.PopFront();
   1259  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 150UL, frame->mDuration);
   1260 
   1261  // [250ms, 300ms)
   1262  frame = encoder.mEncodedVideoQueue.PopFront();
   1263  EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 50UL, frame->mDuration);
   1264 
   1265  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1266 }
   1267 
   1268 TEST(VP8VideoTrackEncoder, MaxKeyFrameDistanceLowFramerate)
   1269 {
   1270  TestVP8TrackEncoder encoder;
   1271  YUVBufferGenerator generator;
   1272  generator.Init(mozilla::gfx::IntSize(240, 180));
   1273  TimeStamp now = TimeStamp::Now();
   1274 
   1275  encoder.SetStartOffset(now);
   1276 
   1277  // Pass 10s worth of frames at 2 fps and verify that the key frame interval
   1278  // is ~7.5s.
   1279  const TimeDuration duration = TimeDuration::FromSeconds(10);
   1280  const uint32_t numFrames = 10 * 2;
   1281  const TimeDuration frameDuration = duration / static_cast<int64_t>(numFrames);
   1282 
   1283  {
   1284    VideoSegment segment;
   1285    for (uint32_t i = 0; i < numFrames; ++i) {
   1286      segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1287                          PRINCIPAL_HANDLE_NONE, false,
   1288                          now + frameDuration * i);
   1289    }
   1290    encoder.AppendVideoSegment(std::move(segment));
   1291  }
   1292 
   1293  encoder.AdvanceCurrentTime(now + duration);
   1294  encoder.NotifyEndOfStream();
   1295 
   1296  EXPECT_TRUE(encoder.IsEncodingComplete());
   1297  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
   1298  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1299 
   1300  for (uint32_t i = 0; i < numFrames; ++i) {
   1301    const RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
   1302    EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 500UL, frame->mDuration)
   1303        << "Frame " << i << ", with start: " << frame->mTime.ToMicroseconds()
   1304        << "us";
   1305    // 7.5s key frame interval at 2 fps becomes the 15th frame.
   1306    EXPECT_EQ(
   1307        i % 15 == 0 ? EncodedFrame::VP8_I_FRAME : EncodedFrame::VP8_P_FRAME,
   1308        frame->mFrameType)
   1309        << "Frame " << i << ", with start: " << frame->mTime.ToMicroseconds()
   1310        << "us";
   1311  }
   1312 
   1313  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1314 }
   1315 
   1316 // This is "High" framerate, as in higher than the test for "Low" framerate.
   1317 // We don't make it too high because the test takes considerably longer to
   1318 // run.
   1319 TEST(VP8VideoTrackEncoder, MaxKeyFrameDistanceHighFramerate)
   1320 {
   1321  TestVP8TrackEncoder encoder;
   1322  YUVBufferGenerator generator;
   1323  generator.Init(mozilla::gfx::IntSize(240, 180));
   1324  TimeStamp now = TimeStamp::Now();
   1325 
   1326  encoder.SetStartOffset(now);
   1327 
   1328  // Pass 10s worth of frames at 8 fps and verify that the key frame interval
   1329  // is ~7.5s.
   1330  const TimeDuration duration = TimeDuration::FromSeconds(10);
   1331  const uint32_t numFrames = 10 * 8;
   1332  const TimeDuration frameDuration = duration / static_cast<int64_t>(numFrames);
   1333 
   1334  {
   1335    VideoSegment segment;
   1336    for (uint32_t i = 0; i < numFrames; ++i) {
   1337      segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1338                          PRINCIPAL_HANDLE_NONE, false,
   1339                          now + frameDuration * i);
   1340    }
   1341    encoder.AppendVideoSegment(std::move(segment));
   1342  }
   1343 
   1344  encoder.AdvanceCurrentTime(now + duration);
   1345  encoder.NotifyEndOfStream();
   1346 
   1347  EXPECT_TRUE(encoder.IsEncodingComplete());
   1348  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
   1349  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1350 
   1351  for (uint32_t i = 0; i < numFrames; ++i) {
   1352    const RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
   1353    EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 125UL, frame->mDuration)
   1354        << "Frame " << i << ", with start: " << frame->mTime.ToMicroseconds()
   1355        << "us";
   1356    // 7.5s key frame interval at 8 fps becomes the 60th frame.
   1357    EXPECT_EQ(
   1358        i % 60 == 0 ? EncodedFrame::VP8_I_FRAME : EncodedFrame::VP8_P_FRAME,
   1359        frame->mFrameType)
   1360        << "Frame " << i << ", with start: " << frame->mTime.ToMicroseconds()
   1361        << "us";
   1362  }
   1363 
   1364  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1365 }
   1366 
   1367 TEST(VP8VideoTrackEncoder, MaxKeyFrameDistanceAdaptiveFramerate)
   1368 {
   1369  TestVP8TrackEncoder encoder;
   1370  YUVBufferGenerator generator;
   1371  generator.Init(mozilla::gfx::IntSize(240, 180));
   1372  TimeStamp now = TimeStamp::Now();
   1373 
   1374  encoder.SetStartOffset(now);
   1375 
   1376  // Pass 11s worth of frames at 2 fps and verify that there is a key frame
   1377  // at 7.5s. Then pass 14s worth of frames at 10 fps and verify that there is
   1378  // a key frame at 15s (due to re-init) and then one at 22.5s.
   1379 
   1380  const TimeDuration firstDuration = TimeDuration::FromSeconds(11);
   1381  const uint32_t firstNumFrames = 11 * 2;
   1382  const TimeDuration firstFrameDuration =
   1383      firstDuration / static_cast<int64_t>(firstNumFrames);
   1384  {
   1385    VideoSegment segment;
   1386    for (uint32_t i = 0; i < firstNumFrames; ++i) {
   1387      segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1388                          PRINCIPAL_HANDLE_NONE, false,
   1389                          now + firstFrameDuration * i);
   1390    }
   1391    encoder.AppendVideoSegment(std::move(segment));
   1392  }
   1393  encoder.AdvanceCurrentTime(now + firstDuration);
   1394 
   1395  const TimeDuration secondDuration = TimeDuration::FromSeconds(14);
   1396  const uint32_t secondNumFrames = 14 * 10;
   1397  const TimeDuration secondFrameDuration =
   1398      secondDuration / static_cast<int64_t>(secondNumFrames);
   1399  {
   1400    VideoSegment segment;
   1401    for (uint32_t i = 0; i < secondNumFrames; ++i) {
   1402      segment.AppendFrame(generator.GenerateI420Image(), generator.GetSize(),
   1403                          PRINCIPAL_HANDLE_NONE, false,
   1404                          now + firstDuration + secondFrameDuration * i);
   1405    }
   1406    encoder.AppendVideoSegment(std::move(segment));
   1407  }
   1408  encoder.AdvanceCurrentTime(now + firstDuration + secondDuration);
   1409 
   1410  encoder.NotifyEndOfStream();
   1411 
   1412  EXPECT_TRUE(encoder.IsEncodingComplete());
   1413  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
   1414  EXPECT_FALSE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1415 
   1416  // [0, 11s) - keyframe distance is now 7.5s@2fps = 15.
   1417  for (uint32_t i = 0; i < 22; ++i) {
   1418    const RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
   1419    EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 500UL, frame->mDuration)
   1420        << "Frame " << i << ", with start: " << frame->mTime.ToMicroseconds()
   1421        << "us";
   1422    // 7.5s key frame interval at 2 fps becomes the 15th frame.
   1423    EXPECT_EQ(
   1424        i % 15 == 0 ? EncodedFrame::VP8_I_FRAME : EncodedFrame::VP8_P_FRAME,
   1425        frame->mFrameType)
   1426        << "Frame " << i << ", with start: " << frame->mTime.ToMicroseconds()
   1427        << "us";
   1428  }
   1429 
   1430  // Input framerate is now 10fps.
   1431  // Framerate re-evaluation every 5s, so the keyframe distance changed at
   1432  // 15s.
   1433  for (uint32_t i = 22; i < 162; ++i) {
   1434    const RefPtr<EncodedFrame> frame = encoder.mEncodedVideoQueue.PopFront();
   1435    EXPECT_EQ(PR_USEC_PER_SEC / 1000 * 100UL, frame->mDuration)
   1436        << "Frame " << i << ", with start: " << frame->mTime.ToMicroseconds()
   1437        << "us";
   1438    if (i < 22 + 40) {
   1439      // [11s, 15s) - 40 frames at 10fps but with the 2fps keyframe distance.
   1440      EXPECT_EQ(
   1441          i % 15 == 0 ? EncodedFrame::VP8_I_FRAME : EncodedFrame::VP8_P_FRAME,
   1442          frame->mFrameType)
   1443          << "Frame " << i << ", with start: " << frame->mTime.ToMicroseconds()
   1444          << "us";
   1445    } else {
   1446      // [15s, 25s) - 100 frames at 10fps. Keyframe distance 75. Starts with
   1447      // keyframe due to re-init.
   1448      EXPECT_EQ((i - 22 - 40) % 75 == 0 ? EncodedFrame::VP8_I_FRAME
   1449                                        : EncodedFrame::VP8_P_FRAME,
   1450                frame->mFrameType)
   1451          << "Frame " << i << ", with start: " << frame->mTime.ToMicroseconds()
   1452          << "us";
   1453    }
   1454  }
   1455 
   1456  EXPECT_TRUE(encoder.mEncodedVideoQueue.AtEndOfStream());
   1457 }
   1458 
   1459 // EOS test
   1460 TEST(VP8VideoTrackEncoder, EncodeComplete)
   1461 {
   1462  TestVP8TrackEncoder encoder;
   1463 
   1464  // NotifyEndOfStream should wrap up the encoding immediately.
   1465  encoder.NotifyEndOfStream();
   1466  EXPECT_TRUE(encoder.mEncodedVideoQueue.IsFinished());
   1467 }