summaryrefslogtreecommitdiffstats
path: root/media/base/seekable_buffer.h
blob: 41d26fea185bb3711605cf761f4d6de3c7758d91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// 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 DataBuffer;

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(const scoped_refptr<DataBuffer>& 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<DataBuffer> > 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_