如何在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);
    }
}
相关推荐
毕设源码-钟学长41 分钟前
【开题答辩全过程】以 浮生馆汉服租赁管理系统为例,包含答辩的问题和答案
android·java·tomcat
louisgeek1 小时前
Android NDK 开发中的崩溃排查
android
2501_915921432 小时前
iOS 开发者工具推荐,构建从调试到性能优化的多维度生产力工具链(2025 深度工程向)
android·ios·性能优化·小程序·uni-app·iphone·webview
Chrison_mu3 小时前
Android项目背景动效-Kotlin
android·开发语言·kotlin
曾经的三心草5 小时前
JavaEE初阶-多线程2
android·java·java-ee
v***5655 小时前
Spring Cloud Gateway
android·前端·后端
苦逼的搬砖工7 小时前
基于 easy_rxdart 的轻量响应式与状态管理架构实践
android·flutter
2501_915918417 小时前
苹果上架 iOS 应用的工程实践,一次从零到上线的完整记录
android·ios·小程序·https·uni-app·iphone·webview
從南走到北8 小时前
JAVA国际版同城跑腿源码快递代取帮买帮送同城服务源码支持Android+IOS+H5
android·java·ios·微信小程序
2501_915918419 小时前
如何解析iOS崩溃日志:从获取到符号化分析
android·ios·小程序·https·uni-app·iphone·webview