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