您的位置:首页 > 移动开发 > Android开发

android 解码出来的视频frame数据,是如何一步步的传递到显示端的(使用hwc composer online 合成)

2016-02-22 21:19 1326 查看


1,初始化的时候,


-----> allocateOutputBuffersFromNativeWindow

-----> status_t OMXNodeInstance::useGraphicBuffer

-----> virtual status_t useGraphicBuffer

-----> status_t OMXNodeInstance::useGraphicBuffer2_l

-----> OMX_UseBuffer

-----> SEC_OMX_UseBuffer //temp_bufferHeader->pBuffer = pBuffer;

//这里就是把graphicBuffer->handle复制给了bufferHeader->pBuffer,也就是data_ptr,也就是存贮一些地址值的内存,也就是graphicBuffer->handle中最终存储了解码完毕数据存放地址信息,最后传给显示

说到底,就是MediaBuffer中指向了有效的data_ptr, MediaBuffer指向了GraphicBuffer,graphicBuffer->handle实际上就是data_ptr

所以一开始传的是MediaBuffer,最后又传的GraphicBuffer, 但是都能使用到data_ptr



2,解码过程运转起来之后


-----> SEC_OutputBufferGetQueue里面,把pSECComponent->processData[OUTPUT_PORT_INDEX].dataBuffer = dataBuffer->bufferHeader->pBuffer;

-----> SEC_MFC_H264_Decode_Nonblock里面

-----> SsbSipMfcDecGetOutBuf 获取到解码完的数据物理地址填充到dataBuffer,也就是填充到了dataBuffer->bufferHeader->pBuffer,然后一步步往上送

-----> sec_mfc_bufferProcess

-----> SEC_Postprocess_OutputData

-----> SEC_OutputBufferReturn

-----> FillBufferDone

-----> OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone

-----> OMX_ERRORTYPE OMX::OnFillBufferDone( node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer)

{

ALOGV("OnFillBufferDone buffer=%p", pBuffer);

omx_message msg;

msg.type = omx_message::FILL_BUFFER_DONE;

msg.node = node;

msg.u.extended_buffer_data.buffer = pBuffer;

msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;

msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;

msg.u.extended_buffer_data.flags = pBuffer->nFlags;

msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;

msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate;

msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer; ///pBuffer->pBuffer实际上就是dataBuffer->bufferHeader->pBuffer; 也就是 pSECComponent->processData[OUTPUT_PORT_INDEX].dataBuffer, 也就是SEC_MFC_H264_Decode_Nonblock里面的pOutputData->dataBuffer;

// void *pOutputBuf = (void *)pOutputData->dataBuffer; 这里的pOutputBuf的内容就传给了data_ptr

// SEC_OSAL_Memcpy(pYUVBuf[0], &(outputInfo.YPhyAddr), sizeof(outputInfo.YPhyAddr));

// SEC_OSAL_Memcpy((unsigned char *)pYUVBuf[0] + (sizeof(void *) * 1), &(outputInfo.CPhyAddr), sizeof(outputInfo.CPhyAddr));

// SEC_OSAL_Memcpy((unsigned char *)pYUVBuf[0] + (sizeof(void *) * 2), &(outputInfo.YVirAddr), sizeof(outputInfo.YVirAddr));

// SEC_OSAL_Memcpy((unsigned char *)pYUVBuf[0] + (sizeof(void *) * 3), &(outputInfo.CVirAddr), sizeof(outputInfo.CVirAddr));

// data_ptr 里面存的就是几个虚拟地址

findDispatcher(node)->post(msg);

return OMX_ErrorNone;

}

-----> void OMX::CallbackDispatcher::post(const omx_message &msg) {

Mutex::Autolock autoLock(mLock);

mQueue.push_back(msg);

mQueueChanged.signal();

}

3,stagefright的某个循环:

void OMXCodec::on_message(const omx_message &msg) {

switch (msg.type) {

case omx_message::FILL_BUFFER_DONE:

{

mFilledBuffers.push_back(i);

mBufferFilled.signal();

if (mIsEncoder) {

sched_yield();

}

}

}

FillBufferDone时候最终会通过OMX的消息机制走到OMXCodec::on_message中进入case omx_message::FILL_BUFFER_DONE:主要工作是,记录这个已经填充的buffer的索引号,然后将这个索引号保存在

mFilledBuffers.push_back(i);

mBufferFilled.signal();

看到mBufferFilled这个Condition被signal了,那么谁wait在这个Condition上呢?看上OMXCodec::read函数中我红色标注的部分。原来在OMXCodec::read函数的后半段中会一直

while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {

if ((err = waitForBufferFilled_l()) != OK) {

return err;

}

}

那么FILL_BUFFER_DONE之后,在OMXCodec::read函数中被返回给AwesomePlayer的mVideoBuffer就是在OMX框架中outPutPort上的buffer。

通过上面的分析可以看到,虽然在OMX框架中 Input/OutPutPort上的buffer的生产和消费是异步,但是还是通过了一个Condition mBufferFilled来做同步。这个生产者消费者的问题,来用一个信号量做同步,还是比较好的。

4,stagefright的某个循环:

void AwesomePlayer::onVideoEvent()

-----> status_t err = mVideoSource->read(&mVideoBuffer, &options);

-----> mVideoRenderer->render(mVideoBuffer);

-----> virtual void render(MediaBuffer *buffer) {

ATRACE_CALL();

int64_t timeUs;

CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));

native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000);

status_t err = mNativeWindow->queueBuffer(

mNativeWindow.get(), buffer->graphicBuffer().get(), -1); //在此之前,传递的都是MediaBuffer,在allocateOutputBuffersFromNativeWindow初始化的时候,MediaBuffer中的成员已经指向。graphicBuffer。从这一步开始,一步步传递的是graphicBuffer。但是前面讲了,graphicBuffer->handle实际上就是要传递的buffer。里面包含了解码物理地址

if (err != 0) {

ALOGE("queueBuffer failed with error %s (%d)", strerror(-err),

-err);

return;

}

sp<MetaData> metaData = buffer->meta_data();

metaData->setInt32(kKeyRendered, 1);

}

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××以上为stagefright的内容,以下为surfaceflinger的内容×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

-----> mNativeWindow->queueBuffer

-----> ANativeWindow::queueBuffer = hook_queueBuffer;

-----> Surface::hook_queueBuffer()

-----> int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) //查出32个slot buffer中的哪一个,把index传下去

-----> virtual status_t queueBuffer

-----> status_t BnGraphicBufferProducer::onTransact

case QUEUE_BUFFER: {

CHECK_INTERFACE(IGraphicBufferProducer, data, reply);

int buf = data.readInt32();

QueueBufferInput input(data);

QueueBufferOutput* const output =

reinterpret_cast<QueueBufferOutput *>(

reply->writeInplace(sizeof(QueueBufferOutput)));

status_t result = queueBuffer(buf, input, output);

reply->writeInt32(result);

return NO_ERROR;

} break;

-----> status_t BufferQueue::queueBuffer //item.mBuf = buf; mQueue.push_back(item); listener->onFrameAvailable();

-----> void FramebufferSurface::onFrameAvailable() 里面nextBuffer获得GraphicBuffer

-----> mHwc.fbPost

-----> int HWComposer::fbPost

-----> status_t HWComposer::setFramebufferTarget //disp.fbTargetHandle = buf->handle; disp.framebufferTarget->handle = disp.fbTargetHandle; 前面已经讲了,graphicBuffer->handle 存的就是有效数据。 也就是最终disp.framebufferTarget->handle指向有效数据

在初始化的时候,HWComposer::createWorkList里面 disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1];让framebufferTarget指向了disp.list->hwLayers[numLayers - 1]。 所以这里最终disp.list->hwLayers[numLayers - 1]->handle指向有效数据



5, Vsync事件触发


-----> dispatchRefresh

-----> SurfaceFlinger::onMessageReceived

-----> handleMessageRefresh

-----> doComposition

-----> postFramebuffer

-----> hwc.commit();

-----> status_t HWComposer::commit()

-----> err = mHwc->set(mHwc, mNumDisplays, mLists);

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××以上为surfaceflinger的内容,以下为exynos HAL的内容×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

----->static int exynos4_set (该函数位于HWC.cpp里面)

-----> exynos4_set

-----> exynos4_set_fimd

-----> exynos4_post_fimd //cur = &contents->hwLayers[win->layer_index];

-----> set_src_dst_img_rect //取 contents->hwLayers[win->layer_index]->handle, 关键数据存入struct sec_img *src_img,

-----> runFimc

-----> runFimcCore

-----> fimc_handle_oneshot

-----> fimc_v4l2_queue (提交YUV,完成颜色空间转换, 函数位于SecHWCUtils.cpp)

-----> window_pan_display (把数据内容打到屏幕上)

总结:

1,graphicBuffer->handle 存放有效数据。具体在哪里初始化申请的,待研究

2,OMX,stagefright,surfaceflinger,HWcomposer说到底就是在传递这个graphicBuffer->handle

3,传到HWcomposer后,并不是马上刷新屏幕。而是先用setFramebufferTarget存好。等Vsync时机到了,刷新
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: