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用于相关类型之间的转换,提供了较为安全的类型转换,并在编译时进行类型检查,如果存在可行的转换路径,则进行转换,否则产生编译错误。
相关推荐
西瓜本瓜@2 小时前
在Android中如何使用Protobuf上传协议
android·java·开发语言·git·学习·android-studio
似霰5 小时前
安卓adb shell串口基础指令
android·adb
fatiaozhang95277 小时前
中兴云电脑W102D_晶晨S905X2_2+16G_mt7661无线_安卓9.0_线刷固件包
android·adb·电视盒子·魔百盒刷机·魔百盒固件
CYRUS_STUDIO8 小时前
Android APP 热修复原理
android·app·hotfix
鸿蒙布道师9 小时前
鸿蒙NEXT开发通知工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
鸿蒙布道师9 小时前
鸿蒙NEXT开发网络相关工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
大耳猫9 小时前
【解决】Android Gradle Sync 报错 Could not read workspace metadata
android·gradle·android studio
ta叫我小白9 小时前
实现 Android 图片信息获取和 EXIF 坐标解析
android·exif·经纬度
dpxiaolong10 小时前
RK3588平台用v4l工具调试USB摄像头实践(亮度,饱和度,对比度,色相等)
android·windows
tangweiguo0305198711 小时前
Android 混合开发实战:统一 View 与 Compose 的浅色/深色主题方案
android