OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webkit/media/buffered_data_source.h" | 5 #include "webkit/media/buffered_data_source.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "media/base/media_log.h" | 9 #include "media/base/media_log.h" |
10 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
11 | 11 |
12 using WebKit::WebFrame; | 12 using WebKit::WebFrame; |
13 | 13 |
14 namespace webkit_media { | 14 namespace webkit_media { |
15 | 15 |
16 // BufferedDataSource has an intermediate buffer, this value governs the initial | 16 // BufferedDataSource has an intermediate buffer, this value governs the initial |
17 // size of that buffer. It is set to 32KB because this is a typical read size | 17 // size of that buffer. It is set to 32KB because this is a typical read size |
18 // of FFmpeg. | 18 // of FFmpeg. |
19 static const int kInitialReadBufferSize = 32768; | 19 static const int kInitialReadBufferSize = 32768; |
20 | 20 |
21 // Number of cache misses we allow for a single Read() before signalling an | 21 // Number of cache misses we allow for a single Read() before signalling an |
22 // error. | 22 // error. |
23 static const int kNumCacheMissRetries = 3; | 23 static const int kNumCacheMissRetries = 3; |
24 | 24 |
25 // Non-HTTP resources are assumed to be fully loaded so we ignore any | |
26 // loading/progress related callbacks. | |
scherkus (not reviewing)
2012/07/06 16:28:35
see http://codereview.chromium.org/10692106/ -- I
Ami GONE FROM CHROMIUM
2012/07/09 03:25:10
FTR, you mean https://chromiumcodereview.appspot.c
| |
27 static void NonHttpLoadingCallback(BufferedResourceLoader::LoadingState) {} | |
28 static void NonHttpProgressCallback(int64) {} | |
29 | |
25 BufferedDataSource::BufferedDataSource( | 30 BufferedDataSource::BufferedDataSource( |
26 MessageLoop* render_loop, | 31 MessageLoop* render_loop, |
27 WebFrame* frame, | 32 WebFrame* frame, |
28 media::MediaLog* media_log) | 33 media::MediaLog* media_log) |
29 : total_bytes_(kPositionNotSpecified), | 34 : total_bytes_(kPositionNotSpecified), |
30 buffered_bytes_(0), | 35 buffered_bytes_(0), |
31 streaming_(false), | 36 streaming_(false), |
32 frame_(frame), | 37 frame_(frame), |
33 loader_(NULL), | 38 loader_(NULL), |
34 is_downloading_data_(false), | 39 is_downloading_data_(false), |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
88 url_ = url; | 93 url_ = url; |
89 | 94 |
90 initialize_cb_ = initialize_cb; | 95 initialize_cb_ = initialize_cb; |
91 | 96 |
92 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { | 97 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { |
93 // Do an unbounded range request starting at the beginning. If the server | 98 // Do an unbounded range request starting at the beginning. If the server |
94 // responds with 200 instead of 206 we'll fall back into a streaming mode. | 99 // responds with 200 instead of 206 we'll fall back into a streaming mode. |
95 loader_.reset(CreateResourceLoader(0, kPositionNotSpecified)); | 100 loader_.reset(CreateResourceLoader(0, kPositionNotSpecified)); |
96 loader_->Start( | 101 loader_->Start( |
97 base::Bind(&BufferedDataSource::HttpInitialStartCallback, this), | 102 base::Bind(&BufferedDataSource::HttpInitialStartCallback, this), |
98 base::Bind(&BufferedDataSource::NetworkEventCallback, this), | 103 base::Bind(&BufferedDataSource::HttpLoadingCallback, this), |
104 base::Bind(&BufferedDataSource::HttpProgressCallback, this), | |
99 frame_); | 105 frame_); |
100 return; | 106 return; |
101 } | 107 } |
102 | 108 |
103 // For all other protocols, assume they support range request. We fetch | 109 // For all other protocols, assume they support range request. We fetch |
104 // the full range of the resource to obtain the instance size because | 110 // the full range of the resource to obtain the instance size because |
105 // we won't be served HTTP headers. | 111 // we won't be served HTTP headers. |
106 loader_.reset(CreateResourceLoader(kPositionNotSpecified, | 112 loader_.reset(CreateResourceLoader(kPositionNotSpecified, |
107 kPositionNotSpecified)); | 113 kPositionNotSpecified)); |
108 loader_->Start( | 114 loader_->Start( |
109 base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this), | 115 base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this), |
110 base::Bind(&BufferedDataSource::NetworkEventCallback, this), | 116 base::Bind(&NonHttpLoadingCallback), |
117 base::Bind(&NonHttpProgressCallback), | |
111 frame_); | 118 frame_); |
112 } | 119 } |
113 | 120 |
114 void BufferedDataSource::SetPreload(Preload preload) { | 121 void BufferedDataSource::SetPreload(Preload preload) { |
115 DCHECK(MessageLoop::current() == render_loop_); | 122 DCHECK(MessageLoop::current() == render_loop_); |
116 preload_ = preload; | 123 preload_ = preload; |
117 } | 124 } |
118 | 125 |
119 bool BufferedDataSource::HasSingleOrigin() { | 126 bool BufferedDataSource::HasSingleOrigin() { |
120 DCHECK(MessageLoop::current() == render_loop_); | 127 DCHECK(MessageLoop::current() == render_loop_); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
248 if (stopped_on_render_loop_) | 255 if (stopped_on_render_loop_) |
249 return; | 256 return; |
250 | 257 |
251 { | 258 { |
252 // If there's no outstanding read then return early. | 259 // If there's no outstanding read then return early. |
253 base::AutoLock auto_lock(lock_); | 260 base::AutoLock auto_lock(lock_); |
254 if (read_cb_.is_null()) | 261 if (read_cb_.is_null()) |
255 return; | 262 return; |
256 } | 263 } |
257 | 264 |
265 // Start reading from where we last left off until the end of the resource. | |
258 loader_.reset( | 266 loader_.reset( |
259 CreateResourceLoader(last_read_start_, kPositionNotSpecified)); | 267 CreateResourceLoader(last_read_start_, kPositionNotSpecified)); |
260 loader_->Start( | 268 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { |
261 base::Bind(&BufferedDataSource::PartialReadStartCallback, this), | 269 loader_->Start( |
262 base::Bind(&BufferedDataSource::NetworkEventCallback, this), | 270 base::Bind(&BufferedDataSource::PartialReadStartCallback, this), |
263 frame_); | 271 base::Bind(&BufferedDataSource::HttpLoadingCallback, this), |
272 base::Bind(&BufferedDataSource::HttpProgressCallback, this), | |
273 frame_); | |
274 } else { | |
275 loader_->Start( | |
276 base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this), | |
277 base::Bind(&NonHttpLoadingCallback), | |
278 base::Bind(&NonHttpProgressCallback), | |
279 frame_); | |
280 } | |
264 } | 281 } |
265 | 282 |
266 void BufferedDataSource::SetPlaybackRateTask(float playback_rate) { | 283 void BufferedDataSource::SetPlaybackRateTask(float playback_rate) { |
267 DCHECK(MessageLoop::current() == render_loop_); | 284 DCHECK(MessageLoop::current() == render_loop_); |
268 DCHECK(loader_.get()); | 285 DCHECK(loader_.get()); |
269 | 286 |
270 if (playback_rate != 0) | 287 if (playback_rate != 0) |
271 media_has_played_ = true; | 288 media_has_played_ = true; |
272 | 289 |
273 playback_rate_ = playback_rate; | 290 playback_rate_ = playback_rate; |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
497 cache_miss_retries_left_--; | 514 cache_miss_retries_left_--; |
498 render_loop_->PostTask(FROM_HERE, | 515 render_loop_->PostTask(FROM_HERE, |
499 base::Bind(&BufferedDataSource::RestartLoadingTask, this)); | 516 base::Bind(&BufferedDataSource::RestartLoadingTask, this)); |
500 return; | 517 return; |
501 } | 518 } |
502 | 519 |
503 // Fall through to signal a read error. | 520 // Fall through to signal a read error. |
504 bytes_read = kReadError; | 521 bytes_read = kReadError; |
505 } | 522 } |
506 | 523 |
507 // We need to prevent calling to filter host and running the callback if | 524 // TODO(scherkus): we shouldn't have to lock to signal host(), see |
508 // we have received the stop signal. We need to lock down the whole callback | 525 // http://crbug.com/113712 for details. |
509 // method to prevent bad things from happening. The reason behind this is | |
510 // that we cannot guarantee tasks on render thread have completely stopped | |
511 // when we receive the Stop() method call. So only way to solve this is to | |
512 // let tasks on render thread to run but make sure they don't call outside | |
513 // this object when Stop() method is ever called. Locking this method is safe | |
514 // because |lock_| is only acquired in tasks on render thread. | |
515 base::AutoLock auto_lock(lock_); | 526 base::AutoLock auto_lock(lock_); |
516 if (stop_signal_received_) | 527 if (stop_signal_received_) |
517 return; | 528 return; |
518 | 529 |
519 if (bytes_read > 0) { | 530 if (bytes_read > 0) { |
520 memcpy(read_buffer_, intermediate_read_buffer_.get(), bytes_read); | 531 memcpy(read_buffer_, intermediate_read_buffer_.get(), bytes_read); |
521 } else if (bytes_read == 0 && total_bytes_ == kPositionNotSpecified) { | 532 } else if (bytes_read == 0 && total_bytes_ == kPositionNotSpecified) { |
522 // We've reached the end of the file and we didn't know the total size | 533 // We've reached the end of the file and we didn't know the total size |
523 // before. Update the total size so Read()s past the end of the file will | 534 // before. Update the total size so Read()s past the end of the file will |
524 // fail like they would if we had known the file size at the beginning. | 535 // fail like they would if we had known the file size at the beginning. |
525 total_bytes_ = loader_->instance_size(); | 536 total_bytes_ = loader_->instance_size(); |
526 | 537 |
527 if (host() && total_bytes_ != kPositionNotSpecified) { | 538 if (host() && total_bytes_ != kPositionNotSpecified) { |
528 host()->SetTotalBytes(total_bytes_); | 539 host()->SetTotalBytes(total_bytes_); |
529 host()->AddBufferedByteRange(last_read_start_, total_bytes_); | 540 host()->AddBufferedByteRange(last_read_start_, total_bytes_); |
530 } | 541 } |
531 } | 542 } |
532 DoneRead_Locked(bytes_read); | 543 DoneRead_Locked(bytes_read); |
533 } | 544 } |
534 | 545 |
535 void BufferedDataSource::NetworkEventCallback() { | 546 void BufferedDataSource::HttpLoadingCallback( |
547 BufferedResourceLoader::LoadingState state) { | |
536 DCHECK(MessageLoop::current() == render_loop_); | 548 DCHECK(MessageLoop::current() == render_loop_); |
537 DCHECK(loader_.get()); | 549 DCHECK(url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)); |
538 | 550 |
539 // In case of non-HTTP request we don't need to report network events, | 551 // TODO(scherkus): we shouldn't have to lock to signal host(), see |
540 // so return immediately. | 552 // http://crbug.com/113712 for details. |
541 if (!url_.SchemeIs(kHttpScheme) && !url_.SchemeIs(kHttpsScheme)) | |
542 return; | |
543 | |
544 bool is_downloading_data = loader_->is_downloading_data(); | |
545 int64 current_buffered_position = loader_->GetBufferedPosition(); | |
546 | |
547 // If we get an unspecified value, return immediately. | |
548 if (current_buffered_position == kPositionNotSpecified) | |
549 return; | |
550 | |
551 // We need to prevent calling to filter host and running the callback if | |
552 // we have received the stop signal. We need to lock down the whole callback | |
553 // method to prevent bad things from happening. The reason behind this is | |
554 // that we cannot guarantee tasks on render thread have completely stopped | |
555 // when we receive the Stop() method call. So only way to solve this is to | |
556 // let tasks on render thread to run but make sure they don't call outside | |
557 // this object when Stop() method is ever called. Locking this method is safe | |
558 // because |lock_| is only acquired in tasks on render thread. | |
559 base::AutoLock auto_lock(lock_); | 553 base::AutoLock auto_lock(lock_); |
560 if (stop_signal_received_) | 554 if (stop_signal_received_) |
561 return; | 555 return; |
562 | 556 |
557 bool is_downloading_data; | |
558 switch (state) { | |
559 case BufferedResourceLoader::kLoading: | |
560 is_downloading_data = true; | |
561 break; | |
562 case BufferedResourceLoader::kLoadingDeferred: | |
563 is_downloading_data = false; | |
564 break; | |
565 | |
566 // TODO(scherkus): we don't signal network activity changes when loads | |
567 // complete or fail to preserve existing behaviour when deferring is | |
568 // toggled, however SetNetworkActivity() should use a similar enum as there | |
569 // isn't any signal today to notify the client that loading has | |
570 // failed/finished (we only get errors on subsequent reads). | |
571 case BufferedResourceLoader::kLoadingFailed: | |
572 case BufferedResourceLoader::kLoadingFinished: | |
573 return; | |
574 } | |
575 | |
563 if (is_downloading_data != is_downloading_data_) { | 576 if (is_downloading_data != is_downloading_data_) { |
564 is_downloading_data_ = is_downloading_data; | 577 is_downloading_data_ = is_downloading_data; |
565 if (host()) | 578 if (host()) |
566 host()->SetNetworkActivity(is_downloading_data); | 579 host()->SetNetworkActivity(is_downloading_data); |
567 } | 580 } |
581 } | |
568 | 582 |
569 if (host() && current_buffered_position > last_read_start_) | 583 void BufferedDataSource::HttpProgressCallback(int64 position) { |
570 host()->AddBufferedByteRange(last_read_start_, current_buffered_position); | 584 DCHECK(MessageLoop::current() == render_loop_); |
585 DCHECK(url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)); | |
586 | |
587 // TODO(scherkus): we shouldn't have to lock to signal host(), see | |
588 // http://crbug.com/113712 for details. | |
589 base::AutoLock auto_lock(lock_); | |
590 if (stop_signal_received_) | |
591 return; | |
592 | |
593 if (host() && position > last_read_start_) | |
594 host()->AddBufferedByteRange(last_read_start_, position); | |
571 } | 595 } |
572 | 596 |
573 void BufferedDataSource::UpdateHostState_Locked() { | 597 void BufferedDataSource::UpdateHostState_Locked() { |
574 // Called from various threads, under lock. | |
575 lock_.AssertAcquired(); | 598 lock_.AssertAcquired(); |
576 | 599 |
577 if (!host()) | 600 if (!host()) |
578 return; | 601 return; |
579 | 602 |
580 if (total_bytes_ != kPositionNotSpecified) | 603 if (total_bytes_ != kPositionNotSpecified) |
581 host()->SetTotalBytes(total_bytes_); | 604 host()->SetTotalBytes(total_bytes_); |
582 if (buffered_bytes_ > last_read_start_) | 605 if (buffered_bytes_ > last_read_start_) |
583 host()->AddBufferedByteRange(last_read_start_, buffered_bytes_); | 606 host()->AddBufferedByteRange(last_read_start_, buffered_bytes_); |
584 } | 607 } |
585 | 608 |
586 } // namespace webkit_media | 609 } // namespace webkit_media |
OLD | NEW |