Bug 1296531 - Add gtests for starting a video track at t > 0. r?jesup draft
authorAndreas Pehrson <pehrsons@gmail.com>
Tue, 16 May 2017 13:25:02 +0200
changeset 670318 f076aa90d0a9d91f0c73197f43740e2030642bb3
parent 670317 22becebfe7ad0f75daa52fce4acf8ad77709517b
child 670319 87e95290c09f49ff226e88a62e8a2102bedc720d
push id81598
push userbmo:apehrson@mozilla.com
push dateTue, 26 Sep 2017 09:13:19 +0000
reviewersjesup
bugs1296531
milestone58.0a1
Bug 1296531 - Add gtests for starting a video track at t > 0. r?jesup MozReview-Commit-ID: 4Nt4Ldcy4I6
dom/media/gtest/TestVideoTrackEncoder.cpp
--- a/dom/media/gtest/TestVideoTrackEncoder.cpp
+++ b/dom/media/gtest/TestVideoTrackEncoder.cpp
@@ -8,16 +8,18 @@
 #include "prtime.h"
 #include "mozilla/ArrayUtils.h"
 #include "VP8TrackEncoder.h"
 #include "ImageContainer.h"
 #include "MediaStreamGraph.h"
 #include "MediaStreamListener.h"
 #include "WebMWriter.h" // TODO: it's weird to include muxer header to get the class definition of VP8 METADATA
 
+#define VIDEO_TRACK_RATE 90000
+
 using ::testing::TestWithParam;
 using ::testing::Values;
 
 using namespace mozilla::layers;
 using namespace mozilla;
 
 // A helper object to generate of different YUV planes.
 class YUVBufferGenerator {
@@ -184,17 +186,17 @@ struct InitParam {
   bool mShouldSucceed;  // This parameter should cause success or fail result
   int  mWidth;          // frame width
   int  mHeight;         // frame height
 };
 
 class TestVP8TrackEncoder: public VP8TrackEncoder
 {
 public:
-  explicit TestVP8TrackEncoder(TrackRate aTrackRate = 90000)
+  explicit TestVP8TrackEncoder(TrackRate aTrackRate = VIDEO_TRACK_RATE)
     : VP8TrackEncoder(aTrackRate) {}
 
   ::testing::AssertionResult TestInit(const InitParam &aParam)
   {
     nsresult result = Init(aParam.mWidth, aParam.mHeight, aParam.mWidth, aParam.mHeight);
 
     if (((NS_FAILED(result) && aParam.mShouldSucceed)) || (NS_SUCCEEDED(result) && !aParam.mShouldSucceed))
     {
@@ -273,49 +275,49 @@ TEST(VP8VideoTrackEncoder, FrameEncode)
   // Put generated YUV frame into video segment.
   // Duration of each frame is 1 second.
   VideoSegment segment;
   TimeStamp now = TimeStamp::Now();
   for (nsTArray<RefPtr<Image>>::size_type i = 0; i < images.Length(); i++)
   {
     RefPtr<Image> image = images[i];
     segment.AppendFrame(image.forget(),
-                        mozilla::StreamTime(90000),
+                        mozilla::StreamTime(VIDEO_TRACK_RATE),
                         generator.GetSize(),
                         PRINCIPAL_HANDLE_NONE,
                         false,
                         now + TimeDuration::FromSeconds(i));
   }
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(images.Length() * 90000);
+  encoder.AdvanceCurrentTime(images.Length() * VIDEO_TRACK_RATE);
 
   // Pull Encoded Data back from encoder.
   EncodedFrameContainer container;
   EXPECT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 }
 
 // Test that encoding a single frame gives useful output.
 TEST(VP8VideoTrackEncoder, SingleFrameEncode)
 {
   TestVP8TrackEncoder encoder;
 
   // Pass a half-second frame to the encoder.
   YUVBufferGenerator generator;
   generator.Init(mozilla::gfx::IntSize(640, 480));
   VideoSegment segment;
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(45000), // 1/2 second
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 2), // 1/2 second
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE);
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(45000);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 2);
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
   // Read out encoded data, and verify.
@@ -338,26 +340,26 @@ TEST(VP8VideoTrackEncoder, SameFrameEnco
   // Pass 15 100ms frames to the encoder.
   YUVBufferGenerator generator;
   generator.Init(mozilla::gfx::IntSize(640, 480));
   RefPtr<Image> image = generator.GenerateI420Image();
   TimeStamp now = TimeStamp::Now();
   VideoSegment segment;
   for (uint32_t i = 0; i < 15; ++i) {
     segment.AppendFrame(do_AddRef(image),
-                        mozilla::StreamTime(9000), // 100ms
+                        mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 100ms
                         generator.GetSize(),
                         PRINCIPAL_HANDLE_NONE,
                         false,
                         now + TimeDuration::FromSeconds(i * 0.1));
   }
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(15 * 9000);
+  encoder.AdvanceCurrentTime((VIDEO_TRACK_RATE / 10) * 15);
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
   // Verify total duration being 1.5s.
@@ -377,34 +379,34 @@ TEST(VP8VideoTrackEncoder, NullFrameFirs
   generator.Init(mozilla::gfx::IntSize(640, 480));
   RefPtr<Image> image = generator.GenerateI420Image();
   TimeStamp now = TimeStamp::Now();
   VideoSegment segment;
 
   // Pass 2 100ms null frames to the encoder.
   for (uint32_t i = 0; i < 2; ++i) {
     segment.AppendFrame(nullptr,
-                        mozilla::StreamTime(9000), // 100ms
+                        mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 100ms
                         generator.GetSize(),
                         PRINCIPAL_HANDLE_NONE,
                         false,
                         now + TimeDuration::FromSeconds(i * 0.1));
   }
 
   // Pass a real 100ms frame to the encoder.
   segment.AppendFrame(image.forget(),
-                      mozilla::StreamTime(9000), // 100ms
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 100ms
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now + TimeDuration::FromSeconds(0.3));
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(3 * 9000);
+  encoder.AdvanceCurrentTime(3 * VIDEO_TRACK_RATE / 10);
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
   // Verify total duration being 0.3s.
@@ -464,34 +466,34 @@ TEST(VP8VideoTrackEncoder, RoundingError
   TimeStamp now = TimeStamp::Now();
   VideoSegment segment;
 
   // Pass nine frames with timestamps not expressable in 90kHz sample rate,
   // then one frame to make the total duration one second.
   uint32_t usPerFrame = 99999; //99.999ms
   for (uint32_t i = 0; i < 9; ++i) {
     segment.AppendFrame(generator.GenerateI420Image(),
-                        mozilla::StreamTime(9000), // 100ms
+                        mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 100ms
                         generator.GetSize(),
                         PRINCIPAL_HANDLE_NONE,
                         false,
                         now + TimeDuration::FromMicroseconds(i * usPerFrame));
   }
 
   // This last frame has timestamp start + 0.9s and duration 0.1s.
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(9000), // 100ms
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 100ms
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now + TimeDuration::FromSeconds(0.9));
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(10 * 9000);
+  encoder.AdvanceCurrentTime(10 * VIDEO_TRACK_RATE / 10);
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
   // Verify total duration being 1s.
@@ -510,37 +512,37 @@ TEST(VP8VideoTrackEncoder, TimestampFram
 
   // Pass 3 frames with duration 0.1s, but varying timestamps to the encoder.
   // Total duration of the segment should be the same for both.
   YUVBufferGenerator generator;
   generator.Init(mozilla::gfx::IntSize(640, 480));
   TimeStamp now = TimeStamp::Now();
   VideoSegment segment;
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(9000), // 0.1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 0.1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now);
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(9000), // 0.1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 0.1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now + TimeDuration::FromSeconds(0.05));
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(9000), // 0.1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 0.1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now + TimeDuration::FromSeconds(0.2));
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(3 * 9000);
+  encoder.AdvanceCurrentTime(3 * VIDEO_TRACK_RATE / 10);
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
   // Verify total duration being 4s and individual frames being [0.5s, 1.5s, 1s, 1s]
@@ -564,47 +566,47 @@ TEST(VP8VideoTrackEncoder, Suspended)
 
   // Pass 3 frames with duration 0.1s. We suspend before and resume after the
   // second frame.
   YUVBufferGenerator generator;
   generator.Init(mozilla::gfx::IntSize(640, 480));
   TimeStamp now = TimeStamp::Now();
   VideoSegment segment;
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(9000), // 0.1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 0.1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now);
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(9000);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 10);
 
   encoder.Suspend(now + TimeDuration::FromSeconds(0.1));
 
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(9000), // 0.1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 0.1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now + TimeDuration::FromSeconds(0.1));
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(9000);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 10);
 
   encoder.Resume(now + TimeDuration::FromSeconds(0.2));
 
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(9000), // 0.1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 0.1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now + TimeDuration::FromSeconds(0.2));
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(9000);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 10);
 
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
@@ -626,36 +628,36 @@ TEST(VP8VideoTrackEncoder, SuspendedUnti
   TestVP8TrackEncoder encoder;
 
   // Pass 2 frames with duration 0.1s. We suspend before the second frame.
   YUVBufferGenerator generator;
   generator.Init(mozilla::gfx::IntSize(640, 480));
   TimeStamp now = TimeStamp::Now();
   VideoSegment segment;
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(9000), // 0.1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 0.1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now);
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(9000);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 10);
 
   encoder.Suspend(now + TimeDuration::FromSeconds(0.1));
 
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(9000), // 0.1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 10), // 0.1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now + TimeDuration::FromSeconds(0.1));
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(9000);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 10);
 
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
@@ -681,25 +683,25 @@ TEST(VP8VideoTrackEncoder, AlwaysSuspend
   generator.Init(mozilla::gfx::IntSize(640, 480));
 
   TimeStamp now = TimeStamp::Now();
 
   encoder.Suspend(now);
 
   VideoSegment segment;
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(180000), // 2s
+                      mozilla::StreamTime(2 * VIDEO_TRACK_RATE), // 2s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now);
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(180000);
+  encoder.AdvanceCurrentTime(2 * VIDEO_TRACK_RATE);
 
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
@@ -716,36 +718,36 @@ TEST(VP8VideoTrackEncoder, SuspendedBegi
 
   // Suspend and pass a frame with duration 0.5s. Then resume and pass one more.
   encoder.Suspend(now);
 
   YUVBufferGenerator generator;
   generator.Init(mozilla::gfx::IntSize(640, 480));
   VideoSegment segment;
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(45000), // 0.5s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 2), // 0.5s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now);
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(45000);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 2);
 
   encoder.Resume(now + TimeDuration::FromSeconds(0.5));
 
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(45000), // 0.5s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE / 2), // 0.5s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now + TimeDuration::FromSeconds(0.5));
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(45000);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 2);
 
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
@@ -768,39 +770,39 @@ TEST(VP8VideoTrackEncoder, SuspendedOver
   TestVP8TrackEncoder encoder;
 
   // Pass a 1s frame and suspend after 0.5s.
   YUVBufferGenerator generator;
   generator.Init(mozilla::gfx::IntSize(640, 480));
   TimeStamp now = TimeStamp::Now();
   VideoSegment segment;
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(90000), // 1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE), // 1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now);
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
 
-  encoder.AdvanceCurrentTime(45000);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 2);
   encoder.Suspend(now + TimeDuration::FromSeconds(0.5));
 
   // Pass another 1s frame and resume after 0.3 of this new frame.
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(90000), // 1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE), // 1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now + TimeDuration::FromSeconds(1));
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(72000);
+  encoder.AdvanceCurrentTime((VIDEO_TRACK_RATE / 10) * 8);
   encoder.Resume(now + TimeDuration::FromSeconds(1.3));
-  encoder.AdvanceCurrentTime(63000);
+  encoder.AdvanceCurrentTime((VIDEO_TRACK_RATE / 10) * 7);
 
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
@@ -822,25 +824,134 @@ TEST(VP8VideoTrackEncoder, PrematureEndi
   TestVP8TrackEncoder encoder;
 
   // Pass a 1s frame and end the track after 0.5s.
   YUVBufferGenerator generator;
   generator.Init(mozilla::gfx::IntSize(640, 480));
   TimeStamp now = TimeStamp::Now();
   VideoSegment segment;
   segment.AppendFrame(generator.GenerateI420Image(),
-                      mozilla::StreamTime(90000), // 1s
+                      mozilla::StreamTime(VIDEO_TRACK_RATE), // 1s
                       generator.GetSize(),
                       PRINCIPAL_HANDLE_NONE,
                       false,
                       now);
 
   encoder.SetStartOffset(0);
   encoder.AppendVideoSegment(Move(segment));
-  encoder.AdvanceCurrentTime(45000);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 2);
+  encoder.NotifyEndOfStream();
+
+  EncodedFrameContainer container;
+  ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
+
+  EXPECT_TRUE(encoder.IsEncodingComplete());
+
+  uint64_t totalDuration = 0;
+  for (auto& frame : container.GetEncodedFrames()) {
+    totalDuration += frame->GetDuration();
+  }
+  const uint64_t half = PR_USEC_PER_SEC / 2;
+  EXPECT_EQ(half, totalDuration);
+}
+
+// Test that a track that starts at t > 0 works as expected.
+TEST(VP8VideoTrackEncoder, DelayedStart)
+{
+  TestVP8TrackEncoder encoder;
+
+  // Pass a 2s frame, start (pass first CurrentTime) at 0.5s, end at 1s.
+  // Should result in a 0.5s encoding.
+  YUVBufferGenerator generator;
+  generator.Init(mozilla::gfx::IntSize(640, 480));
+  TimeStamp now = TimeStamp::Now();
+  VideoSegment segment;
+  segment.AppendFrame(generator.GenerateI420Image(),
+                      mozilla::StreamTime(2 * VIDEO_TRACK_RATE), // 2s
+                      generator.GetSize(),
+                      PRINCIPAL_HANDLE_NONE,
+                      false,
+                      now);
+
+  encoder.SetStartOffset(VIDEO_TRACK_RATE / 2);
+  encoder.AppendVideoSegment(Move(segment));
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 2);
+  encoder.NotifyEndOfStream();
+
+  EncodedFrameContainer container;
+  ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
+
+  EXPECT_TRUE(encoder.IsEncodingComplete());
+
+  uint64_t totalDuration = 0;
+  for (auto& frame : container.GetEncodedFrames()) {
+    totalDuration += frame->GetDuration();
+  }
+  const uint64_t half = PR_USEC_PER_SEC / 2;
+  EXPECT_EQ(half, totalDuration);
+}
+
+// Test that a track that starts at t > 0 works as expected, when
+// SetStartOffset comes after AppendVideoSegment.
+TEST(VP8VideoTrackEncoder, DelayedStartOtherEventOrder)
+{
+  TestVP8TrackEncoder encoder;
+
+  // Pass a 2s frame, start (pass first CurrentTime) at 0.5s, end at 1s.
+  // Should result in a 0.5s encoding.
+  YUVBufferGenerator generator;
+  generator.Init(mozilla::gfx::IntSize(640, 480));
+  TimeStamp now = TimeStamp::Now();
+  VideoSegment segment;
+  segment.AppendFrame(generator.GenerateI420Image(),
+                      mozilla::StreamTime(2 * VIDEO_TRACK_RATE), // 2s
+                      generator.GetSize(),
+                      PRINCIPAL_HANDLE_NONE,
+                      false,
+                      now);
+
+  encoder.AppendVideoSegment(Move(segment));
+  encoder.SetStartOffset(VIDEO_TRACK_RATE / 2);
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 2);
+  encoder.NotifyEndOfStream();
+
+  EncodedFrameContainer container;
+  ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
+
+  EXPECT_TRUE(encoder.IsEncodingComplete());
+
+  uint64_t totalDuration = 0;
+  for (auto& frame : container.GetEncodedFrames()) {
+    totalDuration += frame->GetDuration();
+  }
+  const uint64_t half = PR_USEC_PER_SEC / 2;
+  EXPECT_EQ(half, totalDuration);
+}
+
+// Test that a track that starts at t >>> 0 works as expected.
+TEST(VP8VideoTrackEncoder, VeryDelayedStart)
+{
+  TestVP8TrackEncoder encoder;
+
+  // Pass a 1s frame, start (pass first CurrentTime) at 10s, end at 10.5s.
+  // Should result in a 0.5s encoding.
+  YUVBufferGenerator generator;
+  generator.Init(mozilla::gfx::IntSize(640, 480));
+  TimeStamp now = TimeStamp::Now();
+  VideoSegment segment;
+  segment.AppendFrame(generator.GenerateI420Image(),
+                      mozilla::StreamTime(VIDEO_TRACK_RATE), // 1s
+                      generator.GetSize(),
+                      PRINCIPAL_HANDLE_NONE,
+                      false,
+                      now);
+
+  encoder.SetStartOffset(VIDEO_TRACK_RATE * 10);
+  encoder.AppendVideoSegment(Move(segment));
+  encoder.AdvanceCurrentTime(VIDEO_TRACK_RATE / 2);
   encoder.NotifyEndOfStream();
 
   EncodedFrameContainer container;
   ASSERT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
 
   EXPECT_TRUE(encoder.IsEncodingComplete());
 
   uint64_t totalDuration = 0;