更多信息请访问:https://harmonyos.51cto.com,与华为官方共建的鸿蒙技术社区1.介绍本Codelab将实现的内容Thiscodelab旨在让开发者了解手机HarmonyOS应用开发、常用布局、典型控件、FA组件、媒体-视频、跨设备协同体验,以及从项目创建到代码和布局编写,到编译构建、部署和运行的完整过程过程。您将基于HarmonyOSPlayer类构建应用程序。该应用的功能是播放本地视频资源或从互联网上获取的视频资源。效果图如下:学习内容●如何使用Player类播放视频●如何使用自定义控件控制视频播放●如何添加和使用媒体事件的事件监听器和回调硬件要求●操作系统:Windows1064位●内存:8GB以上●硬盘:100GB以上●分辨率:1280*800像素以上软件要求●安装HuaweiDevEcoStudio。详见下载安装软件●搭建HuaweiDevEcoStudio开发环境HuaweiDevEcoStudio开发环境取决于网络环境,需要连接网络以保证工具的正常使用。开发环境可根据以下两种情况进行配置:1、如果可以直接上网,只需要下载HarmonyOSSDK运行即可;2.如果网络不能直接上网,需要通过代理服务器访问,请参考开发环境配置说明。如果需要在手机端运行程序,需要提前申请证书。如果你使用模拟器,你可以忽略它。生成秘钥并申请证书。详见签名文件编写技巧要求●有在DevEcoStudio中创建、构建和运行应用程序的经验●熟悉Ability和AbilitySlice的生命周期以及使用PA/FAWay的能力。下面对整个项目的代码结构进行说明,如下图所示:●api:监控视频播放状态变化和屏幕状态变化。●常量:定义视频状态、进度条和控制器状态。●factoty:创建一个SourceFactory类以从视频源创建视频源。●manager:创建HmPlayerLifecycle来处理Player类的生命周期。●view:创建PlayerLoading和SimplePlayerController类,分别控制视频加载状态和进度条。●HmPlayer:封装了播放器的主要功能方法。●slice:创建MainAbilitySlice和SimplePlayerAbilitySlice,分别进入应用的主程序页面和视频播放页面。●utils:存放所有封装好的公共方法,如DateUtils、LogUtils等●resources:存放项目中使用的资源文件,其中xml布局文件存放在resources\base\layout下;视频文件存储在resources\base\media下。●config.json:能力声明和权限配置。3.创建视频播放业务逻辑。此应用程序可以播放的视频格式包括mp4、mov、3gp和mkv。首先准备一个视频文件,复制到“resources/base/layout/media”文件目录下。下面介绍视频列表布局和播放逻辑。创建视频播放页面文件和布局第一步-创建一个simple_video_play_layout.xml布局文件来显示视频列表。布局文件有两个id,parent是整个播放页面的layoutid,parent_layout是视频画面的layoutid。Step2-创建SimplePlayerAbilitySlice类,并创建首次初始化页面。@OverridepublicvoidonStart(Intentintent){super.onStart(intent);super.setUIContent(ResourceTable.Layout_simple_video_play_layout);//在常量中定义视频播放的起始位置startMillisecond=intent.getIntParam(Constants.INTENT_STARTTIME_PARAM,0);//初始化surfacelayoutinitView();player.getLifecycle().onStart();}将预设视频资源初始化为url对象,通过initView方法初始化分配视频播放控件。privateStringurl="entry/resources/base/media/gubeishuizhen.mp4";privatevoidinitView(){DependentLayoutplayerLayout=(DependentLayout)findComponentById(ResourceTable.Id_parent_layout);player=newHmPlayer.Builder(this).setStartMillisecond(mStartMillisecond).setFilePath(url).create();playerLayout.addComponent(player.getPlayerView());player.play();}——结束创建HmPlayerHmPlayer类继承自ImPlayer,封装了HarmonyOSPlayer。如果您还不知道HarmonyOSPlayer,请参考视频播放器开发指南。需要注意的是,当页面初始化Player类执行play方法时,视频并没有出现在屏幕上。屏幕上的图像渲染需要用到SurfaceProvider,它控制surface的大小和格式,修改surface的像素点,监听surface的变化等等。surfaceCreated(SurfaceOpssurfaceOps)回调函数在底层显示系统第一次创建表面时被调用。HmPlayer增加了通过设置回调控制视频播放开始或停止。privateSurfaceOps.CallbacksurfaceCallback=newSurfaceOps.Callback(){@OverridepublicvoidsurfaceCreated(SurfaceOpssurfaceOps){//标记surfaceView状态isSurfaceViewCreated=true;surface=surfaceOps.getSurface();start();}@OverridepublicvoidsurfaceChanged(SurfaceOpssurfaceOps,inti,intwidth,intheight){LogUtil.info(TAG,"surfaceChangediis"+i+",widthis"+width+",heightis"+height);}@OverridepublicvoidsurfaceDestroyed(SurfaceOpssurfaceOps){LogUtil.info(TAG,"surfaceDestroyed");isSurfaceViewCreated=false;}};surfaceView的初始化在HmPlayer构造函数中:privateHmPlayer(Builderbuilder){...surfaceView=newSurfaceProvider(playerBuilder.mContext);DependentLayout.LayoutConfiglayoutConfig=newDependentLayout.LayoutConfig();layoutConfig.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT);//设置surfaceView布局surfaceView.setLayoutConfig(layoutConfig);surfaceView.setVisibility(Component.VISIBLE);surfaceView.setFocusable(Component.FOCUS_ENABLE);surfaceView.setTouchFocusable(true);surfaceView.requestFocus();//设置surfaceView是否在顶部surfaceView.pinToZTop(playerBuilder.isTopPlay);surfaceView.getSurfaceOps().get().addCallback(surfaceCallback);}会在执行surfaceCreated回调执行HarmonyOS中Player的play方法0){intmicrosecond=playerBuilder.startMillisecond*MICRO_MILLI_RATE;player.rewindTo(microsecond);}else{player.play();}});}}编译运行应用程序启动后,会打开视频文件,玩过,并且会一直玩到最后。效果如下图所示:4.创建视频控制业务逻辑以上章节实现了视频播放的基本功能。本节将创建一个控制器,其中包含基本的媒体控制UI元素,例如播放、暂停、恢复、重新加载按钮和进度条。.该控制器将与HmPlayer类一起使用,以提供基本的全功能和可操作的视频播放器。创建SimpleVideoPlayerControllerSimplePlayerController类作为自定义组件,包括控制视频播放、暂停、恢复和进度条的控件。这里HarmonyOSEventHandler用于UI更新,请参考HarmonyOS开发者文档线程间通信。publicSimplePlayerController(Contextcontext,ImplPlayerplayer){super(context);this.context=context;implPlayer=player;//创建子线程给自己发送消息更新UIcreateHandler();initView();initListener();}其中initView方法初始化播放控件的控件。ComponentplayerController=LayoutScatter.getInstance(context).parse(ResourceTable.Layout_simple_player_controller_layout,null,false);addComponent(playerController);if(playerController.findComponentById(ResourceTable.Id_play_controller)instanceofImage){//播放或暂停按钮playToogle=(Image)playerController.findComponentById(ResourceTable.Id_play_controller);}if(playerController.findComponentById(ResourceTable.Id_play_forward)instanceofImage){//前进按钮imageForward=(Image)playerController.findComponentById(ResourceTable.Id_play_forward);}if(playerController.findComponentById(ResourceTable.Id_play_backward))instanceofImage){//后退按钮imageBackward=(Image)playerController.findComponentById(ResourceTable.Id_play_backward);}if(playerController.findComponentById(ResourceTable.Id_progress)instanceofSlider){//进度条progressBar=(Slider)playerController.findComponentById(ResourceTable.Id_progress);}initListener方法是监听HmPlayer和播放控制器。implPlayer.addPlayerStatusCallback(statusChangeListener);添加HmPlayer状态变化监听,比如视频播放时,回调StatusChangeListener的statusCallback,刷新controller中各个组件的状态和显示值。HmPlayer中的HmPlayerCallback使用底层播放回调onPlayBackComplete改变界面视频状态。@OverridepublicvoidonPlayBackComplete(){for(StatusChangeListenercallback:statusChangeCallbacks){status=PlayerStatus.COMPLETE;callback.statusCallback(PlayerStatus.COMPLETE);}stop();}在SimplePlayerController的statusCallback中更新控制按钮状态。如果(status==PlayerStatus.STOP||status==PlayerStatus.COMPLETE){controllerHandler.sendEvent(Constants.PLAYER_PROGRESS_RUNNING,EventHandler.Priority.IMMEDIATE);playToogle.setPixelMap(ResourceTable.Media_ic_update);progressBar.setEnabled(false);}此时播放按钮更新为要刷新的图标,不能拖动进度条。创建PlayerLoading时,当视频帧缓冲未完成时,如果播放界面提供加载进度信息,用户体验会更好。创建的PlayerLoading类设置了一个布局,并添加了一个StatusChangeListener监听回调,使得控件可以根据状态显示或隐藏。publicPlayerLoading(Contextcontext,ImplPlayerplayer){super(context);this.player=player;initView(context);initListener();}privatevoidinitListener(){player.addPlayerStatusCallback(newStatusChangeListener(){@OverridepublicvoidstatusCallback(PlayerStatusstatus){//获取主线程更新UImContext.getUITaskDispatcher().delayDispatch(newRunnable(){@Overridepublicvoidrun(){if(status==PlayerStatus.PREPARING||status==PlayerStatus.BUFFERING){show();}elseif(status==PlayerStatus.PLAY){hide();}else{LogUtil.info(PlayerLoading.class.getName(),"statuCallbackelsemessage");}}},0);}});}在上述步骤之后编译并运行应用程序,在这次运行程序,可以看到一个有前进、后退、播放、暂停的界面。用户可以自主控制视频播放,效果如下:5.恭喜,您通过本次Codelab学习到:●一个完整的HarmonyOS视频播放应用需要包含UI、Surface和媒体播放器。●使用player.setSource(source)指定视频文件的路径。●使用SurfaceOps.Callback处理表面创建、状态更改和销毁的回调。●创建内部类HmPlayerCallback实现Player.IPlayerCallback接口,监听视频状态变化,增加controller组件状态和buffer接口的回调方法。●创建HmPlayerLifeCycle来管理HmPlayer的生命周期。6.参考gitee源码和github源码。更多信息请访问:https://harmonyos.51cto.com,与华为官方共同打造的鸿蒙技术社区