先來(lái)張MediaCodec上下文涉及的源碼圖

1、Buffer類型
Buffer主要包含兩個(gè)列表,可用Buffer,和所有Buffer,每個(gè)列表都包含兩個(gè)隊(duì)列
[0]InputBuffer隊(duì)列
[1]OutputBuffer隊(duì)列
List<size_t> mAvailPortBuffers[2];// 當(dāng)前可用的Buffer索引
Vector<BufferInfo> mPortBuffers[2];// 所有Buffer
mAvailPortBuffers包含一下三個(gè)操作
①消費(fèi)(dequeuePortBuffer)
②生產(chǎn)(updateBuffers)
③清除(returnBuffersToCodecOnPort)
1.1、dequeuePortBuffer
ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) {
CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
List<size_t> *availBuffers = &mAvailPortBuffers[portIndex];
if (availBuffers->empty()) {
return -EAGAIN;//如果沒有可用的buffer,返回-EAGAIN(-11)
}
size_t index = *availBuffers->begin();
availBuffers->erase(availBuffers->begin());
...
return index;
}
1.2、updateBuffers
1. ACodec收到omx_message::FILL_BUFFER_DONE消息,調(diào)用onOMXFillBufferDone
2. 函數(shù)onOMXFillBufferDone中構(gòu)建CodecBase::kWhatDrainThisBuffer消息,發(fā)送給MediaCodec
3. kWhatDrainThisBuffer調(diào)用updateBuffers
4. updateBuffers遍歷mPortBuffers找到bufferId相同的buffer所在index,放入mAvailPortBuffers隊(duì)尾
會(huì)在updateBuffers中待會(huì)ACodec中消息
msg->findMessage("reply", &info->mNotify)
在ACodec中會(huì)構(gòu)成解碼前/后數(shù)據(jù)的消息
kWhatInputBufferFilled// 解碼前數(shù)據(jù)消息,主動(dòng)通知ACodec接收解碼前數(shù)據(jù)
kWhatOutputBufferDrained// 解碼后數(shù)據(jù)
1.3、returnBuffersToCodecOnPort
清理主要發(fā)生在以下時(shí)機(jī):
flush
stop
release
state進(jìn)入U(xiǎn)NINITIALIZED
returnBuffersToCodecOnPort主要是clear了mAvailPortBuffers
2、dequeueInputBuffer
申請(qǐng)可用的InputBuffer,該方法為同步方法,輸入?yún)?shù)input是返回當(dāng)前是否有可用buffer
status_t MediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
sp<AMessage> msg = new AMessage(kWhatDequeueInputBuffer, this);
msg->setInt64("timeoutUs", timeoutUs);
sp<AMessage> response;
status_t err;
if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
return err;
}
CHECK(response->findSize("index", index));
return OK;
}
進(jìn)入kWhatDequeueInputBuffer消息中,主要在handleDequeueInputBuffer中處理
bool MediaCodec::handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest) {
ssize_t index = dequeuePortBuffer(kPortIndexInput);
return true;
}
在dequeuePortBuffer方法中查找當(dāng)前是否有可用的InputBuffer,并返回他在隊(duì)列中的索引
3、queueInputBuffer
往InputBuffer中填充解碼前的數(shù)據(jù)
進(jìn)入kWhatQueueInputBuffer消息中,主要在onQueueInputBuffer中處理
status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) {
...
sp<AMessage> reply = info->mNotify;// message=kWhatInputBufferFilled
...
reply->setBuffer("buffer", info->mData);
reply->post();
info->mNotify = NULL;
return OK;
}
然后進(jìn)入ACodec的onInputBufferFilled
這里涉及到ACodec的三種端口模式
KEEP_BUFFERS 不會(huì)把當(dāng)前持有的buffer送到OMX解碼
①onInputBufferFilled填充數(shù)據(jù)時(shí),未找到有效buffer
②ACodec處于BaseState狀態(tài)
RESUBMIT_BUFFERS 把當(dāng)前持有的buffer送到OMX解碼
①ACodec處于ExecutingState狀態(tài)
②ACodec處于OutputPortSettingsChangedState狀態(tài),并且是InputBuffer
FREE_BUFFERS 釋放當(dāng)前持有的buffer
①ACodec處于OutputPortSettingsChangedState狀態(tài),并且是OutputBuffer
只有RESUBMIT_BUFFERS才會(huì)觸發(fā)OMX解碼
void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
...
if (err2 == OK) {
err2 = mCodec->mOMX->emptyBuffer(
mCodec->mNode,
bufferID,
0,
info->mCodecData->size(),
flags,
timeUs,
info->mFenceFd);
}
...
}
然后等待OMX解碼結(jié)束會(huì)觸發(fā)omx_message::FILL_BUFFER_DONE事件,進(jìn)入到onOMXFillBufferDone
bool ACodec::BaseState::onOMXFillBufferDone(...) {
...
sp<AMessage> reply =
new AMessage(kWhatOutputBufferDrained, mCodec);
...
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
notify->setMessage("reply", reply);// 增加回調(diào)kWhatOutputBufferDrained
notify->post();// 觸發(fā)kWhatDrainThisBuffer,回到MediaCodec中updateBuffers
}
size_t MediaCodec::updateBuffers(int32_t portIndex, const sp<AMessage> &msg) {
info->mFormat =
(portIndex == kPortIndexInput) ? mInputFormat : mOutputFormat;
mAvailPortBuffers[portIndex].push_back(i);// 把解碼后的數(shù)據(jù)加入到可用buffer中
return 0;
}
4、dequeueOutputBuffer
讀取已經(jīng)解碼后的數(shù)據(jù)
進(jìn)入kWhatDequeueOutputBuffer消息中,主要在handleDequeueOutputBuffer中處理
bool MediaCodec::handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest) {
...
ssize_t index = dequeuePortBuffer(kPortIndexOutput);// 獲取已經(jīng)解碼后的buffer
if (index < 0) {
CHECK_EQ(index, -EAGAIN);// 獲取失敗
return false;
}
const sp<ABuffer> &buffer =
mPortBuffers[kPortIndexOutput].itemAt(index).mData;
...
}
return true;
}
參考文檔:
https://zhuanlan.zhihu.com/p/47129044
https://blog.csdn.net/dfhuang09/article/details/60132620
https://unordered.org/timelines/5a22667e4ac00000