赞
踩
鸿蒙系统HarmonyOS,今天来写一个视频播放器。
官方给的例子比较简单。
官方示例参考
本例可以实现视频播放、暂停、重播、画面显示、拖拽视频进度。
看最后界面。
图1本文不细讲,它是增加了弹框授权。
图2是开始状态,图三是播放状态。
图2现在没有视频预览,有空再做。
需要准备resources/rawfile/video_1.mp4,
resources/base/graphic/icon_play.xml,
resources/base/graphic/icon_pause.xml,
resources/base/graphic/icon_redo.xml,
4个文件。
其中3个xml文件是用svg文件转化成xml文件的。
先在iconfont-阿里巴巴矢量图标库网上下载几个播放、暂停图标文件,选择下载svg文件,
然后在DevEco Studio->module右键->New->Svg To xml,就能把svg文件转化成xml文件了。
下面给个resources/base/graphic/icon_play.xml的示例。
- <?xml version="1.0" encoding="UTF-8"?>
-
- <vector xmlns:ohos="http://schemas.huawei.com/res/ohos" ohos:width="200vp" ohos:height="200vp" ohos:viewportWidth="1024" ohos:viewportHeight="1024">
- <path ohos:fillColor="#FF000000" ohos:pathData="M157.54,860.55V163.45c0,-19.69 25.6,-33.48 43.32,-17.72l653.78,340.68c15.75,11.82 15.75,37.42 0,49.23L200.86,880.25c-17.72,13.78 -43.32,1.97 -43.32,-19.69z"></path>
- </vector>
在DevEco Studio中新建一个Ability吧,取名SampleVideoPlayerAbility,
会得到
src/main/java/com/example/myapplication/slice/SampleVideoPlayerAbilitySlice.java,
src/main/java/com/example/myapplication/video/SampleVideoPlayerAbility.java,
resources/base/layout/ability_sample_video_player.xml,
3个文件。
本例中,实现代码在SampleVideoPlayerAbilitySlice.java文件中
布局在文件ability_sample_video_player.xml中。
上布局文件ability_sample_video_player.xml。
- <?xml version="1.0" encoding="utf-8"?>
- <DirectionalLayout
- xmlns:ohos="http://schemas.huawei.com/res/ohos"
- ohos:height="match_parent"
- ohos:width="match_parent"
- ohos:alignment="center"
- ohos:orientation="vertical">
-
- <SurfaceProvider
- ohos:id="$+id:sp"
- ohos:height="200vp"
- ohos:width="match_parent"
- >
- </SurfaceProvider>
-
- <DependentLayout
- ohos:height="match_content"
- ohos:width="match_parent"
- ohos:alignment="center"
- >
-
- <Slider
- ohos:id="$+id:slider"
- ohos:height="40vp"
- ohos:width="match_parent"
- ohos:max="6"
- ohos:min="0"
- ohos:progress="2"
- ohos:progress_element="#00FF00"
- ohos:progress_hint_text_alignment="end"
- ohos:progress_hint_text_color="#ff0000"
- ohos:progress_hint_text_size="20fp"
- >
- </Slider>
-
- <Text
- ohos:id="$+id:text_slider_max"
- ohos:height="match_content"
- ohos:width="match_content"
- ohos:align_parent_end="true"
- ohos:background_element="$graphic:background_ability_main_video"
- ohos:below="$id:slider"
- ohos:layout_alignment="horizontal_center"
- ohos:text="0"
- ohos:text_size="20vp"
- />
- <Text
- ohos:id="$+id:text_slider_current"
- ohos:height="match_content"
- ohos:width="match_content"
- ohos:background_element="$graphic:background_ability_main_video"
- ohos:below="$id:slider"
- ohos:layout_alignment="horizontal_center"
- ohos:text="0s"
- ohos:text_size="20vp"
- />
- </DependentLayout>
-
- <DirectionalLayout
- ohos:height="match_content"
- ohos:width="match_content"
- ohos:alignment="center"
- ohos:orientation="horizontal">
-
- <Button
- ohos:id="$+id:button_play_or_pause"
- ohos:height="50vp"
- ohos:width="50vp"
- ohos:background_element="$graphic:icon_play"
- ></Button>
-
- <Button
- ohos:id="$+id:button_restart"
- ohos:height="50vp"
- ohos:width="50vp"
- ohos:background_element="$graphic:icon_redo"
- ></Button>
- </DirectionalLayout>
-
- </DirectionalLayout>
上Slice.java文件。重点部分在注释里说明了。
- package com.example.myapplication.slice;
-
- import com.example.myapplication.ResourceTable;
- import com.example.myapplication.utils.Common;
- import ohos.aafwk.ability.AbilitySlice;
- import ohos.aafwk.content.Intent;
- import ohos.agp.components.Button;
- import ohos.agp.components.Component;
- import ohos.agp.components.Slider;
- import ohos.agp.components.Text;
- import ohos.agp.components.element.Element;
- import ohos.agp.components.element.VectorElement;
- import ohos.agp.components.surfaceprovider.SurfaceProvider;
- import ohos.agp.graphics.SurfaceOps;
- import ohos.agp.utils.LayoutAlignment;
- import ohos.agp.window.dialog.ToastDialog;
- import ohos.eventhandler.EventHandler;
- import ohos.eventhandler.EventRunner;
- import ohos.eventhandler.InnerEvent;
- import ohos.global.resource.RawFileEntry;
- import ohos.media.common.Source;
- import ohos.media.player.Player;
-
- import java.io.File;
- import java.io.FileDescriptor;
- import java.io.FileInputStream;
- import java.io.IOException;
-
- public class SampleVideoPlayerAbilitySlice extends AbilitySlice {
- private Slider slider = null;
- private Button buttonPlay = null, buttonRestart = null;
- private Text textSliderMax = null;
- private Text textSliderCurrent = null;
- private SurfaceProvider sp = null;
- private MyEventHandler handler = null;
- private Player player = null;
- // 可选,在本例中实现视频进度拖拽
- private Slider.ValueChangedListener sliderValueChangedListener = new Slider.ValueChangedListener() {
- int position = 0;
-
- @Override
- public void onProgressUpdated(Slider slider, int i, boolean b) {
- Common.d("onProgressUpdated() " + i);
- position = i;
- //不能在此拖拽视频
- }
-
- @Override
- public void onTouchStart(Slider slider) {
- Common.d("onTouchStart() ");
-
- }
-
- @Override
- public void onTouchEnd(Slider slider) {
- if (player != null) {
- Common.d("onTouchEnd()getCurrentTime()=" + player.getCurrentTime());
- } else {
- Common.d("onTouchEnd() ");
- }
- //拖拽视频
- player.rewindTo(position * 1000);
- }
- };
- // 播放完成 、播放出错、拖拽完成回调函数
- private Player.IPlayerCallback playerCallback = new Player.IPlayerCallback() {
- @Override
- public void onPrepared() {
- Common.d("onPrepared()");
-
- }
-
- @Override
- public void onMessage(int i, int i1) {
- Common.d("onMessage()");
-
- }
-
- @Override
- public void onError(int i, int i1) {
- Common.d("onError()");
- }
-
- @Override
- public void onResolutionChanged(int i, int i1) {
- Common.d("onResolutionChanged()");
-
- }
-
- @Override
- public void onPlayBackComplete() {
- //播放完毕
- Common.d("onPlayBackComplete()");
- Common.d("onPlayBackComplete()getCurrentTime()=" + player.getCurrentTime());
- player.pause();
- InnerEvent event = InnerEvent.get(handler.MSG_UPDATE_BUTTON_PAUSED);
- handler.sendEvent(event);
- }
-
- @Override
- public void onRewindToComplete() {
- // 视频player.rewindTo()执行完成
- Common.d("onRewindToComplete()");
- Common.d("onRewindToComplete()getCurrentTime()=" + player.getCurrentTime());
- }
-
- @Override
- public void onBufferingChange(int i) {
- Common.d("onBufferingChange()");
-
- }
-
- @Override
- public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData) {
- Common.d("onNewTimedMetaData()");
-
- }
-
- @Override
- public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo) {
- if (player != null) {
- Common.d("onMediaTimeIncontinuity()getCurrentTime()=" + player.getCurrentTime());
- if (false) {
- //onMediaTimeIncontinuity()并不会每秒更新,所以此函数不适合更新进度条。
- InnerEvent event = InnerEvent.get(handler.MSG_UPDATE_PROGRESS);
- handler.sendEvent(event);
- }
- } else {
- Common.d("onMediaTimeIncontinuity()");
- }
- }
-
- };
- // 可选,在本例中没有使用
- private SurfaceOps.Callback surfaceOpsCallBack = new SurfaceOps.Callback() {
- @Override
- public void surfaceCreated(SurfaceOps surfaceOps) {
- //Common.d("surfaceCreated()");
- }
-
- @Override
- public void surfaceChanged(SurfaceOps surfaceOps, int i, int i1, int i2) {
- //Common.d("surfaceChanged()");
- }
-
- @Override
- public void surfaceDestroyed(SurfaceOps surfaceOps) {
- //Common.d("surfaceDestroyed()");
- }
- };
- private Component.ClickedListener listener = new Component.ClickedListener() {
- @Override
- public void onClick(Component component) {
- switch (component.getId()) {
- case ResourceTable.Id_button_play_or_pause:
- //点一下播放,再点一下暂停
- handlePlayOrPause();
- break;
- case ResourceTable.Id_button_restart:
- //从头播放、重新播放
- if (player == null) {
- } else if (player.isNowPlaying()) {
- rewind();
- } else {
- handlePlayOrPause();
- }
- break;
- }
- }
- };
-
- @Override
- public void onStart(Intent intent) {
- Common.d("video", "onStart");
- super.onStart(intent);
- //设置布局
- Common.d("before setUIContent");
- super.setUIContent(ResourceTable.Layout_ability_sample_video_player);
- Common.d("after setUIContent");
- buttonPlay = (Button) findComponentById(ResourceTable.Id_button_play_or_pause);
- buttonRestart = (Button) findComponentById(ResourceTable.Id_button_restart);
- buttonPlay.setClickedListener(listener);
- buttonRestart.setClickedListener(listener);
- //进度条可以拖拽
- slider = (Slider) findComponentById(ResourceTable.Id_slider);
- slider.setValueChangedListener(sliderValueChangedListener);
- // handler的处理函数运行在主线程中,用来更新界面
- // 如果参数传入用EventRunner.create(),则handler的处理函数在子线程中运行,并不在主线程中运行。
- handler = new MyEventHandler(EventRunner.current());
- textSliderMax = (Text) findComponentById(ResourceTable.Id_text_slider_max);
- textSliderCurrent = (Text) findComponentById(ResourceTable.Id_text_slider_current);
- //视频内容显示在SurfaceProvider组件中
- sp = (SurfaceProvider) findComponentById(ResourceTable.Id_sp);
- sp.pinToZTop(true);
- sp.getSurfaceOps().get().addCallback(surfaceOpsCallBack);
- // 可忽略,弹框授权
- Common.grand(this, "ohos.permission.READ_MEDIA");
- Common.d("onStart() ---");
-
- }
-
- @Override
- public void onActive() {
- super.onActive();
- }
-
- @Override
- public void onForeground(Intent intent) {
- super.onForeground(intent);
- }
-
-
- private void rewind() {
- player.rewindTo(0);
- }
-
- private void handlePlayOrPause() {
- Common.d("handlePlayOrPause()");
- try {
- if (player == null) {
- //首次播放
- Common.d("handlePlayOrPause() try to play from start");
- play();
- Element element = new VectorElement(this, ResourceTable.Graphic_icon_pause);
- buttonPlay.setBackground(element);
-
- new ToastDialog(getContext())
- .setText("playing")
- // Toast显示在界面底部
- .setAlignment(LayoutAlignment.BOTTOM)
- .show();
- } else if (!player.isNowPlaying()) {
- //暂停了或者播放完成了,则继续播放或者从头播放
- Common.d("handlePlayOrPause() go on playing");
- player.play();
- Element element = new VectorElement(this, ResourceTable.Graphic_icon_pause);
- buttonPlay.setBackground(element);
- new ToastDialog(getContext())
- .setText("playing")
- .setAlignment(LayoutAlignment.BOTTOM)
- .show();
- } else if (player.isNowPlaying()) {
- Common.d("handlePlayOrPause() try to pause");
- pause();
- Element element = new VectorElement(this, ResourceTable.Graphic_icon_play);
- buttonPlay.setBackground(element);
- new ToastDialog(getContext())
- .setText("paused")
- .setAlignment(LayoutAlignment.BOTTOM)
- .show();
- }
- } catch (Exception e) {
- e.printStackTrace();
- Common.d("e:" + e);
- }
- }
-
- public void preparePlayer() {
- // 步骤 1:实例化对象
- if (player == null) {
- player = new Player(this);
- }
- try {
- if (true) {
- //此文件放在rawfile/目录中
- RawFileEntry entry = getResourceManager().getRawFileEntry("resources/rawfile/vid_2.mp4");//这一行和官方例子有点不一样 请注意
- FileDescriptor fd = null;
- fd = entry.openRawFileDescriptor().getFileDescriptor();
- Common.d("fd=" + fd + " valid=" + fd.valid());
- player.setSource(entry.openRawFileDescriptor());
- } else {
- //此文件放在sdcard中,但我运行总说没有权限读取文件。
- FileInputStream fileInputStream = new FileInputStream(new File("/sdcard/xxx.mp4"));
- FileDescriptor fd = fileInputStream.getFD();
- Source source = new Source(fd);
- player.setSource(source);
- }
- player.prepare();
- //设置显示在sp中
- player.setVideoSurface(sp.getSurfaceOps().get().getSurface());
- //播放完成或者播放出错的回调函数
- player.setPlayerCallback(playerCallback);
- //ms为单位,视频时长
- int duration = player.getDuration();
- Common.d("duration=" + duration);
- slider.setMaxValue(duration);
- textSliderMax.setText((duration + 500) / 1000 + "s");
- textSliderCurrent.setText("0s");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- public void play() {
- Common.d("play()");
- preparePlayer();
- try {
- //因为Player的PlayerCallback中onMediaTimeIncontinuity()并不会每秒更新,
- //所以在onMediaTimeIncontinuity()中更新进度条的话,进度条可能长时间不动,一动就是好几秒过去了
- //Player的PlayerCallback中没有一个函数是每秒更新的,
- //所以PlayerCallback()中不适合更新进度条。
- //还是用线程每秒更新吧
- new Thread(new Runnable() {
- @Override
- public void run() {
- Common.d("run() duration=" + player.getDuration());
- int duration = player.getDuration();
- for (int i = 0; i < (duration + 500) / 1000; i++) {
- if (player == null) break;
- if (player.isNowPlaying()) {
- InnerEvent event = InnerEvent.get(handler.MSG_UPDATE_PROGRESS);
- handler.sendEvent(event);
- }
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }).start();
- //set progress --
- player.play();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public void stop() {
- Common.d("stop()");
- if (player != null) {
- player.stop();
- player.release();
- player = null;
- }
- }
-
- public void pause() {
- if (player != null) {
- player.pause();
- }
- }
-
- public class MyEventHandler extends EventHandler {
- public final int MSG_UPDATE_PROGRESS = 1;
- public final int MSG_UPDATE_BUTTON_PLAYING = 2;
- public final int MSG_UPDATE_BUTTON_PAUSED = 3;
-
- public MyEventHandler(EventRunner runner) throws IllegalArgumentException {
- super(runner);
- }
-
- @Override
- protected void processEvent(InnerEvent event) {
- //运行在主线程中
- super.processEvent(event);
- int eventId = event.eventId;
- switch (eventId) {
- case MSG_UPDATE_PROGRESS:
- int duration = player.getDuration();
- int currentTime = player.getCurrentTime();
- int delta = (duration - currentTime + 500) / 1000;
- String t = delta + " s remaining";
- Common.d("hint1:" + t + " progress=" + (currentTime + 500) / 1000);
- slider.setProgressValue(currentTime);
- slider.setProgressHintText(t);
- textSliderCurrent.setText((currentTime + 500) / 1000 + "s");
- Common.d("hint2:" + slider.getProgressHintText() + " progress=" + slider.getProgress());
- break;
- case MSG_UPDATE_BUTTON_PLAYING:
- Element element = new VectorElement(SampleVideoPlayerAbilitySlice.this, ResourceTable.Graphic_icon_pause);
- buttonPlay.setBackground(element);
- break;
- case MSG_UPDATE_BUTTON_PAUSED:
- Element elementPaused = new VectorElement(SampleVideoPlayerAbilitySlice.this, ResourceTable.Graphic_icon_play);
- buttonPlay.setBackground(elementPaused);
- break;
- }
- }
- }
- }
有任何问题欢迎指正!
如果觉得有用的话,就请我喝瓶水吧~~~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。