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