|
|
|
import camera from '@ohos.multimedia.camera';
|
|
|
|
import media from '@ohos.multimedia.media';
|
|
|
|
import { BusinessError } from '@ohos.base';
|
|
|
|
import { promptAction, router } from '@kit.ArkUI'
|
|
|
|
import { common } from '@kit.AbilityKit';
|
|
|
|
import { FileUtil, CommonConstants } from '../utils/FileUtil';
|
|
|
|
import { uploadFileByTask } from '../utils/uploadCloud'
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 视频录制
|
|
|
|
*/
|
|
|
|
|
|
|
|
interface routerParams {
|
|
|
|
cosKeyStr: string;
|
|
|
|
relateId: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TAG: string = 'Record';
|
|
|
|
let context = getContext(this) as common.UIAbilityContext;
|
|
|
|
let routerParamsData: routerParams = router.getParams() as routerParams;
|
|
|
|
@Entry
|
|
|
|
@Component
|
|
|
|
struct CreateCamera {
|
|
|
|
@State xComponentWidth: number = 0;
|
|
|
|
@State xComponentHeight: number = 0;
|
|
|
|
@State recording: boolean = false;
|
|
|
|
@State path: string = '';
|
|
|
|
@State countTime: number = 0;
|
|
|
|
@State cameraManager: camera.CameraManager | undefined = undefined;
|
|
|
|
@State videoOutput: camera.VideoOutput | undefined = undefined;
|
|
|
|
@State captureSession: camera.Session | undefined = undefined;
|
|
|
|
@State cameraInput: camera.CameraInput | undefined = undefined;
|
|
|
|
@State previewOutput: camera.PreviewOutput | undefined = undefined;
|
|
|
|
@State avRecorder: media.AVRecorder | undefined = undefined;
|
|
|
|
private mXComponentController: XComponentController = new XComponentController;
|
|
|
|
private surfaceId: string = '';
|
|
|
|
url: string = '';
|
|
|
|
timer: number = 0;
|
|
|
|
|
|
|
|
aboutToAppear() {
|
|
|
|
// 创建存放视频文件
|
|
|
|
this.path = context.filesDir + '/' + 'VIDEO_' + Date.parse(new Date().toString()) + '.mp4';
|
|
|
|
let file = FileUtil.createOrOpen(this.path);
|
|
|
|
this.url = 'fd://' + file.fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
build() {
|
|
|
|
Stack({ alignContent: Alignment.Top }) {
|
|
|
|
XComponent({
|
|
|
|
id: 'componentId',
|
|
|
|
type: XComponentType.SURFACE,
|
|
|
|
controller: this.mXComponentController,
|
|
|
|
})
|
|
|
|
.onLoad(async () => {
|
|
|
|
this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
|
|
|
|
await this.initCamera(getContext(this), this.surfaceId);
|
|
|
|
})
|
|
|
|
.height(CommonConstants.SEVENTY_PERCENT)
|
|
|
|
.margin({
|
|
|
|
top: CommonConstants.FIFTEEN_PERCENT
|
|
|
|
})
|
|
|
|
Column() {
|
|
|
|
Text(`录制时长:${this.countTime}s`).fontSize(16).fontColor(Color.White)
|
|
|
|
Blank()
|
|
|
|
Row() {
|
|
|
|
Image(this.recording ? $r('app.media.camera_pause_video_4x') : $r('app.media.camera_take_video_4x'))
|
|
|
|
.width(px2vp(CommonConstants.IMAGE_SIZE))
|
|
|
|
.height(px2vp(CommonConstants.IMAGE_SIZE))
|
|
|
|
.onClick(async () => {
|
|
|
|
if (this.recording) {
|
|
|
|
clearInterval(this.timer);
|
|
|
|
this.timer = 0
|
|
|
|
await this.stopRecord();
|
|
|
|
await uploadFileByTask(routerParamsData.cosKeyStr, routerParamsData.relateId, this.path);
|
|
|
|
router.back()
|
|
|
|
} else {
|
|
|
|
this.timer = setInterval(async () => {
|
|
|
|
this.countTime++;
|
|
|
|
if(this.countTime >= 120){
|
|
|
|
clearInterval(this.timer);
|
|
|
|
this.timer = 0
|
|
|
|
await this.stopRecord();
|
|
|
|
await uploadFileByTask(routerParamsData.cosKeyStr, routerParamsData.relateId, this.path);
|
|
|
|
router.back()
|
|
|
|
}
|
|
|
|
}, 1000);
|
|
|
|
this.startRecord();
|
|
|
|
}
|
|
|
|
this.recording = !this.recording;
|
|
|
|
})
|
|
|
|
}
|
|
|
|
.width(CommonConstants.FULL_PERCENT)
|
|
|
|
.height(120)
|
|
|
|
.margin({ bottom: 60 })
|
|
|
|
.justifyContent(FlexAlign.Center)
|
|
|
|
.alignItems(VerticalAlign.Center)
|
|
|
|
}
|
|
|
|
.width(CommonConstants.FULL_PERCENT)
|
|
|
|
.height(CommonConstants.FULL_PERCENT)
|
|
|
|
.justifyContent(FlexAlign.Start)
|
|
|
|
.alignItems(HorizontalAlign.Start)
|
|
|
|
}
|
|
|
|
.backgroundColor(Color.Black)
|
|
|
|
.width(CommonConstants.FULL_PERCENT)
|
|
|
|
.height(CommonConstants.FULL_PERCENT)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 初始化相机
|
|
|
|
async initCamera(context: common.Context, surfaceId: string) {
|
|
|
|
this.cameraManager = camera.getCameraManager(context);
|
|
|
|
if (!this.cameraManager) {
|
|
|
|
promptAction.showToast({ message: 'camera.getCameraManager error' })
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => {
|
|
|
|
promptAction.showToast({ message: `camera : ${cameraStatusInfo.camera.cameraId},status: ${cameraStatusInfo.status}` })
|
|
|
|
});
|
|
|
|
|
|
|
|
let cameraArray: Array<camera.CameraDevice> = [];
|
|
|
|
try {
|
|
|
|
cameraArray = this.cameraManager.getSupportedCameras();
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `getSupportedCameras call failed. error code: ${err.code}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cameraArray.length <= 0) {
|
|
|
|
promptAction.showToast({ message: 'cameraManager.getSupportedCameras error' })
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let cameraOutputCap: camera.CameraOutputCapability =
|
|
|
|
this.cameraManager.getSupportedOutputCapability(cameraArray[0], camera.SceneMode.NORMAL_VIDEO);
|
|
|
|
if (!cameraOutputCap) {
|
|
|
|
promptAction.showToast({ message: 'cameraManager.getSupportedOutputCapability error' })
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
promptAction.showToast({ message: 'outputCapability: ' + JSON.stringify(cameraOutputCap) })
|
|
|
|
|
|
|
|
let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles;
|
|
|
|
if (!previewProfilesArray) {
|
|
|
|
promptAction.showToast({ message: 'createOutput previewProfilesArray === null || undefined' })
|
|
|
|
}
|
|
|
|
|
|
|
|
let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles;
|
|
|
|
if (!photoProfilesArray) {
|
|
|
|
promptAction.showToast({ message: 'createOutput photoProfilesArray === null || undefined' })
|
|
|
|
}
|
|
|
|
|
|
|
|
let videoProfilesArray: Array<camera.VideoProfile> = cameraOutputCap.videoProfiles;
|
|
|
|
if (!videoProfilesArray) {
|
|
|
|
promptAction.showToast({ message: 'createOutput videoProfilesArray === null || undefined' })
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
promptAction.showToast({ message: '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_AVC,
|
|
|
|
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,
|
|
|
|
rotation: 0,
|
|
|
|
location: {
|
|
|
|
latitude: 30,
|
|
|
|
longitude: 130
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.avRecorder = await media.createAVRecorder();
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `createAVRecorder call failed. error code: ${err.code}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.avRecorder === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
await this.avRecorder.prepare(aVRecorderConfig);
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `prepare call failed. error code: ${err.code}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
let videoSurfaceId: string | undefined = undefined;
|
|
|
|
try {
|
|
|
|
videoSurfaceId = await this.avRecorder.getInputSurface();
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `getInputSurface call failed. error code: ${err.code}` })
|
|
|
|
}
|
|
|
|
if (videoSurfaceId === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.videoOutput = this.cameraManager.createVideoOutput(videoProfile, videoSurfaceId);
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to create the videoOutput instance. error: ${JSON.stringify(err)}` })
|
|
|
|
}
|
|
|
|
if (this.videoOutput === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.videoOutput.on('frameStart', () => {
|
|
|
|
promptAction.showToast({ message: 'Video frame started' })
|
|
|
|
});
|
|
|
|
|
|
|
|
this.videoOutput.on('error', (error: BusinessError) => {
|
|
|
|
promptAction.showToast({ message: `Video frame error code: ${error.code}` })
|
|
|
|
});
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.captureSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_VIDEO) as camera.VideoSession;
|
|
|
|
;
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to create the CaptureSession instance. errorCode = ${err.code}` })
|
|
|
|
}
|
|
|
|
if (this.captureSession === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.captureSession.beginConfig();
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to beginConfig. errorCode = ${err.code}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
let cameraInput: camera.CameraInput | undefined = undefined;
|
|
|
|
try {
|
|
|
|
cameraInput = this.cameraManager.createCameraInput(cameraArray[0]);
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to createCameraInput. errorCode = ${err.code}` })
|
|
|
|
}
|
|
|
|
if (cameraInput === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let cameraDevice: camera.CameraDevice = cameraArray[0];
|
|
|
|
cameraInput.on('error', cameraDevice, (error: BusinessError) => {
|
|
|
|
promptAction.showToast({ message: `Camera input error code: ${error.code}` })
|
|
|
|
});
|
|
|
|
|
|
|
|
try {
|
|
|
|
await cameraInput.open();
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to open cameraInput. errorCode = ${err.code}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.captureSession.addInput(cameraInput);
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to add cameraInput. errorCode = ${err.code}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
let previewOutput: camera.PreviewOutput | undefined = undefined;
|
|
|
|
try {
|
|
|
|
previewOutput = this.cameraManager.createPreviewOutput(videoProfile, surfaceId);
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to create the previewOutput instance. error: ${JSON.stringify(err)}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
if (previewOutput === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.captureSession.addOutput(previewOutput);
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to add previewOutput. errorCode = ${err.code}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.captureSession.addOutput(this.videoOutput);
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to add videoOutput. errorCode = ${err.code}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
await this.captureSession.commitConfig();
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to commitConfig. errorCode = ${err.code}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
await this.captureSession.start();
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `Failed to start captureSession. errorCode = ${err.code}` })
|
|
|
|
}
|
|
|
|
|
|
|
|
this.videoOutput.start((err: BusinessError) => {
|
|
|
|
if (err) {
|
|
|
|
promptAction.showToast({ message: `Failed to start the video output. error: ${JSON.stringify(err)}` })
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
promptAction.showToast({message: 'Callback invoked to indicate the video output start success.'})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// 开始录像
|
|
|
|
async startRecord() {
|
|
|
|
if (this.avRecorder) {
|
|
|
|
try {
|
|
|
|
await this.avRecorder.start();
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `avRecorder start error: ${JSON.stringify(err)}` })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 停止录像
|
|
|
|
async stopRecord() {
|
|
|
|
if (this.avRecorder) {
|
|
|
|
try {
|
|
|
|
if (this.videoOutput) {
|
|
|
|
this.videoOutput.stop((err: BusinessError) => {
|
|
|
|
if (err) {
|
|
|
|
promptAction.showToast({ message: `Failed to stop the video output. error: ${JSON.stringify(err)}` })
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
promptAction.showToast({message: 'Callback invoked to indicate the video output stop success.'})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
await this.avRecorder.stop();
|
|
|
|
await this.avRecorder.release();
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `avRecorder stop error: ${JSON.stringify(err)}` })
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `avRecorder stop error: ${JSON.stringify(err)}` })
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
if (this.captureSession) {
|
|
|
|
this.captureSession.stop();
|
|
|
|
}
|
|
|
|
if (this.cameraInput) {
|
|
|
|
this.cameraInput.close();
|
|
|
|
}
|
|
|
|
if (this.previewOutput) {
|
|
|
|
this.previewOutput.release();
|
|
|
|
}
|
|
|
|
if (this.videoOutput) {
|
|
|
|
this.videoOutput.release();
|
|
|
|
}
|
|
|
|
if (this.captureSession) {
|
|
|
|
this.captureSession.release();
|
|
|
|
}
|
|
|
|
if (this.captureSession) {
|
|
|
|
this.captureSession = undefined;
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
let err = error as BusinessError;
|
|
|
|
promptAction.showToast({ message: `avRecorder stop error: ${JSON.stringify(err)}` })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} |
|
|
\ No newline at end of file |
...
|
...
|
|