Android播放视频从解码到显示实质也是BufferQueue的生产消费的过程,如下图所示:

其中生产者是Surface,消费者是SurfaceFlinger。

本文主要针对Surface进行分析,理清ANativeWindow 和 Surface之间的关系。

ANativeWindow的定义如下:

// 代码位置 frameworks/native/libs/nativewindow/include/system/window.h...struct ANativeWindow
{...    int     (*dequeueBuffer_DEPRECATED)(struct ANativeWindow* window,struct ANativeWindowBuffer** buffer);...   int     (*queueBuffer_DEPRECATED)(struct ANativeWindow* window,struct ANativeWindowBuffer* buffer);...int     (*query)(const struct ANativeWindow* window,int what, int* value);...int     (*perform)(struct ANativeWindow* window,int operation, ... );...int     (*cancelBuffer_DEPRECATED)(struct ANativeWindow* window,struct ANativeWindowBuffer* buffer);...int     (*dequeueBuffer)(struct ANativeWindow* window,struct ANativeWindowBuffer** buffer, int* fenceFd);...int     (*queueBuffer)(struct ANativeWindow* window,struct ANativeWindowBuffer* buffer, int fenceFd);    ...int     (*cancelBuffer)(struct ANativeWindow* window,struct ANativeWindowBuffer* buffer, int fenceFd);
}  ...static inline int native_window_set_buffer_count(struct ANativeWindow* window,size_t bufferCount)
{return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
}...static inline int native_window_dequeue_buffer_and_wait(ANativeWindow *anw,struct ANativeWindowBuffer** anb) {return anw->dequeueBuffer_DEPRECATED(anw, anb);
}...

Surface的定义如下:

// frameworks/native/libs/gui/include/gui/Surface.h...class Surface                      : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
{
public:...

可见Surface是ANativeWindow的子类

再看如下代码:

// frameworks/native/libs/gui/Surface.cpp...Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp): mGraphicBufferProducer(bufferProducer),mCrop(Rect::EMPTY_RECT),mBufferAge(0),mGenerationNumber(0),mSharedBufferMode(false),mAutoRefresh(false),mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),mSharedBufferHasBeenQueued(false),mQueriedSupportedTimestamps(false),mFrameTimestampsSupportsPresent(false),mEnableFrameTimestamps(false),mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) {// Initialize the ANativeWindow function pointers.ANativeWindow::setSwapInterval  = hook_setSwapInterval;ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;ANativeWindow::cancelBuffer     = hook_cancelBuffer;ANativeWindow::queueBuffer      = hook_queueBuffer;ANativeWindow::query            = hook_query;ANativeWindow::perform          = hook_perform;ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;...

Surface构造时,会对ANativeWindow定义的那些函数进行初始化,hook_xxx表示钩子函数,说明ANativeWindow真正的实现是在Surface里面。

以MediaCodec为例分析一下申请解码输出buffer到送显示的过程,这两个过程也是生产者dequeue(申请buffer)和queue(送显示)的过程。

Dequeue

// frameworks/av/media/libstagefright/ACodec.cpp...status_t ACodec::allocateOutputBuffersFromNativeWindow() {// This method only handles the non-metadata mode (or simulating legacy// mode with metadata, which is transparent to ACodec).CHECK(!storingMetadataInDecodedBuffers());OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers;status_t err = configureOutputBuffersFromNativeWindow(&bufferCount, &bufferSize, &minUndequeuedBuffers, true /* preregister */);if (err != 0)return err;mNumUndequeuedBuffers = minUndequeuedBuffers;static_cast<Surface*>(mNativeWindow.get())->getIGraphicBufferProducer()->allowAllocation(true);ALOGV("[%s] Allocating %u buffers from a native window of size %u on ""output port",mComponentName.c_str(), bufferCount, bufferSize);// Dequeue buffers and send them to OMXfor (OMX_U32 i = 0; i < bufferCount; i++) {ANativeWindowBuffer *buf;int fenceFd;err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd);if (err != 0) {ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);break;}sp<GraphicBuffer> graphicBuffer(GraphicBuffer::from(buf));BufferInfo info;info.mStatus = BufferInfo::OWNED_BY_US;info.mFenceFd = fenceFd;info.mIsReadFence = false;info.mRenderInfo = NULL;info.mGraphicBuffer = graphicBuffer;info.mNewGraphicBuffer = false;// TODO: We shouln't need to create MediaCodecBuffer. In metadata mode//       OMX doesn't use the shared memory buffer, but some code still//       access info.mData. Create an ABuffer as a placeholder.info.mData = new MediaCodecBuffer(mOutputFormat, new ABuffer(bufferSize));info.mCodecData = info.mData;
...
// frameworks/native/libs/gui/Surface.cpp...int Surface::hook_dequeueBuffer(ANativeWindow* window,                                                                                            ANativeWindowBuffer** buffer, int* fenceFd) {Surface* c = getSelf(window);return c->dequeueBuffer(buffer, fenceFd);
}...int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {ATRACE_CALL();ALOGV("Surface::dequeueBuffer");uint32_t reqWidth;uint32_t reqHeight;PixelFormat reqFormat;uint64_t reqUsage;bool enableFrameTimestamps;{Mutex::Autolock lock(mMutex);if (mReportRemovedBuffers) {mRemovedBuffers.clear();}reqWidth = mReqWidth ? mReqWidth : mUserWidth;reqHeight = mReqHeight ? mReqHeight : mUserHeight;reqFormat = mReqFormat;reqUsage = mReqUsage;
...FrameEventHistoryDelta frameTimestamps;status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth,        reqHeight, reqFormat, reqUsage, &mBufferAge,enableFrameTimestamps ? &frameTimestamps: nullptr);
...

ACodec中allocateOutputBuffersFromNativeWindow调用mNativeWindow->dequeueBuffer,通过Surface的hook_dequeueBuffer最终调用到Surface的dequeueBuffer,最后mGraphicBufferProducer->dequeueBuffer。这个mGraphicBufferProducer的具体实现就是一个BufferQueue,到此可以知道解码申请输出缓存的时候是通过Surface从BufferQueue中dequeue具体数目的匿名共享buffer进行解码显示轮转。

Queue

// frameworks/av/media/libstagefright/ACodec.cpp...void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {IOMX::buffer_id bufferID;      CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));sp<RefBase> obj;               CHECK(msg->findObject("buffer", &obj));sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());int32_t discarded = 0;         msg->findInt32("discarded", &discarded);...info->mData = buffer;int32_t render;if (mCodec->mNativeWindow != NULL&& msg->findInt32("render", &render) && render != 0&& !discarded && buffer->size() != 0) {ATRACE_NAME("render");// The client wants this buffer to be rendered.android_native_rect_t crop;if (buffer->format()->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom)) {// NOTE: native window uses extended right-bottom coordinate++crop.right;++crop.bottom;if (memcmp(&crop, &mCodec->mLastNativeWindowCrop, sizeof(crop)) != 0) {mCodec->mLastNativeWindowCrop = crop;status_t err = native_window_set_crop(mCodec->mNativeWindow.get(), &crop);ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err);}}...info->checkReadFence("onOutputBufferDrained before queueBuffer");err = mCodec->mNativeWindow->queueBuffer(mCodec->mNativeWindow.get(), info->mGraphicBuffer.get(), info->mFenceFd);...
// frameworks/native/libs/gui/Surface.cpp...int Surface::hook_queueBuffer(ANativeWindow* window,                                                                                              ANativeWindowBuffer* buffer, int fenceFd) {Surface* c = getSelf(window);return c->queueBuffer(buffer, fenceFd);
}...int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {ATRACE_CALL();ALOGV("Surface::queueBuffer");Mutex::Autolock lock(mMutex);int64_t timestamp;bool isAutoTimestamp = false;...nsecs_t now = systemTime();status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);mLastQueueDuration = systemTime() - now;...

ACodec的onOutputBufferDrained调用mNativeWindow->queueBuffer,通过Surface的hook_queueBuffer最终调用到Surface的queueBuffer,最后调用mGraphicBufferProducer->queueBuffer完成向BufferQueue送显示帧的过程。

以上代码均来源于Android Pie工程,通过这几段代码期望能大体了解Android视频解码到现实的基本流程

小结:

  1. ANativeWindow是android的本地窗口,Surface是ANativeWindow的子类,也是ANativeWindow的具体实现。
  2. IGraphicBufferProducer的具体实现实质就是BufferQueue,创建Surface的时候作为传参。
  3. 解码和显示共享内存的方式可以节省内存,减小解码到显示消耗时间。

ANativeWindow 和 Surface相关推荐

  1. Camera Surface 从应用到cameraserver的流转

    一.Android相机应用与Surface Camera应用的预览一般通过SurfaceView去显示,SurfaceView作为显示的载体, Surface surface = mSurfaceVi ...

  2. Android 图形架构 之三—— 创建Layer、Surface、SurfaceControl

    前言 上一篇我们分析了,app与SurfaceFlinger建立连接的过程,现在我们就可以继续往下分析,看下创建Surface的过程. 我们可以将Surface理解为一个绘图表面,Android应用程 ...

  3. android camera 显示过程,Android Camera2 API显示已处理的预览图像

    澄清问题后编辑;最初的答案在底部 取决于您在哪里进行处理. 如果您正在使用RenderScript,则可以将Surface从SurfaceView或TextureView连接到分配(使用setSurf ...

  4. android从应用到驱动之—camera(2)---cameraHAL的实现

    本来想用这一篇博客把cameraHAL的实现和流程都给写完的.搞了半天,东西实在是太多了.这篇先写cameraHAL的基本实现框架,下一篇在具体写camerahal的流程吧. cameraHAL的实现 ...

  5. camera 之 createCaptureSession

    camera 之 createCaptureSession 1.createCaptureSession 参数解析 2.createCaptureSession 流程分析 3.时序图 1.create ...

  6. H264视频传输、编解码----FFmpeg软解码

    记录一下之前项目的实际使用过程. 将按照Java层------>JNI接口------>JNI代码中使用FFmpeg解码. 首先Java层: public class CodecWrapp ...

  7. virtual camera

    敲下标题的这一刻,内心还是有点儿小激动的.毕竟虚拟摄像头,也做了几个星期了,硬生生的在android原生系统不支持的情况下,绕过重重限制,完美的实现了这一功能.接下来几天,终于可以睡个好觉了. 好了, ...

  8. Android 源码 Camera2 预览流程分析一

    先上一段典型的预览代码,梳理一下相机预览流程. 从 TextureView 获取到 SurfaceTexture 将 SurfaceTexture 默认缓冲区的大小配置为相机预览的大小 新建一个 Su ...

  9. Camera Framework 分析

    Camera Framework 分析,本文主要介绍 Camera API2 相关. 类文件速查表 类文件目录 1 2 3 4 5 6 1. Framework Java API1:framework ...

最新文章

  1. python基础教程博客_python基础教程(一)
  2. 在cmd指令看计算机位数,在.cmd中使用Windows命令来测试32位或64位并运行命令
  3. python控制电脑关机_Python利用智能音箱语音控制电脑开关机
  4. Springboot国际化信息(i18n)解析
  5. 对比学习:充分利用有限的医学标注数据 |NeurIPS 2020
  6. 使用LazZiya.ExpressLocalization开发多语言ASP.NET Core 2.x项目
  7. awk取文本列_Linux:使用awk命令获取文本的某一行,某一列;sed插入指定的内容到指定文件中...
  8. hadoop3.1集成tez和tez-ui
  9. 用MDT 2012为企业部署windows 7(四)--创建Deploymentshare共享以及介绍一些选项的具体作用...
  10. Nginx 进程间通信
  11. 恢复系统管理员密码的五大奇招
  12. MATLAB小技巧(28)模糊综合评价
  13. 智通标书制作系统 5.1
  14. 经理人必看的十个管理网站
  15. 登录时用户名或密码错误弹窗提醒重新登录
  16. linuxmint/ubuntu修改主机名hostnam
  17. [转载]如何塑造个人品牌:张何个人网络品牌营销全攻略
  18. [日更-2019.3.31]如何下载Nexus5的LineageOS14.1(cm-14.1)系统源码并编译、刷机
  19. 芯片读取设备详解+U盘芯片flash读取分析实录_一篇看够
  20. Fiddler创建根证书不成功和无法找到根证书的解决方法

热门文章

  1. 双重预防机制数字化系统为施工进度提供安全保障
  2. 如何给PPT文件添加水印?
  3. python开发com组件_Python生成COM组件(原创)
  4. Worthington哺乳动物乳酸脱氢酶研究——特点及测定方案
  5. 智能机器人与智能系统(大连理工大学庄严教授)——1.机器人与移动机器人
  6. 四种百度文库资源直接下载的方法!不用代码,不用券!一键搞定!
  7. WordPress 简洁自适应博客杂志类CX-MULTI主题
  8. jQuery模仿淘宝商品评价
  9. 前端开发人员必须了解的七大技能图谱(http://geek.csdn.net/news/detail/88239)
  10. linux怎么设置桌面朝向,Android判断相机图片朝向