| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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 #include <stdint.h> | |
| 6 #include <string.h> | |
| 7 | |
| 8 #include "base/bind.h" | |
| 9 #include "base/location.h" | |
| 10 #include "base/single_thread_task_runner.h" | |
| 11 #include "base/synchronization/waitable_event.h" | |
| 12 #include "base/threading/thread.h" | |
| 13 #include "base/threading/thread_task_runner_handle.h" | |
| 14 #include "content/renderer/media/rtc_video_decoder.h" | |
| 15 #include "media/base/gmock_callback_support.h" | |
| 16 #include "media/renderers/mock_gpu_video_accelerator_factories.h" | |
| 17 #include "media/video/mock_video_decode_accelerator.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 | |
| 20 #if defined(OS_WIN) | |
| 21 #include "base/command_line.h" | |
| 22 #include "content/public/common/content_switches.h" | |
| 23 #endif // defined(OS_WIN) | |
| 24 | |
| 25 using ::testing::_; | |
| 26 using ::testing::Invoke; | |
| 27 using ::testing::Return; | |
| 28 using ::testing::SaveArg; | |
| 29 using ::testing::Values; | |
| 30 using ::testing::WithArgs; | |
| 31 | |
| 32 namespace content { | |
| 33 | |
| 34 namespace { | |
| 35 | |
| 36 static const int kMinResolutionWidth = 16; | |
| 37 static const int kMinResolutionHeight = 16; | |
| 38 static const int kMaxResolutionWidth = 1920; | |
| 39 static const int kMaxResolutionHeight = 1088; | |
| 40 | |
| 41 } // namespace | |
| 42 | |
| 43 // TODO(wuchengli): add MockSharedMemory so more functions can be tested. | |
| 44 class RTCVideoDecoderTest | |
| 45 : public ::testing::TestWithParam<webrtc::VideoCodecType>, | |
| 46 webrtc::DecodedImageCallback { | |
| 47 public: | |
| 48 RTCVideoDecoderTest() | |
| 49 : mock_gpu_factories_( | |
| 50 new media::MockGpuVideoAcceleratorFactories(nullptr)), | |
| 51 vda_thread_("vda_thread"), | |
| 52 idle_waiter_(base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
| 53 base::WaitableEvent::InitialState::NOT_SIGNALED) { | |
| 54 memset(&codec_, 0, sizeof(codec_)); | |
| 55 } | |
| 56 | |
| 57 void SetUp() override { | |
| 58 ASSERT_TRUE(vda_thread_.Start()); | |
| 59 vda_task_runner_ = vda_thread_.task_runner(); | |
| 60 mock_vda_ = new media::MockVideoDecodeAccelerator; | |
| 61 | |
| 62 media::VideoDecodeAccelerator::SupportedProfile supported_profile; | |
| 63 supported_profile.min_resolution.SetSize(kMinResolutionWidth, | |
| 64 kMinResolutionHeight); | |
| 65 supported_profile.max_resolution.SetSize(kMaxResolutionWidth, | |
| 66 kMaxResolutionHeight); | |
| 67 supported_profile.profile = media::H264PROFILE_MAIN; | |
| 68 capabilities_.supported_profiles.push_back(supported_profile); | |
| 69 supported_profile.profile = media::VP8PROFILE_ANY; | |
| 70 capabilities_.supported_profiles.push_back(supported_profile); | |
| 71 | |
| 72 EXPECT_CALL(*mock_gpu_factories_.get(), GetTaskRunner()) | |
| 73 .WillRepeatedly(Return(vda_task_runner_)); | |
| 74 EXPECT_CALL(*mock_gpu_factories_.get(), | |
| 75 GetVideoDecodeAcceleratorCapabilities()) | |
| 76 .WillRepeatedly(Return(capabilities_)); | |
| 77 EXPECT_CALL(*mock_gpu_factories_.get(), DoCreateVideoDecodeAccelerator()) | |
| 78 .WillRepeatedly(Return(mock_vda_)); | |
| 79 EXPECT_CALL(*mock_vda_, Initialize(_, _)) | |
| 80 .Times(1) | |
| 81 .WillRepeatedly(Return(true)); | |
| 82 EXPECT_CALL(*mock_vda_, Destroy()).Times(1); | |
| 83 | |
| 84 #if defined(OS_WIN) | |
| 85 base::CommandLine::ForCurrentProcess()->AppendSwitch( | |
| 86 switches::kEnableWin7WebRtcHWH264Decoding); | |
| 87 #endif // defined(OS_WIN) | |
| 88 } | |
| 89 | |
| 90 void TearDown() override { | |
| 91 DVLOG(2) << "TearDown"; | |
| 92 EXPECT_TRUE(vda_thread_.IsRunning()); | |
| 93 RunUntilIdle(); // Wait until all callbascks complete. | |
| 94 vda_task_runner_->DeleteSoon(FROM_HERE, rtc_decoder_.release()); | |
| 95 // Make sure the decoder is released before stopping the thread. | |
| 96 RunUntilIdle(); | |
| 97 vda_thread_.Stop(); | |
| 98 } | |
| 99 | |
| 100 int32_t Decoded(webrtc::VideoFrame& decoded_image) override { | |
| 101 DVLOG(2) << "Decoded"; | |
| 102 EXPECT_EQ(vda_task_runner_, base::ThreadTaskRunnerHandle::Get()); | |
| 103 return WEBRTC_VIDEO_CODEC_OK; | |
| 104 } | |
| 105 | |
| 106 void CreateDecoder(webrtc::VideoCodecType codec_type) { | |
| 107 DVLOG(2) << "CreateDecoder"; | |
| 108 codec_.codecType = codec_type; | |
| 109 rtc_decoder_ = | |
| 110 RTCVideoDecoder::Create(codec_type, mock_gpu_factories_.get()); | |
| 111 } | |
| 112 | |
| 113 void Initialize() { | |
| 114 DVLOG(2) << "Initialize"; | |
| 115 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->InitDecode(&codec_, 1)); | |
| 116 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, | |
| 117 rtc_decoder_->RegisterDecodeCompleteCallback(this)); | |
| 118 } | |
| 119 | |
| 120 void NotifyResetDone() { | |
| 121 DVLOG(2) << "NotifyResetDone"; | |
| 122 vda_task_runner_->PostTask( | |
| 123 FROM_HERE, | |
| 124 base::Bind(&RTCVideoDecoder::NotifyResetDone, | |
| 125 base::Unretained(rtc_decoder_.get()))); | |
| 126 } | |
| 127 | |
| 128 void NotifyError(media::VideoDecodeAccelerator::Error error) { | |
| 129 DVLOG(2) << "NotifyError"; | |
| 130 vda_task_runner_->PostTask( | |
| 131 FROM_HERE, | |
| 132 base::Bind(&RTCVideoDecoder::NotifyError, | |
| 133 base::Unretained(rtc_decoder_.get()), error)); | |
| 134 } | |
| 135 | |
| 136 void RunUntilIdle() { | |
| 137 DVLOG(2) << "RunUntilIdle"; | |
| 138 vda_task_runner_->PostTask(FROM_HERE, | |
| 139 base::Bind(&base::WaitableEvent::Signal, | |
| 140 base::Unretained(&idle_waiter_))); | |
| 141 idle_waiter_.Wait(); | |
| 142 } | |
| 143 | |
| 144 void SetUpResetVDA() { | |
| 145 mock_vda_after_reset_ = new media::MockVideoDecodeAccelerator; | |
| 146 EXPECT_CALL(*mock_gpu_factories_.get(), DoCreateVideoDecodeAccelerator()) | |
| 147 .WillRepeatedly(Return(mock_vda_after_reset_)); | |
| 148 EXPECT_CALL(*mock_vda_after_reset_, Initialize(_, _)) | |
| 149 .Times(1) | |
| 150 .WillRepeatedly(Return(true)); | |
| 151 EXPECT_CALL(*mock_vda_after_reset_, Destroy()).Times(1); | |
| 152 } | |
| 153 | |
| 154 protected: | |
| 155 std::unique_ptr<media::MockGpuVideoAcceleratorFactories> mock_gpu_factories_; | |
| 156 media::MockVideoDecodeAccelerator* mock_vda_; | |
| 157 media::MockVideoDecodeAccelerator* mock_vda_after_reset_; | |
| 158 std::unique_ptr<RTCVideoDecoder> rtc_decoder_; | |
| 159 webrtc::VideoCodec codec_; | |
| 160 base::Thread vda_thread_; | |
| 161 media::VideoDecodeAccelerator::Capabilities capabilities_; | |
| 162 | |
| 163 private: | |
| 164 scoped_refptr<base::SingleThreadTaskRunner> vda_task_runner_; | |
| 165 | |
| 166 base::Lock lock_; | |
| 167 base::WaitableEvent idle_waiter_; | |
| 168 }; | |
| 169 | |
| 170 TEST_F(RTCVideoDecoderTest, CreateReturnsNullOnUnsupportedCodec) { | |
| 171 CreateDecoder(webrtc::kVideoCodecVP8); | |
| 172 std::unique_ptr<RTCVideoDecoder> null_rtc_decoder(RTCVideoDecoder::Create( | |
| 173 webrtc::kVideoCodecI420, mock_gpu_factories_.get())); | |
| 174 EXPECT_EQ(NULL, null_rtc_decoder.get()); | |
| 175 } | |
| 176 | |
| 177 TEST_P(RTCVideoDecoderTest, CreateAndInitSucceeds) { | |
| 178 const webrtc::VideoCodecType codec_type = GetParam(); | |
| 179 CreateDecoder(codec_type); | |
| 180 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->InitDecode(&codec_, 1)); | |
| 181 } | |
| 182 | |
| 183 TEST_F(RTCVideoDecoderTest, InitDecodeReturnsErrorOnFeedbackMode) { | |
| 184 CreateDecoder(webrtc::kVideoCodecVP8); | |
| 185 codec_.codecSpecific.VP8.feedbackModeOn = true; | |
| 186 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, rtc_decoder_->InitDecode(&codec_, 1)); | |
| 187 } | |
| 188 | |
| 189 TEST_F(RTCVideoDecoderTest, DecodeReturnsErrorWithoutInitDecode) { | |
| 190 CreateDecoder(webrtc::kVideoCodecVP8); | |
| 191 webrtc::EncodedImage input_image; | |
| 192 EXPECT_EQ(WEBRTC_VIDEO_CODEC_UNINITIALIZED, | |
| 193 rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0)); | |
| 194 } | |
| 195 | |
| 196 TEST_F(RTCVideoDecoderTest, DecodeReturnsErrorOnIncompleteFrame) { | |
| 197 CreateDecoder(webrtc::kVideoCodecVP8); | |
| 198 Initialize(); | |
| 199 webrtc::EncodedImage input_image; | |
| 200 input_image._completeFrame = false; | |
| 201 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, | |
| 202 rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0)); | |
| 203 } | |
| 204 | |
| 205 TEST_F(RTCVideoDecoderTest, DecodeReturnsErrorOnMissingFrames) { | |
| 206 CreateDecoder(webrtc::kVideoCodecVP8); | |
| 207 Initialize(); | |
| 208 webrtc::EncodedImage input_image; | |
| 209 input_image._completeFrame = true; | |
| 210 bool missingFrames = true; | |
| 211 EXPECT_EQ( | |
| 212 WEBRTC_VIDEO_CODEC_ERROR, | |
| 213 rtc_decoder_->Decode(input_image, missingFrames, nullptr, nullptr, 0)); | |
| 214 } | |
| 215 | |
| 216 TEST_F(RTCVideoDecoderTest, ReleaseReturnsOk) { | |
| 217 CreateDecoder(webrtc::kVideoCodecVP8); | |
| 218 Initialize(); | |
| 219 EXPECT_CALL(*mock_vda_, Reset()) | |
| 220 .WillOnce(Invoke(this, &RTCVideoDecoderTest::NotifyResetDone)); | |
| 221 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->Release()); | |
| 222 } | |
| 223 | |
| 224 TEST_F(RTCVideoDecoderTest, InitDecodeAfterRelease) { | |
| 225 CreateDecoder(webrtc::kVideoCodecVP8); | |
| 226 EXPECT_CALL(*mock_vda_, Reset()) | |
| 227 .WillRepeatedly(Invoke(this, &RTCVideoDecoderTest::NotifyResetDone)); | |
| 228 Initialize(); | |
| 229 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->Release()); | |
| 230 Initialize(); | |
| 231 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, rtc_decoder_->Release()); | |
| 232 } | |
| 233 | |
| 234 TEST_F(RTCVideoDecoderTest, IsBufferAfterReset) { | |
| 235 CreateDecoder(webrtc::kVideoCodecVP8); | |
| 236 EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(0, RTCVideoDecoder::ID_INVALID)); | |
| 237 EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST, | |
| 238 RTCVideoDecoder::ID_INVALID)); | |
| 239 EXPECT_FALSE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_HALF - 2, | |
| 240 RTCVideoDecoder::ID_HALF + 2)); | |
| 241 EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_HALF + 2, | |
| 242 RTCVideoDecoder::ID_HALF - 2)); | |
| 243 | |
| 244 EXPECT_FALSE(rtc_decoder_->IsBufferAfterReset(0, 0)); | |
| 245 EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(0, RTCVideoDecoder::ID_LAST)); | |
| 246 EXPECT_FALSE( | |
| 247 rtc_decoder_->IsBufferAfterReset(0, RTCVideoDecoder::ID_HALF - 2)); | |
| 248 EXPECT_TRUE( | |
| 249 rtc_decoder_->IsBufferAfterReset(0, RTCVideoDecoder::ID_HALF + 2)); | |
| 250 | |
| 251 EXPECT_FALSE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST, 0)); | |
| 252 EXPECT_FALSE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST, | |
| 253 RTCVideoDecoder::ID_HALF - 2)); | |
| 254 EXPECT_TRUE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST, | |
| 255 RTCVideoDecoder::ID_HALF + 2)); | |
| 256 EXPECT_FALSE(rtc_decoder_->IsBufferAfterReset(RTCVideoDecoder::ID_LAST, | |
| 257 RTCVideoDecoder::ID_LAST)); | |
| 258 } | |
| 259 | |
| 260 TEST_F(RTCVideoDecoderTest, IsFirstBufferAfterReset) { | |
| 261 CreateDecoder(webrtc::kVideoCodecVP8); | |
| 262 EXPECT_TRUE( | |
| 263 rtc_decoder_->IsFirstBufferAfterReset(0, RTCVideoDecoder::ID_INVALID)); | |
| 264 EXPECT_FALSE( | |
| 265 rtc_decoder_->IsFirstBufferAfterReset(1, RTCVideoDecoder::ID_INVALID)); | |
| 266 EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(0, 0)); | |
| 267 EXPECT_TRUE(rtc_decoder_->IsFirstBufferAfterReset(1, 0)); | |
| 268 EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(2, 0)); | |
| 269 | |
| 270 EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(RTCVideoDecoder::ID_HALF, | |
| 271 RTCVideoDecoder::ID_HALF)); | |
| 272 EXPECT_TRUE(rtc_decoder_->IsFirstBufferAfterReset( | |
| 273 RTCVideoDecoder::ID_HALF + 1, RTCVideoDecoder::ID_HALF)); | |
| 274 EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset( | |
| 275 RTCVideoDecoder::ID_HALF + 2, RTCVideoDecoder::ID_HALF)); | |
| 276 | |
| 277 EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(RTCVideoDecoder::ID_LAST, | |
| 278 RTCVideoDecoder::ID_LAST)); | |
| 279 EXPECT_TRUE( | |
| 280 rtc_decoder_->IsFirstBufferAfterReset(0, RTCVideoDecoder::ID_LAST)); | |
| 281 EXPECT_FALSE( | |
| 282 rtc_decoder_->IsFirstBufferAfterReset(1, RTCVideoDecoder::ID_LAST)); | |
| 283 } | |
| 284 | |
| 285 | |
| 286 TEST_P(RTCVideoDecoderTest, GetVDAErrorCounterForTesting) { | |
| 287 const webrtc::VideoCodecType codec_type = GetParam(); | |
| 288 CreateDecoder(codec_type); | |
| 289 Initialize(); | |
| 290 | |
| 291 webrtc::EncodedImage input_image; | |
| 292 input_image._completeFrame = true; | |
| 293 input_image._encodedWidth = kMinResolutionWidth; | |
| 294 input_image._encodedHeight = kMaxResolutionHeight; | |
| 295 input_image._frameType = webrtc::kVideoFrameDelta; | |
| 296 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, | |
| 297 rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0)); | |
| 298 RunUntilIdle(); | |
| 299 | |
| 300 // Notify the decoder about a platform error. | |
| 301 NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE); | |
| 302 RunUntilIdle(); | |
| 303 EXPECT_EQ(1, rtc_decoder_->GetVDAErrorCounterForTesting()); | |
| 304 | |
| 305 // Expect decode call to reset decoder, and set up a new VDA to track it. | |
| 306 SetUpResetVDA(); | |
| 307 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, | |
| 308 rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0)); | |
| 309 EXPECT_EQ(1, rtc_decoder_->GetVDAErrorCounterForTesting()); | |
| 310 | |
| 311 // Decoder expects a keyframe after reset, so drops any other frames. | |
| 312 EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, | |
| 313 rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 0)); | |
| 314 EXPECT_EQ(1, rtc_decoder_->GetVDAErrorCounterForTesting()); | |
| 315 | |
| 316 // Decoder resets error counter after a successfull decode. | |
| 317 input_image._frameType = webrtc::kVideoFrameKey; | |
| 318 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, | |
| 319 rtc_decoder_->Decode(input_image, false, nullptr, nullptr, 10)); | |
| 320 EXPECT_EQ(0, rtc_decoder_->GetVDAErrorCounterForTesting()); | |
| 321 } | |
| 322 | |
| 323 INSTANTIATE_TEST_CASE_P(CodecProfiles, | |
| 324 RTCVideoDecoderTest, | |
| 325 Values(webrtc::kVideoCodecVP8, | |
| 326 webrtc::kVideoCodecH264)); | |
| 327 | |
| 328 } // content | |
| OLD | NEW |