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