鸿蒙App多设备摄像头聚合(手机+平板画面拼接监控)全解析【华为根技术】

举报
鱼弦 发表于 2025/12/12 10:44:01 2025/12/12
【摘要】 1. 引言随着物联网和智能家居的快速发展,多设备协同监控已成为现代安防领域的重要需求。传统的单设备监控存在视角局限、覆盖范围有限等问题,而基于鸿蒙分布式能力的多设备摄像头聚合技术,能够将手机、平板等不同设备的摄像头资源整合为一个统一的监控系统。本方案通过鸿蒙的分布式软总线、设备虚拟化、媒体会话管理等核心技术,实现手机和平板摄像头的实时画面采集、低延迟传输、智能拼接和统一控制,为用户提供360...


1. 引言

随着物联网和智能家居的快速发展,多设备协同监控已成为现代安防领域的重要需求。传统的单设备监控存在视角局限、覆盖范围有限等问题,而基于鸿蒙分布式能力的多设备摄像头聚合技术,能够将手机、平板等不同设备的摄像头资源整合为一个统一的监控系统。
本方案通过鸿蒙的分布式软总线、设备虚拟化、媒体会话管理等核心技术,实现手机和平板摄像头的实时画面采集、低延迟传输、智能拼接和统一控制,为用户提供360度全景监控、多视角协同观察、远程实时监控等创新功能。该方案特别适用于家庭安防、商铺监控、户外探险、大型活动现场等多个场景,显著提升监控覆盖范围和用户体验。

2. 技术背景

2.1 鸿蒙分布式多媒体能力基础

鸿蒙系统为多媒体处理和多设备协同提供了强大的底层支持:
核心技术
作用描述
在摄像头聚合中的应用
分布式软总线
设备间高速数据传输通道
实现摄像头视频流的低延迟传输
媒体会话管理
统一管理多路媒体流
协调手机、平板等多设备视频流
设备虚拟化
将远端设备媒体能力虚拟成本地
手机可访问平板的摄像头,反之亦然
分布式数据管理
跨设备数据同步与共享
同步摄像头状态、配置和控制指令
超级终端
设备动态组网与资源管理
自动发现可用摄像头设备并组网
硬件加速
GPU/VPU硬件编解码支持
提升视频采集、编码、拼接效率

2.2 摄像头聚合技术架构

graph TD
    subgraph 设备层(多设备集群)
        A[手机设备] -->|摄像头| A1[视频采集模块]
        B[平板设备] -->|摄像头| B1[视频采集模块]
        C[智慧屏] -->|摄像头| C1[视频采集模块]
        D[运动相机] -->|摄像头| D1[视频采集模块]
    end
    
    subgraph 分布式中间件
        E[分布式软总线] --> F[设备发现服务]
        F --> G[媒体会话管理]
        G --> H[数据路由中心]
        H --> I[编解码协调器]
        J[超级终端] --> F
    end
    
    subgraph 聚合处理层
        K[视频采集调度器] --> L[视频预处理单元]
        L --> M[视频编码模块]
        M --> N[网络传输优化]
        N --> O[视频拼接引擎]
        O --> P[画面布局管理器]
        P --> Q[显示渲染器]
    end
    
    subgraph 应用展现层
        R[监控主控台] --> S[多画面预览]
        S --> T[PTZ控制面板]
        T --> U[录像回放]
        U --> V[告警管理中心]
        V --> W[AI分析引擎]
    end
    
    A1 --> K
    B1 --> K
    C1 --> K
    D1 --> K
    I --> O
    Q --> R

2.3 关键技术特性

  1. 多源异构接入:支持不同类型设备(手机、平板、专业摄像机)的摄像头接入,兼容不同分辨率和帧率
  2. 智能负载均衡:根据设备性能和网络状况动态分配采集任务,优化资源利用
  3. 自适应码率:根据网络带宽自动调整视频质量和传输参数,保证流畅性
  4. 无缝拼接:支持多种拼接模式(画中画、网格、环形),智能校正视角差异
  5. 低延迟传输:端到端延迟控制在200ms以内,满足实时监控需求
  6. 容错机制:单设备故障不影响整体监控,自动切换备用设备或调整布局
  7. 安全加密:视频流端到端加密传输,防止数据泄露和非法访问
  8. AI增强:集成目标检测、行为识别等AI能力,提升监控智能化水平

3. 应用使用场景

3.1 典型应用场景分类

场景类型
需求描述
技术要求
实现重点
家庭全景监控
客厅、卧室、门口多角度监控
设备自动发现、低功耗
基于位置的自动设备组网
商铺多区域监控
收银台、货架、仓库分区监控
高清画质、稳定传输
网络自适应和故障切换
户外协同监控
徒步、露营时多设备协同观察
移动网络适应、电池优化
弱网环境下的码率自适应
大型活动直播
演唱会、体育赛事多视角直播
高并发、低延迟
分布式编码和CDN分发
远程看护
老人、儿童远程监护
隐私保护、异常检测
AI辅助监控和告警
工业巡检
工厂、工地多区域安全监控
防爆防尘、长续航
工业级设备适配和环境适应
应急指挥
灾害现场多维度态势感知
快速部署、抗干扰
自组网和应急通信保障

3.2 场景复杂度分析

  • 简单场景:2-3台同类型设备,固定位置监控,WiFi网络
  • 中级场景:4-8台多类型设备,部分移动设备,混合网络(WiFi+4G)
  • 复杂场景:10+台设备,包含专业监控设备,复杂网络环境,需要AI分析
  • 企业级场景:大规模设备集群,多级联网,云端协同,大数据分析

4. 核心原理与流程图

4.1 摄像头聚合系统架构图

graph TD
    subgraph 采集端设备
        A[手机] --> A1[Camera Manager]
        A1 --> A2[Video Capture]
        A2 --> A3[Pre-processing]
        A3 --> A4[Encoder]
        A4 --> A5[Network Adapter]
        
        B[平板] --> B1[Camera Manager]
        B1 --> B2[Video Capture]
        B2 --> B3[Pre-processing]
        B3 --> B4[Encoder]
        B4 --> B5[Network Adapter]
    end
    
    subgraph 分布式传输层
        C[Distributed Soft Bus] --> D[Device Discovery]
        D --> E[Connection Manager]
        E --> F[Media Session Controller]
        F --> G[Stream Router]
        G --> H[QoS Manager]
    end
    
    subgraph 聚合处理端
        I[Aggregation Controller] --> J[Stream Scheduler]
        J --> K[Frame Sync Module]
        K --> L[Stitching Engine]
        L --> M[Layout Manager]
        M --> N[Render Engine]
        N --> O[Display Output]
    end
    
    subgraph 控制与管理
        P[Control Panel] --> Q[PTZ Controller]
        Q --> R[Recording Manager]
        R --> S[Alert System]
        S --> T[AI Analyzer]
        T --> U[Configuration Center]
    end
    
    A5 --> G
    B5 --> G
    G --> I
    I --> P
    O --> P

4.2 摄像头聚合工作流程

sequenceDiagram
    participant User as 用户
    participant Controller as 聚合控制器
    participant DeviceMgr as 设备管理器
    participant Camera as 摄像头设备
    participant MediaSession as 媒体会话
    participant Stitcher as 拼接引擎
    participant Renderer as 渲染器
    
    User->>Controller: 启动多设备监控
    Controller->>DeviceMgr: 发现可用摄像头设备
    DeviceMgr->>DeviceMgr: 扫描附近设备
    DeviceMgr->>Controller: 返回设备列表(手机A,平板B)
    
    Controller->>Controller: 筛选可用摄像头
    loop 对每个设备
        Controller->>Camera: 请求视频流(分辨率/帧率)
        Camera->>MediaSession: 创建媒体会话
        MediaSession->>Camera: 配置采集参数
        Camera->>Camera: 开始视频采集
        Camera->>MediaSession: 推送视频帧
        MediaSession->>Controller: 转发视频流
    end
    
    Controller->>Stitcher: 配置拼接参数(布局模式)
    Stitcher->>Stitcher: 初始化拼接上下文
    Controller->>Renderer: 创建显示窗口
    
    loop 实时处理循环
        Controller->>Stitcher: 接收多路视频帧
        Stitcher->>Stitcher: 帧同步处理
        Stitcher->>Stitcher: 执行画面拼接
        Stitcher->>Renderer: 输出合成画面
        Renderer->>Renderer: 渲染到显示设备
    end
    
    User->>Controller: 调整布局/控制PTZ
    Controller->>Stitcher: 更新布局参数
    Controller->>Camera: 发送PTZ控制指令
    Camera->>Camera: 执行云台控制
    
    User->>Controller: 停止监控
    Controller->>Camera: 停止所有采集
    Controller->>MediaSession: 关闭媒体会话
    Controller->>Renderer: 释放显示资源

4.3 工作原理详解

  1. 设备发现与组网:通过分布式软总线和超级终端能力,聚合控制器自动发现附近的手机、平板等设备,建立安全连接并组成监控网络。
  2. 摄像头能力协商:控制器查询各设备的摄像头参数(分辨率、帧率、编码格式、焦距等),根据监控需求和网络条件协商最优采集参数。
  3. 视频采集与预处理:各设备启动摄像头采集,进行图像增强(降噪、锐化、色彩校正)、畸变校正(针对广角镜头)等预处理操作。
  4. 编码与传输:视频帧经过硬件编码(H.264/H.265)压缩,通过分布式软总线以RTP/RTCP协议传输,支持前向纠错和丢包重传。
  5. 流同步与缓冲:聚合控制器对各路视频流进行时间戳同步,使用抖动缓冲区平滑网络波动导致的时延变化。
  6. 画面拼接与渲染:拼接引擎根据预设布局(网格、环形、画中画)将多路视频合成为单一画面,支持实时调整和特效处理。
  7. 智能分析与告警:集成AI算法对合成画面进行目标检测、行为分析,发现异常时触发告警并记录相关视频片段。
  8. 集中控制与管理:提供统一的PTZ控制、录像管理、权限控制界面,支持多用户远程访问和协作监控。

5. 环境准备

5.1 开发环境配置

# 安装DevEco Studio最新版
# 下载地址:https://developer.harmonyos.com/cn/develop/deveco-studio

# 创建鸿蒙多设备摄像头聚合项目
# 1. 打开DevEco Studio -> Create Project
# 2. 选择"Application" -> "Empty Ability"
# 3. 配置项目信息:
#    - Project name: MultiDeviceCameraAggregator
#    - Bundle name: com.example.multidevicecamera
#    - Save location: 选择合适路径
#    - Compile SDK: API 10+ (推荐最新版本)
#    - Device type: Phone + Tablet + Automotive (多选)
#    - Language: ArkTS
#    - UI Framework: ArkUI

# 目录结构规划
MultiDeviceCameraAggregator/
├── entry/                          # 主模块(聚合控制器)
│   ├── src/
│   │   ├── main/
│   │   │   ├── ets/                # ArkTS源代码
│   │   │   │   ├── pages/          # 页面组件
│   │   │   │   │   ├── MainPage.ets        # 主监控页面
│   │   │   │   │   ├── DevicePage.ets      # 设备配置页面
│   │   │   │   │   ├── LayoutPage.ets      # 布局设置页面
│   │   │   │   │   └── SettingsPage.ets    # 系统设置页面
│   │   │   │   ├── components/      # 公共组件
│   │   │   │   │   ├── VideoGrid.ets       # 视频网格组件
│   │   │   │   │   ├── PTZControl.ets      # 云台控制组件
│   │   │   │   │   ├── DeviceCard.ets      # 设备卡片组件
│   │   │   │   │   └── AlertPanel.ets      # 告警面板组件
│   │   │   │   ├── model/           # 数据模型
│   │   │   │   │   ├── CameraDevice.ets    # 摄像头设备模型
│   │   │   │   │   ├── VideoStream.ets     # 视频流模型
│   │   │   │   │   ├── LayoutConfig.ets    # 布局配置模型
│   │   │   │   │   └── AggregationModel.ets # 聚合状态模型
│   │   │   │   ├── service/         # 业务逻辑服务
│   │   │   │   │   ├── DeviceManager.ets    # 设备管理服务
│   │   │   │   │   ├── StreamAggregator.ets # 流聚合服务
│   │   │   │   │   ├── StitchingEngine.ets  # 拼接引擎服务
│   │   │   │   │   ├── MediaSessionMgr.ets # 媒体会话管理
│   │   │   │   │   ├── NetworkOptimizer.ets # 网络优化服务
│   │   │   │   │   ├── PTZController.ets    # 云台控制服务
│   │   │   │   │   └── AIAnalyzer.ets       # AI分析服务
│   │   │   │   ├── utils/           # 工具类
│   │   │   │   │   ├── Logger.ets           # 日志工具
│   │   │   │   │   ├── PermissionUtil.ets   # 权限工具
│   │   │   │   │   ├── VideoUtils.ets       # 视频工具
│   │   │   │   │   └── GeometryUtil.ets     # 几何工具
│   │   │   │   └── Application.ets  # 应用入口
│   │   │   ├── resources/          # 资源文件
│   │   │   │   ├── base/
│   │   │   │   │   ├── element/    # 颜色、字符串、样式
│   │   │   │   │   ├── media/      # 图标、背景图
│   │   │   │   │   ├── profile/    # 配置文件
│   │   │   │   │   └── rawfile/    # 着色器、模型文件
│   │   │   └── module.json5        # 模块配置
│   ├── build-profile.json5         # 构建配置
│   └──hvigorfile.ts                # 构建脚本
├── camera_device/                   # 摄像头设备模块(手机/平板端)
│   ├── src/
│   │   ├── main/
│   │   │   ├── ets/
│   │   │   │   ├── services/       # 设备端服务
│   │   │   │   │   ├── CameraCapture.ets   # 摄像头采集服务
│   │   │   │   │   ├── LocalEncoder.ets     # 本地编码服务
│   │   │   │   │   ├── StreamServer.ets     # 流服务器
│   │   │   │   │   └── DeviceResponder.ets  # 设备响应服务
│   │   │   │   ├── utils/           # 工具类
│   │   │   │   │   ├── CodecUtil.ets        # 编解码工具
│   │   │   │   │   └── NetworkUtil.ets      # 网络工具
│   │   │   │   └── Application.ets  # 设备端入口
│   │   │   ├── resources/
│   │   │   └── module.json5
│   ├── build-profile.json5
│   └──hvigorfile.ts
└── library/                         # 公共库模块
    ├── src/
    │   ├── main/
    │   │   ├── ets/
    │   │   │   ├── common/          # 公共定义
    │   │   │   │   ├── Types.ets            # 类型定义
    │   │   │   │   ├── Constants.ets         # 常量定义
    │   │   │   │   └── Protocols.ets         # 协议定义
    │   │   │   └── utils/           # 公共工具
    │   │   │       ├── CryptoUtil.ets        # 加密工具
    │   │   │       └── TimeUtil.ets           # 时间工具
    │   │   ├── resources/
    │   │   └── module.json5
    ├── build-profile.json5
    └──hvigorfile.ts

5.2 权限配置

聚合控制器端 entry/src/main/module.json5
{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": ["phone", "tablet", "automotive"],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/application/Application.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:icon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["action.system.home"]
          }
        ]
      },
      {
        "name": "AggregationAbility",
        "srcEntry": "./ets/application/AggregationAbility.ets",
        "description": "摄像头聚合能力",
        "icon": "$media:aggregation_icon",
        "label": "$string:AggregationAbility_label",
        "exported": true,
        "backgroundModes": ["audioPlayback", "location", "dataTransfer"]
      }
    ],
    "requestPermissions": [
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC",
        "reason": "$string:distributed_datasync_reason",
        "usedScene": {
          "abilities": ["EntryAbility", "AggregationAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.CAMERA",
        "reason": "$string:camera_reason",
        "usedScene": {
          "abilities": ["AggregationAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.MICROPHONE",
        "reason": "$string:microphone_reason",
        "usedScene": {
          "abilities": ["AggregationAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.RECORD_AUDIO",
        "reason": "$string:record_audio_reason",
        "usedScene": {
          "abilities": ["AggregationAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.LOCATION",
        "reason": "$string:location_reason",
        "usedScene": {
          "abilities": ["AggregationAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.READ_MEDIA",
        "reason": "$string:read_media_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.WRITE_MEDIA",
        "reason": "$string:write_media_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_reason",
        "usedScene": {
          "abilities": ["AggregationAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.ACCESS_NETWORK_STATE",
        "reason": "$string:access_network_state_reason",
        "usedScene": {
          "abilities": ["AggregationAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.BIND_DISTRIBUTED_SERVICE",
        "reason": "$string:bind_distributed_service_reason",
        "usedScene": {
          "abilities": ["AggregationAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.USE_BLUETOOTH",
        "reason": "$string:use_bluetooth_reason",
        "usedScene": {
          "abilities": ["AggregationAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.DISCOVER_BLUETOOTH",
        "reason": "$string:discover_bluetooth_reason",
        "usedScene": {
          "abilities": ["AggregationAbility"],
          "when": "inuse"
        }
      }
    ],
    "extensionAbilities": [
      {
        "name": "AggregationExtAbility",
        "type": "service",
        "srcEntry": "./ets/service/StreamAggregator.ets",
        "description": "流聚合后台服务",
        "exported": true,
        "backgroundModes": ["dataTransfer", "audioPlayback", "location"]
      },
      {
        "name": "DeviceDiscoveryExtAbility",
        "type": "service",
        "srcEntry": "./ets/service/DeviceManager.ets",
        "description": "设备发现后台服务",
        "exported": true,
        "backgroundModes": ["dataTransfer"]
      }
    ],
    "definePermissions": [
      {
        "name": "com.example.multidevicecamera.permission.CAMERA_CONTROL",
        "grantMode": "system_grant",
        "availableLevel": "system_core",
        "description": "摄像头控制权限"
      },
      {
        "name": "com.example.multidevicecamera.permission.STREAM_ACCESS",
        "grantMode": "system_grant",
        "availableLevel": "system_core",
        "description": "视频流访问权限"
      }
    ]
  }
}
摄像头设备端 camera_device/src/main/module.json5
{
  "module": {
    "name": "camera_device",
    "type": "feature",
    "description": "$string:camera_device_module_desc",
    "mainElement": "CameraDeviceAbility",
    "deviceTypes": ["phone", "tablet"],
    "deliveryWithInstall": true,
    "installationFree": false,
    "abilities": [
      {
        "name": "CameraDeviceAbility",
        "srcEntry": "./ets/application/CameraDeviceApplication.ets",
        "description": "摄像头设备能力",
        "icon": "$media:camera_icon",
        "label": "$string:CameraDeviceAbility_label",
        "exported": true,
        "backgroundModes": ["audioPlayback", "dataTransfer"]
      }
    ],
    "requestPermissions": [
      {
        "name": "ohos.permission.CAMERA",
        "reason": "$string:camera_reason",
        "usedScene": {
          "abilities": ["CameraDeviceAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.RECORD_AUDIO",
        "reason": "$string:record_audio_reason",
        "usedScene": {
          "abilities": ["CameraDeviceAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC",
        "reason": "$string:distributed_datasync_reason",
        "usedScene": {
          "abilities": ["CameraDeviceAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_reason",
        "usedScene": {
          "abilities": ["CameraDeviceAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.ACCESS_NETWORK_STATE",
        "reason": "$string:access_network_state_reason",
        "usedScene": {
          "abilities": ["CameraDeviceAbility"],
          "when": "always"
        }
      }
    ],
    "extensionAbilities": [
      {
        "name": "CameraCaptureExtAbility",
        "type": "service",
        "srcEntry": "./ets/services/CameraCapture.ets",
        "description": "摄像头采集服务",
        "exported": true,
        "backgroundModes": ["audioPlayback", "dataTransfer"]
      }
    ]
  }
}

5.3 依赖配置

聚合控制器端 entry/build-profile.json5
{
  "apiType": "stageMode",
  "buildOption": {
    "strictMode": {
      "caseSensitiveCheck": true,
      "useNormalizedOHMUrl": true
    },
    "arkOptions": {
      "debug": false,
      "optimize": true
    }
  },
  "buildOptionSet": [
    {
      "name": "release",
      "arkOptions": {
        "debug": false,
        "optimize": true
      }
    }
  ],
  "targets": [
    {
      "name": "default",
      "applyToProducts": ["default"]
    }
  ],
  "products": [
    {
      "name": "default",
      "compatibleSdkVersion": "10",
      "runtimeOS": "HarmonyOS",
      "signingConfig": "default"
    }
  ],
  "dependencies": {
    "@ohos/distributedHardware.deviceManager": "10.0.0",
    "@ohos.multimedia.media": "10.0.0",
    "@ohos.multimedia.camera": "10.0.0",
    "@ohos.net.connection": "10.0.0",
    "@ohos.bluetooth": "10.0.0",
    "@ohos.ai.cv.vision": "10.0.0",
    "@ohos.utils": "10.0.0",
    "library": "file:../library"
  }
}

6. 详细代码实现

6.1 数据模型定义

聚合控制器端 entry/src/main/ets/model/CameraDevice.ets
/**
 * 摄像头设备数据模型
 */

/**
 * 设备基本信息
 */
export interface DeviceInfo {
  deviceId: string;            // 设备唯一标识
  deviceName: string;          // 设备名称
  deviceType: DeviceType;      // 设备类型
  brand: string;               // 品牌
  model: string;               // 型号
  osVersion: string;           // 操作系统版本
  isOnline: boolean;           // 是否在线
  lastActiveTime: number;      // 最后活跃时间
  ipAddress?: string;          // IP地址(可选)
  macAddress?: string;         // MAC地址(可选)
}

/**
 * 设备类型枚举
 */
export enum DeviceType {
  PHONE = "phone",             // 手机
  TABLET = "tablet",           // 平板
  SMART_DISPLAY = "smart_display", // 智慧屏
  ACTION_CAMERA = "action_camera", // 运动相机
  SECURITY_CAMERA = "security_camera", // 安防摄像头
  WEARABLE = "wearable"        // 可穿戴设备
}

/**
 * 摄像头能力描述
 */
export interface CameraCapability {
  cameraId: string;            // 摄像头ID
  facingType: CameraFacing;    // 朝向类型
  resolution: Resolution;      // 支持的分辨率列表
  frameRateRange: FrameRateRange; // 支持的帧率范围
  supportedFormats: VideoFormat[]; // 支持的视频格式
  opticalZoom: number;         // 光学变焦倍数
  digitalZoom: number;         // 数字变焦倍数
  hasFlash: boolean;           // 是否有闪光灯
  hasAutoFocus: boolean;       // 是否有自动对焦
  hasImageStabilization: boolean; // 是否有防抖
  minFocalLength: number;      // 最小焦距(mm)
  maxFocalLength: number;      // 最大焦距(mm)
  horizontalFOV: number;       // 水平视场角(度)
  verticalFOV: number;         // 垂直视场角(度)
  diagonalFOV: number;         // 对角线视场角(度)
}

/**
 * 摄像头朝向枚举
 */
export enum CameraFacing {
  FRONT = "front",             // 前置摄像头
  BACK = "back",               // 后置摄像头
  EXTERNAL = "external"        // 外接摄像头
}

/**
 * 分辨率定义
 */
export interface Resolution {
  width: number;               // 宽度
  height: number;              // 高度
  aspectRatio: number;         // 宽高比
}

/**
 * 帧率范围
 */
export interface FrameRateRange {
  min: number;                 // 最小帧率(fps)
  max: number;                 // 最大帧率(fps)
  step: number;                // 步长
}

/**
 * 视频格式
 */
export enum VideoFormat {
  YUV_420_888 = "YUV_420_888", // YUV420格式
  NV21 = "NV21",               // NV21格式
  JPEG = "JPEG",               // JPEG格式
  H264 = "H264",               // H.264编码
  H265 = "H265"                // H.265编码
}

/**
 * 摄像头设备完整信息
 */
export interface CameraDevice extends DeviceInfo {
  cameras: CameraCapability[]; // 摄像头能力列表
  currentCameraId?: string;    // 当前使用的摄像头ID
  batteryLevel?: number;       // 电池电量(0-100)
  storageSpace?: number;       // 存储空间(MB)
  cpuUsage?: number;           // CPU使用率(0-100)
  memoryUsage?: number;        // 内存使用率(0-100)
  networkType?: NetworkType;   // 网络类型
  signalStrength?: number;     // 信号强度(0-100)
  temperature?: number;        // 设备温度(摄氏度)
  isCharging?: boolean;        // 是否充电中
}

/**
 * 网络类型枚举
 */
export enum NetworkType {
  WIFI = "wifi",
  CELLULAR_4G = "cellular_4g",
  CELLULAR_5G = "cellular_5g",
  ETHERNET = "ethernet",
  OFFLINE = "offline"
}

/**
 * 视频流配置
 */
export interface StreamConfig {
  streamId: string;            // 流ID
  deviceId: string;            // 设备ID
  cameraId: string;            // 摄像头ID
  resolution: Resolution;      // 分辨率
  frameRate: number;           // 帧率
  videoFormat: VideoFormat;    // 视频格式
  bitrate: number;             // 比特率(kbps)
  keyframeInterval: number;    // 关键帧间隔(帧数)
  rotation: number;            // 旋转角度(0,90,180,270)
  mirror: boolean;             // 是否镜像
  quality: StreamQuality;      // 流质量等级
  adaptiveBitrate: boolean;    // 是否自适应码率
  priority: StreamPriority;    // 流优先级
}

/**
 * 流质量等级
 */
export enum StreamQuality {
  LOW = "low",                 // 低质量(480p)
  MEDIUM = "medium",           // 中等质量(720p)
  HIGH = "high",               // 高质量(1080p)
  ULTRA_HIGH = "ultra_high"    // 超高质量(4K)
}

/**
 * 流优先级
 */
export enum StreamPriority {
  CRITICAL = 0,                // 关键(主画面)
  HIGH = 1,                    // 高
  MEDIUM = 2,                  // 中
  LOW = 3,                     // 低
  BACKGROUND = 4               // 后台
}

/**
 * 视频流状态
 */
export interface StreamStatus {
  streamId: string;            // 流ID
  isActive: boolean;           // 是否激活
  actualResolution: Resolution; // 实际分辨率
  actualFrameRate: number;     // 实际帧率
  actualBitrate: number;       // 实际比特率
  packetLossRate: number;      // 丢包率(0-1)
  latency: number;             // 延迟(ms)
  jitter: number;              // 抖动(ms)
  bufferHealth: number;        // 缓冲区健康度(0-100)
  errorCode?: number;          // 错误码(可选)
  errorMessage?: string;        // 错误信息(可选)
  startTime: number;           // 开始时间
  dataReceived: number;        // 已接收数据量(bytes)
}

/**
 * 摄像头控制参数
 */
export interface CameraControl {
  deviceId: string;            // 设备ID
  cameraId: string;            // 摄像头ID
  zoomLevel?: number;          // 缩放级别(0.0-1.0)
  focusMode?: FocusMode;       // 对焦模式
  exposureCompensation?: number; // 曝光补偿(-2.0到+2.0)
  whiteBalance?: WhiteBalanceMode; // 白平衡模式
  iso?: number;                // ISO值
  shutterSpeed?: number;       // 快门速度(秒)
  aperture?: number;           // 光圈值
  torchMode?: TorchMode;       // 闪光灯模式
  stabilizationMode?: StabilizationMode; // 防抖模式
}

/**
 * 对焦模式枚举
 */
export enum FocusMode {
  AUTO = "auto",               // 自动对焦
  CONTINUOUS_AUTO = "continuous_auto", // 连续自动对焦
  MANUAL = "manual",           // 手动对焦
  INFINITY = "infinity",       // 无穷远
  FIXED = "fixed"              // 固定焦点
}

/**
 * 白平衡模式枚举
 */
export enum WhiteBalanceMode {
  AUTO = "auto",               // 自动
  SUNNY = "sunny",             // 晴天
  CLOUDY = "cloudy",           // 阴天
  INCANDESCENT = "incandescent", // 白炽灯
  FLUORESCENT = "fluorescent", // 荧光灯
  TWILIGHT = "twilight"        // 黄昏
}

/**
 * 闪光灯模式枚举
 */
export enum TorchMode {
  OFF = "off",                 // 关闭
  ON = "on",                   // 开启
  AUTO = "auto"                // 自动
}

/**
 * 防抖模式枚举
 */
export enum StabilizationMode {
  OFF = "off",                 // 关闭
  ON = "on",                   // 开启
  AUTO = "auto"                // 自动
}

/**
 * 云台控制参数
 */
export interface PTZControl {
  deviceId: string;            // 设备ID
  cameraId: string;            // 摄像头ID
  pan: number;                 // 水平角度(-180到+180度)
  tilt: number;                // 垂直角度(-90到+90度)
  zoom: number;                // 变焦级别(0.0-1.0)
  speed: number;               // 转动速度(0.0-1.0)
  absolute?: boolean;          // 是否为绝对位置(否则为相对移动)
  duration?: number;           // 动作持续时间(毫秒)
}

/**
 * 布局配置
 */
export interface LayoutConfig {
  layoutId: string;            // 布局ID
  name: string;                // 布局名称
  gridSize: { rows: number; cols: number }; // 网格大小
  windowPositions: WindowPosition[]; // 窗口位置列表
  transitionEffect: TransitionEffect; // 过渡效果
  backgroundColor: string;     // 背景颜色
  borderColor?: string;        // 边框颜色(可选)
  showLabels: boolean;         // 是否显示标签
  labelPosition: LabelPosition; // 标签位置
}

/**
 * 窗口位置
 */
export interface WindowPosition {
  streamId: string;            // 对应的流ID
  rect: Rectangle;             // 在布局中的位置矩形
  zOrder: number;              // 层级顺序
  isVisible: boolean;          // 是否可见
  opacity: number;             // 透明度(0.0-1.0)
  scaleType: ScaleType;        // 缩放类型
}

/**
 * 矩形区域
 */
export interface Rectangle {
  x: number;                   // X坐标
  y: number;                   // Y坐标
  width: number;               // 宽度
  height: number;              // 高度
}

/**
 * 缩放类型枚举
 */
export enum ScaleType {
  FIT_CENTER = "fit_center",   // 适应居中
  CROP_CENTER = "crop_center", // 裁剪居中
  FIT_XY = "fit_xy",           // 拉伸填充
  CENTER_INSIDE = "center_inside" // 内部居中
}

/**
 * 过渡效果枚举
 */
export enum TransitionEffect {
  NONE = "none",               // 无效果
  FADE = "fade",               // 淡入淡出
  SLIDE = "slide",             // 滑动
  ZOOM = "zoom",               // 缩放
  FLIP = "flip"                // 翻转
}

/**
 * 标签位置枚举
 */
export enum LabelPosition {
  TOP_LEFT = "top_left",       // 左上角
  TOP_CENTER = "top_center",   // 顶部居中
  TOP_RIGHT = "top_right",     // 右上角
  BOTTOM_LEFT = "bottom_left", // 左下角
  BOTTOM_CENTER = "bottom_center", // 底部居中
  BOTTOM_RIGHT = "bottom_right" // 右下角
}
聚合控制器端 entry/src/main/ets/model/VideoStream.ets
import { StreamConfig, StreamStatus, CameraDevice } from './CameraDevice';
import Logger from '../utils/Logger';

/**
 * 视频帧数据
 */
export interface VideoFrame {
  frameId: string;             // 帧唯一标识
  streamId: string;            // 所属流ID
  timestamp: number;           // 时间戳(微秒)
  pts: number;                 // 显示时间戳
  dts: number;                 // 解码时间戳
  width: number;               // 帧宽度
  height: number;              // 帧高度
  format: string;              // 像素格式
  data: ArrayBuffer;           // 帧数据
  isKeyFrame: boolean;         // 是否为关键帧
  metadata?: FrameMetadata;    // 元数据(可选)
}

/**
 * 帧元数据
 */
export interface FrameMetadata {
  exposureTime?: number;       // 曝光时间
  iso?: number;                // ISO值
  focalLength?: number;        // 焦距
  zoomLevel?: number;          // 缩放级别
  gpsLatitude?: number;        // GPS纬度
  gpsLongitude?: number;       // GPS经度
  deviceOrientation?: number;  // 设备方向
  lightIntensity?: number;     // 光照强度
  motionVector?: MotionVector; // 运动矢量
}

/**
 * 运动矢量
 */
export interface MotionVector {
  dx: number;                  // X方向位移
  dy: number;                  // Y方向位移
  magnitude: number;           // 幅度
  direction: number;           // 方向(角度)
}

/**
 * 视频流统计信息
 */
export interface StreamStatistics {
  streamId: string;            // 流ID
  deviceId: string;            // 设备ID
  startTime: number;           // 统计开始时间
  endTime?: number;            // 统计结束时间(可选)
  totalFrames: number;         // 总帧数
  droppedFrames: number;       // 丢弃帧数
  averageFps: number;          // 平均帧率
  averageBitrate: number;      // 平均比特率
  peakBitrate: number;         // 峰值比特率
  networkLatency: number;      // 网络延迟统计
  jitterStats: JitterStats;    // 抖动统计
  qualityMetrics: QualityMetrics; // 质量指标
}

/**
 * 抖动统计
 */
export interface JitterStats {
  minJitter: number;           // 最小抖动(ms)
  maxJitter: number;           // 最大抖动(ms)
  avgJitter: number;           // 平均抖动(ms)
  jitterEvents: number;        // 抖动事件次数
}

/**
 * 质量指标
 */
export interface QualityMetrics {
  psnr: number;                // 峰值信噪比
  ssim: number;                // 结构相似性
  vmaf?: number;               // 视频多方法评估融合(可选)
  blurScore: number;           // 模糊度评分
  noiseLevel: number;          // 噪声水平
  brightnessScore: number;     // 亮度评分
  contrastScore: number;       // 对比度评分
}

/**
 * 视频流管理器
 */
export class VideoStreamManager {
  private static instance: VideoStreamManager;
  private activeStreams: Map<string, VideoStreamWrapper> = new Map();
  private streamListeners: Map<string, Set<StreamEventListener>> = new Map();
  private statisticsInterval?: number;
  
  private constructor() {
    this.startStatisticsCollection();
  }
  
  /**
   * 获取单例实例
   */
  static getInstance(): VideoStreamManager {
    if (!VideoStreamManager.instance) {
      VideoStreamManager.instance = new VideoStreamManager();
    }
    return VideoStreamManager.instance;
  }
  
  /**
   * 添加视频流
   */
  addStream(streamConfig: StreamConfig, device: CameraDevice): boolean {
    try {
      Logger.i(`添加视频流: ${streamConfig.streamId}, 设备: ${device.deviceName}`, 'VideoStreamManager');
      
      if (this.activeStreams.has(streamConfig.streamId)) {
        Logger.w(`流已存在: ${streamConfig.streamId}`, 'VideoStreamManager');
        return false;
      }
      
      const streamWrapper: VideoStreamWrapper = {
        config: streamConfig,
        device: device,
        status: {
          streamId: streamConfig.streamId,
          isActive: false,
          actualResolution: streamConfig.resolution,
          actualFrameRate: streamConfig.frameRate,
          actualBitrate: streamConfig.bitrate,
          packetLossRate: 0,
          latency: 0,
          jitter: 0,
          bufferHealth: 100,
          startTime: Date.now()
        },
        frameQueue: [],
        statistics: {
          streamId: streamConfig.streamId,
          deviceId: device.deviceId,
          startTime: Date.now(),
          totalFrames: 0,
          droppedFrames: 0,
          averageFps: 0,
          averageBitrate: 0,
          peakBitrate: 0,
          networkLatency: 0,
          jitterStats: { minJitter: 0, maxJitter: 0, avgJitter: 0, jitterEvents: 0 },
          qualityMetrics: { psnr: 0, ssim: 0, blurScore: 0, noiseLevel: 0, brightnessScore: 0, contrastScore: 0 }
        }
      };
      
      this.activeStreams.set(streamConfig.streamId, streamWrapper);
      this.streamListeners.set(streamConfig.streamId, new Set());
      
      Logger.i(`视频流添加成功: ${streamConfig.streamId}`, 'VideoStreamManager');
      return true;
    } catch (error) {
      Logger.e(`添加视频流失败: ${streamConfig.streamId}`, 'VideoStreamManager', error as Error);
      return false;
    }
  }
  
  /**
   * 移除视频流
   */
  removeStream(streamId: string): boolean {
    try {
      Logger.i(`移除视频流: ${streamId}`, 'VideoStreamManager');
      
      if (!this.activeStreams.has(streamId)) {
        Logger.w(`流不存在: ${streamId}`, 'VideoStreamManager');
        return false;
      }
      
      // 通知监听器流即将移除
      this.notifyStreamEvent(streamId, {
        type: StreamEventType.STREAM_REMOVED,
        streamId: streamId,
        timestamp: Date.now(),
        data: { reason: 'user_requested' }
      });
      
      // 清理资源
      const wrapper = this.activeStreams.get(streamId)!;
      wrapper.frameQueue = [];
      this.streamListeners.delete(streamId);
      this.activeStreams.delete(streamId);
      
      Logger.i(`视频流移除成功: ${streamId}`, 'VideoStreamManager');
      return true;
    } catch (error) {
      Logger.e(`移除视频流失败: ${streamId}`, 'VideoStreamManager', error as Error);
      return false;
    }
  }
  
  /**
   * 推送视频帧
   */
  pushFrame(frame: VideoFrame): void {
    const wrapper = this.activeStreams.get(frame.streamId);
    if (!wrapper) {
      Logger.w(`未知的流ID: ${frame.streamId}`, 'VideoStreamManager');
      return;
    }
    
    // 更新统计信息
    wrapper.statistics.totalFrames++;
    wrapper.statistics.averageFps = wrapper.statistics.totalFrames / ((Date.now() - wrapper.statistics.startTime) / 1000);
    
    // 添加到帧队列(限制队列大小防止内存溢出)
    wrapper.frameQueue.push(frame);
    if (wrapper.frameQueue.length > 30) { // 保持约1秒的缓冲(30fps)
      const droppedFrame = wrapper.frameQueue.shift()!;
      wrapper.statistics.droppedFrames++;
      Logger.d(`丢弃帧: ${droppedFrame.frameId}`, 'VideoStreamManager');
    }
    
    // 通知帧可用
    this.notifyFrameAvailable(frame.streamId, frame);
  }
  
  /**
   * 获取视频帧
   */
  getFrame(streamId: string, timeoutMs: number = 100): VideoFrame | null {
    const wrapper = this.activeStreams.get(streamId);
    if (!wrapper) {
      return null;
    }
    
    const startTime = Date.now();
    while (Date.now() - startTime < timeoutMs) {
      if (wrapper.frameQueue.length > 0) {
        return wrapper.frameQueue.shift()!;
      }
      // 在实际应用中应该使用异步机制,这里简化处理
      this.sleep(10);
    }
    
    return null; // 超时
  }
  
  /**
   * 启动流
   */
  startStream(streamId: string): boolean {
    const wrapper = this.activeStreams.get(streamId);
    if (!wrapper) {
      return false;
    }
    
    wrapper.status.isActive = true;
    wrapper.status.startTime = Date.now();
    
    this.notifyStreamEvent(streamId, {
      type: StreamEventType.STREAM_STARTED,
      streamId: streamId,
      timestamp: Date.now(),
      data: { config: wrapper.config }
    });
    
    Logger.i(`视频流启动: ${streamId}`, 'VideoStreamManager');
    return true;
  }
  
  /**
   * 停止流
   */
  stopStream(streamId: string): boolean {
    const wrapper = this.activeStreams.get(streamId);
    if (!wrapper) {
      return false;
    }
    
    wrapper.status.isActive = false;
    
    this.notifyStreamEvent(streamId, {
      type: StreamEventType.STREAM_STOPPED,
      streamId: streamId,
      timestamp: Date.now(),
      data: { reason: 'user_requested' }
    });
    
    Logger.i(`视频流停止: ${streamId}`, 'VideoStreamManager');
    return true;
  }
  
  /**
   * 更新流状态
   */
  updateStreamStatus(streamId: string, status: Partial<StreamStatus>): boolean {
    const wrapper = this.activeStreams.get(streamId);
    if (!wrapper) {
      return false;
    }
    
    Object.assign(wrapper.status, status);
    
    this.notifyStreamEvent(streamId, {
      type: StreamEventType.STATUS_UPDATED,
      streamId: streamId,
      timestamp: Date.now(),
      data: { status: wrapper.status }
    });
    
    return true;
  }
  
  /**
   * 注册流事件监听器
   */
  addStreamListener(streamId: string, listener: StreamEventListener): void {
    const listeners = this.streamListeners.get(streamId);
    if (listeners) {
      listeners.add(listener);
    }
  }
  
  /**
   * 移除流事件监听器
   */
  removeStreamListener(streamId: string, listener: StreamEventListener): void {
    const listeners = this.streamListeners.get(streamId);
    if (listeners) {
      listeners.delete(listener);
    }
  }
  
  /**
   * 获取流统计信息
   */
  getStreamStatistics(streamId: string): StreamStatistics | undefined {
    const wrapper = this.activeStreams.get(streamId);
    return wrapper?.statistics;
  }
  
  /**
   * 获取所有活跃流
   */
  getAllActiveStreams(): VideoStreamWrapper[] {
    return Array.from(this.activeStreams.values()).filter(wrapper => wrapper.status.isActive);
  }
  
  /**
   * 开始统计数据收集
   */
  private startStatisticsCollection(): void {
    this.statisticsInterval = setInterval(() => {
      this.collectStatistics();
    }, 5000); // 每5秒收集一次统计
  }
  
  /**
   * 收集统计信息
   */
  private collectStatistics(): void {
    this.activeStreams.forEach((wrapper, streamId) => {
      if (wrapper.status.isActive) {
        // 更新网络延迟(模拟)
        wrapper.status.latency = 20 + Math.random() * 30;
        wrapper.status.jitter = Math.random() * 10;
        wrapper.status.packetLossRate = Math.random() * 0.01;
        
        // 更新缓冲区健康度
        wrapper.status.bufferHealth = Math.max(0, Math.min(100, 100 - wrapper.frameQueue.length));
        
        // 更新实际比特率(模拟)
        const expectedBitrate = wrapper.config.bitrate;
        wrapper.status.actualBitrate = expectedBitrate * (0.8 + Math.random() * 0.4);
        
        // 更新统计信息
        wrapper.statistics.averageBitrate = wrapper.status.actualBitrate;
        wrapper.statistics.peakBitrate = Math.max(wrapper.statistics.peakBitrate, wrapper.status.actualBitrate);
        wrapper.statistics.networkLatency = wrapper.status.latency;
        
        // 检查质量
        if (wrapper.status.packetLossRate > 0.05) {
          Logger.w(`流${streamId}丢包率过高: ${(wrapper.status.packetLossRate * 100).toFixed(2)}%`, 'VideoStreamManager');
        }
        
        if (wrapper.status.latency > 100) {
          Logger.w(`流${streamId}延迟过高: ${wrapper.status.latency.toFixed(2)}ms`, 'VideoStreamManager');
        }
      }
    });
  }
  
  /**
   * 通知流事件
   */
  private notifyStreamEvent(streamId: string, event: StreamEvent): void {
    const listeners = this.streamListeners.get(streamId);
    if (listeners) {
      listeners.forEach(listener => {
        try {
          listener.onStreamEvent(event);
        } catch (error) {
          Logger.e(`流事件回调异常: ${streamId}`, 'VideoStreamManager', error as Error);
        }
      });
    }
  }
  
  /**
   * 通知帧可用
   */
  private notifyFrameAvailable(streamId: string, frame: VideoFrame): void {
    const listeners = this.streamListeners.get(streamId);
    if (listeners) {
      listeners.forEach(listener => {
        try {
          if (listener.onFrameAvailable) {
            listener.onFrameAvailable(frame);
          }
        } catch (error) {
          Logger.e(`帧可用回调异常: ${streamId}`, 'VideoStreamManager', error as Error);
        }
      });
    }
  }
  
  /**
   * 睡眠函数
   */
  private sleep(ms: number): void {
    const start = Date.now();
    while (Date.now() - start < ms) {
      // 空循环实现简单睡眠
    }
  }
  
  /**
   * 释放资源
   */
  release(): void {
    if (this.statisticsInterval) {
      clearInterval(this.statisticsInterval);
      this.statisticsInterval = undefined;
    }
    
    this.activeStreams.clear();
    this.streamListeners.clear();
    
    Logger.i('视频流管理器资源已释放', 'VideoStreamManager');
  }
}

/**
 * 视频流包装器
 */
export interface VideoStreamWrapper {
  config: StreamConfig;         // 流配置
  device: CameraDevice;         // 关联设备
  status: StreamStatus;         // 流状态
  frameQueue: VideoFrame[];     // 帧队列
  statistics: StreamStatistics; // 统计信息
}

/**
 * 流事件类型枚举
 */
export enum StreamEventType {
  STREAM_STARTED = "stream_started",
  STREAM_STOPPED = "stream_stopped",
  STREAM_REMOVED = "stream_removed",
  STATUS_UPDATED = "status_updated",
  FRAME_DROPPED = "frame_dropped",
  ERROR_OCCURRED = "error_occurred",
  QUALITY_CHANGED = "quality_changed"
}

/**
 * 流事件
 */
export interface StreamEvent {
  type: StreamEventType;        // 事件类型
  streamId: string;             // 流ID
  timestamp: number;            // 时间戳
  data: any;                    // 事件数据
}

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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