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