一、前提知识:
App中的一个surface对应SufaceFlinger中的一个layout,surface需要申请GraphicBuffer来绘制UI内容,然后交给SurfaceFlinger去合成,最后显示;ImageReader中获得的image,也就是GraphicBuffer,用于绘制surface中的UI。
应用层经常会搭配如下两个函数来获取camera数据:
// 需要什么样的图像
mImageReader = ImageReader.newInstance(1920, 1080, ImageFormat.YUV_420_888, 2);
// 设置图像绘制完毕的监听
mImageReader.setOnImageAvailableListener(mmOnImageAvailableListener, mBackgroundHandler);
二、函数解析:
首先看下ImageReader::newInstance的实现:
文件路径:Z:\Android9_beta\frameworks\base\media\java\android\media\ImageReader.java
public static ImageReader newInstance(int width, int height, int format, int maxImages) {
return new ImageReader(width, height, format, maxImages,
BUFFER_USAGE_UNKNOWN);
}
接下来看看ImageReader的构造:
protected ImageReader(int width, int height, int format, int maxImages) {
mWidth = width;
mHeight = height;
mFormat = format;
mMaxImages = maxImages;
// 检查width 、height 、mMaxImages ,且不允许申请NV21格式的buffer
if (width < 1 || height < 1) {
throw new IllegalArgumentException(
"The image dimensions must be positive");
}
if (mMaxImages < 1) {
throw new IllegalArgumentException(
"Maximum outstanding image count must be at least 1");
}
// 不允许创建nv21格式数据
if (format == ImageFormat.NV21) {
throw new IllegalArgumentException(
"NV21 format is not supported");
}
mNumPlanes = ImageUtils.getNumPlanesForFormat(mFormat);
// 下面两个是主要实现
nativeInit(new WeakReference<>(this), width, height, format, maxImages, usage);
mSurface = nativeGetSurface();
// 标记申请的是image是合法的
mIsReaderValid = true;
mEstimatedNativeAllocBytes = ImageUtils.getEstimatedNativeAllocBytes(
width, height, format, /*buffer count*/ 1);
VMRuntime.getRuntime().registerNativeAllocation(mEstimatedNativeAllocBytes);
}
这里面主要的就是执行nativeInit和nativeGetSurface两个函数,这两个函数的实现在native文件android_media_ImageReader.cpp(Image.java和ImageReader.java共同的native文件)中,路径为:Z:\Android9_beta\frameworks\base\media\jni\android_media_ImageReader.cpp
函数映射如下:
{"nativeInit", "(Ljava/lang/Object;IIIIJ)V", (void*)ImageReader_init },
{"nativeImageSetup", "(Landroid/media/Image;)I", (void*)ImageReader_imageSetup },
ImageReader_init:
static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint width, jint height,jint format, jint maxImages, jlong ndkUsage) {
status_t res;
int nativeFormat;
android_dataspace nativeDataspace;
ALOGV("%s: width:%d, height: %d, format: 0x%x, maxImages:%d",
__FUNCTION__, width, height, format, maxImages);
// 这里是将申请的格式转化成公共格式,然后获取hal层中跟该格式对应的Format
PublicFormat publicFormat = static_cast<PublicFormat>(format);
nativeFormat = android_view_Surface_mapPublicFormatToHalFormat(
publicFormat);
nativeDataspace = android_view_Surface_mapPublicFormatToHalDataspace(
publicFormat);
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
jniThrowRuntimeException(env, "Can't find android/graphics/ImageReader");
return;
}
// 注意这里new出来的JNIImageReaderContext,这是管理buffer的核心。
// 在JNIImageReaderContext的构造里,会创建一个大小为maxImages的buffer队列mBuffers,
// 用于将ConsumerBase中获得的buffer放进此队列中。
sp<JNIImageReaderContext> ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages));
sp<IGraphicBufferProducer> gbProducer;
sp<IGraphicBufferConsumer> gbConsumer;
// 创建生产者和消费者。
BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
// 创建消费者,BufferItemConsumer是ConsumerBase的子类,这里可以从
// BufferQueueConsumer中拿取已经填充好的buffer数据。
sp<BufferItemConsumer> bufferConsumer;
String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
width, height, format, maxImages, getpid(),
createProcessUniqueId());
uint32_t consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
bool needUsageOverride = ndkUsage != CONSUMER_BUFFER_USAGE_UNKNOWN;
uint64_t outProducerUsage = 0;
uint64_t outConsumerUsage = 0;
android_hardware_HardwareBuffer_convertToGrallocUsageBits(&outProducerUsage, &outConsumerUsage,
ndkUsage, 0);
if (isFormatOpaque(nativeFormat)) {
// Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
// encoding. The only possibility will be ZSL output.
consumerUsage = GRALLOC_USAGE_SW_READ_NEVER;
if (needUsageOverride) {
consumerUsage = android_convertGralloc1To0Usage(0, outConsumerUsage);
}
} else if (needUsageOverride) {
ALOGW(&#