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视频解码到现实的基本流程
小结:
- ANativeWindow是android的本地窗口,Surface是ANativeWindow的子类,也是ANativeWindow的具体实现。
- IGraphicBufferProducer的具体实现实质就是BufferQueue,创建Surface的时候作为传参。
- 解码和显示共享内存的方式可以节省内存,减小解码到显示消耗时间。
















