Upstream version 5.34.92.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 // 16: approximately 250ms of content in 60 fps movies.
35 const size_t kAccessUnitSizeForMediaSource = 16;
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     : main_loop_(base::MessageLoopProxy::current()),
54       main_weak_factory_(this),
55       main_weak_this_(main_weak_factory_.GetWeakPtr()),
56       media_loop_(media_loop),
57       media_weak_factory_(this),
58       demuxer_client_(demuxer_client),
59       demuxer_client_id_(demuxer_client_id),
60       media_log_(media_log),
61       is_demuxer_ready_(false),
62       audio_stream_(NULL),
63       video_stream_(NULL),
64       seeking_(false),
65       is_video_encrypted_(false),
66       doing_browser_seek_(false),
67       browser_seek_time_(media::kNoTimestamp()),
68       expecting_regular_seek_(false),
69       access_unit_size_(0) {
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(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
169 void 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
178 const blink::WebTimeRanges& MediaSourceDelegate::Buffered() {
179   buffered_web_time_ranges_ =
180       ConvertToWebTimeRanges(buffered_time_ranges_);
181   return buffered_web_time_ranges_;
182 }
183
184 size_t MediaSourceDelegate::DecodedFrameCount() const {
185   return statistics_.video_frames_decoded;
186 }
187
188 size_t MediaSourceDelegate::DroppedFrameCount() const {
189   return statistics_.video_frames_dropped;
190 }
191
192 size_t MediaSourceDelegate::AudioDecodedByteCount() const {
193   return statistics_.audio_bytes_decoded;
194 }
195
196 size_t MediaSourceDelegate::VideoDecodedByteCount() const {
197   return statistics_.video_bytes_decoded;
198 }
199
200 void 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
223 void 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
251 void 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
294 void 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
302 void MediaSourceDelegate::SetTotalBytes(int64 total_bytes) {
303   NOTIMPLEMENTED();
304 }
305
306 void MediaSourceDelegate::AddBufferedByteRange(int64 start, int64 end) {
307   NOTIMPLEMENTED();
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_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
326 void 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
334 void 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
349 void 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
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_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
467 void 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
474 void 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
481 void MediaSourceDelegate::RemoveTextStream(
482     media::DemuxerStream* /* text_stream */ ) {
483   // TODO(matthewjheaney): remove text stream (http://crbug/322115).
484   NOTIMPLEMENTED();
485 }
486
487 void 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
520 void 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
533 void 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
546 void 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
569 void 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
586 void 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
599 void 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
612 void 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
625 void 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
636 void 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
644 void MediaSourceDelegate::DeleteSelf() {
645   DCHECK(main_loop_->BelongsToCurrentThread());
646   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
647   chunk_demuxer_.reset();
648   delete this;
649 }
650
651 void MediaSourceDelegate::OnMediaConfigRequest() {
652   DCHECK(media_loop_->BelongsToCurrentThread());
653   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
654   if (CanNotifyDemuxerReady())
655     NotifyDemuxerReady();
656 }
657
658 bool MediaSourceDelegate::CanNotifyDemuxerReady() {
659   DCHECK(media_loop_->BelongsToCurrentThread());
660   return is_demuxer_ready_;
661 }
662
663 void 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
696 int 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
710 void 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
719 void 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
728 bool MediaSourceDelegate::IsSeeking() const {
729   base::AutoLock auto_lock(seeking_lock_);
730   return seeking_;
731 }
732
733 base::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