录像实现,如何自定义录像功能的实现

​录像实现

HarmonyOS
2024-05-28 20:07:03
浏览
收藏 0
回答 1
回答 1
按赞同
/
按时间
放大电路

本文主要介绍自定义录像功能的实现

相关核心API

相机管理

媒体服务

核心代码介绍

初始化相机

async initCamera(baseContext: ESObject, surfaceId: string) { 
  cameraManager = camera.getCameraManager(baseContext); 
  if (!cameraManager) { 
    Logger.error(TAG, "camera.getCameraManager error"); 
    return; 
  } 
 
  //监听照相机状态变化 
  cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => { 
    Logger.info(TAG, `camera : ${cameraStatusInfo.camera.cameraId}`); 
    Logger.info(TAG, `status: ${cameraStatusInfo.status}`); 
  }); 
 
  // 获取相机列表 
  let cameraArray: Array<camera.CameraDevice> = cameraManager.getSupportedCameras(); 
  if (cameraArray.length <= 0) { 
    Logger.error(TAG, "cameraManager.getSupportedCameras error"); 
    return; 
  } 
 
  for (let index = 0; index < cameraArray.length; index++) { 
    Logger.info(TAG, 'cameraId : ' + cameraArray[index].cameraId); // 获取相机ID 
    Logger.info(TAG, 'cameraPosition : ' + cameraArray[index].cameraPosition); // 获取相机位置 
    Logger.info(TAG, 'cameraType : ' + cameraArray[index].cameraType); // 获取相机类型 
    Logger.info(TAG, 'connectionType : ' + cameraArray[index].connectionType); // 获取相机连接类型 
  } 
 
  // 获取相机设备支持的输出流能力 
  let cameraOutputCap: camera.CameraOutputCapability = cameraManager.getSupportedOutputCapability(cameraArray[0]); 
  if (!cameraOutputCap) { 
    Logger.error(TAG, "cameraManager.getSupportedOutputCapability error"); 
    return; 
  } 
  Logger.info(TAG, "outputCapability: " + JSON.stringify(cameraOutputCap)); 
 
  //预览流与录像输出流的分辨率的宽高比要保持一致 
  let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles; 
 
  let position: number = 0; 
  if (previewProfilesArray != null) { 
    previewProfilesArray.forEach((value: camera.Profile, index: number) => { 
      Logger.info(TAG, `支持的预览尺寸: [${value.size.width},${value.size.height}]`); 
      if (value.size.width === 1920 && value.size.height === 1080) { 
        position = index; 
      } 
    }) 
  } else { 
    Logger.error(TAG, "createOutput photoProfilesArray == null || undefined"); 
  } 
 
  let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles; 
  if (!photoProfilesArray) { 
    Logger.error(TAG, "createOutput photoProfilesArray == null || undefined"); 
  } 
 
  this.xComponentWidth = previewProfilesArray[position].size.width; 
  this.xComponentHeight = previewProfilesArray[position].size.height; 
 
  this.mXComponentController.setXComponentSurfaceSize({ 
    surfaceWidth: previewProfilesArray[position].size.width, 
    surfaceHeight: previewProfilesArray[position].size.height 
  }); 
 
  let videoProfilesArray: Array<camera.VideoProfile> = cameraOutputCap.videoProfiles; 
  if (!videoProfilesArray) { 
    console.error("createOutput videoProfilesArray == null || undefined"); 
  } 
 
  let metadataObjectTypesArray: Array<camera.MetadataObjectType> = cameraOutputCap.supportedMetadataObjectTypes; 
  if (!metadataObjectTypesArray) { 
    console.error("createOutput metadataObjectTypesArray == null || undefined"); 
  }
// videoProfile的宽高需要与AVRecorderProfile的宽高保持一致,并且需要使用AVRecorderProfile锁支持的宽高 
let videoSize: camera.Size = { 
  width: 640, 
  height: 480 
} 
let videoProfile: undefined | camera.VideoProfile = videoProfilesArray.find((profile: camera.VideoProfile) => { 
  return profile.size.width === videoSize.width && profile.size.height === videoSize.height; 
}); 
 
if (!videoProfile) { 
  console.error('videoProfile is not found'); 
  return; 
} 
 
// 配置参数以实际硬件设备支持的范围为准 
let aVRecorderProfile: media.AVRecorderProfile = { 
  audioBitrate: 48000, 
  audioChannels: 2, 
  audioCodec: media.CodecMimeType.AUDIO_AAC, 
  audioSampleRate: 48000, 
  fileFormat: media.ContainerFormatType.CFT_MPEG_4, 
  videoBitrate: 2000000, 
  videoCodec: media.CodecMimeType.VIDEO_MPEG4, 
  videoFrameWidth: videoSize.width, 
  videoFrameHeight: videoSize.height, 
  videoFrameRate: 30 
};
 let aVRecorderConfig: media.AVRecorderConfig = { 
    audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, 
    videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, 
    profile: aVRecorderProfile, 
    url: this.url, // 文件需先由调用者创建,赋予读写权限,将文件fd传给此参数,eg.fd://45--file:///data/media/01.mp4 
    rotation: 0, // 合理值0、90、180、270,非合理值prepare接口将报错 
    location: { latitude: 30, longitude: 130 } 
  }; 
  try { 
    avRecorder = await media.createAVRecorder(); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`createAVRecorder call failed. error code: ${err.code}`); 
  } 
 
  if (avRecorder === undefined) { 
    return; 
  } 
 
  try { 
    await avRecorder.prepare(aVRecorderConfig); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`prepare call failed. error code: ${err.code}`); 
  } 
  let videoSurfaceId: string | undefined = undefined; // 该surfaceID用于传递给相机接口创造videoOutput 
  try { 
    videoSurfaceId = await avRecorder.getInputSurface(); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`getInputSurface call failed. error code: ${err.code}`); 
  } 
  if (videoSurfaceId === undefined) { 
    return; 
  } 
  // 创建VideoOutput对象 
  try { 
    videoOutput = cameraManager.createVideoOutput(videoProfilesArray[0], videoSurfaceId); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`Failed to create the videoOutput instance. error: ${JSON.stringify(err)}`); 
  } 
  if (videoOutput === undefined) { 
    return; 
  } 
  // 监听视频输出错误信息 
  videoOutput.on('error', (error: BusinessError) => { 
    console.log(`Preview output error code: ${error.code}`); 
  }); 
  //创建会话 
  try { 
    captureSession = cameraManager.createCaptureSession(); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error('Failed to create the CaptureSession instance. errorCode = ' + err.code); 
  } 
  if (captureSession === undefined) { 
    return; 
  } 
  // 监听session错误信息 
  captureSession.on('error', (error: BusinessError) => { 
    Logger.error(TAG, `Capture session error code: ${error.code}`); 
  }); 
  // 开始配置会话 
  try { 
    captureSession.beginConfig(); 
  } catch (error) { 
    let err = error as BusinessError; 
    Logger.error(TAG, 'Failed to beginConfig. errorCode = ' + err.code); 
  } 
  // 创建相机输入流 
  let cameraInput: camera.CameraInput | undefined = undefined; 
  try { 
    cameraInput = cameraManager.createCameraInput(cameraArray[0]); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`Failed to createCameraInput. error: ${JSON.stringify(err)}`); 
  } 
  if (cameraInput === undefined) { 
    return; 
  } 
  // 监听cameraInput错误信息 
  let cameraDevice: camera.CameraDevice = cameraArray[0]; 
  cameraInput.on('error', cameraDevice, (error: BusinessError) => { 
    console.log(`Camera input error code: ${error.code}`); 
  }); 
  // 打开相机 
  try { 
    await cameraInput.open(); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`Failed to open cameraInput. error: ${JSON.stringify(err)}`); 
  } 
  // 向会话中添加相机输入流 
  try { 
    captureSession.addInput(cameraInput); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`Failed to add cameraInput. error: ${JSON.stringify(err)}`); 
  } 
  // 创建预览输出流,其中参数 surfaceId 参考下面 XComponent 组件,预览流为XComponent组件提供的surface 
  let previewOutput: camera.PreviewOutput | undefined = undefined; 
  try { 
    previewOutput = cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`Failed to create the PreviewOutput instance. error: ${JSON.stringify(err)}`); 
  } 
  if (previewOutput === undefined) { 
    return; 
  } 
  // 向会话中添加预览输入流 
  try { 
    captureSession.addOutput(previewOutput); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`Failed to add previewOutput. error: ${JSON.stringify(err)}`); 
  } 
  // 向会话中添加录像输出流 
  try { 
    captureSession.addOutput(videoOutput); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`Failed to add videoOutput. error: ${JSON.stringify(err)}`); 
  } 
  // 提交会话配置 
  try { 
    await captureSession.commitConfig(); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`captureSession commitConfig error: ${JSON.stringify(err)}`); 
  } 
  // 启动会话 
  try { 
    await captureSession.start(); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`captureSession start error: ${JSON.stringify(err)}`); 
  } 
  // 启动录像输出流 
  videoOutput.start((err: BusinessError) => { 
    if (err) { 
      console.error(`Failed to start the video output. error: ${JSON.stringify(err)}`); 
      return; 
    } 
    console.log('Callback invoked to indicate the video output start success.'); 
  }); 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.
  • 210.
  • 211.
  • 212.
  • 213.
  • 214.
  • 215.
  • 216.
  • 217.
  • 218.
  • 219.
  • 220.
  • 221.
  • 222.
  • 223.
  • 224.
  • 225.
  • 226.
  • 227.
  • 228.
  • 229.
  • 230.
  • 231.
  • 232.
  • 233.
  • 234.
  • 235.
  • 236.
  • 237.
  • 238.
  • 239.
  • 240.
  • 241.
  • 242.
  • 243.
  • 244.
  • 245.
  • 246.
  • 247.

开始录制

async startRecord() { 
  console.log(avRecorder.state) 
  // 开始录像 
  try { 
    avRecorder.start(); 
  } catch (error) { 
    let err = error as BusinessError; 
    console.error(`avRecorder start error: ${JSON.stringify(err)}`); 
  } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

停止录制

async stopRecord() { 
  // 停止录像 
  try { 
    // 停止录像输出流 
    videoOutput.stop((err: BusinessError) => { 
      if (err) { 
        console.error(`Failed to stop the video output. error: ${JSON.stringify(err)}`); 
        return; 
      } 
      console.log('Callback invoked to indicate the video output stop success.'); 
    }); 
    // 停止录像 
    try { 
      await avRecorder.stop(); 
     await this.avRecorder.release(); 
 
    } catch (error) { 
      let err = error as BusinessError; 
      console.error(`avRecorder stop error: ${JSON.stringify(err)}`); 
      console.log("失败") 
    } 
  } catch (error) { 
    let err = error as BusinessError; 
    Logger.error(TAG, `avRecorder stop error: ${JSON.stringify(err)}`); 
  } 
  // 停止当前会话 
  captureSession.stop(); 
  // 释放相机输入流 
  cameraInput.close(); 
  // 释放预览输出流 
  previewOutput.release(); 
  // 释放录像输出流 
  videoOutput.release(); 
  // 释放会话 
  captureSession.release(); 
  this.isFinished = true; 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.

申请权限

"requestPermissions": [ 
  { 
    "name": "ohos.permission.CAMERA" 
  }, 
  { 
    "name": "ohos.permission.MICROPHONE" 
  }, 
  { 
    "name": "ohos.permission.MEDIA_LOCATION" 
  }, 
  { 
    "name": "ohos.permission.WRITE_MEDIA" 
  }, 
  { 
    "name": "ohos.permission.READ_MEDIA" 
  } 
]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

实现效果

适配版本信息

·IDE:DevEco Studio 4.0.1.501

·SDK:HarmoneyOS 4.0.0.38

分享
微博
QQ
微信
回复
2024-05-29 20:25:12


相关问题
HarmonyOS 录像问题咨询
938浏览 • 1回复 待解决
前后双摄录像怎样解决
7114浏览 • 2回复 待解决
HarmonyOS如何实现自定义scheme?
511浏览 • 1回复 待解决
HarmonyOS 如何实现自定义Toast
354浏览 • 1回复 待解决
如何同时启动相机拍照和录像选项?
567浏览 • 0回复 待解决
HarmonyOS 自定义控件实现
645浏览 • 1回复 待解决
后台录像需要怎么做呢?
4627浏览 • 1回复 待解决
HarmonyOS 相机同时支持拍照和录像
590浏览 • 1回复 待解决
HarmonyOS 自定义StepperView组件如何实现
536浏览 • 1回复 待解决
如何实现自定义应用入场动画
1317浏览 • 1回复 待解决
HarmonyOS 数字自定义键盘如何实现
890浏览 • 1回复 待解决
HarmonyOS 全局自定义弹窗实现
575浏览 • 1回复 待解决
HarmonyOS补充nativgation自定义实现
616浏览 • 1回复 待解决
HarmonyOS ArkTS 如何实现自定义装饰器
446浏览 • 1回复 待解决
HarmonyOS自定义组件增加方法如何实现
976浏览 • 1回复 待解决