HarmonyOS APP分布式相机功能开发:跨设备拍照与预览

举报
Jack20 发表于 2026/06/19 23:38:49 2026/06/19
【摘要】 分布式相机:跨设备拍照与预览 背景与动机你有没有遇到过这种场景:想用手机的前置摄像头自拍,但手机屏幕太小看不清;或者想用平板的大屏幕来构图,但平板的摄像头效果不如手机;又或者多人合影时,想用电视的大屏幕来预览,大家都能看到是否拍好了。这就是分布式相机要解决的问题——让相机的能力跨设备流动。你可以用手机的摄像头拍照,但在平板或电视上预览和操作;或者反过来,用平板的屏幕取景,但实际拍照的是手机...

分布式相机:跨设备拍照与预览

背景与动机

你有没有遇到过这种场景:想用手机的前置摄像头自拍,但手机屏幕太小看不清;或者想用平板的大屏幕来构图,但平板的摄像头效果不如手机;又或者多人合影时,想用电视的大屏幕来预览,大家都能看到是否拍好了。

这就是分布式相机要解决的问题——让相机的能力跨设备流动。你可以用手机的摄像头拍照,但在平板或电视上预览和操作;或者反过来,用平板的屏幕取景,但实际拍照的是手机的高素质摄像头。

传统方案下,每个设备的相机都是独立的。手机只能用手机的摄像头,平板只能用平板的。但现实中,不同设备的摄像头素质差异很大——手机的主摄通常比平板好,而电视可能根本没有摄像头。分布式相机打破了这种限制,让"最好的摄像头"和"最大的屏幕"可以组合使用。

核心原理

分布式相机架构

分布式相机基于以下几个核心概念:

  1. CameraProvider:相机提供者,声明本设备的相机能力
  2. CameraProxy:相机代理,在远程设备上代表相机实例
  3. CameraStream:相机流,负责视频流的传输
  4. CameraControl:相机控制,负责参数设置和拍照指令
    图片.png

相机流类型

分布式相机支持多种流类型:

1. 预览流(Preview):实时取景画面,低延迟高帧率
2. 拍照流(Photo):高分辨率照片,按需传输
3. 录像流(Video):视频录制流,持续传输
4. 分析流(Analysis):用于人脸识别、场景分析等

相机控制指令

// 相机控制指令类型
enum CameraCommand {
    START_PREVIEW = 'start_preview',      // 开始预览
    STOP_PREVIEW = 'stop_preview',        // 停止预览
    TAKE_PHOTO = 'take_photo',            // 拍照
    START_RECORDING = 'start_recording',  // 开始录像
    STOP_RECORDING = 'stop_recording',    // 停止录像
    SET_ZOOM = 'set_zoom',                // 设置缩放
    SET_FOCUS = 'set_focus',              // 设置对焦
    SET_EXPOSURE = 'set_exposure',        // 设置曝光
    SWITCH_CAMERA = 'switch_camera'       // 切换摄像头
}

代码实战

示例一:基础分布式相机预览

这是最基础的分布式相机使用示例,在平板上预览手机的摄像头画面。

// DistributedCamera.ets
import camera from '@ohos.multimedia.camera';
import image from '@ohos.multimedia.image';
import deviceManager from '@ohos.distributedDeviceManager';
import distributedCamera from '@ohos.distributedCamera';

export class DistributedCamera {
    private context: common.UIAbilityContext;
    private deviceManager: deviceManager.DeviceManager | null = null;
    
    // 本地相机实例(如果是相机提供者)
    private localCamera: camera.Camera | null = null;
    
    // 远程相机代理(如果是相机使用者)
    private remoteCamera: distributedCamera.CameraProxy | null = null;
    
    // 相机状态
    private cameraState: CameraState = {
        isPreviewing: false,
        isRecording: false,
        currentCameraId: '',
        zoomRatio: 1.0,
        flashMode: 'off'
    };

    constructor(context: common.UIAbilityContext) {
        this.context = context;
    }

    // 初始化
    async initialize(): Promise<void> {
        console.info('[DistributedCamera] Initializing...');
        
        try {
            // 初始化设备管理器
            this.deviceManager = deviceManager.createDeviceManager(
                this.context.applicationInfo.name
            );
            
            // 检查本设备相机能力
            await this.checkLocalCameraCapability();
            
            console.info('[DistributedCamera] Initialized');
        } catch (error) {
            console.error('[DistributedCamera] Init failed:', error);
            throw error;
        }
    }

    // 检查本设备相机能力
    private async checkLocalCameraCapability(): Promise<void> {
        const cameraManager = camera.getCameraManager(this.context);
        const cameras = cameraManager.getSupportedCameras();
        
        console.info('[DistributedCamera] Local cameras:', cameras.length);
        
        for (const cam of cameras) {
            console.info('[DistributedCamera] Camera:', cam.cameraId, 
                ', Position:', cam.cameraPosition,
                ', Type:', cam.cameraType);
        }
    }

    // 作为相机提供者:注册相机服务
    async registerAsCameraProvider(): Promise<void> {
        console.info('[DistributedCamera] Registering as camera provider');
        
        try {
            // 获取相机管理器
            const cameraManager = camera.getCameraManager(this.context);
            const cameras = cameraManager.getSupportedCameras();
            
            // 为每个相机创建提供者配置
            const providerConfigs: distributedCamera.ProviderConfig[] = cameras.map(cam => ({
                cameraId: cam.cameraId,
                cameraPosition: cam.cameraPosition,
                cameraType: cam.cameraType,
                
                // 支持的能力
                capabilities: {
                    preview: true,
                    photo: true,
                    video: true,
                    zoom: true,
                    focus: true,
                    flash: true
                },
                
                // 支持的分辨率
                resolutions: {
                    preview: [{ width: 1920, height: 1080 }, { width: 1280, height: 720 }],
                    photo: [{ width: 4096, height: 3072 }, { width: 1920, height: 1080 }],
                    video: [{ width: 1920, height: 1080 }, { width: 1280, height: 720 }]
                }
            }));
            
            // 注册相机提供者
            await distributedCamera.registerProvider(providerConfigs);
            
            // 监听远程连接请求
            distributedCamera.on('connectionRequest', 
                (deviceId: string, cameraId: string) => {
                    this.handleConnectionRequest(deviceId, cameraId);
                });
            
            console.info('[DistributedCamera] Registered as provider');
        } catch (error) {
            console.error('[DistributedCamera] Register failed:', error);
        }
    }

    // 处理连接请求
    private async handleConnectionRequest(deviceId: string, cameraId: string): Promise<void> {
        console.info('[DistributedCamera] Connection request from:', deviceId, 'camera:', cameraId);
        
        try {
            // 打开本地相机
            const cameraManager = camera.getCameraManager(this.context);
            this.localCamera = await cameraManager.openCamera(cameraId);
            
            // 创建相机输出
            const photoOutput = await this.createPhotoOutput();
            const previewOutput = await this.createPreviewOutput();
            
            // 创建捕获会话
            const captureSession = cameraManager.createCaptureSession();
            captureSession.beginConfig();
            captureSession.addInput(this.localCamera);
            captureSession.addOutput(previewOutput);
            captureSession.addOutput(photoOutput);
            await captureSession.commitConfig();
            await captureSession.start();
            
            // 保存会话引用
            this.captureSession = captureSession;
            this.previewOutput = previewOutput;
            this.photoOutput = photoOutput;
            
            console.info('[DistributedCamera] Camera opened for remote');
        } catch (error) {
            console.error('[DistributedCamera] Handle request failed:', error);
        }
    }

    // 作为相机使用者:连接远程相机
    async connectRemoteCamera(
        sourceDeviceId: string, 
        cameraId: string
    ): Promise<boolean> {
        console.info('[DistributedCamera] Connecting to remote camera:', 
            sourceDeviceId, cameraId);
        
        try {
            // 创建远程相机代理
            this.remoteCamera = await distributedCamera.createCameraProxy({
                sourceDeviceId: sourceDeviceId,
                cameraId: cameraId
            });
            
            // 设置事件监听
            this.setupRemoteCameraListeners();
            
            // 获取相机能力
            const capabilities = await this.remoteCamera.getCapabilities();
            console.info('[DistributedCamera] Remote camera capabilities:', capabilities);
            
            return true;
        } catch (error) {
            console.error('[DistributedCamera] Connect failed:', error);
            return false;
        }
    }

    // 设置远程相机监听
    private setupRemoteCameraListeners(): void {
        if (!this.remoteCamera) return;
        
        // 监听预览帧
        this.remoteCamera.on('previewFrame', (frame: distributedCamera.PreviewFrame) => {
            this.handlePreviewFrame(frame);
        });
        
        // 监听拍照结果
        this.remoteCamera.on('photoTaken', (photo: distributedCamera.PhotoResult) => {
            this.handlePhotoResult(photo);
        });
        
        // 监听相机状态变化
        this.remoteCamera.on('stateChange', (state: distributedCamera.CameraState) => {
            console.info('[DistributedCamera] Remote camera state:', state);
        });
        
        // 监听错误
        this.remoteCamera.on('error', (error: BusinessError) => {
            console.error('[DistributedCamera] Remote camera error:', error);
            this.handleCameraError(error);
        });
    }

    // 开始预览
    async startPreview(): Promise<void> {
        console.info('[DistributedCamera] Starting preview');
        
        if (!this.remoteCamera) {
            console.error('[DistributedCamera] No remote camera');
            return;
        }
        
        try {
            // 配置预览参数
            const previewConfig: distributedCamera.PreviewConfig = {
                resolution: { width: 1920, height: 1080 },
                frameRate: 30,
                format: 'nv21'  // NV21格式
            };
            
            // 开始预览
            await this.remoteCamera.startPreview(previewConfig);
            
            this.cameraState.isPreviewing = true;
            console.info('[DistributedCamera] Preview started');
        } catch (error) {
            console.error('[DistributedCamera] Start preview failed:', error);
        }
    }

    // 停止预览
    async stopPreview(): Promise<void> {
        if (!this.remoteCamera || !this.cameraState.isPreviewing) return;
        
        try {
            await this.remoteCamera.stopPreview();
            this.cameraState.isPreviewing = false;
            console.info('[DistributedCamera] Preview stopped');
        } catch (error) {
            console.error('[DistributedCamera] Stop preview failed:', error);
        }
    }

    // 拍照
    async takePhoto(options?: PhotoOptions): Promise<image.PixelMap | null> {
        console.info('[DistributedCamera] Taking photo');
        
        if (!this.remoteCamera) {
            console.error('[DistributedCamera] No remote camera');
            return null;
        }
        
        try {
            // 配置拍照参数
            const photoConfig: distributedCamera.PhotoConfig = {
                resolution: options?.resolution || { width: 4096, height: 3072 },
                quality: options?.quality || 90,
                format: 'jpeg',
                
                // 额外设置
                flash: this.cameraState.flashMode,
                zoom: this.cameraState.zoomRatio
            };
            
            // 发起拍照
            const photoResult = await this.remoteCamera.takePhoto(photoConfig);
            
            console.info('[DistributedCamera] Photo taken, size:', photoResult.size);
            
            // 返回照片数据
            return photoResult.pixelMap;
        } catch (error) {
            console.error('[DistributedCamera] Take photo failed:', error);
            return null;
        }
    }

    // 设置缩放
    async setZoom(ratio: number): Promise<void> {
        if (!this.remoteCamera) return;
        
        try {
            await this.remoteCamera.setZoom(ratio);
            this.cameraState.zoomRatio = ratio;
            console.info('[DistributedCamera] Zoom set to:', ratio);
        } catch (error) {
            console.error('[DistributedCamera] Set zoom failed:', error);
        }
    }

    // 设置对焦点
    async setFocus(point: Point): Promise<void> {
        if (!this.remoteCamera) return;
        
        try {
            await this.remoteCamera.setFocus(point);
            console.info('[DistributedCamera] Focus set to:', point);
        } catch (error) {
            console.error('[DistributedCamera] Set focus failed:', error);
        }
    }

    // 设置闪光灯模式
    async setFlashMode(mode: 'on' | 'off' | 'auto' | 'torch'): Promise<void> {
        if (!this.remoteCamera) return;
        
        try {
            await this.remoteCamera.setFlashMode(mode);
            this.cameraState.flashMode = mode;
            console.info('[DistributedCamera] Flash mode set to:', mode);
        } catch (error) {
            console.error('[DistributedCamera] Set flash failed:', error);
        }
    }

    // 处理预览帧
    private handlePreviewFrame(frame: distributedCamera.PreviewFrame): void {
        // 通知UI更新预览
        AppStorage.setOrCreate('cameraPreviewFrame', frame.pixelMap);
    }

    // 处理拍照结果
    private handlePhotoResult(photo: distributedCamera.PhotoResult): void {
        console.info('[DistributedCamera] Photo result received');
        
        // 通知UI显示照片
        AppStorage.setOrCreate('cameraPhotoResult', photo);
    }

    // 处理相机错误
    private handleCameraError(error: BusinessError): void {
        console.error('[DistributedCamera] Camera error:', error.code, error.message);
        
        // 根据错误类型处理
        switch (error.code) {
            case distributedCamera.ErrorCode.DEVICE_DISCONNECTED:
                // 设备断开,尝试重连
                this.reconnectCamera();
                break;
            case distributedCamera.ErrorCode.CAMERA_BUSY:
                // 相机忙碌,稍后重试
                setTimeout(() => this.retryLastOperation(), 1000);
                break;
        }
    }

    // 重连相机
    private async reconnectCamera(): Promise<void> {
        // 实际实现
    }

    // 重试上次操作
    private retryLastOperation(): void {
        // 实际实现
    }

    // 创建拍照输出
    private async createPhotoOutput(): Promise<camera.PhotoOutput> {
        // 实际实现
        return null as any;
    }

    // 创建预览输出
    private async createPreviewOutput(): Promise<camera.PreviewOutput> {
        // 实际实现
        return null as any;
    }

    // 断开连接
    async disconnect(): Promise<void> {
        console.info('[DistributedCamera] Disconnecting');
        
        // 停止预览
        if (this.cameraState.isPreviewing) {
            await this.stopPreview();
        }
        
        // 释放远程相机
        if (this.remoteCamera) {
            await this.remoteCamera.release();
            this.remoteCamera = null;
        }
        
        // 释放本地相机
        if (this.localCamera) {
            await this.localCamera.release();
            this.localCamera = null;
        }
        
        console.info('[DistributedCamera] Disconnected');
    }

    // 销毁
    destroy(): void {
        this.disconnect();
        
        if (this.deviceManager) {
            deviceManager.releaseDeviceManager(this.deviceManager);
            this.deviceManager = null;
        }
    }
}

// 接口定义
interface CameraState {
    isPreviewing: boolean;
    isRecording: boolean;
    currentCameraId: string;
    zoomRatio: number;
    flashMode: string;
}

interface PhotoOptions {
    resolution?: { width: number; height: number };
    quality?: number;
}

interface Point {
    x: number;
    y: number;
}

interface BusinessError {
    code: number;
    message: string;
}

示例二:多设备相机协同

支持多个设备同时使用同一个相机,或者一个设备使用多个相机。

// MultiDeviceCamera.ets
import distributedCamera from '@ohos.distributedCamera';

export class MultiDeviceCamera {
    // 相机提供者管理
    private cameraProviders: Map<string, distributedCamera.CameraProvider> = new Map();
    
    // 相机使用者管理
    private cameraConsumers: Map<string, distributedCamera.CameraProxy> = new Map();
    
    // 预览分发器
    private previewDispatcher: PreviewDispatcher | null = null;

    // 发现可用的远程相机
    async discoverRemoteCameras(): Promise<RemoteCameraInfo[]> {
        console.info('[MultiCamera] Discovering remote cameras');
        
        const remoteCameras: RemoteCameraInfo[] = [];
        
        // 获取所有在线设备
        const devices = await this.getOnlineDevices();
        
        for (const device of devices) {
            try {
                // 查询设备的相机能力
                const cameras = await distributedCamera.queryRemoteCameras(device.deviceId);
                
                for (const cam of cameras) {
                    remoteCameras.push({
                        deviceId: device.deviceId,
                        deviceName: device.deviceName,
                        cameraId: cam.cameraId,
                        cameraPosition: cam.cameraPosition,
                        cameraType: cam.cameraType,
                        capabilities: cam.capabilities
                    });
                }
            } catch (error) {
                console.error('[MultiCamera] Query failed for device:', device.deviceId, error);
            }
        }
        
        console.info('[MultiCamera] Found', remoteCameras.length, 'remote cameras');
        return remoteCameras;
    }

    // 连接多个相机
    async connectMultipleCameras(
        cameras: { deviceId: string; cameraId: string }[]
    ): Promise<Map<string, boolean>> {
        console.info('[MultiCamera] Connecting', cameras.length, 'cameras');
        
        const results = new Map<string, boolean>();
        
        // 初始化预览分发器
        this.previewDispatcher = new PreviewDispatcher();
        
        // 并行连接所有相机
        const promises = cameras.map(async ({ deviceId, cameraId }) => {
            const key = `${deviceId}_${cameraId}`;
            
            try {
                const proxy = await distributedCamera.createCameraProxy({
                    sourceDeviceId: deviceId,
                    cameraId: cameraId
                });
                
                this.cameraConsumers.set(key, proxy);
                
                // 注册到预览分发器
                this.previewDispatcher?.addCamera(key, proxy);
                
                results.set(key, true);
            } catch (error) {
                console.error('[MultiCamera] Connect failed:', key, error);
                results.set(key, false);
            }
        });
        
        await Promise.all(promises);
        
        return results;
    }

    // 开始多相机预览
    async startMultiPreview(): Promise<void> {
        console.info('[MultiCamera] Starting multi preview');
        
        // 启动所有相机的预览
        const promises = Array.from(this.cameraConsumers.entries()).map(async ([key, proxy]) => {
            try {
                await proxy.startPreview({
                    resolution: { width: 1920, height: 1080 },
                    frameRate: 30
                });
            } catch (error) {
                console.error('[MultiCamera] Start preview failed:', key, error);
            }
        });
        
        await Promise.all(promises);
        
        // 启动预览分发
        this.previewDispatcher?.start();
    }

    // 同步拍照(多个相机同时拍照)
    async synchronizedCapture(): Promise<Map<string, image.PixelMap>> {
        console.info('[MultiCamera] Synchronized capture');
        
        const results = new Map<string, image.PixelMap>();
        
        // 记录开始时间
        const startTime = Date.now();
        
        // 并行拍照
        const promises = Array.from(this.cameraConsumers.entries()).map(async ([key, proxy]) => {
            try {
                const photo = await proxy.takePhoto({
                    resolution: { width: 4096, height: 3072 },
                    quality: 90
                });
                
                results.set(key, photo.pixelMap);
            } catch (error) {
                console.error('[MultiCamera] Capture failed:', key, error);
            }
        });
        
        await Promise.all(promises);
        
        const elapsed = Date.now() - startTime;
        console.info('[MultiCamera] Capture completed, elapsed:', elapsed, 'ms');
        
        return results;
    }

    // 切换主相机
    async switchPrimaryCamera(cameraKey: string): Promise<void> {
        console.info('[MultiCamera] Switching primary to:', cameraKey);
        
        // 更新预览分发器优先级
        this.previewDispatcher?.setPrimary(cameraKey);
    }

    // 获取在线设备
    private async getOnlineDevices(): Promise<DeviceInfo[]> {
        // 实际实现
        return [];
    }
}

// 预览分发器
class PreviewDispatcher {
    private cameras: Map<string, {
        proxy: distributedCamera.CameraProxy;
        isPrimary: boolean;
    }> = new Map();
    
    private isRunning: boolean = false;
    private frameListeners: Map<string, (frame: distributedCamera.PreviewFrame) => void> = new Map();

    addCamera(key: string, proxy: distributedCamera.CameraProxy): void {
        this.cameras.set(key, { proxy, isPrimary: false });
        
        // 设置帧监听
        proxy.on('previewFrame', (frame: distributedCamera.PreviewFrame) => {
            if (!this.isRunning) return;
            
            const listener = this.frameListeners.get(key);
            if (listener) {
                listener(frame);
            }
        });
    }

    setPrimary(key: string): void {
        // 清除之前的主相机标记
        for (const [k, cam] of this.cameras) {
            cam.isPrimary = (k === key);
        }
    }

    setFrameListener(key: string, listener: (frame: distributedCamera.PreviewFrame) => void): void {
        this.frameListeners.set(key, listener);
    }

    start(): void {
        this.isRunning = true;
    }

    stop(): void {
        this.isRunning = false;
    }
}

// 接口定义
interface RemoteCameraInfo {
    deviceId: string;
    deviceName: string;
    cameraId: string;
    cameraPosition: camera.CameraPosition;
    cameraType: camera.CameraType;
    capabilities: string[];
}

interface DeviceInfo {
    deviceId: string;
    deviceName: string;
}

示例三:分布式相机录像

支持跨设备录像,在目标设备控制,源设备录制。

// DistributedVideoRecording.ets
import distributedCamera from '@ohos.distributedCamera';
import media from '@ohos.multimedia.media';

export class DistributedVideoRecording {
    private remoteCamera: distributedCamera.CameraProxy | null = null;
    private videoRecorder: media.AVRecorder | null = null;
    
    // 录像状态
    private recordingState: RecordingState = {
        isRecording: false,
        duration: 0,
        fileSize: 0
    };

    // 开始分布式录像
    async startRecording(options: RecordingOptions): Promise<boolean> {
        console.info('[DistributedRecording] Starting recording');
        
        if (!this.remoteCamera) {
            console.error('[DistributedRecording] No remote camera');
            return false;
        }
        
        try {
            // 配置录像参数
            const recordingConfig: distributedCamera.RecordingConfig = {
                resolution: options.resolution || { width: 1920, height: 1080 },
                frameRate: options.frameRate || 30,
                bitrate: options.bitrate || 8000000,
                
                // 音频配置
                audio: {
                    enabled: options.enableAudio ?? true,
                    sampleRate: 48000,
                    channels: 2,
                    bitrate: 128000
                },
                
                // 输出配置
                output: {
                    format: 'mp4',
                    location: options.outputPath
                }
            };
            
            // 开始录像
            await this.remoteCamera.startRecording(recordingConfig);
            
            // 设置录像监听
            this.setupRecordingListeners();
            
            this.recordingState.isRecording = true;
            console.info('[DistributedRecording] Recording started');
            
            return true;
        } catch (error) {
            console.error('[DistributedRecording] Start failed:', error);
            return false;
        }
    }

    // 设置录像监听
    private setupRecordingListeners(): void {
        if (!this.remoteCamera) return;
        
        // 监听录像进度
        this.remoteCamera.on('recordingProgress', (progress: RecordingProgress) => {
            this.recordingState.duration = progress.duration;
            this.recordingState.fileSize = progress.fileSize;
            
            // 通知UI更新
            this.notifyRecordingProgress(progress);
        });
        
        // 监听录像完成
        this.remoteCamera.on('recordingComplete', (result: RecordingResult) => {
            console.info('[DistributedRecording] Recording complete');
            this.recordingState.isRecording = false;
            
            // 通知UI
            this.notifyRecordingComplete(result);
        });
        
        // 监听录像错误
        this.remoteCamera.on('recordingError', (error: BusinessError) => {
            console.error('[DistributedRecording] Recording error:', error);
            this.recordingState.isRecording = false;
            
            // 通知UI
            this.notifyRecordingError(error);
        });
    }

    // 暂停录像
    async pauseRecording(): Promise<void> {
        if (!this.remoteCamera || !this.recordingState.isRecording) return;
        
        try {
            await this.remoteCamera.pauseRecording();
            console.info('[DistributedRecording] Recording paused');
        } catch (error) {
            console.error('[DistributedRecording] Pause failed:', error);
        }
    }

    // 恢复录像
    async resumeRecording(): Promise<void> {
        if (!this.remoteCamera) return;
        
        try {
            await this.remoteCamera.resumeRecording();
            console.info('[DistributedRecording] Recording resumed');
        } catch (error) {
            console.error('[DistributedRecording] Resume failed:', error);
        }
    }

    // 停止录像
    async stopRecording(): Promise<RecordingResult | null> {
        console.info('[DistributedRecording] Stopping recording');
        
        if (!this.remoteCamera || !this.recordingState.isRecording) {
            return null;
        }
        
        try {
            const result = await this.remoteCamera.stopRecording();
            
            this.recordingState.isRecording = false;
            console.info('[DistributedRecording] Recording stopped, duration:', result.duration);
            
            return result;
        } catch (error) {
            console.error('[DistributedRecording] Stop failed:', error);
            return null;
        }
    }

    // 获取录像状态
    getRecordingState(): RecordingState {
        return { ...this.recordingState };
    }

    // 通知方法
    private notifyRecordingProgress(progress: RecordingProgress): void {
        AppStorage.setOrCreate('recordingProgress', progress);
    }

    private notifyRecordingComplete(result: RecordingResult): void {
        AppStorage.setOrCreate('recordingResult', result);
    }

    private notifyRecordingError(error: BusinessError): void {
        AppStorage.setOrCreate('recordingError', error);
    }

    // 设置远程相机
    setRemoteCamera(camera: distributedCamera.CameraProxy): void {
        this.remoteCamera = camera;
    }
}

// 接口定义
interface RecordingState {
    isRecording: boolean;
    duration: number;
    fileSize: number;
}

interface RecordingOptions {
    resolution?: { width: number; height: number };
    frameRate?: number;
    bitrate?: number;
    enableAudio?: boolean;
    outputPath: string;
}

interface RecordingProgress {
    duration: number;
    fileSize: number;
    frameCount: number;
}

interface RecordingResult {
    duration: number;
    fileSize: number;
    outputPath: string;
    thumbnail: image.PixelMap;
}

踰坑与注意事项

坑一:预览帧率过低

问题描述:远程预览帧率远低于本地预览,画面卡顿。

解决方案:优化传输配置

const previewConfig: distributedCamera.PreviewConfig = {
    resolution: { width: 1280, height: 720 },  // 降低分辨率
    frameRate: 30,
    
    // 传输优化
    transport: {
        codec: 'h264',  // 使用H.264编码压缩
        bitrate: 2000000,
        keyFrameInterval: 1,  // 每秒一个关键帧
        
        // 网络优化
        protocol: 'udp',  // UDP低延迟
        bufferSize: 512 * 1024
    }
};

坑二:拍照延迟过长

问题描述:点击拍照后,实际拍照和照片返回延迟很长。

解决方案:使用预缓存和异步处理

// 预缓存对焦和曝光
async prepareForCapture(): Promise<void> {
    // 预先对焦
    await this.remoteCamera?.setFocus({ x: 0.5, y: 0.5 });
    
    // 锁定曝光
    await this.remoteCamera?.lockExposure();
    
    // 相机进入就绪状态
    this.cameraReady = true;
}

// 快速拍照
async quickCapture(): Promise<image.PixelMap> {
    if (!this.cameraReady) {
        await this.prepareForCapture();
    }
    
    // 直接拍照,跳过对焦
    return await this.remoteCamera?.takePhoto({
        skipFocus: true,
        skipExposure: true
    });
}

坑三:设备断开导致数据丢失

问题描述:录像过程中设备断开,已录制的内容丢失。

解决方案:实时保存和断点续录

// 配置实时保存
const recordingConfig: distributedCamera.RecordingConfig = {
    // ... 其他配置
    
    // 实时保存配置
    realtimeSave: {
        enabled: true,
        saveInterval: 5000,  // 每5秒保存一次
        tempPath: '/data/temp_recording.mp4'
    },
    
    // 断点续录配置
    resume: {
        enabled: true,
        maxResumeAttempts: 3
    }
};

// 监听断开事件
remoteCamera.on('disconnected', async () => {
    // 尝试恢复已录制的内容
    const recoveredFile = await distributedCamera.recoverRecording(sessionId);
    console.info('Recovered recording:', recoveredFile);
});

HarmonyOS 6适配

新增AI相机能力

HarmonyOS 6支持分布式AI相机能力:

// 启用AI功能
const aiConfig: distributedCamera.AIConfig = {
    // 人脸检测
    faceDetection: {
        enabled: true,
        mode: 'continuous',  // 持续检测
        maxFaces: 10
    },
    
    // 场景识别
    sceneRecognition: {
        enabled: true,
        scenes: ['portrait', 'landscape', 'night', 'food']
    },
    
    // 美颜
    beauty: {
        enabled: true,
        level: 5,  // 美颜等级
        smoothSkin: true,
        slimFace: true
    }
};

await remoteCamera.enableAI(aiConfig);

// 监听AI结果
remoteCamera.on('aiResult', (result: AIResult) => {
    if (result.faceDetection) {
        // 显示人脸框
        this.drawFaceRects(result.faceDetection.faces);
    }
    
    if (result.sceneRecognition) {
        // 根据场景调整参数
        this.adjustForScene(result.sceneRecognition.scene);
    }
});

增强的相机元数据

// 获取详细相机信息
const cameraInfo = await remoteCamera.getCameraInfo();

console.info('Sensor size:', cameraInfo.sensorSize);
console.info('Focal length:', cameraInfo.focalLength);
console.info('Aperture:', cameraInfo.aperture);
console.info('ISO range:', cameraInfo.isoRange);
console.info('Shutter speed range:', cameraInfo.shutterSpeedRange);

// 获取EXIF信息
const exif = await remoteCamera.getExif(photoId);
console.info('GPS:', exif.gps);
console.info('Timestamp:', exif.timestamp);
console.info('Orientation:', exif.orientation);

多流同步

// 同时获取多种流
const multiStreamConfig: distributedCamera.MultiStreamConfig = {
    streams: [
        { type: 'preview', resolution: { width: 1920, height: 1080 } },
        { type: 'analysis', resolution: { width: 640, height: 480 } },  // 用于AI分析
        { type: 'depth', resolution: { width: 640, height: 480 } }      // 深度图
    ],
    
    // 同步模式
    syncMode: 'timestamp'  // 基于时间戳同步
};

await remoteCamera.startMultiStream(multiStreamConfig);

总结

分布式相机让摄像头的能力突破了设备的物理限制,实现了"最好的摄像头"和"最大的屏幕"的自由组合。无论是远程预览、跨设备拍照还是分布式录像,都为用户提供了更灵活、更强大的拍摄体验。

核心要点

  1. 相机提供者与使用者:设备可以作为相机提供者或使用者,或两者兼备
  2. 实时流传输:预览流需要低延迟高帧率的传输策略
  3. 远程控制:拍照、对焦、缩放等操作需要跨设备指令传递
  4. 多设备协同:支持多相机同步拍照、多设备预览等高级场景

最佳实践

  • 根据网络状况调整预览分辨率和帧率
  • 使用预缓存技术减少拍照延迟
  • 实现断点续录防止数据丢失
  • 善用AI能力提升拍摄效果
  • 处理设备断开、权限变化等边界情况

分布式相机是HarmonyOS分布式能力的典型应用,下一篇我们将探讨分布式音频,看看如何实现跨设备的音频播放。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。