blob: 0a3ff72aa8e3ff93689c57631f0dd217608dd0cd [file] [log] [blame]
// Copyright (c) 2012 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.
// SeekableBuffer to support backward and forward seeking in a buffer for
// reading a media data source.
//
// In order to support backward and forward seeking, this class buffers data in
// both backward and forward directions, the current read position can be reset
// to anywhere in the buffered data.
//
// The amount of data buffered is regulated by two variables at construction,
// |backward_capacity| and |forward_capacity|.
//
// In the case of reading and seeking forward, the current read position
// advances and there will be more data in the backward direction. If backward
// bytes exceeds |backward_capacity|, the exceeding bytes are evicted and thus
// backward_bytes() will always be less than or equal to |backward_capacity|.
// The eviction will be caused by Read() and Seek() in the forward direction and
// is done internally when the mentioned criteria is fulfilled.
//
// In the case of appending data to the buffer, there is an advisory limit of
// how many bytes can be kept in the forward direction, regulated by
// |forward_capacity|. The append operation (by calling Append()) that caused
// forward bytes to exceed |forward_capacity| will have a return value that
// advises a halt of append operation, further append operations are allowed but
// are not advised. Since this class is used as a backend buffer for caching
// media files downloaded from network we cannot afford losing data, we can
// only advise a halt of further writing to this buffer.
// This class is not inherently thread-safe. Concurrent access must be
// externally serialized.
#ifndef MEDIA_BASE_SEEKABLE_BUFFER_H_
#define MEDIA_BASE_SEEKABLE_BUFFER_H_
#include <list>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "media/base/buffers.h"
namespace media {
class MEDIA_EXPORT SeekableBuffer {
public:
// Constructs an instance with |forward_capacity| and |backward_capacity|.
// The values are in bytes.
SeekableBuffer(int backward_capacity, int forward_capacity);
~SeekableBuffer();
// Clears the buffer queue.
void Clear();
// Reads a maximum of |size| bytes into |data| from the current read
// position. Returns the number of bytes read.
// The current read position will advance by the amount of bytes read. If
// reading caused backward_bytes() to exceed backward_capacity(), an eviction
// of the backward buffer will be done internally.
int Read(uint8* data, int size);
// Copies up to |size| bytes from current position to |data|. Returns
// number of bytes copied. Doesn't advance current position. Optionally
// starts at a |forward_offset| from current position.
int Peek(uint8* data, int size) { return Peek(data, size, 0); }
int Peek(uint8* data, int size, int forward_offset);
// Returns pointer to the current chunk of data that is being consumed.
// If there is no data left in the buffer false is returned, otherwise
// true is returned and |data| and |size| are updated. The returned
// |data| value becomes invalid when Read(), Append() or Seek()
// are called.
bool GetCurrentChunk(const uint8** data, int* size) const;
// Appends |buffer_in| to this buffer. Returns false if forward_bytes() is
// greater than or equals to forward_capacity(), true otherwise. The data
// is added to the buffer in any case.
bool Append(Buffer* buffer_in);
// Appends |size| bytes of |data| to the buffer. Result is the same
// as for Append(Buffer*).
bool Append(const uint8* data, int size);
// Moves the read position by |offset| bytes. If |offset| is positive, the
// current read position is moved forward. If negative, the current read
// position is moved backward. A zero |offset| value will keep the current
// read position stationary.
// If |offset| exceeds bytes buffered in either direction, reported by
// forward_bytes() when seeking forward and backward_bytes() when seeking
// backward, the seek operation will fail and return value will be false.
// If the seek operation fails, the current read position will not be updated.
// If a forward seeking caused backward_bytes() to exceed backward_capacity(),
// this method call will cause an eviction of the backward buffer.
bool Seek(int32 offset);
// Returns the number of bytes buffered beyond the current read position.
int forward_bytes() const { return forward_bytes_; }
// Returns the number of bytes buffered that precedes the current read
// position.
int backward_bytes() const { return backward_bytes_; }
// Sets the forward_capacity to |new_forward_capacity| bytes.
void set_forward_capacity(int new_forward_capacity) {
forward_capacity_ = new_forward_capacity;
}
// Sets the backward_capacity to |new_backward_capacity| bytes.
void set_backward_capacity(int new_backward_capacity) {
backward_capacity_ = new_backward_capacity;
}
// Returns the maximum number of bytes that should be kept in the forward
// direction.
int forward_capacity() const { return forward_capacity_; }
// Returns the maximum number of bytes that should be kept in the backward
// direction.
int backward_capacity() const { return backward_capacity_; }
// Returns the current timestamp, taking into account current offset. The
// value calculated based on the timestamp of the current buffer. If
// timestamp for the current buffer is set to 0 or the data was added with
// Append(const uint*, int), then returns value that corresponds to the
// last position in a buffer that had timestamp set.
// kNoTimestamp() is returned if no buffers we read from had timestamp set.
base::TimeDelta current_time() const { return current_time_; }
private:
// Definition of the buffer queue.
typedef std::list<scoped_refptr<Buffer> > BufferQueue;
// A helper method to evict buffers in the backward direction until backward
// bytes is within the backward capacity.
void EvictBackwardBuffers();
// An internal method shared by Read() and SeekForward() that actually does
// reading. It reads a maximum of |size| bytes into |data|. Returns the number
// of bytes read. The current read position will be moved forward by the
// number of bytes read. If |data| is NULL, only the current read position
// will advance but no data will be copied.
int InternalRead(
uint8* data, int size, bool advance_position, int forward_offset);
// A helper method that moves the current read position forward by |size|
// bytes.
// If the return value is true, the operation completed successfully.
// If the return value is false, |size| is greater than forward_bytes() and
// the seek operation failed. The current read position is not updated.
bool SeekForward(int size);
// A helper method that moves the current read position backward by |size|
// bytes.
// If the return value is true, the operation completed successfully.
// If the return value is false, |size| is greater than backward_bytes() and
// the seek operation failed. The current read position is not updated.
bool SeekBackward(int size);
// Updates |current_time_| with the time that corresponds to the
// specified position in the buffer.
void UpdateCurrentTime(BufferQueue::iterator buffer, int offset);
BufferQueue::iterator current_buffer_;
BufferQueue buffers_;
int current_buffer_offset_;
int backward_capacity_;
int backward_bytes_;
int forward_capacity_;
int forward_bytes_;
// Keeps track of the most recent time we've seen in case the |buffers_| is
// empty when our owner asks what time it is.
base::TimeDelta current_time_;
DISALLOW_COPY_AND_ASSIGN(SeekableBuffer);
};
} // namespace media
#endif // MEDIA_BASE_SEEKABLE_BUFFER_H_