当前位置: 首页 > news >正文

鸿蒙媒体开发【相机数据采集保存】音频和视频

相机数据采集保存

介绍

本示例主要展示了相机的相关功能,使用libohcamera.so 接口实现相机的预览、拍照、录像、前后置摄像头切换进行拍照、录像,以及对焦、曝光等控制类功能。

效果预览

1

使用说明

  1. 弹出是否允许“CameraSample”使用相机?点击“允许”
  2. 弹出是否允许“CameraSample”使用麦克风?点击“允许”
  3. 弹出是否允许“CameraSample”访问文件?点击“允许”
  4. 弹出是否允许“CameraSample”访问图片和视频?点击“允许”
  5. 进入预览界面,预览正常,点击画面模糊处,画面会变得清晰,对焦效果明显
  6. 进入预览界面,预览正常,上下滑动屏幕,屏幕场景亮度发生变化,曝光效果明显
  7. 进入预览界面,预览正常,进入拍照模式,点击拍照按钮,拍照正常,左下角会生成照片缩略图,点击左下角缩略图,能够跳转到图库,图片保存正常,打开图片显示正常
  8. 进入预览界面,预览正常,切换到前置摄像头,点击拍照按钮,拍照正常,左下角生成照片缩略图,点击左下角缩略图,能够跳转到图库,图片保存正常,打开图片显示正常
  9. 进入预览界面,预览正常,切换到录像模式,点击录像,开始录像,再点击停止录像按钮,录像成功,左下角会生成视频缩略图,点击左下角缩略图,能够跳转到图库,录像文件保存正常,播放录像文件正常
  10. 进入预览界面,预览正常,切换到后置摄像头,点击录像,开始录像,再点击停止录像按钮,录像成功,左下角会生成视频缩略图,点击左下角缩略图,能够跳转到图库,录像文件保存正常,播放录像文件正常

具体实现

  • 相机功能接口实现在CameraManager.cpp中

    • 在NDKCamera构造函数里完成一个相机生命周期初始化的过程,包括调用OH_Camera_GetCameraMananger获取CameraMananger,调用OH_CameraManager_CreateCaptureSession创建CaptureSession,调用CaptureSessionRegisterCallback创建CaptureSession注册回调,调用GetSupportedCameras获取支持的camera设备,调用GetSupportedOutputCapability获取支持的camera设备能力集,调用CreatePreviewOutput创建预览输出,调用CreateCameraInput创建相机输入,调用CameraInputOpen打开相机输入,调用CameraManagerRegisterCallback创建CameraManager注册回调,最后调用SessionFlowFn开启Session。

    • 其中SessionFlowFn是一个开启预览的动作,主要流程包括:调用OH_CaptureSession_BeginConfig开始配置会话,调用OH_CaptureSession_AddInput把CameraInput加入到会话,调用OH_CaptureSession_AddPreviewOutput把previewOutput加入到会话,调用OH_CaptureSession_CommitConfig提交配置信息,调用OH_CaptureSession_Start开始会话工作,还有一步是在开启预览的同时调用IsFocusMode启动对焦功能,这边后面会涉及到。

    • 在NDKCamera析构函数里完成对相机生命周期释放的过程,调用OH_CameraManager_DeleteSupportedCameras删除支持的camera设备,调用OH_CameraManager_DeleteSupportedCameraOutputCapability删除支持的camera设备能力集,调用OH_Camera_DeleteCameraManager删除camera manager。

    • 拍照功能相关接口封装在StartPhoto接口中,主要包含以下流程:调用SessionStop关闭session,调用SessionBegin做session的一个预置动作,调用CreatePhotoOutput创建相机输出,调用OH_CaptureSession_AddPhotoOutput将hotoOutput添加至session中,调用SessionCommitConfig提交session,在调用SessionStart开启session,最后调用TakePicture接口开启拍照动作。

    • 录像功能相关接口封装在StartVideo接口中,主要包含以下流程:调用SessionStop关闭session,调用SessionBegin做session的一个预置动作,调用OH_CaptureSession_RemovePhotoOutput移除相机拍照输出,再调用CreatePhotoOutput创建相机输出,调用AddPhotoOutput将相机输出添加至session中,调用CreateVideoOutput创建录像输出,调用AddVideoOutput将录像输出添加至session中,然后再调用SessionCommitConfig、SessionStart对session进行提交和开启,最后调用VideoOutputRegisterCallback对VideoOutput注册回调。

    • 曝光功能相关接口封装在IsExposureModeSupportedFn接口中,主要包含以下流程:调用OH_CaptureSession_IsExposureModeSupported判断是否支持曝光模式,然后调用OH_CaptureSession_SetExposureMode设置曝光模式,调用OH_CaptureSession_GetExposureMode获取设置后的曝光模式。调用IsExposureBiasRange接口获取曝光补偿,其中包含调用OH_CaptureSession_GetExposureBiasRange获取曝光补偿的范围,调用OH_CaptureSession_SetExposureBias设置曝光点,调用OH_CaptureSession_GetExposureBias获取曝光点。

    • 对焦功能相关接口封装在IsFocusMode接口中,主要包含以下流程:调用OH_CaptureSession_IsFocusModeSupported判断是否支持对焦模式,调用OH_CaptureSession_SetFocusMode设置对焦模式,调用OH_CaptureSession_GetFocusMode获取设置后的对焦模式。

    • 调用IsFocusPoint接口获取对焦点,其中包括调用OH_CaptureSession_SetFocusPoint获取JS侧下发来的对焦点位,然后调用OH_CaptureSession_GetFocusPoint获取设置后的对焦点位。

    • 视频防抖功能相关接口封装在IsVideoStabilizationModeSupportedFn接口中,主要包含以下流程:调用OH_CaptureSession_IsVideoStabilizationModeSupported接口查询是否支持指定的视频防抖模式,调用OH_CaptureSession_SetVideoStabilizationMode设置视频防抖,调用OH_CaptureSession_GetVideoStabilizationMode获取设置后的视频防抖模式。

    • 回调接口设置:

      • CameraManagerRegisterCallback:监听相机状态回调,在打开、退出相机,相机摄像头切换时会触发
      • CameraInputRegisterCallback:相机输入发生错误时触发回调
      • PhotoOutputRegisterCallback:开启拍照时触发回调
      • VideoOutputRegisterCallback:开启录像模式时触发回调
      • CaptureSessionRegisterCallback:session出现异常时以及开启对焦模式时触发回调
  • 相机预览、拍照、录像功能、前后置切换功能实现调用侧位于tableIndex.ets,modeSwitchPage.ets,main.cpp中,源码参考:[Index.ets]

/** Copyright (c) 2024 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the 'License');* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an 'AS IS' BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import { abilityAccessCtrl } from '@kit.AbilityKit';
import { common } from '@kit.AbilityKit';
import { display } from '@kit.ArkUI';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { dataSharePredicates } from '@kit.ArkData';
import { image } from '@kit.ImageKit';
import cameraDemo from 'libentry.so';
import Logger from '../common/utils/Logger';
import { DividerPage } from '../views/DividerPage';
import { ModeSwitchPage } from '../views/ModeSwitchPage';
import { FocusPage } from '../views/FocusPage';
import { FocusAreaPage } from '../views/FocusAreaPage';
import { Constants } from '../common/Constants';
import { SettingDataObj } from '../common/Constants';
import DisplayCalculator from '../common/DisplayCalculator';const TAG: string = 'UI indexPage';
let context = getContext(this) as common.UIAbilityContext;@Entry
@Component
struct Index {// surfaceID value.@State surfaceId: string = '';// Select mode.@State modelBagCol: string = 'photo';// Exposure area.@State focusPointBol: boolean = false;// Finger click coordinates in the exposure area.@State focusPointVal: Array<number> = [0, 0];// Display where scale, focal length value, and focus box cannot coexist.@State exposureBol: boolean = true;// Exposure value.@State exposureNum: number = 0;// Countdown, photography, and video recording.@State countdownNum: number = 0;// Front and rear cameras.@State cameraDeviceIndex: number = 0;@State xComponentWidth: number = 384;@State xComponentHeight: number = 450;// Reference line.@State referenceLineBol: boolean = false;@StorageLink('defaultAspectRatio') @Watch('initXComponentSize') defaultAspectRatio: number= Constants.MIN_ASPECT_RATIO;@State onShow: boolean = false;// Thumbnails@StorageLink('thumbnail') thumbnail: image.PixelMap | undefined | string = '';// XComponentController.private mXComponentController: XComponentController = new XComponentController();private screenHeight: number = 0;private screenWidth: number = 0;private settingDataObj: SettingDataObj = {mirrorBol: false,videoStabilizationMode: 0,exposureMode: 1,focusMode: 2,photoQuality: 1,locationBol: false,photoFormat: 1,photoOrientation: 0,photoResolution: 0,videoResolution: 0,videoFrame: 0,referenceLineBol: false};private appContext: common.Context = getContext(this);atManager = abilityAccessCtrl.createAtManager();// Entry initialization function.async aboutToAppear() {await this.requestPermissionsFn();let mDisplay = display.getDefaultDisplaySync();this.screenWidth = px2vp(mDisplay.width);this.screenHeight = px2vp(mDisplay.height);this.initXComponentSize();}initXComponentSize(): void {let defaultSize =DisplayCalculator.calcSurfaceDisplaySize(this.screenWidth, this.screenHeight, this.defaultAspectRatio);this.xComponentWidth = defaultSize.width;this.xComponentHeight = defaultSize.height;}async aboutToDisAppear() {cameraDemo.releaseCamera();}// Obtain permissions.async requestPermissionsFn() {Logger.info(TAG, `requestPermissionsFn entry`);try {this.atManager.requestPermissionsFromUser(this.appContext, ['ohos.permission.CAMERA','ohos.permission.MICROPHONE','ohos.permission.READ_MEDIA','ohos.permission.WRITE_MEDIA','ohos.permission.WRITE_IMAGEVIDEO','ohos.permission.READ_IMAGEVIDEO']).then(() => {Logger.info(TAG, `request Permissions success!`);this.onShow = true;this.getThumbnail();});} catch (err) {Logger.error(TAG, `requestPermissionsFromUser call Failed! error: ${err.code}`);}}async getThumbnail() {let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();let fetchOptions: photoAccessHelper.FetchOptions = {fetchColumns: [],predicates: predicates};let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> =await phAccessHelper.getAssets(fetchOptions);let asset: photoAccessHelper.PhotoAsset = await fetchResult.getLastObject();console.info('asset displayName = ', asset.displayName);asset.getThumbnail((err, pixelMap) => {if (err === undefined) {this.thumbnail = pixelMap;console.info('getThumbnail successful ' + pixelMap);} else {console.error(`getThumbnail fail with error: ${err.code}, ${err.message}`);}});}async onPageShow() {Logger.info(TAG, `onPageShow App`);if (this.surfaceId && this.onShow) {Logger.error(TAG, `initCamera start`);cameraDemo.initCamera(this.surfaceId, this.settingDataObj.focusMode, this.cameraDeviceIndex);Logger.error(TAG, `initCamera end`);}this.getThumbnail();}onPageHide() {Logger.info(TAG, `onPageHide App`);this.thumbnail = ''cameraDemo.releaseCamera();}build() {Stack() {if (this.onShow) {// General appearance of a picture.XComponent({id: 'componentId',type: 'surface',controller: this.mXComponentController}).onLoad(async () => {Logger.info(TAG, 'onLoad is called');this.surfaceId = this.mXComponentController.getXComponentSurfaceId();Logger.info(TAG, `onLoad surfaceId: ${this.surfaceId}`);Logger.info(TAG, `initCamera start`);cameraDemo.initCamera(this.surfaceId, this.settingDataObj.focusMode, this.cameraDeviceIndex);Logger.info(TAG, `initCamera end`);}).backgroundColor(Color.Black).width(Constants.FULL_PERCENT).height(Constants.SEVENTY_PERCENT).margin({bottom: Constants.FIFTEEN_PERCENT})// Reference line.DividerPage({ referenceLineBol: this.referenceLineBol });// Exposure frame and focus frame.FocusPage({focusPointBol: $focusPointBol,focusPointVal: $focusPointVal,exposureBol: $exposureBol,exposureNum: $exposureNum});// Exposure focusing finger click area.FocusAreaPage({focusPointBol: $focusPointBol,focusPointVal: $focusPointVal,exposureBol: $exposureBol,exposureNum: $exposureNum,xComponentWidth: this.xComponentWidth,xComponentHeight: this.xComponentHeight});// Reverse camera_Multiple workstations_Take photos_Video.ModeSwitchPage({surfaceId: this.surfaceId,cameraDeviceIndex: $cameraDeviceIndex,countdownNum: $countdownNum});}}.height(Constants.FULL_PERCENT).width(Constants.FULL_PERCENT).backgroundColor(Color.Black)}
}
  • 源码参考[ModeSwitchPage.ets]
/** Copyright (c) 2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the 'License');* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an 'AS IS' BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/// Reverse camera_ Multiple workstations_ Take photos Video.
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { dataSharePredicates } from '@kit.ArkData';
import { fileIo } from '@kit.CoreFileKit';
import { BusinessError, deviceInfo } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { image } from '@kit.ImageKit';
import { media } from '@kit.MediaKit';
import cameraDemo from 'libentry.so';
import Logger from '../common/utils/Logger';
import MediaUtils from '../common/utils/MediaUtils';
import { SettingDataObj } from '../common/Constants'
import { Constants } from '../common/Constants'let context = getContext(this) as common.UIAbilityContext;interface PhotoSettings {quality: number, // Photo qualityrotation: number, // Photo directionmirror: boolean, // Mirror Enablelatitude: number, // geographic locationlongitude: number, // geographic locationaltitude: number // geographic location
};interface PhotoRotationMap {rotation0: number,rotation90: number,rotation180: number,rotation270: number,
};@Component
export struct ModeSwitchPage {@State videoId: string = '';@State mSurfaceId: string = '';// Front and rear cameras@Link cameraDeviceIndex: number;// SurfaceID@Prop surfaceId: string;// Countdown value@Link countdownNum: number;// Countdown timer@State countTimerInt: number = -1;@State countTimerOut: number = -1;// Recording time@State videoRecodeTime: number = 0;// Recording time timer@State timer: number = -1;// Select mode@State modelBagCol: string = Constants.PHOTO;// Choose camera or capture@State @Watch('onChangeIsModeBol') isModeBol: boolean = true;// Thumbnails@StorageLink('thumbnail') thumbnail: image.PixelMap | undefined | string = '';private tag: string = 'sample modeSwitchPage:';private mediaUtil = MediaUtils.getInstance();private photoAsset?: string;private fd: number = -1;private cameraSize: image.Size = {width: 1280,height: 720};private photoSettings: PhotoSettings = {quality: 0,rotation: 0,mirror: false,latitude: Constants.LATITUDE,longitude: Constants.LONGITUDE,altitude: Constants.ALTITUDE};private mReceiver?: image.ImageReceiver;private videoRecorder?: media.AVRecorder;private videoConfig: media.AVRecorderConfig = {audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC,videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV,profile: {audioBitrate: Constants.AUDIO_BITRATE_SAMPLE_RATE,audioChannels: Constants.AUDIO_CHANNELS,audioCodec: media.CodecMimeType.AUDIO_AAC,audioSampleRate: Constants.AUDIO_BITRATE_SAMPLE_RATE,fileFormat: media.ContainerFormatType.CFT_MPEG_4,videoBitrate: Constants.VIDEO_BITRATE,videoCodec: media.CodecMimeType.VIDEO_AVC,videoFrameWidth: Constants.VIDEO_FRAME_WIDTH,videoFrameHeight: Constants.VIDEO_FRAME_HEIGHT,videoFrameRate: Constants.VIDEO_FRAME_RATE},url: '',metadata: {videoOrientation: ''}};private photoRotationMap: PhotoRotationMap = {rotation0: 0,rotation90: 90,rotation180: 180,rotation270: 270,};private settingDataObj: SettingDataObj = {mirrorBol: false,videoStabilizationMode: 0,exposureMode: 1,focusMode: 2,photoQuality: 1,locationBol: false,photoFormat: 1,photoOrientation: 0,photoResolution: 0,videoResolution: 0,videoFrame: 0,referenceLineBol: false};// After pausing, click 'stop' to reset the pause to default.onChangeIsModeBol() {}// Countdown capture and video.countTakeVideoFn() {if (this.countdownNum) {// Clear Countdown.if (this.countTimerOut) {clearTimeout(this.countTimerOut);}if (this.countTimerInt) {clearInterval(this.countTimerInt);}// Turn on timer.this.countTimerOut = setTimeout(() => {// Determine whether it is in video or photo mode.this.isVideoPhotoFn();}, this.countdownNum * 1000)// Turn on timer.this.countTimerInt = setInterval(() => {this.countdownNum--;if (this.countdownNum === 0) {clearInterval(this.countTimerInt);}}, 1000)} else {this.isVideoPhotoFn();}}async getVideoSurfaceID() {Logger.info(this.tag, `getVideoSurfaceID`);this.videoRecorder = await media.createAVRecorder();Logger.info(this.tag, `getVideoSurfaceID videoRecorder: ${this.videoRecorder}`);this.photoAsset = await this.mediaUtil.createAndGetUri(photoAccessHelper.PhotoType.VIDEO);Logger.info(this.tag, `getVideoSurfaceID photoAsset: ${this.photoAsset}`);this.fd = await this.mediaUtil.getFdPath(this.photoAsset);Logger.info(this.tag, `getVideoSurfaceID fd: ${this.fd}`);this.videoConfig.url = `fd://${this.fd}`;Logger.info(this.tag, `getVideoSurfaceID videoConfig.url : ${this.videoConfig.url}`);if (deviceInfo.deviceType === Constants.DEFAULT) {Logger.info(this.tag, `deviceType = default`);this.videoConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_ES;}if (deviceInfo.deviceType === Constants.PHONE) {Logger.info(this.tag, `deviceType = phone`)this.videoConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV;this.videoConfig.profile.videoCodec = media.CodecMimeType.VIDEO_AVC;if (this.cameraDeviceIndex === 1) {this.videoConfig.metadata = {videoOrientation: '270'};} else {this.videoConfig.metadata = {videoOrientation: '90'};}}if (deviceInfo.deviceType === 'tablet') {Logger.info(this.tag, `deviceType = tablet`);this.videoConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV;}this.videoConfig.profile.videoFrameWidth = cameraDemo.getVideoFrameWidth();this.videoConfig.profile.videoFrameHeight = cameraDemo.getVideoFrameHeight();this.videoConfig.profile.videoFrameRate = cameraDemo.getVideoFrameRate();await this.videoRecorder.prepare(this.videoConfig);this.videoId = await this.videoRecorder.getInputSurface();Logger.info(this.tag, `getVideoSurfaceID videoId: ${this.videoId}`);}createImageReceiver() {try {this.mReceiver = image.createImageReceiver(this.cameraSize, 2000, 8);Logger.info(this.tag, `createImageReceiver value: ${this.mReceiver} `);this.mReceiver.on('imageArrival', () => {Logger.info(this.tag, 'imageArrival start');if (this.mReceiver) {this.mReceiver.readNextImage((err, image) => {Logger.info(this.tag, 'readNextImage start');if (err || image === undefined) {Logger.error(this.tag, 'readNextImage failed ');return;}image.getComponent(4, (errMsg, img) => {Logger.info(this.tag, 'getComponent start');if (errMsg || img === undefined) {Logger.info(this.tag, 'getComponent failed ');return;}let buffer = new ArrayBuffer(2048);if (img.byteBuffer) {buffer = img.byteBuffer;} else {Logger.error(this.tag, 'img.byteBuffer is undefined');}this.savePicture(buffer, image);})})}})} catch {Logger.info(this.tag, 'savePicture err');}}// Read Image.async savePicture(buffer: ArrayBuffer, img: image.Image) {try {Logger.info(this.tag, 'savePicture start');let photoAssetUri: string = await this.mediaUtil.createAndGetUri(photoAccessHelper.PhotoType.IMAGE);let imgPhotoUri: string = photoAssetUri;Logger.info(this.tag, `photoUri = ${imgPhotoUri}`);let imgFd = await this.mediaUtil.getFdPath(imgPhotoUri);Logger.info(this.tag, `fd = ${imgFd}`);fileIo.writeSync(imgFd, buffer);fileIo.closeSync(imgFd);await img.release();Logger.info(this.tag, 'save image End');setTimeout(() => {if (this.handleTakePicture) {this.handleTakePicture(imgPhotoUri);}}, 10)} catch (err) {Logger.info(this.tag, 'savePicture err' + JSON.stringify(err.message));}}async getPhotoSurfaceID() {if (this.mReceiver) {Logger.info(this.tag, 'imageReceiver has been created');} else {this.createImageReceiver();}if (this.mReceiver) {this.mSurfaceId = await this.mReceiver.getReceivingSurfaceId();}if (this.mSurfaceId) {Logger.info(this.tag, `createImageReceiver mSurfaceId: ${this.mSurfaceId} `);} else {Logger.info(this.tag, `Get mSurfaceId failed `);}}// Determine the video or photo mode.async isVideoPhotoFn() {await this.getPhotoSurfaceID();if (this.modelBagCol === Constants.PHOTO) {cameraDemo.startPhotoOrVideo(this.modelBagCol, this.videoId, this.mSurfaceId);} else if (this.modelBagCol === Constants.VIDEO) {this.isModeBol = false;if (this.timer) {clearInterval(this.timer);}// Start record.await this.getVideoSurfaceID();cameraDemo.startPhotoOrVideo(this.modelBagCol, this.videoId, this.mSurfaceId);cameraDemo.videoOutputStart();if (this.videoRecorder) {this.videoRecorder.start();}}}async handleTakePicture(thumbnail: string) {this.thumbnail = thumbnailLogger.info(this.tag, `takePicture end , thumbnail: ${this.thumbnail}`);}aboutToDisappear() {if (this.mReceiver) {this.mReceiver.release().then(() => {Logger.info(this.tag, 'release succeeded.');}).catch((error: BusinessError) => {Logger.error(this.tag, `release failed, error: ${error}`);})}}build() {if (this.isModeBol) {Column() {Text($r('app.string.photo')).size({ width: $r('app.float.model_size_width'), height: $r('app.float.model_size_height') }).borderRadius($r('app.float.border_radius')).fontSize($r('app.float.photo_video_font_size')).fontColor(Color.White).onClick(() => {cameraDemo.releaseSession()cameraDemo.initCamera(this.surfaceId, this.settingDataObj.focusMode, this.cameraDeviceIndex)this.modelBagCol = Constants.PHOTO})}.position({ x: Constants.PHOTO_X_POSITION, y: Constants.Y_POSITION })Column() {Text($r('app.string.video')).size({ width: $r('app.float.model_size_width'), height: $r('app.float.model_size_height') }).borderRadius($r('app.float.border_radius')).fontSize($r('app.float.photo_video_font_size')).fontColor(Color.White).onClick(() => {cameraDemo.releaseSession()cameraDemo.initCamera(this.surfaceId, this.settingDataObj.focusMode, this.cameraDeviceIndex)this.modelBagCol = Constants.VIDEO})}.position({ x: Constants.VIDEO_X_POSITION, y: Constants.Y_POSITION })// Album.Column() {Row() {if (this.modelBagCol === Constants.PHOTO) {Image(this.thumbnail || $r('app.media.camera_thumbnail_4x')).borderRadius(px2vp(Constants.ICON_SIZE / 2)).syncLoad(true).objectFit(ImageFit.Fill).width(px2vp(Constants.ICON_SIZE)).height(px2vp(Constants.ICON_SIZE))} else {Image(this.thumbnail || $r('app.media.camera_thumbnail_4x')).borderRadius(px2vp(Constants.ICON_SIZE / 2)).objectFit(ImageFit.Fill).width(px2vp(Constants.ICON_SIZE)).height(px2vp(Constants.ICON_SIZE))}}.onClick(() => {if (deviceInfo.deviceType === Constants.DEFAULT) {context.startAbility({bundleName: 'com.ohos.photos',abilityName: 'com.ohos.photos.MainAbility'})} else if (deviceInfo.deviceType === Constants.PHONE) {context.startAbility({bundleName: 'com.huawei.hmos.photos',abilityName: 'com.huawei.hmos.photos.MainAbility'})}})}.position({ x: Constants.ALBUM_X_POSITION, y: Constants.ICON_Y_POSITION }).id('Thumbnail')// Capture video icon.Column() {Row() {if (this.modelBagCol === Constants.PHOTO) {Image($r('app.media.camera_take_photo_4x')).width(px2vp(Constants.ICON_SIZE)).height(px2vp(Constants.ICON_SIZE)).onClick(() => {// Countdown camera recording - default camera recording.this.countTakeVideoFn();})} else {Image($r('app.media.camera_take_video_4x')).width(px2vp(Constants.ICON_SIZE)).height(px2vp(Constants.ICON_SIZE)).onClick(() => {// Countdown camera recording - default camera recording.this.countTakeVideoFn();})}}}.position({ x: Constants.CAPTURE_X_POSITION, y: Constants.ICON_Y_POSITION }).id('CaptureOrVideoButton')// Front and rear camera switching.Column() {Row() {Image($r('app.media.camera_switch_4x')).width(px2vp(Constants.ICON_SIZE)).height(px2vp(Constants.ICON_SIZE)).onClick(async () => {// Switching cameras.this.cameraDeviceIndex ? this.cameraDeviceIndex = 0 : this.cameraDeviceIndex = 1;// Clear configuration.cameraDemo.releaseSession();// Start preview.cameraDemo.initCamera(this.surfaceId, this.settingDataObj.focusMode, this.cameraDeviceIndex);})}}.position({ x: Constants.SWITCH_X_POSITION, y: Constants.ICON_Y_POSITION }).id('SwitchCameraButton')} else {Column() {// Video capture button.Image($r('app.media.camera_take_photo_4x')).width(px2vp(Constants.ICON_SIZE)).height(px2vp(Constants.ICON_SIZE)).onClick(() => {cameraDemo.takePictureWithSettings(this.photoSettings);})}.position({ x: Constants.ALBUM_X_POSITION, y: Constants.ICON_Y_POSITION }).id('VideoCaptureButton')Column() {Row() {Column() {// video stop button.Image($r('app.media.camera_pause_video_4x')).size({ width: $r('app.float.video_stop_size'), height: $r('app.float.video_stop_size') }).width(px2vp(Constants.ICON_SIZE)).height(px2vp(Constants.ICON_SIZE)).id('StopVideo').onClick(() => {if (this.timer) {clearInterval(this.timer);}// Stop video.this.stopVideo().then(() => {this.videoRecodeTime = 0;this.isModeBol = true;})})}}.width(px2vp(Constants.ICON_SIZE)).height(px2vp(Constants.ICON_SIZE))}.position({ x: Constants.CAPTURE_X_POSITION, y: Constants.ICON_Y_POSITION })}}async stopVideo() {try {if (this.videoRecorder) {await this.videoRecorder.stop();await this.videoRecorder.release();}cameraDemo.videoOutputStopAndRelease();let result: photoAccessHelper.PhotoAsset | undefined = undefined;if (this.photoAsset) {await fileIo.close(this.fd);setTimeout(async () => {let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();let fetchOptions: photoAccessHelper.FetchOptions = {fetchColumns: [],predicates: predicates};let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> =await phAccessHelper.getAssets(fetchOptions);let photoAssetList: Array<photoAccessHelper.PhotoAsset> = await fetchResult.getAllObjects();photoAssetList.forEach((item: photoAccessHelper.PhotoAsset) => {if (item.uri === this.photoAsset) {Logger.info(this.tag, `item.uri = ${item.uri}`)result = item}})try {// Get video thumbnail.this.thumbnail = await result?.getThumbnail();Logger.info(this.tag, 'videoThumbnail = ' + JSON.stringify(this.thumbnail));} catch (err) {Logger.error(this.tag, 'videoThumbnail err----------:' + JSON.stringify(err.message));}}, 1000)}Logger.info(this.tag, 'stopVideo end');} catch (err) {Logger.error(this.tag, 'stopVideo err: ' + JSON.stringify(err));}return;}
}
  • 源码参考[main.cpp]
/** Copyright (c) 2024 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the 'License');* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an 'AS IS' BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#include <hilog/log.h>
#include <js_native_api.h>
#include <node_api.h>
#include "camera_manager.h"using namespace OHOS_CAMERA_SAMPLE;
static NDKCamera *ndkCamera_ = nullptr;
const int32_t ARGS_TWO = 2;
struct Capture_Setting {int32_t quality;int32_t rotation;int32_t location;bool mirror;int32_t latitude;int32_t longitude;int32_t altitude;
};static napi_value SetZoomRatio(napi_env env, napi_callback_info info) {size_t argc = 2;napi_value args[2] = {nullptr};napi_value result;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_valuetype valuetype0;napi_typeof(env, args[0], &valuetype0);int32_t zoomRatio;napi_get_value_int32(env, args[0], &zoomRatio);OH_LOG_INFO(LOG_APP, "SetZoomRatio : %{public}d", zoomRatio);ndkCamera_->setZoomRatioFn(zoomRatio);napi_create_int32(env, argc, &result);return result;
}static napi_value HasFlash(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "HasFlash");size_t argc = 2;napi_value args[2] = {nullptr};napi_value result;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_valuetype valuetype0;napi_typeof(env, args[0], &valuetype0);int32_t flashMode;napi_get_value_int32(env, args[0], &flashMode);OH_LOG_INFO(LOG_APP, "HasFlash flashMode : %{public}d", flashMode);ndkCamera_->HasFlashFn(flashMode);napi_create_int32(env, argc, &result);return result;
}static napi_value IsVideoStabilizationModeSupported(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "IsVideoStabilizationModeSupportedFn");size_t argc = 2;napi_value args[2] = {nullptr};napi_value result;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_valuetype valuetype0;napi_typeof(env, args[0], &valuetype0);int32_t videoMode;napi_get_value_int32(env, args[0], &videoMode);OH_LOG_INFO(LOG_APP, "IsVideoStabilizationModeSupportedFn videoMode : %{public}d", videoMode);ndkCamera_->IsVideoStabilizationModeSupportedFn(videoMode);napi_create_int32(env, argc, &result);return result;
}static napi_value InitCamera(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "InitCamera Start");size_t argc = 3;napi_value args[3] = {nullptr};napi_value result;size_t typeLen = 0;char *surfaceId = nullptr;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_get_value_string_utf8(env, args[0], nullptr, 0, &typeLen);surfaceId = new char[typeLen + 1];napi_get_value_string_utf8(env, args[0], surfaceId, typeLen + 1, &typeLen);napi_valuetype valuetype1;napi_typeof(env, args[1], &valuetype1);int32_t focusMode;napi_get_value_int32(env, args[1], &focusMode);uint32_t cameraDeviceIndex;napi_get_value_uint32(env, args[ARGS_TWO], &cameraDeviceIndex);OH_LOG_INFO(LOG_APP, "InitCamera focusMode : %{public}d", focusMode);OH_LOG_INFO(LOG_APP, "InitCamera surfaceId : %{public}s", surfaceId);OH_LOG_INFO(LOG_APP, "InitCamera cameraDeviceIndex : %{public}d", cameraDeviceIndex);if (ndkCamera_) {OH_LOG_INFO(LOG_APP, "ndkCamera_ is not null");delete ndkCamera_;ndkCamera_ = nullptr;}ndkCamera_ = new NDKCamera(surfaceId, focusMode, cameraDeviceIndex);OH_LOG_INFO(LOG_APP, "InitCamera End");napi_create_int32(env, argc, &result);return result;
}static napi_value ReleaseCamera(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "ReleaseCamera Start");size_t argc = 2;napi_value args[2] = {nullptr};napi_value result;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);ndkCamera_->ReleaseCamera();if (ndkCamera_) {OH_LOG_INFO(LOG_APP, "ndkCamera_ is not null");delete ndkCamera_;ndkCamera_ = nullptr;}OH_LOG_INFO(LOG_APP, "ReleaseCamera End");napi_create_int32(env, argc, &result);return result;
}
static napi_value ReleaseSession(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "ReleaseCamera Start");size_t argc = 2;napi_value args[2] = {nullptr};napi_value result;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);ndkCamera_->ReleaseSession();OH_LOG_INFO(LOG_APP, "ReleaseCamera End");napi_create_int32(env, argc, &result);return result;
}
static napi_value StartPhotoOrVideo(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "StartPhotoOrVideo Start");Camera_ErrorCode ret = CAMERA_OK;size_t argc = 3;napi_value args[3] = {nullptr};napi_value result;size_t typeLen = 0;size_t videoIdLen = 0;size_t photoIdLen = 0;char *modeFlag = nullptr;char *videoId = nullptr;char *photoId = nullptr;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_get_value_string_utf8(env, args[0], nullptr, 0, &typeLen);modeFlag = new char[typeLen + 1];napi_get_value_string_utf8(env, args[0], modeFlag, typeLen + 1, &typeLen);napi_get_value_string_utf8(env, args[1], nullptr, 0, &videoIdLen);videoId = new char[videoIdLen + 1];napi_get_value_string_utf8(env, args[1], videoId, videoIdLen + 1, &videoIdLen);napi_get_value_string_utf8(env, args[ARGS_TWO], nullptr, 0, &photoIdLen);photoId = new char[photoIdLen + 1];napi_get_value_string_utf8(env, args[ARGS_TWO], photoId, photoIdLen + 1, &photoIdLen);if (!strcmp(modeFlag, "photo")) {OH_LOG_INFO(LOG_APP, "StartPhoto surfaceId %{public}s", photoId);ret = ndkCamera_->StartPhoto(photoId);} else if (!strcmp(modeFlag, "video")) {ret = ndkCamera_->StartVideo(videoId, photoId);OH_LOG_INFO(LOG_APP, "StartPhotoOrVideo %{public}s, %{public}s", videoId, photoId);}napi_create_int32(env, ret, &result);return result;
}static napi_value VideoOutputStart(napi_env env, napi_callback_info info) {if (info == nullptr) {OH_LOG_ERROR(LOG_APP, "Info is nullptr.");}OH_LOG_INFO(LOG_APP, "VideoOutputStart Start");napi_value result;Camera_ErrorCode ret = ndkCamera_->VideoOutputStart();napi_create_int32(env, ret, &result);return result;
}static napi_value IsExposureModeSupported(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "IsExposureModeSupported exposureMode start.");size_t argc = 2;napi_value args[2] = {nullptr};napi_value result;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_valuetype valuetype0;napi_typeof(env, args[0], &valuetype0);int32_t exposureMode;napi_get_value_int32(env, args[0], &exposureMode);OH_LOG_INFO(LOG_APP, "IsExposureModeSupported exposureMode : %{public}d", exposureMode);ndkCamera_->IsExposureModeSupportedFn(exposureMode);OH_LOG_INFO(LOG_APP, "IsExposureModeSupported exposureMode end.");napi_create_int32(env, argc, &result);return result;
}static napi_value IsMeteringPoint(napi_env env, napi_callback_info info) {size_t argc = 2;napi_value args[2] = {nullptr};napi_value result;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_valuetype valuetype0;napi_typeof(env, args[0], &valuetype0);int x;napi_get_value_int32(env, args[0], &x);napi_typeof(env, args[0], &valuetype0);int y;napi_get_value_int32(env, args[1], &y);ndkCamera_->IsMeteringPoint(x, y);napi_create_int32(env, argc, &result);return result;
}static napi_value IsExposureBiasRange(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "IsExposureBiasRange start.");size_t argc = 2;napi_value args[2] = {nullptr};napi_value result;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_valuetype valuetype0;napi_typeof(env, args[0], &valuetype0);int exposureBiasValue;napi_get_value_int32(env, args[0], &exposureBiasValue);ndkCamera_->IsExposureBiasRange(exposureBiasValue);OH_LOG_INFO(LOG_APP, "IsExposureBiasRange end.");napi_create_int32(env, argc, &result);return result;
}static napi_value IsFocusModeSupported(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "IsFocusModeSupported start.");size_t argc = 2;napi_value args[2] = {nullptr};napi_value result;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_valuetype valuetype0;napi_typeof(env, args[0], &valuetype0);int32_t focusMode;napi_get_value_int32(env, args[0], &focusMode);OH_LOG_INFO(LOG_APP, "IsFocusModeSupportedFn videoMode : %{public}d", focusMode);ndkCamera_->IsFocusModeSupported(focusMode);OH_LOG_INFO(LOG_APP, "IsFocusModeSupported end.");napi_create_int32(env, argc, &result);return result;
}static napi_value IsFocusPoint(napi_env env, napi_callback_info info) {size_t argc = 2;napi_value args[2] = {nullptr};napi_value result;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_valuetype valuetype0;napi_typeof(env, args[0], &valuetype0);double x;napi_get_value_double(env, args[0], &x);napi_valuetype valuetype1;napi_typeof(env, args[1], &valuetype1);double y;napi_get_value_double(env, args[1], &y);float focusPointX = static_cast<float>(x);float focusPointY = static_cast<float>(y);ndkCamera_->IsFocusPoint(focusPointX, focusPointY);napi_create_int32(env, argc, &result);return result;
}static napi_value GetVideoFrameWidth(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "GetVideoFrameWidth Start");size_t argc = 1;napi_value args[1] = {nullptr};napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_value result = nullptr;napi_create_int32(env, ndkCamera_->GetVideoFrameWidth(), &result);OH_LOG_INFO(LOG_APP, "GetVideoFrameWidth End");return result;
}static napi_value GetVideoFrameHeight(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "GetVideoFrameHeight Start");size_t argc = 1;napi_value args[1] = {nullptr};napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_value result = nullptr;napi_create_int32(env, ndkCamera_->GetVideoFrameHeight(), &result);OH_LOG_INFO(LOG_APP, "GetVideoFrameHeight End");return result;
}static napi_value GetVideoFrameRate(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "GetVideoFrameRate Start");size_t argc = 1;napi_value args[1] = {nullptr};napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_value result = nullptr;napi_create_int32(env, ndkCamera_->GetVideoFrameRate(), &result);OH_LOG_INFO(LOG_APP, "GetVideoFrameRate End");return result;
}static napi_value VideoOutputStopAndRelease(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "VideoOutputStopAndRelease Start");size_t argc = 1;napi_value args[1] = {nullptr};napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);napi_value result = nullptr;ndkCamera_->VideoOutputStop();ndkCamera_->VideoOutputRelease();OH_LOG_INFO(LOG_APP, "VideoOutputStopAndRelease End");napi_create_int32(env, argc, &result);return result;
}static napi_value TakePicture(napi_env env, napi_callback_info info) {if (info == nullptr) {OH_LOG_ERROR(LOG_APP, "Info is nullptr.");}OH_LOG_INFO(LOG_APP, "TakePicture Start");napi_value result;Camera_ErrorCode ret = ndkCamera_->TakePicture();OH_LOG_INFO(LOG_APP, "TakePicture result is %{public}d", ret);napi_create_int32(env, ret, &result);return result;
}static napi_value GetCaptureParam(napi_env env, napi_value captureConfigValue, Capture_Setting *config) {napi_value value = nullptr;napi_get_named_property(env, captureConfigValue, "quality", &value);napi_get_value_int32(env, value, &config->quality);napi_get_named_property(env, captureConfigValue, "rotation", &value);napi_get_value_int32(env, value, &config->rotation);napi_get_named_property(env, captureConfigValue, "mirror", &value);napi_get_value_bool(env, value, &config->mirror);napi_get_named_property(env, captureConfigValue, "latitude", &value);napi_get_value_int32(env, value, &config->latitude);napi_get_named_property(env, captureConfigValue, "longitude", &value);napi_get_value_int32(env, value, &config->longitude);napi_get_named_property(env, captureConfigValue, "altitude", &value);napi_get_value_int32(env, value, &config->altitude);OH_LOG_INFO(LOG_APP,"get quality %{public}d, rotation %{public}d, mirror %{public}d, latitude ""%{public}d, longitude %{public}d, altitude %{public}d",config->quality, config->rotation, config->mirror, config->latitude, config->longitude,config->altitude);return 0;
}
static void SetConfig(Capture_Setting settings, Camera_PhotoCaptureSetting *photoSetting, Camera_Location *location) {if (photoSetting == nullptr || location == nullptr) {OH_LOG_INFO(LOG_APP, "photoSetting is null");}photoSetting->quality = static_cast<Camera_QualityLevel>(settings.quality);photoSetting->rotation = static_cast<Camera_ImageRotation>(settings.rotation);photoSetting->mirror = settings.mirror;location->altitude = settings.altitude;location->latitude = settings.latitude;location->longitude = settings.longitude;photoSetting->location = location;
}static napi_value TakePictureWithSettings(napi_env env, napi_callback_info info) {OH_LOG_INFO(LOG_APP, "TakePictureWithSettings Start");size_t argc = 1;napi_value args[1] = {nullptr};Camera_PhotoCaptureSetting photoSetting;Capture_Setting setting_inner;Camera_Location *location = new Camera_Location;napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);GetCaptureParam(env, args[0], &setting_inner);SetConfig(setting_inner, &photoSetting, location);napi_value result;Camera_ErrorCode ret = ndkCamera_->TakePictureWithPhotoSettings(photoSetting);OH_LOG_INFO(LOG_APP, "TakePictureWithSettings result is %{public}d", ret);napi_create_int32(env, ret, &result);return result;
}EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {napi_property_descriptor desc[] = {{"initCamera", nullptr, InitCamera, nullptr, nullptr, nullptr, napi_default, nullptr},{"startPhotoOrVideo", nullptr, StartPhotoOrVideo, nullptr, nullptr, nullptr, napi_default, nullptr},{"videoOutputStart", nullptr, VideoOutputStart, nullptr, nullptr, nullptr, napi_default, nullptr},{"setZoomRatio", nullptr, SetZoomRatio, nullptr, nullptr, nullptr, napi_default, nullptr},{"hasFlash", nullptr, HasFlash, nullptr, nullptr, nullptr, napi_default, nullptr},{"isVideoStabilizationModeSupported", nullptr, IsVideoStabilizationModeSupported, nullptr, nullptr, nullptr,napi_default, nullptr},{"isExposureModeSupported", nullptr, IsExposureModeSupported, nullptr, nullptr, nullptr, napi_default, nullptr},{"isMeteringPoint", nullptr, IsMeteringPoint, nullptr, nullptr, nullptr, napi_default, nullptr},{"isExposureBiasRange", nullptr, IsExposureBiasRange, nullptr, nullptr, nullptr, napi_default, nullptr},{"IsFocusModeSupported", nullptr, IsFocusModeSupported, nullptr, nullptr, nullptr, napi_default, nullptr},{"isFocusPoint", nullptr, IsFocusPoint, nullptr, nullptr, nullptr, napi_default, nullptr},{"getVideoFrameWidth", nullptr, GetVideoFrameWidth, nullptr, nullptr, nullptr, napi_default, nullptr},{"getVideoFrameHeight", nullptr, GetVideoFrameHeight, nullptr, nullptr, nullptr, napi_default, nullptr},{"getVideoFrameRate", nullptr, GetVideoFrameRate, nullptr, nullptr, nullptr, napi_default, nullptr},{"videoOutputStopAndRelease", nullptr, VideoOutputStopAndRelease, nullptr, nullptr, nullptr, napi_default,nullptr},{"takePicture", nullptr, TakePicture, nullptr, nullptr, nullptr, napi_default, nullptr},{"takePictureWithSettings", nullptr, TakePictureWithSettings, nullptr, nullptr, nullptr, napi_default, nullptr},{"releaseSession", nullptr, ReleaseSession, nullptr, nullptr, nullptr, napi_default, nullptr},{"releaseCamera", nullptr, ReleaseCamera, nullptr, nullptr, nullptr, napi_default, nullptr}};napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);return exports;
}
EXTERN_C_ENDstatic napi_module demoModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = Init,.nm_modname = "entry",.nm_priv = ((void *)0),.reserved = {0},
};extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
  • 预览:开启预览位于Index.ets下的onPageShow接口,其中调用cameraDemo.initCamera接口,将预览的surfaceId,对焦模式的值,以及是前置还是后置摄像头设备作为入参啊传下去,实际调用的是main.cpp下的InitCamera接口,InitCamera接口将JS侧拿到的参数进行转换再传入cameraManager.cpp中的构造函数里去,完成开启相机的操作,开启预览并设置好对焦模式。

    • 拍照和录像:开启拍照位于ModeSwitchPage.ets下的isVideoPhotoFn接口,通过判断modelBagCol的值是photo还是video,将modelBagCol的值,videoId,拍照的surfaceID或者录像的surfaceId传入接口startPhotoOrVideo。如果是拍照模式,则通过modeSwitchPage.ets下的getPhotoSurfaceID接口获取photo surfaceId,跳转到main.cpp中的StartPhotoOrVideo接口,将传下来的参数进行格式转换,再调用CameraManager对象下的StartPhoto接口开启拍照操作;如果是录像模式,则通过modeSwitchPage.ets下的getVideoSurfaceID接口获取video surfaceId,跳转到main.cpp中的StartPhotoOrVideo接口,将传下来的参数进行格式转换,再调用CameraManager对象下的StartVideo接口开启录像操作
    • 前后置切换:前后置摄像头切换接口位于ModeSwitchPage.ets,切换cameraDeviceIndex,将先前的session配置释放,调用cameraDemo.releaseSession接口,实际上是main.cpp下的ReleaseSession接口,最终调用到CameraMangaer.cpp下的ReleaseSession接口。然后将预览的surfaceId,对焦模式的值以及cameraDeviceIndex传入cameraDemo.initCamera接口中,逻辑和预览一致。
  • 相机对焦、曝光功能实现调用侧位于FocusAreaPage.ets中,源码参考:[FocusAreaPage.ets]

/** Copyright (c) 2024 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import cameraDemo from 'libentry.so';
import Logger from '../common/utils/Logger';
import { Constants } from '../common/Constants'const TAG: string = 'FocusAreaPage';// Focus Area.
@Component
export struct FocusAreaPage {@Link focusPointBol: boolean;@Link focusPointVal: Array<number>;// Display where scale, focal length value, and focus box cannot coexist.@Link exposureBol: boolean;// Exposure value.@Link exposureNum: number;@Prop xComponentWidth: number;@Prop xComponentHeight: number;// Focusing area display box timer.private areaTimer: number = -1;// Sliding Exposure Up and Down.private panOption: PanGestureOptions = new PanGestureOptions({direction: PanDirection.Up | PanDirection.Down,fingers: 1});build() {Row() {}.width(Constants.FULL_PERCENT).height(Constants.SEVENTY_PERCENT).margin({bottom: Constants.FIFTEEN_PERCENT}).opacity(1).id('FocusArea').onTouch((e: TouchEvent) => {if (e.type === TouchType.Down) {this.focusPointBol = true;this.focusPointVal[0] = e.touches[0].windowX;this.focusPointVal[1] = e.touches[0].windowY;// Focus point.cameraDemo.isFocusPoint(e.touches[0].windowX / this.xComponentWidth,e.touches[0].windowY / this.xComponentHeight);cameraDemo.isMeteringPoint(e.touches[0].windowX / this.xComponentWidth,e.touches[0].windowY / this.xComponentHeight + 50);}if (e.type === TouchType.Up) {if (this.areaTimer) {clearTimeout(this.areaTimer);}this.areaTimer = setTimeout(() => {this.focusPointBol = false;}, 3500);}})// Trigger this gesture event by dragging vertically with one finger..gesture(PanGesture(this.panOption).onActionStart(() => {Logger.info(TAG, 'PanGesture onActionStart');this.exposureBol = false;}).onActionUpdate((event: GestureEvent) => {let offset = -event.offsetY;if (offset > Constants.EVENT_Y_OFFSET) {this.exposureNum = 4;}if (offset < Constants.EVENT_Y_OFFSET1) {this.exposureNum = -4;}if (offset > Constants.EVENT_Y_OFFSET1 && offset < Constants.EVENT_Y_OFFSET) {this.exposureNum = Number((offset / 50).toFixed(1));}// Exposure Compensation -4 +4.cameraDemo.isExposureBiasRange(this.exposureNum);Logger.info(TAG, `PanGesture onActionUpdate offset: ${offset}, exposureNum: ${this.exposureNum}`);}).onActionEnd(() => {this.exposureNum = 0;this.exposureBol = true;Logger.info(TAG, 'PanGesture onActionEnd end');}))}
}
  • 对焦:对焦功能位于FocusAreaPage.ets,通过在build中将对焦焦点下发到cpp侧,在CameraManager.cpp文件中的SessionFlowFn函数中,会调用IsFocusMode接口来判断是否支持对焦模式,然后通过onTouch的方式将对焦点位通过cameraDemo.isFocusPoint接口下发到main.cpp侧的IsFocusPoint接口,最终调到CameraManager.cpp中的IsFocusPoint接口。以及调用OH_CaptureSession_SetFocusMode拿到对焦点位来设置对焦模式,最后调用OH_CaptureSession_GetFocusMode来获取对焦模式,完成对焦功能实现。
  • 曝光:曝光功能位于FocusAreaPage.ets,通过在build中将侧光点位下发到cpp侧,然后通过onTouch的方式将对焦点位以及侧光点位通过cameraDemo.isFocusPoint接口下发到main.cpp侧的isMeteringPoint接口,最终调到CameraManager.cpp中的IsMeteringPoint接口。然后设置曝光补偿,单指竖直方向拖动触发该手势事件,调用gesture中的cameraDemo.isExposureBiasRange接口将曝光值下发到main.cpp中的IsExposureBiasRange,然后经过napi转换后将值传到CameraManager.cpp中的IsExposureBiasRange接口,之后从native侧发到曝光补偿的范围,再调用OH_CaptureSession_SetExposureBias设置曝光值,最后调用OH_CaptureSession_GetExposureBias接口获取曝光值,完成曝光功能。

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
1

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

在这里插入图片描述

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

http://www.lryc.cn/news/415035.html

相关文章:

  • 【java基础】徒手写Hello, World!程序
  • 对 vllm 与 ollama 的一些研究
  • 浅谈基础的图算法——强联通分量算法(c++)
  • C#:通用方法总结—第13集
  • AI答题应用平台相关面试题
  • 树莓派NAS系统搭建教程:使用Flask和SQLite实现HTTP/HTTPS文件管理(代码示例)
  • mysql如何储存大量数据,分库存分表的建议和看法
  • Golang | Leetcode Golang题解之第310题最小高度树
  • 【面试系列】软件架构师 高频面试题及详细解答
  • 二百五十四、OceanBase——Linux上安装OceanBase数据库(四):登录ocp-express,配置租户管理等信息
  • HCIP学习作业一 | HCIA复习
  • OCR图片矫正、表格检测及裁剪综合实践
  • c++ 容器 vector
  • 零基础部署Minecraft到云服务器上教程
  • 常见cms漏洞之dedecms
  • 深入探究Liunx服务器内存:模拟程序实际占用与缓存占用内存
  • 《Milvus Cloud向量数据库指南》——Zilliz Cloud 高可用性深度解析:赋能GenAI应用,引领非结构化数据新纪元
  • 2024/8/4 维高-STD60N驱动器(伺服)---客户反馈:电机异响
  • 驾驭RESTful海洋:在PyCharm中配置和使用REST客户端全攻略
  • 策略模式的一次应用
  • 探索PyCharm的C/C++支持:一站式配置指南
  • 手机三要素接口怎么对接呢?(一)
  • 状态同步帧同步
  • Flink 开发语言选择 —— Java vs Scala
  • 如何在 Apache Web 服务器中安装、配置和使用模块
  • 海信聚好看的DBDocter软件使用心得
  • dfs深搜
  • 【React】详解 index.js 文件
  • Android NDK/JNI面试题大全及参考答案(3万字长文)
  • 从根儿上学习spring一 之杂谈