开源播放器GSYVideoPlayer + ViewPager2 源码解析

开源播放器GSYVideoPlayer + ViewPager2 源码解析


前言

本文介绍GSYVideoPlayer源码中关于ViewPager2 +GSYVideoPlayer 实现的滑动播放列表的实现原理。

本文使用的版本为gsyVideoPlayerVersion = "7.1.4"


一、GSYVideoPlayer🔥🔥🔥是什么?

github地址: https://github.com/CarGuo/GSYVideoPlayer

让我们看看介绍:

视频播放器(IJKplayer、ExoPlayer、MediaPlayer),HTTPS支持,支持弹幕,支持滤镜、水印、gif截图,片头广告、中间广告,多个同时播放,支持基本的拖动,声音、亮度调节,支持边播边缓存,支持视频本身自带rotation的旋转(90,270之类),重力旋转与手动旋转的同步支持,支持列表播放 ,直接添加控件为封面,列表全屏动画,视频加载速度,列表小窗口支持拖动,动画效果,调整比例,多分辨率切换,支持切换播放器,进度条小窗口预览,其他一些小动画效果,rtsp、concat、mpeg。(总结,高端大气上档次)
让我们看看作者:

让我们看看文档:

优点

  • 支持好几种开源播放器,集大成者
  • 可以按需引用所需要的依赖,这样一来包体积不会太大
  • 作者维护很勤快,有什么问题issues,作者也会帮忙看看
  • 文档写的很清楚不需要额外查资料,实在不懂代码拉下来一跑,对照着代码基本上就能理解了

缺点:

-有一些版本对应会有不同的问题,比如我使用的时候用了最新的依赖,按照文档不能播放rtsp流,降低了依赖过后就可以播放了。

如果想使用其他播放器的可以看看我的这篇文章

安卓的播放器对比与选型(vlc,EXOplayer,Ijkplayer,GSYVideoPlayer)详细过程

二、源码解析

1.ViewPager2Activity

在ViewPager2Activity中,我们可以看到相关代码。

代码如下(示例):

kotlin 复制代码
 viewPagerAdapter = new ViewPagerAdapter(this, dataList);
        binding.viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
        binding.viewPager2.setAdapter(viewPagerAdapter);
        binding.viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
                //大于0说明有播放
                int playPosition = GSYVideoManager.instance().getPlayPosition();
                if (playPosition >= 0) {
                    //对应的播放列表TAG
                    if (GSYVideoManager.instance().getPlayTag().equals(RecyclerItemNormalHolder.TAG)
                        && (position != playPosition)) {
                        GSYVideoManager.releaseAllVideos();
                        playPosition(position);
                    }
                }
            }
        });
        binding.viewPager2.post(new Runnable() {
            @Override
            public void run() {
                playPosition(0);
            }
        });
    }

这段代码是在使用Android中的ViewPager2来创建一个滑动页面效果。ViewPager2是Android提供的一个用于实现滑动页面效果的组件。下面是对这段代码的逐行解释:

  1. viewPagerAdapter = new ViewPagerAdapter(this, dataList); 这一行是创建一个ViewPager的适配器,其中this是指当前的Activity,dataList是用来提供数据给ViewPager的列表。
  2. binding.viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL); 这一行是设置ViewPager的滑动方向为垂直滑动。
  3. binding.viewPager2.setAdapter(viewPagerAdapter); 这一行是将刚刚创建的ViewPager适配器设置到ViewPager上。
  4. binding.viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {...}); 这一行是注册一个页面改变的回调。当ViewPager的页面发生改变时,会回调这个接口的实现。
  5. 在回调的实现中,int playPosition = GSYVideoManager.instance().getPlayPosition(); 获取当前播放的位置。
  6. if (playPosition >= 0) {...} 这个判断是为了确认当前有视频播放状态是正常的。
  7. 在这个if语句中,首先判断当前正在播放的视频的Tag是否等于RecyclerItemNormalHolder的Tag,如果不是,那么就释放所有的视频并跳转到当前的位置。这个逻辑是为了处理当页面发生改变时,如果当前播放的视频不在这个页面上,就停止播放并跳转到当前页面的视频。
  8. binding.viewPager2.post(new Runnable() {...}); 这一行代码在ViewPager的Looper中执行一个Runnable,这个Runnable会在ViewPager的UI线程中运行。
  9. 在Runnable的实现中,调用playPosition(0); 方法,是为了在页面加载完成后自动播放位于第一个位置的视频。

在上面的代码中,我们可以看到playPosition这个方法出现了两次,并且从名字中可以看出是播放的方法,我们接下来看看这个方法干了些什么。

kotlin 复制代码
    private void playPosition(int position) {
        binding.viewPager2.postDelayed(new Runnable() {
            @Override
            public void run() {
                RecyclerView.ViewHolder viewHolder = ((RecyclerView) binding.
                    viewPager2.getChildAt(0)).findViewHolderForAdapterPosition(position);
                if (viewHolder != null) {
                    RecyclerItemNormalHolder recyclerItemNormalHolder = (RecyclerItemNormalHolder) viewHolder;
                    recyclerItemNormalHolder.getPlayer().startPlayLogic();
                }
            }
        }, 50);
    }

可以看到playPosition通过findViewHolderForAdapterPosition方法找到了当前viewPager2对应的viewHolder,通过viewHolder的getPlayer()方法获取到了播放器,并开始了播放,我们再去看看RecyclerItemNormalHolder类。

kotlin 复制代码
package com.example.gsyvideoplayer.holder;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.example.gsyvideoplayer.R;
import com.example.gsyvideoplayer.databinding.ActivityDetailExoSubtitlePlayerBinding;
import com.example.gsyvideoplayer.model.VideoModel;
import com.example.gsyvideoplayer.video.SampleCoverVideo;
import com.shuyu.gsyvideoplayer.GSYVideoManager;
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder;
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack;
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by guoshuyu on 2017/1/9.
 */

public class RecyclerItemNormalHolder extends RecyclerItemBaseHolder {

    public final static String TAG = "RecyclerView2List";

    protected Context context;

    SampleCoverVideo gsyVideoPlayer;

    ImageView imageView;

    GSYVideoOptionBuilder gsyVideoOptionBuilder;

    public RecyclerItemNormalHolder(Context context, View v) {
        super(v);
        this.context = context;
        gsyVideoPlayer = v.findViewById(R.id.video_item_player);
        imageView = new ImageView(context);
        gsyVideoOptionBuilder = new GSYVideoOptionBuilder();
    }

    public void onBind(final int position, VideoModel videoModel) {

        String url;
        String title;
        if (position % 2 == 0) {
            url = "https://pointshow.oss-cn-hangzhou.aliyuncs.com/McTk51586843620689.mp4";
            title = "这是title";
        } else {
            url = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";
            title = "哦?Title?";
        }


        Map<String, String> header = new HashMap<>();
        header.put("ee", "33");

        //防止错位,离开释放
        //gsyVideoPlayer.initUIState();
        gsyVideoOptionBuilder
            .setIsTouchWiget(false)
            //.setThumbImageView(imageView)
            .setUrl(url)
            .setVideoTitle(title)
            .setCacheWithPlay(false)
            .setRotateViewAuto(true)
            .setLockLand(true)
            .setPlayTag(TAG)
            .setMapHeadData(header)
            .setShowFullAnimation(true)
            .setNeedLockFull(true)
            .setPlayPosition(position)
            .setVideoAllCallBack(new GSYSampleCallBack() {
                @Override
                public void onPrepared(String url, Object... objects) {
                    super.onPrepared(url, objects);
                    if (!gsyVideoPlayer.isIfCurrentIsFullscreen()) {
                        //静音
                        GSYVideoManager.instance().setNeedMute(true);
                    }

                }

                @Override
                public void onQuitFullscreen(String url, Object... objects) {
                    super.onQuitFullscreen(url, objects);
                    //全屏不静音
                    GSYVideoManager.instance().setNeedMute(true);
                }

                @Override
                public void onEnterFullscreen(String url, Object... objects) {
                    super.onEnterFullscreen(url, objects);
                    GSYVideoManager.instance().setNeedMute(false);
                    gsyVideoPlayer.getCurrentPlayer().getTitleTextView().setText((String) objects[0]);
                }
            }).build(gsyVideoPlayer);


        //增加title
        gsyVideoPlayer.getTitleTextView().setVisibility(View.GONE);

        //设置返回键
        gsyVideoPlayer.getBackButton().setVisibility(View.GONE);

        //设置全屏按键功能
        gsyVideoPlayer.getFullscreenButton().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                resolveFullBtn(gsyVideoPlayer);
            }
        });

        gsyVideoPlayer.loadCoverImageBy(R.mipmap.xxx2, R.mipmap.xxx2);
    }

    /**
     * 全屏幕按键处理
     */
    private void resolveFullBtn(final StandardGSYVideoPlayer standardGSYVideoPlayer) {
        standardGSYVideoPlayer.startWindowFullscreen(context, true, true);
    }

    public SampleCoverVideo getPlayer() {
        return gsyVideoPlayer;
    }
}

为了让读者看的更清晰,我提了整个类,可以看到,在自身初始化时就对gsyVideoPlayer进行了初始化,并且在数据绑定的onBind方法中为了防止错位,专门设置了gsyVideoOptionBuilder,而getPlayer方法只是把gsyVideoPlayer返回。所以,实现列表播放的关键代码其实就是gsyVideoOptionBuilder

kotlin 复制代码
 gsyVideoOptionBuilder
            .setIsTouchWiget(false)
            //.setThumbImageView(imageView)
            .setUrl(url)
            .setVideoTitle(title)
            .setCacheWithPlay(false)
            .setRotateViewAuto(true)
            .setLockLand(true)
            .setPlayTag(TAG)
            .setMapHeadData(header)
            .setShowFullAnimation(true)
            .setNeedLockFull(true)
            .setPlayPosition(position)

总结

本文主要介绍了开源播放器GSYVideoPlayer和ViewPager2的结合使用,实现滑动播放列表的原理。通过对ViewPager2Activity、RecyclerItemNormalHolder等类中的代码解析,了解了如何在ViewPager2中播放视频,关键代码为gsyVideoOptionBuilder。GSYVideoPlayer支持多种开源播放器,具有较好的维护和文档,但使用时需注意不同版本对应问题。

相关推荐
小牛itbull3 小时前
ReactPress:构建高效、灵活、可扩展的开源发布平台
react.js·开源·reactpress
IT规划师3 小时前
开源 - Ideal库 - 常用枚举扩展方法(一)
开源·c#·.net core·ideal库·枚举转换
OpenI启智社区4 小时前
共筑开源技术新篇章 | 2024 CCF中国开源大会盛大开幕
人工智能·开源·ccf中国开源大会·大湾区
AI服务老曹4 小时前
建立更及时、更有效的安全生产优化提升策略的智慧油站开源了
大数据·人工智能·物联网·开源·音视频
IT规划师6 小时前
开源 - Ideal库 -获取特殊时间扩展方法(三)
开源·ideal库·特殊时间
OpenI启智社区6 小时前
湾区聚力 开源启智 | 2024 CCF中国开源大会暨第五届OpenI/O启智开发者大会闪耀深圳
人工智能·开源·openi启智社区·ccf中国开源大会·启智开发者大会
vvw&11 小时前
Seafile 私有云盘部署教程
linux·运维·服务器·开源·云盘·网盘·seafile
临水逸16 小时前
GitHub 上的开源项目推荐
开源·github
LunarCod18 小时前
WorkFlow源码剖析——Communicator之TCPServer(下)
开源·workflow·c/c++·网络框架·异步编程·高性能高并发