summaryrefslogtreecommitdiffstats
path: root/webkit/glue/media/buffered_data_source.cc
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-30 02:46:29 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-30 02:46:29 +0000
commit84b0cbf0fc3b8eafa444be319fd10bb33b5f0f79 (patch)
treef75771ca6eb4a2f09d1ba1d89cee20671edc0faa /webkit/glue/media/buffered_data_source.cc
parentc0222007b5c580f0d5b8332e491c12918c9bad04 (diff)
downloadchromium_src-84b0cbf0fc3b8eafa444be319fd10bb33b5f0f79.zip
chromium_src-84b0cbf0fc3b8eafa444be319fd10bb33b5f0f79.tar.gz
chromium_src-84b0cbf0fc3b8eafa444be319fd10bb33b5f0f79.tar.bz2
Change how <video> fetch a resource to make it friendly to sparse caching
BUG=16013 TEST=test_shell_tests --gtest_filter=Buffered* Also video on a server that doesn't support range request will still work. How <video> used to fetch a resource: 1. Fetch the whole file to get the header 2. Fetch a small range (1, 1) to determine if server supports range request 3. If [2] was successful, then fetch the file with range request if necessary If [2] failed, prevent range request by telling ffmpeg this is streaming New way of fetching a resource for <video>: 1. Fetch (0, 1023) to get the header (This needs more experiment). 2. If [1] was successful, then request later on will be made partial If [1] failed, prevent range request by telling ffmpeg this is streaming By doing this change we can eliminate one request before we can start the file. And with the help of sparse cache, we would be able to reuse the first 1KB fetched even we need to fetch the index at the end of file. Review URL: http://codereview.chromium.org/248012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27587 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/media/buffered_data_source.cc')
-rw-r--r--webkit/glue/media/buffered_data_source.cc102
1 files changed, 35 insertions, 67 deletions
diff --git a/webkit/glue/media/buffered_data_source.cc b/webkit/glue/media/buffered_data_source.cc
index 36e43d0..6efaa8c 100644
--- a/webkit/glue/media/buffered_data_source.cc
+++ b/webkit/glue/media/buffered_data_source.cc
@@ -72,6 +72,7 @@ BufferedResourceLoader::BufferedResourceLoader(
deferred_(false),
completed_(false),
range_requested_(false),
+ partial_response_(false),
bridge_factory_(bridge_factory),
url_(url),
first_byte_position_(first_byte_position),
@@ -235,14 +236,19 @@ void BufferedResourceLoader::OnReceivedResponse(
// We expect to receive headers because this is a HTTP or HTTPS protocol,
// if not report failure.
error = net::ERR_INVALID_RESPONSE;
- } else if (range_requested_) {
- // If we have verified the partial response and it is correct, we will
- // return net::OK.
- if (!VerifyPartialResponse(info))
- error = net::ERR_REQUEST_RANGE_NOT_SATISFIABLE;
- } else if (info.headers->response_code() != kHttpOK) {
- // We didn't request a range but server didn't reply with "200 OK".
- error = net::ERR_FAILED;
+ } else {
+ if (info.headers->response_code() == kHttpPartialContent)
+ partial_response_ = true;
+
+ if (range_requested_ && partial_response_) {
+ // If we have verified the partial response and it is correct, we will
+ // return net::OK.
+ if (!VerifyPartialResponse(info))
+ error = net::ERR_INVALID_RESPONSE;
+ } else if (info.headers->response_code() != kHttpOK) {
+ // We didn't request a range but server didn't reply with "200 OK".
+ error = net::ERR_FAILED;
+ }
}
if (error != net::OK) {
@@ -250,6 +256,10 @@ void BufferedResourceLoader::OnReceivedResponse(
Stop();
return;
}
+ } else {
+ // For any protocol other than HTTP and HTTPS, assume range request is
+ // always fulfilled.
+ partial_response_ = range_requested_;
}
// |info.content_length| can be -1, in that case |content_length_| is
@@ -258,7 +268,7 @@ void BufferedResourceLoader::OnReceivedResponse(
// If we have not requested a range, then the size of the instance is equal
// to the content length.
- if (!range_requested_)
+ if (!partial_response_)
instance_size_ = content_length_;
// Calls with a successful response.
@@ -418,9 +428,6 @@ void BufferedResourceLoader::DoneStart(int error) {
bool BufferedResourceLoader::VerifyPartialResponse(
const ResourceLoaderBridge::ResponseInfo& info) {
- if (info.headers->response_code() != kHttpPartialContent)
- return false;
-
int64 first_byte_position, last_byte_position, instance_size;
if (!info.headers->GetContentRange(&first_byte_position,
&last_byte_position,
@@ -455,8 +462,6 @@ BufferedDataSource::BufferedDataSource(
read_position_(0),
read_size_(0),
read_buffer_(NULL),
- initial_response_received_(false),
- probe_response_received_(false),
intermediate_read_buffer_(new uint8[kInitialReadBufferSize]),
intermediate_read_buffer_size_(kInitialReadBufferSize),
render_loop_(render_loop),
@@ -551,7 +556,6 @@ bool BufferedDataSource::IsStreaming() {
void BufferedDataSource::InitializeTask() {
DCHECK(MessageLoop::current() == render_loop_);
DCHECK(!loader_.get());
- DCHECK(!probe_loader_.get());
// Kick starts the watch dog task that will handle connection timeout.
// We run the watch dog 2 times faster the actual timeout so as to catch
@@ -561,18 +565,13 @@ void BufferedDataSource::InitializeTask() {
this,
&BufferedDataSource::WatchDogTask);
- // Creates a new resource loader with the full range and a probe resource
- // loader. Creates a probe resource loader to make sure the server supports
- // partial range request.
- // TODO(hclam): Only request 1 byte for this probe request, it may be useful
- // that we perform a suffix range request and fetch the index. That way we
- // can minimize the number of requests made.
- loader_ = CreateLoader(-1, -1);
- probe_loader_ = CreateLoader(1, 1);
-
+ // Fetch only first 1024 bytes as this usually covers the header portion
+ // of a media file that gives enough information about the codecs, etc.
+ // This also serve as a probe to determine server capability to serve
+ // range request.
+ // TODO(hclam): Do some experiments for the best approach.
+ loader_ = CreateLoader(0, 1024);
loader_->Start(NewCallback(this, &BufferedDataSource::InitialStartCallback));
- probe_loader_->Start(
- NewCallback(this, &BufferedDataSource::ProbeStartCallback));
}
void BufferedDataSource::ReadTask(
@@ -612,10 +611,6 @@ void BufferedDataSource::StopTask() {
if (loader_.get())
loader_->Stop();
- // If the probe request is still active, stop it too.
- if (probe_loader_.get())
- probe_loader_->Stop();
-
// Reset the parameters of the current read request.
read_callback_.reset();
read_position_ = 0;
@@ -731,21 +726,21 @@ void BufferedDataSource::InitialStartCallback(int error) {
// TODO(hclam): In case of failure, we can retry several times.
host()->SetError(media::PIPELINE_ERROR_NETWORK);
DCHECK(loader_.get());
- DCHECK(probe_loader_.get());
loader_->Stop();
- probe_loader_->Stop();
DoneInitialization();
return;
}
+ // TODO(hclam): Needs more thinking about supporting servers without range
+ // request or their partial response is not complete.
total_bytes_ = loader_->instance_size();
- if (total_bytes_ >= 0) {
+ if (total_bytes_ >= 0 && loader_->partial_response()) {
// This value governs the range that we can seek to.
// TODO(hclam): Report the correct value of buffered bytes.
host()->SetTotalBytes(total_bytes_);
host()->SetBufferedBytes(total_bytes_);
} else {
- // If the server didn't reply with a content length, it is likely this
+ // If the server didn't reply with an instance size, it is likely this
// is a streaming response.
streaming_ = true;
host()->SetStreaming(true);
@@ -753,45 +748,18 @@ void BufferedDataSource::InitialStartCallback(int error) {
// Currently, only files can be used reliably w/o a network.
host()->SetLoaded(url_.SchemeIsFile());
-
- initial_response_received_ = true;
- if (probe_response_received_)
- DoneInitialization();
-}
-
-void BufferedDataSource::ProbeStartCallback(int error) {
- DCHECK(MessageLoop::current() == render_loop_);
-
- // We need to prevent calling to filter host and running the callback if
- // we have received the stop signal. We need to lock down the whole callback
- // method to prevent bad things from happening. The reason behind this is
- // that we cannot guarantee tasks on render thread have completely stopped
- // when we receive the Stop() method call. The only way to solve this is to
- // let tasks on render thread to run but make sure they don't call outside
- // this object when Stop() method is ever called. Locking this method is safe
- // because |lock_| is only acquired in tasks on render thread.
- AutoLock auto_lock(lock_);
- if (stopped_)
- return;
-
- if (error != net::OK) {
- streaming_ = true;
- host()->SetStreaming(true);
- }
-
- DCHECK(probe_loader_.get());
- probe_loader_->Stop();
- probe_response_received_ = true;
- if (initial_response_received_)
- DoneInitialization();
+ DoneInitialization();
}
void BufferedDataSource::PartialReadStartCallback(int error) {
DCHECK(MessageLoop::current() == render_loop_);
DCHECK(loader_.get());
- if (error == net::OK) {
- // Once the range request has start successfully, we can proceed with
+ // This callback method is invoked after we have verified the server has
+ // range request capability, so as a safety guard verify again the response
+ // is partial.
+ if (error == net::OK && loader_->partial_response()) {
+ // Once the range request has started successfully, we can proceed with
// reading from it.
ReadInternal();
} else {