text: // 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.
  
  // 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 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();
  
    // 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.
    size_t Read(uint8* data, size_t size);
  
    // Copies up to |size| bytes from current position to |data|. Returns
    // number of bytes copied. Doesn't advance current position.
    size_t Peek(uint8* data, size_t size);
  
    // 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, size_t* 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, size_t 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.
    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_; }
  
    // 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*, size_t), 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.
    size_t InternalRead(uint8* data, size_t size, bool advance_position);
  
    // 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);
  
    // Updates |current_time_| with the time that corresponds to the
    // specified position in the buffer.
    void UpdateCurrentTime(BufferQueue::iterator buffer, size_t offset);
  
    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_;
  
    // 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_
  