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
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::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
73MediaSourceDelegate::~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
84void 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
109bool MediaSourceDelegate::IsVideoEncrypted() {
110  DCHECK(main_task_runner_->BelongsToCurrentThread());
111  base::AutoLock auto_lock(is_video_encrypted_lock_);
112  return is_video_encrypted_;
113}
114
115base::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
123void 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
149void 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
179void 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
188blink::WebTimeRanges MediaSourceDelegate::Buffered() const {
189  return media::ConvertToWebTimeRanges(buffered_time_ranges_);
190}
191
192size_t MediaSourceDelegate::DecodedFrameCount() const {
193  return statistics_.video_frames_decoded;
194}
195
196size_t MediaSourceDelegate::DroppedFrameCount() const {
197  return statistics_.video_frames_dropped;
198}
199
200size_t MediaSourceDelegate::AudioDecodedByteCount() const {
201  return statistics_.audio_bytes_decoded;
202}
203
204size_t MediaSourceDelegate::VideoDecodedByteCount() const {
205  return statistics_.video_bytes_decoded;
206}
207
208void 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
231void 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
259void 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
302void 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
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_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
326void 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
334void 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
349void 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
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_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
464void 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
471void 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
478void MediaSourceDelegate::RemoveTextStream(
479    media::DemuxerStream* /* text_stream */ ) {
480  // TODO(matthewjheaney): remove text stream (http://crbug/322115).
481  NOTIMPLEMENTED();
482}
483
484void 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
516void 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
529void 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
542void 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
564void 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
580void 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
593void 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
606void 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
619void 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
630void 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
647base::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
659void 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
668void 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
677bool MediaSourceDelegate::IsSeeking() const {
678  base::AutoLock auto_lock(seeking_lock_);
679  return seeking_;
680}
681
682base::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
723bool 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