简介

Camera Engine为开发者提供了一套兼容EMUI的相机能力开放接口,开发者可以通过Camera Engine使自己的应用快速接入华为相机的私有能力,扩展应用的拍摄功能,为用户提供更好拍摄体验。

超级慢动作模式为Camera Engine开放的多种相机模式其中之一,它将允许您:

你将建立什么

在本次CodeLab中,您将使用Camera Engine建立一款Android相机应用程序,使其可以获得华为相机的超级慢动作功能,实现高速物体的慢动作效果。

超级慢动作下的景象

你会学到什么

你需要什么

硬件要求

软件要求

  1. 在工程的Manifest文件中添加相关权限:
    <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  2. 动态申请相关权限:
    private static final String[] PERMISSIONS_ARRAY = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}; private static List<String> permissionsList = new ArrayList<>(PERMISSIONS_ARRAY.length); /** * 动态请求WRITE_EXTERNAL_STORAGE CAMERA RECORD_AUDIO权限 * * @param activity 应用activity */ public static void requestPermission(final Activity activity) { for (String permission : PERMISSIONS_ARRAY) { if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) { permissionsList.add(permission); } } ActivityCompat.requestPermissions(activity, permissionsList.toArray(new String[permissionsList.size()]), REQUEST_CODE_ASK_PERMISSIONS); }

通过IDE提供的功能卡片,可以快速获取示例代码并将其添加到工程中,以超级慢动作模式为例,找到超级慢动作能力卡片:可通过EMUI->Kit Assistant->Media->Camera Engine->Super Slow Motion Mode 来找到该卡片

找到Camera Engine相关卡片

步骤1 模式创建:获取CameraKit实例,创建超级慢动作模式

/**超级慢动作模式*/ private static final @Mode.Type int CURRENT_MODE_TYPE = Mode.Type.SUPER_SLOW_MOTION; private CameraKit mCameraKit; private void createMode() { mCameraKit = CameraKit.getInstance(getApplicationContext()); if (mCameraKit == null) { Log.e(TAG, "This device does not support CameraKit!"); } // 查询摄像头ID列表 String[] cameraLists = mCameraKit.getCameraIdList(); if ((cameraLists != null) && (cameraLists.length > 0)) { mCameraId = cameraLists[0]; Log.i(TAG, "Try to use camera with id " + cameraLists[0]); // 查询当前设备所支持的模式 int[] modes = mCameraKit.getSupportedModes(cameraLists[0]); if (!Arrays.stream(modes).anyMatch((i) -> i == CURRENT_MODE_TYPE)) { Log.w(TAG, "Current mode is not supported in this device!"); return; } mCameraKit.createMode(mCameraId, CURRENT_MODE_TYPE, mModeStateCallback, mModeCbHandler); } }

步骤2 配置模式:配置模式的状态回调,数据回调及处理这些回调的Handler,以及预览、录像分辨率等参数

从mModeStateCallback的onCreated回调后,可从入参可获得超级慢动作Mode实例

/** 在onCreated回调中获取mode对象,然后以行为的状态回调和数据回调及对应的线程为入参,初始化ModeConfig.Builder,配置预览的surface和录像的大小,通过configure命令将配置项设置到mMode中,进行模式的激活*/ private void configureMode() { try { mPrepareModeConfigLock.acquire(); mModeCharacteristics = mCameraKit.getModeCharacteristics(mCameraId, CURRENT_MODE_TYPE); List<Size> previewSizes = mModeCharacteristics.getSupportedPreviewSizes(SurfaceTexture.class); Map<Integer, List<Size>> recordSizes = mModeCharacteristics.getSupportedVideoSizes(MediaRecorder.class); // 获取录像帧率、分辨率,这两个配置项要modeCharacteristics.getSupportedVideoSizes()返回的Map,成对设置 if (recordSizes.containsKey(Metadata.FpsRange.HW_FPS_960)) { mRecordFps = Metadata.FpsRange.HW_FPS_960; mRecordSize = recordSizes.get(Metadata.FpsRange.HW_FPS_960).get(0); } else { Log.e(TAG, "prepareConfig: Internal error"); return; } Log.d(TAG, "prepareConfig: recordFps = " + mRecordFps + ", recordSize = " + mRecordSize); // 超慢要求录像分辨率和预览分辨率保持一致 if (!previewSizes.contains(mRecordSize)) { Log.e(TAG, "preparePreviewSurface: the previewSize and recordSize should be the same, Internal error!"); return; } SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture(); if (surfaceTexture != null) { surfaceTexture.setDefaultBufferSize(mRecordSize.getWidth(), mRecordSize.getHeight()); mPreviewSurface = new Surface(surfaceTexture); } mModeConfigBuilder = mCurrentMode.getModeConfigBuilder(); mModeConfigBuilder.setStateCallback(mActionStateCallback, mStatusCbHandler); mModeConfigBuilder.setVideoFps(mRecordFps); mModeConfigBuilder.addVideoSize(mRecordSize); mModeConfigBuilder.addPreviewSurface(mPreviewSurface); mCurrentMode.configure(); } catch (InterruptedException e) { Log.e(TAG, "prepareModeConfig fail " + e.getMessage()); } finally { mPrepareModeConfigLock.release(); } }

使用构造器ModeConfig.Builder配置模式的状态回调及执行回调所在的Handler。从状态回调中,开发者可以获取超级慢动作录制过程中各种状态如返回未知错误、底层准备好、开始录制、结束录制、保存完毕结果返回等信息。还可通过ModeConfig.Builder配置预览Surface及拍照分辨率

步骤3 模式操作

  1. 开启预览

    /* 在接收到到onConfigured回调后,说明mode配置成功,模式进入开启状态,此时调用startPreview命令开启预览。*/ private void startPreview() { mCurrentMode.startPreview(); }
  2. 参数设置

    /* 用户可以通过ModeCharacteristics#getSupportedParameters查询当前模式下支持的参数(以超级慢动作模式为例:支持zoom 闪光灯、自动对焦等),通过ModeCharacteristics#getParameterRange查询参数支持的取值范围,通过Mode#setParameter设置对应效果。*/ /* 设置闪光灯 */ int[] flashDatas = mMode.getModeCharacteristics().getSupportedFlashMode(); mCurrentMode.setFlashMode(1); /* 用户可以通过设计按钮等方式,调用startRecording进行慢动作录制。*/ private void startRecord() { mRecordOrStop.setEnabled(false); mCurrentMode.startRecording(getExternalFilesDir(null)); }

步骤4 操作Callback

/* 以动作状态回调为例,获取执行状态结果的回调处理,如开启超级慢动作录制的准备、开始、结束、保存。*/ private ActionStateCallback mActionStateCallback = new ActionStateCallback() { @Override public void onRecording(Mode mode, int state, RecordingResult result) { switch (state) { // 出现IO错误 case RecordingResult.State.ERROR_FILE_IO: // 内部出现未知错误 case RecordingResult.State.ERROR_UNKNOWN: throw new IllegalStateException("error!"); // 底层初始化未准备好 case RecordingResult.State.ERROR_RECORDING_NOT_READY: runOnUiThread( () -> Toast.makeText(SuperSlowDemoActivity.this, R.string.status_not_ready, Toast.LENGTH_SHORT).show()); break; // 底层准备就绪 case RecordingResult.State.RECORDING_READY: runOnUiThread(() -> mRecordOrStop.setEnabled(true)); break; // 录制开始,自动模式下才会返回 case RecordingResult.State.RECORDING_STARTED: runOnUiThread(() -> { mRecordOrStop.setEnabled(false); Toast.makeText(SuperSlowDemoActivity.this, R.string.status_started, Toast.LENGTH_SHORT).show(); }); break; // 录制停止 case RecordingResult.State.RECORDING_STOPPED: runOnUiThread(() -> { Toast.makeText(SuperSlowDemoActivity.this, R.string.status_stopped, Toast.LENGTH_SHORT).show(); }); break; // 录制完成 case RecordingResult.State.RECORDING_COMPLETED: runOnUiThread( () -> Toast.makeText(SuperSlowDemoActivity.this, R.string.status_completed, Toast.LENGTH_SHORT).show()); break; // 录制文件保存完毕 case RecordingResult.State.RECORDING_FILE_SAVED: runOnUiThread(() -> { Toast.makeText(SuperSlowDemoActivity.this, mSaveFilePath + " saved", Toast.LENGTH_SHORT).show(); mRecordOrStop.setText(R.string.button_record); mRecordOrStop.setEnabled(true); }); break; default: break; } } };

步骤5 模式释放

/* 结束应用或切后台,需要将模式释放 */ @Override protected void onPause() { if (mBackgroundHandler != null) { mBackgroundHandler.post(new Runnable() { @Override public void run() { if (mCurrentMode!= null) { mCurrentMode.release(); mCurrentMode = null; } } }); } super.onPause(); }

干得好,你已经成功完成了开发并学到了:

更多Camera Engine相关信息请关注我们的官网:

https://developer.huawei.com/consumer/cn/CameraKit

已复制代码