summaryrefslogtreecommitdiffstats
path: root/media/base/seekable_buffer.h
blob: 58b0be98c710999aa2d25c0037d105c35fbf47ea (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
// 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:
  // 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<uint8> data;
    // Size of this block.
    size_t size;
  };

  // Definition of the buffer queue.
  typedef std::list<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(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_