summaryrefslogtreecommitdiffstats
path: root/remoting/base/compound_buffer.h
blob: 4883e11ee696523f468b3f4793975cb874156459 (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
// 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.

// CompoundBuffer implements a data buffer that is composed of several pieces,
// each stored in a refcounted IOBuffer. It is needed for encoding/decoding
// video pipeline to represent data packet and minimize data copying.
// It is particularly useful for splitting data between multiple RTP packets
// and assembling them into one buffer on the receiving side.
//
// CompoundBufferInputStream implements ZeroCopyInputStream interface
// to be used by protobuf to decode data stored in CompoundBuffer into
// a protocol buffer message.
//
// Mutations to the buffer are not thread-safe. Immutability can be ensured
// with the Lock() method.

#ifndef REMOTING_BASE_COMPOUND_BUFFER_H_
#define REMOTING_BASE_COMPOUND_BUFFER_H_

#include <stddef.h>
#include <stdint.h>

#include <deque>

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "google/protobuf/io/zero_copy_stream.h"

namespace net {
class IOBuffer;
class IOBufferWithSize;
}  // namespace net

namespace remoting {

class CompoundBuffer {
 public:
  CompoundBuffer();
  ~CompoundBuffer();

  void Clear();

  // Adds new chunk to the buffer. |start| defines position of the chunk
  // within the |buffer|. |size| is the size of the chunk that is being
  // added, not size of the |buffer|.
  void Append(net::IOBuffer* buffer, int size);
  void Append(net::IOBuffer* buffer, const char* start, int size);
  void Append(const CompoundBuffer& buffer);
  void Prepend(net::IOBuffer* buffer, int size);
  void Prepend(net::IOBuffer* buffer, const char* start, int size);
  void Prepend(const CompoundBuffer& buffer);

  // Same as above, but creates new IOBuffer and copies the data.
  void AppendCopyOf(const char* data, int data_size);
  void PrependCopyOf(const char* data, int data_size);

  // Drop |bytes| bytes from the beginning or the end of the buffer.
  void CropFront(int bytes);
  void CropBack(int bytes);

  // Current size of the buffer.
  int total_bytes() const { return total_bytes_; }

  // Locks the buffer. After the buffer is locked, no data can be
  // added or removed (content can still be changed if some other
  // object holds reference to the IOBuffer objects).
  void Lock();

  // Returns true if content is locked.
  bool locked() const { return locked_; }

  // Creates new IOBufferWithSize object and copies all data into it.
  // Ownership of the result is given to the caller.
  net::IOBufferWithSize* ToIOBufferWithSize() const;

  // Copies all data into given location.
  void CopyTo(char* data, int data_size) const;

  // Clears the buffer, and initializes it with the interval from |buffer|
  // starting at |start| and ending at |end|. The data itself isn't copied.
  void CopyFrom(const CompoundBuffer& source, int start, int end);

 private:
  friend class CompoundBufferInputStream;

  struct DataChunk {
    DataChunk(net::IOBuffer* buffer, const char* start, int size);
    ~DataChunk();

    scoped_refptr<net::IOBuffer> buffer;
    const char* start;
    int size;
  };
  typedef std::deque<DataChunk> DataChunkList;

  DataChunkList chunks_;
  int total_bytes_;
  bool locked_;

  DISALLOW_COPY_AND_ASSIGN(CompoundBuffer);
};

class CompoundBufferInputStream
    : public google::protobuf::io::ZeroCopyInputStream  {
 public:
  // Caller keeps ownership of |buffer|. |buffer| must be locked.
  explicit CompoundBufferInputStream(const CompoundBuffer* buffer);
  ~CompoundBufferInputStream() override;

  int position() const { return position_; }

  // google::protobuf::io::ZeroCopyInputStream interface.
  bool Next(const void** data, int* size) override;
  void BackUp(int count) override;
  bool Skip(int count) override;
  int64_t ByteCount() const override;

 private:
  const CompoundBuffer* buffer_;

  size_t current_chunk_;
  int current_chunk_position_;
  int position_;
  int last_returned_size_;
};

}  // namespace remoting

#endif  // REMOTING_BASE_COMPOUND_BUFFER_H_