HarmonyOS跨设备屏幕镜像开发小知识
小知识
前面聊了分布式窗口,那是"窗口级"的投射。但有时候我们需要更彻底的方案——把整个屏幕都镜像过去。
想象这样一个场景:你在做产品演示,需要把手机上的操作实时展示给会议室里的人看。用分布式窗口?太麻烦了,每个应用都要单独配置。这时候分布式屏幕镜像就派上用场了——一键把整个手机屏幕镜像到大屏,所见即所得。
或者你在玩游戏,想在电视的大屏幕上玩,但手机还要当手柄用。这时候就需要屏幕镜像+输入分离——画面投射到电视,但触摸操作还在手机上处理。
分布式屏幕镜像是HarmonyOS分布式能力的"核武器"——威力大,但也要慎用。它会把整个屏幕的内容都传输过去,数据量大、延迟敏感,对网络要求高。但用对了场景,体验提升是立竿见影的。
核心原理
屏幕镜像架构
分布式屏幕镜像涉及以下几个核心模块:
- ScreenCapture:屏幕捕获模块,负责截取屏幕内容
- ScreenEncoder:屏幕编码模块,负责视频编码压缩
- ScreenTransport:屏幕传输模块,负责网络传输
- ScreenDecoder:屏幕解码模块,在目标设备解码
- ScreenRender:屏幕渲染模块,在目标设备显示

镜像模式分类
分布式屏幕支持多种镜像模式:
1. 纯镜像模式:完全复制源屏幕,包括所有内容和交互
2. 扩展屏模式:目标设备作为扩展显示器,可以显示不同内容
3. 演示模式:只传输画面,输入事件在源设备处理
4. 协作模式:双向同步,两端都可以操作
性能关键指标
屏幕镜像对性能要求极高,关键指标包括:
- 帧率:至少30fps,流畅需要60fps
- 延迟:端到端延迟应控制在100ms以内
- 码率:根据分辨率和网络动态调整
- 分辨率:支持动态调整以适应网络状况
代码实战
示例一:基础屏幕镜像
这是最基础的屏幕镜像实现,将手机屏幕完整镜像到电视。
// DistributedScreenMirror.ets
import screenCapture from '@ohos.screenCapture';
import image from '@ohos.multimedia.image';
import deviceManager from '@ohos.distributedDeviceManager';
import distributedScreen from '@ohos.distributedScreen';
export class DistributedScreenMirror {
private context: common.UIAbilityContext;
private deviceManager: deviceManager.DeviceManager | null = null;
// 屏幕捕获实例
private capture: screenCapture.ScreenCapture | null = null;
// 屏幕镜像会话
private mirrorSession: distributedScreen.MirrorSession | null = null;
// 镜像状态
private mirrorState: MirrorState = {
isMirroring: false,
targetDeviceId: '',
frameRate: 30,
bitrate: 4000000,
resolution: { width: 1920, height: 1080 }
};
constructor(context: common.UIAbilityContext) {
this.context = context;
}
// 初始化
async initialize(): Promise<void> {
console.info('[ScreenMirror] Initializing...');
try {
// 初始化设备管理器
this.deviceManager = deviceManager.createDeviceManager(
this.context.applicationInfo.name
);
// 初始化屏幕捕获
await this.initScreenCapture();
console.info('[ScreenMirror] Initialized');
} catch (error) {
console.error('[ScreenMirror] Init failed:', error);
throw error;
}
}
// 初始化屏幕捕获
private async initScreenCapture(): Promise<void> {
// 获取主显示器信息
const displayInfo = await this.getMainDisplayInfo();
// 创建屏幕捕获配置
const captureConfig: screenCapture.CaptureConfig = {
// 捕获区域:整个屏幕
captureRect: {
left: 0,
top: 0,
width: displayInfo.width,
height: displayInfo.height
},
// 捕获参数
captureParam: {
// 数据格式:RGBA
pixelFormat: image.PixelMapFormat.RGBA_8888,
// 帧率
frameRate: this.mirrorState.frameRate
}
};
// 创建屏幕捕获实例
this.capture = await screenCapture.createScreenCapture(captureConfig);
console.info('[ScreenMirror] Screen capture created');
}
// 开始屏幕镜像
async startMirror(targetDeviceId: string, options?: MirrorOptions): Promise<boolean> {
console.info('[ScreenMirror] Starting mirror to:', targetDeviceId);
if (this.mirrorState.isMirroring) {
console.warn('[ScreenMirror] Already mirroring');
return false;
}
try {
// 检查目标设备是否在线
if (!await this.checkDeviceOnline(targetDeviceId)) {
console.error('[ScreenMirror] Target device offline');
return false;
}
// 获取目标设备显示信息
const targetDisplay = await this.getTargetDisplayInfo(targetDeviceId);
// 创建镜像配置
const mirrorConfig: distributedScreen.MirrorConfig = {
targetDeviceId: targetDeviceId,
// 镜像模式
mode: options?.mode || distributedScreen.MirrorMode.MIRROR_FULL,
// 编码配置
encoding: {
codec: options?.codec || 'h264',
bitrate: options?.bitrate || this.calculateOptimalBitrate(targetDisplay),
frameRate: options?.frameRate || 30,
keyFrameInterval: 2, // 每2秒一个关键帧
profile: 'high' // H.264 High Profile
},
// 分辨率配置
resolution: {
width: targetDisplay.width,
height: targetDisplay.height,
scaleMode: 'fit' // 保持比例适配
},
// 传输配置
transport: {
protocol: 'udp', // UDP协议,低延迟
bufferSize: 1024 * 1024, // 1MB缓冲区
retryCount: 3, // 重试次数
timeout: 5000 // 超时时间
},
// 输入配置
input: {
routeToSource: options?.routeInputToSource ?? true, // 输入路由到源设备
enableRemoteControl: options?.enableRemoteControl ?? false
}
};
// 创建镜像会话
this.mirrorSession = await distributedScreen.createMirrorSession(mirrorConfig);
// 设置事件监听
this.setupMirrorListeners();
// 启动屏幕捕获
await this.capture?.startCapture();
// 开始镜像传输
await this.mirrorSession.start();
// 更新状态
this.mirrorState.isMirroring = true;
this.mirrorState.targetDeviceId = targetDeviceId;
console.info('[ScreenMirror] Mirror started');
return true;
} catch (error) {
console.error('[ScreenMirror] Start failed:', error);
return false;
}
}
// 设置镜像监听器
private setupMirrorListeners(): void {
if (!this.mirrorSession) return;
// 监听连接状态
this.mirrorSession.on('connectionState', (state: distributedScreen.ConnectionState) => {
console.info('[ScreenMirror] Connection state:', state);
switch (state) {
case distributedScreen.ConnectionState.CONNECTED:
this.onMirrorConnected();
break;
case distributedScreen.ConnectionState.DISCONNECTED:
this.onMirrorDisconnected();
break;
case distributedScreen.ConnectionState.ERROR:
this.onMirrorError();
break;
}
});
// 监听性能指标
this.mirrorSession.on('performanceMetrics', (metrics: PerformanceMetrics) => {
this.handlePerformanceMetrics(metrics);
});
// 监听远程输入事件
this.mirrorSession.on('remoteInput', (event: InputEvent) => {
this.handleRemoteInput(event);
});
// 监听网络状态变化
this.mirrorSession.on('networkChange', (networkInfo: NetworkInfo) => {
this.handleNetworkChange(networkInfo);
});
}
// 镜像连接成功
private onMirrorConnected(): void {
console.info('[ScreenMirror] Mirror connected');
// 开始捕获帧并发送
this.startFrameCapture();
}
// 镜像断开连接
private onMirrorDisconnected(): void {
console.info('[ScreenMirror] Mirror disconnected');
this.mirrorState.isMirroring = false;
this.stopFrameCapture();
}
// 镜像错误
private onMirrorError(): void {
console.error('[ScreenMirror] Mirror error');
// 尝试重连
this.retryMirror();
}
// 开始帧捕获
private startFrameCapture(): void {
if (!this.capture || !this.mirrorSession) return;
// 设置帧回调
this.capture.on('frameAvailable', async (pixelMap: image.PixelMap) => {
try {
// 发送帧到镜像会话
await this.mirrorSession?.sendFrame(pixelMap);
} catch (error) {
console.error('[ScreenMirror] Send frame failed:', error);
}
});
}
// 停止帧捕获
private stopFrameCapture(): void {
this.capture?.off('frameAvailable');
}
// 处理性能指标
private handlePerformanceMetrics(metrics: PerformanceMetrics): void {
console.info('[ScreenMirror] FPS:', metrics.fps,
', Latency:', metrics.latency, 'ms',
', Bitrate:', metrics.bitrate / 1000, 'kbps');
// 根据性能动态调整参数
if (metrics.fps < 20) {
// 帧率过低,降低分辨率或码率
this.adjustEncodingForBetterPerformance();
} else if (metrics.latency > 150) {
// 延迟过高,降低码率
this.adjustBitrate(metrics.bitrate * 0.8);
}
}
// 处理远程输入
private handleRemoteInput(event: InputEvent): void {
console.info('[ScreenMirror] Remote input:', event.type);
// 根据配置决定是否转发到源设备
if (this.mirrorState.routeInputToSource) {
this.forwardInputToSource(event);
}
}
// 处理网络变化
private handleNetworkChange(networkInfo: NetworkInfo): void {
console.info('[ScreenMirror] Network changed, bandwidth:', networkInfo.bandwidth);
// 根据网络带宽调整码率
const newBitrate = this.calculateBitrateForBandwidth(networkInfo.bandwidth);
this.adjustBitrate(newBitrate);
}
// 调整编码参数以提升性能
private async adjustEncodingForBetterPerformance(): Promise<void> {
if (!this.mirrorSession) return;
// 降低分辨率
const newResolution = {
width: this.mirrorState.resolution.width * 0.8,
height: this.mirrorState.resolution.height * 0.8
};
await this.mirrorSession.updateConfig({
resolution: newResolution
});
this.mirrorState.resolution = newResolution;
console.info('[ScreenMirror] Resolution adjusted to:', newResolution);
}
// 调整码率
private async adjustBitrate(newBitrate: number): Promise<void> {
if (!this.mirrorSession) return;
await this.mirrorSession.updateConfig({
encoding: {
bitrate: newBitrate
}
});
this.mirrorState.bitrate = newBitrate;
console.info('[ScreenMirror] Bitrate adjusted to:', newBitrate);
}
// 计算最优码率
private calculateOptimalBitrate(display: DisplayInfo): number {
// 基于分辨率和帧率计算
const pixels = display.width * display.height;
const baseBitrate = pixels * this.mirrorState.frameRate * 0.1; // 经验系数
// 限制在合理范围
return Math.min(Math.max(baseBitrate, 1000000), 10000000); // 1-10Mbps
}
// 根据带宽计算码率
private calculateBitrateForBandwidth(bandwidth: number): number {
// 留出20%余量
return bandwidth * 0.8;
}
// 转发输入到源设备
private forwardInputToSource(event: InputEvent): void {
// 实际实现需要派发输入事件
console.info('[ScreenMirror] Forwarding input to source');
}
// 重试镜像
private async retryMirror(): Promise<void> {
console.info('[ScreenMirror] Retrying mirror...');
await this.stopMirror();
// 等待3秒后重试
setTimeout(async () => {
await this.startMirror(this.mirrorState.targetDeviceId);
}, 3000);
}
// 停止屏幕镜像
async stopMirror(): Promise<void> {
console.info('[ScreenMirror] Stopping mirror');
if (!this.mirrorState.isMirroring) return;
try {
// 停止帧捕获
this.stopFrameCapture();
// 停止屏幕捕获
await this.capture?.stopCapture();
// 停止镜像会话
await this.mirrorSession?.stop();
this.mirrorSession = null;
// 更新状态
this.mirrorState.isMirroring = false;
console.info('[ScreenMirror] Mirror stopped');
} catch (error) {
console.error('[ScreenMirror] Stop failed:', error);
}
}
// 检查设备是否在线
private async checkDeviceOnline(deviceId: string): Promise<boolean> {
if (!this.deviceManager) return false;
const devices = this.deviceManager.getTrustedDeviceListSync();
return devices.some(d =>
d.deviceId === deviceId &&
d.deviceState === deviceManager.DeviceState.ONLINE
);
}
// 获取主显示器信息
private async getMainDisplayInfo(): Promise<DisplayInfo> {
// 实际实现需要调用display API
return { width: 1080, height: 2340, density: 3.0 };
}
// 获取目标设备显示信息
private async getTargetDisplayInfo(deviceId: string): Promise<DisplayInfo> {
// 实际实现需要查询远程设备
return { width: 1920, height: 1080, density: 1.0 };
}
// 销毁
destroy(): void {
this.stopMirror();
if (this.capture) {
screenCapture.releaseScreenCapture(this.capture);
this.capture = null;
}
if (this.deviceManager) {
deviceManager.releaseDeviceManager(this.deviceManager);
this.deviceManager = null;
}
}
}
// 接口定义
interface MirrorState {
isMirroring: boolean;
targetDeviceId: string;
frameRate: number;
bitrate: number;
resolution: { width: number; height: number };
}
interface MirrorOptions {
mode?: distributedScreen.MirrorMode;
codec?: string;
bitrate?: number;
frameRate?: number;
routeInputToSource?: boolean;
enableRemoteControl?: boolean;
}
interface DisplayInfo {
width: number;
height: number;
density: number;
}
interface PerformanceMetrics {
fps: number;
latency: number;
bitrate: number;
packetLoss: number;
}
interface InputEvent {
type: string;
data: any;
timestamp: number;
}
interface NetworkInfo {
bandwidth: number;
latency: number;
quality: 'excellent' | 'good' | 'fair' | 'poor';
}
示例二:多屏镜像与切换
支持同时镜像到多个设备,并可以在设备间切换。
// MultiScreenMirror.ets
import distributedScreen from '@ohos.distributedScreen';
export class MultiScreenMirror {
// 活跃的镜像会话
private activeMirrors: Map<string, distributedScreen.MirrorSession> = new Map();
// 主镜像设备
private primaryDeviceId: string = '';
// 屏幕捕获(共享)
private capture: screenCapture.ScreenCapture | null = null;
// 帧分发器
private frameDispatcher: FrameDispatcher | null = null;
// 镜像到多个设备
async mirrorToMultiple(
targetDevices: string[],
options?: MultiMirrorOptions
): Promise<Map<string, boolean>> {
console.info('[MultiMirror] Mirroring to', targetDevices.length, 'devices');
const results = new Map<string, boolean>();
// 初始化共享的屏幕捕获
await this.initSharedCapture();
// 初始化帧分发器
this.frameDispatcher = new FrameDispatcher(this.capture!);
// 并行创建镜像会话
const promises = targetDevices.map(async (deviceId) => {
try {
const session = await this.createMirrorSession(deviceId, options);
this.activeMirrors.set(deviceId, session);
// 注册到帧分发器
this.frameDispatcher?.addTarget(deviceId, session);
results.set(deviceId, true);
} catch (error) {
console.error('[MultiMirror] Failed for device:', deviceId, error);
results.set(deviceId, false);
}
});
await Promise.all(promises);
// 设置第一个成功的设备为主设备
for (const [deviceId, success] of results) {
if (success) {
this.primaryDeviceId = deviceId;
break;
}
}
// 开始帧分发
this.frameDispatcher?.start();
return results;
}
// 创建镜像会话
private async createMirrorSession(
deviceId: string,
options?: MultiMirrorOptions
): Promise<distributedScreen.MirrorSession> {
const displayInfo = await this.getTargetDisplayInfo(deviceId);
const config: distributedScreen.MirrorConfig = {
targetDeviceId: deviceId,
mode: distributedScreen.MirrorMode.MIRROR_FULL,
encoding: {
codec: 'h264',
bitrate: options?.bitrate || this.calculateBitrate(displayInfo),
frameRate: 30
},
resolution: {
width: displayInfo.width,
height: displayInfo.height
}
};
const session = await distributedScreen.createMirrorSession(config);
await session.start();
return session;
}
// 切换主设备
async switchPrimaryDevice(newPrimaryId: string): Promise<boolean> {
console.info('[MultiMirror] Switching primary to:', newPrimaryId);
if (!this.activeMirrors.has(newPrimaryId)) {
console.error('[MultiMirror] Device not in active mirrors');
return false;
}
// 更新主设备
const oldPrimary = this.primaryDeviceId;
this.primaryDeviceId = newPrimaryId;
// 通知帧分发器优先级变化
this.frameDispatcher?.setPriority(newPrimaryId, 'high');
if (oldPrimary) {
this.frameDispatcher?.setPriority(oldPrimary, 'normal');
}
return true;
}
// 添加新的镜像目标
async addTargetDevice(deviceId: string): Promise<boolean> {
console.info('[MultiMirror] Adding target:', deviceId);
if (this.activeMirrors.has(deviceId)) {
console.warn('[MultiMirror] Device already in mirrors');
return false;
}
try {
const session = await this.createMirrorSession(deviceId);
this.activeMirrors.set(deviceId, session);
this.frameDispatcher?.addTarget(deviceId, session);
return true;
} catch (error) {
console.error('[MultiMirror] Add failed:', error);
return false;
}
}
// 移除镜像目标
async removeTargetDevice(deviceId: string): Promise<void> {
console.info('[MultiMirror] Removing target:', deviceId);
const session = this.activeMirrors.get(deviceId);
if (session) {
await session.stop();
this.activeMirrors.delete(deviceId);
this.frameDispatcher?.removeTarget(deviceId);
}
// 如果移除的是主设备,需要重新选择
if (this.primaryDeviceId === deviceId) {
this.primaryDeviceId = this.activeMirrors.keys().next().value || '';
}
}
// 停止所有镜像
async stopAll(): Promise<void> {
console.info('[MultiMirror] Stopping all mirrors');
// 停止帧分发
this.frameDispatcher?.stop();
// 停止所有会话
const promises = Array.from(this.activeMirrors.values()).map(session => {
return session.stop().catch(err => {
console.error('[MultiMirror] Stop session failed:', err);
});
});
await Promise.all(promises);
this.activeMirrors.clear();
this.primaryDeviceId = '';
}
// 获取镜像状态
getMirrorStatus(): MirrorStatusReport {
return {
activeDeviceCount: this.activeMirrors.size,
primaryDevice: this.primaryDeviceId,
activeDevices: Array.from(this.activeMirrors.keys()),
isMirroring: this.activeMirrors.size > 0
};
}
// 辅助方法
private async initSharedCapture(): Promise<void> {
// 实际实现
}
private async getTargetDisplayInfo(deviceId: string): Promise<DisplayInfo> {
return { width: 1920, height: 1080, density: 1.0 };
}
private calculateBitrate(display: DisplayInfo): number {
return 4000000;
}
}
// 帧分发器
class FrameDispatcher {
private capture: screenCapture.ScreenCapture;
private targets: Map<string, {
session: distributedScreen.MirrorSession;
priority: 'high' | 'normal' | 'low';
}> = new Map();
private isRunning: boolean = false;
private frameQueue: image.PixelMap[] = [];
private maxQueueSize: number = 3;
constructor(capture: screenCapture.ScreenCapture) {
this.capture = capture;
}
addTarget(deviceId: string, session: distributedScreen.MirrorSession): void {
this.targets.set(deviceId, { session, priority: 'normal' });
}
removeTarget(deviceId: string): void {
this.targets.delete(deviceId);
}
setPriority(deviceId: string, priority: 'high' | 'normal' | 'low'): void {
const target = this.targets.get(deviceId);
if (target) {
target.priority = priority;
}
}
start(): void {
this.isRunning = true;
this.capture.on('frameAvailable', (pixelMap: image.PixelMap) => {
if (!this.isRunning) return;
// 添加到队列
this.frameQueue.push(pixelMap);
// 限制队列大小
while (this.frameQueue.length > this.maxQueueSize) {
this.frameQueue.shift();
}
// 分发最新帧
this.dispatchFrame(pixelMap);
});
}
stop(): void {
this.isRunning = false;
this.capture.off('frameAvailable');
this.frameQueue = [];
}
private async dispatchFrame(frame: image.PixelMap): Promise<void> {
// 按优先级分发
const sortedTargets = Array.from(this.targets.entries())
.sort((a, b) => {
const priorityOrder = { high: 0, normal: 1, low: 2 };
return priorityOrder[a[1].priority] - priorityOrder[b[1].priority];
});
for (const [deviceId, { session }] of sortedTargets) {
try {
await session.sendFrame(frame);
} catch (error) {
console.error('[FrameDispatcher] Send to', deviceId, 'failed:', error);
}
}
}
}
// 接口定义
interface MultiMirrorOptions {
bitrate?: number;
frameRate?: number;
}
interface MirrorStatusReport {
activeDeviceCount: number;
primaryDevice: string;
activeDevices: string[];
isMirroring: boolean;
}
示例三:自适应质量屏幕镜像
根据网络状况动态调整镜像质量,确保流畅体验。
// AdaptiveScreenMirror.ets
export class AdaptiveScreenMirror {
private mirrorSession: distributedScreen.MirrorSession | null = null;
// 质量配置
private qualityConfig: QualityConfig = {
resolution: { width: 1920, height: 1080 },
bitrate: 4000000,
frameRate: 30,
quality: 'high'
};
// 网络监测
private networkMonitor: NetworkMonitor | null = null;
// 性能统计
private performanceStats: PerformanceStats = {
avgFps: 30,
avgLatency: 50,
avgBitrate: 4000000,
packetLossRate: 0
};
// 启动自适应镜像
async startAdaptiveMirror(targetDeviceId: string): Promise<void> {
// 创建镜像会话
this.mirrorSession = await this.createMirrorWithQuality(targetDeviceId, 'high');
// 启动网络监测
this.networkMonitor = new NetworkMonitor();
await this.networkMonitor.start();
// 启动自适应调节
this.startAdaptiveAdjustment();
}
// 启动自适应调节
private startAdaptiveAdjustment(): void {
// 每2秒评估一次
setInterval(async () => {
if (!this.mirrorSession) return;
// 收集性能数据
const metrics = await this.collectPerformanceMetrics();
this.updatePerformanceStats(metrics);
// 评估是否需要调整
const adjustment = this.evaluateAdjustment(metrics);
if (adjustment.needed) {
await this.applyAdjustment(adjustment);
}
}, 2000);
}
// 收集性能指标
private async collectPerformanceMetrics(): Promise<PerformanceMetrics> {
const sessionMetrics = await this.mirrorSession?.getMetrics();
const networkMetrics = this.networkMonitor?.getMetrics();
return {
fps: sessionMetrics?.fps || 30,
latency: sessionMetrics?.latency || 50,
bitrate: sessionMetrics?.bitrate || 4000000,
packetLoss: sessionMetrics?.packetLoss || 0,
networkBandwidth: networkMetrics?.bandwidth || 10000000,
networkLatency: networkMetrics?.latency || 20
};
}
// 更新性能统计
private updatePerformanceStats(metrics: PerformanceMetrics): void {
// 使用指数移动平均
const alpha = 0.3;
this.performanceStats.avgFps =
alpha * metrics.fps + (1 - alpha) * this.performanceStats.avgFps;
this.performanceStats.avgLatency =
alpha * metrics.latency + (1 - alpha) * this.performanceStats.avgLatency;
this.performanceStats.avgBitrate =
alpha * metrics.bitrate + (1 - alpha) * this.performanceStats.avgBitrate;
this.performanceStats.packetLossRate =
alpha * metrics.packetLoss + (1 - alpha) * this.performanceStats.packetLossRate;
}
// 评估是否需要调整
private evaluateAdjustment(metrics: PerformanceMetrics): Adjustment {
const issues: string[] = [];
let qualityChange: 'up' | 'down' | 'none' = 'none';
// 检查帧率
if (metrics.fps < 20) {
issues.push('fps_too_low');
qualityChange = 'down';
} else if (metrics.fps > 55 && this.qualityConfig.quality !== 'high') {
issues.push('fps_good_can_improve');
qualityChange = 'up';
}
// 检查延迟
if (metrics.latency > 150) {
issues.push('latency_too_high');
qualityChange = 'down';
}
// 检查丢包
if (metrics.packetLoss > 5) {
issues.push('packet_loss_high');
qualityChange = 'down';
}
// 检查网络带宽
const requiredBandwidth = metrics.bitrate * 1.2; // 留20%余量
if (metrics.networkBandwidth < requiredBandwidth) {
issues.push('bandwidth_insufficient');
qualityChange = 'down';
}
return {
needed: issues.length > 0,
issues: issues,
qualityChange: qualityChange
};
}
// 应用调整
private async applyAdjustment(adjustment: Adjustment): Promise<void> {
console.info('[AdaptiveMirror] Applying adjustment:', adjustment);
const currentQuality = this.qualityConfig.quality;
let newQuality = currentQuality;
if (adjustment.qualityChange === 'down') {
const qualityOrder = ['high', 'medium', 'low', 'very_low'];
const currentIndex = qualityOrder.indexOf(currentQuality);
if (currentIndex < qualityOrder.length - 1) {
newQuality = qualityOrder[currentIndex + 1] as QualityLevel;
}
} else if (adjustment.qualityChange === 'up') {
const qualityOrder = ['very_low', 'low', 'medium', 'high'];
const currentIndex = qualityOrder.indexOf(currentQuality);
if (currentIndex < qualityOrder.length - 1) {
newQuality = qualityOrder[currentIndex + 1] as QualityLevel;
}
}
if (newQuality !== currentQuality) {
await this.changeQuality(newQuality);
}
}
// 改变质量等级
private async changeQuality(newQuality: QualityLevel): Promise<void> {
console.info('[AdaptiveMirror] Changing quality to:', newQuality);
const qualitySettings = {
high: { resolution: { width: 1920, height: 1080 }, bitrate: 8000000, frameRate: 30 },
medium: { resolution: { width: 1280, height: 720 }, bitrate: 4000000, frameRate: 30 },
low: { resolution: { width: 960, height: 540 }, bitrate: 2000000, frameRate: 25 },
very_low: { resolution: { width: 640, height: 360 }, bitrate: 1000000, frameRate: 20 }
};
const settings = qualitySettings[newQuality];
await this.mirrorSession?.updateConfig({
resolution: settings.resolution,
encoding: {
bitrate: settings.bitrate,
frameRate: settings.frameRate
}
});
this.qualityConfig = {
...this.qualityConfig,
resolution: settings.resolution,
bitrate: settings.bitrate,
frameRate: settings.frameRate,
quality: newQuality
};
}
// 创建指定质量的镜像
private async createMirrorWithQuality(
deviceId: string,
quality: QualityLevel
): Promise<distributedScreen.MirrorSession> {
// 实际实现
return null as any;
}
}
// 网络监测器
class NetworkMonitor {
private metrics: NetworkMetrics = {
bandwidth: 10000000,
latency: 20,
quality: 'excellent'
};
async start(): Promise<void> {
// 定期测量网络状况
setInterval(async () => {
this.metrics = await this.measureNetwork();
}, 5000);
}
getMetrics(): NetworkMetrics {
return this.metrics;
}
private async measureNetwork(): Promise<NetworkMetrics> {
// 实际实现需要测量网络
return this.metrics;
}
}
// 接口定义
type QualityLevel = 'high' | 'medium' | 'low' | 'very_low';
interface QualityConfig {
resolution: { width: number; height: number };
bitrate: number;
frameRate: number;
quality: QualityLevel;
}
interface PerformanceStats {
avgFps: number;
avgLatency: number;
avgBitrate: number;
packetLossRate: number;
}
interface PerformanceMetrics {
fps: number;
latency: number;
bitrate: number;
packetLoss: number;
networkBandwidth: number;
networkLatency: number;
}
interface Adjustment {
needed: boolean;
issues: string[];
qualityChange: 'up' | 'down' | 'none';
}
interface NetworkMetrics {
bandwidth: number;
latency: number;
quality: string;
}
踰坑与注意事项
坑一:屏幕旋转时镜像异常
问题描述:源设备屏幕旋转时,镜像画面没有正确旋转,导致显示错乱。
解决方案:监听屏幕旋转并更新配置
import display from '@ohos.display';
// 监听屏幕旋转
display.on('change', (id: number) => {
const rotation = display.getDisplayById(id).rotation;
// 更新镜像配置
this.mirrorSession?.updateConfig({
rotation: rotation
});
});
坑二:隐私内容泄露
问题描述:镜像时可能不小心把隐私内容(如密码输入界面)投射出去。
解决方案:设置隐私区域或敏感应用过滤
const mirrorConfig: distributedScreen.MirrorConfig = {
// ... 其他配置
// 隐私保护
privacy: {
// 敏感应用列表,这些应用显示时暂停镜像
sensitiveApps: ['com.example.passwordmanager', 'com.example.bank'],
// 隐私区域(如状态栏通知区域)
privacyRegions: [
{ x: 0, y: 0, width: 1080, height: 50 } // 顶部状态栏
],
// 隐私区域处理方式
privacyAction: 'blur' // 模糊处理
}
};
坑三:性能消耗过大
问题描述:屏幕镜像消耗大量CPU和内存,导致源设备卡顿。
解决方案:使用硬件编码和优化配置
const encodingConfig = {
codec: 'h264',
// 使用硬件编码
useHardwareEncoder: true,
// 编码线程数
encoderThreads: 2,
// 编码优先级
priority: 'normal', // 不抢占UI线程资源
// 性能优化
performance: {
// 低延迟模式
lowLatency: true,
// 快速编码
fastEncode: true,
// 跳帧策略
skipFrameStrategy: 'auto'
}
};
HarmonyOS 6适配
新增HDR镜像支持
HarmonyOS 6支持HDR内容的屏幕镜像:
const mirrorConfig: distributedScreen.MirrorConfig = {
// ... 其他配置
hdr: {
enabled: true,
format: 'hdr10', // HDR10格式
toneMapping: 'auto' // 自动色调映射
}
};
增强的音频镜像
const mirrorConfig: distributedScreen.MirrorConfig = {
// ... 其他配置
audio: {
enabled: true,
codec: 'aac',
sampleRate: 48000,
channels: 2,
bitrate: 128000,
// 音频同步模式
syncMode: 'av_sync', // 音视频同步
// 音频延迟补偿
latencyCompensation: true
}
};
屏幕镜像录制
HarmonyOS 6支持在镜像的同时录制:
const mirrorConfig: distributedScreen.MirrorConfig = {
// ... 其他配置
recording: {
enabled: true,
outputPath: '/data/mirror_recording.mp4',
format: 'mp4',
maxDuration: 600, // 最长10分钟
maxSize: 500 * 1024 * 1024 // 最大500MB
}
};
总结
分布式屏幕镜像是最底层的跨设备显示能力,它把整个屏幕内容实时传输到目标设备。相比窗口级投射,屏幕镜像更简单直接,但也更消耗资源。
核心要点:
- 屏幕捕获与编码:高效捕获屏幕内容并进行视频编码
- 网络传输优化:低延迟、抗丢包的传输策略
- 自适应质量:根据网络和性能动态调整参数
- 多设备支持:同时镜像到多个设备并管理优先级
最佳实践:
- 使用硬件编码减轻CPU负担
- 实现自适应质量调节确保流畅体验
- 注意隐私保护,设置敏感区域过滤
- 监控性能指标并及时调整
- 处理屏幕旋转、分辨率变化等边界情况
分布式屏幕镜像适合演示、游戏投屏等需要完整屏幕内容的场景。下一篇我们将探讨分布式相机,看看如何实现跨设备的拍照与预览。
- 点赞
- 收藏
- 关注作者

评论(0)