blob: 530f4032e4fbf80575152b1fadbb5bb91ebed053 [file] [log] [blame]
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COBALT_MEDIA_FETCHER_BUFFERED_DATA_SOURCE_H_
#define COBALT_MEDIA_FETCHER_BUFFERED_DATA_SOURCE_H_
#include <string>
#include "base/circular_buffer_shell.h"
#include "base/compiler_specific.h"
#include "base/message_loop_proxy.h"
#include "base/optional.h"
#include "base/synchronization/lock.h"
#include "cobalt/csp/content_security_policy.h"
#include "cobalt/network/network_module.h"
#include "googleurl/src/gurl.h"
#include "media/player/buffered_data_source.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
namespace cobalt {
namespace media {
// TODO: This class requires a large block of memory. Consider to
// use ShellBufferFactory for its memory if possible to avoid possible OOM.
// A BufferedDataSource based on URLFetcher that can be used to retrieve
// progressive videos from both local and network sources.
// It uses a fixed size circular buffer so we may not be able to store all data
// into this buffer. It is based on the following assumptions/strategies:
// 1. It assumes that the buffer is large enough to fulfill one Read() request.
// So any outstanding request only requires at most one request.
// 2. It will do one initial request to retrieve the target resource. If the
// whole resource can be fit into the buffer, no further request will be
// fired.
// 3. If the resource doesn't fit into the buffer. The class will store
// kBackwardBytes bytes before the last read offset(LRO) and kForwardBytes
// after LRO. Note that if LRO is less than kBackwardBytes, then data starts
// from offset 0 will be cached.
// 4. It assumes that the server supports range request.
// 5. All data stored are continuous.
class FetcherBufferedDataSource : public ::media::BufferedDataSource,
private net::URLFetcherDelegate {
public:
static const int64 kInvalidSize = -1;
// Because the Fetchers have to be created and destroyed on the same thread,
// we use the message_loop passed in to create and destroy Fetchers.
FetcherBufferedDataSource(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
const GURL& url, const csp::SecurityCallback& security_callback,
network::NetworkModule* network_module);
~FetcherBufferedDataSource() OVERRIDE;
// DataSource methods.
void Read(int64 position, int size, uint8* data,
const ReadCB& read_cb) OVERRIDE;
void Stop(const base::Closure& callback) OVERRIDE;
bool GetSize(int64* size_out) OVERRIDE;
bool IsStreaming() OVERRIDE { return false; }
void SetBitrate(int bitrate) OVERRIDE { UNREFERENCED_PARAMETER(bitrate); }
private:
// net::URLFetcherDelegate methods
void OnURLFetchResponseStarted(const net::URLFetcher* source) OVERRIDE;
bool ShouldSendDownloadData() OVERRIDE { return true; }
void OnURLFetchDownloadData(const net::URLFetcher* source,
scoped_ptr<std::string> download_data) OVERRIDE;
void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
// This function can be posted to |message_loop_| to destroy a fetcher on it.
void DestroyFetcher(scoped_ptr<net::URLFetcher> fetcher);
void CreateNewFetcher();
void Read_Locked(uint64 position, uint64 size, uint8* data,
const ReadCB& read_cb);
void ProcessPendingRead_Locked();
void TryToSendRequest_Locked();
base::Lock lock_;
scoped_refptr<base::MessageLoopProxy> message_loop_;
GURL url_;
network::NetworkModule* network_module_;
scoped_ptr<net::URLFetcher> fetcher_;
// |buffer_| stores a continuous block of data of target resource starts from
// |buffer_offset_|. When the target resource can be fit into |buffer_|,
// |buffer_offset_| will always be 0.
base::CircularBufferShell buffer_;
uint64 buffer_offset_;
base::optional<uint64> total_size_of_resource_;
bool error_occured_;
uint64 last_request_offset_;
uint64 last_request_size_;
// This is usually the same as pending_read_position_. Represent it
// explicitly using a separate variable.
uint64 last_read_position_;
ReadCB pending_read_cb_;
uint64 pending_read_position_;
uint64 pending_read_size_;
uint8* pending_read_data_;
csp::SecurityCallback security_callback_;
};
} // namespace media
} // namespace cobalt
#endif // COBALT_MEDIA_FETCHER_BUFFERED_DATA_SOURCE_H_