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

Unified Diff: webkit/glue/media/buffered_data_source.cc

Issue 8570010: Moving media-related files from webkit/glue/ to webkit/media/. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src
Patch Set: minor fixes Created 9 years, 1 month 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webkit/glue/media/buffered_data_source.h ('k') | webkit/glue/media/buffered_data_source_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webkit/glue/media/buffered_data_source.cc
diff --git a/webkit/glue/media/buffered_data_source.cc b/webkit/glue/media/buffered_data_source.cc
deleted file mode 100644
index a3f43cf5d2bb218d092bfcb8f9b73a0c512215db..0000000000000000000000000000000000000000
--- a/webkit/glue/media/buffered_data_source.cc
+++ /dev/null
@@ -1,672 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "webkit/glue/media/buffered_data_source.h"
-
-#include "base/bind.h"
-#include "media/base/filter_host.h"
-#include "media/base/media_log.h"
-#include "net/base/net_errors.h"
-#include "webkit/glue/media/web_data_source_factory.h"
-#include "webkit/glue/webkit_glue.h"
-
-using WebKit::WebFrame;
-
-namespace webkit_glue {
-
-// BufferedDataSource has an intermediate buffer, this value governs the initial
-// size of that buffer. It is set to 32KB because this is a typical read size
-// of FFmpeg.
-static const int kInitialReadBufferSize = 32768;
-
-// Number of cache misses we allow for a single Read() before signalling an
-// error.
-static const int kNumCacheMissRetries = 3;
-
-static WebDataSource* NewBufferedDataSource(MessageLoop* render_loop,
- WebKit::WebFrame* frame,
- media::MediaLog* media_log) {
- return new BufferedDataSource(render_loop, frame, media_log);
-}
-
-// static
-media::DataSourceFactory* BufferedDataSource::CreateFactory(
- MessageLoop* render_loop,
- WebKit::WebFrame* frame,
- media::MediaLog* media_log,
- const WebDataSourceBuildObserverHack& build_observer) {
- return new WebDataSourceFactory(render_loop, frame, media_log,
- &NewBufferedDataSource, build_observer);
-}
-
-BufferedDataSource::BufferedDataSource(
- MessageLoop* render_loop,
- WebFrame* frame,
- media::MediaLog* media_log)
- : total_bytes_(kPositionNotSpecified),
- buffered_bytes_(0),
- loaded_(false),
- streaming_(false),
- frame_(frame),
- loader_(NULL),
- is_downloading_data_(false),
- read_position_(0),
- read_size_(0),
- read_buffer_(NULL),
- intermediate_read_buffer_(new uint8[kInitialReadBufferSize]),
- intermediate_read_buffer_size_(kInitialReadBufferSize),
- render_loop_(render_loop),
- stop_signal_received_(false),
- stopped_on_render_loop_(false),
- media_is_paused_(true),
- media_has_played_(false),
- preload_(media::AUTO),
- using_range_request_(true),
- cache_miss_retries_left_(kNumCacheMissRetries),
- bitrate_(0),
- playback_rate_(0.0),
- media_log_(media_log) {
-}
-
-BufferedDataSource::~BufferedDataSource() {}
-
-// A factory method to create BufferedResourceLoader using the read parameters.
-// This method can be overrided to inject mock BufferedResourceLoader object
-// for testing purpose.
-BufferedResourceLoader* BufferedDataSource::CreateResourceLoader(
- int64 first_byte_position, int64 last_byte_position) {
- DCHECK(MessageLoop::current() == render_loop_);
-
- return new BufferedResourceLoader(url_,
- first_byte_position,
- last_byte_position,
- ChooseDeferStrategy(),
- bitrate_,
- playback_rate_,
- media_log_);
-}
-
-void BufferedDataSource::set_host(media::FilterHost* host) {
- DataSource::set_host(host);
-
- if (loader_.get()) {
- base::AutoLock auto_lock(lock_);
- UpdateHostState_Locked();
- }
-}
-
-void BufferedDataSource::Initialize(const std::string& url,
- const media::PipelineStatusCB& callback) {
- // Saves the url.
- url_ = GURL(url);
-
- // This data source doesn't support data:// protocol so reject it.
- if (url_.SchemeIs(kDataScheme)) {
- callback.Run(media::DATASOURCE_ERROR_URL_NOT_SUPPORTED);
- return;
- } else if (!IsProtocolSupportedForMedia(url_)) {
- callback.Run(media::PIPELINE_ERROR_NETWORK);
- return;
- }
-
- DCHECK(!callback.is_null());
- {
- base::AutoLock auto_lock(lock_);
- initialize_cb_ = callback;
- }
-
- // Post a task to complete the initialization task.
- render_loop_->PostTask(FROM_HERE,
- base::Bind(&BufferedDataSource::InitializeTask, this));
-}
-
-void BufferedDataSource::CancelInitialize() {
- base::AutoLock auto_lock(lock_);
- DCHECK(!initialize_cb_.is_null());
-
- initialize_cb_.Reset();
-
- render_loop_->PostTask(
- FROM_HERE, base::Bind(&BufferedDataSource::CleanupTask, this));
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// media::Filter implementation.
-void BufferedDataSource::Stop(const base::Closure& callback) {
- {
- base::AutoLock auto_lock(lock_);
- stop_signal_received_ = true;
- }
- if (!callback.is_null())
- callback.Run();
-
- render_loop_->PostTask(FROM_HERE,
- base::Bind(&BufferedDataSource::CleanupTask, this));
-}
-
-void BufferedDataSource::SetPlaybackRate(float playback_rate) {
- render_loop_->PostTask(FROM_HERE, base::Bind(
- &BufferedDataSource::SetPlaybackRateTask, this, playback_rate));
-}
-
-void BufferedDataSource::SetPreload(media::Preload preload) {
- render_loop_->PostTask(FROM_HERE, base::Bind(
- &BufferedDataSource::SetPreloadTask, this, preload));
-}
-
-void BufferedDataSource::SetBitrate(int bitrate) {
- render_loop_->PostTask(FROM_HERE, base::Bind(
- &BufferedDataSource::SetBitrateTask, this, bitrate));
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// media::DataSource implementation.
-void BufferedDataSource::Read(
- int64 position, size_t size, uint8* data,
- const media::DataSource::ReadCallback& read_callback) {
- VLOG(1) << "Read: " << position << " offset, " << size << " bytes";
- DCHECK(!read_callback.is_null());
-
- {
- base::AutoLock auto_lock(lock_);
- DCHECK(read_callback_.is_null());
-
- if (stop_signal_received_ || stopped_on_render_loop_) {
- read_callback.Run(kReadError);
- return;
- }
-
- read_callback_ = read_callback;
- }
-
- render_loop_->PostTask(FROM_HERE, base::Bind(
- &BufferedDataSource::ReadTask, this,
- position, static_cast<int>(size), data));
-}
-
-bool BufferedDataSource::GetSize(int64* size_out) {
- if (total_bytes_ != kPositionNotSpecified) {
- *size_out = total_bytes_;
- return true;
- }
- *size_out = 0;
- return false;
-}
-
-bool BufferedDataSource::IsStreaming() {
- return streaming_;
-}
-
-bool BufferedDataSource::HasSingleOrigin() {
- DCHECK(MessageLoop::current() == render_loop_);
- return loader_.get() ? loader_->HasSingleOrigin() : true;
-}
-
-void BufferedDataSource::Abort() {
- DCHECK(MessageLoop::current() == render_loop_);
-
- CleanupTask();
- frame_ = NULL;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Render thread tasks.
-void BufferedDataSource::InitializeTask() {
- DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(!loader_.get());
-
- {
- base::AutoLock auto_lock(lock_);
- if (stopped_on_render_loop_ || initialize_cb_.is_null() ||
- stop_signal_received_) {
- return;
- }
- }
-
- if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) {
- // Do an unbounded range request starting at the beginning. If the server
- // responds with 200 instead of 206 we'll fall back into a streaming mode.
- loader_ = CreateResourceLoader(0, kPositionNotSpecified);
- loader_->Start(
- NewCallback(this, &BufferedDataSource::HttpInitialStartCallback),
- base::Bind(&BufferedDataSource::NetworkEventCallback, this),
- frame_);
- } else {
- // For all other protocols, assume they support range request. We fetch
- // the full range of the resource to obtain the instance size because
- // we won't be served HTTP headers.
- loader_ = CreateResourceLoader(kPositionNotSpecified,
- kPositionNotSpecified);
- loader_->Start(
- NewCallback(this, &BufferedDataSource::NonHttpInitialStartCallback),
- base::Bind(&BufferedDataSource::NetworkEventCallback, this),
- frame_);
- }
-}
-
-void BufferedDataSource::ReadTask(
- int64 position,
- int read_size,
- uint8* buffer) {
- DCHECK(MessageLoop::current() == render_loop_);
- {
- base::AutoLock auto_lock(lock_);
- if (stopped_on_render_loop_)
- return;
-
- DCHECK(!read_callback_.is_null());
- }
-
- // Saves the read parameters.
- read_position_ = position;
- read_size_ = read_size;
- read_buffer_ = buffer;
- cache_miss_retries_left_ = kNumCacheMissRetries;
-
- // Call to read internal to perform the actual read.
- ReadInternal();
-}
-
-void BufferedDataSource::CleanupTask() {
- DCHECK(MessageLoop::current() == render_loop_);
-
- {
- base::AutoLock auto_lock(lock_);
- initialize_cb_.Reset();
- if (stopped_on_render_loop_)
- return;
-
- // Signal that stop task has finished execution.
- // NOTE: it's vital that this be set under lock, as that's how Read() tests
- // before registering a new |read_callback_| (which is cleared below).
- stopped_on_render_loop_ = true;
-
- if (!read_callback_.is_null())
- DoneRead_Locked(net::ERR_FAILED);
- }
-
- // We just need to stop the loader, so it stops activity.
- if (loader_.get())
- loader_->Stop();
-
- // Reset the parameters of the current read request.
- read_position_ = 0;
- read_size_ = 0;
- read_buffer_ = 0;
-}
-
-void BufferedDataSource::RestartLoadingTask() {
- DCHECK(MessageLoop::current() == render_loop_);
- if (stopped_on_render_loop_)
- return;
-
- {
- // If there's no outstanding read then return early.
- base::AutoLock auto_lock(lock_);
- if (read_callback_.is_null())
- return;
- }
-
- loader_ = CreateResourceLoader(read_position_, kPositionNotSpecified);
- loader_->Start(
- NewCallback(this, &BufferedDataSource::PartialReadStartCallback),
- base::Bind(&BufferedDataSource::NetworkEventCallback, this),
- frame_);
-}
-
-void BufferedDataSource::SetPlaybackRateTask(float playback_rate) {
- DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(loader_.get());
-
- playback_rate_ = playback_rate;
- loader_->SetPlaybackRate(playback_rate);
-
- bool previously_paused = media_is_paused_;
- media_is_paused_ = (playback_rate == 0.0);
-
- if (!media_has_played_ && previously_paused && !media_is_paused_)
- media_has_played_ = true;
-
- BufferedResourceLoader::DeferStrategy strategy = ChooseDeferStrategy();
- loader_->UpdateDeferStrategy(strategy);
-}
-
-void BufferedDataSource::SetPreloadTask(media::Preload preload) {
- DCHECK(MessageLoop::current() == render_loop_);
- preload_ = preload;
-}
-
-void BufferedDataSource::SetBitrateTask(int bitrate) {
- DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(loader_.get());
-
- bitrate_ = bitrate;
- loader_->SetBitrate(bitrate);
-}
-
-BufferedResourceLoader::DeferStrategy
-BufferedDataSource::ChooseDeferStrategy() {
- DCHECK(MessageLoop::current() == render_loop_);
- // If the page indicated preload=metadata, then load exactly what is needed
- // needed for starting playback.
- if (!media_has_played_ && preload_ == media::METADATA)
- return BufferedResourceLoader::kReadThenDefer;
-
- // If the playback has started (at which point the preload value is ignored)
- // and we're paused, then try to load as much as possible.
- if (media_has_played_ && media_is_paused_)
- return BufferedResourceLoader::kNeverDefer;
-
- // If media is currently playing or the page indicated preload=auto,
- // use threshold strategy to enable/disable deferring when the buffer
- // is full/depleted.
- return BufferedResourceLoader::kThresholdDefer;
-}
-
-// This method is the place where actual read happens, |loader_| must be valid
-// prior to make this method call.
-void BufferedDataSource::ReadInternal() {
- DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(loader_);
-
- // First we prepare the intermediate read buffer for BufferedResourceLoader
- // to write to.
- if (read_size_ > intermediate_read_buffer_size_) {
- intermediate_read_buffer_.reset(new uint8[read_size_]);
- }
-
- // Perform the actual read with BufferedResourceLoader.
- loader_->Read(read_position_, read_size_, intermediate_read_buffer_.get(),
- NewCallback(this, &BufferedDataSource::ReadCallback));
-}
-
-// Method to report the results of the current read request. Also reset all
-// the read parameters.
-void BufferedDataSource::DoneRead_Locked(int error) {
- VLOG(1) << "DoneRead: " << error << " bytes";
-
- DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(!read_callback_.is_null());
- lock_.AssertAcquired();
-
- if (error >= 0) {
- read_callback_.Run(static_cast<size_t>(error));
- } else {
- read_callback_.Run(kReadError);
- }
-
- read_callback_.Reset();
- read_position_ = 0;
- read_size_ = 0;
- read_buffer_ = 0;
-}
-
-void BufferedDataSource::DoneInitialization_Locked(
- media::PipelineStatus status) {
- DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(!initialize_cb_.is_null());
- lock_.AssertAcquired();
-
- initialize_cb_.Run(status);
- initialize_cb_.Reset();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// BufferedResourceLoader callback methods.
-void BufferedDataSource::HttpInitialStartCallback(int error) {
- DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(loader_.get());
-
- int64 instance_size = loader_->instance_size();
- bool success = error == net::OK;
-
- bool initialize_cb_is_null = false;
- {
- base::AutoLock auto_lock(lock_);
- initialize_cb_is_null = initialize_cb_.is_null();
- }
- if (initialize_cb_is_null) {
- loader_->Stop();
- return;
- }
-
- if (success) {
- // TODO(hclam): Needs more thinking about supporting servers without range
- // request or their partial response is not complete.
- total_bytes_ = instance_size;
- loaded_ = false;
- streaming_ = (instance_size == kPositionNotSpecified) ||
- !loader_->range_supported();
- } else {
- // TODO(hclam): In case of failure, we can retry several times.
- loader_->Stop();
- }
-
- if (error == net::ERR_INVALID_RESPONSE && using_range_request_) {
- // Assuming that the Range header was causing the problem. Retry without
- // the Range header.
- using_range_request_ = false;
- loader_ = CreateResourceLoader(kPositionNotSpecified,
- kPositionNotSpecified);
- loader_->Start(
- NewCallback(this, &BufferedDataSource::HttpInitialStartCallback),
- base::Bind(&BufferedDataSource::NetworkEventCallback, this),
- frame_);
- return;
- }
-
- // Reference to prevent destruction while inside the |initialize_cb_|
- // call. This is a temporary fix to prevent crashes caused by holding the
- // lock and running the destructor.
- // TODO: Review locking in this class and figure out a way to run the callback
- // w/o the lock.
- scoped_refptr<BufferedDataSource> destruction_guard(this);
- {
- // 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.
- base::AutoLock auto_lock(lock_);
- if (stop_signal_received_)
- return;
-
- if (!success) {
- DoneInitialization_Locked(media::PIPELINE_ERROR_NETWORK);
- return;
- }
-
- UpdateHostState_Locked();
- DoneInitialization_Locked(media::PIPELINE_OK);
- }
-}
-
-void BufferedDataSource::NonHttpInitialStartCallback(int error) {
- DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(loader_.get());
-
- bool initialize_cb_is_null = false;
- {
- base::AutoLock auto_lock(lock_);
- initialize_cb_is_null = initialize_cb_.is_null();
- }
- if (initialize_cb_is_null) {
- loader_->Stop();
- return;
- }
-
- int64 instance_size = loader_->instance_size();
- bool success = error == net::OK && instance_size != kPositionNotSpecified;
-
- if (success) {
- total_bytes_ = instance_size;
- buffered_bytes_ = total_bytes_;
- loaded_ = true;
- } else {
- loader_->Stop();
- }
-
- // Reference to prevent destruction while inside the |initialize_cb_|
- // call. This is a temporary fix to prevent crashes caused by holding the
- // lock and running the destructor.
- // TODO: Review locking in this class and figure out a way to run the callback
- // w/o the lock.
- scoped_refptr<BufferedDataSource> destruction_guard(this);
- {
- // 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.
- base::AutoLock auto_lock(lock_);
- if (stop_signal_received_ || initialize_cb_.is_null())
- return;
-
- if (!success) {
- DoneInitialization_Locked(media::PIPELINE_ERROR_NETWORK);
- return;
- }
-
- UpdateHostState_Locked();
- DoneInitialization_Locked(media::PIPELINE_OK);
- }
-}
-
-void BufferedDataSource::PartialReadStartCallback(int error) {
- DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(loader_.get());
-
- if (error == net::OK) {
- // Once the request has started successfully, we can proceed with
- // reading from it.
- ReadInternal();
- return;
- }
-
- // Stop the resource loader since we have received an error.
- loader_->Stop();
-
- // 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. So 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.
- base::AutoLock auto_lock(lock_);
- if (stop_signal_received_)
- return;
- DoneRead_Locked(net::ERR_INVALID_RESPONSE);
-}
-
-void BufferedDataSource::ReadCallback(int error) {
- DCHECK(MessageLoop::current() == render_loop_);
-
- if (error < 0) {
- DCHECK(loader_.get());
-
- // Stop the resource load if it failed.
- loader_->Stop();
-
- if (error == net::ERR_CACHE_MISS && cache_miss_retries_left_ > 0) {
- cache_miss_retries_left_--;
- render_loop_->PostTask(FROM_HERE,
- base::Bind(&BufferedDataSource::RestartLoadingTask, this));
- return;
- }
- }
-
- // 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. So 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.
- base::AutoLock auto_lock(lock_);
- if (stop_signal_received_)
- return;
-
- if (error > 0) {
- // If a position error code is received, read was successful. So copy
- // from intermediate read buffer to the target read buffer.
- memcpy(read_buffer_, intermediate_read_buffer_.get(), error);
- } else if (error == 0 && total_bytes_ == kPositionNotSpecified) {
- // We've reached the end of the file and we didn't know the total size
- // before. Update the total size so Read()s past the end of the file will
- // fail like they would if we had known the file size at the beginning.
- total_bytes_ = loader_->instance_size();
-
- if (host() && total_bytes_ != kPositionNotSpecified)
- host()->SetTotalBytes(total_bytes_);
- }
- DoneRead_Locked(error);
-}
-
-void BufferedDataSource::NetworkEventCallback() {
- DCHECK(MessageLoop::current() == render_loop_);
- DCHECK(loader_.get());
-
- // In case of non-HTTP request we don't need to report network events,
- // so return immediately.
- if (loaded_)
- return;
-
- bool is_downloading_data = loader_->is_downloading_data();
- int64 buffered_position = loader_->GetBufferedPosition();
-
- // If we get an unspecified value, return immediately.
- if (buffered_position == kPositionNotSpecified)
- return;
-
- // 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. So 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.
- base::AutoLock auto_lock(lock_);
- if (stop_signal_received_)
- return;
-
- if (is_downloading_data != is_downloading_data_) {
- is_downloading_data_ = is_downloading_data;
- if (host())
- host()->SetNetworkActivity(is_downloading_data);
- }
-
- buffered_bytes_ = buffered_position + 1;
- if (host())
- host()->SetBufferedBytes(buffered_bytes_);
-}
-
-void BufferedDataSource::UpdateHostState_Locked() {
- // Called from various threads, under lock.
- lock_.AssertAcquired();
-
- media::FilterHost* filter_host = host();
- if (!filter_host)
- return;
-
- filter_host->SetLoaded(loaded_);
-
- if (streaming_) {
- filter_host->SetStreaming(true);
- } else {
- filter_host->SetTotalBytes(total_bytes_);
- filter_host->SetBufferedBytes(buffered_bytes_);
- }
-}
-
-} // namespace webkit_glue
« no previous file with comments | « webkit/glue/media/buffered_data_source.h ('k') | webkit/glue/media/buffered_data_source_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698