1. 介绍
本篇Codelab将实现的内容
本篇Codelab旨在让开发者了解手机HarmonyOS应用开发,常用布局、典型控件、FA组件、媒体-视频、跨设备协同的体验以及从工程创建到代码和布局的编写,再到编译构建、部署和运行全过程。
您将构建一个基于HarmonyOSPlayer类实现的应用程序,该应用程序功能为播放本地视频资源或从Internet获得的视频资源。效果图如下:
您将会学到什么
●如何使用Player类播放视频
●如何使用自定义控件来控制视频播放
●如何添加并使用媒体事件的事件侦听器和回调
硬件要求
●操作系统:Windows10 64位
●内存:8GB及以上
●硬盘:100GB及以上
●分辨率:1280*800像素及以上
软件要求
●安装Huawei DevEco Studio,详情请参考下载和安装软件
●设置Huawei DevEco Studio开发环境,Huawei DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境
1.如果可以直接访问Internet,只需进行下载HarmonyOS SDK操作
2.如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考配置开发环境
说明
如需要在手机中运行程序,则需要提前申请证书,如使用模拟器可忽略
●生成秘钥和申请证书,详情请参考准备签名文件
技能要求
●具备DevEco Studio中创建、构建和运行应用经验
●熟悉Ability和AbilitySlice生命周期及使用PA/FA的能力
2. 代码结构
本篇Codelab只对核心代码进行讲解,对于完整代码,我们在参考提供下载方式。接下来我们会讲解整个工程的代码结构,如下图:
●api:视频播放状态改变及屏幕状态变化监听。
●constant:定义视频状态、进度条和控制器状态。
●factoty:创建SourceFactory类来根据视频来源创建视频源。
●manager:创建HmPlayerLifecycle来处理Player类的生命周期。
●view:创建PlayerLoading、SimplePlayerController类分别为视频加载状态及进度条控制类文件。
●HmPlayer:封装播放器的主要功能方法。
●slice:创建MainAbilitySlice、SimplePlayerAbilitySlice分别为进入应用的主程序页面和视频播放页面。
●utils:存放所有封装好的公共方法,如DateUtils,LogUtils等。
●resources:存放工程使用到的资源文件,其中resourcesaselayout下存放xml布局文件;resourcesasemedia下存放视频文件。
●config.json:Ability声明及权限配置。
3. 创建视频播放业务逻辑
该应用程序可播放的视频格式包括mp4、mov、3gp、mkv,首先准备一份视频文件并复制到"resources/base/layout/media"文件目录。下面将会介绍视频列表布局及播放逻辑。
创建视频播放页面文件及布局
Step 1 -创建simple_video_play_layout.xml布局文件展示视频列表。
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:id="$+id:parent"
ohos:height="match_parent"
ohos:width="match_parent">
该布局文件有两个id,parent是整个播放页面的布局id,parent_layout是视频画面的布局id。
Step 2- 创建SimplePlayerAbilitySlice类,初次创建该页面进行初始化。
@Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_simple_video_play_layout); // 在Constants中定义视频播放的起始位置 startMillisecond = intent.getIntParam(Constants.INTENT_STARTTIME_PARAM, 0); // 初始化surface布局 initView(); player.getLifecycle().onStart(); }
将预置的视频资源初始化为url对象,并通过initView方法对视频播放的控件进行初始化及赋值。
private String url = "entry/resources/base/media/gubeishuizhen.mp4";
private void initView() {
DependentLayout playerLayout = (DependentLayout) findComponentById(ResourceTable.Id_parent_layout);
player = new HmPlayer.Builder(this).setStartMillisecond(mStartMillisecond).setFilePath(url).create();
playerLayout.addComponent(player.getPlayerView());
player.play();
}
结束
创建HmPlayer
HmPlayer类是继承自对HarmonyOS Player封装的ImPlayer。如果您还不了解HarmonyOS Player,请参考视频播放开发指导。
需要注意的是当页面初始化Player类执行play方法时,视频并没有出现画面。图像渲染在屏幕上需要使用SurfaceProvider,该类控制surface的尺寸和格式,修改surface的像素,监视surface的变化等等。当底层显示系统第一次创建surface之后会调用surfaceCreated(SurfaceOps surfaceOps)回调函数。HmPlayer中通过设置回调增加对视频的播放开始或停止控制。
private SurfaceOps.Callback surfaceCallback = new SurfaceOps.Callback() {
@Override
public void surfaceCreated(SurfaceOps surfaceOps) {
// 标记surfaceView状态
isSurfaceViewCreated = true;
surface = surfaceOps.getSurface();
start();
}
@Override
public void surfaceChanged(SurfaceOps surfaceOps, int i, int width, int height) {
LogUtil.info(TAG, "surfaceChanged i is " + i + ",width is " + width + ",height is " + height);
}
@Override
public void surfaceDestroyed(SurfaceOps surfaceOps) {
LogUtil.info(TAG, "surfaceDestroyed");
isSurfaceViewCreated = false;
}
};
surfaceView的初始化在HmPlayer构造函数中:
private HmPlayer(Builder builder) {
...
surfaceView = new SurfaceProvider(playerBuilder.mContext);
DependentLayout.LayoutConfig layoutConfig = new DependentLayout.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方法。
private void start() {
if (isSurfaceViewCreated) {
threadPoolExecutor.execute(() -> {
player.setVideoSurface(surface);
player.prepare();
if (playerBuilder.startMillisecond > 0) {
int microsecond = playerBuilder.startMillisecond * MICRO_MILLI_RATE;
player.rewindTo(microsecond);
} else {
player.play();
}
});
}
}
编译运行该应用程序
应用启动后,视频文件将被打开并开始播放,持续播放到最后。效果如下图:
4. 创建视频控制业务逻辑
上面的章节实现了视频播放的基本功能,本小节将创建一个控制器,包含基本的媒体控制UI元素如播放、暂停、恢复、重新加载按钮以及进度条。该控制器将与HmPlayer类一起提供一个基本功能全面且可操作的视频播放器。
创建SimpleVideoPlayerController
SimplePlayerController类为自定义组件,包括控制视频的播放、暂停、恢复以及进度条等控件。此处使用HarmonyOS EventHandler来进行UI更新,请参考HarmonyOS开发者文档线程间通信。
public SimplePlayerController(Context context, ImplPlayer player) {
super(context);
this.context = context;
implPlayer = player;
// 创建子线程给自己发消息来及时更新UI
createHandler();
initView();
initListener();
}
其中initView方法初始化播放控制的控件。
Component playerController = LayoutScatter.getInstance(context).parse( ResourceTable.Layout_simple_player_controller_layout, null, false); addComponent(playerController); if (playerController.findComponentById(ResourceTable.Id_play_controller) instanceof Image) { // 播放或者暂停按钮 playToogle = (Image) playerController.findComponentById(ResourceTable.Id_play_controller); } if (playerController.findComponentById(ResourceTable.Id_play_forward) instanceof Image) { // 前进按钮 imageForward = (Image) playerController.findComponentById(ResourceTable.Id_play_forward); } if (playerController.findComponentById(ResourceTable.Id_play_backward) instanceof Image) { // 后退按钮 imageBackward = (Image) playerController.findComponentById(ResourceTable.Id_play_backward); } if (playerController.findComponentById(ResourceTable.Id_progress) instanceof Slider) { // 进度条 progressBar = (Slider) playerController.findComponentById(ResourceTable.Id_progress); }
initListener方法是对HmPlayer和播放控制器相互之间状态变化的监听处理。
implPlayer.addPlayerStatusCallback(statusChangeListener);
添加HmPlayer状态变化的监听,例如当视频播放完毕时,回调StatusChangeListener的statusCallback来刷新对控制器中各种组件的状态和显示值。HmPlayer中HmPlayerCallback中通过底层播放回调onPlayBackComplete来对界面视频状态进行更改。
@Override
public void onPlayBackComplete() {
for (StatusChangeListener callback : statusChangeCallbacks) {
status = PlayerStatus.COMPLETE;
callback.statusCallback(PlayerStatus.COMPLETE);
}
stop();
}
在SimplePlayerController的statusCallback中更新控制按钮状态。
if (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监听回调,使得该控件可以根据状态显示或隐藏。
public PlayerLoading(Context context, ImplPlayer player) {
super(context);
this.player = player;
initView(context);
initListener();
}
private void initListener() {
player.addPlayerStatusCallback(new StatusChangeListener() {
@Override
public void statusCallback(PlayerStatus status) {
//获取主线程更新UI
mContext.getUITaskDispatcher().delayDispatch(
new Runnable() {
@Override
public void run() {
if (status == PlayerStatus.PREPARING || status == PlayerStatus.BUFFERING) {
show();
} else if (status == PlayerStatus.PLAY) {
hide();
} else {
LogUtil.info(PlayerLoading.class.getName(), "statuCallback else message");
}
}
}, 0);
}
});
}
编译运行该应用程序
经过上面的步骤,此时运行程序就可以看到一个有前进、后退、播放、暂停的界面,用户可以自主控制该视频播放,效果如下图:
编辑:hfy
-
HarmonyOS
+关注
关注
80文章
2146浏览量
35580
发布评论请先 登录
HarmonyOS应用开发-视频播放
HarmonyOS应用开发-元程序交互
应用程序开发
【线上】华为 HarmonyOS Codelab 挑战赛,你过关来我发奖【第二期】
【基于HarmonyOS开发购物应用】SetllatWood Codelab第二期记录帖
HarmonyOS技术社区HDD期间Codelab活动获奖人名单公布
基于HarmonyOS Player,实现音频的播放、管理控制和采集
基于HarmonyOS Player,实现视频文件的播放
使用JS实现一款简单的HarmonyOS购物应用
HarmonyOS Codelabs软件应用视频操作指南
HarmonyOS应用程序Ability的作用
华为开发者分论坛HarmonyOS学生公开课-基于开发样例Codelab进行改装

基于HarmonyOS Player类实现的应用程序——Codelab技术
评论