ANativeWindow 和 Surface(解码和显示共享内存的解释)

`





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

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

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

ANativeWindow的定义如下:


 
 
  1. // 代码位置 frameworks/native/libs/nativewindow/include/system/window.h
  2. ...
  3. struct ANativeWindow
  4. {
  5. ...
  6. int (*dequeueBuffer_DEPRECATED)( struct ANativeWindow* window,
  7. struct ANativeWindowBuffer** buffer);
  8. ...
  9. int (*queueBuffer_DEPRECATED)( struct ANativeWindow* window,
  10. struct ANativeWindowBuffer* buffer);
  11. ...
  12. int (*query)( const struct ANativeWindow* window,
  13. int what, int* value);
  14. ...
  15. int (*perform)( struct ANativeWindow* window,
  16. int operation, ... );
  17. ...
  18. int (*cancelBuffer_DEPRECATED)( struct ANativeWindow* window,
  19. struct ANativeWindowBuffer* buffer);
  20. ...
  21. int (*dequeueBuffer)( struct ANativeWindow* window,
  22. struct ANativeWindowBuffer** buffer, int* fenceFd);
  23. ...
  24. int (*queueBuffer)( struct ANativeWindow* window,
  25. struct ANativeWindowBuffer* buffer, int fenceFd);
  26. ...
  27. int (*cancelBuffer)( struct ANativeWindow* window,
  28. struct ANativeWindowBuffer* buffer, int fenceFd);
  29. }
  30. ...
  31. static inline int native_window_set_buffer_count(
  32. struct ANativeWindow* window,
  33. size_t bufferCount)
  34. {
  35. return window-> perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
  36. }
  37. ...
  38. static inline int native_window_dequeue_buffer_and_wait(ANativeWindow *anw,
  39. struct ANativeWindowBuffer** anb) {
  40. return anw-> dequeueBuffer_DEPRECATED(anw, anb);
  41. }
  42. ...

Surface的定义如下:


 
 
  1. // frameworks/native/libs/gui/include/gui/Surface.h
  2. ...
  3. class Surface
  4. : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
  5. {
  6. public:
  7. ...

可见Surface是ANativeWindow的子类

再看如下代码:


 
 
  1. // frameworks/native/libs/gui/Surface.cpp
  2. ...
  3. Surface:: Surface( const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
  4. : mGraphicBufferProducer(bufferProducer),
  5. mCrop(Rect::EMPTY_RECT),
  6. mBufferAge( 0),
  7. mGenerationNumber( 0),
  8. mSharedBufferMode( false),
  9. mAutoRefresh( false),
  10. mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
  11. mSharedBufferHasBeenQueued( false),
  12. mQueriedSupportedTimestamps( false),
  13. mFrameTimestampsSupportsPresent( false),
  14. mEnableFrameTimestamps( false),
  15. mFrameEventHistory(std:: make_unique<ProducerFrameEventHistory>()) {
  16. // Initialize the ANativeWindow function pointers.
  17. ANativeWindow::setSwapInterval = hook_setSwapInterval;
  18. ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
  19. ANativeWindow::cancelBuffer = hook_cancelBuffer;
  20. ANativeWindow::queueBuffer = hook_queueBuffer;
  21. ANativeWindow::query = hook_query;
  22. ANativeWindow::perform = hook_perform;
  23. ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
  24. ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
  25. ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
  26. ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
  27. ...

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

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

Dequeue


 
 
  1. // frameworks/av/media/libstagefright/ACodec.cpp
  2. ...
  3. status_t ACodec::allocateOutputBuffersFromNativeWindow() {
  4. // This method only handles the non-metadata mode (or simulating legacy
  5. // mode with metadata, which is transparent to ACodec).
  6. CHECK(! storingMetadataInDecodedBuffers());
  7. OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers;
  8. status_t err = configureOutputBuffersFromNativeWindow(
  9. &bufferCount, &bufferSize, &minUndequeuedBuffers, true /* preregister */);
  10. if (err != 0)
  11. return err;
  12. mNumUndequeuedBuffers = minUndequeuedBuffers;
  13. static_cast<Surface*>(mNativeWindow. get())
  14. -> getIGraphicBufferProducer()-> allowAllocation( true);
  15. ALOGV( "[%s] Allocating %u buffers from a native window of size %u on "
  16. "output port",
  17. mComponentName. c_str(), bufferCount, bufferSize);
  18. // Dequeue buffers and send them to OMX
  19. for (OMX_U32 i = 0; i < bufferCount; i++) {
  20. ANativeWindowBuffer *buf;
  21. int fenceFd;
  22. err = mNativeWindow-> dequeueBuffer(mNativeWindow. get(), &buf, &fenceFd);
  23. if (err != 0) {
  24. ALOGE( "dequeueBuffer failed: %s (%d)", strerror(-err), -err);
  25. break;
  26. }
  27. sp<GraphicBuffer> graphicBuffer(GraphicBuffer::from(buf));
  28. BufferInfo info;
  29. info.mStatus = BufferInfo::OWNED_BY_US;
  30. info.mFenceFd = fenceFd;
  31. info.mIsReadFence = false;
  32. info.mRenderInfo = NULL;
  33. info.mGraphicBuffer = graphicBuffer;
  34. info.mNewGraphicBuffer = false;
  35. // TODO: We shouln't need to create MediaCodecBuffer. In metadata mode
  36. // OMX doesn't use the shared memory buffer, but some code still
  37. // access info.mData. Create an ABuffer as a placeholder.
  38. info.mData = new MediaCodecBuffer(mOutputFormat, new ABuffer(bufferSize));
  39. info.mCodecData = info.mData;
  40. ...

 
 
  1. // frameworks/native/libs/gui/Surface.cpp
  2. ...
  3. int Surface::hook_dequeueBuffer(ANativeWindow* window,
  4. ANativeWindowBuffer** buffer, int* fenceFd) {
  5. Surface* c = getSelf(window);
  6. return c-> dequeueBuffer(buffer, fenceFd);
  7. }
  8. ...
  9. int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
  10. ATRACE_CALL();
  11. ALOGV( "Surface::dequeueBuffer");
  12. uint32_t reqWidth;
  13. uint32_t reqHeight;
  14. PixelFormat reqFormat;
  15. uint64_t reqUsage;
  16. bool enableFrameTimestamps;
  17. {
  18. Mutex::Autolock lock(mMutex);
  19. if (mReportRemovedBuffers) {
  20. mRemovedBuffers. clear();
  21. }
  22. reqWidth = mReqWidth ? mReqWidth : mUserWidth;
  23. reqHeight = mReqHeight ? mReqHeight : mUserHeight;
  24. reqFormat = mReqFormat;
  25. reqUsage = mReqUsage;
  26. ...
  27. FrameEventHistoryDelta frameTimestamps;
  28. status_t result = mGraphicBufferProducer-> dequeueBuffer(&buf, &fence, reqWidth,
  29. reqHeight, reqFormat,
  30. reqUsage, &mBufferAge,
  31. enableFrameTimestamps ?
  32. &frameTimestamps:
  33. nullptr);
  34. ...

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

Queue


 
 
  1. // frameworks/av/media/libstagefright/ACodec.cpp
  2. ...
  3. void ACodec::BaseState:: onOutputBufferDrained( const sp<AMessage> &msg) {
  4. IOMX::buffer_id bufferID;
  5. CHECK(msg-> findInt32( "buffer-id", ( int32_t*)&bufferID));
  6. sp<RefBase> obj;
  7. CHECK(msg-> findObject( "buffer", &obj));
  8. sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj. get());
  9. int32_t discarded = 0;
  10. msg-> findInt32( "discarded", &discarded);
  11. ...
  12. info->mData = buffer;
  13. int32_t render;
  14. if (mCodec->mNativeWindow != NULL
  15. && msg-> findInt32( "render", &render) && render != 0
  16. && !discarded && buffer-> size() != 0) {
  17. ATRACE_NAME( "render");
  18. // The client wants this buffer to be rendered.
  19. android_native_rect_t crop;
  20. if (buffer->format()-> findRect( "crop", &crop.left, &crop.top, &crop.right, &crop.bottom)) {
  21. // NOTE: native window uses extended right-bottom coordinate
  22. ++crop.right;
  23. ++crop.bottom;
  24. if ( memcmp(&crop, &mCodec->mLastNativeWindowCrop, sizeof(crop)) != 0) {
  25. mCodec->mLastNativeWindowCrop = crop;
  26. status_t err = native_window_set_crop(mCodec->mNativeWindow. get(), &crop);
  27. ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err);
  28. }
  29. }
  30. ...
  31. info-> checkReadFence( "onOutputBufferDrained before queueBuffer");
  32. err = mCodec->mNativeWindow-> queueBuffer(
  33. mCodec->mNativeWindow. get(), info->mGraphicBuffer. get(), info->mFenceFd);
  34. ...

 
 
  1. // frameworks/native/libs/gui/Surface.cpp
  2. ...
  3. int Surface::hook_queueBuffer(ANativeWindow* window,
  4. ANativeWindowBuffer* buffer, int fenceFd) {
  5. Surface* c = getSelf(window);
  6. return c-> queueBuffer(buffer, fenceFd);
  7. }
  8. ...
  9. int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
  10. ATRACE_CALL();
  11. ALOGV( "Surface::queueBuffer");
  12. Mutex::Autolock lock(mMutex);
  13. int64_t timestamp;
  14. bool isAutoTimestamp = false;
  15. ...
  16. nsecs_t now = systemTime();
  17. status_t err = mGraphicBufferProducer-> queueBuffer(i, input, &output);
  18. mLastQueueDuration = systemTime() - now;
  19. ...

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

 

 

在这里插入代码片
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值