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