ACodec与MediaCodec的通知。OMX的组件解码之后,当ACodec的onOMXFillBufferDone会被回调,去取得解码后的数据。
ACodec在onOMXFillBufferDone调用后会调用notify通知MediaCodec(notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);//发给MediaCodec的消息。
MediaCodec收到ACodec发的消息之后会更新updateBuffers(kPortIndexOutput, msg),同时onOutputBufferAvailable()中通知Decoder。
1.ACodec的onOMXFillBufferDone;
2.MediaCodec收到ACodec发的消息之后会更新updateBuffers(kPortIndexOutput, msg);同时onOutputBufferAvailable()中通知Decoder
3.1 MediaCodec的updateBuffers,找到随消息过来的reply,并存放在MediaCodec的BufferInfo的mNotify中。
3.Decoder收到从MediaCodec::onOutputBufferAvailable发回的回调消息kWhatCodecNotify之后,知道有可用的buffer,就handleAnOutputBuffer.
4.Decoder::handleAnOutputBuffer, 之后Decoder要与Render交互确定是否渲染。参看《NuPlayerDecoder与NuPlayerRender分析》
5. Decoder 接受 renderer对(mVideoQueue的QueueEntry)buffer发回的消费消息,并在Decoder的onRenderBuffer中调用MediaCodec的mCodec>renderOutputBufferAndRelease(bufferIx, timestampNs)或者mCodec->releaseOutputBuffer(bufferIx)。
6.Decoder到MediaCodec
MediaCodec的mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs)或者mCodec->releaseOutputBuffer(bufferIx),一个会真的渲染一个不渲染.
最终会到MediaCodec的onReleaseOutputBuffer(msg)处理.
status_t MediaCodec::renderOutputBufferAndRelease(size_t index, int64_t timestampNs) {
sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);//发送消息
msg->setSize("index", index);
msg->setInt32("render", true);//设置是否渲染
msg->setInt64("timestampNs", timestampNs);//timestampNs
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t MediaCodec::releaseOutputBuffer(size_t index) {
sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);//发送消息
msg->setSize("index", index);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
然后到MediaCodec的onReleaseOutputBuffer(msg)处理;
case kWhatReleaseOutputBuffer:
{
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (!isExecuting()) {
PostReplyWithError(replyID, INVALID_OPERATION);
break;
} else if (mFlags & kFlagStickyError) {
PostReplyWithError(replyID, getStickyError());
break;
}
status_t err = onReleaseOutputBuffer(msg);//onReleaseOutputBuffer(msg)处理
PostReplyWithError(replyID, err);
break;
}
7.MediaCodec到ACodec,MediaCodec::onReleaseOutputBuffer中判断使用硬件渲染后者软件渲染,并使用info->mNotify中ACodec传过来的reply消息,最终发给ACodec接受并处理。
ACodec接受消息后调用onOutputBufferDrained(msg),看是正在的硬件渲染。
8.ACodec的onOutputBufferDrained(msg);//真正的硬件渲染
ACodec在onOMXFillBufferDone调用后会调用notify通知MediaCodec(notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);//发给MediaCodec的消息。
MediaCodec收到ACodec发的消息之后会更新updateBuffers(kPortIndexOutput, msg),同时onOutputBufferAvailable()中通知Decoder。
1.ACodec的onOMXFillBufferDone;
bool ACodec::BaseState::onOMXFillBufferDone(
IOMX::buffer_id bufferID,
size_t rangeOffset, size_t rangeLength,
OMX_U32 flags,
int64_t timeUs,
int fenceFd) {
ALOGV("[%s] onOMXFillBufferDone %u time %" PRId64 " us, flags = 0x%08x",
mCodec->mComponentName.c_str(), bufferID, timeUs, flags);
ssize_t index;
status_t err= OK;
#if TRACK_BUFFER_TIMING
index = mCodec->mBufferStats.indexOfKey(timeUs);
if (index >= 0) {
ACodec::BufferStats *stats = &mCodec->mBufferStats.editValueAt(index);
stats->mFillBufferDoneTimeUs = ALooper::GetNowUs();
ALOGI("frame PTS %lld: %lld",
timeUs,
stats->mFillBufferDoneTimeUs - stats->mEmptyBufferTimeUs);
mCodec->mBufferStats.removeItemsAt(index);
stats = NULL;
}
#endif
BufferInfo *info =
mCodec->findBufferByID(kPortIndexOutput, bufferID, &index);//根据bufferID找到ACodec的BufferInfo
BufferInfo::Status status = BufferInfo::getSafeStatus(info);
if (status != BufferInfo::OWNED_BY_COMPONENT) {
ALOGE("Wrong ownership in FBD: %s(%d) buffer #%u", _asString(status), status, bufferID);
mCodec->dumpBuffers(kPortIndexOutput);
mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
if (fenceFd >= 0) {
::close(fenceFd);
}
return true;
}
info->mDequeuedAt = ++mCodec->mDequeueCounter;
info->mStatus = BufferInfo::OWNED_BY_US;
if (info->mRenderInfo != NULL) {
// The fence for an emptied buffer must have signaled, but there still could be queued
// or out-of-order dequeued buffers in the render queue prior to this buffer. Drop these,
// as we will soon requeue this buffer to the surface. While in theory we could still keep
// track of buffers that are requeued to the surface, it is better to add support to the
// buffer-queue to notify us of released buffers and their fences (in the future).
mCodec->notifyOfRenderedFrames(true /* dropIncomplete */);
}
// byte buffers cannot take fences, so wait for any fence now
if (mCodec->mNativeWindow == NULL) {
(void)mCodec->waitForFence(fenceFd, "onOMXFillBufferDone");
fenceFd = -1;
}
info->setReadFence(fenceFd, "onOMXFillBufferDone");
PortMode mode = getPortMode(kPortIndexOutput);
switch (mode) {
case KEEP_BUFFERS:
break;
case RESUBMIT_BUFFERS:
{
if (rangeLength == 0 && (!(flags & OMX_BUFFERFLAG_EOS)
|| mCodec->mPortEOS[kPortIndexOutput])) {
ALOGV("[%s] calling fillBuffer %u",
mCodec->mComponentName.c_str(), info->mBufferID);
err = mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID, info->mFenceFd);//继续填充outputbuffer
info->mFenceFd = -1;
if (err != OK) {
mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
return true;
}
info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
break;
}
sp<AMessage> reply =
new AMessage(kWhatOutputBufferDrained, mCodec);//ACodec生成reply消息,最终会传给MediaCodec
if (!mCodec->mSentFormat && rangeLength > 0) {
mCodec->sendFormatChange(reply);
}
if (mCodec->usingMetadataOnEncoderOutput()) {
native_handle_t *handle = NULL;
VideoGrallocMetadata &grallocMeta = *(VideoGrallocMetadata *)info->mData->data();
VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)info->mData->data();
if (info->mData->size() >= sizeof(grallocMeta)
&& grallocMeta.eType == kMetadataBufferTypeGrallocSource) {
handle = (native_handle_t *)(uintptr_t)grallocMeta.pHandle;
} else if (info->mData->size() >= sizeof(nativeMeta)
&& nativeMeta.eType == kMetadataBufferTypeANWBuffer) {
#ifdef OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
// ANativeWindowBuffer is only valid on 32-bit/mediaserver process
handle = NULL;
#else
handle = (native_handle_t *)nativeMeta.pBuffer->handle;
#endif
}
info->mData->meta()->setPointer("handle", handle);
info->mData->meta()->setInt32("rangeOffset", rangeOffset);
info->mData->meta()->setInt32("rangeLength", rangeLength);
} else {
info->mData->setRange(rangeOffset, rangeLength);
}
#if 0
if (mCodec->mNativeWindow == NULL) {
if (IsIDR(info->mData)) {
ALOGI("IDR frame");
}
}
#endif
if (mCodec->mSkipCutBuffer != NULL) {
mCodec->mSkipCutBuffer->submit(info->mData);
}
info->mData->meta()->setInt64("timeUs", timeUs);
info->mData->meta()->setObject("graphic-buffer", info->mGraphicBuffer);//在info的mDate(sp<ABuffer>)的mMeta(sp<AMessage>)中设置graphic-buffer
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);//发给MediaCodec的消息
notify->setInt32("buffer-id", info->mBufferID);
notify->setBuffer("buffer", info->mData);
notify->setInt32("flags", flags);
reply->setInt32("buffer-id", info->mBufferID);//reply在发给(传给)MediaCodec的BufferInfo的mNotify的时候,已经设置的buffer-id
(void)mCodec->setDSModeHint(reply, flags, timeUs);
notify->setMessage("reply", reply);//把reply设进去,用于MediaCodec向ACodec发消息
notify->post();//notify发出去之后MediaCodec会处理
info->mStatus = BufferInfo::OWNED_BY_DOWNSTREAM;
if (flags & OMX_BUFFERFLAG_EOS) {
ALOGV("[%s] saw output EOS", mCodec->mComponentName.c_str());
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", CodecBase::kWhatEOS);
notify->setInt32("err", mCodec->mInputEOSResult);
notify->post();
mCodec->mPortEOS[kPortIndexOutput] = true;
}
break;
}
case FREE_BUFFERS:
err = mCodec->freeBuffer(kPortIndexOutput, index);
if (err != OK) {
mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
return true;
}
break;
default:
ALOGE("Invalid port mode: %d", mode);
return false;
}
return true;
}
2.MediaCodec收到ACodec发的消息之后会更新updateBuffers(kPortIndexOutput, msg);同时onOutputBufferAvailable()中通知Decoder
case CodecBase::kWhatDrainThisBuffer:
{
/* size_t index = */updateBuffers(kPortIndexOutput, msg);//updateBuffers
if (mState == FLUSHING
|| mState == STOPPING
|| mState == RELEASING) {
returnBuffersToCodecOnPort(kPortIndexOutput);
break;
}
sp<ABuffer> buffer;
CHECK(msg->findBuffer("buffer", &buffer));
int32_t omxFlags;
CHECK(msg->findInt32("flags", &omxFlags));
buffer->meta()->setInt32("omxFlags", omxFlags);
if (mFlags & kFlagGatherCodecSpecificData) {
// This is the very first output buffer after a
// format change was signalled, it'll either contain
// the one piece of codec specific data we can expect
// or there won't be codec specific data.
if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
status_t err =
amendOutputFormatWithCodecSpecificData(buffer);
if (err != OK) {
ALOGE("Codec spit out malformed codec "
"specific data!");
}
}
mFlags &= ~kFlagGatherCodecSpecificData;
if (mFlags & kFlagIsAsync) {
onOutputFormatChanged();
} else {
mFlags |= kFlagOutputFormatChanged;
}
}
if (mFlags & kFlagIsAsync) {
onOutputBufferAvailable();//通知Decoder
} else if (mFlags & kFlagDequeueOutputPending) {
CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID));
++mDequeueOutputTimeoutGeneration;
mFlags &= ~kFlagDequeueOutputPending;
mDequeueOutputReplyID = 0;
} else {
postActivityNotificationIfPossible();
}
break;
}
3.1 MediaCodec的updateBuffers,找到随消息过来的reply,并存放在MediaCodec的BufferInfo的mNotify中。
size_t MediaCodec::updateBuffers(
int32_t portIndex, const sp<AMessage> &msg) {
CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
uint32_t bufferID;
CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
Mutex::Autolock al(mBufferLock);
Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
for (size_t i = 0; i < buffers->size(); ++i) {
BufferInfo *info = &buffers->editItemAt(i);
if (info->mBufferID == bufferID) {
CHECK(info->mNotify == NULL);
CHECK(msg->findMessage("reply", &info->mNotify));//找到随消息过来的reply,并存放在MediaCodec的BufferInfo的mNotify中
info->mFormat =
(portIndex == kPortIndexInput) ? mInputFormat : mOutputFormat;
mAvailPortBuffers[portIndex].push_back(i);
return i;
}
}
TRESPASS();
return 0;
}
3.2 MediaCodec的onOutputBufferAvailable,通知Decoder有可用的output buffer.
void MediaCodec::onOutputBufferAvailable() {
int32_t index;
while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) {
const sp<ABuffer> &buffer =
mPortBuffers[kPortIndexOutput].itemAt(index).mData;
sp<AMessage> msg = mCallback->dup();//发送给Decoder的消息,kWhatCodecNotify
msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);//设置callbackID,CB_OUTPUT_AVAILABLE,通知有可用的outputbuffer
msg->setInt32("index", index);
msg->setSize("offset", buffer->offset());
msg->setSize("size", buffer->size());
int64_t timeUs;
CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
msg->setInt64("timeUs", timeUs);
int32_t omxFlags;
CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
uint32_t flags = 0;
if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
flags |= BUFFER_FLAG_SYNCFRAME;
}
if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
flags |= BUFFER_FLAG_CODECCONFIG;
}
if (omxFlags & OMX_BUFFERFLAG_EOS) {
flags |= BUFFER_FLAG_EOS;
}
msg->setInt32("flags", flags);
msg->post();
}
}
3.Decoder收到从MediaCodec::onOutputBufferAvailable发回的回调消息kWhatCodecNotify之后,知道有可用的buffer,就handleAnOutputBuffer.
void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
switch (msg->what()) {
case kWhatCodecNotify://MediaCodec发回的回调消息
{
int32_t cbID;
CHECK(msg->findInt32("callbackID", &cbID));
ALOGV("[%s] kWhatCodecNotify: cbID = %d, paused = %d",
mIsAudio ? "audio" : "video", cbID, mPaused);
if (mPaused) {
break;
}
switch (cbID) {
case MediaCodec::CB_INPUT_AVAILABLE:
{
int32_t index;
CHECK(msg->findInt32("index", &index));
handleAnInputBuffer(index);
break;
}
case MediaCodec::CB_OUTPUT_AVAILABLE: // CB_OUTPUT_AVAILABLE,有可用的output buffer
{
int32_t index;
size_t offset;
size_t size;
int64_t timeUs;
int32_t flags;
CHECK(msg->findInt32("index", &index));
CHECK(msg->findSize("offset", &offset));
CHECK(msg->findSize("size", &size));
CHECK(msg->findInt64("timeUs", &timeUs));
CHECK(msg->findInt32("flags", &flags));
handleAnOutputBuffer(index, offset, size, timeUs, flags);//开始handleAnOutputBuffer
break;
}
case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:
{
sp<AMessage> format;
CHECK(msg->findMessage("format", &format));
handleOutputFormatChange(format);
break;
}
case MediaCodec::CB_ERROR:
{
status_t err;
CHECK(msg->findInt32("err", &err));
ALOGE("Decoder (%s) reported error : 0x%x",
mIsAudio ? "audio" : "video", err);
handleError(err);
break;
}
default:
{
TRESPASS();
break;
}
}
break;
}
case kWhatRenderBuffer:
{
if (!isStaleReply(msg)) {
onRenderBuffer(msg);
}
break;
}
case kWhatSetVideoSurface:
{
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<RefBase> obj;
CHECK(msg->findObject("surface", &obj));
sp<Surface> surface = static_cast<Surface *>(obj.get()); // non-null
int32_t err = INVALID_OPERATION;
// NOTE: in practice mSurface is always non-null, but checking here for completeness
if (mCodec != NULL && mSurface != NULL) {
// TODO: once AwesomePlayer is removed, remove this automatic connecting
// to the surface by MediaPlayerService.
//
// at this point MediaPlayerService::client has already connected to the
// surface, which MediaCodec does not expect
err = native_window_api_disconnect(surface.get(), NATIVE_WINDOW_API_MEDIA);
if (err == OK) {
err = mCodec->setSurface(surface);
ALOGI_IF(err, "codec setSurface returned: %d", err);
if (err == OK) {
// reconnect to the old surface as MPS::Client will expect to
// be able to disconnect from it.
(void)native_window_api_connect(mSurface.get(), NATIVE_WINDOW_API_MEDIA);
mSurface = surface;
}
}
if (err != OK) {
// reconnect to the new surface on error as MPS::Client will expect to
// be able to disconnect from it.
(void)native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA);
}
}
sp<AMessage> response = new AMessage;
response->setInt32("err", err);
response->postReply(replyID);
break;
}
default:
DecoderBase::onMessageReceived(msg);
break;
}
}
4.Decoder::handleAnOutputBuffer, 之后Decoder要与Render交互确定是否渲染。参看《NuPlayerDecoder与NuPlayerRender分析》
bool NuPlayer::Decoder::handleAnOutputBuffer(
size_t index,
size_t offset,
size_t size,
int64_t timeUs,
int32_t flags) {
// CHECK_LT(bufferIx, mOutputBuffers.size());
sp<ABuffer> buffer;
mCodec->getOutputBuffer(index, &buffer);//用index找到对应的ABuffer
if (index >= mOutputBuffers.size()) {
for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
mOutputBuffers.add();
}
}
mOutputBuffers.editItemAt(index) = buffer;
buffer->setRange(offset, size);
buffer->meta()->clear();
buffer->meta()->setInt64("timeUs", timeUs);
setPcmFormat(buffer->meta());
bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
// we do not expect CODECCONFIG or SYNCFRAME for decoder
sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this);//Decoder发给Renderer的用于回调的消息
reply->setSize("buffer-ix", index);
reply->setInt32("generation", mBufferGeneration);
if (eos) {
ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video");
buffer->meta()->setInt32("eos", true);
reply->setInt32("eos", true);
} else if (mSkipRenderingUntilMediaTimeUs >= 0) {
if (timeUs < mSkipRenderingUntilMediaTimeUs) {
ALOGV("[%s] dropping buffer at time %lld as requested.",
mComponentName.c_str(), (long long)timeUs);
reply->post();
return true;
}
mSkipRenderingUntilMediaTimeUs = -1;
}
mNumFramesTotal += !mIsAudio;
// wait until 1st frame comes out to signal resume complete
notifyResumeCompleteIfNecessary();
if (mRenderer != NULL) {
// send the buffer to renderer.
mRenderer->queueBuffer(mIsAudio, buffer, reply);//Renderer的相关处理,注意设进去的reply
if (eos && !isDiscontinuityPending()) {
mRenderer->queueEOS(mIsAudio, ERROR_END_OF_STREAM);
}
}
return true;
}
5. Decoder 接受 renderer对(mVideoQueue的QueueEntry)buffer发回的消费消息,并在Decoder的onRenderBuffer中调用MediaCodec的mCodec>renderOutputBufferAndRelease(bufferIx, timestampNs)或者mCodec->releaseOutputBuffer(bufferIx)。
5.1. Decoder 接受 renderer对(mVideoQueue的QueueEntry)buffer发回的消息进行消费
case kWhatRenderBuffer:
{
if (!isStaleReply(msg)) {
onRenderBuffer(msg);
}
break;
}
5.2 Decoder的onRenderBuffer
void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
status_t err;
int32_t render;
size_t bufferIx;
int32_t eos;
CHECK(msg->findSize("buffer-ix", &bufferIx));//找到buffer-ix
if (!mIsAudio) {
int64_t timeUs;
sp<ABuffer> buffer = mOutputBuffers[bufferIx];
buffer->meta()->findInt64("timeUs", &timeUs);
if (mCCDecoder != NULL && mCCDecoder->isSelected()) {
mCCDecoder->display(timeUs);
}
}
if (msg->findInt32("render", &render) && render) {
int64_t timestampNs;
CHECK(msg->findInt64("timestampNs", ×tampNs));
err = mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs);//Decoder发给MediaCodec渲染加release
} else {
mNumOutputFramesDropped += !mIsAudio;
err = mCodec->releaseOutputBuffer(bufferIx);//不渲染直接release
}
if (err != OK) {
ALOGE("failed to release output buffer for %s (err=%d)",
mComponentName.c_str(), err);
handleError(err);
}
if (msg->findInt32("eos", &eos) && eos
&& isDiscontinuityPending()) {
finishHandleDiscontinuity(true /* flushOnTimeChange */);
}
}
6.Decoder到MediaCodec
MediaCodec的mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs)或者mCodec->releaseOutputBuffer(bufferIx),一个会真的渲染一个不渲染.
最终会到MediaCodec的onReleaseOutputBuffer(msg)处理.
status_t MediaCodec::renderOutputBufferAndRelease(size_t index, int64_t timestampNs) {
sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);//发送消息
msg->setSize("index", index);
msg->setInt32("render", true);//设置是否渲染
msg->setInt64("timestampNs", timestampNs);//timestampNs
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t MediaCodec::releaseOutputBuffer(size_t index) {
sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this);//发送消息
msg->setSize("index", index);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
然后到MediaCodec的onReleaseOutputBuffer(msg)处理;
case kWhatReleaseOutputBuffer:
{
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (!isExecuting()) {
PostReplyWithError(replyID, INVALID_OPERATION);
break;
} else if (mFlags & kFlagStickyError) {
PostReplyWithError(replyID, getStickyError());
break;
}
status_t err = onReleaseOutputBuffer(msg);//onReleaseOutputBuffer(msg)处理
PostReplyWithError(replyID, err);
break;
}
//onReleaseOutputBuffer
status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) {
size_t index;
CHECK(msg->findSize("index", &index));
int32_t render;
if (!msg->findInt32("render", &render)) { //设置了render为true则渲染,否则不渲染直接release buffer
render = 0;
}
if (!isExecuting()) {
return -EINVAL;
}
if (index >= mPortBuffers[kPortIndexOutput].size()) {
return -ERANGE;
}
BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
if (info->mNotify == NULL || !info->mOwnedByClient) {
return -EACCES;
}
// synchronization boundary for getBufferAndFormat
{
Mutex::Autolock al(mBufferLock);
info->mOwnedByClient = false;
}
if (render && info->mData != NULL && info->mData->size() != 0) { //render是否为true
info->mNotify->setInt32("render", true);//reply设置render为true
int64_t mediaTimeUs = -1;
info->mData->meta()->findInt64("timeUs", &mediaTimeUs);
int64_t renderTimeNs = 0;
if (!msg->findInt64("timestampNs", &renderTimeNs)) {//Renderer给的timestampNs
// use media timestamp if client did not request a specific render timestamp
ALOGV("using buffer PTS of %lld", (long long)mediaTimeUs);
renderTimeNs = mediaTimeUs * 1000;
}
info->mNotify->setInt64("timestampNs", renderTimeNs);
if (mSoftRenderer != NULL) {//是否用softRender,如果设置过SoftwareRender而则用软件渲染,不然就让ACodec去硬件渲染
std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render(
info->mData->data(), info->mData->size(),
mediaTimeUs, renderTimeNs, NULL, info->mFormat);
// if we are running, notify rendered frames
if (!doneFrames.empty() && mState == STARTED && mOnFrameRenderedNotification != NULL) {
sp<AMessage> notify = mOnFrameRenderedNotification->dup();
sp<AMessage> data = new AMessage;
if (CreateFramesRenderedMessage(doneFrames, data)) {
notify->setMessage("data", data);
notify->post();
}
}
}
}
info->mNotify->post();//info-mNotify保存着ACodec传过来的reply消息,ACdoec会硬件渲染,不管硬件渲染还是软件熏染都会fillbuffer
info->mNotify = NULL;
return OK;
}
7.MediaCodec到ACodec,MediaCodec::onReleaseOutputBuffer中判断使用硬件渲染后者软件渲染,并使用info->mNotify中ACodec传过来的reply消息,最终发给ACodec接受并处理。
ACodec接受消息后调用onOutputBufferDrained(msg),看是正在的硬件渲染。
bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatInputBufferFilled:
{
onInputBufferFilled(msg);
break;
}
case kWhatOutputBufferDrained://MediaCodec消费reply消息
{
onOutputBufferDrained(msg);
break;
}
case ACodec::kWhatOMXMessageList:
{
return checkOMXMessage(msg) ? onOMXMessageList(msg) : true;
}
case ACodec::kWhatOMXMessageItem:
{
// no need to check as we already did it for kWhatOMXMessageList
return onOMXMessage(msg);
}
case ACodec::kWhatOMXMessage:
{
return checkOMXMessage(msg) ? onOMXMessage(msg) : true;
}
case ACodec::kWhatSetSurface:
{
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<RefBase> obj;
CHECK(msg->findObject("surface", &obj));
status_t err = mCodec->handleSetSurface(static_cast<Surface *>(obj.get()));
sp<AMessage> response = new AMessage;
response->setInt32("err", err);
response->postReply(replyID);
break;
}
case ACodec::kWhatCreateInputSurface:
case ACodec::kWhatSetInputSurface:
case ACodec::kWhatSignalEndOfInputStream:
{
// This may result in an app illegal state exception.
ALOGE("Message 0x%x was not handled", msg->what());
mCodec->signalError(OMX_ErrorUndefined, INVALID_OPERATION);
return true;
}
case ACodec::kWhatOMXDied:
{
// This will result in kFlagSawMediaServerDie handling in MediaCodec.
ALOGE("OMX/mediaserver died, signalling error!");
mCodec->signalError(OMX_ErrorResourcesLost, DEAD_OBJECT);
break;
}
case ACodec::kWhatReleaseCodecInstance:
{
ALOGI("[%s] forcing the release of codec",
mCodec->mComponentName.c_str());
status_t err = mCodec->mOMX->freeNode(mCodec->mNode);
ALOGE_IF("[%s] failed to release codec instance: err=%d",
mCodec->mComponentName.c_str(), err);
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
notify->post();
break;
}
default:
return false;
}
return true;
}
8.ACodec的onOutputBufferDrained(msg);//真正的硬件渲染
void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {
IOMX::buffer_id bufferID;
CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));//找到bufferID
ssize_t index;
BufferInfo *info = mCodec->findBufferByID(kPortIndexOutput, bufferID, &index);//根据bufferID找到ACodec的BufferInfo
BufferInfo::Status status = BufferInfo::getSafeStatus(info);
if (status != BufferInfo::OWNED_BY_DOWNSTREAM) {
ALOGE("Wrong ownership in OBD: %s(%d) buffer #%u", _asString(status), status, bufferID);
mCodec->dumpBuffers(kPortIndexOutput);
mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
return;
}
android_native_rect_t crop;
if (msg->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom)) {
status_t err = native_window_set_crop(mCodec->mNativeWindow.get(), &crop);
ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err);
}
bool skip = mCodec->getDSModeHint(msg);
int32_t render;
if (!skip && mCodec->mNativeWindow != NULL //mCodec->mNativeWindow != NULL 才用硬件渲染。软件渲染在MediaCodec的onReleaseOutputBuffer已经用SoftwareRender处理
&& msg->findInt32("render", &render) && render != 0
&& info->mData != NULL && info->mData->size() != 0) {
ATRACE_NAME("render");
// The client wants this buffer to be rendered.
// save buffers sent to the surface so we can get render time when they return
int64_t mediaTimeUs = -1;
info->mData->meta()->findInt64("timeUs", &mediaTimeUs);
if (mediaTimeUs >= 0) {
mCodec->mRenderTracker.onFrameQueued(
mediaTimeUs, info->mGraphicBuffer, new Fence(::dup(info->mFenceFd)));
}
int64_t timestampNs = 0;
if (!msg->findInt64("timestampNs", ×tampNs)) {
// use media timestamp if client did not request a specific render timestamp
if (info->mData->meta()->findInt64("timeUs", ×tampNs)) {
ALOGV("using buffer PTS of %lld", (long long)timestampNs);
timestampNs *= 1000;
}
}
status_t err;
err = native_window_set_buffers_timestamp(mCodec->mNativeWindow.get(), timestampNs);//使用timestampNs
ALOGW_IF(err != NO_ERROR, "failed to set buffer timestamp: %d", err);
info->checkReadFence("onOutputBufferDrained before queueBuffer");
err = mCodec->mNativeWindow->queueBuffer(
mCodec->mNativeWindow.get(), info->mGraphicBuffer.get(), info->mFenceFd);//插入mNaiveWindow(surface)进行渲染
info->mFenceFd = -1;
if (err == OK) {
info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
} else {
ALOGE("queueBuffer failed in onOutputBufferDrained: %d", err);
mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
info->mStatus = BufferInfo::OWNED_BY_US;
// keeping read fence as write fence to avoid clobbering
info->mIsReadFence = false;
}
} else {
if (mCodec->mNativeWindow != NULL &&
(info->mData == NULL || info->mData->size() != 0)) {
// move read fence into write fence to avoid clobbering
info->mIsReadFence = false;
ATRACE_NAME("frame-drop");
}
info->mStatus = BufferInfo::OWNED_BY_US;
}
PortMode mode = getPortMode(kPortIndexOutput);
switch (mode) {
case KEEP_BUFFERS:
{
// XXX fishy, revisit!!! What about the FREE_BUFFERS case below?
if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {
// We cannot resubmit the buffer we just rendered, dequeue
// the spare instead.
info = mCodec->dequeueBufferFromNativeWindow();
}
break;
}
case RESUBMIT_BUFFERS:
{
if (!mCodec->mPortEOS[kPortIndexOutput]) {
if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) {
// We cannot resubmit the buffer we just rendered, dequeue
// the spare instead.
info = mCodec->dequeueBufferFromNativeWindow();
}
if (info != NULL) {
ALOGV("[%s] calling fillBuffer %u",
mCodec->mComponentName.c_str(), info->mBufferID);
info->checkWriteFence("onOutputBufferDrained::RESUBMIT_BUFFERS");
status_t err = mCodec->mOMX->fillBuffer(
mCodec->mNode, info->mBufferID, info->mFenceFd);//渲染之后重新填充buffer,然后回调onOMXFillBufferDone
info->mFenceFd = -1;
if (err == OK) {
info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
} else {
mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
}
}
}
break;
}
case FREE_BUFFERS:
{
status_t err = mCodec->freeBuffer(kPortIndexOutput, index);
if (err != OK) {
mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
}
break;
}
default:
ALOGE("Invalid port mode: %d", mode);
return;
}
}