Update To 11.40.268.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 "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.get() || buffer->end_of_stream())
370                    ? -1
371                    : 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       CHECK((is_audio && audio_stream_) || (!is_audio && video_stream_));
402       data->demuxer_configs.resize(1);
403       CHECK(GetDemuxerConfigFromStream(&data->demuxer_configs[0], is_audio));
404       if (!is_audio) {
405         gfx::Size size = data->demuxer_configs[0].video_size;
406         DVLOG(1) << "Video config is changed: " << size.width() << "x"
407                  << size.height();
408       }
409       data->access_units[index].status = status;
410       data->access_units.resize(index + 1);
411       break;
412
413     case DemuxerStream::kOk:
414       data->access_units[index].status = status;
415       if (buffer->end_of_stream()) {
416         data->access_units[index].end_of_stream = true;
417         data->access_units.resize(index + 1);
418         break;
419       }
420       // TODO(ycheo): We assume that the inputed stream will be decoded
421       // right away.
422       // Need to implement this properly using MediaPlayer.OnInfoListener.
423       if (is_audio) {
424         statistics_.audio_bytes_decoded += buffer->data_size();
425       } else {
426         statistics_.video_bytes_decoded += buffer->data_size();
427         statistics_.video_frames_decoded++;
428       }
429       data->access_units[index].timestamp = buffer->timestamp();
430
431       data->access_units[index].data.assign(
432           buffer->data(), buffer->data() + buffer->data_size());
433       // Vorbis needs 4 extra bytes padding on Android. Check
434       // NuMediaExtractor.cpp in Android source code.
435       if (is_audio && media::kCodecVorbis ==
436           audio_stream_->audio_decoder_config().codec()) {
437         data->access_units[index].data.insert(
438             data->access_units[index].data.end(), kVorbisPadding,
439             kVorbisPadding + 4);
440       }
441       if (buffer->decrypt_config()) {
442         data->access_units[index].key_id = std::vector<char>(
443             buffer->decrypt_config()->key_id().begin(),
444             buffer->decrypt_config()->key_id().end());
445         data->access_units[index].iv = std::vector<char>(
446             buffer->decrypt_config()->iv().begin(),
447             buffer->decrypt_config()->iv().end());
448         data->access_units[index].subsamples =
449             buffer->decrypt_config()->subsamples();
450       }
451       if (++index < data->access_units.size()) {
452         ReadFromDemuxerStream(type, data.Pass(), index);
453         return;
454       }
455       break;
456
457     default:
458       NOTREACHED();
459   }
460
461   if (!IsSeeking() && demuxer_client_)
462     demuxer_client_->ReadFromDemuxerAck(demuxer_client_id_, *data);
463 }
464
465 void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) {
466   DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
467   // |update_network_state_cb_| is bound to the main thread.
468   if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null())
469     update_network_state_cb_.Run(PipelineErrorToNetworkState(status));
470 }
471
472 void MediaSourceDelegate::AddTextStream(
473     media::DemuxerStream* /* text_stream */ ,
474     const media::TextTrackConfig& /* config */ ) {
475   // TODO(matthewjheaney): add text stream (http://crbug/322115).
476   NOTIMPLEMENTED();
477 }
478
479 void MediaSourceDelegate::RemoveTextStream(
480     media::DemuxerStream* /* text_stream */ ) {
481   // TODO(matthewjheaney): remove text stream (http://crbug/322115).
482   NOTIMPLEMENTED();
483 }
484
485 void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) {
486   DCHECK(media_task_runner_->BelongsToCurrentThread());
487   DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
488   DCHECK(chunk_demuxer_);
489
490   if (status != media::PIPELINE_OK) {
491     OnDemuxerError(status);
492     return;
493   }
494
495   audio_stream_ = chunk_demuxer_->GetStream(DemuxerStream::AUDIO);
496   video_stream_ = chunk_demuxer_->GetStream(DemuxerStream::VIDEO);
497
498   if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() &&
499       !set_decryptor_ready_cb_.is_null()) {
500     InitAudioDecryptingDemuxerStream();
501     // InitVideoDecryptingDemuxerStream() will be called in
502     // OnAudioDecryptingDemuxerStreamInitDone().
503     return;
504   }
505
506   if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() &&
507       !set_decryptor_ready_cb_.is_null()) {
508     InitVideoDecryptingDemuxerStream();
509     return;
510   }
511
512   // Notify demuxer ready when both streams are not encrypted.
513   is_demuxer_ready_ = true;
514   NotifyDemuxerReady();
515 }
516
517 void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() {
518   DCHECK(media_task_runner_->BelongsToCurrentThread());
519   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
520   DCHECK(!set_decryptor_ready_cb_.is_null());
521
522   audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
523       media_task_runner_, set_decryptor_ready_cb_));
524   audio_decrypting_demuxer_stream_->Initialize(
525       audio_stream_,
526       base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone,
527                  media_weak_factory_.GetWeakPtr()));
528 }
529
530 void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() {
531   DCHECK(media_task_runner_->BelongsToCurrentThread());
532   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
533   DCHECK(!set_decryptor_ready_cb_.is_null());
534
535   video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
536       media_task_runner_, set_decryptor_ready_cb_));
537   video_decrypting_demuxer_stream_->Initialize(
538       video_stream_,
539       base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone,
540                  media_weak_factory_.GetWeakPtr()));
541 }
542
543 void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone(
544     media::PipelineStatus status) {
545   DCHECK(media_task_runner_->BelongsToCurrentThread());
546   DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
547   DCHECK(chunk_demuxer_);
548
549   if (status != media::PIPELINE_OK)
550     audio_decrypting_demuxer_stream_.reset();
551   else
552     audio_stream_ = audio_decrypting_demuxer_stream_.get();
553
554   if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) {
555     InitVideoDecryptingDemuxerStream();
556     return;
557   }
558
559   // Try to notify demuxer ready when audio DDS initialization finished and
560   // video is not encrypted.
561   is_demuxer_ready_ = true;
562   NotifyDemuxerReady();
563 }
564
565 void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone(
566     media::PipelineStatus status) {
567   DCHECK(media_task_runner_->BelongsToCurrentThread());
568   DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
569   DCHECK(chunk_demuxer_);
570
571   if (status != media::PIPELINE_OK)
572     video_decrypting_demuxer_stream_.reset();
573   else
574     video_stream_ = video_decrypting_demuxer_stream_.get();
575
576   // Try to notify demuxer ready when video DDS initialization finished.
577   is_demuxer_ready_ = true;
578   NotifyDemuxerReady();
579 }
580
581 void MediaSourceDelegate::OnDemuxerSeekDone(media::PipelineStatus status) {
582   DCHECK(media_task_runner_->BelongsToCurrentThread());
583   DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
584   DCHECK(IsSeeking());
585
586   if (status != media::PIPELINE_OK) {
587     OnDemuxerError(status);
588     return;
589   }
590
591   ResetAudioDecryptingDemuxerStream();
592 }
593
594 void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() {
595   DCHECK(media_task_runner_->BelongsToCurrentThread());
596   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
597   if (audio_decrypting_demuxer_stream_) {
598     audio_decrypting_demuxer_stream_->Reset(
599         base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream,
600                    media_weak_factory_.GetWeakPtr()));
601     return;
602   }
603
604   ResetVideoDecryptingDemuxerStream();
605 }
606
607 void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() {
608   DCHECK(media_task_runner_->BelongsToCurrentThread());
609   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
610   if (video_decrypting_demuxer_stream_) {
611     video_decrypting_demuxer_stream_->Reset(base::Bind(
612         &MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams,
613         media_weak_factory_.GetWeakPtr()));
614     return;
615   }
616
617   FinishResettingDecryptingDemuxerStreams();
618 }
619
620 void MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams() {
621   DCHECK(media_task_runner_->BelongsToCurrentThread());
622   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
623
624   base::AutoLock auto_lock(seeking_lock_);
625   DCHECK(seeking_);
626   seeking_ = false;
627   doing_browser_seek_ = false;
628   demuxer_client_->DemuxerSeekDone(demuxer_client_id_, browser_seek_time_);
629 }
630
631 void MediaSourceDelegate::NotifyDemuxerReady() {
632   DCHECK(media_task_runner_->BelongsToCurrentThread());
633   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
634   DCHECK(is_demuxer_ready_);
635
636   scoped_ptr<DemuxerConfigs> configs(new DemuxerConfigs());
637   GetDemuxerConfigFromStream(configs.get(), true);
638   GetDemuxerConfigFromStream(configs.get(), false);
639   configs->duration = GetDuration();
640
641   if (demuxer_client_)
642     demuxer_client_->DemuxerReady(demuxer_client_id_, *configs);
643
644   base::AutoLock auto_lock(is_video_encrypted_lock_);
645   is_video_encrypted_ = configs->is_video_encrypted;
646 }
647
648 base::TimeDelta MediaSourceDelegate::GetDuration() const {
649   DCHECK(media_task_runner_->BelongsToCurrentThread());
650   if (!chunk_demuxer_)
651     return media::kNoTimestamp();
652
653   double duration = chunk_demuxer_->GetDuration();
654   if (duration == std::numeric_limits<double>::infinity())
655     return media::kInfiniteDuration();
656
657   return media::ConvertSecondsToTimestamp(duration);
658 }
659
660 void MediaSourceDelegate::OnDemuxerOpened() {
661   DCHECK(main_task_runner_->BelongsToCurrentThread());
662   if (media_source_opened_cb_.is_null())
663     return;
664
665   media_source_opened_cb_.Run(new media::WebMediaSourceImpl(
666       chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
667 }
668
669 void MediaSourceDelegate::OnNeedKey(const std::string& type,
670                                     const std::vector<uint8>& init_data) {
671   DCHECK(main_task_runner_->BelongsToCurrentThread());
672   if (need_key_cb_.is_null())
673     return;
674
675   need_key_cb_.Run(type, init_data);
676 }
677
678 bool MediaSourceDelegate::IsSeeking() const {
679   base::AutoLock auto_lock(seeking_lock_);
680   return seeking_;
681 }
682
683 base::TimeDelta MediaSourceDelegate::FindBufferedBrowserSeekTime_Locked(
684     const base::TimeDelta& seek_time) const {
685   seeking_lock_.AssertAcquired();
686   DCHECK(seeking_);
687   DCHECK(doing_browser_seek_);
688   DCHECK(chunk_demuxer_) << "Browser seek requested, but no chunk demuxer";
689
690   media::Ranges<base::TimeDelta> buffered =
691       chunk_demuxer_->GetBufferedRanges();
692
693   for (size_t i = 0; i < buffered.size(); ++i) {
694     base::TimeDelta range_start = buffered.start(i);
695     base::TimeDelta range_end = buffered.end(i);
696     if (range_start <= seek_time) {
697       if (range_end >= seek_time)
698         return seek_time;
699       continue;
700     }
701
702     // If the start of the next buffered range after |seek_time| is too far
703     // into the future, do not jump forward.
704     if ((range_start - seek_time) > base::TimeDelta::FromMilliseconds(100))
705       break;
706
707     // TODO(wolenetz): Remove possibility that this browser seek jumps
708     // into future when the requested range is unbuffered but there is some
709     // other buffered range after it. See http://crbug.com/304234.
710     return range_start;
711   }
712
713   // We found no range containing |seek_time| or beginning shortly after
714   // |seek_time|. While possible that such data at and beyond the player's
715   // current time have been garbage collected or removed by the web app, this is
716   // unlikely. This may cause unexpected playback stall due to seek pending an
717   // append for a GOP prior to the last GOP demuxed.
718   // TODO(wolenetz): Remove the possibility for this seek to cause unexpected
719   // player stall by replaying cached data since last keyframe in browser player
720   // rather than issuing browser seek. See http://crbug.com/304234.
721   return seek_time;
722 }
723
724 bool MediaSourceDelegate::GetDemuxerConfigFromStream(
725     media::DemuxerConfigs* configs, bool is_audio) {
726   DCHECK(media_task_runner_->BelongsToCurrentThread());
727   if (!is_demuxer_ready_)
728     return false;
729   if (is_audio && audio_stream_) {
730     media::AudioDecoderConfig config = audio_stream_->audio_decoder_config();
731     configs->audio_codec = config.codec();
732     configs->audio_channels =
733         media::ChannelLayoutToChannelCount(config.channel_layout());
734     configs->audio_sampling_rate = config.samples_per_second();
735     configs->is_audio_encrypted = config.is_encrypted();
736     configs->audio_extra_data = std::vector<uint8>(
737         config.extra_data(), config.extra_data() + config.extra_data_size());
738     return true;
739   }
740   if (!is_audio && video_stream_) {
741     media::VideoDecoderConfig config = video_stream_->video_decoder_config();
742     configs->video_codec = config.codec();
743     configs->video_size = config.natural_size();
744     configs->is_video_encrypted = config.is_encrypted();
745     configs->video_extra_data = std::vector<uint8>(
746         config.extra_data(), config.extra_data() + config.extra_data_size());
747     return true;
748   }
749   return false;
750 }
751
752 }  // namespace content