0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

HarmonyOS应用视频投播解决方案

HarmonyOS开发者 来源:HarmonyOS开发者 2025-07-23 16:43 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

概述

系统投播功能让用户能够轻松将手机上的音视频投放到其他设备(如PC/2in1设备、华为智慧屏)上继续播放,实现跨设备切换,带来流畅的观影体验。为简化开发流程,系统提供了标准化的音视频投播解决方案,开发者仅需配置资源信息、监听投播状态并实现播放控制(如播放、暂停),即可快速集成该功能。

本文将结合实际案例,详细介绍如何高效利用系统投播组件和接口实现视频投播,帮助开发者提升开发效率,包含如下关键步骤:

接入播控中心播控中心系统提供的播放管理模块,可以后台管理应用播放任务,是投播接入的必备条件。

本端控制远端设备状态:手机端实现遥控器功能,直接控制远端设备的播放状态、进度、音量等。

远端视频状态回传本端:能够实时同步播放进度至手机端显示。

视频资源切换和设备切换:支持投播过程中集数的切换及投播设备的切换。

用户体验

体验

用户体验路径

本文案例提供本端播放和视频投播两种播放模式,体验路径和交互流程图如下。用户可以在本端和远端播放视频,在投播模式下,用户可以通过遥控界面实现快进/快退、切换上下集、音量调节(支持物理键控制)、进度条拖动跳转、选集切换控制功能,应用接入时,可根据实际需求参考本文实现,并按照应用接入播控自检表完成基础功能验证,确保应用基础体验。

fb481c98-63b6-11f0-a6aa-92fbcf53809c.png

实现原理

名词解释

fb64f142-63b6-11f0-a6aa-92fbcf53809c.png

投播功能的实现基于AVSession媒体会话和AVCastController投播控制器的协同工作:系统通过AVSession建立设备连接,由AVCastController向Cast+服务发送控制指令。开发者需要聚焦两个核心环节——通过AVSession实现监听设备连接,以及使用AVCastController控制远端播放并同步状态,详见运作机制。

fb790a2e-63b6-11f0-a6aa-92fbcf53809c.png

模块设计

建议应用封装三个模块:

VideoPlayerController:应用封装的本地视频控制器,控制本端视频资源的暂停、播放、进度、音量、倍速。

VideoSessionController:应用封装的媒体会话控制器,本端视频播放时用于本应用与播控中心的同步、切换设备发起投播、结束投播。

VideoCastController:应用封装的投播视频控制器,控制远端设备视频资源的暂停、播放、进度、音量、倍速。

完成投播功能,建议参考如下流程接入,其中本端视频显示和控制可参考视频播放组件、使用AVPlayer播放视频(ArkTS)、使用AVPlayer播放视频(C/C++)等视频实现方案根据功能诉求自行实现,本文从接入播控中心进行介绍。

fb900544-63b6-11f0-a6aa-92fbcf53809c.png

接入播控中心

投播功能依赖于播控中心,因此必须接入播控中心才能实现投播功能。播控中心不仅能够控制本端设备的播放,还能控制远端设备的播放。本章节将简要介绍应用接入播控中心的开发流程。

媒体会话初始化

1.avSession.createAVSession()创建avsession,类型为VIDEO_SESSION。

2.设置后台长时播放任务,确保应用退至后台后播放不会停止。

3.videoSession.setLaunchAbility()设置一个WantAgent用于拉起会话的Ability。

4.videoSession.activate()激活videoSession。

letvideoSession =awaitavSession.createAVSession(context,'VIDEO_SESSION','video');
// Set up a background task.
BackgroundTaskManager.startContinuousTask(context);
constwantAgentInfo: wantAgent.WantAgentInfo= {
wants: [
  {
  bundleName: context.abilityInfo.bundleName,
  abilityName: context.abilityInfo.name
  }
 ],
operationType: wantAgent.OperationType.START_ABILITIES,
requestCode:0,
wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
letagent = wantAgent.getWantAgent(wantAgentInfo);
videoSession.setLaunchAbility(agent);
videoSession.activate();
returnnewVideoSessionController(videoSession);

设置媒体会话元数据

videoSession.setAVMetadata()上传元数据,从而在播控中心界面进行展示。如媒体ID(assetId)、标题(title)、播控中心显示的图片(mediaImage)、媒体时长(duration)。

letmetadata: avSession.AVMetadata= {
assetId:`${curSource.index}`,
title: curSource.name,
mediaImage: headPixel,
duration: duration,
filter: avSession.ProtocolType.TYPE_DLNA| avSession.ProtocolType.TYPE_CAST_PLUS_STREAM
};
awaitthis.videoSession.setAVMetadata(metadata);

本应用播放状态同步到播控中心

当设置元数据后,播控中心会显示进度条并自动计算播放进度,但播放状态变更(如暂停、播放、进度跳转)、音量调节和倍速设置等操作不会自动同步到播控中心。开发者需要主动监听本地的播放状态变化(包括进度跳转、倍速调整、音量修改等事件),并主动将这些状态同步到播控中心,以确保两端状态一致。

以下是videoSession状态更新的示例代码,特别注意的是,在更新进度状态时,需要传入当前时间戳updateTime和视频播放的时间进度elapsedTime。

awaitthis.videoSession.setAVPlaybackState({
state: state ==='playing'? avSession.PlaybackState.PLAYBACK_STATE_PLAY:
 avSession.PlaybackState.PLAYBACK_STATE_PAUSE,
});

播控中心控制应用播放

当用户在播控中心进行操作(如播放、暂停、停止、进度跳转、快进、快退等)时,这些操作不会自动同步到应用端,开发者需要主动通过avCastController.on('controlCommand')监听这些事件,并在回调函数中主动更新应用播放器的状态以保持同步,例如在收到播放指令时调用本地播放器的play()方法,在收到跳转指令时调整播放进度等,确保播控中心与应用端的操作状态完全一致。

this.videoSession.on('play',() =>avPlayerController.setAVPlayerPlaying());
this.videoSession.on('pause',() =>avPlayerController.setAVPlayerPause());

说明: 这里注册的交互监听所有on()事件建议在退出播放页时通过videoSession.off()事件销毁。

投播基础功能

为确保投播功能正常使用,应用在发起投播前需要完成播控中心初始化。如未完成此关键步骤,则导致投播功能不可用。

创建投播

在完成创建投播后,远端设备即可正常播放视频,本端会停止播放并页面跳转。

创建投播时需要setExtras()告知系统可投播、绘制AVCastPicker、videosession监听设备改变事件,用户点击AVCastPicker组件后会弹出设备选择半模态,在选择设备后,应用需要设置投播媒体信息,调用prepare、start启动播放。时序图如下,具体实现见开发步骤:

时序图

fbe7bd3e-63b6-11f0-a6aa-92fbcf53809c.png

开发步骤

1.videosession创建后,创建投播前,声明当前应用支持投播。

awaitvideoSession.setExtras({
requireAbilityList: ['url-cast']
})

2.绘制AVCastPicker,AVCastPicker是投播组件,点击后系统会弹出设备选择半模态。

AVCastPicker({
 normalColor: Color.White,
 pickerStyle:AVCastPickerStyle.STYLE_PANEL,
 sessionType:'video',
// ...
})

3.当用户选择设备并设备切换成功后触发videoSession.on('outputDeviceChange')事件,应用可选择停止本地播放并跳转到遥控页面(或保持本端继续播放),此时播控中心会自动接管远端设备的播放控制,开发者无需额外设置。

videoSession.on('outputDeviceChange',async(connectState: avSession.ConnectionState,
device: avSession.OutputDeviceInfo) => {
 hilog.info(0x0000,TAG,`device${JSON.stringify(device)}`);
 hilog.info(0x0000,TAG,`connectState${JSON.stringify(connectState)}`);
// The linked device is a remote device.
if(device.devices[0].castCategory=== avSession.AVCastCategory.CATEGORY_REMOTE&&
  connectState === avSession.ConnectionState.STATE_CONNECTED) {
 // Page jump
 this.remoteControlPathStack.replacePath({name:'detail',param:this.currentTime});
 this.castingList.push(this.videoType);
 awaitthis.releaseAVPlayer();
 // The linked device is the local device.
 }elseif(device.devices[0].castCategory=== avSession.AVCastCategory.CATEGORY_REMOTE&&
  connectState === avSession.ConnectionState.STATE_DISCONNECTED) {
 if(this.avCastController) {
  awaitthis.avCastController.releaseAVCast();
  awaitthis.avSessionController!.stopCasting();
  this.avCastController=undefined;
  }
 }
// ...
})

4.设置avCastController资源,完成以下三步后远端设备即可投播视频,以播放网络资源为例。

1.构建avSession.AVQueueItem。需要传入assetId(播放列表媒体ID,应用自定义)、title(媒体标题)、artist(媒体专辑作者)、mediaUri(媒体URI)、mediaType(媒体类型)、mediaImage(媒体图片像素数据)、duration(媒体播放时长)。

2.avCastController.prepare(playItem)准备播放媒体资源,即进行播放资源的加载和缓冲。

3.avCastController.start(playItem)启动播放媒体资源。

letplayItem: avSession.AVQueueItem= {
itemId: videoIndex,
description: {
 assetId:'VIDEO-'+JSON.stringify(videoIndex),
 title:this.videoDataArray[videoIndex].name,
 artist:'ExampleArtist',
 mediaUri:this.videoDataArray[videoIndex].urlasstring,
 mediaType:'VIDEO',
 mediaImage: imgPixel,
 mediaSize:1000,
 startPosition: startPosition,
 duration:this.videoDataArray[videoIndex].duration
 }
};
awaitthis.avCastController.prepare(playItem);
awaitthis.avCastController.start(playItem);

若需要投播本地资源,需要打开沙箱文件,并在fdSrc中传入文件fd实现。

try{
letfile =awaitfileIo.open(context.filesDir+'/'+this.videoDataArray[videoIndex].url);
letavFileDescriptor: media.AVFileDescriptor= {fd: file.fd};
letplayItem: avSession.AVQueueItem= {
 itemId: videoIndex,
 description: {
  assetId:'VIDEO-'+JSON.stringify(videoIndex),
  title:this.videoDataArray[videoIndex].name,
  artist:'ExampleArtist',
  mediaType:'VIDEO',
  mediaImage: imgPixel,
  mediaSize:1000,
  fdSrc: avFileDescriptor,
  startPosition: startPosition,
  duration:this.videoDataArray[videoIndex].duration
  }
 };
awaitthis.avCastController.prepare(playItem);
awaitthis.avCastController.start(playItem);

设备切换

设备切换依赖于videosession监听设备改变事件,可以通过stopCasting终止投播切换设备,也可以通过avCastPicker.select()进行切换。均会触发videoSession.on('outputDeviceChange')事件,当切换到远端设备播放,本端应该跳转到遥控器界面,当切换回本端设备播放,应当停止投播并跳转到视频播放页面。应用时序图如下,具体实现见开发步骤。

时序图

fc11e7a8-63b6-11f0-a6aa-92fbcf53809c.png

开发步骤

可以直接使用AVCastPicker切换设备,系统会自动弹出设备选择半模态弹窗,用户可直接选择目标设备完成切换。开发者无需额外处理弹窗逻辑。也可以使用avCastPicker.select() 接口切换设备。

当设备切换时,videoSession.on

('outputDeviceChange')事件将被触发,开发者可在回调中处理设备切换逻辑:若切换至远端设备则跳转至遥控页面,若切回本端设备则恢复本地播放,实现播放控制的无缝切换。

videoSession.on('outputDeviceChange', async (connectState: avSession.ConnectionState,
 device: avSession.OutputDeviceInfo) => {
 hilog.info(0x0000, TAG, `device ${JSON.stringify(device)}`);
 hilog.info(0x0000, TAG, `connectState ${JSON.stringify(connectState)}`);
// The linked device is a remote device.
if(device.devices[0].castCategory === avSession.AVCastCategory.CATEGORY_REMOTE &&
  connectState === avSession.ConnectionState.STATE_CONNECTED) {
 // Page jump
 this.remoteControlPathStack.replacePath({ name:'detail', param:this.currentTime });
 this.castingList.push(this.videoType);
  awaitthis.releaseAVPlayer();
 // The linked device is the local device.
 }elseif(device.devices[0].castCategory === avSession.AVCastCategory.CATEGORY_LOCAL) {
 this.remoteControlPathStack.clear();
  let videoType =this.castingList[0];
 this.castingList = [];
  let videoPlayParam = new VideoPlayParam(videoType,0,this.avplayerContinueIndex);
 this.videoPlayPathStack.replacePath({ name:'detail', param: videoPlayParam });
 if(this.avCastController) {
   awaitthis.avCastController.releaseAVCast();
   awaitthis.avSessionController!.stopCasting();
  this.avCastController = undefined;
  }
 }
})

远端视频状态回传本端

当视频在远端设备播放时,为了控制远端视频的播放应用需要监听远端视频播放状态并同步显示本端,通过远端设备或本端播控中心控制,都会直接改变远端设备的播放状态,并触发avCastController.on('playbackStateChange')。应用时序图如下,具体实现见开发步骤。

时序图

fc2301d2-63b6-11f0-a6aa-92fbcf53809c.png

开发步骤

当需要在本地遥控界面同步显示远端视频的播放状态时,可通过avCastController.on

('playbackStateChange') 监听状态变化,并使用过滤器筛选目标状态。

建议使用@Track修饰器标记这些经常改变的状态变量,以便页面自动响应数据更新。该机制可统一获取播放状态(如播放/暂停)、音量、总时长及倍速等信息,以下代码以获取已播放时长为例:

@Observed
exportclassVideoCastController{
@Trackstate: avSession.PlaybackState= avSession.PlaybackState.PLAYBACK_STATE_INITIAL;
// ...
/**
 * Sets up AV cast playback state change callbacks.
 * Handles playback completion, position updates, volume changes and errors.
 */
setAVCastCallback() {
 this.avCastController.on('playbackStateChange', ['state'],async(playbackState: avSession.AVPlaybackState) => {
  if(playbackState.state) {
   this.state= playbackState.state;
   }
  });
 // ...
 }
// ...
}

本端控制远端设备状态

时序图

fc321dac-63b6-11f0-a6aa-92fbcf53809c.png

开发步骤

控制远端设备状态可通过avCastController.sendControlCommand()接口实现,支持多种播放控制命令,包括:暂停、停止、下一首、上一首、快进、快退、跳转、音量调节和倍速设置。只需修改command字段即可切换不同功能,具体命令与功能的对应关系请参考AVCastControlCommandType。

publicasyncsetAVCastPlay(){
letavCommand: avSession.AVCastControlCommand = { command:'play'};
awaitthis.avCastController.sendControlCommand(avCommand);
}

在控制跳转、音量调节和倍速设置时,需要传入时间(单位ms)、音量、倍速参数。

publicasyncsetAVCastSeek(timeMS:number) {
letavCommand: avSession.AVCastControlCommand= {command:'seek',parameter: timeMS };
awaitthis.avCastController.sendControlCommand(avCommand);
}
publicasyncsetAVCastVolume(volume:number) {
letavCommand: avSession.AVCastControlCommand= {command:'setVolume',parameter: volume };
awaitthis.avCastController.sendControlCommand(avCommand);
}
publicasyncsetAVCastSpeed(speed: media.PlaybackSpeed) {
letavCommand: avSession.AVCastControlCommand= {command:'setSpeed',parameter: speed };
awaitthis.avCastController.sendControlCommand(avCommand);
}

资源切换

在完成本集播放/用户触发集数切换时不需要断开连接,重新设置资源即可。

1.构建avSession.AVQueueItem。

2.avCastController.prepare(playItem)。

3.avCastController.start(playItem)。

letplayItem: avSession.AVQueueItem= {
itemId: videoIndex,
description: {
 assetId:'VIDEO-'+JSON.stringify(videoIndex),
 title:this.videoDataArray[videoIndex].name,
 subtitle:'video',
 mediaUri:this.videoDataArray[videoIndex].urlasstring,
 mediaType:'VIDEO',
 mediaImage: imgPixel,
 startPosition: startPosition,
 duration:this.videoDataArray[videoIndex].duration
 }
};
awaitthis.avCastController.prepare(playItem);
awaitthis.avCastController.start(playItem);

扩展功能

悬浮球快捷控制

建议应用集成悬浮球快捷控制功能,便于用户快速返回投播页面进行操作控制,实现效果如图:

可以通过为页面设置浮层实现。

.overlay(this.OverlayNode(), {
 align: Alignment.BottomEnd,
 offset: {x: -24,
 y: -136}
})
@Builder
OverlayNode(){
// ...
}

手机物理音量键同步远端

音量同步需要通过遥控器页面的焦点管理和按键监听实现,具体流程为:当遥控器页面获焦时,监听音量加减按键事件,在事件回调中调用音量调节函数并同步更新播控中心状态。典型实现示例如下:

letupOptions: inputConsumer.KeyPressedConfig= {
key:KeyCode.KEYCODE_VOLUME_UP,
action:1,
isRepeat:true,
}
inputConsumer.on('keyPressed', upOptions,async()=> {
if(this.avCastPlayerController) {
 console.log('currentVolume'+JSON.stringify(this.currentVolume));
 letvolume =this.currentVolume+10;
 awaitthis.avCastPlayerController.setAVCastVolume(volume);
 }
})
letdownOptions: inputConsumer.KeyPressedConfig= {
key:KeyCode.KEYCODE_VOLUME_DOWN,
action:1,
isRepeat:true,
}
inputConsumer.on('keyPressed', downOptions,async()=> {
if(this.avCastPlayerController) {
 letvolume =this.currentVolume-10;
 if(volume < 0){
      await this.avCastPlayerController.setAVCastVolume(0);
    }
    await this.avCastPlayerController.setAVCastVolume(volume);
  }
})

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 视频
    +关注

    关注

    6

    文章

    1999

    浏览量

    74647
  • 华为
    +关注

    关注

    217

    文章

    35783

    浏览量

    260717
  • HarmonyOS
    +关注

    关注

    80

    文章

    2146

    浏览量

    35575

原文标题:HarmonyOS应用视频投播解决方案

文章出处:【微信号:HarmonyOS_Dev,微信公众号:HarmonyOS开发者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    立体智慧仓储解决方案.#云计算

    解决方案智能设备
    学习电子知识
    发布于 :2022年10月06日 19:45:47

    HDTV的完整音视频解决方案

    HDTV的完整音视频解决方案不管是受摩尔定律还是消费者需求的推动,当前电视机对性能的要求大幅提升。具有数据处理量是标准清晰度(SD)电视格式 6 倍的1,080像素高清晰度(HD)格式、管理DTV
    发表于 05-28 16:40

    视频语音解决方案

    视频语音解决方案采用达芬奇TMS320DM6437数字媒体处理器的消费类IP视频电话结构图音频编解码器 TLV320AIC12KTLV320AIC23B 降压控制器 TPS40190
    发表于 07-29 08:46

    [求助]视频转换器解决方案

    本帖最后由 gk320830 于 2015-3-9 21:35 编辑 本人求助一个视频转换器的解决方案,有现成的最好。有的请与我联系,谢谢/
    发表于 11-30 02:45

    杰士安校园网络视频监控解决方案

    方案办公大楼模拟视频监控解决方案  办公大楼网络视频监控解决方案  连锁机构网络视频
    发表于 12-08 18:23

    如何构建更好的视频桥接解决方案

    相关的影响和设计问题,并介绍一些可行的解决方案和应用方法。桥接新旧视频接口人们对创新的低成本视频桥接解决方案的需求正与日俱增。 例如,构建监控系统、无人机或 DSLR 摄像头的设计人员
    发表于 04-06 13:48

    视频解决方案第4期:极小硬件方案介绍

    本期介绍HarmonyOS Connect标准开发方案——极小硬件方案(BLE),重点介绍方案选择、体验定义、软硬件定义以及开发要点,帮助您快速接入蓝牙极小硬件产品。定义产品:http
    发表于 04-08 10:20

    求助,请问如何发布我的HarmonyOS组件或解决方案

    我要如何发布我的HarmonyOS组件或解决方案
    发表于 06-02 15:55

    Altera的视频和图像处理解决方案

    Altera的视频和图像处理解决方案图1. 解决方案领域 Altera及其合作伙伴的多种开发套件、IP和参考设计为视频和图像处理提供了全面的
    发表于 06-08 07:51 52次下载

    IP视频电话解决方案

    IP视频电话解决方案  
    发表于 07-29 08:48 1521次阅读
    IP<b class='flag-5'>视频</b>电话<b class='flag-5'>解决方案</b>

    无线传输视频监控解决方案

    一种无线传输视频监控解决方案的讲解
    发表于 11-11 17:59 198次下载
    无线传输<b class='flag-5'>视频</b>监控<b class='flag-5'>解决方案</b>

    视频与影像解决方案指南

    视频与影像解决方案指南,有需要的朋友下来看看
    发表于 01-19 14:30 30次下载

    家庭无线视频监控解决方案

    家庭无线视频监控解决方案
    发表于 12-25 00:26 0次下载

    HarmonyOS测试技术与实战-分布式应用测试解决方案

    HDC 2021华为开发者大会HarmonyOS测试技术与实战-HarmonyOS分布式应用测试解决方案
    的头像 发表于 10-23 14:48 1977次阅读
    <b class='flag-5'>HarmonyOS</b>测试技术与实战-分布式应用测试<b class='flag-5'>解决方案</b>

    视频会议解决方案

    飞腾云XU316 7MIC无感本地扩音方案正是可以解决视频会议中音质不好的问题的有效解决方案
    的头像 发表于 06-28 15:30 1347次阅读
    <b class='flag-5'>视频</b>会议<b class='flag-5'>解决方案</b>