Process Alt-Svc headers.
[chromium-blink-merge.git] / content / renderer / media / android / media_source_delegate.cc
blob62edeca8c42eda1c97f4d9f48e8632e326fecafb
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.
5 #include "content/renderer/media/android/media_source_delegate.h"
7 #include <limits>
8 #include <string>
9 #include <vector>
11 #include "base/strings/string_number_conversions.h"
12 #include "base/thread_task_runner_handle.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"
25 using media::DemuxerStream;
26 using media::DemuxerConfigs;
27 using media::DemuxerData;
28 using blink::WebMediaPlayer;
29 using blink::WebString;
31 namespace {
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;
37 const uint8 kVorbisPadding[] = { 0xff, 0xff, 0xff, 0xff };
39 } // namespace
41 namespace content {
43 MediaSourceDelegate::MediaSourceDelegate(
44 RendererDemuxerAndroid* demuxer_client,
45 int demuxer_client_id,
46 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
47 const scoped_refptr<media::MediaLog> media_log)
48 : demuxer_client_(demuxer_client),
49 demuxer_client_id_(demuxer_client_id),
50 media_log_(media_log),
51 is_demuxer_ready_(false),
52 audio_stream_(NULL),
53 video_stream_(NULL),
54 seeking_(false),
55 is_video_encrypted_(false),
56 doing_browser_seek_(false),
57 browser_seek_time_(media::kNoTimestamp()),
58 expecting_regular_seek_(false),
59 access_unit_size_(0),
60 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
61 media_task_runner_(media_task_runner),
62 main_weak_factory_(this),
63 media_weak_factory_(this) {
64 main_weak_this_ = main_weak_factory_.GetWeakPtr();
65 DCHECK(main_task_runner_->BelongsToCurrentThread());
68 MediaSourceDelegate::~MediaSourceDelegate() {
69 DCHECK(main_task_runner_->BelongsToCurrentThread());
70 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
71 DCHECK(!chunk_demuxer_);
72 DCHECK(!demuxer_client_);
73 DCHECK(!audio_decrypting_demuxer_stream_);
74 DCHECK(!video_decrypting_demuxer_stream_);
75 DCHECK(!audio_stream_);
76 DCHECK(!video_stream_);
79 void MediaSourceDelegate::Stop(const base::Closure& stop_cb) {
80 DCHECK(main_task_runner_->BelongsToCurrentThread());
81 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
83 if (!chunk_demuxer_) {
84 DCHECK(!demuxer_client_);
85 return;
88 duration_change_cb_.Reset();
89 update_network_state_cb_.Reset();
90 media_source_opened_cb_.Reset();
92 main_weak_factory_.InvalidateWeakPtrs();
93 DCHECK(!main_weak_factory_.HasWeakPtrs());
95 chunk_demuxer_->Shutdown();
97 // Continue to stop objects on the media thread.
98 media_task_runner_->PostTask(
99 FROM_HERE,
100 base::Bind(
101 &MediaSourceDelegate::StopDemuxer, base::Unretained(this), stop_cb));
104 bool MediaSourceDelegate::IsVideoEncrypted() {
105 DCHECK(main_task_runner_->BelongsToCurrentThread());
106 base::AutoLock auto_lock(is_video_encrypted_lock_);
107 return is_video_encrypted_;
110 base::Time MediaSourceDelegate::GetTimelineOffset() const {
111 DCHECK(main_task_runner_->BelongsToCurrentThread());
112 if (!chunk_demuxer_)
113 return base::Time();
115 return chunk_demuxer_->GetTimelineOffset();
118 void MediaSourceDelegate::StopDemuxer(const base::Closure& stop_cb) {
119 DVLOG(2) << __FUNCTION__;
120 DCHECK(media_task_runner_->BelongsToCurrentThread());
121 DCHECK(chunk_demuxer_);
123 demuxer_client_->RemoveDelegate(demuxer_client_id_);
124 demuxer_client_ = NULL;
126 audio_stream_ = NULL;
127 video_stream_ = NULL;
128 // TODO(xhwang): Figure out if we need to Reset the DDSs after Seeking or
129 // before destroying them.
130 audio_decrypting_demuxer_stream_.reset();
131 video_decrypting_demuxer_stream_.reset();
133 media_weak_factory_.InvalidateWeakPtrs();
134 DCHECK(!media_weak_factory_.HasWeakPtrs());
136 chunk_demuxer_->Stop();
137 chunk_demuxer_.reset();
139 // |this| may be destroyed at this point in time as a result of running
140 // |stop_cb|.
141 stop_cb.Run();
144 void MediaSourceDelegate::InitializeMediaSource(
145 const MediaSourceOpenedCB& media_source_opened_cb,
146 const media::Demuxer::EncryptedMediaInitDataCB&
147 encrypted_media_init_data_cb,
148 const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
149 const UpdateNetworkStateCB& update_network_state_cb,
150 const DurationChangeCB& duration_change_cb,
151 const base::Closure& waiting_for_decryption_key_cb) {
152 DCHECK(main_task_runner_->BelongsToCurrentThread());
153 DCHECK(!media_source_opened_cb.is_null());
154 media_source_opened_cb_ = media_source_opened_cb;
155 encrypted_media_init_data_cb_ = encrypted_media_init_data_cb;
156 set_decryptor_ready_cb_ = media::BindToCurrentLoop(set_decryptor_ready_cb);
157 update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb);
158 duration_change_cb_ = duration_change_cb;
159 waiting_for_decryption_key_cb_ =
160 media::BindToCurrentLoop(waiting_for_decryption_key_cb);
161 access_unit_size_ = kAccessUnitSizeForMediaSource;
163 chunk_demuxer_.reset(new media::ChunkDemuxer(
164 media::BindToCurrentLoop(
165 base::Bind(&MediaSourceDelegate::OnDemuxerOpened, main_weak_this_)),
166 media::BindToCurrentLoop(base::Bind(
167 &MediaSourceDelegate::OnEncryptedMediaInitData, main_weak_this_)),
168 media_log_, false));
170 // |this| will be retained until StopDemuxer() is posted, so Unretained() is
171 // safe here.
172 media_task_runner_->PostTask(FROM_HERE,
173 base::Bind(&MediaSourceDelegate::InitializeDemuxer,
174 base::Unretained(this)));
177 void MediaSourceDelegate::InitializeDemuxer() {
178 DCHECK(media_task_runner_->BelongsToCurrentThread());
179 demuxer_client_->AddDelegate(demuxer_client_id_, this);
180 chunk_demuxer_->Initialize(this,
181 base::Bind(&MediaSourceDelegate::OnDemuxerInitDone,
182 media_weak_factory_.GetWeakPtr()),
183 false);
186 blink::WebTimeRanges MediaSourceDelegate::Buffered() const {
187 return media::ConvertToWebTimeRanges(buffered_time_ranges_);
190 size_t MediaSourceDelegate::DecodedFrameCount() const {
191 return statistics_.video_frames_decoded;
194 size_t MediaSourceDelegate::DroppedFrameCount() const {
195 return statistics_.video_frames_dropped;
198 size_t MediaSourceDelegate::AudioDecodedByteCount() const {
199 return statistics_.audio_bytes_decoded;
202 size_t MediaSourceDelegate::VideoDecodedByteCount() const {
203 return statistics_.video_bytes_decoded;
206 void MediaSourceDelegate::CancelPendingSeek(const base::TimeDelta& seek_time) {
207 DCHECK(main_task_runner_->BelongsToCurrentThread());
208 DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
209 << demuxer_client_id_;
211 if (!chunk_demuxer_)
212 return;
215 // Remember to trivially finish any newly arriving browser seek requests
216 // that may arrive prior to the next regular seek request.
217 base::AutoLock auto_lock(seeking_lock_);
218 expecting_regular_seek_ = true;
221 // Cancel any previously expected or in-progress regular or browser seek.
222 // It is possible that we have just finished the seek, but caller does
223 // not know this yet. It is still safe to cancel in this case because the
224 // caller will always call StartWaitingForSeek() when it is notified of
225 // the finished seek.
226 chunk_demuxer_->CancelPendingSeek(seek_time);
229 void MediaSourceDelegate::StartWaitingForSeek(
230 const base::TimeDelta& seek_time) {
231 DCHECK(main_task_runner_->BelongsToCurrentThread());
232 DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ") : "
233 << demuxer_client_id_;
235 if (!chunk_demuxer_)
236 return;
238 bool cancel_browser_seek = false;
240 // Remember to trivially finish any newly arriving browser seek requests
241 // that may arrive prior to the next regular seek request.
242 base::AutoLock auto_lock(seeking_lock_);
243 expecting_regular_seek_ = true;
245 // Remember to cancel any in-progress browser seek.
246 if (seeking_) {
247 DCHECK(doing_browser_seek_);
248 cancel_browser_seek = true;
252 if (cancel_browser_seek)
253 chunk_demuxer_->CancelPendingSeek(seek_time);
254 chunk_demuxer_->StartWaitingForSeek(seek_time);
257 void MediaSourceDelegate::Seek(
258 const base::TimeDelta& seek_time, bool is_browser_seek) {
259 DCHECK(media_task_runner_->BelongsToCurrentThread());
260 DVLOG(1) << __FUNCTION__ << "(" << seek_time.InSecondsF() << ", "
261 << (is_browser_seek ? "browser seek" : "regular seek") << ") : "
262 << demuxer_client_id_;
264 base::TimeDelta internal_seek_time = seek_time;
266 base::AutoLock auto_lock(seeking_lock_);
267 DCHECK(!seeking_);
268 seeking_ = true;
269 doing_browser_seek_ = is_browser_seek;
271 if (doing_browser_seek_ && (!chunk_demuxer_ || expecting_regular_seek_)) {
272 // Trivially finish the browser seek without actually doing it. Reads will
273 // continue to be |kAborted| until the next regular seek is done. Browser
274 // seeking is not supported unless using a ChunkDemuxer; browser seeks are
275 // trivially finished if |chunk_demuxer_| is NULL.
276 seeking_ = false;
277 doing_browser_seek_ = false;
278 demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time);
279 return;
282 if (doing_browser_seek_) {
283 internal_seek_time = FindBufferedBrowserSeekTime_Locked(seek_time);
284 browser_seek_time_ = internal_seek_time;
285 } else {
286 expecting_regular_seek_ = false;
287 browser_seek_time_ = media::kNoTimestamp();
291 // Prepare |chunk_demuxer_| for browser seek.
292 if (is_browser_seek) {
293 chunk_demuxer_->CancelPendingSeek(internal_seek_time);
294 chunk_demuxer_->StartWaitingForSeek(internal_seek_time);
297 SeekInternal(internal_seek_time);
300 void MediaSourceDelegate::SeekInternal(const base::TimeDelta& seek_time) {
301 DCHECK(media_task_runner_->BelongsToCurrentThread());
302 DCHECK(IsSeeking());
303 chunk_demuxer_->Seek(seek_time, base::Bind(
304 &MediaSourceDelegate::OnDemuxerSeekDone,
305 media_weak_factory_.GetWeakPtr()));
308 void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start,
309 base::TimeDelta end) {
310 buffered_time_ranges_.Add(start, end);
313 void MediaSourceDelegate::SetDuration(base::TimeDelta duration) {
314 DCHECK(main_task_runner_->BelongsToCurrentThread());
315 DVLOG(1) << __FUNCTION__ << "(" << duration.InSecondsF() << ") : "
316 << demuxer_client_id_;
318 // Force duration change notification to be async to avoid reentrancy into
319 // ChunkDemxuer.
320 main_task_runner_->PostTask(FROM_HERE, base::Bind(
321 &MediaSourceDelegate::OnDurationChanged, main_weak_this_, duration));
324 void MediaSourceDelegate::OnDurationChanged(const base::TimeDelta& duration) {
325 DCHECK(main_task_runner_->BelongsToCurrentThread());
326 if (demuxer_client_)
327 demuxer_client_->DurationChanged(demuxer_client_id_, duration);
328 if (!duration_change_cb_.is_null())
329 duration_change_cb_.Run(duration);
332 void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) {
333 DCHECK(media_task_runner_->BelongsToCurrentThread());
334 DVLOG(1) << __FUNCTION__ << "(" << type << ") : " << demuxer_client_id_;
335 if (IsSeeking())
336 return; // Drop the request during seeking.
338 DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO);
339 // The access unit size should have been initialized properly at this stage.
340 DCHECK_GT(access_unit_size_, 0u);
341 scoped_ptr<DemuxerData> data(new DemuxerData());
342 data->type = type;
343 data->access_units.resize(access_unit_size_);
344 ReadFromDemuxerStream(type, data.Pass(), 0);
347 void MediaSourceDelegate::ReadFromDemuxerStream(media::DemuxerStream::Type type,
348 scoped_ptr<DemuxerData> data,
349 size_t index) {
350 DCHECK(media_task_runner_->BelongsToCurrentThread());
351 // DemuxerStream::Read() always returns the read callback asynchronously.
352 DemuxerStream* stream =
353 (type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_;
354 stream->Read(base::Bind(
355 &MediaSourceDelegate::OnBufferReady,
356 media_weak_factory_.GetWeakPtr(), type, base::Passed(&data), index));
359 void MediaSourceDelegate::OnBufferReady(
360 media::DemuxerStream::Type type,
361 scoped_ptr<DemuxerData> data,
362 size_t index,
363 DemuxerStream::Status status,
364 const scoped_refptr<media::DecoderBuffer>& buffer) {
365 DCHECK(media_task_runner_->BelongsToCurrentThread());
366 DVLOG(1) << __FUNCTION__ << "(" << index << ", " << status << ", "
367 << ((!buffer.get() || buffer->end_of_stream())
368 ? -1
369 : buffer->timestamp().InMilliseconds())
370 << ") : " << demuxer_client_id_;
371 DCHECK(chunk_demuxer_);
373 // No new OnReadFromDemuxer() will be called during seeking. So this callback
374 // must be from previous OnReadFromDemuxer() call and should be ignored.
375 if (IsSeeking()) {
376 DVLOG(1) << __FUNCTION__ << ": Ignore previous read during seeking.";
377 return;
380 bool is_audio = (type == DemuxerStream::AUDIO);
381 if (status != DemuxerStream::kAborted &&
382 index >= data->access_units.size()) {
383 LOG(ERROR) << "The internal state inconsistency onBufferReady: "
384 << (is_audio ? "Audio" : "Video") << ", index " << index
385 << ", size " << data->access_units.size()
386 << ", status " << static_cast<int>(status);
387 NOTREACHED();
388 return;
391 switch (status) {
392 case DemuxerStream::kAborted:
393 DVLOG(1) << __FUNCTION__ << " : Aborted";
394 data->access_units[index].status = status;
395 data->access_units.resize(index + 1);
396 break;
398 case DemuxerStream::kConfigChanged:
399 CHECK((is_audio && audio_stream_) || (!is_audio && video_stream_));
400 data->demuxer_configs.resize(1);
401 CHECK(GetDemuxerConfigFromStream(&data->demuxer_configs[0], is_audio));
402 if (!is_audio) {
403 gfx::Size size = data->demuxer_configs[0].video_size;
404 DVLOG(1) << "Video config is changed: " << size.width() << "x"
405 << size.height();
407 data->access_units[index].status = status;
408 data->access_units.resize(index + 1);
409 break;
411 case DemuxerStream::kOk:
412 data->access_units[index].status = status;
413 if (buffer->end_of_stream()) {
414 data->access_units[index].is_end_of_stream = true;
415 data->access_units.resize(index + 1);
416 break;
418 data->access_units[index].is_key_frame = buffer->is_key_frame();
419 // TODO(ycheo): We assume that the inputed stream will be decoded
420 // right away.
421 // Need to implement this properly using MediaPlayer.OnInfoListener.
422 if (is_audio) {
423 statistics_.audio_bytes_decoded += buffer->data_size();
424 } else {
425 statistics_.video_bytes_decoded += buffer->data_size();
426 statistics_.video_frames_decoded++;
428 data->access_units[index].timestamp = buffer->timestamp();
430 data->access_units[index].data.assign(
431 buffer->data(), buffer->data() + buffer->data_size());
432 // Vorbis needs 4 extra bytes padding on Android. Check
433 // NuMediaExtractor.cpp in Android source code.
434 if (is_audio && media::kCodecVorbis ==
435 audio_stream_->audio_decoder_config().codec()) {
436 data->access_units[index].data.insert(
437 data->access_units[index].data.end(), kVorbisPadding,
438 kVorbisPadding + 4);
440 if (buffer->decrypt_config()) {
441 data->access_units[index].key_id = std::vector<char>(
442 buffer->decrypt_config()->key_id().begin(),
443 buffer->decrypt_config()->key_id().end());
444 data->access_units[index].iv = std::vector<char>(
445 buffer->decrypt_config()->iv().begin(),
446 buffer->decrypt_config()->iv().end());
447 data->access_units[index].subsamples =
448 buffer->decrypt_config()->subsamples();
450 if (++index < data->access_units.size()) {
451 ReadFromDemuxerStream(type, data.Pass(), index);
452 return;
454 break;
456 default:
457 NOTREACHED();
460 if (!IsSeeking() && demuxer_client_)
461 demuxer_client_->ReadFromDemuxerAck(demuxer_client_id_, *data);
464 void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) {
465 DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
466 // |update_network_state_cb_| is bound to the main thread.
467 if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null())
468 update_network_state_cb_.Run(PipelineErrorToNetworkState(status));
471 void MediaSourceDelegate::AddTextStream(
472 media::DemuxerStream* /* text_stream */ ,
473 const media::TextTrackConfig& /* config */ ) {
474 // TODO(matthewjheaney): add text stream (http://crbug/322115).
475 NOTIMPLEMENTED();
478 void MediaSourceDelegate::RemoveTextStream(
479 media::DemuxerStream* /* text_stream */ ) {
480 // TODO(matthewjheaney): remove text stream (http://crbug/322115).
481 NOTIMPLEMENTED();
484 void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) {
485 DCHECK(media_task_runner_->BelongsToCurrentThread());
486 DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
487 DCHECK(chunk_demuxer_);
489 if (status != media::PIPELINE_OK) {
490 OnDemuxerError(status);
491 return;
494 audio_stream_ = chunk_demuxer_->GetStream(DemuxerStream::AUDIO);
495 video_stream_ = chunk_demuxer_->GetStream(DemuxerStream::VIDEO);
497 if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() &&
498 !set_decryptor_ready_cb_.is_null()) {
499 InitAudioDecryptingDemuxerStream();
500 // InitVideoDecryptingDemuxerStream() will be called in
501 // OnAudioDecryptingDemuxerStreamInitDone().
502 return;
505 if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() &&
506 !set_decryptor_ready_cb_.is_null()) {
507 InitVideoDecryptingDemuxerStream();
508 return;
511 // Notify demuxer ready when both streams are not encrypted.
512 is_demuxer_ready_ = true;
513 NotifyDemuxerReady();
516 void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() {
517 DCHECK(media_task_runner_->BelongsToCurrentThread());
518 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
519 DCHECK(!set_decryptor_ready_cb_.is_null());
521 audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
522 media_task_runner_, media_log_, set_decryptor_ready_cb_,
523 waiting_for_decryption_key_cb_));
524 audio_decrypting_demuxer_stream_->Initialize(
525 audio_stream_,
526 base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone,
527 media_weak_factory_.GetWeakPtr()));
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());
535 video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
536 media_task_runner_, media_log_, set_decryptor_ready_cb_,
537 waiting_for_decryption_key_cb_));
538 video_decrypting_demuxer_stream_->Initialize(
539 video_stream_,
540 base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone,
541 media_weak_factory_.GetWeakPtr()));
544 void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone(
545 media::PipelineStatus status) {
546 DCHECK(media_task_runner_->BelongsToCurrentThread());
547 DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
548 DCHECK(chunk_demuxer_);
550 if (status != media::PIPELINE_OK)
551 audio_decrypting_demuxer_stream_.reset();
552 else
553 audio_stream_ = audio_decrypting_demuxer_stream_.get();
555 if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) {
556 InitVideoDecryptingDemuxerStream();
557 return;
560 // Try to notify demuxer ready when audio DDS initialization finished and
561 // video is not encrypted.
562 is_demuxer_ready_ = true;
563 NotifyDemuxerReady();
566 void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone(
567 media::PipelineStatus status) {
568 DCHECK(media_task_runner_->BelongsToCurrentThread());
569 DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
570 DCHECK(chunk_demuxer_);
572 if (status != media::PIPELINE_OK)
573 video_decrypting_demuxer_stream_.reset();
574 else
575 video_stream_ = video_decrypting_demuxer_stream_.get();
577 // Try to notify demuxer ready when video DDS initialization finished.
578 is_demuxer_ready_ = true;
579 NotifyDemuxerReady();
582 void MediaSourceDelegate::OnDemuxerSeekDone(media::PipelineStatus status) {
583 DCHECK(media_task_runner_->BelongsToCurrentThread());
584 DVLOG(1) << __FUNCTION__ << "(" << status << ") : " << demuxer_client_id_;
585 DCHECK(IsSeeking());
587 if (status != media::PIPELINE_OK) {
588 OnDemuxerError(status);
589 return;
592 ResetAudioDecryptingDemuxerStream();
595 void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() {
596 DCHECK(media_task_runner_->BelongsToCurrentThread());
597 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
598 if (audio_decrypting_demuxer_stream_) {
599 audio_decrypting_demuxer_stream_->Reset(
600 base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream,
601 media_weak_factory_.GetWeakPtr()));
602 return;
605 ResetVideoDecryptingDemuxerStream();
608 void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() {
609 DCHECK(media_task_runner_->BelongsToCurrentThread());
610 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
611 if (video_decrypting_demuxer_stream_) {
612 video_decrypting_demuxer_stream_->Reset(base::Bind(
613 &MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams,
614 media_weak_factory_.GetWeakPtr()));
615 return;
618 FinishResettingDecryptingDemuxerStreams();
621 void MediaSourceDelegate::FinishResettingDecryptingDemuxerStreams() {
622 DCHECK(media_task_runner_->BelongsToCurrentThread());
623 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
625 base::AutoLock auto_lock(seeking_lock_);
626 DCHECK(seeking_);
627 seeking_ = false;
628 doing_browser_seek_ = false;
629 demuxer_client_->DemuxerSeekDone(demuxer_client_id_, browser_seek_time_);
632 void MediaSourceDelegate::NotifyDemuxerReady() {
633 DCHECK(media_task_runner_->BelongsToCurrentThread());
634 DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
635 DCHECK(is_demuxer_ready_);
637 scoped_ptr<DemuxerConfigs> configs(new DemuxerConfigs());
638 GetDemuxerConfigFromStream(configs.get(), true);
639 GetDemuxerConfigFromStream(configs.get(), false);
640 configs->duration = GetDuration();
642 if (demuxer_client_)
643 demuxer_client_->DemuxerReady(demuxer_client_id_, *configs);
645 base::AutoLock auto_lock(is_video_encrypted_lock_);
646 is_video_encrypted_ = configs->is_video_encrypted;
649 base::TimeDelta MediaSourceDelegate::GetDuration() const {
650 DCHECK(media_task_runner_->BelongsToCurrentThread());
651 if (!chunk_demuxer_)
652 return media::kNoTimestamp();
654 double duration = chunk_demuxer_->GetDuration();
655 if (duration == std::numeric_limits<double>::infinity())
656 return media::kInfiniteDuration();
658 return media::ConvertSecondsToTimestamp(duration);
661 void MediaSourceDelegate::OnDemuxerOpened() {
662 DCHECK(main_task_runner_->BelongsToCurrentThread());
663 if (media_source_opened_cb_.is_null())
664 return;
666 media_source_opened_cb_.Run(
667 new media::WebMediaSourceImpl(chunk_demuxer_.get(), media_log_));
670 void MediaSourceDelegate::OnEncryptedMediaInitData(
671 media::EmeInitDataType init_data_type,
672 const std::vector<uint8>& init_data) {
673 DCHECK(main_task_runner_->BelongsToCurrentThread());
674 if (encrypted_media_init_data_cb_.is_null())
675 return;
677 encrypted_media_init_data_cb_.Run(init_data_type, init_data);
680 bool MediaSourceDelegate::IsSeeking() const {
681 base::AutoLock auto_lock(seeking_lock_);
682 return seeking_;
685 base::TimeDelta MediaSourceDelegate::FindBufferedBrowserSeekTime_Locked(
686 const base::TimeDelta& seek_time) const {
687 seeking_lock_.AssertAcquired();
688 DCHECK(seeking_);
689 DCHECK(doing_browser_seek_);
690 DCHECK(chunk_demuxer_) << "Browser seek requested, but no chunk demuxer";
692 media::Ranges<base::TimeDelta> buffered =
693 chunk_demuxer_->GetBufferedRanges();
695 for (size_t i = 0; i < buffered.size(); ++i) {
696 base::TimeDelta range_start = buffered.start(i);
697 base::TimeDelta range_end = buffered.end(i);
698 if (range_start <= seek_time) {
699 if (range_end >= seek_time)
700 return seek_time;
701 continue;
704 // If the start of the next buffered range after |seek_time| is too far
705 // into the future, do not jump forward.
706 if ((range_start - seek_time) > base::TimeDelta::FromMilliseconds(100))
707 break;
709 // TODO(wolenetz): Remove possibility that this browser seek jumps
710 // into future when the requested range is unbuffered but there is some
711 // other buffered range after it. See http://crbug.com/304234.
712 return range_start;
715 // We found no range containing |seek_time| or beginning shortly after
716 // |seek_time|. While possible that such data at and beyond the player's
717 // current time have been garbage collected or removed by the web app, this is
718 // unlikely. This may cause unexpected playback stall due to seek pending an
719 // append for a GOP prior to the last GOP demuxed.
720 // TODO(wolenetz): Remove the possibility for this seek to cause unexpected
721 // player stall by replaying cached data since last keyframe in browser player
722 // rather than issuing browser seek. See http://crbug.com/304234.
723 return seek_time;
726 bool MediaSourceDelegate::GetDemuxerConfigFromStream(
727 media::DemuxerConfigs* configs, bool is_audio) {
728 DCHECK(media_task_runner_->BelongsToCurrentThread());
729 if (!is_demuxer_ready_)
730 return false;
731 if (is_audio && audio_stream_) {
732 media::AudioDecoderConfig config = audio_stream_->audio_decoder_config();
733 configs->audio_codec = config.codec();
734 configs->audio_channels =
735 media::ChannelLayoutToChannelCount(config.channel_layout());
736 configs->audio_sampling_rate = config.samples_per_second();
737 configs->is_audio_encrypted = config.is_encrypted();
738 configs->audio_extra_data = std::vector<uint8>(
739 config.extra_data(), config.extra_data() + config.extra_data_size());
740 configs->audio_codec_delay_ns = static_cast<int64_t>(
741 config.codec_delay() *
742 (static_cast<double>(base::Time::kNanosecondsPerSecond) /
743 config.samples_per_second()));
744 configs->audio_seek_preroll_ns =
745 config.seek_preroll().InMicroseconds() *
746 base::Time::kNanosecondsPerMicrosecond;
747 return true;
749 if (!is_audio && video_stream_) {
750 media::VideoDecoderConfig config = video_stream_->video_decoder_config();
751 configs->video_codec = config.codec();
752 configs->video_size = config.natural_size();
753 configs->is_video_encrypted = config.is_encrypted();
754 configs->video_extra_data = std::vector<uint8>(
755 config.extra_data(), config.extra_data() + config.extra_data_size());
756 return true;
758 return false;
761 } // namespace content