实现dump 函数
实现1
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) ; fclose ( fp) ; } GraphicBufferMapper :: getInstance ( ) . unlock ( * buffer) ;
}
实现2
# 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;
# 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
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 ; 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: size = width * height; break ; default : size = width * height * 4 ; } } } if ( data == nullptr || size == 0 ) { ALOGE ( "dumpBufferToFile: failed to lock buffer" ) ; return ; } char path[ 256 ] ; snprintf ( path, sizeof ( path) , "/data/vendor/camera/dump_%04d%s" , frameNum, getFormatSuffix ( format) ) ; 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) ; } mapper. unlock ( handle) ;
}
添加调用位置
推荐位置 1, Camera3OutputStream::queueBufferToConsumer()
此函数负责将 HAL 返回的 buffer 通过 ANativeWindow 传给 Surface,因此非常适合 dump。
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。
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 后 dumpdumpBufferToFile(buffer.buffer, stream->getWidth(), stream->getHeight(), result->frame_number);}
}