为什么相机库CameraView预览和拍照的效果不一致 ?

您所在的位置:网站首页 谷歌相机拍的照片预览不了 为什么相机库CameraView预览和拍照的效果不一致 ?

为什么相机库CameraView预览和拍照的效果不一致 ?

2024-07-05 18:00| 来源: 网络整理| 查看: 265

1. 前言

在项目中,我们经常使用到CameraView,遇到好几次预览和拍照实际的效果不一致的情况。

这是为什么呢,为什么使用滤镜的时候,CameraView拍照和预览的效果会不一致 ?

终于在CameraView的源码里找到了答案。

2. takePictureSnapshot

带滤镜拍照的入口是CameraView.takePictureSnapshot()

cameraView.takePictureSnapshot()

cameraView.takePictureSnapshot()会调用到mCameraEngine.takePictureSnapshot(), 这个PictureResult.Stub是一个参数封装类,这里重新创建了一个PictureResult.Stub并传入takePictureSnapshot()方法中。 mCameraEngine是CameraEngine抽象类,实现类有Camera1Engine和Camera2Engine。

public void takePictureSnapshot() { PictureResult.Stub stub = new PictureResult.Stub(); mCameraEngine.takePictureSnapshot(stub); }

我们这里以Camera2为例,可以看到这里对stub参数封装类赋值了一些参数(摄像头ID、图片格式等),并调用了onTakePicture

@Override public void takePictureSnapshot(final PictureResult.Stub stub) { final boolean metering = mPictureSnapshotMetering; if (isTakingPicture()) return; stub.location = mLocation; stub.isSnapshot = true; stub.facing = mFacing; stub.format = PictureFormat.JPEG; AspectRatio ratio = AspectRatio.of(getPreviewSurfaceSize(Reference.OUTPUT)); onTakePictureSnapshot(stub, ratio, metering); } 3. onTakePictureSnapshot

这里给参数封装类stub赋值了一些值,然后初始化Snapshot2PictureRecorder,并调用其take()方法

@Override protected void onTakePictureSnapshot(@NonNull final PictureResult.Stub stub, @NonNull final AspectRatio outputRatio, boolean doMetering) { stub.size = getUncroppedSnapshotSize(Reference.OUTPUT); stub.rotation = getAngles().offset(Reference.VIEW, Reference.OUTPUT, Axis.ABSOLUTE); mPictureRecorder = new Snapshot2PictureRecorder(stub, this, (RendererCameraPreview) mPreview, outputRatio); mPictureRecorder.take(); } 4. Snapshot2PictureRecorder.take

Snapshot2PictureRecorder继承自SnapshotGlPictureRecorder,我们这里直接来看SnapshotGlPictureRecorder.take()

public void take() { mPreview.addRendererFrameCallback(new RendererFrameCallback() { @RendererThread public void onRendererTextureCreated(int textureId) { SnapshotGlPictureRecorder.this.onRendererTextureCreated(textureId); } @RendererThread @Override public void onRendererFilterChanged(@NonNull Filter filter) { SnapshotGlPictureRecorder.this.onRendererFilterChanged(filter); } @RendererThread @Override public void onRendererFrame(@NonNull SurfaceTexture surfaceTexture, int rotation, float scaleX, float scaleY) { mPreview.removeRendererFrameCallback(this); SnapshotGlPictureRecorder.this.onRendererFrame(surfaceTexture, rotation, scaleX, scaleY); } }); }

这里的mPreview实际上是GlCameraPreview,而通过RendererFrameCallback回调,会触发如下几个方法 onRendererTextureCreated 、onRendererFilterChanged、onRendererFrame 。

4.1 onRendererFilterChanged

当重新设置Filter的时候会调用这个回调。onRendererFilterChanged里会将filter拷贝一份,赋值给TextureDrawer

protected void onRendererFilterChanged(@NonNull Filter filter) { mTextureDrawer.setFilter(filter.copy()); } 4.2 onRendererFrame

当OpenGL绘制的时候,会调用onRendererFrame,onRendererFrame里会调用takeFrame()

protected void onRendererFrame(final SurfaceTexture surfaceTexture, final int rotation, final float scaleX, final float scaleY) { final EGLContext eglContext = EGL14.eglGetCurrentContext(); takeFrame(surfaceTexture, rotation, scaleX, scaleY, eglContext); } 5. takeFrame 5.1 创建EGL窗口

首先,会创建EGL窗口,这里创建了一个假的,前台不可见的一个EGL窗口,专门用来保存图片

// 0. EGL window will need an output. // We create a fake one as explained in javadocs. final int fakeOutputTextureId = 9999; SurfaceTexture fakeOutputSurface = new SurfaceTexture(fakeOutputTextureId); fakeOutputSurface.setDefaultBufferSize(mResult.size.getWidth(), mResult.size.getHeight()); 5.2 创建EGL Surface

接着,来创建EglSurface

// 1. Create an EGL surface final EglCore core = new EglCore(eglContext, EglCore.FLAG_RECORDABLE); final EglSurface eglSurface = new EglWindowSurface(core, fakeOutputSurface); eglSurface.makeCurrent(); 5.2.1 EglSurface

其中,这个com.otaliastudios.opengl.EglSurface是作者自己创建的,继承自EglNativeSurface,其内部调用了EglCore

public expect abstract class EglSurface internal constructor(eglCore: EglCore, eglSurface: EglSurface) : EglNativeSurface public open class EglNativeSurface internal constructor( internal var eglCore: EglCore, internal var eglSurface: EglSurface) { public fun getWidth(): Int { return if (width


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3