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 "content/renderer/media/android/media_source_delegate.h" 6 7 #include <limits> 8 #include <string> 9 #include <vector> 10 11 #include "base/message_loop/message_loop_proxy.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "content/renderer/media/android/renderer_demuxer_android.h" 14 #include "content/renderer/media/webmediaplayer_util.h" 15 #include "content/renderer/media/webmediasource_impl.h" 16 #include "media/base/android/demuxer_stream_player_params.h" 17 #include "media/base/bind_to_loop.h" 18 #include "media/base/demuxer_stream.h" 19 #include "media/base/media_log.h" 20 #include "media/filters/chunk_demuxer.h" 21 #include "media/filters/decrypting_demuxer_stream.h" 22 #include "third_party/WebKit/public/platform/WebString.h" 23 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" 24 25 using media::DemuxerStream; 26 using media::DemuxerConfigs; 27 using media::DemuxerData; 28 using blink::WebMediaPlayer; 29 using blink::WebString; 30 31 namespace { 32 33 // The size of the access unit to transfer in an IPC in case of MediaSource. 34 // 16: approximately 250ms of content in 60 fps movies. 35 const size_t kAccessUnitSizeForMediaSource = 16; 36 37 const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff }; 38 39 } // namespace 40 41 namespace content { 42 43 static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log, 44 const std::string& error) { 45 media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error)); 46 } 47 48 MediaSourceDelegate::MediaSourceDelegate( 49 RendererDemuxerAndroid* demuxer_client, 50 int demuxer_client_id, 51 const scoped_refptr<base::MessageLoopProxy>& media_loop, 52 media::MediaLog* media_log) 53 : main_loop_(base::MessageLoopProxy::current()), 54 main_weak_factory_(this), 55 main_weak_this_(main_weak_factory_.GetWeakPtr()), 56 media_loop_(media_loop), 57 media_weak_factory_(this), 58 demuxer_client_(demuxer_client), 59 demuxer_client_id_(demuxer_client_id), 60 media_log_(media_log), 61 demuxer_(NULL), 62 is_demuxer_ready_(false), 63 audio_stream_(NULL), 64 video_stream_(NULL), 65 seeking_(false), 66 doing_browser_seek_(false), 67 browser_seek_time_(media::kNoTimestamp()), 68 expecting_regular_seek_(false), 69 #if defined(GOOGLE_TV) 70 key_added_(false), 71 #endif 72 access_unit_size_(0) { 73 DCHECK(main_loop_->BelongsToCurrentThread()); 74 } 75 76 MediaSourceDelegate::~MediaSourceDelegate() { 77 DCHECK(main_loop_->BelongsToCurrentThread()); 78 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 79 DCHECK(!chunk_demuxer_); 80 DCHECK(!demuxer_); 81 DCHECK(!demuxer_client_); 82 DCHECK(!audio_decrypting_demuxer_stream_); 83 DCHECK(!video_decrypting_demuxer_stream_); 84 DCHECK(!audio_stream_); 85 DCHECK(!video_stream_); 86 } 87 88 void MediaSourceDelegate::Destroy() { 89 DCHECK(main_loop_->BelongsToCurrentThread()); 90 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 91 92 if (!demuxer_) { 93 DCHECK(!demuxer_client_); 94 delete this; 95 return; 96 } 97 98 duration_change_cb_.Reset(); 99 update_network_state_cb_.Reset(); 100 media_source_opened_cb_.Reset(); 101 102 main_weak_factory_.InvalidateWeakPtrs(); 103 DCHECK(!main_weak_factory_.HasWeakPtrs()); 104 105 if (chunk_demuxer_) 106 chunk_demuxer_->Shutdown(); 107 108 // |this| will be transferred to the callback StopDemuxer() and 109 // OnDemuxerStopDone(). They own |this| and OnDemuxerStopDone() will delete 110 // it when called, hence using base::Unretained(this) is safe here. 111 media_loop_->PostTask(FROM_HERE, 112 base::Bind(&MediaSourceDelegate::StopDemuxer, 113 base::Unretained(this))); 114 } 115 116 void MediaSourceDelegate::StopDemuxer() { 117 DCHECK(media_loop_->BelongsToCurrentThread()); 118 DCHECK(demuxer_); 119 120 demuxer_client_->RemoveDelegate(demuxer_client_id_); 121 demuxer_client_ = NULL; 122 123 audio_stream_ = NULL; 124 video_stream_ = NULL; 125 // TODO(xhwang): Figure out if we need to Reset the DDSs after Seeking or 126 // before destroying them. 127 audio_decrypting_demuxer_stream_.reset(); 128 video_decrypting_demuxer_stream_.reset(); 129 130 media_weak_factory_.InvalidateWeakPtrs(); 131 DCHECK(!media_weak_factory_.HasWeakPtrs()); 132 133 // The callback OnDemuxerStopDone() owns |this| and will delete it when 134 // called. Hence using base::Unretained(this) is safe here. 135 demuxer_->Stop(media::BindToLoop(main_loop_, 136 base::Bind(&MediaSourceDelegate::OnDemuxerStopDone, 137 base::Unretained(this)))); 138 } 139 140 void MediaSourceDelegate::InitializeMediaSource( 141 const MediaSourceOpenedCB& media_source_opened_cb, 142 const media::Demuxer::NeedKeyCB& need_key_cb, 143 const media::SetDecryptorReadyCB& set_decryptor_ready_cb, 144 const UpdateNetworkStateCB& update_network_state_cb, 145 const DurationChangeCB& duration_change_cb) { 146 DCHECK(main_loop_->BelongsToCurrentThread()); 147 DCHECK(!media_source_opened_cb.is_null()); 148 media_source_opened_cb_ = media_source_opened_cb; 149 need_key_cb_ = need_key_cb; 150 set_decryptor_ready_cb_ = set_decryptor_ready_cb; 151 update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); 152 duration_change_cb_ = duration_change_cb; 153 access_unit_size_ = kAccessUnitSizeForMediaSource; 154 155 chunk_demuxer_.reset(new media::ChunkDemuxer( 156 media::BindToCurrentLoop(base::Bind( 157 &MediaSourceDelegate::OnDemuxerOpened, main_weak_this_)), 158 media::BindToCurrentLoop(base::Bind( 159 &MediaSourceDelegate::OnNeedKey, main_weak_this_)), 160 base::Bind(&LogMediaSourceError, media_log_))); 161 demuxer_ = chunk_demuxer_.get(); 162 163 // |this| will be retained until StopDemuxer() is posted, so Unretained() is 164 // safe here. 165 media_loop_->PostTask(FROM_HERE, 166 base::Bind(&MediaSourceDelegate::InitializeDemuxer, 167 base::Unretained(this))); 168 } 169 170 void MediaSourceDelegate::InitializeDemuxer() { 171 DCHECK(media_loop_->BelongsToCurrentThread()); 172 demuxer_client_->AddDelegate(demuxer_client_id_, this); 173 demuxer_->Initialize(this, base::Bind(&MediaSourceDelegate::OnDemuxerInitDone, 174 media_weak_factory_.GetWeakPtr()), 175 false); 176 } 177 178 #if defined(GOOGLE_TV) 179 void MediaSourceDelegate::InitializeMediaStream( 180 media::Demuxer* demuxer, 181 const UpdateNetworkStateCB& update_network_state_cb) { 182 DCHECK(main_loop_->BelongsToCurrentThread()); 183 DCHECK(demuxer); 184 demuxer_ = demuxer; 185 update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); 186 // When playing Media Stream, don't wait to accumulate multiple packets per 187 // IPC communication. 188 access_unit_size_ = 1; 189 190 // |this| will be retained until StopDemuxer() is posted, so Unretained() is 191 // safe here. 192 media_loop_->PostTask(FROM_HERE, 193 base::Bind(&MediaSourceDelegate::InitializeDemuxer, 194 base::Unretained(this))); 195 } 196 #endif 197 198 const blink::WebTimeRanges& MediaSourceDelegate::Buffered() { 199 buffered_web_time_ranges_ = 200 ConvertToWebTimeRanges(buffered_time_ranges_); 201 return buffered_web_time_ranges_; 202 } 203 204 size_t MediaSourceDelegate::DecodedFrameCount() const { 205 return statistics_.video_frames_decoded; 206 } 207 208 size_t MediaSourceDelegate::DroppedFrameCount() const { 209 return statistics_.video_frames_dropped; 210 } 211 212 size_t MediaSourceDelegate::AudioDecodedByteCount() const { 213 return statistics_.audio_bytes_decoded; 214 } 215 216 size_t MediaSourceDelegate::VideoDecodedByteCount() const { 217 return statistics_.video_bytes_decoded; 218 } 219 220 void MediaSourceDelegate::CancelPendingSeek(const base::TimeDelta& seek_time) { 221 DCHECK(main_loop_->BelongsToCurrentThread()); 222 DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : " 223 << demuxer_client_id_; 224 225 if (!chunk_demuxer_) 226 return; 227 228 { 229 // Remember to trivially finish any newly arriving browser seek requests 230 // that may arrive prior to the next regular seek request. 231 base::AutoLock auto_lock(seeking_lock_); 232 expecting_regular_seek_ = true; 233 } 234 235 // Cancel any previously expected or in-progress regular or browser seek. 236 // It is possible that we have just finished the seek, but caller does 237 // not know this yet. It is still safe to cancel in this case because the 238 // caller will always call StartWaitingForSeek() when it is notified of 239 // the finished seek. 240 chunk_demuxer_->CancelPendingSeek(seek_time); 241 } 242 243 void MediaSourceDelegate::StartWaitingForSeek( 244 const base::TimeDelta& seek_time) { 245 DCHECK(main_loop_->BelongsToCurrentThread()); 246 DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : " 247 << demuxer_client_id_; 248 249 if (!chunk_demuxer_) 250 return; 251 252 bool cancel_browser_seek = false; 253 { 254 // Remember to trivially finish any newly arriving browser seek requests 255 // that may arrive prior to the next regular seek request. 256 base::AutoLock auto_lock(seeking_lock_); 257 expecting_regular_seek_ = true; 258 259 // Remember to cancel any in-progress browser seek. 260 if (seeking_) { 261 DCHECK(doing_browser_seek_); 262 cancel_browser_seek = true; 263 } 264 } 265 266 if (cancel_browser_seek) 267 chunk_demuxer_->CancelPendingSeek(seek_time); 268 chunk_demuxer_->StartWaitingForSeek(seek_time); 269 } 270 271 void MediaSourceDelegate::Seek( 272 const base::TimeDelta& seek_time, bool is_browser_seek) { 273 DCHECK(media_loop_->BelongsToCurrentThread()); 274 DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ", " 275 << (is_browser_seek ? "browser seek" : "regular seek") << ") : " 276 << demuxer_client_id_; 277 278 base::TimeDelta internal_seek_time = seek_time; 279 { 280 base::AutoLock auto_lock(seeking_lock_); 281 DCHECK(!seeking_); 282 seeking_ = true; 283 doing_browser_seek_ = is_browser_seek; 284 285 if (doing_browser_seek_ && (!chunk_demuxer_ || expecting_regular_seek_)) { 286 // Trivially finish the browser seek without actually doing it. Reads will 287 // continue to be |kAborted| until the next regular seek is done. Browser 288 // seeking is not supported unless using a ChunkDemuxer; browser seeks are 289 // trivially finished if |chunk_demuxer_| is NULL. 290 seeking_ = false; 291 doing_browser_seek_ = false; 292 demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time); 293 return; 294 } 295 296 if (doing_browser_seek_) { 297 internal_seek_time = FindBufferedBrowserSeekTime_Locked(seek_time); 298 browser_seek_time_ = internal_seek_time; 299 } else { 300 expecting_regular_seek_ = false; 301 browser_seek_time_ = media::kNoTimestamp(); 302 } 303 } 304 305 // Prepare |chunk_demuxer_| for browser seek. 306 if (is_browser_seek) { 307 chunk_demuxer_->CancelPendingSeek(internal_seek_time); 308 chunk_demuxer_->StartWaitingForSeek(internal_seek_time); 309 } 310 311 SeekInternal(internal_seek_time); 312 } 313 314 void MediaSourceDelegate::SeekInternal(const base::TimeDelta& seek_time) { 315 DCHECK(media_loop_->BelongsToCurrentThread()); 316 DCHECK(IsSeeking()); 317 demuxer_->Seek(seek_time, base::Bind( 318 &MediaSourceDelegate::OnDemuxerSeekDone, 319 media_weak_factory_.GetWeakPtr())); 320 } 321 322 void MediaSourceDelegate::SetTotalBytes(int64 total_bytes) { 323 NOTIMPLEMENTED(); 324 } 325 326 void MediaSourceDelegate::AddBufferedByteRange(int64 start, int64 end) { 327 NOTIMPLEMENTED(); 328 } 329 330 void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start, 331 base::TimeDelta end) { 332 buffered_time_ranges_.Add(start, end); 333 } 334 335 void MediaSourceDelegate::SetDuration(base::TimeDelta duration) { 336 DCHECK(main_loop_->BelongsToCurrentThread()); 337 DVLOG(1) << __FUNCTION__ << "(" << duration.InSecondsF() << ") : " 338 << demuxer_client_id_; 339 340 // Force duration change notification to be async to avoid reentrancy into 341 // ChunkDemxuer. 342 main_loop_->PostTask(FROM_HERE, base::Bind( 343 &MediaSourceDelegate::OnDurationChanged, main_weak_this_, duration)); 344 } 345 346 void MediaSourceDelegate::OnDurationChanged(const base::TimeDelta& duration) { 347 DCHECK(main_loop_->BelongsToCurrentThread()); 348 if (demuxer_client_) 349 demuxer_client_->DurationChanged(demuxer_client_id_, duration); 350 if (!duration_change_cb_.is_null()) 351 duration_change_cb_.Run(duration); 352 } 353 354 void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) { 355 DCHECK(media_loop_->BelongsToCurrentThread()); 356 DVLOG(1) << __FUNCTION__ << "(" << type << ") : " << demuxer_client_id_; 357 if (IsSeeking()) 358 return; // Drop the request during seeking. 359 360 DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO); 361 // The access unit size should have been initialized properly at this stage. 362 DCHECK_GT(access_unit_size_, 0u); 363 scoped_ptr<DemuxerData> data(new DemuxerData()); 364 data->type = type; 365 data->access_units.resize(access_unit_size_); 366 ReadFromDemuxerStream(type, data.Pass(), 0); 367 } 368 369 void MediaSourceDelegate::ReadFromDemuxerStream(media::DemuxerStream::Type type, 370 scoped_ptr<DemuxerData> data, 371 size_t index) { 372 DCHECK(media_loop_->BelongsToCurrentThread()); 373 // DemuxerStream::Read() always returns the read callback asynchronously. 374 DemuxerStream* stream = 375 (type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_; 376 stream->Read(base::Bind( 377 &MediaSourceDelegate::OnBufferReady, 378 media_weak_factory_.GetWeakPtr(), type, base::Passed(&data), index)); 379 } 380 381 void MediaSourceDelegate::OnBufferReady( 382 media::DemuxerStream::Type type, 383 scoped_ptr<DemuxerData> data, 384 size_t index, 385 DemuxerStream::Status status, 386 const scoped_refptr<media::DecoderBuffer>& buffer) { 387 DCHECK(media_loop_->BelongsToCurrentThread()); 388 DVLOG(1) << __FUNCTION__ << "(" << index << ", " << status << ", " 389 << ((!buffer || buffer->end_of_stream()) ? 390 -1 : buffer->timestamp().InMilliseconds()) 391 << ") : " << demuxer_client_id_; 392 DCHECK(demuxer_); 393 394 // No new OnReadFromDemuxer() will be called during seeking. So this callback 395 // must be from previous OnReadFromDemuxer() call and should be ignored. 396 if (IsSeeking()) { 397 DVLOG(1) << __FUNCTION__ << ": Ignore previous read during seeking."; 398 return; 399 } 400 401 bool is_audio = (type == DemuxerStream::AUDIO); 402 if (status != DemuxerStream::kAborted && 403 index >= data->access_units.size()) { 404 LOG(ERROR) << "The internal state inconsistency onBufferReady: " 405 << (is_audio ? "Audio" : "Video") << ", index " << index 406 << ", size " << data->access_units.size() 407 << ", status " << static_cast<int>(status); 408 NOTREACHED(); 409 return; 410 } 411 412 switch (status) { 413 case DemuxerStream::kAborted: 414 DVLOG(1) << __FUNCTION__ << " : Aborted"; 415 data->access_units[index].status = status; 416 data->access_units.resize(index + 1); 417 break; 418 419 case DemuxerStream::kConfigChanged: 420 // In case of kConfigChanged, need to read decoder_config once 421 // for the next reads. 422 // TODO(kjyoun): Investigate if we need to use this new config. See 423 // http://crbug.com/255783 424 if (is_audio) { 425 audio_stream_->audio_decoder_config(); 426 } else { 427 gfx::Size size = video_stream_->video_decoder_config().coded_size(); 428 DVLOG(1) << "Video config is changed: " << size.width() << "x" 429 << size.height(); 430 } 431 data->access_units[index].status = status; 432 data->access_units.resize(index + 1); 433 break; 434 435 case DemuxerStream::kOk: 436 data->access_units[index].status = status; 437 if (buffer->end_of_stream()) { 438 data->access_units[index].end_of_stream = true; 439 data->access_units.resize(index + 1); 440 break; 441 } 442 // TODO(ycheo): We assume that the inputed stream will be decoded 443 // right away. 444 // Need to implement this properly using MediaPlayer.OnInfoListener. 445 if (is_audio) { 446 statistics_.audio_bytes_decoded += buffer->data_size(); 447 } else { 448 statistics_.video_bytes_decoded += buffer->data_size(); 449 statistics_.video_frames_decoded++; 450 } 451 data->access_units[index].timestamp = buffer->timestamp(); 452 453 { // No local variable in switch-case scope. 454 int data_offset = buffer->decrypt_config() ? 455 buffer->decrypt_config()->data_offset() : 0; 456 DCHECK_LT(data_offset, buffer->data_size()); 457 data->access_units[index].data = std::vector<uint8>( 458 buffer->data() + data_offset, 459 buffer->data() + buffer->data_size() - data_offset); 460 } 461 #if !defined(GOOGLE_TV) 462 // Vorbis needs 4 extra bytes padding on Android. Check 463 // NuMediaExtractor.cpp in Android source code. 464 if (is_audio && media::kCodecVorbis == 465 audio_stream_->audio_decoder_config().codec()) { 466 data->access_units[index].data.insert( 467 data->access_units[index].data.end(), kVorbisPadding, 468 kVorbisPadding + 4); 469 } 470 #endif 471 if (buffer->decrypt_config()) { 472 data->access_units[index].key_id = std::vector<char>( 473 buffer->decrypt_config()->key_id().begin(), 474 buffer->decrypt_config()->key_id().end()); 475 data->access_units[index].iv = std::vector<char>( 476 buffer->decrypt_config()->iv().begin(), 477 buffer->decrypt_config()->iv().end()); 478 data->access_units[index].subsamples = 479 buffer->decrypt_config()->subsamples(); 480 } 481 if (++index < data->access_units.size()) { 482 ReadFromDemuxerStream(type, data.Pass(), index); 483 return; 484 } 485 break; 486 487 default: 488 NOTREACHED(); 489 } 490 491 if (!IsSeeking() && demuxer_client_) 492 demuxer_client_->ReadFromDemuxerAck(demuxer_client_id_, *data); 493 } 494 495 void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) { 496 DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; 497 // |update_network_state_cb_| is bound to the main thread. 498 if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null()) 499 update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); 500 } 501 502 void MediaSourceDelegate::AddTextStream( 503 media::DemuxerStream* /* text_stream */ , 504 const media::TextTrackConfig& /* config */ ) { 505 // TODO(matthewjheaney): add text stream (http://crbug/322115). 506 NOTIMPLEMENTED(); 507 } 508 509 void MediaSourceDelegate::RemoveTextStream( 510 media::DemuxerStream* /* text_stream */ ) { 511 // TODO(matthewjheaney): remove text stream (http://crbug/322115). 512 NOTIMPLEMENTED(); 513 } 514 515 void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) { 516 DCHECK(media_loop_->BelongsToCurrentThread()); 517 DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; 518 DCHECK(demuxer_); 519 520 if (status != media::PIPELINE_OK) { 521 OnDemuxerError(status); 522 return; 523 } 524 525 audio_stream_ = demuxer_->GetStream(DemuxerStream::AUDIO); 526 video_stream_ = demuxer_->GetStream(DemuxerStream::VIDEO); 527 528 if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() && 529 !set_decryptor_ready_cb_.is_null()) { 530 InitAudioDecryptingDemuxerStream(); 531 // InitVideoDecryptingDemuxerStream() will be called in 532 // OnAudioDecryptingDemuxerStreamInitDone(). 533 return; 534 } 535 536 if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() && 537 !set_decryptor_ready_cb_.is_null()) { 538 InitVideoDecryptingDemuxerStream(); 539 return; 540 } 541 542 // Notify demuxer ready when both streams are not encrypted. 543 is_demuxer_ready_ = true; 544 if (CanNotifyDemuxerReady()) 545 NotifyDemuxerReady(); 546 } 547 548 void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() { 549 DCHECK(media_loop_->BelongsToCurrentThread()); 550 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 551 DCHECK(!set_decryptor_ready_cb_.is_null()); 552 553 audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( 554 media_loop_, set_decryptor_ready_cb_)); 555 audio_decrypting_demuxer_stream_->Initialize( 556 audio_stream_, 557 base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone, 558 media_weak_factory_.GetWeakPtr())); 559 } 560 561 void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() { 562 DCHECK(media_loop_->BelongsToCurrentThread()); 563 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 564 DCHECK(!set_decryptor_ready_cb_.is_null()); 565 566 video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( 567 media_loop_, set_decryptor_ready_cb_)); 568 video_decrypting_demuxer_stream_->Initialize( 569 video_stream_, 570 base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone, 571 media_weak_factory_.GetWeakPtr())); 572 } 573 574 void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone( 575 media::PipelineStatus status) { 576 DCHECK(media_loop_->BelongsToCurrentThread()); 577 DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; 578 DCHECK(demuxer_); 579 580 if (status != media::PIPELINE_OK) 581 audio_decrypting_demuxer_stream_.reset(); 582 else 583 audio_stream_ = audio_decrypting_demuxer_stream_.get(); 584 585 if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) { 586 InitVideoDecryptingDemuxerStream(); 587 return; 588 } 589 590 // Try to notify demuxer ready when audio DDS initialization finished and 591 // video is not encrypted. 592 is_demuxer_ready_ = true; 593 if (CanNotifyDemuxerReady()) 594 NotifyDemuxerReady(); 595 } 596 597 void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone( 598 media::PipelineStatus status) { 599 DCHECK(media_loop_->BelongsToCurrentThread()); 600 DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; 601 DCHECK(demuxer_); 602 603 if (status != media::PIPELINE_OK) 604 video_decrypting_demuxer_stream_.reset(); 605 else 606 video_stream_ = video_decrypting_demuxer_stream_.get(); 607 608 // Try to notify demuxer ready when video DDS initialization finished. 609 is_demuxer_ready_ = true; 610 if (CanNotifyDemuxerReady()) 611 NotifyDemuxerReady(); 612 } 613 614 void MediaSourceDelegate::OnDemuxerSeekDone(media::PipelineStatus status) { 615 DCHECK(media_loop_->BelongsToCurrentThread()); 616 DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; 617 DCHECK(IsSeeking()); 618 619 if (status != media::PIPELINE_OK) { 620 OnDemuxerError(status); 621 return; 622 } 623 624 ResetAudioDecryptingDemuxerStream(); 625 } 626 627 void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() { 628 DCHECK(media_loop_->BelongsToCurrentThread()); 629 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 630 if (audio_decrypting_demuxer_stream_) { 631 audio_decrypting_demuxer_stream_->Reset( 632 base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream, 633 media_weak_factory_.GetWeakPtr())); 634 return; 635 } 636 637 ResetVideoDecryptingDemuxerStream(); 638 } 639 640 void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() { 641 DCHECK(media_loop_->BelongsToCurrentThread()); 642 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 643 if (video_decrypting_demuxer_stream_) { 644 video_decrypting_demuxer_stream_->Reset(base::Bind( 645 &MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams, 646 media_weak_factory_.GetWeakPtr())); 647 return; 648 } 649 650 FinishResettingDecryptingDemuxerStreams(); 651 } 652 653 void MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams() { 654 DCHECK(media_loop_->BelongsToCurrentThread()); 655 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 656 657 base::AutoLock auto_lock(seeking_lock_); 658 DCHECK(seeking_); 659 seeking_ = false; 660 doing_browser_seek_ = false; 661 demuxer_client_->DemuxerSeekDone(demuxer_client_id_, browser_seek_time_); 662 } 663 664 void MediaSourceDelegate::OnDemuxerStopDone() { 665 DCHECK(main_loop_->BelongsToCurrentThread()); 666 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 667 chunk_demuxer_.reset(); 668 demuxer_ = NULL; 669 delete this; 670 } 671 672 void MediaSourceDelegate::OnMediaConfigRequest() { 673 DCHECK(media_loop_->BelongsToCurrentThread()); 674 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 675 if (CanNotifyDemuxerReady()) 676 NotifyDemuxerReady(); 677 } 678 679 #if defined(GOOGLE_TV) 680 // TODO(kjyoun): Enhance logic to detect when to call NotifyDemuxerReady() 681 // For now, we call it when the first key is added. See http://crbug.com/255781 682 void MediaSourceDelegate::NotifyKeyAdded(const std::string& key_system) { 683 if (!media_loop_->BelongsToCurrentThread()) { 684 media_loop_->PostTask(FROM_HERE, 685 base::Bind(&MediaSourceDelegate::NotifyKeyAdded, 686 base::Unretained(this), key_system)); 687 return; 688 } 689 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 690 if (key_added_) 691 return; 692 key_added_ = true; 693 key_system_ = key_system; 694 if (!CanNotifyDemuxerReady()) 695 return; 696 if (HasEncryptedStream()) 697 NotifyDemuxerReady(); 698 } 699 #endif // defined(GOOGLE_TV) 700 701 bool MediaSourceDelegate::CanNotifyDemuxerReady() { 702 DCHECK(media_loop_->BelongsToCurrentThread()); 703 // This can happen when a key is added before the demuxer is initialized. 704 // See NotifyKeyAdded(). 705 // TODO(kjyoun): Remove NotifyDemxuerReady() call from NotifyKeyAdded() so 706 // that we can remove all is_demuxer_ready_/key_added_/key_system_ madness. 707 // See http://crbug.com/255781 708 if (!is_demuxer_ready_) 709 return false; 710 #if defined(GOOGLE_TV) 711 if (HasEncryptedStream() && !key_added_) 712 return false; 713 #endif // defined(GOOGLE_TV) 714 return true; 715 } 716 717 void MediaSourceDelegate::NotifyDemuxerReady() { 718 DCHECK(media_loop_->BelongsToCurrentThread()); 719 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; 720 DCHECK(CanNotifyDemuxerReady()); 721 722 scoped_ptr<DemuxerConfigs> configs(new DemuxerConfigs()); 723 if (audio_stream_) { 724 media::AudioDecoderConfig config = audio_stream_->audio_decoder_config(); 725 configs->audio_codec = config.codec(); 726 configs->audio_channels = 727 media::ChannelLayoutToChannelCount(config.channel_layout()); 728 configs->audio_sampling_rate = config.samples_per_second(); 729 configs->is_audio_encrypted = config.is_encrypted(); 730 configs->audio_extra_data = std::vector<uint8>( 731 config.extra_data(), config.extra_data() + config.extra_data_size()); 732 } 733 if (video_stream_) { 734 media::VideoDecoderConfig config = video_stream_->video_decoder_config(); 735 configs->video_codec = config.codec(); 736 configs->video_size = config.natural_size(); 737 configs->is_video_encrypted = config.is_encrypted(); 738 configs->video_extra_data = std::vector<uint8>( 739 config.extra_data(), config.extra_data() + config.extra_data_size()); 740 } 741 configs->duration_ms = GetDurationMs(); 742 743 #if defined(GOOGLE_TV) 744 configs->key_system = HasEncryptedStream() ? key_system_ : ""; 745 #endif 746 747 if (demuxer_client_) 748 demuxer_client_->DemuxerReady(demuxer_client_id_, *configs); 749 } 750 751 int MediaSourceDelegate::GetDurationMs() { 752 DCHECK(media_loop_->BelongsToCurrentThread()); 753 if (!chunk_demuxer_) 754 return -1; 755 756 double duration_ms = chunk_demuxer_->GetDuration() * 1000; 757 if (duration_ms > std::numeric_limits<int32>::max()) { 758 LOG(WARNING) << "Duration from ChunkDemuxer is too large; probably " 759 "something has gone wrong."; 760 return std::numeric_limits<int32>::max(); 761 } 762 return duration_ms; 763 } 764 765 void MediaSourceDelegate::OnDemuxerOpened() { 766 DCHECK(main_loop_->BelongsToCurrentThread()); 767 if (media_source_opened_cb_.is_null()) 768 return; 769 770 media_source_opened_cb_.Run(new WebMediaSourceImpl( 771 chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_))); 772 } 773 774 void MediaSourceDelegate::OnNeedKey(const std::string& type, 775 const std::vector<uint8>& init_data) { 776 DCHECK(main_loop_->BelongsToCurrentThread()); 777 if (need_key_cb_.is_null()) 778 return; 779 780 need_key_cb_.Run(type, init_data); 781 } 782 783 bool MediaSourceDelegate::HasEncryptedStream() { 784 DCHECK(media_loop_->BelongsToCurrentThread()); 785 return (audio_stream_ && 786 audio_stream_->audio_decoder_config().is_encrypted()) || 787 (video_stream_ && 788 video_stream_->video_decoder_config().is_encrypted()); 789 } 790 791 bool MediaSourceDelegate::IsSeeking() const { 792 base::AutoLock auto_lock(seeking_lock_); 793 return seeking_; 794 } 795 796 base::TimeDelta MediaSourceDelegate::FindBufferedBrowserSeekTime_Locked( 797 const base::TimeDelta& seek_time) const { 798 seeking_lock_.AssertAcquired(); 799 DCHECK(seeking_); 800 DCHECK(doing_browser_seek_); 801 DCHECK(chunk_demuxer_) << "Browser seek requested, but no chunk demuxer"; 802 803 media::Ranges<base::TimeDelta> buffered = 804 chunk_demuxer_->GetBufferedRanges(); 805 806 for (size_t i = 0; i < buffered.size(); ++i) { 807 base::TimeDelta range_start = buffered.start(i); 808 base::TimeDelta range_end = buffered.end(i); 809 if (range_start <= seek_time) { 810 if (range_end >= seek_time) 811 return seek_time; 812 continue; 813 } 814 815 // If the start of the next buffered range after |seek_time| is too far 816 // into the future, do not jump forward. 817 if ((range_start - seek_time) > base::TimeDelta::FromMilliseconds(100)) 818 break; 819 820 // TODO(wolenetz): Remove possibility that this browser seek jumps 821 // into future when the requested range is unbuffered but there is some 822 // other buffered range after it. See http://crbug.com/304234. 823 return range_start; 824 } 825 826 // We found no range containing |seek_time| or beginning shortly after 827 // |seek_time|. While possible that such data at and beyond the player's 828 // current time have been garbage collected or removed by the web app, this is 829 // unlikely. This may cause unexpected playback stall due to seek pending an 830 // append for a GOP prior to the last GOP demuxed. 831 // TODO(wolenetz): Remove the possibility for this seek to cause unexpected 832 // player stall by replaying cached data since last keyframe in browser player 833 // rather than issuing browser seek. See http://crbug.com/304234. 834 return seek_time; 835 } 836 837 } // namespace content 838