Home | History | Annotate | Download | only in android
      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