高斯模糊场景:手机相机不同于工业相机以及车载相机,手机相机的模式切换往往会伴随着预览分辨率的改变,而分辨率的切换伴随手机App->Framework->HAL->Drivel一层层的下发上传,所造成的时间延迟已经带来了不可忽略的视觉冲击,为了缓解这种冲击,引入高斯模糊对手机切换分辨率场景进行处理,提高用户体验舒适度。
应用层处理高斯模糊:
1.处理时机:肯定是越早越好,放到CameraActivity的Resume阶段,保证了每一次切换都可以调到高斯模糊的showPreviewAnim(0)方法。
@Override
protected void onResumeTasks() {
super.onResumeTasks();
PictureQuality.enterCameraMode();
mCameraAppUI.showPreviewAnim(0);
mCameraAppUI.removeTopSurface();
CameraSysTrace.onEventSystrace("CameraActivity.onResumeTasks", false, true);
}
//高斯模糊的处理,getPreviewBlurDrawable拿到最后的预览Bitmap
public void showPreviewAnim(int duration) {
if (mSwitchAnim == null || mSwitchAnim.getVisibility() == View.VISIBLE) {
return;
}
if (!mPause) {
getPreviewBlurDrawable();
}
if (mLastBitmap == null) {
mLastBitmap = mDefaultBitmap;
}
//RectF rect = new RectF(0, 0, 720, 1280);
RectF rect = mPreviewManager.getPreviewArea();
if (!isCameraSwitch) {
mSwitchAnim.setVisibility(View.VISIBLE);
startSwitchAnimation(0.0f, 1.0f, duration);
mSwitchAnim.setSwitchAnimInfo(mLastBitmap, rect);
}
}
2.高斯模糊去除时机:这个肯定是要在旧的预览session已经切断,新的预览session创建且上传数据之后去除高斯模糊效果,可通过下发预览请求时的回调函数达到这个时机的监控以及把握,CaptureCallback回调函数的onCaptureFailed捕捉旧预览切断的时机,onCaptureCompleted捕捉新预览第一帧数据上传时机。
//下发repeatingPreview请求
mSession.setRepeatingRequest(mBuilder.build(), mCaptureCallback, mModeHandler);
//mCaptureCallback回调函数监控
private final CaptureCallback mCaptureCallback = new CaptureCallback() {
@Override
public void onCaptureCompleted(@Nonnull CameraCaptureSession session,
@Nonnull CaptureRequest request, @Nonnull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
if (mCamera2Proxy == null
|| mModeDeviceCallback == null
|| session.getDevice() != mCamera2Proxy.getCameraDevice()) {
return;
}
if (!CameraUtil.isStillCaptureTemplate(result) && !mFirstFrameArrived) {
mFirstFrameArrived = true;
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
LogHelper.d(TAG, "[onCaptureCompleted] hidePreviewAnim");
((CameraAppUI) ((CameraActivity) mActivity).getAppUi()).hidePreviewAnim(0);
}
}, 700);
}
}
@Override
public void onCaptureFailed(@Nonnull CameraCaptureSession session,
@Nonnull CaptureRequest request, @Nonnull CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
}
3.高斯模糊预览帧获:通过应用层接收预览buffer的CaptureSurface的OnImageAvailable来获取预览的Image,高斯模糊对之前分辨率下的最后一帧Buffer进行模糊处理。
private PreviewImageCallback mPreviewImageCallback;
public interface PreviewImageCallback {
void onPreviewImageCallback(Image image);
}
public void setPreviewCallback(PreviewImageCallback captureCallback) {
mPreviewImageCallback = captureCallback;
}
public final OnImageAvailableListener mCaptureImageListener = new OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
int format = image.getFormat();
int width = image.getWidth();
int height = image.getHeight();
if((format == ImageFormat.YUV_420_888 && "previewImage".equalsIgnoreCase(mCaptureType))) {
if(mPreviewImageCallback != null) {
mPreviewImageCallback.onPreviewImageCallback(image);
}
image.close();
}
}
}
//每次下发repeatingPreview请求时
mPreviewImageSurface.setPreviewCallback(this);
@Override
public void onPreviewImageCallback(Image image) {
//拿到了预览帧Image
((CameraAppUI) ((CameraActivity) mActivity).getAppUi()).setPreviewBitmap(image);
}
public void getPreviewBlurDrawable() {
mLastBitmap = mDefaultBitmap;
GaussianBlur blur = new GaussianBlur(mApp.getActivity());
Bitmap preview;
preview = getPreviewBitmap(mPreviewImageData);
if (preview != null) {
Bitmap bitmap = blur.blurBitmap(mApp.getActivity(), blur.small(preview));
if (bitmap != null) {
mLastBitmap = bitmap;
}
}
}
4.对最后的预览帧Bitmap进行高斯模糊处理:对Bitmap数据的高斯模糊处理也是引入canvas以及一些Matrix的方式进行坐标的模糊处理,上代码。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final DisplayMetrics metrics = new DisplayMetrics();
mApp.getActivity().getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
int[] loc = new int[2];
getPreviewFrameLayout().getLocationOnScreen(loc);
int x = loc[0];
int y = loc[1];
if (mBlurBitmapWidth > 0 && mBlurBitmapHeight > 0) {
mPreviewRatio = CameraUtil.determineRatio((int) mBlurBitmapWidth, (int) mBlurBitmapHeight);
canvas.drawColor(mBgColor);
mMatrix.reset();
final Bitmap bitmap = changeBitmapSize(mBlurBitmap, mBlurBitmapWidth, mBlurBitmapHeight);
mMatrix.postTranslate(x, y);
canvas.drawBitmap(bitmap, mMatrix, null);
}
}
经过高斯模糊处理后:
对比华为手机模式切换时候的高斯模糊处理: