Androi4.0 SurfaceTexture的Buffer入队流程

本文详细解析了SurfaceTexture的Buffer入队流程,包括从AwesomePlayer的Render中将解码后的Buffer通过ANativeWindow接口通知SurfaceTextureClient,再到SurfaceFlinger进程中的SurfaceTexture接收Binder消息并处理的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SurfaceTexture的Buffer入队流程

Figure 1queueBuffer流程

1. 在AWesomePlayer的Render中将解码后的Buf通过ANativeWindow接口通知SurfaceTextureClient

struct AwesomeNativeWindowRenderer : public AwesomeRenderer {

virtual void render(MediaBuffer *buffer) {

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());

 

}

}

进入到SurfaceTextureClient的queueBuffer(),这里的工作主要有:

1) 更新timestamp,如果没有,则用系统时间

2) 根据Buffer地址从slots中取出Buffer的序号

3) 将序号以及时间戳、以及其它信息通过Binder通信发送给SurfaceTexture。

int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {

LOGV("SurfaceTextureClient::queueBuffer");

Mutex::Autolock lock(mMutex);

int64_t timestamp;

if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {

timestamp = systemTime(SYSTEM_TIME_MONOTONIC);

LOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms",

timestamp / 1000000.f);

} else {

timestamp = mTimestamp;

}

int i = getSlotFromBufferLocked(buffer);

status_t err = mSurfaceTexture->queueBuffer(i, timestamp,

&mDefaultWidth, &mDefaultHeight, &mTransformHint);

return err;

}

2. 在SurfaceFlinger进程中,本地端的SurfaceTexture接收到Binder消息,并进入queueBuffer函数。主要做以下工作:

1) 根据传入的int buf从slots中找出相应的Buffer,并更新此buffer的相关信息。

2)发信号mDequeueCondition.signal(),用作通知等待者

3) 通知监听者,onFrameAvailable有帧到达

status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,

uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {

ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);

 

sp<FrameAvailableListener> listener;

 

{ // scope for the lock

Mutex::Autolock lock(mMutex);

//一些参数检查

 

if (mSynchronousMode) {

// In synchronous mode we queue all buffers in a FIFO.

mQueue.push_back(buf);

 

// Synchronous mode always signals that an additional frame should

// be consumed.

listener = mFrameAvailableListener;

} else {

// In asynchronous mode we only keep the most recent buffer.

if (mQueue.empty()) {

mQueue.push_back(buf);

 

// Asynchronous mode only signals that a frame should be

// consumed if no previous frame was pending. If a frame were

// pending then the consumer would have already been notified.

listener = mFrameAvailableListener;

} else {

Fifo::iterator front(mQueue.begin());

// buffer currently queued is freed

mSlots[*front].mBufferState = BufferSlot::FREE;

// and we record the new buffer index in the queued list

*front = buf;

}

}

 

mSlots[buf].mBufferState = BufferSlot::QUEUED;

mSlots[buf].mCrop = mNextCrop;

mSlots[buf].mTransform = mNextTransform;

mSlots[buf].mScalingMode = mNextScalingMode;

mSlots[buf].mTimestamp = timestamp;

mFrameCounter++;

mSlots[buf].mFrameNumber = mFrameCounter;

 

mDequeueCondition.signal();

 

*outWidth = mDefaultWidth;

*outHeight = mDefaultHeight;

*outTransform = 0;

} // scope for the lock

 

// call back without lock held

if (listener != 0) {

listener->onFrameAvailable();

}

return OK;

}

在Layer中,第一次引用时会创建SurfaceTexture,并实现FrameAvailableListener

void Layer::onFirstRef()

{

LayerBaseClient::onFirstRef();

 

struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {

FrameQueuedListener(Layer* layer) : mLayer(layer) { }

private:

wp<Layer> mLayer;

virtual void onFrameAvailable() {

sp<Layer> that(mLayer.promote());

if (that != 0) {

that->onFrameQueued();

}

}

};

mSurfaceTexture = new SurfaceTextureLayer(mTextureName, this);

mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));

mSurfaceTexture->setSynchronousMode(true);

mSurfaceTexture->setBufferCountServer(2);

}

控制流进入Layer:onFrameQueued()函数,最后调用SurfaceFlinger的事件函数,通知其新事件。

void Layer::onFrameQueued() {

android_atomic_inc(&mQueuedFrames);

mFlinger->signalEvent();

}

3. 在SurfaceFlinger中获得事件,进入主循环处理事件

bool SurfaceFlinger::threadLoop()

{

waitForEvent();

// post surfaces (if needed)

handlePageFlip();//设置刚入队的Buffer为当前激活的Buffer

handleRepaint();//将当前激活的Buffer地址送给硬件叠加层,进行叠加

 

在lockPageFlip函数中遍历每一层设置当前激活的Buffer

bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)

{

bool recomputeVisibleRegions = false;

size_t count = currentLayers.size();

sp<LayerBase> const* layers = currentLayers.array();

for (size_t i=0 ; i<count ; i++) {

const sp<LayerBase>& layer(layers[i]);

layer->lockPageFlip(recomputeVisibleRegions);

}

return recomputeVisibleRegions;

}

对每个Layer将当前Buffer设置为激活Buffer

void Layer::lockPageFlip(bool& recomputeVisibleRegions)

{

// update the active buffer

mActiveBuffer = mSurfaceTexture->getCurrentBuffer();

 

在handleRepaint()中调用setupHardwareComposer建立叠加层

setupHardwareComposer(mDirtyRegion);

void SurfaceFlinger::setupHardwareComposer(Region& dirtyInOut)

{

/*

* update the per-frame h/w composer data for each layer

* and build the transparent region of the FB

*/

for (size_t i=0 ; i<count ; i++) {

const sp<LayerBase>& layer(layers[i]);

layer->setPerFrameData(&cur[i]);

}

}

 

将当前激活的buffer设置到 handware composer中进行叠加

void Layer::setPerFrameData(hwc_layer_t* hwcl) {

const sp<GraphicBuffer>& buffer(mActiveBuffer);

if (buffer == NULL) {

// this can happen if the client never drew into this layer yet,

// or if we ran out of memory. In that case, don't let

// HWC handle it.

hwcl->flags |= HWC_SKIP_LAYER;

hwcl->handle = NULL;

} else {

hwcl->handle = buffer->handle;

}

}

来自: http://www.cnblogs.com/zhgyee/archive/2011/12/27/2302709.html
<think>好的,用户的问题是关于如何在Android中将SurfaceTexture与显存进行绑定的教程。首先,我需要回忆一下Android中图形处理的相关知识。SurfaceTexture通常用于将图像流直接传递给OpenGL ES纹理,这样可以高效处理视频或相机预览等数据。用户提到“显存”,这可能指的是直接操作图形内存,比如使用Vulkan或者OpenGL的扩展。不过,标准的AndroidAPI中,SurfaceTexture通常与OpenGL ES结合使用,而显存的管理由系统处理。需要检查是否有特定的API或方法允许显存的显式绑定。接下来,查阅相关文档。SurfaceTexture类有一个attachToGLContext方法,可以将纹理附着到OpenGL上下文,这可能涉及到显存。另外,在较新的Android版本中,可能支持AHardwareBuffer,它允许直接分配和使用显存。例如,通过AHardwareBuffer_allocate函数分配内存,然后与SurfaceTexture关联。另外,用户可能需要使用EGLImage来将显存与纹理关联。EGLImage可以包装一个硬件缓冲区,然后通过OpenGLES的glEGLImageTargetTexture2DOES将其绑定到纹理上。SurfaceTexture可以通过Surface构造函数关联到一个SurfaceTexture实例,然后通过EGL创建Image,进而绑定显存。还需要考虑不同Android版本的支持情况,比如AHardwareBuffer从API26开始引入。因此,在教程中需要说明版本兼容性,并提供替代方案。最后,整合这些步骤:创建SurfaceTexture,分配显存(如使用AHardwareBuffer),将显存与SurfaceTexture关联,并通过OpenGLES进行渲染。同时,代码示例可能涉及JNI层,因为部分API在Java层可能不可用,需要Native代码实现。 确保回答中提到的步骤准确,并引用相关的Android文档或开发者资源。可能还需要提到性能优化和常见问题,比如内存对齐和同步处理。</think>在Android实现SurfaceTexture与显存(图形内存)的绑定,需要结合图形API(如OpenGL ES或Vulkan)及Android底层框架的接口。以下是关键步骤和示例: --- ### **1. 核心原理** - **SurfaceTexture**:用于将图像流(如相机或视频数据)直接传递到OpenGL ES纹理。 - **显存绑定**:通过`AHardwareBuffer`(API 26+)或`EGLImage`直接操作图形内存,提升性能[^1][^5]。 --- ### **2. 实现步骤(以OpenGL ES为例)** #### **步骤1:创建SurfaceTexture** ```java // 创建OpenGL ES纹理 int[] textureId = new int[1]; glGenTextures(1, textureId, 0); SurfaceTexture surfaceTexture = new SurfaceTexture(textureId[0]); ``` #### **步骤2:分配显存(AHardwareBuffer)** ```java // 分配硬件缓冲(显存) AHardwareBuffer.HardwareBufferDesc desc = new AHardwareBuffer.HardwareBufferDesc( width, height, 1, AHardwareBuffer.RGBA_8888, AHardwareBuffer.USAGE_GPU_SAMPLED_IMAGE ); AHardwareBuffer hardwareBuffer = AHardwareBuffer.allocate(desc); ``` #### **步骤3:将显存绑定到SurfaceTexture** ```java // 通过EGLImage关联显存与纹理 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGLImageKHR eglImage = eglCreateImageKHR( display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, hardwareBuffer.getNativeHandle(), null ); // 将EGLImage绑定到纹理 glBindTexture(GL_TEXTURE_2D, textureId[0]); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage); ``` #### **步骤4:渲染到Surface** ```java Surface surface = new Surface(surfaceTexture); // 通过Canvas或OpenGL ES渲染到Surface try (Canvas canvas = surface.lockCanvas(null)) { canvas.drawColor(Color.RED); // 示例绘制操作 } surface.unlockCanvasAndPost(canvas); ``` --- ### **3. Vulkan显存绑定(可选)** 若使用Vulkan,需通过`VkDeviceMemory`显式管理显存: ```cpp // 创建Vulkan缓冲并绑定显存 VkBufferCreateInfo bufferInfo = { ... }; vkCreateBuffer(device, &bufferInfo, nullptr, &buffer); VkMemoryRequirements memRequirements; vkGetBufferMemoryRequirements(device, buffer, &memRequirements); VkMemoryAllocateInfo allocInfo = { ... }; allocInfo.memoryTypeIndex = // 选择显存类型 vkAllocateMemory(device, &allocInfo, nullptr, &vertexBufferMemory); vkBindBufferMemory(device, buffer, vertexBufferMemory, 0); // 偏移需对齐[^5] ``` --- ### **4. 注意事项** 1. **版本兼容性**:`AHardwareBuffer`需Android 8.0+,低版本可使用`EGLImage`扩展。 2. **同步机制**:更新显存时需调用`surfaceTexture.updateTexImage()`避免数据竞争。 3. **性能优化**:优先复用显存对象,减少分配开销[^1][^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值