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 <utility> 6 7#include "base/bind.h" 8#include "base/callback.h" 9#include "base/callback_helpers.h" 10#include "base/debug/stack_trace.h" 11#include "base/message_loop/message_loop.h" 12#include "base/stl_util.h" 13#include "base/strings/string_number_conversions.h" 14#include "base/strings/string_split.h" 15#include "base/strings/stringprintf.h" 16#include "base/synchronization/lock.h" 17#include "base/timer/timer.h" 18#include "media/base/data_buffer.h" 19#include "media/base/gmock_callback_support.h" 20#include "media/base/limits.h" 21#include "media/base/mock_filters.h" 22#include "media/base/test_helpers.h" 23#include "media/base/video_frame.h" 24#include "media/filters/video_renderer_impl.h" 25#include "testing/gtest/include/gtest/gtest.h" 26 27using ::testing::_; 28using ::testing::AnyNumber; 29using ::testing::Invoke; 30using ::testing::NiceMock; 31using ::testing::Return; 32using ::testing::SaveArg; 33using ::testing::StrictMock; 34 35namespace media { 36 37ACTION_P(RunClosure, closure) { 38 closure.Run(); 39} 40 41MATCHER_P(HasTimestamp, ms, "") { 42 *result_listener << "has timestamp " << arg->timestamp().InMilliseconds(); 43 return arg->timestamp().InMilliseconds() == ms; 44} 45 46class VideoRendererImplTest : public ::testing::Test { 47 public: 48 VideoRendererImplTest() 49 : decoder_(new MockVideoDecoder()), 50 demuxer_stream_(DemuxerStream::VIDEO) { 51 ScopedVector<VideoDecoder> decoders; 52 decoders.push_back(decoder_); 53 54 renderer_.reset(new VideoRendererImpl( 55 message_loop_.message_loop_proxy(), 56 decoders.Pass(), 57 media::SetDecryptorReadyCB(), 58 base::Bind(&StrictMock<MockCB>::Display, base::Unretained(&mock_cb_)), 59 true, 60 new MediaLog())); 61 62 demuxer_stream_.set_video_decoder_config(TestVideoConfig::Normal()); 63 64 // We expect these to be called but we don't care how/when. 65 EXPECT_CALL(demuxer_stream_, Read(_)).WillRepeatedly( 66 RunCallback<0>(DemuxerStream::kOk, 67 scoped_refptr<DecoderBuffer>(new DecoderBuffer(0)))); 68 } 69 70 virtual ~VideoRendererImplTest() {} 71 72 void Initialize() { 73 InitializeWithLowDelay(false); 74 } 75 76 void InitializeWithLowDelay(bool low_delay) { 77 // Monitor decodes from the decoder. 78 EXPECT_CALL(*decoder_, Decode(_, _)) 79 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested)); 80 81 EXPECT_CALL(*decoder_, Reset(_)) 82 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested)); 83 84 // Initialize, we shouldn't have any reads. 85 InitializeRenderer(PIPELINE_OK, low_delay); 86 } 87 88 void InitializeRenderer(PipelineStatus expected, bool low_delay) { 89 SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected)); 90 WaitableMessageLoopEvent event; 91 CallInitialize(event.GetPipelineStatusCB(), low_delay, expected); 92 event.RunAndWaitForStatus(expected); 93 } 94 95 void CallInitialize(const PipelineStatusCB& status_cb, 96 bool low_delay, 97 PipelineStatus decoder_status) { 98 EXPECT_CALL(*decoder_, Initialize(_, _, _, _)).WillOnce( 99 DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(decoder_status))); 100 renderer_->Initialize( 101 &demuxer_stream_, 102 low_delay, 103 status_cb, 104 base::Bind(&VideoRendererImplTest::OnStatisticsUpdate, 105 base::Unretained(this)), 106 base::Bind(&StrictMock<MockCB>::BufferingStateChange, 107 base::Unretained(&mock_cb_)), 108 ended_event_.GetClosure(), 109 error_event_.GetPipelineStatusCB(), 110 base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this))); 111 } 112 113 void StartPlayingFrom(int milliseconds) { 114 SCOPED_TRACE(base::StringPrintf("StartPlayingFrom(%d)", milliseconds)); 115 renderer_->StartPlayingFrom( 116 base::TimeDelta::FromMilliseconds(milliseconds)); 117 message_loop_.RunUntilIdle(); 118 } 119 120 void Flush() { 121 SCOPED_TRACE("Flush()"); 122 WaitableMessageLoopEvent event; 123 renderer_->Flush(event.GetClosure()); 124 event.RunAndWait(); 125 } 126 127 void Destroy() { 128 SCOPED_TRACE("Destroy()"); 129 renderer_.reset(); 130 message_loop_.RunUntilIdle(); 131 } 132 133 // Parses a string representation of video frames and generates corresponding 134 // VideoFrame objects in |decode_results_|. 135 // 136 // Syntax: 137 // nn - Queue a decoder buffer with timestamp nn * 1000us 138 // abort - Queue an aborted read 139 // error - Queue a decoder error 140 // 141 // Examples: 142 // A clip that is four frames long: "0 10 20 30" 143 // A clip that has a decode error: "60 70 error" 144 void QueueFrames(const std::string& str) { 145 std::vector<std::string> tokens; 146 base::SplitString(str, ' ', &tokens); 147 for (size_t i = 0; i < tokens.size(); ++i) { 148 if (tokens[i] == "abort") { 149 scoped_refptr<VideoFrame> null_frame; 150 decode_results_.push_back( 151 std::make_pair(VideoDecoder::kAborted, null_frame)); 152 continue; 153 } 154 155 if (tokens[i] == "error") { 156 scoped_refptr<VideoFrame> null_frame; 157 decode_results_.push_back( 158 std::make_pair(VideoDecoder::kDecodeError, null_frame)); 159 continue; 160 } 161 162 int timestamp_in_ms = 0; 163 if (base::StringToInt(tokens[i], ×tamp_in_ms)) { 164 gfx::Size natural_size = TestVideoConfig::NormalCodedSize(); 165 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame( 166 VideoFrame::YV12, 167 natural_size, 168 gfx::Rect(natural_size), 169 natural_size, 170 base::TimeDelta::FromMilliseconds(timestamp_in_ms)); 171 decode_results_.push_back(std::make_pair(VideoDecoder::kOk, frame)); 172 continue; 173 } 174 175 CHECK(false) << "Unrecognized decoder buffer token: " << tokens[i]; 176 } 177 } 178 179 bool IsReadPending() { 180 return !decode_cb_.is_null(); 181 } 182 183 void WaitForError(PipelineStatus expected) { 184 SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected)); 185 error_event_.RunAndWaitForStatus(expected); 186 } 187 188 void WaitForEnded() { 189 SCOPED_TRACE("WaitForEnded()"); 190 ended_event_.RunAndWait(); 191 } 192 193 void WaitForPendingRead() { 194 SCOPED_TRACE("WaitForPendingRead()"); 195 if (!decode_cb_.is_null()) 196 return; 197 198 DCHECK(wait_for_pending_decode_cb_.is_null()); 199 200 WaitableMessageLoopEvent event; 201 wait_for_pending_decode_cb_ = event.GetClosure(); 202 event.RunAndWait(); 203 204 DCHECK(!decode_cb_.is_null()); 205 DCHECK(wait_for_pending_decode_cb_.is_null()); 206 } 207 208 void SatisfyPendingRead() { 209 CHECK(!decode_cb_.is_null()); 210 CHECK(!decode_results_.empty()); 211 212 // Post tasks for OutputCB and DecodeCB. 213 scoped_refptr<VideoFrame> frame = decode_results_.front().second; 214 if (frame.get()) 215 message_loop_.PostTask(FROM_HERE, base::Bind(output_cb_, frame)); 216 message_loop_.PostTask( 217 FROM_HERE, base::Bind(base::ResetAndReturn(&decode_cb_), 218 decode_results_.front().first)); 219 decode_results_.pop_front(); 220 } 221 222 void SatisfyPendingReadWithEndOfStream() { 223 DCHECK(!decode_cb_.is_null()); 224 225 // Return EOS buffer to trigger EOS frame. 226 EXPECT_CALL(demuxer_stream_, Read(_)) 227 .WillOnce(RunCallback<0>(DemuxerStream::kOk, 228 DecoderBuffer::CreateEOSBuffer())); 229 230 // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read(). 231 message_loop_.PostTask( 232 FROM_HERE, 233 base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk)); 234 235 WaitForPendingRead(); 236 237 message_loop_.PostTask( 238 FROM_HERE, 239 base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk)); 240 } 241 242 void AdvanceTimeInMs(int time_ms) { 243 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); 244 base::AutoLock l(lock_); 245 time_ += base::TimeDelta::FromMilliseconds(time_ms); 246 } 247 248 protected: 249 // Fixture members. 250 scoped_ptr<VideoRendererImpl> renderer_; 251 MockVideoDecoder* decoder_; // Owned by |renderer_|. 252 NiceMock<MockDemuxerStream> demuxer_stream_; 253 254 // Use StrictMock<T> to catch missing/extra callbacks. 255 class MockCB { 256 public: 257 MOCK_METHOD1(Display, void(const scoped_refptr<VideoFrame>&)); 258 MOCK_METHOD1(BufferingStateChange, void(BufferingState)); 259 }; 260 StrictMock<MockCB> mock_cb_; 261 262 private: 263 base::TimeDelta GetTime() { 264 base::AutoLock l(lock_); 265 return time_; 266 } 267 268 void DecodeRequested(const scoped_refptr<DecoderBuffer>& buffer, 269 const VideoDecoder::DecodeCB& decode_cb) { 270 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); 271 CHECK(decode_cb_.is_null()); 272 decode_cb_ = decode_cb; 273 274 // Wake up WaitForPendingRead() if needed. 275 if (!wait_for_pending_decode_cb_.is_null()) 276 base::ResetAndReturn(&wait_for_pending_decode_cb_).Run(); 277 278 if (decode_results_.empty()) 279 return; 280 281 SatisfyPendingRead(); 282 } 283 284 void FlushRequested(const base::Closure& callback) { 285 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); 286 decode_results_.clear(); 287 if (!decode_cb_.is_null()) { 288 QueueFrames("abort"); 289 SatisfyPendingRead(); 290 } 291 292 message_loop_.PostTask(FROM_HERE, callback); 293 } 294 295 void OnStatisticsUpdate(const PipelineStatistics& stats) {} 296 297 base::MessageLoop message_loop_; 298 299 // Used to protect |time_|. 300 base::Lock lock_; 301 base::TimeDelta time_; 302 303 // Used for satisfying reads. 304 VideoDecoder::OutputCB output_cb_; 305 VideoDecoder::DecodeCB decode_cb_; 306 base::TimeDelta next_frame_timestamp_; 307 308 WaitableMessageLoopEvent error_event_; 309 WaitableMessageLoopEvent ended_event_; 310 311 // Run during DecodeRequested() to unblock WaitForPendingRead(). 312 base::Closure wait_for_pending_decode_cb_; 313 314 std::deque<std::pair< 315 VideoDecoder::Status, scoped_refptr<VideoFrame> > > decode_results_; 316 317 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest); 318}; 319 320TEST_F(VideoRendererImplTest, DoNothing) { 321 // Test that creation and deletion doesn't depend on calls to Initialize() 322 // and/or Destroy(). 323} 324 325TEST_F(VideoRendererImplTest, DestroyWithoutInitialize) { 326 Destroy(); 327} 328 329TEST_F(VideoRendererImplTest, Initialize) { 330 Initialize(); 331 Destroy(); 332} 333 334TEST_F(VideoRendererImplTest, InitializeAndStartPlayingFrom) { 335 Initialize(); 336 QueueFrames("0 10 20 30"); 337 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); 338 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); 339 StartPlayingFrom(0); 340 Destroy(); 341} 342 343TEST_F(VideoRendererImplTest, DestroyWhileInitializing) { 344 CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT), false, PIPELINE_OK); 345 Destroy(); 346} 347 348TEST_F(VideoRendererImplTest, DestroyWhileFlushing) { 349 Initialize(); 350 QueueFrames("0 10 20 30"); 351 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); 352 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); 353 StartPlayingFrom(0); 354 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING)); 355 renderer_->Flush(NewExpectedClosure()); 356 Destroy(); 357} 358 359TEST_F(VideoRendererImplTest, Play) { 360 Initialize(); 361 QueueFrames("0 10 20 30"); 362 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); 363 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); 364 StartPlayingFrom(0); 365 Destroy(); 366} 367 368TEST_F(VideoRendererImplTest, FlushWithNothingBuffered) { 369 Initialize(); 370 StartPlayingFrom(0); 371 372 // We shouldn't expect a buffering state change since we never reached 373 // BUFFERING_HAVE_ENOUGH. 374 Flush(); 375 Destroy(); 376} 377 378TEST_F(VideoRendererImplTest, DecodeError_Playing) { 379 Initialize(); 380 QueueFrames("0 10 20 30"); 381 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); 382 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); 383 StartPlayingFrom(0); 384 385 QueueFrames("error"); 386 SatisfyPendingRead(); 387 WaitForError(PIPELINE_ERROR_DECODE); 388 Destroy(); 389} 390 391TEST_F(VideoRendererImplTest, DecodeError_DuringStartPlayingFrom) { 392 Initialize(); 393 QueueFrames("error"); 394 StartPlayingFrom(0); 395 Destroy(); 396} 397 398TEST_F(VideoRendererImplTest, StartPlayingFrom_Exact) { 399 Initialize(); 400 QueueFrames("50 60 70 80 90"); 401 402 EXPECT_CALL(mock_cb_, Display(HasTimestamp(60))); 403 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); 404 StartPlayingFrom(60); 405 Destroy(); 406} 407 408TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) { 409 Initialize(); 410 QueueFrames("50 60 70 80 90"); 411 412 EXPECT_CALL(mock_cb_, Display(HasTimestamp(50))); 413 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); 414 StartPlayingFrom(59); 415 Destroy(); 416} 417 418TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) { 419 Initialize(); 420 QueueFrames("50 60 70 80 90"); 421 422 EXPECT_CALL(mock_cb_, Display(HasTimestamp(60))); 423 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); 424 StartPlayingFrom(61); 425 Destroy(); 426} 427 428TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) { 429 // In low-delay mode only one frame is required to finish preroll. 430 InitializeWithLowDelay(true); 431 QueueFrames("0"); 432 433 // Expect some amount of have enough/nothing due to only requiring one frame. 434 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); 435 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)) 436 .Times(AnyNumber()); 437 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING)) 438 .Times(AnyNumber()); 439 StartPlayingFrom(0); 440 441 QueueFrames("10"); 442 SatisfyPendingRead(); 443 444 WaitableMessageLoopEvent event; 445 EXPECT_CALL(mock_cb_, Display(HasTimestamp(10))) 446 .WillOnce(RunClosure(event.GetClosure())); 447 AdvanceTimeInMs(10); 448 event.RunAndWait(); 449 450 Destroy(); 451} 452 453// Verify that a late decoder response doesn't break invariants in the renderer. 454TEST_F(VideoRendererImplTest, DestroyDuringOutstandingRead) { 455 Initialize(); 456 QueueFrames("0 10 20 30"); 457 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); 458 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); 459 StartPlayingFrom(0); 460 461 // Check that there is an outstanding Read() request. 462 EXPECT_TRUE(IsReadPending()); 463 464 Destroy(); 465} 466 467TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) { 468 InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED, false); 469 Destroy(); 470} 471 472TEST_F(VideoRendererImplTest, Underflow) { 473 Initialize(); 474 QueueFrames("0 10 20 30"); 475 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); 476 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); 477 StartPlayingFrom(0); 478 479 // Advance time slightly. Frames should be dropped and we should NOT signal 480 // having nothing. 481 AdvanceTimeInMs(100); 482 483 // Advance time more. Now we should signal having nothing. 484 { 485 SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING"); 486 WaitableMessageLoopEvent event; 487 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING)) 488 .WillOnce(RunClosure(event.GetClosure())); 489 AdvanceTimeInMs(3000); // Must match kTimeToDeclareHaveNothing. 490 event.RunAndWait(); 491 } 492 493 // Receiving end of stream should signal having enough. 494 { 495 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH"); 496 WaitableMessageLoopEvent event; 497 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)) 498 .WillOnce(RunClosure(event.GetClosure())); 499 SatisfyPendingReadWithEndOfStream(); 500 event.RunAndWait(); 501 } 502 503 WaitForEnded(); 504 Destroy(); 505} 506 507} // namespace media 508