Index: media/base/seekable_buffer.h |
=================================================================== |
--- media/base/seekable_buffer.h (revision 0) |
+++ media/base/seekable_buffer.h (revision 0) |
@@ -0,0 +1,132 @@ |
+// 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 <list> |
+ |
+#include "base/basictypes.h" |
+#include "base/lock.h" |
+#include "base/scoped_ptr.h" |
+ |
+namespace media { |
+ |
+class SeekableBuffer { |
+ public: |
+ // Construct an instance with forward capacity of |forward_capacity| |
+ // and backward capacity of |backward_capacity|. The values are in bytes. |
+ SeekableBuffer(size_t backward_capacity, size_t forward_capacity); |
+ |
+ ~SeekableBuffer(); |
+ |
+ // Read a maximum of |size| bytes into |buffer| from the current read |
+ // position. Return the number of bytes read. |
+ // The current read position will advances by the amount of bytes read. If |
+ // reading caused backward bytes to exceed backward_capacity(), an eviction |
+ // of backward buffer will be done internally. |
+ size_t Read(size_t size, uint8* buffer); |
+ |
+ // Append |data| with |size| bytes to this buffer. If this buffer becomes full |
+ // or is already full then return false, otherwise true. |
+ // Append operations are always successful, a return value of false only means |
+ // that there's more forward bytes than the capacity, data is still in this |
+ // buffer, but user is advised not to write any more. |
+ bool Append(size_t size, const uint8* data); |
+ |
+ // Move the read position by an offset of |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 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 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); |
+ |
+ bool SeekForward(size_t size); |
+ |
+ bool SeekBackward(size_t size); |
+ |
+ // 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<uint8> data; |
+ // Size of this block. |
+ size_t size; |
+ }; |
+ |
+ typedef std::list<Buffer*> BufferQueue; |
+ 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_ |