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