media_source_player_unittest.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
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 <string> 6 7#include "base/basictypes.h" 8#include "base/memory/scoped_ptr.h" 9#include "media/base/android/media_codec_bridge.h" 10#include "media/base/android/media_player_manager.h" 11#include "media/base/android/media_source_player.h" 12#include "media/base/decoder_buffer.h" 13#include "media/base/test_data_util.h" 14#include "testing/gmock/include/gmock/gmock.h" 15#include "ui/gl/android/surface_texture_bridge.h" 16 17namespace media { 18 19static const int kDefaultDurationInMs = 10000; 20 21// Mock of MediaPlayerManager for testing purpose 22class MockMediaPlayerManager : public MediaPlayerManager { 23 public: 24 MockMediaPlayerManager() : num_requests_(0), last_seek_request_id_(0) {} 25 virtual ~MockMediaPlayerManager() {}; 26 27 // MediaPlayerManager implementation. 28 virtual void RequestMediaResources(int player_id) OVERRIDE {} 29 virtual void ReleaseMediaResources(int player_id) OVERRIDE {} 30 virtual MediaResourceGetter* GetMediaResourceGetter() OVERRIDE { 31 return NULL; 32 } 33 virtual void OnTimeUpdate(int player_id, 34 base::TimeDelta current_time) OVERRIDE {} 35 virtual void OnMediaMetadataChanged( 36 int player_id, base::TimeDelta duration, int width, int height, 37 bool success) OVERRIDE {} 38 virtual void OnPlaybackComplete(int player_id) OVERRIDE {} 39 virtual void OnMediaInterrupted(int player_id) OVERRIDE {} 40 virtual void OnBufferingUpdate(int player_id, int percentage) OVERRIDE {} 41 virtual void OnSeekComplete(int player_id, 42 base::TimeDelta current_time) OVERRIDE {} 43 virtual void OnError(int player_id, int error) OVERRIDE {} 44 virtual void OnVideoSizeChanged(int player_id, int width, 45 int height) OVERRIDE {} 46 virtual MediaPlayerAndroid* GetFullscreenPlayer() OVERRIDE { return NULL; } 47 virtual MediaPlayerAndroid* GetPlayer(int player_id) OVERRIDE { return NULL; } 48 virtual void DestroyAllMediaPlayers() OVERRIDE {} 49 virtual void OnReadFromDemuxer(int player_id, 50 media::DemuxerStream::Type type) OVERRIDE { 51 num_requests_++; 52 if (message_loop_.is_running()) 53 message_loop_.Quit(); 54 } 55 virtual void OnMediaSeekRequest(int player_id, base::TimeDelta time_to_seek, 56 unsigned seek_request_id) OVERRIDE { 57 last_seek_request_id_ = seek_request_id; 58 } 59 virtual void OnMediaConfigRequest(int player_id) OVERRIDE {} 60 virtual media::MediaDrmBridge* GetDrmBridge(int media_keys_id) OVERRIDE { 61 return NULL; 62 } 63 virtual void OnProtectedSurfaceRequested(int player_id) OVERRIDE {} 64 virtual void OnKeyAdded(int key_id, 65 const std::string& session_id) OVERRIDE {} 66 virtual void OnKeyError(int key_id, 67 const std::string& session_id, 68 media::MediaKeys::KeyError error_code, 69 int system_code) OVERRIDE {} 70 virtual void OnKeyMessage(int key_id, 71 const std::string& session_id, 72 const std::vector<uint8>& message, 73 const std::string& destination_url) OVERRIDE {} 74 75 int num_requests() const { return num_requests_; } 76 unsigned last_seek_request_id() const { return last_seek_request_id_; } 77 base::MessageLoop* message_loop() { return &message_loop_; } 78 79 private: 80 // The number of request this object sents for decoding data. 81 int num_requests_; 82 unsigned last_seek_request_id_; 83 base::MessageLoop message_loop_; 84}; 85 86class MediaSourcePlayerTest : public testing::Test { 87 public: 88 MediaSourcePlayerTest() { 89 manager_.reset(new MockMediaPlayerManager()); 90 player_.reset(new MediaSourcePlayer(0, manager_.get())); 91 } 92 virtual ~MediaSourcePlayerTest() {} 93 94 protected: 95 // Get the decoder job from the MediaSourcePlayer. 96 MediaDecoderJob* GetMediaDecoderJob(bool is_audio) { 97 if (is_audio) { 98 return reinterpret_cast<MediaDecoderJob*>( 99 player_->audio_decoder_job_.get()); 100 } 101 return reinterpret_cast<MediaDecoderJob*>( 102 player_->video_decoder_job_.get()); 103 } 104 105 // Starts an audio decoder job. 106 void StartAudioDecoderJob() { 107 MediaPlayerHostMsg_DemuxerReady_Params params; 108 params.audio_codec = kCodecVorbis; 109 params.audio_channels = 2; 110 params.audio_sampling_rate = 44100; 111 params.is_audio_encrypted = false; 112 params.duration_ms = kDefaultDurationInMs; 113 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("vorbis-extradata"); 114 params.audio_extra_data = std::vector<uint8>( 115 buffer->data(), 116 buffer->data() + buffer->data_size()); 117 Start(params); 118 } 119 120 void StartVideoDecoderJob() { 121 MediaPlayerHostMsg_DemuxerReady_Params params; 122 params.video_codec = kCodecVP8; 123 params.video_size = gfx::Size(320, 240); 124 params.is_video_encrypted = false; 125 params.duration_ms = kDefaultDurationInMs; 126 Start(params); 127 } 128 129 // Starts decoding the data. 130 void Start(const MediaPlayerHostMsg_DemuxerReady_Params& params) { 131 player_->DemuxerReady(params); 132 player_->Start(); 133 } 134 135 MediaPlayerHostMsg_ReadFromDemuxerAck_Params 136 CreateReadFromDemuxerAckForAudio() { 137 MediaPlayerHostMsg_ReadFromDemuxerAck_Params ack_params; 138 ack_params.type = DemuxerStream::AUDIO; 139 ack_params.access_units.resize(1); 140 ack_params.access_units[0].status = DemuxerStream::kOk; 141 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("vorbis-packet-0"); 142 ack_params.access_units[0].data = std::vector<uint8>( 143 buffer->data(), buffer->data() + buffer->data_size()); 144 // Vorbis needs 4 extra bytes padding on Android to decode properly. Check 145 // NuMediaExtractor.cpp in Android source code. 146 uint8 padding[4] = { 0xff , 0xff , 0xff , 0xff }; 147 ack_params.access_units[0].data.insert( 148 ack_params.access_units[0].data.end(), padding, padding + 4); 149 return ack_params; 150 } 151 152 MediaPlayerHostMsg_ReadFromDemuxerAck_Params 153 CreateReadFromDemuxerAckForVideo() { 154 MediaPlayerHostMsg_ReadFromDemuxerAck_Params ack_params; 155 ack_params.type = DemuxerStream::VIDEO; 156 ack_params.access_units.resize(1); 157 ack_params.access_units[0].status = DemuxerStream::kOk; 158 scoped_refptr<DecoderBuffer> buffer = 159 ReadTestDataFile("vp8-I-frame-320x240"); 160 ack_params.access_units[0].data = std::vector<uint8>( 161 buffer->data(), buffer->data() + buffer->data_size()); 162 return ack_params; 163 } 164 165 base::TimeTicks StartTimeTicks() { 166 return player_->start_time_ticks_; 167 } 168 169 protected: 170 scoped_ptr<MockMediaPlayerManager> manager_; 171 scoped_ptr<MediaSourcePlayer> player_; 172 173 DISALLOW_COPY_AND_ASSIGN(MediaSourcePlayerTest); 174}; 175 176TEST_F(MediaSourcePlayerTest, StartAudioDecoderWithValidConfig) { 177 if (!MediaCodecBridge::IsAvailable()) 178 return; 179 180 // Test audio decoder job will be created when codec is successfully started. 181 StartAudioDecoderJob(); 182 EXPECT_TRUE(NULL != GetMediaDecoderJob(true)); 183 EXPECT_EQ(1, manager_->num_requests()); 184} 185 186TEST_F(MediaSourcePlayerTest, StartAudioDecoderWithInvalidConfig) { 187 if (!MediaCodecBridge::IsAvailable()) 188 return; 189 190 // Test audio decoder job will not be created when failed to start the codec. 191 MediaPlayerHostMsg_DemuxerReady_Params params; 192 params.audio_codec = kCodecVorbis; 193 params.audio_channels = 2; 194 params.audio_sampling_rate = 44100; 195 params.is_audio_encrypted = false; 196 params.duration_ms = kDefaultDurationInMs; 197 uint8 invalid_codec_data[] = { 0x00, 0xff, 0xff, 0xff, 0xff }; 198 params.audio_extra_data.insert(params.audio_extra_data.begin(), 199 invalid_codec_data, invalid_codec_data + 4); 200 Start(params); 201 EXPECT_EQ(NULL, GetMediaDecoderJob(true)); 202 EXPECT_EQ(0, manager_->num_requests()); 203} 204 205TEST_F(MediaSourcePlayerTest, StartVideoCodecWithValidSurface) { 206 if (!MediaCodecBridge::IsAvailable()) 207 return; 208 209 // Test video decoder job will be created when surface is valid. 210 scoped_refptr<gfx::SurfaceTextureBridge> surface_texture( 211 new gfx::SurfaceTextureBridge(0)); 212 gfx::ScopedJavaSurface surface(surface_texture.get()); 213 StartVideoDecoderJob(); 214 // Video decoder job will not be created until surface is available. 215 EXPECT_EQ(NULL, GetMediaDecoderJob(false)); 216 EXPECT_EQ(0, manager_->num_requests()); 217 218 player_->SetVideoSurface(surface.Pass()); 219 EXPECT_EQ(1u, manager_->last_seek_request_id()); 220 player_->OnSeekRequestAck(manager_->last_seek_request_id()); 221 // The decoder job should be ready now. 222 EXPECT_TRUE(NULL != GetMediaDecoderJob(false)); 223 EXPECT_EQ(1, manager_->num_requests()); 224} 225 226TEST_F(MediaSourcePlayerTest, StartVideoCodecWithInvalidSurface) { 227 if (!MediaCodecBridge::IsAvailable()) 228 return; 229 230 // Test video decoder job will be created when surface is valid. 231 scoped_refptr<gfx::SurfaceTextureBridge> surface_texture( 232 new gfx::SurfaceTextureBridge(0)); 233 gfx::ScopedJavaSurface surface(surface_texture.get()); 234 StartVideoDecoderJob(); 235 // Video decoder job will not be created until surface is available. 236 EXPECT_EQ(NULL, GetMediaDecoderJob(false)); 237 EXPECT_EQ(0, manager_->num_requests()); 238 239 // Release the surface texture. 240 surface_texture = NULL; 241 player_->SetVideoSurface(surface.Pass()); 242 EXPECT_EQ(1u, manager_->last_seek_request_id()); 243 player_->OnSeekRequestAck(manager_->last_seek_request_id()); 244 EXPECT_EQ(NULL, GetMediaDecoderJob(false)); 245 EXPECT_EQ(0, manager_->num_requests()); 246} 247 248TEST_F(MediaSourcePlayerTest, ReadFromDemuxerAfterSeek) { 249 if (!MediaCodecBridge::IsAvailable()) 250 return; 251 252 // Test decoder job will resend a ReadFromDemuxer request after seek. 253 StartAudioDecoderJob(); 254 EXPECT_TRUE(NULL != GetMediaDecoderJob(true)); 255 EXPECT_EQ(1, manager_->num_requests()); 256 257 // Initiate a seek 258 player_->SeekTo(base::TimeDelta()); 259 EXPECT_EQ(1u, manager_->last_seek_request_id()); 260 // Sending back the seek ACK, this should trigger the player to call 261 // OnReadFromDemuxer() again. 262 player_->OnSeekRequestAck(manager_->last_seek_request_id()); 263 EXPECT_EQ(2, manager_->num_requests()); 264} 265 266TEST_F(MediaSourcePlayerTest, SetSurfaceWhileSeeking) { 267 if (!MediaCodecBridge::IsAvailable()) 268 return; 269 270 // Test SetVideoSurface() will not cause an extra seek while the player is 271 // waiting for a seek ACK. 272 scoped_refptr<gfx::SurfaceTextureBridge> surface_texture( 273 new gfx::SurfaceTextureBridge(0)); 274 gfx::ScopedJavaSurface surface(surface_texture.get()); 275 StartVideoDecoderJob(); 276 // Player is still waiting for SetVideoSurface(), so no request is sent. 277 EXPECT_EQ(0, manager_->num_requests()); 278 player_->SeekTo(base::TimeDelta()); 279 EXPECT_EQ(1u, manager_->last_seek_request_id()); 280 281 player_->SetVideoSurface(surface.Pass()); 282 EXPECT_TRUE(NULL == GetMediaDecoderJob(false)); 283 EXPECT_EQ(1u, manager_->last_seek_request_id()); 284 285 // Send the seek ack, player should start requesting data afterwards. 286 player_->OnSeekRequestAck(manager_->last_seek_request_id()); 287 EXPECT_TRUE(NULL != GetMediaDecoderJob(false)); 288 EXPECT_EQ(1, manager_->num_requests()); 289} 290 291TEST_F(MediaSourcePlayerTest, StartAfterSeekFinish) { 292 if (!MediaCodecBridge::IsAvailable()) 293 return; 294 295 // Test decoder job will not start until all pending seek event is handled. 296 MediaPlayerHostMsg_DemuxerReady_Params params; 297 params.audio_codec = kCodecVorbis; 298 params.audio_channels = 2; 299 params.audio_sampling_rate = 44100; 300 params.is_audio_encrypted = false; 301 params.duration_ms = kDefaultDurationInMs; 302 player_->DemuxerReady(params); 303 EXPECT_EQ(NULL, GetMediaDecoderJob(true)); 304 EXPECT_EQ(0, manager_->num_requests()); 305 306 // Initiate a seek 307 player_->SeekTo(base::TimeDelta()); 308 EXPECT_EQ(1u, manager_->last_seek_request_id()); 309 310 player_->Start(); 311 EXPECT_EQ(NULL, GetMediaDecoderJob(true)); 312 EXPECT_EQ(0, manager_->num_requests()); 313 314 // Sending back the seek ACK. 315 player_->OnSeekRequestAck(manager_->last_seek_request_id()); 316 EXPECT_TRUE(NULL != GetMediaDecoderJob(true)); 317 EXPECT_EQ(1, manager_->num_requests()); 318} 319 320TEST_F(MediaSourcePlayerTest, StartImmediatelyAfterPause) { 321 if (!MediaCodecBridge::IsAvailable()) 322 return; 323 324 // Test that if the decoding job is not fully stopped after Pause(), 325 // calling Start() will be a noop. 326 StartAudioDecoderJob(); 327 328 MediaDecoderJob* decoder_job = GetMediaDecoderJob(true); 329 EXPECT_TRUE(NULL != decoder_job); 330 EXPECT_EQ(1, manager_->num_requests()); 331 EXPECT_FALSE(GetMediaDecoderJob(true)->is_decoding()); 332 333 // Sending data to player. 334 player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio()); 335 EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding()); 336 337 // Decoder job will not immediately stop after Pause() since it is 338 // running on another thread. 339 player_->Pause(); 340 EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding()); 341 342 // Nothing happens when calling Start() again. 343 player_->Start(); 344 // Verify that Start() will not destroy and recreate the decoder job. 345 EXPECT_EQ(decoder_job, GetMediaDecoderJob(true)); 346 EXPECT_EQ(1, manager_->num_requests()); 347 EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding()); 348 manager_->message_loop()->Run(); 349 // The decoder job should finish and a new request will be sent. 350 EXPECT_EQ(2, manager_->num_requests()); 351 EXPECT_FALSE(GetMediaDecoderJob(true)->is_decoding()); 352} 353 354TEST_F(MediaSourcePlayerTest, DecoderJobsCannotStartWithoutAudio) { 355 if (!MediaCodecBridge::IsAvailable()) 356 return; 357 358 // Test that when Start() is called, video decoder jobs will wait for audio 359 // decoder job before start decoding the data. 360 MediaPlayerHostMsg_DemuxerReady_Params params; 361 params.audio_codec = kCodecVorbis; 362 params.audio_channels = 2; 363 params.audio_sampling_rate = 44100; 364 params.is_audio_encrypted = false; 365 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("vorbis-extradata"); 366 params.audio_extra_data = std::vector<uint8>( 367 buffer->data(), 368 buffer->data() + buffer->data_size()); 369 params.video_codec = kCodecVP8; 370 params.video_size = gfx::Size(320, 240); 371 params.is_video_encrypted = false; 372 params.duration_ms = kDefaultDurationInMs; 373 Start(params); 374 EXPECT_EQ(0, manager_->num_requests()); 375 376 scoped_refptr<gfx::SurfaceTextureBridge> surface_texture( 377 new gfx::SurfaceTextureBridge(0)); 378 gfx::ScopedJavaSurface surface(surface_texture.get()); 379 player_->SetVideoSurface(surface.Pass()); 380 EXPECT_EQ(1u, manager_->last_seek_request_id()); 381 player_->OnSeekRequestAck(manager_->last_seek_request_id()); 382 383 MediaDecoderJob* audio_decoder_job = GetMediaDecoderJob(true); 384 MediaDecoderJob* video_decoder_job = GetMediaDecoderJob(false); 385 EXPECT_EQ(2, manager_->num_requests()); 386 EXPECT_FALSE(audio_decoder_job->is_decoding()); 387 EXPECT_FALSE(video_decoder_job->is_decoding()); 388 389 // Sending audio data to player, audio decoder should not start. 390 player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForVideo()); 391 EXPECT_FALSE(video_decoder_job->is_decoding()); 392 393 // Sending video data to player, both decoders should start now. 394 player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio()); 395 EXPECT_TRUE(audio_decoder_job->is_decoding()); 396 EXPECT_TRUE(video_decoder_job->is_decoding()); 397} 398 399// Disabled due to http://crbug.com/266041. 400// TODO(xhwang/qinmin): Fix this test and reenable it. 401TEST_F(MediaSourcePlayerTest, 402 DISABLED_StartTimeTicksResetAfterDecoderUnderruns) { 403 if (!MediaCodecBridge::IsAvailable()) 404 return; 405 406 // Test start time ticks will reset after decoder job underruns. 407 StartAudioDecoderJob(); 408 EXPECT_TRUE(NULL != GetMediaDecoderJob(true)); 409 EXPECT_EQ(1, manager_->num_requests()); 410 player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio()); 411 EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding()); 412 413 manager_->message_loop()->Run(); 414 // The decoder job should finish and a new request will be sent. 415 EXPECT_EQ(2, manager_->num_requests()); 416 EXPECT_FALSE(GetMediaDecoderJob(true)->is_decoding()); 417 base::TimeTicks previous = StartTimeTicks(); 418 419 // Let the decoder timeout and execute the OnDecoderStarved() callback. 420 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); 421 manager_->message_loop()->RunUntilIdle(); 422 423 // Send new data to the decoder. This should reset the start time ticks. 424 player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio()); 425 base::TimeTicks current = StartTimeTicks(); 426 EXPECT_LE(100.0, (current - previous).InMillisecondsF()); 427} 428 429} // namespace media 430