Android 系统中AHardwareBuffer、ANativeWindowBuffer和GraphicBuffer的关系

Android Camera软件系统中,每路Stream的Buffer都是DMA-BUF,这种Buffer通常对外暴露的结构是ANativeWindowBuffer或GraphicBuffer(跨进程传递时用的native_handle_t),本文介绍Android系统中AHardwareBuffer、ANativeWindowBuffer和GraphicBuffer的关系。ANativeWindowBuffer、AHardwareBuffer都是GraphicBuffer通过类型转换而来,ANativeWindowBuffer对native_handle_t进行了封装。

ANativeWindowBuffer

ANativeWindowBuffer定义在nativebase.h头文件中。

复制代码
frameworks/native/libs/nativebase/include/nativebase/nativebase.h

定义如下:

复制代码
typedef struct ANativeWindowBuffer
{
#ifdef __cplusplus
    ANativeWindowBuffer() {
        common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
        common.version = sizeof(ANativeWindowBuffer);
        memset(common.reserved, 0, sizeof(common.reserved));
    }

    // Implement the methods that sp<ANativeWindowBuffer> expects so that it
    // can be used to automatically refcount ANativeWindowBuffer's.
    void incStrong(const void* /*id*/) const {
        common.incRef(const_cast<android_native_base_t*>(&common));
    }
    void decStrong(const void* /*id*/) const {
        common.decRef(const_cast<android_native_base_t*>(&common));
    }
#endif

    struct android_native_base_t common;

    int width;
    int height;
    int stride;
    int format;
    int usage_deprecated;
    uintptr_t layerCount;

    void* reserved[1];

    const native_handle_t* handle;
    uint64_t usage;

    // we needed extra space for storing the 64-bits usage flags
    // the number of slots to use from reserved_proc depends on the
    // architecture.
    void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];
} ANativeWindowBuffer_t;

typedef struct ANativeWindowBuffer ANativeWindowBuffer;

可以看到它是一个结构体,重要的成员有:

  • handle
  • width
  • height
  • stride
  • format
  • usage

ANativeWindowBuffer描述的是一块DMA Buffer,handle中包含了Buffer的FD,其他成员是该Buffer的一些描述/补充。

GraphicBuffer

GraphicBuffer的头文件分为

-- frameworks/native/libs/ui/include_vndk/ui/GraphicBuffer.h

-- frameworks/native/libs/ui/include/ui/GraphicBuffer.h

GraphicBuffer继承自ANativeWindowBuffer。

我们可以在Vendor/System分区使用GraphicBuffer,用到的库是libui.so(支持VNDK)。

AHardwareBuffer

AHardwareBuffer定义在

复制代码
frameworks/native/libs/nativewindow/include/android/hardware_buffer.h

定义如下:

复制代码
/**
 * Opaque handle for a native hardware buffer.
 */
typedef struct AHardwareBuffer AHardwareBuffer;

所以,AHardwareBuffer是一个抽象的概念,没有具体类型(类似void类型),主要用于在同一进程的不同模块间传递ANativeWindowBuffer。

GraphicBuffer 与 ANativeWindowBuffer相互转换

GraphicBuffer提供了接口来做转换,使用的static_cast

GraphicBuffer转成ANativeWindowBuffer:

复制代码
ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const
{
    return static_cast<ANativeWindowBuffer*>(
            const_cast<GraphicBuffer*>(this));
}

ANativeWindowBuffer转换成GraphicBuffer:

复制代码
sp<GraphicBuffer> GraphicBuffer::from(ANativeWindowBuffer* anwb) {
    return static_cast<GraphicBuffer *>(anwb);
}

AHardwareBuffer 与 GraphicBuffer 相互转换

GraphicBuffer提供了接口来做转换,使用的reinterpret_cast

AHardwareBuffer 转换成GraphicBuffer:

复制代码
GraphicBuffer* GraphicBuffer::fromAHardwareBuffer(AHardwareBuffer* buffer) {
    return reinterpret_cast<GraphicBuffer*>(buffer);
}

GraphicBuffer转换成AHardwareBuffer:

复制代码
AHardwareBuffer const* GraphicBuffer::toAHardwareBuffer() const {
    return reinterpret_cast<AHardwareBuffer const*>(this);
}

AHardwareBuffer 与 ANativeWindowBuffer相互转换

他们两不能直接转换,必须借助GraphicBuffer来作为中间桥梁。

AHardwareBuffer转换成ANativeWindowBuffer:

frameworks/native/libs/nativewindow/AHardwareBuffer.cpp定义了AHardwareBuffer_to_ANativeWindowBuffer方法完成该转换(注:无法在Vendor分区使用)

复制代码
ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(AHardwareBuffer* buffer) {
    return AHardwareBuffer_to_GraphicBuffer(buffer)->getNativeBuffer();
}

先将AHardwareBuffer转换成GraphicBuffer,然后再调用GraphicBuffer的getNativeBuffer。

ANativeWindowBuffer转换成AHardwareBuffer:

先将ANativeWindowBuffer转换成GraphicBuffer,再调用toAHardwareBuffer获取到HardwareBuffer。

复制代码
sp<GraphicBuffer> GraphicBuffer::from(ANativeWindowBuffer* anwb) {
    return static_cast<GraphicBuffer *>(anwb);
}

AHardwareBuffer* GraphicBuffer::toAHardwareBuffer() {
    return reinterpret_cast<AHardwareBuffer*>(this);
}

如何创建ANativeWindowBuffer

为了让ANativeWindowBuffer有智能指针的作用,需要定义一个类继承自ANativeWindowBuffer和android::RefBase(如果不想要智能指针的作用则不用做这一步)。

举例:

复制代码
class NativeBuffer : public ANativeWindowBuffer, public android::RefBase
{
public:
    void incStrong(const void* id) const { RefBase::incStrong(id); }
    void decStrong(const void* id) const { RefBase::decStrong(id); }

    NativeBuffer(INT32 widthIn, INT32 heightIn, INT32 strideIn, INT32 formatIn,
        INT32 usageIn, native_handle_t *handleIn) :
        ANativeWindowBuffer(), RefBase()
    {
        width           = widthIn;
        height          = heightIn;
        stride          = strideIn;
        format          = formatIn;
        usage           = usageIn;
        handle          = handleIn;
        common.incRef   = incRef;
        common.decRef   = decRef;
    }

private:
    static void incRef(android_native_base_t* base)
    {
        NativeBuffer *self = static_cast<NativeBuffer*>(
            reinterpret_cast<ANativeWindowBuffer*>(base));
        self->incStrong(self);
    }

    static void decRef(android_native_base_t* base)
    {
        NativeBuffer *self = static_cast<NativeBuffer*>(
            reinterpret_cast<ANativeWindowBuffer*>(base));
        self->decStrong(self);
    }
};

这里面主要实现incRef和decRef,会尝试static_cast检查能否正常进行转换,然后调用RefBase相应的接口。

使用时,直接new NativeBuffer

复制代码
new NativeBuffer(width, height, stride, m_formatInput, m_usage, static_cast<native_handle_t*>(pImage->pNativeHandle));

reinterpret_cast与static_cast的作用和区别

reinterpret_cast用于执行低级别的类型转换,可以将一个指针或引用转换为另一种不同类型的指针或引用。它允许将任何指针类型转换为任何其他指针类型,即使它们之间没有任何关系。这种转换是非常危险的,潜在地导致未定义行为,因此应该谨慎使用。reinterpret_cast通常用于底层编程,例如将指针转换为整数类型或将数据强制转换为特定的内存布局。

static_cast是一种较为安全的类型转换操作符,它主要用于相关类型之间的转换,例如整数之间的转换、父类指针/引用到子类指针/引用的转换等。static_cast会在编译时进行类型检查,并检查是否存在可行的转换路径。如果存在转换,则进行转换,否则会产生编译错误。相对于reinterpret_cast,static_cast提供了更多的类型安全性,并且在一定程度上减少了潜在的错误。

总结一下:

  • reinterpret_cast执行低级别的类型转换,允许将任何指针类型转换为任何其他指针类型,但是风险较高,容易导致未定义行为。
  • static_cast用于相关类型之间的转换,提供了较为安全的类型转换,并在编译时进行类型检查,如果存在可行的转换路径,则进行转换,否则产生编译错误。
相关推荐
草莓熊Lotso1 小时前
Linux 文件描述符与重定向实战:从原理到 minishell 实现
android·linux·运维·服务器·数据库·c++·人工智能
恋猫de小郭1 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
工程师老罗8 小时前
如何在Android工程中配置NDK版本
android
Libraeking11 小时前
破壁行动:在旧项目中丝滑嵌入 Compose(混合开发实战)
android·经验分享·android jetpack
市场部需要一个软件开发岗位11 小时前
JAVA开发常见安全问题:Cookie 中明文存储用户名、密码
android·java·安全
JMchen12313 小时前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
crmscs14 小时前
剪映永久解锁版/电脑版永久会员VIP/安卓SVIP手机永久版下载
android·智能手机·电脑
localbob14 小时前
杀戮尖塔 v6 MOD整合版(Slay the Spire)安卓+PC端免安装中文版分享 卡牌肉鸽神作!杀戮尖塔中文版,电脑和手机都能玩!杀戮尖塔.exe 杀戮尖塔.apk
android·杀戮尖塔apk·杀戮尖塔exe·游戏分享
机建狂魔14 小时前
手机秒变电影机:Blackmagic Camera + LUT滤镜包的专业级视频解决方案
android·拍照·摄影·lut滤镜·拍摄·摄像·录像
hudawei99614 小时前
flutter和Android动画的对比
android·flutter·动画