鸿蒙开发(JAVA)使用SurfaceProvider+Player实现播放本地视频功能。

一、申请读取内存权限,详见官方文档:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/security-permissions-guidelines-0000000000029886

        实现播放单独一个视频参考官网的文档即可,这里主要实现的是自动循环播放多个视频,并且可以控制视频上一曲、下一曲、暂停和播放功能。

 二、创建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();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值