media_source_delegate.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
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
25using media::DemuxerStream;
26using media::DemuxerConfigs;
27using media::DemuxerData;
28using blink::WebMediaPlayer;
29using blink::WebString;
30
31namespace {
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.
35const size_t kAccessUnitSizeForMediaSource = 4;
36
37const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff };
38
39}  // namespace
40
41namespace content {
42
43static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log,
44                                const std::string& error) {
45  media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
46}
47
48MediaSourceDelegate::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
73MediaSourceDelegate::~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
84void 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
111bool MediaSourceDelegate::IsVideoEncrypted() {
112  DCHECK(main_loop_->BelongsToCurrentThread());
113  base::AutoLock auto_lock(is_video_encrypted_lock_);
114  return is_video_encrypted_;
115}
116
117void MediaSourceDelegate::StopDemuxer() {
118  DCHECK(media_loop_->BelongsToCurrentThread());
119  DCHECK(chunk_demuxer_);
120
121  demuxer_client_->RemoveDelegate(demuxer_client_id_);
122  demuxer_client_ = NULL;
123
124  audio_stream_ = NULL;
125  video_stream_ = NULL;
126  // TODO(xhwang): Figure out if we need to Reset the DDSs after Seeking or
127  // before destroying them.
128  audio_decrypting_demuxer_stream_.reset();
129  video_decrypting_demuxer_stream_.reset();
130
131  media_weak_factory_.InvalidateWeakPtrs();
132  DCHECK(!media_weak_factory_.HasWeakPtrs());
133
134  // The callback OnDemuxerStopDone() owns |this| and will delete it when
135  // called. Hence using base::Unretained(this) is safe here.
136  chunk_demuxer_->Stop(base::Bind(&MediaSourceDelegate::OnDemuxerStopDone,
137                                  base::Unretained(this)));
138}
139
140void 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
162  // |this| will be retained until StopDemuxer() is posted, so Unretained() is
163  // safe here.
164  media_loop_->PostTask(FROM_HERE,
165                        base::Bind(&MediaSourceDelegate::InitializeDemuxer,
166                        base::Unretained(this)));
167}
168
169void MediaSourceDelegate::InitializeDemuxer() {
170  DCHECK(media_loop_->BelongsToCurrentThread());
171  demuxer_client_->AddDelegate(demuxer_client_id_, this);
172  chunk_demuxer_->Initialize(this,
173                             base::Bind(&MediaSourceDelegate::OnDemuxerInitDone,
174                                        media_weak_factory_.GetWeakPtr()),
175                             false);
176}
177
178const blink::WebTimeRanges& MediaSourceDelegate::Buffered() {
179  buffered_web_time_ranges_ =
180      ConvertToWebTimeRanges(buffered_time_ranges_);
181  return buffered_web_time_ranges_;
182}
183
184size_t MediaSourceDelegate::DecodedFrameCount() const {
185  return statistics_.video_frames_decoded;
186}
187
188size_t MediaSourceDelegate::DroppedFrameCount() const {
189  return statistics_.video_frames_dropped;
190}
191
192size_t MediaSourceDelegate::AudioDecodedByteCount() const {
193  return statistics_.audio_bytes_decoded;
194}
195
196size_t MediaSourceDelegate::VideoDecodedByteCount() const {
197  return statistics_.video_bytes_decoded;
198}
199
200void MediaSourceDelegate::CancelPendingSeek(const base::TimeDelta& seek_time) {
201  DCHECK(main_loop_->BelongsToCurrentThread());
202  DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
203           << demuxer_client_id_;
204
205  if (!chunk_demuxer_)
206    return;
207
208  {
209    // Remember to trivially finish any newly arriving browser seek requests
210    // that may arrive prior to the next regular seek request.
211    base::AutoLock auto_lock(seeking_lock_);
212    expecting_regular_seek_ = true;
213  }
214
215  // Cancel any previously expected or in-progress regular or browser seek.
216  // It is possible that we have just finished the seek, but caller does
217  // not know this yet. It is still safe to cancel in this case because the
218  // caller will always call StartWaitingForSeek() when it is notified of
219  // the finished seek.
220  chunk_demuxer_->CancelPendingSeek(seek_time);
221}
222
223void MediaSourceDelegate::StartWaitingForSeek(
224    const base::TimeDelta& seek_time) {
225  DCHECK(main_loop_->BelongsToCurrentThread());
226  DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
227           << demuxer_client_id_;
228
229  if (!chunk_demuxer_)
230    return;
231
232  bool cancel_browser_seek = false;
233  {
234    // Remember to trivially finish any newly arriving browser seek requests
235    // that may arrive prior to the next regular seek request.
236    base::AutoLock auto_lock(seeking_lock_);
237    expecting_regular_seek_ = true;
238
239    // Remember to cancel any in-progress browser seek.
240    if (seeking_) {
241      DCHECK(doing_browser_seek_);
242      cancel_browser_seek = true;
243    }
244  }
245
246  if (cancel_browser_seek)
247    chunk_demuxer_->CancelPendingSeek(seek_time);
248  chunk_demuxer_->StartWaitingForSeek(seek_time);
249}
250
251void MediaSourceDelegate::Seek(
252    const base::TimeDelta& seek_time, bool is_browser_seek) {
253  DCHECK(media_loop_->BelongsToCurrentThread());
254  DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ", "
255           << (is_browser_seek ? "browser seek" : "regular seek") << ") : "
256           << demuxer_client_id_;
257
258  base::TimeDelta internal_seek_time = seek_time;
259  {
260    base::AutoLock auto_lock(seeking_lock_);
261    DCHECK(!seeking_);
262    seeking_ = true;
263    doing_browser_seek_ = is_browser_seek;
264
265    if (doing_browser_seek_ && (!chunk_demuxer_ || expecting_regular_seek_)) {
266      // Trivially finish the browser seek without actually doing it. Reads will
267      // continue to be |kAborted| until the next regular seek is done. Browser
268      // seeking is not supported unless using a ChunkDemuxer; browser seeks are
269      // trivially finished if |chunk_demuxer_| is NULL.
270      seeking_ = false;
271      doing_browser_seek_ = false;
272      demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time);
273      return;
274    }
275
276    if (doing_browser_seek_) {
277      internal_seek_time = FindBufferedBrowserSeekTime_Locked(seek_time);
278      browser_seek_time_ = internal_seek_time;
279    } else {
280      expecting_regular_seek_ = false;
281      browser_seek_time_ = media::kNoTimestamp();
282    }
283  }
284
285  // Prepare |chunk_demuxer_| for browser seek.
286  if (is_browser_seek) {
287    chunk_demuxer_->CancelPendingSeek(internal_seek_time);
288    chunk_demuxer_->StartWaitingForSeek(internal_seek_time);
289  }
290
291  SeekInternal(internal_seek_time);
292}
293
294void MediaSourceDelegate::SeekInternal(const base::TimeDelta& seek_time) {
295  DCHECK(media_loop_->BelongsToCurrentThread());
296  DCHECK(IsSeeking());
297  chunk_demuxer_->Seek(seek_time, base::Bind(
298      &MediaSourceDelegate::OnDemuxerSeekDone,
299      media_weak_factory_.GetWeakPtr()));
300}
301
302void MediaSourceDelegate::SetTotalBytes(int64 total_bytes) {
303  NOTIMPLEMENTED();
304}
305
306void MediaSourceDelegate::AddBufferedByteRange(int64 start, int64 end) {
307  NOTIMPLEMENTED();
308}
309
310void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start,
311                                               base::TimeDelta end) {
312  buffered_time_ranges_.Add(start, end);
313}
314
315void MediaSourceDelegate::SetDuration(base::TimeDelta duration) {
316  DCHECK(main_loop_->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_loop_->PostTask(FROM_HERE, base::Bind(
323      &MediaSourceDelegate::OnDurationChanged, main_weak_this_, duration));
324}
325
326void MediaSourceDelegate::OnDurationChanged(const base::TimeDelta& duration) {
327  DCHECK(main_loop_->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
334void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) {
335  DCHECK(media_loop_->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
349void MediaSourceDelegate::ReadFromDemuxerStream(media::DemuxerStream::Type type,
350                                                scoped_ptr<DemuxerData> data,
351                                                size_t index) {
352  DCHECK(media_loop_->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
361void 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_loop_->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      // In case of kConfigChanged, need to read decoder_config once
401      // for the next reads.
402      // TODO(kjyoun): Investigate if we need to use this new config. See
403      // http://crbug.com/255783
404      if (is_audio) {
405        audio_stream_->audio_decoder_config();
406      } else {
407        gfx::Size size = video_stream_->video_decoder_config().coded_size();
408        DVLOG(1) << "Video config is changed: " << size.width() << "x"
409                 << size.height();
410      }
411      data->access_units[index].status = status;
412      data->access_units.resize(index + 1);
413      break;
414
415    case DemuxerStream::kOk:
416      data->access_units[index].status = status;
417      if (buffer->end_of_stream()) {
418        data->access_units[index].end_of_stream = true;
419        data->access_units.resize(index + 1);
420        break;
421      }
422      // TODO(ycheo): We assume that the inputed stream will be decoded
423      // right away.
424      // Need to implement this properly using MediaPlayer.OnInfoListener.
425      if (is_audio) {
426        statistics_.audio_bytes_decoded += buffer->data_size();
427      } else {
428        statistics_.video_bytes_decoded += buffer->data_size();
429        statistics_.video_frames_decoded++;
430      }
431      data->access_units[index].timestamp = buffer->timestamp();
432
433      data->access_units[index].data.assign(
434          buffer->data(), buffer->data() + buffer->data_size());
435      // Vorbis needs 4 extra bytes padding on Android. Check
436      // NuMediaExtractor.cpp in Android source code.
437      if (is_audio && media::kCodecVorbis ==
438          audio_stream_->audio_decoder_config().codec()) {
439        data->access_units[index].data.insert(
440            data->access_units[index].data.end(), kVorbisPadding,
441            kVorbisPadding + 4);
442      }
443      if (buffer->decrypt_config()) {
444        data->access_units[index].key_id = std::vector<char>(
445            buffer->decrypt_config()->key_id().begin(),
446            buffer->decrypt_config()->key_id().end());
447        data->access_units[index].iv = std::vector<char>(
448            buffer->decrypt_config()->iv().begin(),
449            buffer->decrypt_config()->iv().end());
450        data->access_units[index].subsamples =
451            buffer->decrypt_config()->subsamples();
452      }
453      if (++index < data->access_units.size()) {
454        ReadFromDemuxerStream(type, data.Pass(), index);
455        return;
456      }
457      break;
458
459    default:
460      NOTREACHED();
461  }
462
463  if (!IsSeeking() && demuxer_client_)
464    demuxer_client_->ReadFromDemuxerAck(demuxer_client_id_, *data);
465}
466
467void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) {
468  DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
469  // |update_network_state_cb_| is bound to the main thread.
470  if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null())
471    update_network_state_cb_.Run(PipelineErrorToNetworkState(status));
472}
473
474void MediaSourceDelegate::AddTextStream(
475    media::DemuxerStream* /* text_stream */ ,
476    const media::TextTrackConfig& /* config */ ) {
477  // TODO(matthewjheaney): add text stream (http://crbug/322115).
478  NOTIMPLEMENTED();
479}
480
481void MediaSourceDelegate::RemoveTextStream(
482    media::DemuxerStream* /* text_stream */ ) {
483  // TODO(matthewjheaney): remove text stream (http://crbug/322115).
484  NOTIMPLEMENTED();
485}
486
487void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) {
488  DCHECK(media_loop_->BelongsToCurrentThread());
489  DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
490  DCHECK(chunk_demuxer_);
491
492  if (status != media::PIPELINE_OK) {
493    OnDemuxerError(status);
494    return;
495  }
496
497  audio_stream_ = chunk_demuxer_->GetStream(DemuxerStream::AUDIO);
498  video_stream_ = chunk_demuxer_->GetStream(DemuxerStream::VIDEO);
499
500  if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() &&
501      !set_decryptor_ready_cb_.is_null()) {
502    InitAudioDecryptingDemuxerStream();
503    // InitVideoDecryptingDemuxerStream() will be called in
504    // OnAudioDecryptingDemuxerStreamInitDone().
505    return;
506  }
507
508  if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() &&
509      !set_decryptor_ready_cb_.is_null()) {
510    InitVideoDecryptingDemuxerStream();
511    return;
512  }
513
514  // Notify demuxer ready when both streams are not encrypted.
515  is_demuxer_ready_ = true;
516  if (CanNotifyDemuxerReady())
517    NotifyDemuxerReady();
518}
519
520void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() {
521  DCHECK(media_loop_->BelongsToCurrentThread());
522  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
523  DCHECK(!set_decryptor_ready_cb_.is_null());
524
525  audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
526      media_loop_, set_decryptor_ready_cb_));
527  audio_decrypting_demuxer_stream_->Initialize(
528      audio_stream_,
529      base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone,
530                 media_weak_factory_.GetWeakPtr()));
531}
532
533void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() {
534  DCHECK(media_loop_->BelongsToCurrentThread());
535  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
536  DCHECK(!set_decryptor_ready_cb_.is_null());
537
538  video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
539      media_loop_, set_decryptor_ready_cb_));
540  video_decrypting_demuxer_stream_->Initialize(
541      video_stream_,
542      base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone,
543                 media_weak_factory_.GetWeakPtr()));
544}
545
546void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone(
547    media::PipelineStatus status) {
548  DCHECK(media_loop_->BelongsToCurrentThread());
549  DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
550  DCHECK(chunk_demuxer_);
551
552  if (status != media::PIPELINE_OK)
553    audio_decrypting_demuxer_stream_.reset();
554  else
555    audio_stream_ = audio_decrypting_demuxer_stream_.get();
556
557  if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) {
558    InitVideoDecryptingDemuxerStream();
559    return;
560  }
561
562  // Try to notify demuxer ready when audio DDS initialization finished and
563  // video is not encrypted.
564  is_demuxer_ready_ = true;
565  if (CanNotifyDemuxerReady())
566    NotifyDemuxerReady();
567}
568
569void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone(
570    media::PipelineStatus status) {
571  DCHECK(media_loop_->BelongsToCurrentThread());
572  DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
573  DCHECK(chunk_demuxer_);
574
575  if (status != media::PIPELINE_OK)
576    video_decrypting_demuxer_stream_.reset();
577  else
578    video_stream_ = video_decrypting_demuxer_stream_.get();
579
580  // Try to notify demuxer ready when video DDS initialization finished.
581  is_demuxer_ready_ = true;
582  if (CanNotifyDemuxerReady())
583    NotifyDemuxerReady();
584}
585
586void MediaSourceDelegate::OnDemuxerSeekDone(media::PipelineStatus status) {
587  DCHECK(media_loop_->BelongsToCurrentThread());
588  DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
589  DCHECK(IsSeeking());
590
591  if (status != media::PIPELINE_OK) {
592    OnDemuxerError(status);
593    return;
594  }
595
596  ResetAudioDecryptingDemuxerStream();
597}
598
599void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() {
600  DCHECK(media_loop_->BelongsToCurrentThread());
601  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
602  if (audio_decrypting_demuxer_stream_) {
603    audio_decrypting_demuxer_stream_->Reset(
604        base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream,
605                   media_weak_factory_.GetWeakPtr()));
606    return;
607  }
608
609  ResetVideoDecryptingDemuxerStream();
610}
611
612void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() {
613  DCHECK(media_loop_->BelongsToCurrentThread());
614  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
615  if (video_decrypting_demuxer_stream_) {
616    video_decrypting_demuxer_stream_->Reset(base::Bind(
617        &MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams,
618        media_weak_factory_.GetWeakPtr()));
619    return;
620  }
621
622  FinishResettingDecryptingDemuxerStreams();
623}
624
625void MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams() {
626  DCHECK(media_loop_->BelongsToCurrentThread());
627  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
628
629  base::AutoLock auto_lock(seeking_lock_);
630  DCHECK(seeking_);
631  seeking_ = false;
632  doing_browser_seek_ = false;
633  demuxer_client_->DemuxerSeekDone(demuxer_client_id_, browser_seek_time_);
634}
635
636void MediaSourceDelegate::OnDemuxerStopDone() {
637  DCHECK(media_loop_->BelongsToCurrentThread());
638  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
639  main_loop_->PostTask(
640      FROM_HERE,
641      base::Bind(&MediaSourceDelegate::DeleteSelf, base::Unretained(this)));
642}
643
644void MediaSourceDelegate::DeleteSelf() {
645  DCHECK(main_loop_->BelongsToCurrentThread());
646  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
647  chunk_demuxer_.reset();
648  delete this;
649}
650
651void MediaSourceDelegate::OnMediaConfigRequest() {
652  DCHECK(media_loop_->BelongsToCurrentThread());
653  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
654  if (CanNotifyDemuxerReady())
655    NotifyDemuxerReady();
656}
657
658bool MediaSourceDelegate::CanNotifyDemuxerReady() {
659  DCHECK(media_loop_->BelongsToCurrentThread());
660  return is_demuxer_ready_;
661}
662
663void MediaSourceDelegate::NotifyDemuxerReady() {
664  DCHECK(media_loop_->BelongsToCurrentThread());
665  DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
666  DCHECK(CanNotifyDemuxerReady());
667
668  scoped_ptr<DemuxerConfigs> configs(new DemuxerConfigs());
669  if (audio_stream_) {
670    media::AudioDecoderConfig config = audio_stream_->audio_decoder_config();
671    configs->audio_codec = config.codec();
672    configs->audio_channels =
673        media::ChannelLayoutToChannelCount(config.channel_layout());
674    configs->audio_sampling_rate = config.samples_per_second();
675    configs->is_audio_encrypted = config.is_encrypted();
676    configs->audio_extra_data = std::vector<uint8>(
677        config.extra_data(), config.extra_data() + config.extra_data_size());
678  }
679  if (video_stream_) {
680    media::VideoDecoderConfig config = video_stream_->video_decoder_config();
681    configs->video_codec = config.codec();
682    configs->video_size = config.natural_size();
683    configs->is_video_encrypted = config.is_encrypted();
684    configs->video_extra_data = std::vector<uint8>(
685        config.extra_data(), config.extra_data() + config.extra_data_size());
686  }
687  configs->duration_ms = GetDurationMs();
688
689  if (demuxer_client_)
690    demuxer_client_->DemuxerReady(demuxer_client_id_, *configs);
691
692  base::AutoLock auto_lock(is_video_encrypted_lock_);
693  is_video_encrypted_ = configs->is_video_encrypted;
694}
695
696int MediaSourceDelegate::GetDurationMs() {
697  DCHECK(media_loop_->BelongsToCurrentThread());
698  if (!chunk_demuxer_)
699    return -1;
700
701  double duration_ms = chunk_demuxer_->GetDuration() * 1000;
702  if (duration_ms > std::numeric_limits<int32>::max()) {
703    LOG(WARNING) << "Duration from ChunkDemuxer is too large; probably "
704                    "something has gone wrong.";
705    return std::numeric_limits<int32>::max();
706  }
707  return duration_ms;
708}
709
710void MediaSourceDelegate::OnDemuxerOpened() {
711  DCHECK(main_loop_->BelongsToCurrentThread());
712  if (media_source_opened_cb_.is_null())
713    return;
714
715  media_source_opened_cb_.Run(new WebMediaSourceImpl(
716      chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
717}
718
719void MediaSourceDelegate::OnNeedKey(const std::string& type,
720                                    const std::vector<uint8>& init_data) {
721  DCHECK(main_loop_->BelongsToCurrentThread());
722  if (need_key_cb_.is_null())
723    return;
724
725  need_key_cb_.Run(type, init_data);
726}
727
728bool MediaSourceDelegate::IsSeeking() const {
729  base::AutoLock auto_lock(seeking_lock_);
730  return seeking_;
731}
732
733base::TimeDelta MediaSourceDelegate::FindBufferedBrowserSeekTime_Locked(
734    const base::TimeDelta& seek_time) const {
735  seeking_lock_.AssertAcquired();
736  DCHECK(seeking_);
737  DCHECK(doing_browser_seek_);
738  DCHECK(chunk_demuxer_) << "Browser seek requested, but no chunk demuxer";
739
740  media::Ranges<base::TimeDelta> buffered =
741      chunk_demuxer_->GetBufferedRanges();
742
743  for (size_t i = 0; i < buffered.size(); ++i) {
744    base::TimeDelta range_start = buffered.start(i);
745    base::TimeDelta range_end = buffered.end(i);
746    if (range_start <= seek_time) {
747      if (range_end >= seek_time)
748        return seek_time;
749      continue;
750    }
751
752    // If the start of the next buffered range after |seek_time| is too far
753    // into the future, do not jump forward.
754    if ((range_start - seek_time) > base::TimeDelta::FromMilliseconds(100))
755      break;
756
757    // TODO(wolenetz): Remove possibility that this browser seek jumps
758    // into future when the requested range is unbuffered but there is some
759    // other buffered range after it. See http://crbug.com/304234.
760    return range_start;
761  }
762
763  // We found no range containing |seek_time| or beginning shortly after
764  // |seek_time|. While possible that such data at and beyond the player's
765  // current time have been garbage collected or removed by the web app, this is
766  // unlikely. This may cause unexpected playback stall due to seek pending an
767  // append for a GOP prior to the last GOP demuxed.
768  // TODO(wolenetz): Remove the possibility for this seek to cause unexpected
769  // player stall by replaying cached data since last keyframe in browser player
770  // rather than issuing browser seek. See http://crbug.com/304234.
771  return seek_time;
772}
773
774}  // namespace content
775