如何在android framewrok dump camera data

实现dump 函数

实现1

cpp 复制代码
void dumpBufferToFile(buffer_handle_t* buffer, int width, int height, int frameNum) {
    void* data = NULL;
    GraphicBufferMapper::getInstance().lock(*buffer, GRALLOC_USAGE_SW_READ_OFTEN, Rect(width, height), &data);

    char filename[128];
    sprintf(filename, "/data/vendor/camera/frame_%04d.yuv", frameNum);
    FILE* fp = fopen(filename, "wb");
    if (fp && data) {
        fwrite(data, 1, width * height * 3 / 2, fp); // 如果是 NV12/YUV420
        fclose(fp);
    }

    GraphicBufferMapper::getInstance().unlock(*buffer);
}

实现2

cpp 复制代码
#include <stdio.h>
#include <fcntl.h>
#include <string>
#include <sys/mman.h>
#include <hardware/gralloc.h>
#include <ui/GraphicBufferMapper.h>
#include <cutils/native_handle.h>
#include <android/hardware_buffer.h>

using namespace android;

// Camera format types
#define CAMERA_FORMAT_RAW16   0x20
#define CAMERA_FORMAT_RAW10   0x25
#define CAMERA_FORMAT_RAW12   0x26
#define CAMERA_FORMAT_YUV_420_888 0x23
#define CAMERA_FORMAT_JPEG    0x100

// Helper: Get format name
const char* getFormatSuffix(int format) {
    switch (format) {
        case HAL_PIXEL_FORMAT_YCbCr_420_888:
            return ".yuv";
        case HAL_PIXEL_FORMAT_BLOB:
            return ".jpg";
        case HAL_PIXEL_FORMAT_RAW16:
            return ".raw16";
        case HAL_PIXEL_FORMAT_RAW10:
            return ".raw10";
        case HAL_PIXEL_FORMAT_RAW12:
            return ".raw12";
        default:
            return ".bin";
    }
}

void dumpBufferToFile(buffer_handle_t handle, int width, int height, int frameNum, int format) {
    void* data = nullptr;
    uint32_t size = 0;

    // Lock buffer for reading
    GraphicBufferMapper& mapper = GraphicBufferMapper::get();
    android_ycbcr ycbcr = {};
    int usage = GRALLOC_USAGE_SW_READ_OFTEN;

    if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
        if (mapper.lockYCbCr(handle, usage, {0, 0, width, height}, &ycbcr) == OK) {
            data = ycbcr.y;
            size = width * height * 3 / 2;
        }
    } else {
        if (mapper.lock(handle, usage, {0, 0, width, height}, &data) == OK) {
            switch (format) {
                case HAL_PIXEL_FORMAT_RAW16:
                    size = width * height * 2;
                    break;
                case HAL_PIXEL_FORMAT_RAW10:
                    size = width * height * 10 / 8;
                    break;
                case HAL_PIXEL_FORMAT_RAW12:
                    size = width * height * 12 / 8;
                    break;
                case HAL_PIXEL_FORMAT_BLOB:
                    // BLOB: Usually JPEG
                    // You may need to get actual size from metadata, here we assume max
                    size = width * height;
                    break;
                default:
                    size = width * height * 4; // assume RGBA fallback
            }
        }
    }

    if (data == nullptr || size == 0) {
        ALOGE("dumpBufferToFile: failed to lock buffer");
        return;
    }

    // Generate file path
    char path[256];
    snprintf(path, sizeof(path), "/data/vendor/camera/dump_%04d%s", frameNum, getFormatSuffix(format));

    // Dump to file
    FILE* fp = fopen(path, "wb");
    if (fp) {
        fwrite(data, 1, size, fp);
        fclose(fp);
        ALOGI("dumpBufferToFile: dumped frame %d to %s", frameNum, path);
    } else {
        ALOGE("dumpBufferToFile: failed to open file %s", path);
    }

    // Unlock buffer
    mapper.unlock(handle);
}

添加调用位置

推荐位置 1, Camera3OutputStream::queueBufferToConsumer()

复制代码
此函数负责将 HAL 返回的 buffer 通过 ANativeWindow 传给 Surface,因此非常适合 dump。
cpp 复制代码
status_t Camera3OutputStream::queueBufferToConsumer(sp<GraphicBuffer>& buffer, ...)
{
    dumpBufferToFile(buffer->getNativeBuffer()->handle, mWidth, mHeight, mFrameNumber);

    // 原逻辑继续
    res = mConsumer->queueBuffer(...);
}

推荐位置 2,Camera3Device::processCaptureResult()

复制代码
HAL 返回一个 camera3_capture_result_t 结构,这里可以拿到 metadata 和 buffer。
cppvoid 复制代码
    for (size_t i = 0; i < result->num_output_buffers; i++) {
        const camera3_stream_buffer_t &buffer = result->output_buffers[i];
        Camera3OutputStreamInterface* stream = static_cast<Camera3OutputStreamInterface*>(buffer.stream->priv);
        
        // 📌 拿到 buffer 后 dump
        dumpBufferToFile(buffer.buffer, stream->getWidth(), stream->getHeight(), result->frame_number);
    }
}
相关推荐
PuddingSama1 小时前
Android 高级绘制技巧: BlendMode
android·前端·面试
2501_915921431 小时前
iOS App 性能监控与优化实战 如何监控CPU、GPU、内存、帧率、耗电情况并提升用户体验(uni-app iOS开发调试必备指南)
android·ios·小程序·uni-app·iphone·webview·ux
Digitally2 小时前
如何将视频从安卓手机传输到电脑?
android·智能手机·电脑
CV资深专家2 小时前
Android 相机框架的跨进程通信架构
android
前行的小黑炭2 小时前
Android :如何提升代码的扩展性,方便复制到其他项目不会粘合太多逻辑,增强你的实战经验。
android·java·kotlin
2501_915921432 小时前
前端开发工具有哪些?常用前端开发工具、前端调试工具、前端构建工具与效率提升工具对比与最佳实践
android·前端·ios·小程序·uni-app·iphone·webview
花菜会噎住2 小时前
MySQL 高级特性与性能优化:深入理解函数、视图、存储过程、触发器
android·mysql·函数·索引·视图
娅娅梨8 小时前
Android- Surface, SurfaceView, TextureView, SurfaceTexture 原理图解
android·surface
2501_9159184110 小时前
HTTPS 端口号详解 443 端口作用、iOS 抓包方法、常见 HTTPS 抓包工具与网络调试实践
android·网络·ios·小程序·https·uni-app·iphone
程序员码歌10 小时前
明年35岁了,如何破局?说说心里话
android·前端·后端