ANativeWindow 和 Surface

article/2025/10/28 19:12:57

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.  解码和显示共享内存的方式可以节省内存,减小解码到显示消耗时间。

 

 


http://chatgpt.dhexx.cn/article/OtRFe7v5.shtml

相关文章

Android之Surface 与 SurfaceFlinger关系

通过前面的知识我们知道了&#xff0c;Android 系统从按下开机键到桌面&#xff0c;从桌面点击 App 图标到 Activity 显示的过程。但是 Activity 是怎么显示在屏幕上的呢&#xff1f;下面我们就来讨论下这一过程。 SurfaceFlinger 启动过程 SurfaceFlinger 进程是由 init 进程…

SurfaceView、SurfaceHolder与Surface

相关文章 SurfaceView、SurfaceHolder与SurfaceTextureView、SurfaceTexture与Surface 按照官方文档的说法&#xff0c;SurfaceView继承自View&#xff0c;并提供了一个独立的绘图层&#xff0c;你可以完全控制这个绘图层&#xff0c;比如说设定它的大小&#xff0c;所以Surf…

surfaceView、surface和sufaceHolder的关系

surfaceView、surface和sufaceHolder的关系 1.SurfaceView与Surface的联系2.SurfaceView3.Surface4.SurfaceHolder 1.SurfaceView与Surface的联系 简单来说&#xff0c;Surface是管理显示内容的数据&#xff08;implementsParcelable&#xff09;&#xff0c;包括存储于数据的…

线程天敌TerminateThread与SuspendThread http://blog.csdn.net/magictong/article/details/6304439

线程天敌TerminateThread与SuspendThread 标签&#xff1a; thread null delete dll c user 2011-04-06 13:22 10295人阅读 评论(1) 收藏 举报 分类&#xff1a; C Win32&#xff08;93&#xff09; 版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得…

511遇见易语言API模块线程挂起(SuspendThread)

线程挂起用到的API是SuspendThread 511遇见易语言模块API教程 API 暂停指定的线程 函数功能&#xff1a; 挂起线程。 参数&#xff1a; 第1个参数&#xff1a; HANDLE hThread 线程句柄。 返回值&#xff1a; 成功&#xff1a;线程的前一个挂起数。 失败&#xff1a;-1。 …

面向对象设计6大原则

概览 单一职责 1、单一职责 Single Responsibility Principle&#xff0c;简称是SRP。SRP的英文定义是&#xff1a; There should never be more than one reason for a class to change. 翻译过来的意思是&#xff1a; 应该有且仅有一个原因引起类的变更。 或许我们可以…

带你了解面向对象的设计原则

##一 摘要 今天晚上给大家介绍一下面向对象的设计原则,为什么要介绍这个呢,原因很简单,大家平时所接触的语言,无论是object-C,C,JavaScrpt,C#等都是属于面向对象语言,既然是面向对象设计语言,那么就有必要去了解一下面向对象的设计原则.那么面向对象的设计原则有哪些呢?今天来…

面向对象七大设计原则

面向对象设计的七大原则 前言 在软件开发中&#xff0c;为了提高软件系统的可维护性和可复用性&#xff0c;增加软件的可扩展性和灵活性&#xff0c;我们能要尽量根据 7 条原则来开发程序&#xff0c;从而提高软件开发效率、节约软件开发成本和维护成本。 面向对象设计原则概…

软件设计与体系——面向对象设计的原则

一&#xff1a;前言 用一道题熟悉OO设计与编程&#xff1a;给定一个4位数&#xff08;数字不完全相同&#xff09;&#xff0c;这4个数字可以得到最大4位数和最小4位数&#xff0c;算它们的差&#xff0c;不是6174则重复上述过程&#xff0c;最终会得到6174&#xff0c;验证这…

面向对象设计七大原则

面向对象设计七大原则 1) 开-闭原则 &#xff08;Open Closed Principle&#xff0c;OCP&#xff09;定义开闭原则的作用实现方法例子其它例子代码 2) 里氏代换原则&#xff08;Liskov Substitutiion Principle&#xff0c;LSP&#xff09;定义作用实现方法例子 3) 依赖倒置原则…

面向对象设计六大原则

6大原则如下&#xff1a; 1)单一职责原则,一个合理的类&#xff0c;应该仅有一个引起它变化的原因&#xff0c;即单一职责,就是设计的这个类功能应该只有一个; 优点&#xff1a;消除耦合&#xff0c;减小因需求变化引起代码僵化。 2) 开-闭原则&#xff0c;讲的是设计要对扩展…

设计模式(三)——面向对象设计原则

设计模式需要遵循基本的软件设计原则。可维护性(Maintainability)和可复用性(Reusability)是衡量软件质量的重要的两个属性: 可维护性:软件能够被理解、改正、适应及扩展的难易程度可复用性:软件能够被复用的难易程度面向对象设计的原则是支持可维护性复用,一方面需要实…

程序员必备的七大面向对象设计原则(一)

花絮 每天都在和面向对象打交道&#xff0c;但是我们在应用面向对象的时候感觉自己的面向对象技术应用的很合理&#xff1f;理解的很到位&#xff1f;应用的很到位&#xff1f;用的时候恰到好处&#xff1f;用的是否符合软件的发展趋势&#xff1f; 上面很多一连串的问题&#…

面向对象设计原则之开闭原则

开闭原则是面向对象的可复用设计的第一块基石&#xff0c;它是最重要的面向对象设计原则。开闭原则由Bertrand Meyer于1988年提出&#xff0c;其定义如下&#xff1a; 开闭原则(Open-Closed Principle, OCP)&#xff1a;一个软件实体应当对扩展开放&#xff0c;对修改关闭。即…

面向对象设计模式5大基本原则

“宇宙万物之中,没有一样东西能像思想那么顽固。” 一爱默生 首先明确模式是针对面向对象的&#xff0c;它的三大特性&#xff0c;封装、继承、多态。 面向对象设计模式有5大基本原则&#xff1a;单一职责原则、开发封闭原则、依赖倒置原则、接口隔离原则、Liskov替换原…

面向对象六大设计原则

目录 1 、单一职责&#xff08;Single Responsibility Principle&#xff09; 2 、开闭原则&#xff08;Open Close Principle&#xff09; 3、里氏替换原则&#xff08;Liskov Substitution Principle&#xff09; 4、接口隔离原则&#xff08;Interface Segregation Prin…

阿里巴巴编码规范解读(六、七)-工程结构及设计规约

工程结构 应用分层 1.【推荐】 图中默认上层依赖于下层&#xff0c;箭头关系表示可直接依赖&#xff0c;如&#xff1a;开放接口层可以依赖于 Web层&#xff0c;也可以直接依赖于 Service层&#xff0c;依此类推。 开放接口层&#xff1a;可直接封装 Service 方法暴露成RPC…

面向对象设计的七大设计原则详解

面向对象的七大设计原则 文章目录 面向对象的七大设计原则简述七大原则之间的关系 一、开闭原则&#xff08;The Open-Closed Principle &#xff0c;OCP&#xff09;概念理解系统设计需要遵循开闭原则的原因开闭原则的实现方法一个符合开闭原则的设计开闭原则的相对性 二、 里…

Android Binder机制简述

一、Android binder是什么&#xff1f; Android平台上的一种跨进程通信&#xff08;IPC&#xff09;机制 从OpenBinder演化而来 从Android应用层角度来说&#xff0c;Binder是客户端和服务端进行通信的媒介 二、IPC原理 每个Android进程&#xff0c;只能运行在自己的进程所…