Android14 Camera框架中Jpeg流buffer大小的计算

news/2025/2/23 17:37:42

背景描述

Android13中,相机框架包含对AIDL Camera HAL的支持,在Android13或更高版本中添加的相机功能只能通过AIDL Camera HAL接口使用。

对于Android应用层来说,使用API34即以后版本的Camera应用程序通过Camera AIDL Interface访问到HAL层。在将HAL层从HIDL相机接口迁移到AIDL相机接口时,发现AIDL HAL Jpeg buffer带下是框架确定的。

接下来,先来看下HIDL HAL和AIDL HAL两者这块Gralloc Buffer(框架下来那块output buffer)是如何来获取的,

Demo HIDL HAL 输出buffer

以Google Demo为例子,HIDL HAL中output buffer是这样映射到camera hal的:

int V4L2Wrapper::DequeueRequest(std::shared_ptr<CaptureRequest>* request)
{
    ...
    
    v4l2_buffer buffer;
    memset(&buffer, 0, sizeof(buffer));
    buffer.type = format_->type();
    buffer.memory = V4L2_MEMORY_USERPTR;
    int res = IoctlLocked(VIDIOC_DQBUF, &buffer);
    if (res) {
    }
    ...

    arc::GrallocFrameBuffer output_frame(*stream_buffer->buffer,
            stream_buffer->stream->width, stream_buffer->stream->height,
            fourcc, buffer.length, stream_buffer->stream->usage);
    res = output_frame.Map();
    ...
}

//GrallocFrameBuffer类进行地址映射
GrallocFrameBuffer::GrallocFrameBuffer(buffer_handle_t buffer, uint32_t width,
        uint32_t height, uint32_t fourcc, uint32_t device_buffer_length,
        uint32_t stream_usage)
    : buffer_(buffer),
      is_mapped_(false),
      device_buffer_length_(device_buffer_length),  /*这里接收到外部传过来的buffer大小*/
      stream_usage_(stream_usage), {
    ...
}

int GrallocFrameBuffer::Map() {
    ...
    switch (fourcc_) {
        ...
        case V4L2_PIX_FMT_JPEG:
            //这里调用gralloc mapper,映射地址
            ret = gralloc_module_->lock(gralloc_module_, buffer_, stream_usage_,
                        0, 0, device_buffer_length_, 1, &addr);
        break;
        ...
    }
    ...
}

Demo AIDL HAL输出buffer

aidl hal buffer的大小在configure stream阶段确认,框架下发流配置中携带着对应buffer大小。request阶段完成“lock”操作。

status_t EmulatedRequestProcessor::LockSensorBuffer(const EmulatedStream& stream,
                buffer_handle_t buffer, int32_t width, uint32_t height,
                SensorBuffer* sensor_buffer /*out*/) {
    ...
    if ((isYUV_420_888) || (isP010)) {
        ...
    } else {
        uint32_t buffer_size = 0, stride = 0;
        auto ret = GetBufferSizeAndStride(stream, buffer, &buffer_size, &stride);
        if (ret != OK) {
            ALOGE("%s: Unsupported pixel format: 0x%x", __FUNCTION__,
                stream.override_format);
            return BAD_VALUE;
        }

        if (stream.override_format == HAL_PIXEL_FORMAT_BLOB) {
            //这里调用lock(),进行地址映射
            sensor_buffer->plane.img.img =
                static_cast<uint8_t*>(importer_->lock(buffer, usage, buffer_size));
        } else {
            ...
        }
    }
    ...
}

status_t EmulatedRequestProcessor::GetBufferSizeAndStride(const EmulatedStream& stream,
    buffer_handle_t buffer, uint32_t* size/*out*/, uint32_t* stride/*out*/) {
    
    if (size == nullptr) {
        return BAD_VALUE;
    }

    switch (stream.override_format) {
        ...
        case HAL_PIXEL_FORMAT_BLOB:
            if (stream.override_data_space == HAL_DATASPACE_V0_JFIF) {
                *size = stream.buffer_size;   //这里的stream是configure stream阶段设置的
                *stride = *size;
            } else {
                return BAD_VALUE;
            }
        break;
        ...
    }

    return OK;
}

Camera AIDL中JPEG bufferSize

request jpeg buffer大小是框架下发request到HAL层之前确定好的,有明确的计算规则:

jpegBufferSize = scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) + kMinJpegBufferSize

参数说明:

  • scaleFactor 是缩放因子
  • maxJpegBufferSize 是相机本身支持的最大Jpeg数据大小
  • kMinJpegBufferSize 是框架定义的最小Jpeg数据大小

kMinJpegBufferSize = 256 * 1024 + blobHeader 这个是框架定的最小jpeg数据大小

blobHeader是框架定义的Jpeg Blob头部, 框架接口中定义的数据结构,有明确的大小。

//框架中最小jpeg blob

//blob header定义

scaleFactor缩放因子

scaleFactor =(jpegImage.width * jpegImage.height) / (chosenMaxJpegResolution.width * chosenMaxJpegResolution.height)

参数说明:

  • jpegImage  是request请求中的拍照流图像
  • chosenMaxJpegResolution  是相机(HAL层)能输出的最大Jpeg图像分辨率。根据是否支持max sensor pixel mode有两种情况。

chosenMaxJpegResolution相机输出的最大Jpeg图像分辨率

相机(HAL层)最大能输出多大分辨率的Jpeg图像,是由硬件决定的。

1. 如果相机支持max sensor pixel mode输出,并且请求的jpeg分辨率超出defaultMaxJpegResolution,那么chosenMaxJpegResolution是相机特征中最大分辨率(tag: "availableStreamConfigurationsMaximumResolution")中最大jpeg分辩率。

2. 如果相机支持default sensor pixel mode,那么chosenMaxJpegResolution是相机特征中默认模式(tag: "availableStreamConfigurations")最大jpeg分辨率。

maxJpegBufferSize相机输出的最大Jpeg数据大小

相机输出的Jpeg图像多大,不仅和Sensor传感器有关,和编码模块也有关系。对于相同的一张图像输入不同的编码模块编码输出能力不同。

相机(HAL层)最大能输出多大的Jpeg图像,和输入图像的最大分辨率有关,

1. 如果相机是max sensor pixel mode输出,那么maxJpegBufferSize即为uhrMaxJpegBufferSize,

uhrMaxJpegBufferSize = (uhrMaxJpegResolution.width * uhrMaxJpegResolution.height) / (defaultMaxJpegResolution.width * defaultMaxJpegResolution.height) * defaultMaxJpegBufferSize;

参数说明:

  • uhrMaxJpegResolution  是相机max sensor pixel mode下能输出的Jpeg最大分辩率,见上节有提到。
  • defaultMaxJpegResolution  是相机default sensor pixel mode下输出的Jpeg最大分辨率,见上节。
  • defaultMaxJpegBufferSize  是相机default sensor pixel mode下个输出的Jpeg最大大小,  间接体现了编码压缩能力。

2. 如果相机是default sensor pixel mode输出,那么maxJpegBufferSize即defaultMaxJpegBufferSize,

defaultMaxJpegBufferSize是相机特征直接上报的,tag "android.jpeg.maxSize"

Camera框架中JPEG bufferSize逻辑

CameraBlob定义

//hardware/interfaces/camera/device/aidl/android/hardware/camera/device/CameraBlob.aidl
package android.hardware.camera.device;

import android.hardware.camera.device.CameraBlobId;

@VintfStability
parcelable CameraBlob {
    CameraBlobId blobId;
    
    int blobSizeBytes;
}

最小Jpeg bufferSize

statis const ssize_t kMinJpegBufferSize =
        256 * 1024 + sizeof(aidl::android::hardware::camera::device::CameraBlob);

计算Jpeg bufferSize

ssize_t Camera3Device::getJpegBufferSize(const CameraMetadata &info, uint32_t width, uint32_t height) const {

    //获取defaultMaxJpegResolution
    //Get max jpeg size (area-wise) for default sensor pixel mode
    camera3::Size maxDefaultJpegResolution = 
        SessionConfigurationUtils::getMaxJpegResolution(info,
            /*supportsUltraHighResolutionCapture*/false);

    //获取uhrMaxJpegResolution
    //Get max jpeg size (area-wise) for max resolution sensor pixel mode.
    camera3::Size uhrMaxJpegResolution = 
        SessionConfigurationUtils::getMaxJpegResolution(info,
            /*isUltraHighResolution*/true);

    if (maxDefaultJpegResolution.width == 0) {
        ALOGE("%s: Camera %s: Can't find valid available jpeg sizes in static metadata!",
                __FUNCTION__, mId.c_str());
        return BAD_VALUE;
    }

    //确定sensor以何种模式输出
    bool useMaxSensorPixelModeThreshold = false;
    if (uhrMaxJpegResolution.width != 0 &&
       width * height > maxDefaultJpegResolution.width * maxDefaultJpegResolution.height) {
        //Use the ultra high res max jpeg size and max jpeg buffer size.
        useMaxSensorPixelModeThreshold = true;
    }

    //获取defaultJpegBufferSize
    //Get max jpeg buffer size
    ssize_t maxJpegBufferSize = 0;
    camera_metadata_ro_entry jpegBufMaxSize = info.find(ANDROID_JPEG_MAX_SIZE);
    if (jpegBufMaxSize.count == 0) {
        ALOGE("%s: Camera %s: Can't find maximum JPEG size in static metadata!", 
            __FUNCTION__, mId.c_str());
        return BAD_VALUE;
    }
    maxJpegBufferSize = jpegBufMaxSize.data.i32[0];

    //确定最大Jpeg分辨率和最大Jpeg大小
    camera3::Size chosenMaxJpegResolution = maxDefaultJpegResolution;
    if (useMaxSensorPixelModeThreshold) {
        maxJpegBufferSize = SessionConfigurationUtils::getUHRMaxJpegBufferSize(
                uhrMaxJpegResolution, maxDefaultJpegResolution, maxJpegBufferSize);
        chosenMaxJpegResolution = uhrMaxJpegResolution;
    }
    assert(kMinJpegBufferSize < maxJpegBufferSize);

    //确定缩放因子
    //Calculate final jpeg buffer size for the given resolution
    float scaleFactor = ((float) (width * height)) /
            (chosenMaxJpegResolution.width * chosenMaxJpegResolution.height);
    //计算得到request jpeg bufferSize
    ssize_t jpegBufferSize = scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) +
            kMinJpegBufferSize);
    //校正request jpeg bufferSize,以确保jpeg bufferSize在最大值和最小值之间
    if (jpegBufferSize > maxJpegBufferSize) {
        ALOGI("%s: jpeg buffer size calculated is > maxJpeg bufferSize(%zd), clamping",
            __FUNCTION__, maxJpegBufferSize);
        jpegBufferSize = maxJpegBufferSize;
    }
    return jpegBufferSize;
}

Camera Demo AIDL HAL相关的相机特征参数

Demo AIDL HAL中相机特征参数是从.json中加载的,这里以后置相机为例,特征参数如下:

//hardware/google/camera/devices/EmulatedCamera/hwl/configs/emu_camera_back.json
"android.scaler.availableStreamConfigurations" : [
    ...
    "33",
    "1856",
    "1392",
    "OUTPUT",
    "33",
    "1280",
    "720",
    "OUTPUT",
    ...
],

"android.jpeg.maxSize" : [
    "300000"
],
...


http://www.niftyadmin.cn/n/5863623.html

相关文章

TCP/UDP调试工具推荐:Socket通信图解教程

TCP/UDP调试工具推荐&#xff1a;Socket通信图解教程 一、引言二、串口调试流程三、下载链接 SocketTool 调试助手是一款旨在协助程序员和网络管理员进行TCP和UDP协议调试的网络通信工具。TCP作为一种面向连接、可靠的协议&#xff0c;具有诸如连接管理、数据分片与重组、流量和…

@media 的常用场景与示例

media 的常用场景与示例 1. 基本概念2. 常用场景2.1 不同屏幕宽度的布局调整2.2 隐藏或显示元素2.3 字体大小调整2.4 图片大小调整2.5 高度调整2.6 颜色调整2.7 鼠标悬停效果 3. 常用示例3.1 基本响应式布局3.2 隐藏侧边栏3.3 字体大小和图片大小 4. 总结 在现代网页设计中&…

【架构】事件驱动架构(Event - Driven Architecture,EDA)

一、事件驱动架构理论基础 事件驱动架构(Event - Driven Architecture,EDA)是一种软件设计范式,事件驱动的体系结构由生成事件流、侦听这些事件的事件使用者以及将事件从生成者传输到使用者的事件通道组成。 在事件驱动架构中,系统的行为由事件触发。事件可几乎实时发送,…

苹果确认iOS 18.4四月初推出:Apple Intelligence将迎来中文支持

在科技飞速发展的当下&#xff0c;人工智能&#xff08;AI&#xff09;已经成为智能设备领域的核心竞争力之一。苹果公司作为全球科技行业的领军者&#xff0c;其在AI领域的每一步动作都备受关注。2025年2月20日&#xff0c;苹果公司正式宣布&#xff0c;将于4月初推出iOS 18.4…

Linux中ps -ef命令详解

ps -ef 是一个常用的 Unix/Linux 命令&#xff0c;用于显示当前系统中所有进程的详细信息。具体来说&#xff0c;ps 是 "process status" 的缩写&#xff0c;用于查看进程的状态。-ef 是 ps 命令的选项组合&#xff0c;用于指定输出的格式和内容。 选项解释&#xf…

Linux命令行导出Emacs ORG文档为HTML

个人博客地址&#xff1a;Linux命令行导出Emacs ORG文档为HTML | 一张假钞的真实世界 Emacs版本25.2。使用以下命令将org文档导出html&#xff1a; emacs {orgFile} --batch --eval "(require ox)" --eval "(org-html-export-to-html)" 批量导出目录下的…

PWR电源控制详解教程文章 ~内置初始化驱动代码!!!

文章目录 前言 stm32 cpu默认频率基础知识详解 降低频率会影响指令执行速度 stm32 cpu芯片超频 PWR 基础知识详解 stm32内部电源供电基础知识详解 电压调节器模式 低功耗模式基础知识详解 低功耗模式不同频率耗电详解图 前言 在使用锂电池作为系统电源供应的开发中&am…

mysql之InnoDB Buffer Pool 深度解析与性能优化

文章目录 InnoDB Buffer Pool 深度解析与性能优化1. 概述&#xff1a;平衡磁盘与 CPU 的关键枢纽1.1. Buffer Pool 的本质与作用1.2. 多级缓存体系 2. Buffer Pool 的内部机制2.1. 页 (Page) 的概念2.2. Buffer Pool 的组成结构2.3. Buffer Pool 的工作流程 (数据页的生命周期)…