// Copyright (c) 2009 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 #include "base/basictypes.h" #include "base/lock.h" #include "base/scoped_ptr.h" namespace media { class SeekableBuffer { public: // Constructs an instance with |forward_capacity| and |backward_capacity|. // The values are in bytes. SeekableBuffer(size_t backward_capacity, size_t forward_capacity); ~SeekableBuffer(); // Reads a maximum of |size| bytes into |buffer| 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. size_t Read(size_t size, uint8* buffer); // Appends |data| with |size| bytes to this buffer. If this buffer becomes // full or is already full then returns false, otherwise returns true. // Append operations are always successful. A return value of false only means // that forward_bytes() is greater than or equals to forward_capacity(). Data // appended is still in this buffer but user is advised not to write any more. bool Append(size_t size, const uint8* data); // 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. size_t forward_bytes() const { return forward_bytes_; } // Returns the number of bytes buffered that precedes the current read // position. size_t backward_bytes() const { return backward_bytes_; } // Returns the maximum number of bytes that should be kept in the forward // direction. size_t forward_capacity() const { return forward_capacity_; } // Returns the maximum number of bytes that should be kept in the backward // direction. size_t backward_capacity() const { return backward_capacity_; } private: // A structure that contains a block of data. struct Buffer { explicit Buffer(size_t len) : data(new uint8[len]), size(len) {} // Pointer to data. scoped_array data; // Size of this block. size_t size; }; // Definition of the buffer queue. typedef std::list 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. size_t InternalRead(size_t size, uint8* data); // 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(size_t 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(size_t size); BufferQueue::iterator current_buffer_; BufferQueue buffers_; size_t current_buffer_offset_; size_t backward_capacity_; size_t backward_bytes_; size_t forward_capacity_; size_t forward_bytes_; }; } // namespace media #endif // MEDIA_BASE_SEEKABLE_BUFFER_H_