--- 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;