Android MultiMedia框架——MediaCodec编码(下)
Posted VNanyesheshou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android MultiMedia框架——MediaCodec编码(下)相关的知识,希望对你有一定的参考价值。
Android MultiMedia框架——OMX服务启动
Android MultiMedia框架——OMXPlugin
Android MultiMedia框架——MediaCodec编码(上)
Android MultiMedia框架——MediaCodec编码(下)
这篇主要分析以下MeidaCodec获取可用输入buffer,buffer加入队列相关流程
MediaCodec.cpp中相关数据结构
List<size_t> mAvailPortBuffers[2];
std::vector<BufferInfo> mPortBuffers[2];
mAvailPortBuffers:可用buffer对应的index。mAvailPortBuffers[0]为输入,mAvailPortBuffers[1]为输出。
mPortBuffers:所有buffer缓冲区,包括可用和已占用。mPortBuffers[0]为输入buffer,mPortBuffers[1]为输出buffer。
这些数据缓冲区是在Mediacodec configure的时候进行的分配。
input
查看MediaCodec 输入缓冲区使用流程
1 dequeueInputBuffer
这里就不在贴java层代码了,直接看MediaCodec.cpp dequeueInputBuffer
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;
这里发送AMessage消息,MediaCodec继承AHandler,通过onMessageReceived处理消息
void MediaCodec::onMessageReceived(const sp<AMessage> &msg)
switch (msg->what())
case kWhatDequeueInputBuffer:
//.....
if (handleDequeueInputBuffer(replyID, true /* new request */))
break;
//.......
接着看handleDequeueInputBuffer
bool MediaCodec::handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest)
if (!isExecuting() || (mFlags & kFlagIsAsync)
|| (newRequest && (mFlags & kFlagDequeueInputPending)))
PostReplyWithError(replyID, INVALID_OPERATION);
return true;
else if (mFlags & kFlagStickyError)
PostReplyWithError(replyID, getStickyError());
return true;
ssize_t index = dequeuePortBuffer(kPortIndexInput);
if (index < 0)
CHECK_EQ(index, -EAGAIN);
return false;
sp<AMessage> response = new AMessage;
response->setSize("index", index);
response->postReply(replyID);
return true;
- 检查状态及flag;
- dequeuePortBuffer 从mAvailPortBuffers获取可用输入buffer下标;
- 将index通过response返回
2 getInputBuffer
MediaCodec.java 中getInputBuffer,直接看jni的方法
static jobject android_media_MediaCodec_getBuffer(
JNIEnv *env, jobject thiz, jboolean input, jint index)
jobject buffer;
status_t err = codec->getBuffer(env, input, index, &buffer);
//获取buffer,并return;
if (err == OK)
return buffer;
return NULL;
status_t JMediaCodec::getBuffer(
JNIEnv *env, bool input, size_t index, jobject *buf) const
sp<MediaCodecBuffer> buffer;
status_t err =
input
? mCodec->getInputBuffer(index, &buffer)
: mCodec->getOutputBuffer(index, &buffer);
if (err != OK)
return err;
return createByteBufferFromABuffer(
env, !input /* readOnly */, input /* clearBuffer */, buffer, buf);
- 调用MediaCodec.cpp中getInputBuffer函数,获取id 对应buffer;
- 通过MediaCodecBuffer创建ByteBuffer,实现java和native共享内存;
- 返回ByteBuffer;
接着看mCodec->getInputBuffer
status_t MediaCodec::getInputBuffer(size_t index, sp<MediaCodecBuffer> *buffer)
sp<AMessage> format;
return getBufferAndFormat(kPortIndexInput, index, buffer, &format);
status_t MediaCodec::getBufferAndFormat(
size_t portIndex, size_t index,
sp<MediaCodecBuffer> *buffer, sp<AMessage> *format)
//...
std::vector<BufferInfo> &buffers = mPortBuffers[portIndex];
if (index >= buffers.size())
return INVALID_OPERATION;
const BufferInfo &info = buffers[index];
if (!info.mOwnedByClient)
return INVALID_OPERATION;
*buffer = info.mData;
*format = info.mData->format();
return OK;
- mPortBuffers通过index区分输入输出,这里获取所有输入BufferInfo;
- 通过下标获取指定的BufferInfo;
- 将buffer指针指向BufferInfo的mData.
3 queueInputBuffer
static void android_media_MediaCodec_queueInputBuffer(
JNIEnv *env,
jobject thiz,
jint index,
jint offset,
jint size,
jlong timestampUs,
jint flags)
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL)
throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
AString errorDetailMsg;
status_t err = codec->queueInputBuffer(
index, offset, size, timestampUs, flags, &errorDetailMsg);
throwExceptionAsNecessary(
env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
status_t JMediaCodec::queueInputBuffer(
size_t index,
size_t offset, size_t size, int64_t timeUs, uint32_t flags,
AString *errorDetailMsg)
return mCodec->queueInputBuffer(
index, offset, size, timeUs, flags, errorDetailMsg);
jni 方法android_media_MediaCodec_queueInputBuffer获取JMediaCodec,调用其queueInputBuffer,然后调用MediaCodec的queueInputBuffer函数
MediaCodec.cpp queueInputBuffer
status_t MediaCodec::queueInputBuffer(
size_t index,
size_t offset,
size_t size,
int64_t presentationTimeUs,
uint32_t flags,
AString *errorDetailMsg)
if (errorDetailMsg != NULL)
errorDetailMsg->clear();
sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
msg->setSize("index", index);
msg->setSize("offset", offset);
msg->setSize("size", size);
msg->setInt64("timeUs", presentationTimeUs);
msg->setInt32("flags", flags);
msg->setPointer("errorDetailMsg", errorDetailMsg);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
void MediaCodec::onMessageReceived(const sp<AMessage> &msg)
switch (msg->what())
case kWhatQueueInputBuffer:
//......
status_t err = onQueueInputBuffer(msg);
PostReplyWithError(replyID, err);
break;
onMessageReceived接收消息kWhatQueueInputBuffer,调用onQueueInputBuffer函数
status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg)
//......
sp<MediaCodecBuffer> buffer = info->mData;
status_t err = OK;
if (hasCryptoOrDescrambler())
else
err = mBufferChannel->queueInputBuffer(buffer);
return err;
调用ACodecBufferChannel queueInputBuffer函数
status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer)
if (mDealer != nullptr)
return -ENOSYS;
std::shared_ptr<const std::vector<const BufferInfo>> array(
std::atomic_load(&mInputBuffers));
BufferInfoIterator it = findClientBuffer(array, buffer);
if (it == array->end())
return -ENOENT;
sp<AMessage> msg = mInputBufferFilled->dup();
msg->setObject("buffer", it->mCodecBuffer);
msg->setInt32("buffer-id", it->mBufferId);
msg->post();
return OK;
暂不清楚ACodecBufferChannel 的用处是什么。。 发送kWhatInputBufferFilled message.
ACodec接收到kWhatInputBufferFilled信息后续
void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg)
//.......
switch (mode)
case KEEP_BUFFERS:
case RESUBMIT_BUFFERS:
status_t err2 = mCodec->mOMXNode->emptyBuffer(
bufferID, OMXBuffer::sPreset, OMX_BUFFERFLAG_EOS, 0, info->mFenceFd);
break;
case FREE_BUFFERS:
break;
ACodec通知OMX,写入数据。
output
output 数据获取流程和input流程大致上都相似,这里就不在细说了。
以上是关于Android MultiMedia框架——MediaCodec编码(下)的主要内容,如果未能解决你的问题,请参考以下文章
Android MultiMedia框架——OMXPlugin
Android MultiMedia框架——ACodec加载OMX
Android MultiMedia框架——ALooper AHandler AMessage
Android MultiMedia框架——MediaCodec编码(下)