1. 介紹
本篇Codelab將實(shí)現(xiàn)的內(nèi)容
本篇Codelab旨在讓開發(fā)者了解手機(jī)HarmonyOS應(yīng)用開發(fā),常用布局、典型控件、FA組件、媒體-視頻、跨設(shè)備協(xié)同的體驗(yàn)以及從工程創(chuàng)建到代碼和布局的編寫,再到編譯構(gòu)建、部署和運(yùn)行全過程。
您將構(gòu)建一個(gè)基于HarmonyOSPlayer類實(shí)現(xiàn)的應(yīng)用程序,該應(yīng)用程序功能為播放本地視頻資源或從Internet獲得的視頻資源。效果圖如下:
您將會(huì)學(xué)到什么
●如何使用Player類播放視頻
●如何使用自定義控件來控制視頻播放
●如何添加并使用媒體事件的事件偵聽器和回調(diào)
硬件要求
●操作系統(tǒng):Windows10 64位
●內(nèi)存:8GB及以上
●硬盤:100GB及以上
●分辨率:1280*800像素及以上
軟件要求
●安裝Huawei DevEco Studio,詳情請(qǐng)參考下載和安裝軟件
●設(shè)置Huawei DevEco Studio開發(fā)環(huán)境,Huawei DevEco Studio開發(fā)環(huán)境需要依賴于網(wǎng)絡(luò)環(huán)境,需要連接上網(wǎng)絡(luò)才能確保工具的正常使用,可以根據(jù)如下兩種情況來配置開發(fā)環(huán)境
1.如果可以直接訪問Internet,只需進(jìn)行下載HarmonyOS SDK操作
2.如果網(wǎng)絡(luò)不能直接訪問Internet,需要通過代理服務(wù)器才可以訪問,請(qǐng)參考配置開發(fā)環(huán)境
說明
如需要在手機(jī)中運(yùn)行程序,則需要提前申請(qǐng)證書,如使用模擬器可忽略
●生成秘鑰和申請(qǐng)證書,詳情請(qǐng)參考準(zhǔn)備簽名文件
技能要求
●具備DevEco Studio中創(chuàng)建、構(gòu)建和運(yùn)行應(yīng)用經(jīng)驗(yàn)
●熟悉Ability和AbilitySlice生命周期及使用PA/FA的能力
2. 代碼結(jié)構(gòu)
本篇Codelab只對(duì)核心代碼進(jìn)行講解,對(duì)于完整代碼,我們?cè)趨⒖继峁┫螺d方式。接下來我們會(huì)講解整個(gè)工程的代碼結(jié)構(gòu),如下圖:
●api:視頻播放狀態(tài)改變及屏幕狀態(tài)變化監(jiān)聽。
●constant:定義視頻狀態(tài)、進(jìn)度條和控制器狀態(tài)。
●factoty:創(chuàng)建SourceFactory類來根據(jù)視頻來源創(chuàng)建視頻源。
●manager:創(chuàng)建HmPlayerLifecycle來處理Player類的生命周期。
●view:創(chuàng)建PlayerLoading、SimplePlayerController類分別為視頻加載狀態(tài)及進(jìn)度條控制類文件。
●HmPlayer:封裝播放器的主要功能方法。
●slice:創(chuàng)建MainAbilitySlice、SimplePlayerAbilitySlice分別為進(jìn)入應(yīng)用的主程序頁面和視頻播放頁面。
●utils:存放所有封裝好的公共方法,如DateUtils,LogUtils等。
●resources:存放工程使用到的資源文件,其中resourcesaselayout下存放xml布局文件;resourcesasemedia下存放視頻文件。
●config.json:Ability聲明及權(quán)限配置。
3. 創(chuàng)建視頻播放業(yè)務(wù)邏輯
該應(yīng)用程序可播放的視頻格式包括mp4、mov、3gp、mkv,首先準(zhǔn)備一份視頻文件并復(fù)制到"resources/base/layout/media"文件目錄。下面將會(huì)介紹視頻列表布局及播放邏輯。
創(chuàng)建視頻播放頁面文件及布局
Step 1 -創(chuàng)建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">
該布局文件有兩個(gè)id,parent是整個(gè)播放頁面的布局id,parent_layout是視頻畫面的布局id。
Step 2- 創(chuàng)建SimplePlayerAbilitySlice類,初次創(chuàng)建該頁面進(jìn)行初始化。
@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(); }
將預(yù)置的視頻資源初始化為url對(duì)象,并通過initView方法對(duì)視頻播放的控件進(jìn)行初始化及賦值。
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();
}
結(jié)束
創(chuàng)建HmPlayer
HmPlayer類是繼承自對(duì)HarmonyOS Player封裝的ImPlayer。如果您還不了解HarmonyOS Player,請(qǐng)參考視頻播放開發(fā)指導(dǎo)。
需要注意的是當(dāng)頁面初始化Player類執(zhí)行play方法時(shí),視頻并沒有出現(xiàn)畫面。圖像渲染在屏幕上需要使用SurfaceProvider,該類控制surface的尺寸和格式,修改surface的像素,監(jiān)視surface的變化等等。當(dāng)?shù)讓语@示系統(tǒng)第一次創(chuàng)建surface之后會(huì)調(diào)用surfaceCreated(SurfaceOps surfaceOps)回調(diào)函數(shù)。HmPlayer中通過設(shè)置回調(diào)增加對(duì)視頻的播放開始或停止控制。
private SurfaceOps.Callback surfaceCallback = new SurfaceOps.Callback() {
@Override
public void surfaceCreated(SurfaceOps surfaceOps) {
// 標(biāo)記surfaceView狀態(tài)
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構(gòu)造函數(shù)中:
private HmPlayer(Builder builder) {
...
surfaceView = new SurfaceProvider(playerBuilder.mContext);
DependentLayout.LayoutConfig layoutConfig = new DependentLayout.LayoutConfig();
layoutConfig.addRule(DependentLayout.LayoutConfig.CENTER_IN_PARENT);
// 設(shè)置surfaceView布局
surfaceView.setLayoutConfig(layoutConfig);
surfaceView.setVisibility(Component.VISIBLE);
surfaceView.setFocusable(Component.FOCUS_ENABLE);
surfaceView.setTouchFocusable(true);
surfaceView.requestFocus();
// 設(shè)置surfaceView是否在最上方
surfaceView.pinToZTop(playerBuilder.isTopPlay);
surfaceView.getSurfaceOps().get().addCallback(surfaceCallback);
}
在執(zhí)行surfaceCreated回調(diào)時(shí)會(huì)執(zhí)行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();
}
});
}
}
編譯運(yùn)行該應(yīng)用程序
應(yīng)用啟動(dòng)后,視頻文件將被打開并開始播放,持續(xù)播放到最后。效果如下圖:
4. 創(chuàng)建視頻控制業(yè)務(wù)邏輯
上面的章節(jié)實(shí)現(xiàn)了視頻播放的基本功能,本小節(jié)將創(chuàng)建一個(gè)控制器,包含基本的媒體控制UI元素如播放、暫停、恢復(fù)、重新加載按鈕以及進(jìn)度條。該控制器將與HmPlayer類一起提供一個(gè)基本功能全面且可操作的視頻播放器。
創(chuàng)建SimpleVideoPlayerController
SimplePlayerController類為自定義組件,包括控制視頻的播放、暫停、恢復(fù)以及進(jìn)度條等控件。此處使用HarmonyOS EventHandler來進(jìn)行UI更新,請(qǐng)參考HarmonyOS開發(fā)者文檔線程間通信。
public SimplePlayerController(Context context, ImplPlayer player) {
super(context);
this.context = context;
implPlayer = player;
// 創(chuàng)建子線程給自己發(fā)消息來及時(shí)更新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) { // 前進(jìn)按鈕 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) { // 進(jìn)度條 progressBar = (Slider) playerController.findComponentById(ResourceTable.Id_progress); }
initListener方法是對(duì)HmPlayer和播放控制器相互之間狀態(tài)變化的監(jiān)聽處理。
implPlayer.addPlayerStatusCallback(statusChangeListener);
添加HmPlayer狀態(tài)變化的監(jiān)聽,例如當(dāng)視頻播放完畢時(shí),回調(diào)StatusChangeListener的statusCallback來刷新對(duì)控制器中各種組件的狀態(tài)和顯示值。HmPlayer中HmPlayerCallback中通過底層播放回調(diào)onPlayBackComplete來對(duì)界面視頻狀態(tài)進(jìn)行更改。
@Override
public void onPlayBackComplete() {
for (StatusChangeListener callback : statusChangeCallbacks) {
status = PlayerStatus.COMPLETE;
callback.statusCallback(PlayerStatus.COMPLETE);
}
stop();
}
在SimplePlayerController的statusCallback中更新控制按鈕狀態(tài)。
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);
}
此時(shí)播放按鈕更新成待刷新圖標(biāo),進(jìn)度條不可拖拽。
創(chuàng)建PlayerLoading
在視頻畫面緩沖沒有完成時(shí),播放界面如果提供加載進(jìn)度信息,用戶體驗(yàn)更好。創(chuàng)建的PlayerLoading類設(shè)置一個(gè)布局并且添加StatusChangeListener監(jiān)聽回調(diào),使得該控件可以根據(jù)狀態(tài)顯示或隱藏。
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);
}
});
}
編譯運(yùn)行該應(yīng)用程序
經(jīng)過上面的步驟,此時(shí)運(yùn)行程序就可以看到一個(gè)有前進(jìn)、后退、播放、暫停的界面,用戶可以自主控制該視頻播放,效果如下圖:
編輯:hfy
-
HarmonyOS
+關(guān)注
關(guān)注
80文章
2144瀏覽量
35225
發(fā)布評(píng)論請(qǐng)先 登錄
HarmonyOS應(yīng)用開發(fā)-視頻播放
HarmonyOS應(yīng)用開發(fā)-元程序交互
應(yīng)用程序開發(fā)
【線上】華為 HarmonyOS Codelab 挑戰(zhàn)賽,你過關(guān)來我發(fā)獎(jiǎng)【第二期】
【基于HarmonyOS開發(fā)購(gòu)物應(yīng)用】SetllatWood Codelab第二期記錄帖
HarmonyOS技術(shù)社區(qū)HDD期間Codelab活動(dòng)獲獎(jiǎng)人名單公布
基于HarmonyOS Player,實(shí)現(xiàn)音頻的播放、管理控制和采集
基于HarmonyOS Player,實(shí)現(xiàn)視頻文件的播放
使用JS實(shí)現(xiàn)一款簡(jiǎn)單的HarmonyOS購(gòu)物應(yīng)用
HarmonyOS Codelabs軟件應(yīng)用視頻操作指南
HarmonyOS應(yīng)用程序Ability的作用
華為開發(fā)者分論壇HarmonyOS學(xué)生公開課-基于開發(fā)樣例Codelab進(jìn)行改裝
泰凌微電子| OpenThread組Telink Codelab正式上線

基于HarmonyOS Player類實(shí)現(xiàn)的應(yīng)用程序——Codelab技術(shù)
評(píng)論