1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// SeekableBuffer to support backward and forward seeking in a buffer for
6// reading a media data source.
7//
8// In order to support backward and forward seeking, this class buffers data in
9// both backward and forward directions, the current read position can be reset
10// to anywhere in the buffered data.
11//
12// The amount of data buffered is regulated by two variables at construction,
13// |backward_capacity| and |forward_capacity|.
14//
15// In the case of reading and seeking forward, the current read position
16// advances and there will be more data in the backward direction. If backward
17// bytes exceeds |backward_capacity|, the exceeding bytes are evicted and thus
18// backward_bytes() will always be less than or equal to |backward_capacity|.
19// The eviction will be caused by Read() and Seek() in the forward direction and
20// is done internally when the mentioned criteria is fulfilled.
21//
22// In the case of appending data to the buffer, there is an advisory limit of
23// how many bytes can be kept in the forward direction, regulated by
24// |forward_capacity|. The append operation (by calling Append()) that caused
25// forward bytes to exceed |forward_capacity| will have a return value that
26// advises a halt of append operation, further append operations are allowed but
27// are not advised. Since this class is used as a backend buffer for caching
28// media files downloaded from network we cannot afford losing data, we can
29// only advise a halt of further writing to this buffer.
30// This class is not inherently thread-safe. Concurrent access must be
31// externally serialized.
32
33#ifndef MEDIA_BASE_SEEKABLE_BUFFER_H_
34#define MEDIA_BASE_SEEKABLE_BUFFER_H_
35
36#include <list>
37
38#include "base/basictypes.h"
39#include "base/memory/ref_counted.h"
40#include "media/base/buffers.h"
41
42namespace media {
43
44class DataBuffer;
45
46class MEDIA_EXPORT SeekableBuffer {
47 public:
48  // Constructs an instance with |forward_capacity| and |backward_capacity|.
49  // The values are in bytes.
50  SeekableBuffer(int backward_capacity, int forward_capacity);
51
52  ~SeekableBuffer();
53
54  // Clears the buffer queue.
55  void Clear();
56
57  // Reads a maximum of |size| bytes into |data| from the current read
58  // position. Returns the number of bytes read.
59  // The current read position will advance by the amount of bytes read. If
60  // reading caused backward_bytes() to exceed backward_capacity(), an eviction
61  // of the backward buffer will be done internally.
62  int Read(uint8* data, int size);
63
64  // Copies up to |size| bytes from current position to |data|. Returns
65  // number of bytes copied. Doesn't advance current position. Optionally
66  // starts at a |forward_offset| from current position.
67  int Peek(uint8* data, int size) { return Peek(data, size, 0); }
68  int Peek(uint8* data, int size, int forward_offset);
69
70  // Returns pointer to the current chunk of data that is being consumed.
71  // If there is no data left in the buffer false is returned, otherwise
72  // true is returned and |data| and |size| are updated. The returned
73  // |data| value becomes invalid when Read(), Append() or Seek()
74  // are called.
75  bool GetCurrentChunk(const uint8** data, int* size) const;
76
77  // Appends |buffer_in| to this buffer. Returns false if forward_bytes() is
78  // greater than or equals to forward_capacity(), true otherwise. The data
79  // is added to the buffer in any case.
80  bool Append(const scoped_refptr<DataBuffer>& buffer_in);
81
82  // Appends |size| bytes of |data| to the buffer. Result is the same
83  // as for Append(Buffer*).
84  bool Append(const uint8* data, int size);
85
86  // Moves the read position by |offset| bytes. If |offset| is positive, the
87  // current read position is moved forward. If negative, the current read
88  // position is moved backward. A zero |offset| value will keep the current
89  // read position stationary.
90  // If |offset| exceeds bytes buffered in either direction, reported by
91  // forward_bytes() when seeking forward and backward_bytes() when seeking
92  // backward, the seek operation will fail and return value will be false.
93  // If the seek operation fails, the current read position will not be updated.
94  // If a forward seeking caused backward_bytes() to exceed backward_capacity(),
95  // this method call will cause an eviction of the backward buffer.
96  bool Seek(int32 offset);
97
98  // Returns the number of bytes buffered beyond the current read position.
99  int forward_bytes() const { return forward_bytes_; }
100
101  // Returns the number of bytes buffered that precedes the current read
102  // position.
103  int backward_bytes() const { return backward_bytes_; }
104
105  // Sets the forward_capacity to |new_forward_capacity| bytes.
106  void set_forward_capacity(int new_forward_capacity) {
107    forward_capacity_ = new_forward_capacity;
108  }
109
110  // Sets the backward_capacity to |new_backward_capacity| bytes.
111  void set_backward_capacity(int new_backward_capacity) {
112    backward_capacity_ = new_backward_capacity;
113  }
114
115  // Returns the maximum number of bytes that should be kept in the forward
116  // direction.
117  int forward_capacity() const { return forward_capacity_; }
118
119  // Returns the maximum number of bytes that should be kept in the backward
120  // direction.
121  int backward_capacity() const { return backward_capacity_; }
122
123  // Returns the current timestamp, taking into account current offset. The
124  // value calculated based on the timestamp of the current buffer. If
125  // timestamp for the current buffer is set to 0 or the data was added with
126  // Append(const uint*, int), then returns value that corresponds to the
127  // last position in a buffer that had timestamp set.
128  // kNoTimestamp() is returned if no buffers we read from had timestamp set.
129  base::TimeDelta current_time() const { return current_time_; }
130
131 private:
132  // Definition of the buffer queue.
133  typedef std::list<scoped_refptr<DataBuffer> > BufferQueue;
134
135  // A helper method to evict buffers in the backward direction until backward
136  // bytes is within the backward capacity.
137  void EvictBackwardBuffers();
138
139  // An internal method shared by Read() and SeekForward() that actually does
140  // reading. It reads a maximum of |size| bytes into |data|. Returns the number
141  // of bytes read. The current read position will be moved forward by the
142  // number of bytes read. If |data| is NULL, only the current read position
143  // will advance but no data will be copied.
144  int InternalRead(
145      uint8* data, int size, bool advance_position, int forward_offset);
146
147  // A helper method that moves the current read position forward by |size|
148  // bytes.
149  // If the return value is true, the operation completed successfully.
150  // If the return value is false, |size| is greater than forward_bytes() and
151  // the seek operation failed. The current read position is not updated.
152  bool SeekForward(int size);
153
154  // A helper method that moves the current read position backward by |size|
155  // bytes.
156  // If the return value is true, the operation completed successfully.
157  // If the return value is false, |size| is greater than backward_bytes() and
158  // the seek operation failed. The current read position is not updated.
159  bool SeekBackward(int size);
160
161  // Updates |current_time_| with the time that corresponds to the
162  // specified position in the buffer.
163  void UpdateCurrentTime(BufferQueue::iterator buffer, int offset);
164
165  BufferQueue::iterator current_buffer_;
166  BufferQueue buffers_;
167  int current_buffer_offset_;
168
169  int backward_capacity_;
170  int backward_bytes_;
171
172  int forward_capacity_;
173  int forward_bytes_;
174
175  // Keeps track of the most recent time we've seen in case the |buffers_| is
176  // empty when our owner asks what time it is.
177  base::TimeDelta current_time_;
178
179  DISALLOW_COPY_AND_ASSIGN(SeekableBuffer);
180};
181
182}  // namespace media
183
184#endif  // MEDIA_BASE_SEEKABLE_BUFFER_H_
185