Buffer实现原理,简单的来说,
Buffer就像一个
vector,自动管理内存,自动扩容,相比
vector它提供了更易用的写入,读取数据的接口。它可以作为一个基本
Buffer,在它的基础上构建功能更多丰富的buffer类。
在webrtc中有一个CopyOnWriteBuffer类,它就是基于Buffer实现了一个写时复制功能的buffer。
写时复制指在改变内容时,产生一个buffer的拷贝,在拷贝上更改内容,而不影响原buffer的内容。这是CopyOnWriteBuffer的核心特性。它还具有如下几个特性:
Buffer)Buffer对象)CopyOnwrite对象共享内存(Buffer对象)Buffer对象)在流媒体,实时音视频这类应用中有个基本流程就是收媒体流,处理,再发送媒体流:
CopyOnWriteBuffer就很适合,将媒体数据写入CopyOnWirteBuffer对象,将以值语义传递,内部的Buffer并不会拷贝,这样比使用裸指针更方便,因为CopyOnWriteBuffer就提供了多种操作/读取数据的接口。CopyOnWriteBuffer中,在更改时,自动copy一份rtp包。这样比直接使用裸指针更方便。内部buffer是一个Buffer类型shared_ptr指针,表述它的语义就是可以共享_buffer。
//是一个Buffer对象
std::shared_ptr<Buffer> _buffer;
CopyOnWriteBuffer支持复制语义,所以有复制构造函数,赋值操作符。
//复制构造函数
CopyOnWriteBuffer(const CopyOnWriteBuffer& buf);
//赋值操作符
CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& buf);
复制语义的作用就是让多个CopyOnWriteBuffer对象共享_buffer。
CopyOnWriteBuffer::CopyOnWriteBuffer(const CopyOnWriteBuffer& buf)
: _buffer(buf._buffer), _offset(buf._offset), _size(buf._size) {}
赋值操作符,也是如此:
CopyOnWriteBuffer& operator=(const CopyOnWriteBuffer& buf) {
assert(IsConsistent());
assert(buf.IsConsistent());
if (&buf != this) {
_buffer = buf._buffer;
_offset = buf._offset;
_size = buf._size;
}
return *this;
}
CopyOnWriteBuffer定义有移动构造函数和**移动赋值函数。 **通过std::move将_buffer的所有权交给另外一个CopyOnWriteBuffer对象。
CopyOnWriteBuffer::CopyOnWriteBuffer(CopyOnWriteBuffer&& buf)
: _buffer(std::move(buf._buffer)), _offset(buf._offset), _size(buf._size) {
buf._offset = 0;
buf._size = 0;
assert(IsConsistent());
}
移动赋值操作符也是如此:
CopyOnWriteBuffer& operator=(CopyOnWriteBuffer&& buf) {
assert(IsConsistent());
assert(buf.IsConsistent());
_buffer = std::move(buf._buffer);
_offset = buf._offset;
_size = buf._size;
buf._offset = 0;
buf._size = 0;
return *this;
}
CopyOnWriteBuffer核心特性就是写时复制,多个CopyOnWriteBuffer对象共享一个 Buffer,当某个对象改动Buffer时,就会对这个对象产生一个新的Buffer。涉及到修改Buffer的接口如下:
void AppendData(const uint8_t*data, size_t size)uint8_t& operator[](size_t index)void SetSize(size_t size)void SetData(const uint8_t*data, size_t size)前三个方法都会调用UnshareAndEnsureCapacity方法,通过它来确定是否产生新的Buffer。
如函数名表示的意思,它有两个逻辑 :如果_buffer被共享则产生一个新的_buffer对象;如果没有被共享,则通过capacity来确认是否需要产生一个新的_buffer对象。
void CopyOnWriteBuffer::UnshareAndEnsureCapacity(size_t new_capacity) {
if (_buffer.unique() && new_capacity <= capacity()) {
return;
}
_buffer.reset(new Buffer(_buffer->data() + _offset, _size, new_capacity));
_offset = 0;
assert(IsConsistent());
}
下面这个例子是使用AppendData的例子
const uint8_t kTestData[] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};
//共享
CopyOnWriteBuffer buf23(kTestData,3,10);
CopyOnWriteBuffer buf24(buf23);
const uint8_t* d1 = buf23.cdata();
const uint8_t* d2 = buf24.cdata();
std::cout<<"before append data d1 == d2 "<<(d1 == d2)<<",buf23 size "<<buf23.size()<<",buf24 size "<<buf24.size()<<",buf23 c "<<buf23.capacity()<<",buf24 c "<<buf24.capacity()<<std::endl;
uint8_t moreData[] = {17,18,19};
//buf24 调用Append时,会产生一个新的buffer
buf24.AppendData(moreData,3);
std::cout<<"after append data,buf23 size "<<buf23.size()<<",buf24 size "<<buf24.size()<<",buf23 c "<<buf23.capacity()<<",buf24 c "<<buf24.capacity()<<std::endl;
const uint8_t* d3 = buf24.cdata();
std::cout<<"d1 == d3 "<<(d1 == d3)<<std::endl;
//打印buf23的内容:1,2,3
std::cout<<"print buf23 data:";
for (size_t i=0; i<buf23.size(); ++i) {
std::cout<<static_cast<int>(buf23[i])<<" ";
}
std::cout<<std::endl;
//打印buf24的内容:1,2,3,17,18,19
std::cout<<"print buf24 data:";
for (size_t i=0; i<buf24.size(); ++i) {
std::cout<<static_cast<int>(buf24[i])<<" ";
}
std::cout<<std::endl;
用于对CopyOnWriteBuffer对象进行分片,产生的一个从原对象offset处,size为length,新的CopyOnWriteBuffer对象,它与原对象共享_buffer。
CopyOnWriteBuffer Slice(size_t offset, size_t length) const {
CopyOnWriteBuffer slice(*this);
slice._offset += offset;
slice._size = length;
return slice;
}
const uint8_t kTestData[] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf};
CopyOnWriteBuffer ssbuf(kTestData,10,10);
//slice并不导致产生新buffer
CopyOnWriteBuffer sslice = ssbuf.Slice(0,3);
//sslice[0]改变了,将产生一个新的buffer
sslice[0] = 0xaa;
//sslice[0]的值为170
std::cout<<"sslice index 0 "<<static_cast<int>(*sslice.cdata())<<std::endl;
//ssbuf[0]的值为1
std::cout<<"ssbuf index 0 "<<static_cast<int>(*ssbuf.cdata())<<std::endl;
std::cout<<"sslic data == ssbuf data "<<(sslice.cdata() == ssbuf.cdata())<<std::endl;
CopyOnWriteBuffer的实现基于Buffer,在功能上强于Buffer。我们也可以根据业务的需求,基于Buffer封装自己的Buffer类。