Rockit多媒体播放器音频的解码buffer,正确的做法是实时分配,因为音频的解码buffer大小有可能在某些流不是固定的。而且某些流也不能在初始化的时候知道解码frame的size,如果提前预分配,很可能造成buffer的浪费或者分配buffer太小造成声音断音。所以需要根据解码frame实时分配。但是分配方式是插件创建,所以只有插件才有分配释放权,而具体的解码
Rockit音频的代码简单逻辑线:
buffer监听基类RTBufferListener:
class RTBufferListener {
public:
RTBufferListener() {}
virtual ~RTBufferListener() {}
public:
// buffer callback.
/*
* section: override virtual methods of RTBufferListener.
* name: onBufferAvailable
*/
virtual void onBufferAvailable(void* buffer) = 0;
/*
* section: override virtual methods of RTBufferListener.
* name: onBufferRealloc
*/
virtual void onBufferRealloc(void* buffer, UINT32 size) = 0;
/*
* section: override virtual methods of RTBufferListener.
* name: onBufferRelease
*/
virtual void onBufferRelease(void* buffer, RT_BOOL render) = 0;
};
此三个函数的功能:
void onBufferAvailable(void* buffer) : 可用buffer回调函数
void onBufferRealloc(void* buffer, UINT32 size) : buffer重分配回调函数
void onBufferRelease(void* buffer, RT_BOOL render) : buffer释放回调函数
音频解码插件RTNodeAudioCodec和buffer管理池RTMediaBufferPool分别继承了此监听基类:
class RTNodeAudioCodec : public RTNodeCodec, RTBufferListener {
public:
RTNodeAudioCodec();
virtual ~RTNodeAudioCodec();
......
}
class RTMediaBufferPool : public RTBufferListener {
public:
/* create for external buffer pool */
explicit RTMediaBufferPool(UINT32 max_buffer_count = 0);
/* create for internal buffer pool */
explicit RTMediaBufferPool(UINT32 max_buffer_count, UINT32 buffer_size);
~RTMediaBufferPool();
......
}
RTNodeAudioCodec在初始化init()中会new RTMediaBufferPool,并把自己注册通过setBufferListener(this)给RTMediaBufferPool
RTNodeAudoCodec 在prepare阶段会拿到分配方式(使用malloc的分配的方式),并且进行buffer的预分配:
RT_RET RTNodeAudioCodec::onPrepare() {
// create malloc allocator for audio
RTAllocatorStore::fetchAllocator(RTAllocatorStore::RT_ALLOC_TYPE_MALLOC, mMetaInput, &mLinearAllocator);
RT_LOGD_IF(DEBUG_FLAG, "fetchAllocator(ALLOC_TYPE_MALLOC), mLinearAllocator = %p", mLinearAllocator);
RT_ASSERT(RT_NULL != mLinearAllocator);
// allocate input and output buffers.
allocateBuffersOnPort(RT_PORT_INPUT);
allocateBuffersOnPort(RT_PORT_OUTPUT);
mFramePool->start();
mPacketPool->start();
return RT_OK;
}
buffer预分配,这里对解码轮转buffer进行空分配(仅new出轮转的RTMediaBuffer,并没有分配实际的内存),并且把buffer注册进内存池:
在RTMediaBufferPool->registerBuffer中,会把RTMediaBufferPool注册给RTMediaBuffer:
开始播放后,RTNodeAudioCodec->runtask->IAudioCodec->fa_xx_get_frame,此时会对buffer开始监听:
当buffer->getSize()小于解码frame的size或者buffer->getData()为空时,会对buffer进行重分配:
RT_RET fa_xx_get_frame(FABSEncoderContext* ctx, RTMediaBuffer *buffer) {
UINT8 *dst = RT_NULL;
if (ctx->mSize > 0) {
// reallocate MediaBuffer is if resample_size > buffer_size
if (buffer->getSize() < ctx->mSize) {
RT_LOGD_IF(DEBUG_FLAG, "reallocate buffer(this=%p, size=%d), old=%d", \
buffer, ctx->mSize, buffer->getSize());
}
buffer->signalBufferRealloc(ctx->mSize);
if (buffer->getSize() < ctx->mSize) {
RT_LOGD("fail to reallocate buffer(this=%p, size=%d) is smaller than ctx->mSize=%d", \
buffer, buffer->getSize(), ctx->mSize);
ctx->mSize = buffer->getSize();
}
......
}
......
}
这里buffer->signalBufferRealloc(ctx->mSize);会调用:
void RTMediaBuffer::signalBufferRealloc(UINT32 size) {
if (RT_NULL != mBufferListener) {
mBufferListener->onBufferRealloc(this, size);
}
}
这里的mBufferListener是上面RTMediaBufferPool->registerBuffer中截图部分注册进来的,所以这里回调到RTMediaBufferPool中的onBufferRealloc:
/*
* section: override virtual methods of RTBufferListener.
* name: onBufferRealloc
*/
void RTMediaBufferPool::onBufferRealloc(void* buffer, UINT32 size) {
RT_LOGD_IF(DEBUG_FLAG, "buffer(%p) is reallocated", buffer);
if (RT_NULL != mBufferListener) {
mBufferListener->onBufferRealloc(buffer, size);
if (RT_NULL != buffer) {
RTMediaBuffer* frame = reinterpret_cast<RTMediaBuffer*>(buffer);
// need to increase the reference count when RTMediaBuffer is realloced,
// otherwise the RTMediaBuffer will be probabilistically recycled and reused,
// and objects that are using RTMediaBuffer will crash.
if (0 == frame->refsCount()) {
frame->addRefs();
}
// buffer pool manages this new buffer, so needs RTBufferListener.
frame->setListener(this);
}
}
}
而RTMediaBufferPool中的mBufferListener是RTNodeAudioCodec注册进来的,所以这里调用RTNodeAudioCodec->onBufferRealloc:
/*
* section: override virtual methods of RTBufferListener.
* name: onBufferRealloc
*/
void RTNodeAudioCodec::onBufferRealloc(void* buffer, UINT32 size) {
RTMediaBuffer* frame = reinterpret_cast<RTMediaBuffer*>(buffer);
if ((RT_NULL != frame) && (RT_NULL != mLinearAllocator)) {
if ((frame->getSize() < size) || (RT_NULL == frame->getData())) {
frame->release();
mLinearAllocator->freeBuffer(&frame);
mLinearAllocator->newBuffer(size, &frame);
RT_LOGD_IF(DEBUG_FLAG, "reallocated buffer(this: %p, data: %p, size: %d)",
frame, frame->getData(), size);
return;
}
}
}
这样就会根据RTNodeAudioCodec注册的分配方式判断是否进行重分配,实现了谁注册分配方式,谁管理的监听。
注意:在当前buffer进行重分配的时候,需要把buffer置上引用标记(见下面截图框1),因为这buffer有概率会回收或者再利用,造成crash. 并且buffer pool管理新分配的buffer,所以新分配的需要注册监听(下面截图框2)。