在阅读Codec2框架代码时,我们可能会发现好几个名称中都带有“buffer”的类,如MediaCodecBuffer、ABuffer、CCodecBuffers、Codec2Buffer以及C2Buffer。它们分别是什么?各自承担着什么功能?它们之间有何联系?本文将围绕这三个问题展开了解。
1、ABuffer
ABuffer不是Codec2框架中的类型,它是由Android Media Framework定义的,类型声明于 /frameworks/av/media/module/foundation/include/media/stagefright/foundation/ABuffer.h。从Android 14开始,这个头文件的路径不再置于libstagefright下,改到module下。
ABuffer是对裸指针的封装,可以记录buffer的大小,buffer地址,写入数据长度等信息。ABuffer提供了两种构造函数:
- 指定buffer大小,在ABuffer内部进行malloc
ABuffer::ABuffer(size_t capacity): mRangeOffset(0),mInt32Data(0),mOwnsData(true) {mData = malloc(capacity);if (mData == NULL) {mCapacity = 0;mRangeLength = 0;} else {mCapacity = capacity;mRangeLength = capacity;}
}
- 使用已有的buffer来创建ABuffer,此时除了要传入裸指针外,还要提供buffer的容量(capacity)
ABuffer::ABuffer(void *data, size_t capacity): mData(data),mCapacity(capacity),mRangeOffset(0),mRangeLength(capacity),mInt32Data(0),mOwnsData(false) {
}
ABuffer有如下几个成员含义需要了解:
- mData:裸指针,buffer的起始地址;
- mCapacity:buffer的大小/容量;
- mRangeOffset:它是对buffer可用范围限定的一部分,表示可用地址相对起始地址的偏移量;
- mRangeLength:它是对buffer可用范围限定的另一部分,表示buffer可用长度;
限定范围可以用setRange方法完成:
void ABuffer::setRange(size_t offset, size_t size) {CHECK_LE(offset, mCapacity);CHECK_LE(size, mCapacity - offset);mRangeOffset = offset;mRangeLength = size;
}
了解这几个成员后,ABuffer的其他方法就很好理解了:
uint8_t *base() { return (uint8_t *)mData; }
uint8_t *data() { return (uint8_t *)mData + mRangeOffset; }
size_t capacity() const { return mCapacity; }
size_t size() const { return mRangeLength; }
size_t offset() const { return mRangeOffset; }
- base:返回buffer起始地址;
- data:返回可写起始地址,如果不调用setRange,默认起始等于base;
- capacity:返回buffer容量;
- size:返回buffer可用长度,如果不调用setRange,默认大小等于capacity;
- offset:返回可用buffer的偏移量;
2、MediaCodecBuffer
MediaCodecBuffer是对ABuffer的封装,在数据的基础上增加了格式信息。创建MediaCodecBuffer需要传入参数format和一个ABuffer:
MediaCodecBuffer(const sp<AMessage> &format, const sp<ABuffer> &buffer);
MediaCodec的base、data、capacity等方法调用的是ABuffer对应方法,这里不再展开。要了解的是MediaCodecBuffer内部有三个为Codec2设计的虚函数:
virtual std::shared_ptr<C2Buffer> asC2Buffer() { return nullptr; }virtual bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const {(void)buffer;return false;
}virtual bool copy(const std::shared_ptr<C2Buffer> &buffer) {(void)buffer;return false;
}
我们现在还不知道C2Buffer是什么,所以暂且知道有这三个方法就好:
- asC2Buffer:使用当前buffer创建一个C2Buffer对象;
- canCopy:测试是否能将数据从C2Buffer拷贝到当前buffer中;
- copy:将数据从C2Buffer拷贝到buffer中;
3、C2Buffer
C2Buffer所在的头文件没有对该类做详细注释,要了解它的功能还要从它的结构来看。先来看C2Buffer的UML类图:
C2Buffer的构造函数都是protected,想要创建C2Buffer实例需要调用静态方法CreateLinearBuffer或者CreateGraphicBuffer。以CreateLinearBuffer为例看一下C2Buffer实例化过程: