Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(246)

Side by Side Diff: webkit/media/buffered_data_source.cc

Issue 10735016: Collapse HTTP and non-HTTP codepaths into single methods. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix bugs due to my tests Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/media/buffered_data_source.h ('k') | webkit/media/buffered_data_source_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 { 14 namespace {
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 const int kInitialReadBufferSize = 32768; 19 const int kInitialReadBufferSize = 32768;
20 20
21 // Number of cache misses we allow for a single Read() before signaling an 21 // Number of cache misses we allow for a single Read() before signaling an
22 // error. 22 // error.
23 const int kNumCacheMissRetries = 3; 23 const int kNumCacheMissRetries = 3;
24 24
25 } // namespace 25 } // namespace
26 26
27 namespace webkit_media { 27 namespace webkit_media {
28 28
29 // Non-HTTP resources are assumed to be fully loaded so we ignore any
30 // loading/progress related callbacks.
31 static void NonHttpLoadingStateChangedCallback(
32 BufferedResourceLoader::LoadingState) {
33 }
34 static void NonHttpProgressCallback(int64) {}
35
36 BufferedDataSource::BufferedDataSource( 29 BufferedDataSource::BufferedDataSource(
37 MessageLoop* render_loop, 30 MessageLoop* render_loop,
38 WebFrame* frame, 31 WebFrame* frame,
39 media::MediaLog* media_log, 32 media::MediaLog* media_log,
40 const DownloadingCB& downloading_cb) 33 const DownloadingCB& downloading_cb)
41 : cors_mode_(BufferedResourceLoader::kUnspecified), 34 : cors_mode_(BufferedResourceLoader::kUnspecified),
42 total_bytes_(kPositionNotSpecified), 35 total_bytes_(kPositionNotSpecified),
43 assume_fully_buffered_(false), 36 assume_fully_buffered_(false),
44 streaming_(false), 37 streaming_(false),
45 frame_(frame), 38 frame_(frame),
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 DCHECK(!loader_.get()); 95 DCHECK(!loader_.get());
103 url_ = url; 96 url_ = url;
104 cors_mode_ = cors_mode; 97 cors_mode_ = cors_mode;
105 98
106 initialize_cb_ = initialize_cb; 99 initialize_cb_ = initialize_cb;
107 100
108 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { 101 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) {
109 // Do an unbounded range request starting at the beginning. If the server 102 // Do an unbounded range request starting at the beginning. If the server
110 // responds with 200 instead of 206 we'll fall back into a streaming mode. 103 // responds with 200 instead of 206 we'll fall back into a streaming mode.
111 loader_.reset(CreateResourceLoader(0, kPositionNotSpecified)); 104 loader_.reset(CreateResourceLoader(0, kPositionNotSpecified));
112 loader_->Start( 105 } else {
113 base::Bind(&BufferedDataSource::HttpInitialStartCallback, this), 106 // For all other protocols, assume they support range request. We fetch
114 base::Bind(&BufferedDataSource::HttpLoadingStateChangedCallback, this), 107 // the full range of the resource to obtain the instance size because
115 base::Bind(&BufferedDataSource::HttpProgressCallback, this), 108 // we won't be served HTTP headers.
116 frame_); 109 loader_.reset(CreateResourceLoader(kPositionNotSpecified,
117 return; 110 kPositionNotSpecified));
111 assume_fully_buffered_ = true;
scherkus (not reviewing) 2012/07/11 00:25:44 NOTE!!! my newly minted tests revealed that since
Ami GONE FROM CHROMIUM 2012/07/11 00:56:41 I mildly dislike that assume_fully_buffered_ === !
scherkus (not reviewing) 2012/07/11 18:39:02 That's true today but perhaps one day ftp:// (and
118 } 112 }
119 113
120 // For all other protocols, assume they support range request. We fetch
121 // the full range of the resource to obtain the instance size because
122 // we won't be served HTTP headers.
123 loader_.reset(CreateResourceLoader(kPositionNotSpecified,
124 kPositionNotSpecified));
125 loader_->Start( 114 loader_->Start(
126 base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this), 115 base::Bind(&BufferedDataSource::StartCallback, this),
127 base::Bind(&NonHttpLoadingStateChangedCallback), 116 base::Bind(&BufferedDataSource::LoadingStateChangedCallback, this),
128 base::Bind(&NonHttpProgressCallback), 117 base::Bind(&BufferedDataSource::ProgressCallback, this),
129 frame_); 118 frame_);
130 } 119 }
131 120
132 void BufferedDataSource::SetPreload(Preload preload) { 121 void BufferedDataSource::SetPreload(Preload preload) {
133 DCHECK(MessageLoop::current() == render_loop_); 122 DCHECK(MessageLoop::current() == render_loop_);
134 preload_ = preload; 123 preload_ = preload;
135 } 124 }
136 125
137 bool BufferedDataSource::HasSingleOrigin() { 126 bool BufferedDataSource::HasSingleOrigin() {
138 DCHECK(MessageLoop::current() == render_loop_); 127 DCHECK(MessageLoop::current() == render_loop_);
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 return; 260 return;
272 261
273 { 262 {
274 // If there's no outstanding read then return early. 263 // If there's no outstanding read then return early.
275 base::AutoLock auto_lock(lock_); 264 base::AutoLock auto_lock(lock_);
276 if (read_cb_.is_null()) 265 if (read_cb_.is_null())
277 return; 266 return;
278 } 267 }
279 268
280 // Start reading from where we last left off until the end of the resource. 269 // Start reading from where we last left off until the end of the resource.
281 loader_.reset( 270 loader_.reset(CreateResourceLoader(last_read_start_, kPositionNotSpecified));
282 CreateResourceLoader(last_read_start_, kPositionNotSpecified)); 271 loader_->Start(
283 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { 272 base::Bind(&BufferedDataSource::PartialReadStartCallback, this),
284 loader_->Start( 273 base::Bind(&BufferedDataSource::LoadingStateChangedCallback, this),
285 base::Bind(&BufferedDataSource::PartialReadStartCallback, this), 274 base::Bind(&BufferedDataSource::ProgressCallback, this),
286 base::Bind(&BufferedDataSource::HttpLoadingStateChangedCallback, this), 275 frame_);
287 base::Bind(&BufferedDataSource::HttpProgressCallback, this),
288 frame_);
289 } else {
290 loader_->Start(
291 base::Bind(&BufferedDataSource::PartialReadStartCallback, this),
292 base::Bind(&NonHttpLoadingStateChangedCallback),
293 base::Bind(&NonHttpProgressCallback),
294 frame_);
295 }
296 } 276 }
297 277
298 void BufferedDataSource::SetPlaybackRateTask(float playback_rate) { 278 void BufferedDataSource::SetPlaybackRateTask(float playback_rate) {
299 DCHECK(MessageLoop::current() == render_loop_); 279 DCHECK(MessageLoop::current() == render_loop_);
300 DCHECK(loader_.get()); 280 DCHECK(loader_.get());
301 281
302 if (playback_rate != 0) 282 if (playback_rate != 0)
303 media_has_played_ = true; 283 media_has_played_ = true;
304 284
305 playback_rate_ = playback_rate; 285 playback_rate_ = playback_rate;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 DCHECK(MessageLoop::current() == render_loop_); 348 DCHECK(MessageLoop::current() == render_loop_);
369 DCHECK(!initialize_cb_.is_null()); 349 DCHECK(!initialize_cb_.is_null());
370 lock_.AssertAcquired(); 350 lock_.AssertAcquired();
371 351
372 initialize_cb_.Run(status); 352 initialize_cb_.Run(status);
373 initialize_cb_.Reset(); 353 initialize_cb_.Reset();
374 } 354 }
375 355
376 ///////////////////////////////////////////////////////////////////////////// 356 /////////////////////////////////////////////////////////////////////////////
377 // BufferedResourceLoader callback methods. 357 // BufferedResourceLoader callback methods.
378 void BufferedDataSource::HttpInitialStartCallback( 358 void BufferedDataSource::StartCallback(
379 BufferedResourceLoader::Status status) { 359 BufferedResourceLoader::Status status) {
380 DCHECK(MessageLoop::current() == render_loop_); 360 DCHECK(MessageLoop::current() == render_loop_);
381 DCHECK(loader_.get()); 361 DCHECK(loader_.get());
382 362
383 bool initialize_cb_is_null = false; 363 bool initialize_cb_is_null = false;
384 { 364 {
385 base::AutoLock auto_lock(lock_); 365 base::AutoLock auto_lock(lock_);
386 initialize_cb_is_null = initialize_cb_.is_null(); 366 initialize_cb_is_null = initialize_cb_.is_null();
387 } 367 }
388 if (initialize_cb_is_null) { 368 if (initialize_cb_is_null) {
389 loader_->Stop(); 369 loader_->Stop();
390 return; 370 return;
391 } 371 }
392 372
393 bool success = status == BufferedResourceLoader::kOk; 373 // All responses must be successful. Resources that are assumed to be fully
374 // buffered must have a known content length.
375 bool success = status == BufferedResourceLoader::kOk &&
376 (!assume_fully_buffered_ ||
377 loader_->instance_size() != kPositionNotSpecified);
378
394 if (success) { 379 if (success) {
395 // TODO(hclam): Needs more thinking about supporting servers without range
396 // request or their partial response is not complete.
397 total_bytes_ = loader_->instance_size(); 380 total_bytes_ = loader_->instance_size();
398 streaming_ = (total_bytes_ == kPositionNotSpecified) || 381 streaming_ = !assume_fully_buffered_ &&
399 !loader_->range_supported(); 382 (total_bytes_ == kPositionNotSpecified || !loader_->range_supported());
400 } else { 383 } else {
401 // TODO(hclam): In case of failure, we can retry several times.
402 loader_->Stop(); 384 loader_->Stop();
403 } 385 }
404 386
405 // Reference to prevent destruction while inside the |initialize_cb_| 387 // TODO(scherkus): we shouldn't have to lock to signal host(), see
406 // call. This is a temporary fix to prevent crashes caused by holding the 388 // http://crbug.com/113712 for details.
407 // lock and running the destructor.
408 // TODO: Review locking in this class and figure out a way to run the callback
409 // w/o the lock.
410 scoped_refptr<BufferedDataSource> destruction_guard(this); 389 scoped_refptr<BufferedDataSource> destruction_guard(this);
411 { 390 {
412 // We need to prevent calling to filter host and running the callback if
413 // we have received the stop signal. We need to lock down the whole callback
414 // method to prevent bad things from happening. The reason behind this is
415 // that we cannot guarantee tasks on render thread have completely stopped
416 // when we receive the Stop() method call. The only way to solve this is to
417 // let tasks on render thread to run but make sure they don't call outside
418 // this object when Stop() method is ever called. Locking this method is
419 // safe because |lock_| is only acquired in tasks on render thread.
420 base::AutoLock auto_lock(lock_); 391 base::AutoLock auto_lock(lock_);
421 if (stop_signal_received_) 392 if (stop_signal_received_)
422 return; 393 return;
423 394
424 if (!success) { 395 if (!success) {
425 DoneInitialization_Locked(media::PIPELINE_ERROR_NETWORK);
426 return;
427 }
428
429 UpdateHostState_Locked();
430 DoneInitialization_Locked(media::PIPELINE_OK);
431 }
432 }
433
434 void BufferedDataSource::NonHttpInitialStartCallback(
435 BufferedResourceLoader::Status status) {
436 DCHECK(MessageLoop::current() == render_loop_);
437 DCHECK(loader_.get());
438
439 bool initialize_cb_is_null = false;
440 {
441 base::AutoLock auto_lock(lock_);
442 initialize_cb_is_null = initialize_cb_.is_null();
443 }
444 if (initialize_cb_is_null) {
445 loader_->Stop();
446 return;
447 }
448
449 int64 instance_size = loader_->instance_size();
450 bool success = status == BufferedResourceLoader::kOk &&
451 instance_size != kPositionNotSpecified;
452
453 if (success) {
454 total_bytes_ = instance_size;
455 assume_fully_buffered_ = true;
456 } else {
457 loader_->Stop();
458 }
459
460 // Reference to prevent destruction while inside the |initialize_cb_|
461 // call. This is a temporary fix to prevent crashes caused by holding the
462 // lock and running the destructor.
463 // TODO: Review locking in this class and figure out a way to run the callback
464 // w/o the lock.
465 scoped_refptr<BufferedDataSource> destruction_guard(this);
466 {
467 // We need to prevent calling to filter host and running the callback if
468 // we have received the stop signal. We need to lock down the whole callback
469 // method to prevent bad things from happening. The reason behind this is
470 // that we cannot guarantee tasks on render thread have completely stopped
471 // when we receive the Stop() method call. The only way to solve this is to
472 // let tasks on render thread to run but make sure they don't call outside
473 // this object when Stop() method is ever called. Locking this method is
474 // safe because |lock_| is only acquired in tasks on render thread.
475 base::AutoLock auto_lock(lock_);
476 if (stop_signal_received_ || initialize_cb_.is_null())
477 return;
478
479 if (!success) {
480 DoneInitialization_Locked(media::PIPELINE_ERROR_NETWORK); 396 DoneInitialization_Locked(media::PIPELINE_ERROR_NETWORK);
481 return; 397 return;
482 } 398 }
483 399
484 UpdateHostState_Locked(); 400 UpdateHostState_Locked();
485 DoneInitialization_Locked(media::PIPELINE_OK); 401 DoneInitialization_Locked(media::PIPELINE_OK);
486 } 402 }
487 } 403 }
488 404
489 void BufferedDataSource::PartialReadStartCallback( 405 void BufferedDataSource::PartialReadStartCallback(
490 BufferedResourceLoader::Status status) { 406 BufferedResourceLoader::Status status) {
491 DCHECK(MessageLoop::current() == render_loop_); 407 DCHECK(MessageLoop::current() == render_loop_);
492 DCHECK(loader_.get()); 408 DCHECK(loader_.get());
493 409
494 if (status == BufferedResourceLoader::kOk) { 410 if (status == BufferedResourceLoader::kOk) {
495 // Once the request has started successfully, we can proceed with 411 // Once the request has started successfully, we can proceed with
496 // reading from it. 412 // reading from it.
497 ReadInternal(); 413 ReadInternal();
498 return; 414 return;
499 } 415 }
500 416
501 // Stop the resource loader since we have received an error. 417 // Stop the resource loader since we have received an error.
502 loader_->Stop(); 418 loader_->Stop();
503 419
504 // We need to prevent calling to filter host and running the callback if 420 // TODO(scherkus): we shouldn't have to lock to signal host(), see
505 // we have received the stop signal. We need to lock down the whole callback 421 // http://crbug.com/113712 for details.
506 // method to prevent bad things from happening. The reason behind this is
507 // that we cannot guarantee tasks on render thread have completely stopped
508 // when we receive the Stop() method call. So only way to solve this is to
509 // let tasks on render thread to run but make sure they don't call outside
510 // this object when Stop() method is ever called. Locking this method is
511 // safe because |lock_| is only acquired in tasks on render thread.
512 base::AutoLock auto_lock(lock_); 422 base::AutoLock auto_lock(lock_);
513 if (stop_signal_received_) 423 if (stop_signal_received_)
514 return; 424 return;
515 DoneRead_Locked(kReadError); 425 DoneRead_Locked(kReadError);
516 } 426 }
517 427
518 void BufferedDataSource::ReadCallback( 428 void BufferedDataSource::ReadCallback(
519 BufferedResourceLoader::Status status, 429 BufferedResourceLoader::Status status,
520 int bytes_read) { 430 int bytes_read) {
521 DCHECK(MessageLoop::current() == render_loop_); 431 DCHECK(MessageLoop::current() == render_loop_);
(...skipping 30 matching lines...) Expand all
552 462
553 if (host() && total_bytes_ != kPositionNotSpecified) { 463 if (host() && total_bytes_ != kPositionNotSpecified) {
554 host()->SetTotalBytes(total_bytes_); 464 host()->SetTotalBytes(total_bytes_);
555 host()->AddBufferedByteRange(loader_->first_byte_position(), 465 host()->AddBufferedByteRange(loader_->first_byte_position(),
556 total_bytes_); 466 total_bytes_);
557 } 467 }
558 } 468 }
559 DoneRead_Locked(bytes_read); 469 DoneRead_Locked(bytes_read);
560 } 470 }
561 471
562 void BufferedDataSource::HttpLoadingStateChangedCallback( 472 void BufferedDataSource::LoadingStateChangedCallback(
563 BufferedResourceLoader::LoadingState state) { 473 BufferedResourceLoader::LoadingState state) {
564 DCHECK(MessageLoop::current() == render_loop_); 474 DCHECK(MessageLoop::current() == render_loop_);
565 DCHECK(url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)); 475
476 if (assume_fully_buffered_)
477 return;
566 478
567 bool is_downloading_data; 479 bool is_downloading_data;
568 switch (state) { 480 switch (state) {
569 case BufferedResourceLoader::kLoading: 481 case BufferedResourceLoader::kLoading:
570 is_downloading_data = true; 482 is_downloading_data = true;
571 break; 483 break;
572 case BufferedResourceLoader::kLoadingDeferred: 484 case BufferedResourceLoader::kLoadingDeferred:
573 is_downloading_data = false; 485 is_downloading_data = false;
574 break; 486 break;
575 487
576 // TODO(scherkus): we don't signal network activity changes when loads 488 // TODO(scherkus): we don't signal network activity changes when loads
577 // complete or fail to preserve existing behaviour when deferring is 489 // complete or fail to preserve existing behaviour when deferring is
578 // toggled, however we considering changing DownloadingCB to also 490 // toggled, however we considering changing DownloadingCB to also
579 // propagate loading state. For example there isn't any signal today 491 // propagate loading state. For example there isn't any signal today
580 // to notify the client that loading has failed/finished (we only get 492 // to notify the client that loading has failed/finished (we only get
581 // errors on subsequent reads). 493 // errors on subsequent reads).
582 case BufferedResourceLoader::kLoadingFailed: 494 case BufferedResourceLoader::kLoadingFailed:
583 case BufferedResourceLoader::kLoadingFinished: 495 case BufferedResourceLoader::kLoadingFinished:
584 return; 496 return;
585 } 497 }
586 498
587 downloading_cb_.Run(is_downloading_data); 499 downloading_cb_.Run(is_downloading_data);
588 } 500 }
589 501
590 void BufferedDataSource::HttpProgressCallback(int64 position) { 502 void BufferedDataSource::ProgressCallback(int64 position) {
591 DCHECK(MessageLoop::current() == render_loop_); 503 DCHECK(MessageLoop::current() == render_loop_);
592 DCHECK(url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)); 504
505 if (assume_fully_buffered_)
506 return;
593 507
594 // TODO(scherkus): we shouldn't have to lock to signal host(), see 508 // TODO(scherkus): we shouldn't have to lock to signal host(), see
595 // http://crbug.com/113712 for details. 509 // http://crbug.com/113712 for details.
596 base::AutoLock auto_lock(lock_); 510 base::AutoLock auto_lock(lock_);
597 if (stop_signal_received_) 511 if (stop_signal_received_)
598 return; 512 return;
599 513
600 if (host() && position > last_read_start_) 514 if (host() && position > last_read_start_)
601 host()->AddBufferedByteRange(last_read_start_, position); 515 host()->AddBufferedByteRange(last_read_start_, position);
602 } 516 }
603 517
604 void BufferedDataSource::UpdateHostState_Locked() { 518 void BufferedDataSource::UpdateHostState_Locked() {
605 lock_.AssertAcquired(); 519 lock_.AssertAcquired();
606 520
607 if (!host()) 521 if (!host())
608 return; 522 return;
609 523
610 if (total_bytes_ != kPositionNotSpecified) { 524 if (total_bytes_ != kPositionNotSpecified) {
611 host()->SetTotalBytes(total_bytes_); 525 host()->SetTotalBytes(total_bytes_);
612 526
613 if (assume_fully_buffered_) 527 if (assume_fully_buffered_)
614 host()->AddBufferedByteRange(0, total_bytes_); 528 host()->AddBufferedByteRange(0, total_bytes_);
615 } 529 }
616 } 530 }
617 531
618 } // namespace webkit_media 532 } // namespace webkit_media
OLDNEW
« no previous file with comments | « webkit/media/buffered_data_source.h ('k') | webkit/media/buffered_data_source_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698