Coverage Report

Created: 2018-09-25 14:53

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