一、申请读取内存权限,详见官方文档:
实现播放单独一个视频参考官网的文档即可,这里主要实现的是自动循环播放多个视频,并且可以控制视频上一曲、下一曲、暂停和播放功能。
二、创建VideoProvider集成SurfaceProvider实现视频播放
快捷键Alt+INS自动生成构造方法(构造方法写一个就行,这里我三个都写),在最后一个构造方法中创建Player对象,this.pinToZTop(true)这一行很重要,是将SurfaceProvider放在最上层显示,如果没有设置成ture视频播放只有声音没有画面。
package com.example.hello.world;
import ohos.agp.components.AttrSet;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.SurfaceOps;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.media.common.Source;
import ohos.media.player.Player;
import java.util.List;
public class VideoProvider extends SurfaceProvider {
public VideoProvider(Context context) {
this(context, null);
}
public VideoProvider(Context context, AttrSet attrSet) {
this(context, attrSet, null);
}
public VideoProvider(Context context, AttrSet attrSet, String styleName) {
super(context, attrSet, styleName);
initPlayer();
}
private void initPlayer() {
this.pinToZTop(true);
this.getSurfaceOps().get().addCallback(callback);
}
}
通过Set方法传去需要播放的列表,链式写法用起来更方便,全局定义一个mIndex作为自动循环播放的下边进行遍历播放。
public VideoProvider setResource(List<String> resource) {
this.mResource = resource;
return this;
}
public void startAutoPlay() {
start();
}
给Player设置播放路径和画面输出窗口,并给Player设置视频播放过程监听接口。注意setSource()必须要在play()前面:
private void start() {
if (null == player) {
player = new Player(getContext());
player.setPlayerCallback(playerCallback);
}
String path = mResource.get(mIndex % mResource.size());
Source source = new Source(path);
player.setSource(source);
player.prepare();
player.setVideoSurface(this.getSurfaceOps().get().getSurface());
play();
}
实现视频上一曲、下一曲、暂停和播放的可控制方法:
public void next() {
mIndex += 1;
preparePlayer();
}
public void previous() {
mIndex -= 1;
if (mIndex < 0) mIndex = mResource.size() - 1;
preparePlayer();
}
public void play() {
if (null != player && !player.isNowPlaying()) player.play();
}
public void pause() {
if (null != player && player.isNowPlaying()) player.pause();
}
在Player播放回调接口监听视频播放完成出发自动切换到下一个视频播放:
private final Player.IPlayerCallback playerCallback = new Player.IPlayerCallback() {
@Override
public void onPrepared() {
}
@Override
public void onMessage(int i, int i1) {
}
@Override
public void onError(int i, int i1) {
}
@Override
public void onResolutionChanged(int i, int i1) {
}
@Override
public void onPlayBackComplete() {
pause();
next();
}
@Override
public void onRewindToComplete() {
}
@Override
public void onBufferingChange(int i) {
}
@Override
public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData) {
}
@Override
public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo) {
}
};
使用VideoProvider 播放列表视频:
<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<com.example.hello.world.VideoProvider
ohos:id="$+id:main_surface_provide"
ohos:width="match_parent"
ohos:height="match_parent"/>
</DependentLayout>
package com.example.hello.world.slice;
import com.example.hello.world.ResourceTable;
import com.example.hello.world.VideoProvider;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import java.util.ArrayList;
import java.util.List;
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
VideoProvider videoProvider = (VideoProvider) findComponentById(ResourceTable.Id_main_surface_provide);
List<String> resource = new ArrayList<>();//List数据自己整理,是本地视频文件的绝对路径即可
videoProvider.setResource(resource).startAutoPlay();
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
最后写资源释放方法,由于对SurfaceProvider进行了pinToZTop(true)处理,如果在Fraction中进行播放视频,Fraction销毁后还会在屏幕上留下一块黑色区域,通过removeFromWindow()方法将SurfaceProvider窗口移除:
public void stopAutoPlay() {
if (null != player) {
player.stop();
player.release();
player = null;
}
this.removeFromWindow();
}
最后发现不能播放视频没有画面也没有声音,研究了好久才解决,原来是不能在player.setSource(source)后立即调用Player()进行播放,需要延迟个500毫秒左右,因此添加一个VideoHandler将Play()方法延迟500毫秒执行。
private void preparePlayer() {
InnerEvent event = InnerEvent.get(VideoHandler.HANDLER_COMMAND_PLAY);
videoHandler.sendEvent(event, VideoHandler.HANDLER_DELAY);
}
private class VideoHandler extends EventHandler {
public static final int HANDLER_COMMAND_PLAY = 1;
public static final long HANDLER_DELAY = 500;
public VideoHandler(EventRunner runner) throws IllegalArgumentException {
super(runner);
}
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
if (null == event) return;
if (event.eventId == HANDLER_COMMAND_PLAY) start();
}
}
由于SurfaceProvider已经至于布局的顶层,之后需要写视频的播放进度条和暂停按钮都显示不出来,解决方法是将pinToZTop(true)替换成:
pinToZTop(false);
getWindow().setTransparent(false);
完整代码:
package com.example.hello.world;
import ohos.agp.components.AttrSet;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.SurfaceOps;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.media.common.Source;
import ohos.media.player.Player;
import java.util.List;
public class VideoProvider extends SurfaceProvider {
private List<String> mResource;
private int mIndex = 0;
private Player player;
private VideoHandler videoHandler;
public VideoProvider(Context context) {
this(context, null);
}
public VideoProvider(Context context, AttrSet attrSet) {
this(context, attrSet, null);
}
public VideoProvider(Context context, AttrSet attrSet, String styleName) {
super(context, attrSet, styleName);
initPlayer();
}
private void initPlayer() {
this.pinToZTop(true);
videoHandler = new VideoHandler(EventRunner.current());
this.getSurfaceOps().get().addCallback(callback);
}
public VideoProvider setResource(List<String> resource) {
this.mResource = resource;
return this;
}
public void startAutoPlay() {
preparePlayer();
}
private void preparePlayer() {
InnerEvent event = InnerEvent.get(VideoHandler.HANDLER_COMMAND_PLAY);
videoHandler.sendEvent(event, VideoHandler.HANDLER_DELAY);
}
private void start() {
if (null == player) {
player = new Player(getContext());
player.setPlayerCallback(playerCallback);
}
String path = mResource.get(mIndex % mResource.size());
Source source = new Source(path);
player.setSource(source);
player.prepare();
player.setVideoSurface(this.getSurfaceOps().get().getSurface());
play();
}
public void next() {
mIndex += 1;
preparePlayer();
}
public void previous() {
mIndex -= 1;
if (mIndex < 0) mIndex = mResource.size() - 1;
preparePlayer();
}
public void play() {
if (null != player && !player.isNowPlaying()) player.play();
}
public void pause() {
if (null != player && player.isNowPlaying()) player.pause();
}
public void stopAutoPlay() {
if (null != player) {
player.stop();
player.release();
player = null;
}
this.removeFromWindow();
}
private final SurfaceOps.Callback callback = new SurfaceOps.Callback() {
@Override
public void surfaceCreated(SurfaceOps surfaceOps) {
}
@Override
public void surfaceChanged(SurfaceOps surfaceOps, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceOps surfaceOps) {
}
};
private final Player.IPlayerCallback playerCallback = new Player.IPlayerCallback() {
@Override
public void onPrepared() {
}
@Override
public void onMessage(int i, int i1) {
}
@Override
public void onError(int i, int i1) {
}
@Override
public void onResolutionChanged(int i, int i1) {
}
@Override
public void onPlayBackComplete() {
pause();
next();
}
@Override
public void onRewindToComplete() {
}
@Override
public void onBufferingChange(int i) {
}
@Override
public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData) {
}
@Override
public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo) {
}
};
private class VideoHandler extends EventHandler {
public static final int HANDLER_COMMAND_PLAY = 1;
public static final long HANDLER_DELAY = 500;
public VideoHandler(EventRunner runner) throws IllegalArgumentException {
super(runner);
}
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
if (null == event) return;
if (event.eventId == HANDLER_COMMAND_PLAY) start();
}
}
}