| Index: content/renderer/media/android/media_source_delegate.cc | 
| diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc | 
| deleted file mode 100644 | 
| index 24a65a04804b439549d34fa1ebcf93ac4f84b416..0000000000000000000000000000000000000000 | 
| --- a/content/renderer/media/android/media_source_delegate.cc | 
| +++ /dev/null | 
| @@ -1,811 +0,0 @@ | 
| -// Copyright 2013 The Chromium Authors. All rights reserved. | 
| -// Use of this source code is governed by a BSD-style license that can be | 
| -// found in the LICENSE file. | 
| - | 
| -#include "content/renderer/media/android/media_source_delegate.h" | 
| - | 
| -#include <limits> | 
| -#include <string> | 
| -#include <utility> | 
| -#include <vector> | 
| - | 
| -#include "base/callback_helpers.h" | 
| -#include "base/strings/string_number_conversions.h" | 
| -#include "base/threading/thread_task_runner_handle.h" | 
| -#include "content/renderer/media/android/renderer_demuxer_android.h" | 
| -#include "media/base/android/demuxer_stream_player_params.h" | 
| -#include "media/base/bind_to_current_loop.h" | 
| -#include "media/base/demuxer_stream.h" | 
| -#include "media/base/media_log.h" | 
| -#include "media/base/timestamp_constants.h" | 
| -#include "media/blink/webmediaplayer_util.h" | 
| -#include "media/blink/webmediasource_impl.h" | 
| -#include "media/filters/chunk_demuxer.h" | 
| -#include "media/filters/decrypting_demuxer_stream.h" | 
| -#include "third_party/WebKit/public/platform/WebString.h" | 
| -#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" | 
| - | 
| -using media::DemuxerStream; | 
| -using media::DemuxerConfigs; | 
| -using media::DemuxerData; | 
| -using blink::WebMediaPlayer; | 
| -using blink::WebString; | 
| - | 
| -namespace { | 
| - | 
| -// The size of the access unit to transfer in an IPC in case of MediaSource. | 
| -// 4: approximately 64ms of content in 60 fps movies. | 
| -const size_t kAccessUnitSizeForMediaSource = 4; | 
| - | 
| -const uint8_t kVorbisPadding[] = {0xff, 0xff, 0xff, 0xff}; | 
| - | 
| -}  // namespace | 
| - | 
| -namespace content { | 
| - | 
| -MediaSourceDelegate::MediaSourceDelegate( | 
| -    RendererDemuxerAndroid* demuxer_client, | 
| -    int demuxer_client_id, | 
| -    const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | 
| -    const scoped_refptr<media::MediaLog> media_log) | 
| -    : demuxer_client_(demuxer_client), | 
| -      demuxer_client_id_(demuxer_client_id), | 
| -      media_log_(media_log), | 
| -      is_demuxer_ready_(false), | 
| -      audio_stream_(NULL), | 
| -      video_stream_(NULL), | 
| -      seeking_(false), | 
| -      is_video_encrypted_(false), | 
| -      doing_browser_seek_(false), | 
| -      browser_seek_time_(media::kNoTimestamp), | 
| -      expecting_regular_seek_(false), | 
| -      access_unit_size_(0), | 
| -      main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 
| -      media_task_runner_(media_task_runner), | 
| -      main_weak_factory_(this), | 
| -      media_weak_factory_(this) { | 
| -  main_weak_this_ = main_weak_factory_.GetWeakPtr(); | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -} | 
| - | 
| -MediaSourceDelegate::~MediaSourceDelegate() { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; | 
| -  DCHECK(!chunk_demuxer_); | 
| -  DCHECK(!demuxer_client_); | 
| -  DCHECK(!audio_decrypting_demuxer_stream_); | 
| -  DCHECK(!video_decrypting_demuxer_stream_); | 
| -  DCHECK(!audio_stream_); | 
| -  DCHECK(!video_stream_); | 
| -} | 
| - | 
| -void MediaSourceDelegate::Stop(const base::Closure& stop_cb) { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; | 
| - | 
| -  if (!chunk_demuxer_) { | 
| -    DCHECK(!demuxer_client_); | 
| -    return; | 
| -  } | 
| - | 
| -  duration_change_cb_.Reset(); | 
| -  update_network_state_cb_.Reset(); | 
| -  media_source_opened_cb_.Reset(); | 
| - | 
| -  main_weak_factory_.InvalidateWeakPtrs(); | 
| -  DCHECK(!main_weak_factory_.HasWeakPtrs()); | 
| - | 
| -  chunk_demuxer_->Shutdown(); | 
| - | 
| -  // Continue to stop objects on the media thread. | 
| -  media_task_runner_->PostTask( | 
| -      FROM_HERE, | 
| -      base::Bind( | 
| -          &MediaSourceDelegate::StopDemuxer, base::Unretained(this), stop_cb)); | 
| -} | 
| - | 
| -bool MediaSourceDelegate::IsVideoEncrypted() { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  base::AutoLock auto_lock(is_video_encrypted_lock_); | 
| -  return is_video_encrypted_; | 
| -} | 
| - | 
| -base::Time MediaSourceDelegate::GetTimelineOffset() const { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  if (!chunk_demuxer_) | 
| -    return base::Time(); | 
| - | 
| -  return chunk_demuxer_->GetTimelineOffset(); | 
| -} | 
| - | 
| -void MediaSourceDelegate::StopDemuxer(const base::Closure& stop_cb) { | 
| -  DVLOG(2) << __FUNCTION__; | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DCHECK(chunk_demuxer_); | 
| - | 
| -  demuxer_client_->RemoveDelegate(demuxer_client_id_); | 
| -  demuxer_client_ = NULL; | 
| - | 
| -  audio_stream_ = NULL; | 
| -  video_stream_ = NULL; | 
| -  // TODO(xhwang): Figure out if we need to Reset the DDSs after Seeking or | 
| -  // before destroying them. | 
| -  audio_decrypting_demuxer_stream_.reset(); | 
| -  video_decrypting_demuxer_stream_.reset(); | 
| - | 
| -  media_weak_factory_.InvalidateWeakPtrs(); | 
| -  DCHECK(!media_weak_factory_.HasWeakPtrs()); | 
| - | 
| -  chunk_demuxer_->Stop(); | 
| -  chunk_demuxer_.reset(); | 
| - | 
| -  // |this| may be destroyed at this point in time as a result of running | 
| -  // |stop_cb|. | 
| -  stop_cb.Run(); | 
| -} | 
| - | 
| -void MediaSourceDelegate::InitializeMediaSource( | 
| -    const MediaSourceOpenedCB& media_source_opened_cb, | 
| -    const media::Demuxer::EncryptedMediaInitDataCB& | 
| -        encrypted_media_init_data_cb, | 
| -    const SetCdmReadyCB& set_cdm_ready_cb, | 
| -    const UpdateNetworkStateCB& update_network_state_cb, | 
| -    const DurationChangeCB& duration_change_cb, | 
| -    const base::Closure& waiting_for_decryption_key_cb) { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  DCHECK(!media_source_opened_cb.is_null()); | 
| -  DCHECK(!encrypted_media_init_data_cb.is_null()); | 
| -  DCHECK(!set_cdm_ready_cb.is_null()); | 
| -  DCHECK(!update_network_state_cb.is_null()); | 
| -  DCHECK(!duration_change_cb.is_null()); | 
| -  DCHECK(!waiting_for_decryption_key_cb.is_null()); | 
| - | 
| -  media_source_opened_cb_ = media_source_opened_cb; | 
| -  encrypted_media_init_data_cb_ = encrypted_media_init_data_cb; | 
| -  set_cdm_ready_cb_ = media::BindToCurrentLoop(set_cdm_ready_cb); | 
| -  update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); | 
| -  duration_change_cb_ = duration_change_cb; | 
| -  waiting_for_decryption_key_cb_ = | 
| -      media::BindToCurrentLoop(waiting_for_decryption_key_cb); | 
| -  access_unit_size_ = kAccessUnitSizeForMediaSource; | 
| - | 
| -  chunk_demuxer_.reset(new media::ChunkDemuxer( | 
| -      media::BindToCurrentLoop( | 
| -          base::Bind(&MediaSourceDelegate::OnDemuxerOpened, main_weak_this_)), | 
| -      media::BindToCurrentLoop(base::Bind( | 
| -          &MediaSourceDelegate::OnEncryptedMediaInitData, main_weak_this_)), | 
| -      media_log_, false)); | 
| - | 
| -  // |this| will be retained until StopDemuxer() is posted, so Unretained() is | 
| -  // safe here. | 
| -  media_task_runner_->PostTask(FROM_HERE, | 
| -                        base::Bind(&MediaSourceDelegate::InitializeDemuxer, | 
| -                        base::Unretained(this))); | 
| -} | 
| - | 
| -void MediaSourceDelegate::InitializeDemuxer() { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  demuxer_client_->AddDelegate(demuxer_client_id_, this); | 
| -  chunk_demuxer_->Initialize(this, | 
| -                             base::Bind(&MediaSourceDelegate::OnDemuxerInitDone, | 
| -                                        media_weak_factory_.GetWeakPtr()), | 
| -                             false); | 
| -} | 
| - | 
| -blink::WebTimeRanges MediaSourceDelegate::Buffered() const { | 
| -  return media::ConvertToWebTimeRanges(buffered_time_ranges_); | 
| -} | 
| - | 
| -size_t MediaSourceDelegate::DecodedFrameCount() const { | 
| -  return statistics_.video_frames_decoded; | 
| -} | 
| - | 
| -size_t MediaSourceDelegate::DroppedFrameCount() const { | 
| -  return statistics_.video_frames_dropped; | 
| -} | 
| - | 
| -size_t MediaSourceDelegate::AudioDecodedByteCount() const { | 
| -  return statistics_.audio_bytes_decoded; | 
| -} | 
| - | 
| -size_t MediaSourceDelegate::VideoDecodedByteCount() const { | 
| -  return statistics_.video_bytes_decoded; | 
| -} | 
| - | 
| -void MediaSourceDelegate::CancelPendingSeek(const base::TimeDelta& seek_time) { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : " | 
| -           << demuxer_client_id_; | 
| - | 
| -  if (!chunk_demuxer_) | 
| -    return; | 
| - | 
| -  { | 
| -    // Remember to trivially finish any newly arriving browser seek requests | 
| -    // that may arrive prior to the next regular seek request. | 
| -    base::AutoLock auto_lock(seeking_lock_); | 
| -    expecting_regular_seek_ = true; | 
| -  } | 
| - | 
| -  // Cancel any previously expected or in-progress regular or browser seek. | 
| -  // It is possible that we have just finished the seek, but caller does | 
| -  // not know this yet. It is still safe to cancel in this case because the | 
| -  // caller will always call StartWaitingForSeek() when it is notified of | 
| -  // the finished seek. | 
| -  chunk_demuxer_->CancelPendingSeek(seek_time); | 
| -} | 
| - | 
| -void MediaSourceDelegate::StartWaitingForSeek( | 
| -    const base::TimeDelta& seek_time) { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : " | 
| -           << demuxer_client_id_; | 
| - | 
| -  if (!chunk_demuxer_) | 
| -    return; | 
| - | 
| -  bool cancel_browser_seek = false; | 
| -  { | 
| -    // Remember to trivially finish any newly arriving browser seek requests | 
| -    // that may arrive prior to the next regular seek request. | 
| -    base::AutoLock auto_lock(seeking_lock_); | 
| -    expecting_regular_seek_ = true; | 
| - | 
| -    // Remember to cancel any in-progress browser seek. | 
| -    if (seeking_) { | 
| -      DCHECK(doing_browser_seek_); | 
| -      cancel_browser_seek = true; | 
| -    } | 
| -  } | 
| - | 
| -  if (cancel_browser_seek) | 
| -    chunk_demuxer_->CancelPendingSeek(seek_time); | 
| -  chunk_demuxer_->StartWaitingForSeek(seek_time); | 
| -} | 
| - | 
| -void MediaSourceDelegate::Seek( | 
| -    const base::TimeDelta& seek_time, bool is_browser_seek) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ", " | 
| -           << (is_browser_seek ? "browser seek" : "regular seek") << ") : " | 
| -           << demuxer_client_id_; | 
| - | 
| -  base::TimeDelta internal_seek_time = seek_time; | 
| -  { | 
| -    base::AutoLock auto_lock(seeking_lock_); | 
| -    DCHECK(!seeking_); | 
| -    seeking_ = true; | 
| -    doing_browser_seek_ = is_browser_seek; | 
| - | 
| -    if (doing_browser_seek_ && (!chunk_demuxer_ || expecting_regular_seek_)) { | 
| -      // Trivially finish the browser seek without actually doing it. Reads will | 
| -      // continue to be |kAborted| until the next regular seek is done. Browser | 
| -      // seeking is not supported unless using a ChunkDemuxer; browser seeks are | 
| -      // trivially finished if |chunk_demuxer_| is NULL. | 
| -      seeking_ = false; | 
| -      doing_browser_seek_ = false; | 
| -      demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time); | 
| -      return; | 
| -    } | 
| - | 
| -    if (doing_browser_seek_) { | 
| -      internal_seek_time = FindBufferedBrowserSeekTime_Locked(seek_time); | 
| -      browser_seek_time_ = internal_seek_time; | 
| -    } else { | 
| -      expecting_regular_seek_ = false; | 
| -      browser_seek_time_ = media::kNoTimestamp; | 
| -    } | 
| -  } | 
| - | 
| -  // Prepare |chunk_demuxer_| for browser seek. | 
| -  if (is_browser_seek) { | 
| -    chunk_demuxer_->CancelPendingSeek(internal_seek_time); | 
| -    chunk_demuxer_->StartWaitingForSeek(internal_seek_time); | 
| -  } | 
| - | 
| -  SeekInternal(internal_seek_time); | 
| -} | 
| - | 
| -void MediaSourceDelegate::SeekInternal(const base::TimeDelta& seek_time) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DCHECK(IsSeeking()); | 
| -  chunk_demuxer_->Seek(seek_time, base::Bind( | 
| -      &MediaSourceDelegate::OnDemuxerSeekDone, | 
| -      media_weak_factory_.GetWeakPtr())); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnBufferedTimeRangesChanged( | 
| -    const media::Ranges<base::TimeDelta>& ranges) { | 
| -  buffered_time_ranges_ = ranges; | 
| -} | 
| - | 
| -void MediaSourceDelegate::SetDuration(base::TimeDelta duration) { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << "(" << duration.InSecondsF() << ") : " | 
| -           << demuxer_client_id_; | 
| - | 
| -  // Force duration change notification to be async to avoid reentrancy into | 
| -  // ChunkDemxuer. | 
| -  main_task_runner_->PostTask(FROM_HERE, base::Bind( | 
| -      &MediaSourceDelegate::OnDurationChanged, main_weak_this_, duration)); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnDurationChanged(const base::TimeDelta& duration) { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  if (demuxer_client_) | 
| -    demuxer_client_->DurationChanged(demuxer_client_id_, duration); | 
| -  if (!duration_change_cb_.is_null()) | 
| -    duration_change_cb_.Run(duration); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << "(" << type << ") : " << demuxer_client_id_; | 
| -  if (IsSeeking()) | 
| -    return;  // Drop the request during seeking. | 
| - | 
| -  DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO); | 
| -  // The access unit size should have been initialized properly at this stage. | 
| -  DCHECK_GT(access_unit_size_, 0u); | 
| -  std::unique_ptr<DemuxerData> data(new DemuxerData()); | 
| -  data->type = type; | 
| -  data->access_units.resize(access_unit_size_); | 
| -  ReadFromDemuxerStream(type, std::move(data), 0); | 
| -} | 
| - | 
| -void MediaSourceDelegate::ReadFromDemuxerStream( | 
| -    media::DemuxerStream::Type type, | 
| -    std::unique_ptr<DemuxerData> data, | 
| -    size_t index) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  // DemuxerStream::Read() always returns the read callback asynchronously. | 
| -  DemuxerStream* stream = | 
| -      (type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_; | 
| -  stream->Read(base::Bind( | 
| -      &MediaSourceDelegate::OnBufferReady, | 
| -      media_weak_factory_.GetWeakPtr(), type, base::Passed(&data), index)); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnBufferReady( | 
| -    media::DemuxerStream::Type type, | 
| -    std::unique_ptr<DemuxerData> data, | 
| -    size_t index, | 
| -    DemuxerStream::Status status, | 
| -    const scoped_refptr<media::DecoderBuffer>& buffer) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << "(" << index << ", " << status << ", " | 
| -           << ((!buffer.get() || buffer->end_of_stream()) | 
| -                   ? -1 | 
| -                   : buffer->timestamp().InMilliseconds()) | 
| -           << ") : " << demuxer_client_id_; | 
| -  DCHECK(chunk_demuxer_); | 
| - | 
| -  // No new OnReadFromDemuxer() will be called during seeking. So this callback | 
| -  // must be from previous OnReadFromDemuxer() call and should be ignored. | 
| -  if (IsSeeking()) { | 
| -    DVLOG(1) << __FUNCTION__ << ": Ignore previous read during seeking."; | 
| -    return; | 
| -  } | 
| - | 
| -  bool is_audio = (type == DemuxerStream::AUDIO); | 
| -  if (status != DemuxerStream::kAborted && | 
| -      index >= data->access_units.size()) { | 
| -    LOG(ERROR) << "The internal state inconsistency onBufferReady: " | 
| -               << (is_audio ? "Audio" : "Video") << ", index " << index | 
| -               << ", size " << data->access_units.size() | 
| -               << ", status " << static_cast<int>(status); | 
| -    NOTREACHED(); | 
| -    return; | 
| -  } | 
| - | 
| -  switch (status) { | 
| -    case DemuxerStream::kAborted: | 
| -      DVLOG(1) << __FUNCTION__ << " : Aborted"; | 
| -      data->access_units[index].status = status; | 
| -      data->access_units.resize(index + 1); | 
| -      break; | 
| - | 
| -    case DemuxerStream::kConfigChanged: | 
| -      CHECK((is_audio && audio_stream_) || (!is_audio && video_stream_)); | 
| -      data->demuxer_configs.resize(1); | 
| -      CHECK(GetDemuxerConfigFromStream(&data->demuxer_configs[0], is_audio)); | 
| -      if (!is_audio) { | 
| -        gfx::Size size = data->demuxer_configs[0].video_size; | 
| -        DVLOG(1) << "Video config is changed: " << size.width() << "x" | 
| -                 << size.height(); | 
| -      } | 
| -      data->access_units[index].status = status; | 
| -      data->access_units.resize(index + 1); | 
| -      break; | 
| - | 
| -    case DemuxerStream::kOk: | 
| -      data->access_units[index].status = status; | 
| -      if (buffer->end_of_stream()) { | 
| -        data->access_units[index].is_end_of_stream = true; | 
| -        data->access_units.resize(index + 1); | 
| -        break; | 
| -      } | 
| -      data->access_units[index].is_key_frame = buffer->is_key_frame(); | 
| -      // TODO(ycheo): We assume that the inputed stream will be decoded | 
| -      // right away. | 
| -      // Need to implement this properly using MediaPlayer.OnInfoListener. | 
| -      if (is_audio) { | 
| -        statistics_.audio_bytes_decoded += buffer->data_size(); | 
| -      } else { | 
| -        statistics_.video_bytes_decoded += buffer->data_size(); | 
| -        statistics_.video_frames_decoded++; | 
| -      } | 
| -      data->access_units[index].timestamp = buffer->timestamp(); | 
| - | 
| -      data->access_units[index].data.assign( | 
| -          buffer->data(), buffer->data() + buffer->data_size()); | 
| -      // Vorbis needs 4 extra bytes padding on Android. Check | 
| -      // NuMediaExtractor.cpp in Android source code. | 
| -      if (is_audio && media::kCodecVorbis == | 
| -          audio_stream_->audio_decoder_config().codec()) { | 
| -        data->access_units[index].data.insert( | 
| -            data->access_units[index].data.end(), kVorbisPadding, | 
| -            kVorbisPadding + 4); | 
| -      } | 
| -      if (buffer->decrypt_config()) { | 
| -        data->access_units[index].key_id = std::vector<char>( | 
| -            buffer->decrypt_config()->key_id().begin(), | 
| -            buffer->decrypt_config()->key_id().end()); | 
| -        data->access_units[index].iv = std::vector<char>( | 
| -            buffer->decrypt_config()->iv().begin(), | 
| -            buffer->decrypt_config()->iv().end()); | 
| -        data->access_units[index].subsamples = | 
| -            buffer->decrypt_config()->subsamples(); | 
| -      } | 
| -      if (++index < data->access_units.size()) { | 
| -        ReadFromDemuxerStream(type, std::move(data), index); | 
| -        return; | 
| -      } | 
| -      break; | 
| - | 
| -    default: | 
| -      NOTREACHED(); | 
| -  } | 
| - | 
| -  if (!IsSeeking() && demuxer_client_) | 
| -    demuxer_client_->ReadFromDemuxerAck(demuxer_client_id_, *data); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) { | 
| -  DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; | 
| -  // |update_network_state_cb_| is bound to the main thread. | 
| -  if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null()) | 
| -    update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); | 
| -} | 
| - | 
| -void MediaSourceDelegate::AddTextStream( | 
| -    media::DemuxerStream* /* text_stream */ , | 
| -    const media::TextTrackConfig& /* config */ ) { | 
| -  // TODO(matthewjheaney): add text stream (http://crbug/322115). | 
| -  NOTIMPLEMENTED(); | 
| -} | 
| - | 
| -void MediaSourceDelegate::RemoveTextStream( | 
| -    media::DemuxerStream* /* text_stream */ ) { | 
| -  // TODO(matthewjheaney): remove text stream (http://crbug/322115). | 
| -  NOTIMPLEMENTED(); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; | 
| -  DCHECK(chunk_demuxer_); | 
| - | 
| -  if (status != media::PIPELINE_OK) { | 
| -    OnDemuxerError(status); | 
| -    return; | 
| -  } | 
| - | 
| -  audio_stream_ = chunk_demuxer_->GetStream(DemuxerStream::AUDIO); | 
| -  video_stream_ = chunk_demuxer_->GetStream(DemuxerStream::VIDEO); | 
| -  DCHECK(audio_stream_ || video_stream_); | 
| - | 
| -  if (HasEncryptedStream()) { | 
| -    set_cdm_ready_cb_.Run(BindToCurrentLoop(base::Bind( | 
| -        &MediaSourceDelegate::SetCdm, media_weak_factory_.GetWeakPtr()))); | 
| -    return; | 
| -  } | 
| - | 
| -  // Notify demuxer ready when both streams are not encrypted. | 
| -  NotifyDemuxerReady(false); | 
| -} | 
| - | 
| -bool MediaSourceDelegate::HasEncryptedStream() { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DCHECK(audio_stream_ || video_stream_); | 
| - | 
| -  return (audio_stream_ && | 
| -          audio_stream_->audio_decoder_config().is_encrypted()) || | 
| -         (video_stream_ && | 
| -          video_stream_->video_decoder_config().is_encrypted()); | 
| -} | 
| - | 
| -void MediaSourceDelegate::SetCdm(media::CdmContext* cdm_context, | 
| -                                 const media::CdmAttachedCB& cdm_attached_cb) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DCHECK(cdm_context); | 
| -  DCHECK(!cdm_attached_cb.is_null()); | 
| -  DCHECK(!is_demuxer_ready_); | 
| -  DCHECK(HasEncryptedStream()); | 
| - | 
| -  cdm_context_ = cdm_context; | 
| -  pending_cdm_attached_cb_ = cdm_attached_cb; | 
| - | 
| -  if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted()) { | 
| -    InitAudioDecryptingDemuxerStream(); | 
| -    // InitVideoDecryptingDemuxerStream() will be called in | 
| -    // OnAudioDecryptingDemuxerStreamInitDone(). | 
| -    return; | 
| -  } | 
| - | 
| -  if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) { | 
| -    InitVideoDecryptingDemuxerStream(); | 
| -    return; | 
| -  } | 
| - | 
| -  NOTREACHED() << "No encrytped stream."; | 
| -} | 
| - | 
| -void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; | 
| -  DCHECK(cdm_context_); | 
| -  audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( | 
| -      media_task_runner_, media_log_, waiting_for_decryption_key_cb_)); | 
| -  audio_decrypting_demuxer_stream_->Initialize( | 
| -      audio_stream_, cdm_context_, | 
| -      base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone, | 
| -                 media_weak_factory_.GetWeakPtr())); | 
| -} | 
| - | 
| -void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; | 
| -  DCHECK(cdm_context_); | 
| - | 
| -  video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( | 
| -      media_task_runner_, media_log_, waiting_for_decryption_key_cb_)); | 
| -  video_decrypting_demuxer_stream_->Initialize( | 
| -      video_stream_, cdm_context_, | 
| -      base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone, | 
| -                 media_weak_factory_.GetWeakPtr())); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone( | 
| -    media::PipelineStatus status) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; | 
| -  DCHECK(chunk_demuxer_); | 
| - | 
| -  if (status != media::PIPELINE_OK) { | 
| -    audio_decrypting_demuxer_stream_.reset(); | 
| -    // Different CDMs are supported differently. For CDMs that support a | 
| -    // Decryptor, we'll try to use DecryptingDemuxerStream in the render side. | 
| -    // Otherwise, we'll try to use the CDMs in the browser side. Therefore, if | 
| -    // DecryptingDemuxerStream initialization failed, it's still possible that | 
| -    // we can handle the audio with a CDM in the browser. Declare demuxer ready | 
| -    // now to try that path. Note there's no need to try DecryptingDemuxerStream | 
| -    // for video here since it is impossible to handle audio in the browser and | 
| -    // handle video in the render process. | 
| -    NotifyDemuxerReady(false); | 
| -    return; | 
| -  } | 
| - | 
| -  audio_stream_ = audio_decrypting_demuxer_stream_.get(); | 
| - | 
| -  if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) { | 
| -    InitVideoDecryptingDemuxerStream(); | 
| -    return; | 
| -  } | 
| - | 
| -  // Try to notify demuxer ready when audio DDS initialization finished and | 
| -  // video is not encrypted. | 
| -  NotifyDemuxerReady(true); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone( | 
| -    media::PipelineStatus status) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; | 
| -  DCHECK(chunk_demuxer_); | 
| - | 
| -  bool success = status == media::PIPELINE_OK; | 
| - | 
| -  if (!success) | 
| -    video_decrypting_demuxer_stream_.reset(); | 
| -  else | 
| -    video_stream_ = video_decrypting_demuxer_stream_.get(); | 
| - | 
| -  // Try to notify demuxer ready when video DDS initialization finished. | 
| -  NotifyDemuxerReady(success); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnDemuxerSeekDone(media::PipelineStatus status) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_; | 
| -  DCHECK(IsSeeking()); | 
| - | 
| -  if (status != media::PIPELINE_OK) { | 
| -    OnDemuxerError(status); | 
| -    return; | 
| -  } | 
| - | 
| -  ResetAudioDecryptingDemuxerStream(); | 
| -} | 
| - | 
| -void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; | 
| -  if (audio_decrypting_demuxer_stream_) { | 
| -    audio_decrypting_demuxer_stream_->Reset( | 
| -        base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream, | 
| -                   media_weak_factory_.GetWeakPtr())); | 
| -    return; | 
| -  } | 
| - | 
| -  ResetVideoDecryptingDemuxerStream(); | 
| -} | 
| - | 
| -void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; | 
| -  if (video_decrypting_demuxer_stream_) { | 
| -    video_decrypting_demuxer_stream_->Reset(base::Bind( | 
| -        &MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams, | 
| -        media_weak_factory_.GetWeakPtr())); | 
| -    return; | 
| -  } | 
| - | 
| -  FinishResettingDecryptingDemuxerStreams(); | 
| -} | 
| - | 
| -void MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams() { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_; | 
| - | 
| -  base::AutoLock auto_lock(seeking_lock_); | 
| -  DCHECK(seeking_); | 
| -  seeking_ = false; | 
| -  doing_browser_seek_ = false; | 
| -  demuxer_client_->DemuxerSeekDone(demuxer_client_id_, browser_seek_time_); | 
| -} | 
| - | 
| -void MediaSourceDelegate::NotifyDemuxerReady(bool is_cdm_attached) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_ | 
| -           << ", is_cdm_attached: " << is_cdm_attached; | 
| -  DCHECK(!is_demuxer_ready_); | 
| - | 
| -  is_demuxer_ready_ = true; | 
| - | 
| -  if (!pending_cdm_attached_cb_.is_null()) | 
| -    base::ResetAndReturn(&pending_cdm_attached_cb_).Run(is_cdm_attached); | 
| - | 
| -  std::unique_ptr<DemuxerConfigs> configs(new DemuxerConfigs()); | 
| -  GetDemuxerConfigFromStream(configs.get(), true); | 
| -  GetDemuxerConfigFromStream(configs.get(), false); | 
| -  configs->duration = GetDuration(); | 
| - | 
| -  if (demuxer_client_) | 
| -    demuxer_client_->DemuxerReady(demuxer_client_id_, *configs); | 
| - | 
| -  base::AutoLock auto_lock(is_video_encrypted_lock_); | 
| -  is_video_encrypted_ = configs->is_video_encrypted; | 
| -} | 
| - | 
| -base::TimeDelta MediaSourceDelegate::GetDuration() const { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  if (!chunk_demuxer_) | 
| -    return media::kNoTimestamp; | 
| - | 
| -  double duration = chunk_demuxer_->GetDuration(); | 
| -  if (duration == std::numeric_limits<double>::infinity()) | 
| -    return media::kInfiniteDuration; | 
| - | 
| -  return base::TimeDelta::FromSecondsD(duration); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnDemuxerOpened() { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  if (media_source_opened_cb_.is_null()) | 
| -    return; | 
| - | 
| -  media_source_opened_cb_.Run( | 
| -      new media::WebMediaSourceImpl(chunk_demuxer_.get(), media_log_)); | 
| -} | 
| - | 
| -void MediaSourceDelegate::OnEncryptedMediaInitData( | 
| -    media::EmeInitDataType init_data_type, | 
| -    const std::vector<uint8_t>& init_data) { | 
| -  DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| -  if (encrypted_media_init_data_cb_.is_null()) | 
| -    return; | 
| - | 
| -  encrypted_media_init_data_cb_.Run(init_data_type, init_data); | 
| -} | 
| - | 
| -bool MediaSourceDelegate::IsSeeking() const { | 
| -  base::AutoLock auto_lock(seeking_lock_); | 
| -  return seeking_; | 
| -} | 
| - | 
| -base::TimeDelta MediaSourceDelegate::FindBufferedBrowserSeekTime_Locked( | 
| -    const base::TimeDelta& seek_time) const { | 
| -  seeking_lock_.AssertAcquired(); | 
| -  DCHECK(seeking_); | 
| -  DCHECK(doing_browser_seek_); | 
| -  DCHECK(chunk_demuxer_) << "Browser seek requested, but no chunk demuxer"; | 
| - | 
| -  media::Ranges<base::TimeDelta> buffered = | 
| -      chunk_demuxer_->GetBufferedRanges(); | 
| - | 
| -  for (size_t i = 0; i < buffered.size(); ++i) { | 
| -    base::TimeDelta range_start = buffered.start(i); | 
| -    base::TimeDelta range_end = buffered.end(i); | 
| -    if (range_start <= seek_time) { | 
| -      if (range_end >= seek_time) | 
| -        return seek_time; | 
| -      continue; | 
| -    } | 
| - | 
| -    // If the start of the next buffered range after |seek_time| is too far | 
| -    // into the future, do not jump forward. | 
| -    if ((range_start - seek_time) > base::TimeDelta::FromMilliseconds(100)) | 
| -      break; | 
| - | 
| -    // TODO(wolenetz): Remove possibility that this browser seek jumps | 
| -    // into future when the requested range is unbuffered but there is some | 
| -    // other buffered range after it. See http://crbug.com/304234. | 
| -    return range_start; | 
| -  } | 
| - | 
| -  // We found no range containing |seek_time| or beginning shortly after | 
| -  // |seek_time|. While possible that such data at and beyond the player's | 
| -  // current time have been garbage collected or removed by the web app, this is | 
| -  // unlikely. This may cause unexpected playback stall due to seek pending an | 
| -  // append for a GOP prior to the last GOP demuxed. | 
| -  // TODO(wolenetz): Remove the possibility for this seek to cause unexpected | 
| -  // player stall by replaying cached data since last keyframe in browser player | 
| -  // rather than issuing browser seek. See http://crbug.com/304234. | 
| -  return seek_time; | 
| -} | 
| - | 
| -bool MediaSourceDelegate::GetDemuxerConfigFromStream( | 
| -    media::DemuxerConfigs* configs, bool is_audio) { | 
| -  DCHECK(media_task_runner_->BelongsToCurrentThread()); | 
| -  if (!is_demuxer_ready_) | 
| -    return false; | 
| -  if (is_audio && audio_stream_) { | 
| -    media::AudioDecoderConfig config = audio_stream_->audio_decoder_config(); | 
| -    configs->audio_codec = config.codec(); | 
| -    configs->audio_channels = | 
| -        media::ChannelLayoutToChannelCount(config.channel_layout()); | 
| -    configs->audio_sampling_rate = config.samples_per_second(); | 
| -    configs->is_audio_encrypted = config.is_encrypted(); | 
| -    configs->audio_extra_data = config.extra_data(); | 
| -    configs->audio_codec_delay_ns = static_cast<int64_t>( | 
| -        config.codec_delay()  * | 
| -        (static_cast<double>(base::Time::kNanosecondsPerSecond) / | 
| -         config.samples_per_second())); | 
| -    configs->audio_seek_preroll_ns = | 
| -        config.seek_preroll().InMicroseconds() * | 
| -        base::Time::kNanosecondsPerMicrosecond; | 
| -    return true; | 
| -  } | 
| -  if (!is_audio && video_stream_) { | 
| -    media::VideoDecoderConfig config = video_stream_->video_decoder_config(); | 
| -    configs->video_codec = config.codec(); | 
| -    configs->video_size = config.natural_size(); | 
| -    configs->is_video_encrypted = config.is_encrypted(); | 
| -    configs->video_extra_data = config.extra_data(); | 
| -    return true; | 
| -  } | 
| -  return false; | 
| -} | 
| - | 
| -}  // namespace content | 
|  |