【HarmonyOS NEXT】FAQ之媒体开发(相机开发)

1、使用XComponent组件显示相机的预览输出流时,如何获取相机的帧数据

A:通过创建双路预览来实现。

  1. Xcomponent来创建预览流。

  2. 使用imageReceiver来监听图像信息。

2、如何获取前置摄像头的预览图像

A:示例代码如下

import { BusinessError } from '@kit.BasicServicesKit'; 
import { camera } from '@kit.CameraKit'; 
import { common } from '@kit.AbilityKit'; 
const context = getContext(this) as common.UIAbilityContext; 
@Entry 
@Component 
struct GetFrontCameraImage { 
  private xComponentController: XComponentController = new XComponentController(); 
  async getCameraImage() { 
    // 1、使用系统相机框架camera模块获取物理摄像头信息。 
    let cameraManager = camera.getCameraManager(context); 
    let camerasInfo: Array<camera.CameraDevice> = cameraManager.getSupportedCameras(); 
    let cameraDevice: camera.CameraDevice = camerasInfo[0]; 
    // 检测相机状态 
    cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => { 
      console.log(`camera : ${cameraStatusInfo.camera.cameraId}`); 
      console.log(`status : : ${cameraStatusInfo.status}`); 
    }); 
    // 2、创建并启动物理摄像头输入流通道 
    // 设置为前置摄像头 camera.CameraPosition.CAMERA_POSITION_FRONT 
    let cameraInput = cameraManager.createCameraInput(camera.CameraPosition.CAMERA_POSITION_FRONT, camera.CameraType.CAMERA_TYPE_DEFAULT); 
    await cameraInput.open(); 
    // 3、拿到物理摄像头信息查询摄像头支持预览流支持的输出格式,结合XComponent提供的surfaceId创建预览输出通道 
    let outputCapability = cameraManager.getSupportedOutputCapability(cameraDevice, camera.SceneMode.NORMAL_PHOTO); 
    let previewProfile = outputCapability.previewProfiles[0]; 
    let surfaceId = this.xComponentController.getXComponentSurfaceId(); 
    let previewOutput = cameraManager.createPreviewOutput(previewProfile, surfaceId); 
    // 4、创建相机会话,在会话中添加摄像头输入流和预览输出流,然后启动会话,预览画面就会在XComponent组件上送显。 
    let captureSession = cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO); 
    captureSession.beginConfig(); 
    captureSession.addInput(cameraInput); 
    captureSession.addOutput(previewOutput); 
    captureSession.commitConfig() 
    captureSession.start(); 
  } 
  build() { 
    Row() { 
      Column({ space: 20 }) { 
        XComponent({ id: 'xComponentId1', type: 'surface', controller: this.xComponentController }) 
          .height(300) 
        Button('打开摄像头') 
          .onClick(() => { 
            // 在调用前确保已经获得相机权限 
            this.getCameraImage(); 
          }) 
      } 
      .width('100%') 
    } 
    .height('100%') 
  } 
}

3、如何设置相机焦距

A:步骤如下

  1. 判断当前摄像头是否为前置摄像头,前置摄像头不支持设置焦距。

  2. 通过getZoomRatioRange()接口获取设备焦距设置支持的最大、最小范围。

  3. 判断目标焦距参数大小是否在步骤二获取的范围内,然后通过setZoomRatio()接口设置相机焦距。

4、如何检测当前相机服务的状态

A:通过cameraManager设置状态回调返回相机状态。

import { camera } from '@kit.CameraKit'; 
import { BusinessError } from '@kit.BasicServicesKit'; 
 
let cameraManager = camera.getCameraManager(getContext(this)); 
cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => { 
  console.log(`camera : ${cameraStatusInfo.camera.cameraId}`); 
  console.log(`status: ${cameraStatusInfo.status}`); 
});

相机状态:CameraStatus

枚举,相机状态。

CAMERA_STATUS_APPEAR 0 新的相机出现。

CAMERA_STATUS_DISAPPEAR 1 相机被移除。

CAMERA_STATUS_AVAILABLE 2 相机可用。

CAMERA_STATUS_UNAVAILABLE 3 相机不可用。

5、相机是否支持HDR模式的采集

A:支持HDR模式,采用的是HDR vivid标准。

6、如何读取相机的预览图

A:开发步骤如下:

  1. 导入image接口。

创建双路预览流的SurfaceId,除XComponent组件的SurfaceId外,还需要使用ImageReceiver组件创建生成的SurfaceId,需要使用image模块提供的接口。

  1. 创建ImageReceiver组件Surface。

  2. 创建XComponent组件Surface。

  3. 实现双路预览。

  4. 通过ImageReceiver实时获取预览图像。

7、如何保证相机在全屏预览时不变形

A:需要获取手机的宽高比,用手机的屏幕的height/width去和支持的预览尺寸的width/height去取最贴近的值。预览流与录像输出流的分辨率的宽高比要保持一致,如示例代码中宽高比为1920:1080 = 16:9,则需要预览流中的分辨率的宽高比也为16:9,如分辨率选择640:360,或960:540,或1920:1080,以此类推。

8、相机预览切后台再回来画面不正确

A:切换后台再切回来,必须要重新初始化相机才可以。因为切后台,相机资源是全部回收的。

9、如何实现相机关闭

A:实现相机关闭参考代码如下:

// 停止当前会话   photoSession.stop();  
// 释放相机输入流   cameraInput.close();  
// 释放预览输出流   previewOutput.release();  
// 释放拍照输出流   photoOutput.release();  
// 释放会话   photoSession.release();  
// 会话置空   photoSession = undefined;

10、预览流黑屏但无报错信息该怎么解决

A:未正确获取相机权限,就进行初始化相机、获取相机输入流等操作。应用切换至后台后切回,相机资源被回收后,没有重新获取权限开启预览导致。设置的预览流尺寸不支持。

  • 确保初始化相机、获取相机输入流等操作之前先正确获取相机权限。

  • 因为当应用被切换到后台后,相机资源会被全部回收,所以为了避免出现前后台切换后预览流黑屏的问题,需在onPageShow中进行重新创建会话、配置会话、启动等操作,并在onPageHide中对相机资源进行销毁。

  • 可先获取相机设备支持的输出流能力,得到支持的预览尺寸。

11、调用API方法camera.getCameraManager传入context报错如何解决

A:该问题是由不兼容修改引起的。之前用的是FA模型的context,现在应用都是Stage模型的,所以有app/Context和application/Context的变化,可使用getContext() as common.BaseContext获取需要的context。

12、如何避免预览流产生畸变

A:使用下列代码获取设备支持的宽和高,然后根据手机屏幕的宽高设置最合适的预览流分辨率,并且使得surface和XComponent的宽高相同。

//预览流与录像输出流的分辨率的宽高比要保持一致 
let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles; 
 
let position: number = 0; 
if (previewProfilesArray != null) { 
  previewProfilesArray.forEach((value: camera.Profile, index: number) => { 
    // 查看支持的预览尺寸 
    console.info(TAG, `支持的预览尺寸: [${value.size.width},${value.size.height},${value.size.width / value.size.height}]`); 
    if (value.size.width === 2592 && value.size.height === 1200) { 
      position = index; 
    } 
  }) 
} else { 
  console.error(TAG, "createOutput photoProfilesArray == null || undefined"); 
} 
// DocsCode 2 
 
let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles; 
if (!photoProfilesArray) { 
  console.error(TAG, "createOutput photoProfilesArray == null || undefined"); 
} 
 
this.xComponentWidth = previewProfilesArray[position].size.width; 
this.xComponentHeight = previewProfilesArray[position].size.height; 
 
this.mXComponentController.setXComponentSurfaceSize({ 
  surfaceWidth: this.xComponentWidth, 
  surfaceHeight: this.xComponentHeight 
}); 
// 创建预览输出流,其中参数 surfaceId 参考上文 XComponent 组件,预览流为XComponent组件提供的surface 
try { 
  previewOutput = cameraManager.createPreviewOutput(previewProfilesArray[position], surfaceId); 
} catch (error) { 
  let err = error as BusinessError; 
  console.error(TAG, `Failed to create the PreviewOutput instance. error code: ${err.code}`); 
} 
if (previewOutput === undefined) { 
  return; 
} 
 
// 监听预览输出错误信息 
previewOutput.on('error', (error: BusinessError) => { 
  console.error(TAG, `Preview output error code: ${error.code}`); 
}); 
 
// 创建ImageReceiver对象,并设置照片参数:分辨率大小是根据前面 photoProfilesArray 获取的当前设备所支持的拍照分辨率大小去设置 
let size: image.Size = { 
  height: 1200, 
  width: 2592 
} 
let imageReceiver: image.ImageReceiver = image.createImageReceiver(size, 4, 8);

13、如何开关闪光灯

A:使用isFlashModeSupported方法检测设备是否支持需要设置的闪光灯模式后,使用setFlashMode设置闪光灯模式。

14、如何调用系统拍照并获取图片

A:可参考如下代码,拉起系统拍照页面并获取图片uri:

@State imagePathSrc: String = ''; 
context:common.UIAbilityContext | undefined = (getContext(this) as common.UIAbilityContext); 
savePath: string = getContext().filesDir; 
 
async thirdPartyCall(supportMultiMode: boolean): Promise<common.AbilityResult | undefined> { 
  console.log("thirdPartyCall savaPath=" + this.savePath) // ohos.want.action.imageCapture 
  // 拉起拍照功能 
  let want: Want = { 
    "action": 'ohos.want.action.imageCapture', 
    "parameters": { 
      supportMultiMode: supportMultiMode, 
      callBundleName: "com.example.systemcapturegetphoto" 
    } 
  }; 
  // 获取图片uri 
  if (this.context) { 
    let result: common.AbilityResult = await this.context.startAbilityForResult(want); 
    let params = result?.want?.parameters as Record<string, string | number> 
    this.imagePathSrc = params?.resourceUri as string; 
    console.info('Operation imagePathSrc= ' + this.imagePathSrc); 
  } 
  return undefined; 
}

15、视频的SPS/PPS需要单独传递给解码器吗

A:AVC视频中的SPS/PPS需要通过queueInputBuffer提交。

16、视频流支持哪些格式

A:ts层无其他格式, 这些字节数据可以转成pixelMap,经过编码后可以转成JPEG、WebP 和 png 格式(目前支持这三种)。

17、视频预览分辨率设置

问题现象

旋转手机,预览画面中同一个物品高度会发生明显变化,画面畸变。代码中的预览分辨率:previewProfile {"format":1003,"size":{"width":3200,"height":2400}},XComponent的surfaceWidth: 3200, surfaceHeight: 2400。

XComponent({ 
  id: 'componentId', 
  type: 'surface', 
  controller: this.mXComponentController, 
}).onLoad(async () => { 
  this.surfaceId = this.mXComponentController.getXComponentSurfaceId(); 
  let baseContext = getContext() as common.BaseContext; 
  await this.initCamera(baseContext, this.surfaceId) 
}).width('100%') 
  .height('100%')

A:上面代码 .width('100%').height('100%') 这两个值不要都设置成100%, 保证width和height的比例与previewProfile的height与width比例一致。

18、如何连续获取相机预览流数据

A:使用双路预览获取连续数据,设置previewOutput2接收连续数据。

20、如何获取相机原始yuv数据流

A:初始化相机类,传入xcomponent组件的id作为参数,使用双路预览绑定ImageReceiver接收相机原始数据流并保存为yuv形式,实例代码链接:文档中心

21、如何调用相机开放的接口,拍照并获取拍照的图片uri

A:

  • 在模块级module.json5中申明权限

  • 获取权限

  • 创建拍摄和预览页面

  • 创建camera类完成相机初始化、拍摄和获取图片uri并存储

22、YUV数据相关格式

A:目前相机给出的YUV数据是8bit位深的,采用的是BT709色域。

相机有HDR模式,采用的是HDR vivid标准;返回10bit位深的YUV数据,使用的是BT2020色域。

更多详情及参考代码查看如下:文档中心

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值