1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// Tests PPB_MediaStreamVideoTrack interface.
6
7#include "ppapi/tests/test_media_stream_video_track.h"
8
9#include "ppapi/c/private/ppb_testing_private.h"
10#include "ppapi/cpp/completion_callback.h"
11#include "ppapi/cpp/instance.h"
12#include "ppapi/cpp/var.h"
13#include "ppapi/cpp/video_frame.h"
14#include "ppapi/tests/test_utils.h"
15#include "ppapi/tests/testing_instance.h"
16
17REGISTER_TEST_CASE(MediaStreamVideoTrack);
18
19namespace {
20
21const int32_t kTimes = 3;
22const int32_t kDefaultWidth = 640;
23const int32_t kDefaultHeight = 480;
24const char kJSCode[] =
25    "function gotStream(stream) {"
26    "  var track = stream.getVideoTracks()[0];"
27    "  var plugin = document.getElementById('plugin');"
28    "  plugin.postMessage(track);"
29    "}"
30    "var constraints = {"
31    "  audio: false,"
32    "  video: { mandatory: { minWidth: 640, minHeight: 480 } }"
33    "};"
34    "navigator.getUserMedia ="
35    "    navigator.getUserMedia || navigator.webkitGetUserMedia;"
36    "navigator.getUserMedia(constraints,"
37    "    gotStream, function() {});";
38}
39
40TestMediaStreamVideoTrack::TestMediaStreamVideoTrack(TestingInstance* instance)
41    : TestCase(instance),
42      event_(instance_->pp_instance()) {
43}
44
45bool TestMediaStreamVideoTrack::Init() {
46  return true;
47}
48
49TestMediaStreamVideoTrack::~TestMediaStreamVideoTrack() {
50}
51
52void TestMediaStreamVideoTrack::RunTests(const std::string& filter) {
53  RUN_TEST(Create, filter);
54  RUN_TEST(GetFrame, filter);
55  RUN_TEST(Configure, filter);
56}
57
58void TestMediaStreamVideoTrack::HandleMessage(const pp::Var& message) {
59  if (message.is_resource())
60    video_track_ = pp::MediaStreamVideoTrack(message.AsResource());
61  event_.Signal();
62}
63
64std::string TestMediaStreamVideoTrack::TestCreate() {
65  // Create a track.
66  instance_->EvalScript(kJSCode);
67  event_.Wait();
68  event_.Reset();
69
70  ASSERT_FALSE(video_track_.is_null());
71  ASSERT_FALSE(video_track_.HasEnded());
72  ASSERT_FALSE(video_track_.GetId().empty());
73
74  // Close the track.
75  video_track_.Close();
76  ASSERT_TRUE(video_track_.HasEnded());
77  video_track_ = pp::MediaStreamVideoTrack();
78  PASS();
79}
80
81std::string TestMediaStreamVideoTrack::TestGetFrame() {
82  // Create a track.
83  instance_->EvalScript(kJSCode);
84  event_.Wait();
85  event_.Reset();
86
87  ASSERT_FALSE(video_track_.is_null());
88  ASSERT_FALSE(video_track_.HasEnded());
89  ASSERT_FALSE(video_track_.GetId().empty());
90
91  PP_TimeDelta timestamp = 0.0;
92
93  // Get |kTimes| frames.
94  for (int i = 0; i < kTimes; ++i) {
95    TestCompletionCallbackWithOutput<pp::VideoFrame> cc(
96        instance_->pp_instance(), false);
97    cc.WaitForResult(video_track_.GetFrame(cc.GetCallback()));
98    ASSERT_EQ(PP_OK, cc.result());
99    pp::VideoFrame frame = cc.output();
100    ASSERT_FALSE(frame.is_null());
101    ASSERT_TRUE(frame.GetFormat() == PP_VIDEOFRAME_FORMAT_YV12 ||
102                frame.GetFormat() == PP_VIDEOFRAME_FORMAT_I420);
103
104    pp::Size size;
105    ASSERT_TRUE(frame.GetSize(&size));
106    ASSERT_EQ(size.width(), kDefaultWidth);
107    ASSERT_EQ(size.height(), kDefaultHeight);
108
109    ASSERT_GE(frame.GetTimestamp(), timestamp);
110    timestamp = frame.GetTimestamp();
111
112    ASSERT_GT(frame.GetDataBufferSize(), 0U);
113    ASSERT_TRUE(frame.GetDataBuffer() != NULL);
114
115    video_track_.RecycleFrame(frame);
116
117    // A recycled frame should be invalidated.
118    ASSERT_EQ(frame.GetFormat(), PP_VIDEOFRAME_FORMAT_UNKNOWN);
119    ASSERT_FALSE(frame.GetSize(&size));
120    ASSERT_EQ(frame.GetDataBufferSize(), 0U);
121    ASSERT_TRUE(frame.GetDataBuffer() == NULL);
122  }
123
124  // Close the track.
125  video_track_.Close();
126  ASSERT_TRUE(video_track_.HasEnded());
127  video_track_ = pp::MediaStreamVideoTrack();
128  PASS();
129}
130
131std::string TestMediaStreamVideoTrack::TestConfigure() {
132  // Create a track.
133  instance_->EvalScript(kJSCode);
134  event_.Wait();
135  event_.Reset();
136
137  ASSERT_FALSE(video_track_.is_null());
138  ASSERT_FALSE(video_track_.HasEnded());
139  ASSERT_FALSE(video_track_.GetId().empty());
140
141  // Configure format.
142  struct {
143    int32_t format;
144    int32_t expected_format;
145  } formats[] = {
146    { PP_VIDEOFRAME_FORMAT_BGRA, PP_VIDEOFRAME_FORMAT_BGRA }, // To RGBA.
147    { PP_VIDEOFRAME_FORMAT_I420, PP_VIDEOFRAME_FORMAT_I420 }, // To I420.
148    { PP_VIDEOFRAME_FORMAT_YV12, PP_VIDEOFRAME_FORMAT_YV12 }, // To YV12.
149    { PP_VIDEOFRAME_FORMAT_BGRA, PP_VIDEOFRAME_FORMAT_BGRA }, // To RGBA.
150    { PP_VIDEOFRAME_FORMAT_UNKNOWN, PP_VIDEOFRAME_FORMAT_YV12 }, // To default.
151  };
152  for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) {
153    TestCompletionCallback cc1(instance_->pp_instance(), false);
154    int32_t attrib_list[] = {
155      PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT, formats[i].format,
156      PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE,
157    };
158    cc1.WaitForResult(video_track_.Configure(attrib_list, cc1.GetCallback()));
159    ASSERT_EQ(PP_OK, cc1.result());
160
161    for (int j = 0; j < kTimes; ++j) {
162      TestCompletionCallbackWithOutput<pp::VideoFrame> cc2(
163          instance_->pp_instance(), false);
164      cc2.WaitForResult(video_track_.GetFrame(cc2.GetCallback()));
165      ASSERT_EQ(PP_OK, cc2.result());
166      pp::VideoFrame frame = cc2.output();
167      ASSERT_FALSE(frame.is_null());
168      if (formats[i].format != PP_VIDEOFRAME_FORMAT_UNKNOWN) {
169        ASSERT_EQ(frame.GetFormat(), formats[i].expected_format);
170      } else {
171        // Both YV12 and I420 are acceptable as default YUV formats.
172        ASSERT_TRUE(frame.GetFormat() == PP_VIDEOFRAME_FORMAT_YV12 ||
173                    frame.GetFormat() == PP_VIDEOFRAME_FORMAT_I420);
174      }
175
176      pp::Size size;
177      ASSERT_TRUE(frame.GetSize(&size));
178      ASSERT_EQ(size.width(), kDefaultWidth);
179      ASSERT_EQ(size.height(), kDefaultHeight);
180
181      ASSERT_GT(frame.GetDataBufferSize(), 0U);
182      ASSERT_TRUE(frame.GetDataBuffer() != NULL);
183
184      video_track_.RecycleFrame(frame);
185    }
186  }
187
188  // Configure size.
189  struct {
190    int32_t width;
191    int32_t height;
192    int32_t expect_width;
193    int32_t expect_height;
194  } sizes[] = {
195    { 72, 72, 72, 72 }, // To 72x27.
196    { 1024, 768, 1024, 768 }, // To 1024x768.
197    { 0, 0, kDefaultWidth, kDefaultHeight }, // To default.
198  };
199  for (size_t i = 0; i < sizeof(sizes) / sizeof(sizes[0]); ++i) {
200    TestCompletionCallback cc1(instance_->pp_instance(), false);
201    int32_t attrib_list[] = {
202      PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH, sizes[i].width,
203      PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT, sizes[i].height,
204      PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE,
205    };
206    cc1.WaitForResult(video_track_.Configure(attrib_list, cc1.GetCallback()));
207    ASSERT_EQ(PP_OK, cc1.result());
208
209    for (int j = 0; j < kTimes; ++j) {
210      TestCompletionCallbackWithOutput<pp::VideoFrame> cc2(
211          instance_->pp_instance(), false);
212      cc2.WaitForResult(video_track_.GetFrame(cc2.GetCallback()));
213      ASSERT_EQ(PP_OK, cc2.result());
214      pp::VideoFrame frame = cc2.output();
215      ASSERT_FALSE(frame.is_null());
216      ASSERT_TRUE(frame.GetFormat() == PP_VIDEOFRAME_FORMAT_YV12 ||
217                  frame.GetFormat() == PP_VIDEOFRAME_FORMAT_I420);
218
219      pp::Size size;
220      ASSERT_TRUE(frame.GetSize(&size));
221      ASSERT_EQ(size.width(), sizes[i].expect_width);
222      ASSERT_EQ(size.height(), sizes[i].expect_height);
223
224      ASSERT_GT(frame.GetDataBufferSize(), 0U);
225      ASSERT_TRUE(frame.GetDataBuffer() != NULL);
226
227      video_track_.RecycleFrame(frame);
228    }
229  }
230
231  // Close the track.
232  video_track_.Close();
233  ASSERT_TRUE(video_track_.HasEnded());
234  video_track_ = pp::MediaStreamVideoTrack();
235  PASS();
236}
237