media_source_player.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
1// Copyright (c) 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 "media/base/android/media_source_player.h" 6 7#include "base/android/jni_android.h" 8#include "base/android/jni_string.h" 9#include "base/basictypes.h" 10#include "base/bind.h" 11#include "base/logging.h" 12#include "base/message_loop.h" 13#include "base/threading/thread.h" 14#include "media/base/android/media_codec_bridge.h" 15#include "media/base/android/media_player_manager.h" 16 17namespace { 18// Timeout value for media codec operations. 19const int kMediaCodecTimeoutInMicroseconds = 5000; 20} 21 22namespace media { 23 24MediaDecoderJob::MediaDecoderJob( 25 bool is_audio, const scoped_refptr<base::MessageLoopProxy>& message_loop) 26 : message_loop_(message_loop), 27 needs_flush_(false), 28 is_audio_(is_audio), 29 weak_this_(this) { 30} 31 32MediaDecoderJob::~MediaDecoderJob() {} 33 34// Class for managing audio decoding jobs. 35class AudioDecoderJob : public MediaDecoderJob { 36 public: 37 AudioDecoderJob( 38 const scoped_refptr<base::MessageLoopProxy>& message_loop, 39 const AudioCodec audio_codec, int sample_rate, int channel_count, 40 const uint8* extra_data, size_t extra_data_size); 41 virtual ~AudioDecoderJob() {} 42}; 43 44// Class for managing video decoding jobs. 45class VideoDecoderJob : public MediaDecoderJob { 46 public: 47 VideoDecoderJob( 48 const scoped_refptr<base::MessageLoopProxy>& message_loop, 49 const VideoCodec video_codec, const gfx::Size& size, jobject surface); 50 virtual ~VideoDecoderJob() {} 51 52 void Configure( 53 const VideoCodec codec, const gfx::Size& size, jobject surface); 54}; 55 56void MediaDecoderJob::Decode( 57 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit& unit, 58 const base::Time& start_wallclock_time, 59 const base::TimeDelta& start_presentation_timestamp, 60 const MediaDecoderJob::DecoderCallback& callback) { 61 if (!thread_->IsRunning()) 62 thread_->Start(); 63 thread_->message_loop()->PostTask(FROM_HERE, base::Bind( 64 &MediaDecoderJob::DecodeInternal, base::Unretained(this), unit, 65 start_wallclock_time, start_presentation_timestamp, needs_flush_, 66 callback)); 67 needs_flush_ = false; 68} 69 70void MediaDecoderJob::DecodeInternal( 71 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params::AccessUnit& unit, 72 const base::Time& start_wallclock_time, 73 const base::TimeDelta& start_presentation_timestamp, 74 bool needs_flush, 75 const MediaDecoderJob::DecoderCallback& callback) { 76 if (needs_flush) 77 media_codec_bridge_->Reset(); 78 base::TimeDelta timeout = base::TimeDelta::FromMicroseconds( 79 kMediaCodecTimeoutInMicroseconds); 80 int input_buf_index = media_codec_bridge_->DequeueInputBuffer(timeout); 81 // TODO(qinmin): skip frames if video is falling far behind. 82 if (input_buf_index >= 0) { 83 if (unit.end_of_stream) { 84 media_codec_bridge_->QueueEOS(input_buf_index); 85 } else { 86 media_codec_bridge_->QueueInputBuffer( 87 input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp); 88 } 89 } 90 size_t offset = 0; 91 size_t size = 0; 92 base::TimeDelta presentation_timestamp; 93 bool end_of_stream = false; 94 95 int outputBufferIndex = media_codec_bridge_->DequeueOutputBuffer( 96 timeout, &offset, &size, &presentation_timestamp, &end_of_stream); 97 switch (outputBufferIndex) { 98 case MediaCodecBridge::INFO_OUTPUT_BUFFERS_CHANGED: 99 media_codec_bridge_->GetOutputBuffers(); 100 break; 101 case MediaCodecBridge::INFO_OUTPUT_FORMAT_CHANGED: 102 // TODO(qinmin): figure out what we should do if format changes. 103 break; 104 case MediaCodecBridge::INFO_TRY_AGAIN_LATER: 105 break; 106 default: 107 DCHECK_LE(0, outputBufferIndex); 108 if (size == 0 && end_of_stream) 109 break; 110 base::TimeDelta time_to_render; 111 if (!start_wallclock_time.is_null()) { 112 time_to_render = presentation_timestamp - (base::Time::Now() - 113 start_wallclock_time + start_presentation_timestamp); 114 } 115 if (time_to_render >= base::TimeDelta()) { 116 MessageLoop::current()->PostDelayedTask( 117 FROM_HERE, 118 base::Bind(&MediaDecoderJob::ReleaseOutputBuffer, 119 weak_this_.GetWeakPtr(), outputBufferIndex, size, 120 presentation_timestamp, end_of_stream, callback), 121 time_to_render); 122 } else { 123 // TODO(qinmin): The codec is lagging behind, need to recalculate the 124 // |start_presentation_timestamp_| and |start_wallclock_time_|. 125 DVLOG(1) << (is_audio_ ? "audio " : "video ") 126 << "codec is lagging behind :" << time_to_render.InMicroseconds(); 127 ReleaseOutputBuffer(outputBufferIndex, size, presentation_timestamp, 128 end_of_stream, callback); 129 } 130 return; 131 } 132 message_loop_->PostTask(FROM_HERE, base::Bind( 133 callback, start_presentation_timestamp, start_wallclock_time, 134 end_of_stream)); 135} 136 137void MediaDecoderJob::ReleaseOutputBuffer( 138 int outputBufferIndex, size_t size, 139 const base::TimeDelta& presentation_timestamp, 140 bool end_of_stream, const MediaDecoderJob::DecoderCallback& callback) { 141 // TODO(qinmin): Refactor this function. Maybe AudioDecoderJob should provide 142 // its own ReleaseOutputBuffer(). 143 if (is_audio_) { 144 static_cast<AudioCodecBridge*>(media_codec_bridge_.get())->PlayOutputBuffer( 145 outputBufferIndex, size); 146 } 147 media_codec_bridge_->ReleaseOutputBuffer(outputBufferIndex, !is_audio_); 148 message_loop_->PostTask(FROM_HERE, base::Bind( 149 callback, presentation_timestamp, base::Time::Now(), end_of_stream)); 150} 151 152void MediaDecoderJob::Flush() { 153 // Do nothing, flush when the next Decode() happens. 154 needs_flush_ = true; 155} 156 157void MediaDecoderJob::Release() { 158 if (thread_->IsRunning() && 159 thread_->message_loop() != base::MessageLoop::current()) { 160 thread_->message_loop()->DeleteSoon(FROM_HERE, this); 161 } else { 162 delete this; 163 } 164} 165 166VideoDecoderJob::VideoDecoderJob( 167 const scoped_refptr<base::MessageLoopProxy>& message_loop, 168 const VideoCodec video_codec, const gfx::Size& size, jobject surface) 169 : MediaDecoderJob(false, message_loop) { 170 scoped_ptr<VideoCodecBridge> codec(VideoCodecBridge::Create(video_codec)); 171 codec->Start(video_codec, size, surface); 172 media_codec_bridge_.reset(codec.release()); 173 thread_.reset(new base::Thread("MediaSource_VideoDecoderThread")); 174} 175 176AudioDecoderJob::AudioDecoderJob( 177 const scoped_refptr<base::MessageLoopProxy>& message_loop, 178 const AudioCodec audio_codec, 179 int sample_rate, 180 int channel_count, 181 const uint8* extra_data, 182 size_t extra_data_size) 183 : MediaDecoderJob(true, message_loop) { 184 scoped_ptr<AudioCodecBridge> codec(AudioCodecBridge::Create(audio_codec)); 185 codec->Start(audio_codec, sample_rate, channel_count, extra_data, 186 extra_data_size, true); 187 media_codec_bridge_.reset(codec.release()); 188 thread_.reset(new base::Thread("MediaSource_AudioDecoderThread")); 189} 190 191MediaSourcePlayer::MediaSourcePlayer( 192 int player_id, 193 MediaPlayerManager* manager) 194 : MediaPlayerAndroid(player_id, manager), 195 pending_event_(NO_EVENT_PENDING), 196 active_decoding_tasks_(0), 197 width_(0), 198 height_(0), 199 audio_codec_(kUnknownAudioCodec), 200 video_codec_(kUnknownVideoCodec), 201 num_channels_(0), 202 sampling_rate_(0), 203 seekable_(true), 204 audio_finished_(true), 205 video_finished_(true), 206 playing_(false), 207 audio_access_unit_index_(0), 208 video_access_unit_index_(0), 209 waiting_for_audio_data_(false), 210 waiting_for_video_data_(false), 211 use_empty_surface_(true), 212 weak_this_(this) { 213} 214 215MediaSourcePlayer::~MediaSourcePlayer() { 216 Release(); 217} 218 219void MediaSourcePlayer::SetVideoSurface(jobject surface) { 220 use_empty_surface_ = surface ? false : true; 221 222 // If we haven't processed a surface change event, do so now. 223 if (active_decoding_tasks_ > 0) { 224 pending_event_ |= SURFACE_CHANGE_EVENT_PENDING; 225 // Request a seek so that the next decoder will decode an I-frame first. 226 // Or otherwise, MediaCodec might crash. See b/8950387. 227 pending_event_ |= SEEK_EVENT_PENDING; 228 ProcessPendingEvents(); 229 return; 230 } 231 232 if (HasVideo()) { 233 video_decoder_job_.reset(new VideoDecoderJob( 234 base::MessageLoopProxy::current(), video_codec_, 235 gfx::Size(width_, height_), surface)); 236 } 237 238 // Inform the fullscreen view the player is ready. 239 // TODO(qinmin): refactor MediaPlayerBridge so that we have a better way 240 // to inform ContentVideoView. 241 OnMediaMetadataChanged(duration_, width_, height_, true); 242 243 if (pending_event_ & SURFACE_CHANGE_EVENT_PENDING) { 244 // We should already requested a seek in this case. 245 pending_event_ &= ~SURFACE_CHANGE_EVENT_PENDING; 246 } else { 247 // Perform a seek so the new decoder can get the I-frame first. 248 pending_event_ |= SEEK_EVENT_PENDING; 249 ProcessPendingEvents(); 250 return; 251 } 252 253 if (playing_) 254 StartInternal(); 255} 256 257void MediaSourcePlayer::Start() { 258 playing_ = true; 259 if (HasAudio() && !audio_decoder_job_) { 260 audio_decoder_job_.reset(new AudioDecoderJob( 261 base::MessageLoopProxy::current(), audio_codec_, sampling_rate_, 262 num_channels_, &audio_extra_data_[0], audio_extra_data_.size())); 263 } 264 265 if (HasVideo() && !video_decoder_job_) { 266 // StartInternal() will be delayed until SetVideoSurface() gets called. 267 return; 268 } 269 270 StartInternal(); 271} 272 273void MediaSourcePlayer::Pause() { 274 playing_ = false; 275 start_wallclock_time_ = base::Time(); 276} 277 278bool MediaSourcePlayer::IsPlaying() { 279 return playing_; 280} 281 282int MediaSourcePlayer::GetVideoWidth() { 283 return width_; 284} 285 286int MediaSourcePlayer::GetVideoHeight() { 287 return height_; 288} 289 290void MediaSourcePlayer::SeekTo(base::TimeDelta timestamp) { 291 last_presentation_timestamp_ = timestamp; 292 pending_event_ |= SEEK_EVENT_PENDING; 293 ProcessPendingEvents(); 294} 295 296base::TimeDelta MediaSourcePlayer::GetCurrentTime() { 297 return last_presentation_timestamp_; 298} 299 300base::TimeDelta MediaSourcePlayer::GetDuration() { 301 return duration_; 302} 303 304void MediaSourcePlayer::Release() { 305 ClearDecodingData(); 306 audio_decoder_job_.reset(); 307 video_decoder_job_.reset(); 308 active_decoding_tasks_ = 0; 309 playing_ = false; 310 pending_event_ = NO_EVENT_PENDING; 311 ReleaseMediaResourcesFromManager(); 312} 313 314void MediaSourcePlayer::SetVolume(float leftVolume, float rightVolume) { 315} 316 317bool MediaSourcePlayer::CanPause() { 318 return seekable_; 319} 320 321bool MediaSourcePlayer::CanSeekForward() { 322 return seekable_; 323} 324 325bool MediaSourcePlayer::CanSeekBackward() { 326 return seekable_; 327} 328 329bool MediaSourcePlayer::IsPlayerReady() { 330 return audio_decoder_job_ || video_decoder_job_; 331} 332 333void MediaSourcePlayer::StartInternal() { 334 // Do nothing if the decoders are already running. 335 if (active_decoding_tasks_ > 0 || pending_event_ != NO_EVENT_PENDING) 336 return; 337 338 if (HasAudio()) { 339 audio_finished_ = false; 340 DecodeMoreAudio(); 341 } 342 if (HasVideo()) { 343 video_finished_ = false; 344 DecodeMoreVideo(); 345 } 346} 347 348void MediaSourcePlayer::DemuxerReady( 349 const MediaPlayerHostMsg_DemuxerReady_Params& params) { 350 if (params.duration_ms == std::numeric_limits<int>::max()) 351 seekable_ = false; 352 duration_ = base::TimeDelta::FromMilliseconds(params.duration_ms); 353 width_ = params.video_size.width(); 354 height_ = params.video_size.height(); 355 num_channels_ = params.audio_channels; 356 sampling_rate_ = params.audio_sampling_rate; 357 audio_codec_ = params.audio_codec; 358 video_codec_ = params.video_codec; 359 audio_extra_data_ = params.audio_extra_data; 360 OnMediaMetadataChanged(duration_, width_, height_, true); 361} 362 363void MediaSourcePlayer::ReadFromDemuxerAck( 364 const MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) { 365 if (params.type == DemuxerStream::AUDIO) 366 waiting_for_audio_data_ = false; 367 else 368 waiting_for_video_data_ = false; 369 370 // If there is a pending seek request, ignore the data from the chunk demuxer. 371 // The data will be requested later when OnSeekRequestAck() is called. 372 if (pending_event_ & SEEK_EVENT_PENDING) 373 return; 374 375 if (params.type == DemuxerStream::AUDIO) { 376 DCHECK_EQ(0u, audio_access_unit_index_); 377 received_audio_ = params; 378 if (!pending_event_) 379 DecodeMoreAudio(); 380 } else { 381 DCHECK_EQ(0u, video_access_unit_index_); 382 received_video_ = params; 383 if (!pending_event_) 384 DecodeMoreVideo(); 385 } 386} 387 388void MediaSourcePlayer::OnSeekRequestAck() { 389 pending_event_ &= ~SEEK_EVENT_PENDING; 390 OnSeekComplete(); 391 if (playing_) 392 StartInternal(); 393} 394 395void MediaSourcePlayer::UpdateTimestamps( 396 const base::TimeDelta& presentation_timestamp, 397 const base::Time& wallclock_time) { 398 last_presentation_timestamp_ = presentation_timestamp; 399 OnTimeUpdated(); 400 if (start_wallclock_time_.is_null() && playing_) { 401 start_wallclock_time_ = wallclock_time; 402 start_presentation_timestamp_ = last_presentation_timestamp_; 403 } 404} 405 406void MediaSourcePlayer::ProcessPendingEvents() { 407 // Wait for all the decoding jobs to finish before sending a seek request. 408 if (active_decoding_tasks_ > 0) 409 return; 410 411 DCHECK(pending_event_ != NO_EVENT_PENDING); 412 if (use_empty_surface_ && (pending_event_ & SURFACE_CHANGE_EVENT_PENDING)) { 413 video_decoder_job_.reset(); 414 pending_event_ &= ~SURFACE_CHANGE_EVENT_PENDING; 415 } 416 417 ClearDecodingData(); 418 manager()->OnMediaSeekRequest(player_id(), 419 last_presentation_timestamp_, 420 pending_event_ & SURFACE_CHANGE_EVENT_PENDING); 421} 422 423void MediaSourcePlayer::MediaDecoderCallback( 424 bool is_audio, const base::TimeDelta& presentation_timestamp, 425 const base::Time& wallclock_time, bool end_of_stream) { 426 if (active_decoding_tasks_ > 0) 427 active_decoding_tasks_--; 428 429 if (pending_event_ != NO_EVENT_PENDING) { 430 ProcessPendingEvents(); 431 return; 432 } 433 434 if (is_audio || !HasAudio()) 435 UpdateTimestamps(presentation_timestamp, wallclock_time); 436 437 if (end_of_stream) { 438 PlaybackCompleted(is_audio); 439 return; 440 } 441 442 if (!playing_) 443 return; 444 445 if (is_audio) 446 DecodeMoreAudio(); 447 else 448 DecodeMoreVideo(); 449} 450 451void MediaSourcePlayer::DecodeMoreAudio() { 452 if (audio_access_unit_index_ >= received_audio_.access_units.size()) { 453 if (!waiting_for_audio_data_) { 454 manager()->OnReadFromDemuxer(player_id(), DemuxerStream::AUDIO, true); 455 received_audio_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); 456 audio_access_unit_index_ = 0; 457 waiting_for_audio_data_ = true; 458 } 459 return; 460 } 461 462 audio_decoder_job_->Decode( 463 received_audio_.access_units[audio_access_unit_index_], 464 start_wallclock_time_, start_presentation_timestamp_, 465 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, 466 weak_this_.GetWeakPtr(), true)); 467 active_decoding_tasks_++; 468 audio_access_unit_index_++; 469} 470 471void MediaSourcePlayer::DecodeMoreVideo() { 472 if (video_access_unit_index_ >= received_video_.access_units.size()) { 473 if (!waiting_for_video_data_) { 474 manager()->OnReadFromDemuxer(player_id(), DemuxerStream::VIDEO, true); 475 received_video_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); 476 video_access_unit_index_ = 0; 477 waiting_for_video_data_ = true; 478 } 479 return; 480 } 481 482 video_decoder_job_->Decode( 483 received_video_.access_units[video_access_unit_index_], 484 start_wallclock_time_, start_presentation_timestamp_, 485 base::Bind(&MediaSourcePlayer::MediaDecoderCallback, 486 weak_this_.GetWeakPtr(), false)); 487 active_decoding_tasks_++; 488 video_access_unit_index_++; 489} 490 491 492void MediaSourcePlayer::PlaybackCompleted(bool is_audio) { 493 if (is_audio) 494 audio_finished_ = true; 495 else 496 video_finished_ = true; 497 498 if ((!HasAudio() || audio_finished_) && (!HasVideo() || video_finished_)) { 499 playing_ = false; 500 start_wallclock_time_ = base::Time(); 501 OnPlaybackComplete(); 502 } 503} 504 505void MediaSourcePlayer::ClearDecodingData() { 506 if (audio_decoder_job_) 507 audio_decoder_job_->Flush(); 508 if (video_decoder_job_) 509 video_decoder_job_->Flush(); 510 start_wallclock_time_ = base::Time(); 511 received_audio_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); 512 received_video_ = MediaPlayerHostMsg_ReadFromDemuxerAck_Params(); 513 audio_access_unit_index_ = 0; 514 video_access_unit_index_ = 0; 515} 516 517bool MediaSourcePlayer::HasVideo() { 518 return kUnknownVideoCodec != video_codec_; 519} 520 521bool MediaSourcePlayer::HasAudio() { 522 return kUnknownAudioCodec != audio_codec_; 523} 524 525} // namespace media 526