Android 视频播放器dkplayer

这篇具有很好参考价值的文章主要介绍了Android 视频播放器dkplayer。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

gihub地址

https://github.com/Doikki/DKVideoPlayer

GitHub - Doikki/DKVideoPlayer: Android Video Player. 安卓视频播放器,封装MediaPlayer、ExoPlayer、IjkPlayer。模仿抖音并实现预加载,列表播放,悬浮播放,广告播放,弹幕,视频水印,视频滤镜

列表播放如图所示:

Android 视频播放器dkplayer,android,音视频

一、依赖

     //添加RecyclerView的依赖包
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
    // 异步加载图片依赖
    implementation 'com.squareup.picasso:picasso:2.5.2'
    // 上拉刷新、下来加载依赖
    implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.3'
    // --  Android:视频播放器dkplayer
    //# 必选,内部默认使用系统mediaplayer进行解码
    implementation 'com.github.dueeeke.dkplayer:dkplayer-java:3.2.6'
    //# 可选,包含StandardVideoController的实现
    implementation 'com.github.dueeeke.dkplayer:dkplayer-ui:3.2.6'
    //# 可选,使用exoplayer进行解码
    implementation 'com.github.dueeeke.dkplayer:player-exo:3.2.6'
    //# 可选,使用ijkplayer进行解码
    implementation 'com.github.dueeeke.dkplayer:player-ijk:3.2.6'
    //# 可选,如需要缓存或者抖音预加载功能请引入此库
    implementation 'com.github.dueeeke.dkplayer:videocache:3.2.6'

二、工具类

Tag.java

package com.chy.permission;

/**
 * 播放器标签
 */
public final class Tag {
    //列表播放
    public static final String LIST = "list";
    //无缝播放
    public static final String SEAMLESS = "seamless";
    //画中画
    public static final String PIP = "pip";
}
Utils.java
package com.chy.permission;

import android.view.View;
import android.view.ViewParent;
import android.widget.FrameLayout;

import com.dueeeke.videoplayer.player.VideoView;
import com.dueeeke.videoplayer.player.VideoViewConfig;
import com.dueeeke.videoplayer.player.VideoViewManager;

import java.lang.reflect.Field;

public final class Utils {

    private Utils() {
    }


    /**
     * 获取当前的播放核心
     */
    public static Object getCurrentPlayerFactory() {
        VideoViewConfig config = VideoViewManager.getConfig();
        Object playerFactory = null;
        try {
            Field mPlayerFactoryField = config.getClass().getDeclaredField("mPlayerFactory");
            mPlayerFactoryField.setAccessible(true);
            playerFactory = mPlayerFactoryField.get(config);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return playerFactory;
    }

    /**
     * 将View从父控件中移除
     */
    public static void removeViewFormParent(View v) {
        if (v == null) return;
        ViewParent parent = v.getParent();
        if (parent instanceof FrameLayout) {
            ((FrameLayout) parent).removeView(v);
        }
    }

    /**
     * Returns a string containing player state debugging information.
     */
    public static String playState2str(int state) {
        String playStateString;
        switch (state) {
            default:
            case VideoView.STATE_IDLE:
                playStateString = "idle";
                break;
            case VideoView.STATE_PREPARING:
                playStateString = "preparing";
                break;
            case VideoView.STATE_PREPARED:
                playStateString = "prepared";
                break;
            case VideoView.STATE_PLAYING:
                playStateString = "playing";
                break;
            case VideoView.STATE_PAUSED:
                playStateString = "pause";
                break;
            case VideoView.STATE_BUFFERING:
                playStateString = "buffering";
                break;
            case VideoView.STATE_BUFFERED:
                playStateString = "buffered";
                break;
            case VideoView.STATE_PLAYBACK_COMPLETED:
                playStateString = "playback completed";
                break;
            case VideoView.STATE_ERROR:
                playStateString = "error";
                break;
        }
        return String.format("playState: %s", playStateString);
    }

    /**
     * Returns a string containing player state debugging information.
     */
    public static String playerState2str(int state) {
        String playerStateString;
        switch (state) {
            default:
            case VideoView.PLAYER_NORMAL:
                playerStateString = "normal";
                break;
            case VideoView.PLAYER_FULL_SCREEN:
                playerStateString = "full screen";
                break;
            case VideoView.PLAYER_TINY_SCREEN:
                playerStateString = "tiny screen";
                break;
        }
        return String.format("playerState: %s", playerStateString);
    }


}

VideoAdapter.java

package com.chy.demoprj.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.chy.demoprj.R;
import com.dueeeke.videocontroller.component.PrepareView;
import com.squareup.picasso.Picasso;

import java.util.HashMap;
import java.util.List;

public class VideoAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context context;
    private List<HashMap<String,String>> datas;

    private OnItemChildClickListener mOnItemChildClickListener;// 播放控件点击事件

    /**
     * 构造函数
     * */
    public VideoAdapter(Context context,List<HashMap<String,String>> datas){
        this.context = context;
        this.datas = datas;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.item_video_layout,parent,false);
         ViewHolder viewHolder = new ViewHolder(view);

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder,int position) {
        ViewHolder vh = (ViewHolder) holder;
        HashMap<String,String> entity = datas.get(position);

        // 设置播放占位图(不设置默认黑色)
        Picasso.with(context)
                .load(entity.get("thumbUrl"))
                .into(vh.mThumb);

        vh.mPosition = position;
    }

    @Override
    public int getItemCount() {
        return datas.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
        public FrameLayout mPlayerContainer;// 容器
        public PrepareView mPrepareView;// 播放视图
        public ImageView mThumb;// 缩略图
        public int mPosition;// 当前视图index

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            mPlayerContainer = itemView.findViewById(R.id.player_container);
            mPrepareView = itemView.findViewById(R.id.prepare_view);
            mThumb = mPrepareView.findViewById(R.id.thumb);

            /**
             * 添加点击事件
             * */
            if (mOnItemChildClickListener != null) {
                mPlayerContainer.setOnClickListener(this);
            }


            //通过tag将ViewHolder和itemView绑定
            itemView.setTag(this);
        }

        @Override
        public void onClick(View v) {
            if (v.getId() == R.id.player_container){

                if (mOnItemChildClickListener != null){
                    mOnItemChildClickListener.onItemChildClick(mPosition);
                }

            }
        }
    }

    /**
     * 点击事件接口
     * */
    public interface OnItemChildClickListener{
        void onItemChildClick(int position);
    }

    /**
     * 点击事件回调函数
     * */
    public void setOnItemChildClickListener(OnItemChildClickListener onItemChildClickListener) {
        mOnItemChildClickListener = onItemChildClickListener;
    }

}

三、布局

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<com.scwang.smartrefresh.layout.SmartRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/refreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>


</com.scwang.smartrefresh.layout.SmartRefreshLayout>

item_video_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/player_container"
        android:layout_width="match_parent"
        android:layout_height="187dp"
        android:layout_marginTop="8dp"
        android:background="@android:color/black"
        app:layout_constraintDimensionRatio="16:9"
        app:layout_constraintTop_toTopOf="parent">

        <com.dueeeke.videocontroller.component.PrepareView
            android:id="@+id/prepare_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </FrameLayout>


</LinearLayout>

四、实现文章来源地址https://www.toymoban.com/news/detail-638029.html

package com.chy.demoprj;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.Manifest;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.chy.demoprj.adapter.VideoAdapter;
import com.chy.permission.PermissionUtils;
import com.chy.permission.Tag;
import com.chy.permission.Utils;
import com.dueeeke.videocontroller.StandardVideoController;
import com.dueeeke.videocontroller.component.CompleteView;
import com.dueeeke.videocontroller.component.ErrorView;
import com.dueeeke.videocontroller.component.GestureView;
import com.dueeeke.videocontroller.component.TitleView;
import com.dueeeke.videocontroller.component.VodControlView;
import com.dueeeke.videoplayer.player.VideoView;
import com.dueeeke.videoplayer.player.VideoViewManager;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.listener.OnLoadMoreListener;
import com.scwang.smartrefresh.layout.listener.OnRefreshListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private static final int REQUEST_PERMISSION_CODE = 0;// 权限所用
    // 动态申请权限
    private String[] permissions = {
            Manifest.permission.INTERNET,// 网络权限
            Manifest.permission.WRITE_EXTERNAL_STORAGE,// 写入数据权限
            Manifest.permission.READ_EXTERNAL_STORAGE,// 读取数据权限
            Manifest.permission.ACCESS_FINE_LOCATION,// 定位权限
            Manifest.permission.ACCESS_COARSE_LOCATION // 获取基站的服务信号权限,以便获取位置信息
    };


    private RefreshLayout refreshLayout;
    private RecyclerView recyclerView;// 列表
    private LinearLayoutManager layoutManager;
    private List<HashMap<String,String>> datas = new ArrayList<>();

    // 视频播放-控件
    protected VideoView mVideoView;
    protected StandardVideoController mController;
    protected ErrorView mErrorView;
    protected CompleteView mCompleteView;
    protected TitleView mTitleView;

    /**
     * 当前播放的位置
     * */
    protected int mCurPos = -1;
    /**
     * 上次播放的位置,用于页面切换回来继续播放
     * */
    protected int mLastPos = mCurPos;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getPermission();


        initData();
        initControls();
        initVideoView();

    }

    /**
     * 权限
     * */
    private void getPermission(){
        boolean flage = PermissionUtils.hasPermissions(MainActivity.this,permissions);
        if (flage) {
            System.out.println("权限获取成功!");
        } else {
            PermissionUtils.requestPermissions(MainActivity.this, REQUEST_PERMISSION_CODE, permissions);
        }
    }


    /**
     * 数据初始化
     * */
    private void initData(){
        HashMap<String,String> hashMap = null;
        // 占位图
        String thumbUrl = "https://p1-xg.byteimg.com/img/tos-cn-p-0000/527b08d0f31d4705a4d8f4a72120948c~tplv-crop-center:1041:582.jpg";
        // 视频播放地址
        String playerUrl = "https://vd4.bdstatic.com/mda-pdhb52ikamv3bdb7/sc/cae_h264/1681819063478400576/mda-pdhb52ikamv3bdb7.mp4";
        // 循环添加数据
        for (int i=0,len=8;i<=len;i++){
            hashMap = new HashMap<>();
            hashMap.put("thumbUrl",thumbUrl);
            hashMap.put("playerUrl",playerUrl);
            hashMap.put("vtitle","播放标题"+i);

            datas.add(hashMap);
        }

    }

    /**
     * 初始化控件
     * */
    private void initControls(){
        refreshLayout = findViewById(R.id.refreshLayout);
        // 下拉刷新事件
        refreshLayout.setOnRefreshListener(new OnRefreshListener() {
            @Override
            public void onRefresh(@NonNull RefreshLayout refreshLayout) {
                refreshLayout.finishRefresh(2000/*,false*/);// 传入false表示刷新失败

            }
        });
        // 上拉加载事件
        refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
                refreshLayout.finishLoadMore(2000/*,false*/);// 传入false表示加载失败
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplication(),"没有更多数据",Toast.LENGTH_SHORT).show();
                    }
                });

            }
        });


        recyclerView = findViewById(R.id.recyclerView);
        // 设置布局
        layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);

        // 配置器
        VideoAdapter videoAdapter = new VideoAdapter(this,datas);
        // 设置点击事件
        videoAdapter.setOnItemChildClickListener(new VideoAdapter.OnItemChildClickListener() {
            @Override
            public void onItemChildClick(int position) {
                /**
                 * PrepareView被点击
                 */
                startPlay(position);
            }
        });

        recyclerView.setAdapter(videoAdapter);
        // RecyclerView监听事件
        recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
            @Override
            public void onChildViewAttachedToWindow(@NonNull View view) {

            }

            @Override
            public void onChildViewDetachedFromWindow(@NonNull View view) {
                FrameLayout playerContainer = view.findViewById(R.id.player_container);
                View v = playerContainer.getChildAt(0);
                if (v != null && v == mVideoView && !mVideoView.isFullScreen()){
                    releaseVideoView();
                }
            }
        });

    }


    /**
     * 播放控件初始化
     * */
    protected void initVideoView() {
        mVideoView = new VideoView(this);
        mVideoView.setOnStateChangeListener(new VideoView.SimpleOnStateChangeListener() {
            @Override
            public void onPlayStateChanged(int playState) {
                //监听VideoViewManager释放,重置状态
                if (playState == com.dueeeke.videoplayer.player.VideoView.STATE_IDLE) {
                    Utils.removeViewFormParent(mVideoView);
                    mLastPos = mCurPos;
                    mCurPos = -1;
                }
            }
        });

        mController = new StandardVideoController(this);
        mErrorView = new ErrorView(this);
        mController.addControlComponent(mErrorView);
        mCompleteView = new CompleteView(this);
        mController.addControlComponent(mCompleteView);
        mTitleView = new TitleView(this);
        mController.addControlComponent(mTitleView);
        mController.addControlComponent(new VodControlView(this));
        mController.addControlComponent(new GestureView(this));
        mController.setEnableOrientation(true);
        mVideoView.setVideoController(mController);
    }

    @Override
    public void onPause() {
        super.onPause();
        pause();
    }

    /**
     * 由于onPause必须调用super。故增加此方法,
     * 子类将会重写此方法,改变onPause的逻辑
     */
    protected void pause() {
        releaseVideoView();
    }

    @Override
    public void onResume() {
        super.onResume();
        resume();
    }


    /**
     * 由于onResume必须调用super。故增加此方法,
     * 子类将会重写此方法,改变onResume的逻辑
     */
    protected void resume() {
        if (mLastPos == -1)
            return;
        //恢复上次播放的位置
        startPlay(mLastPos);
    }



    /**
     * 开始播放
     *
     * @param position 列表位置
     */
    protected void startPlay(int position) {
        if (mCurPos == position) return;
        if (mCurPos != -1) {
            releaseVideoView();
        }
        HashMap<String,String> entity = datas.get(position);
        //边播边存
//        String proxyUrl = ProxyVideoCacheManager.getProxy(getActivity()).getProxyUrl(videoBean.getUrl());
//        mVideoView.setUrl(proxyUrl);
        String playurl = entity.get("playerUrl");
        mVideoView.setUrl(playurl);
        mTitleView.setTitle(entity.get("vtitle"));
        View itemView = layoutManager.findViewByPosition(position);
        if (itemView == null) return;
        VideoAdapter.ViewHolder viewHolder = (VideoAdapter.ViewHolder) itemView.getTag();
        //把列表中预置的PrepareView添加到控制器中,注意isPrivate此处只能为true。
        mController.addControlComponent(viewHolder.mPrepareView, true);
        Utils.removeViewFormParent(mVideoView);
        viewHolder.mPlayerContainer.addView(mVideoView, 0);
        //播放之前将VideoView添加到VideoViewManager以便在别的页面也能操作它
        getVideoViewManager().add(mVideoView, Tag.LIST);
        mVideoView.start();
        mCurPos = position;

    }


    /**
     * 释放播放控件
     * */
    private void releaseVideoView() {
        mVideoView.release();
        if (mVideoView.isFullScreen()) {
            mVideoView.stopFullScreen();
        }
        if (this.getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
            this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
        mCurPos = -1;
    }

    /**
     * 创建播放管理类
     * */
    protected VideoViewManager getVideoViewManager(){
        return VideoViewManager.instance();
    }


}

到了这里,关于Android 视频播放器dkplayer的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter视频播放器在iOS端和Android端都能实现全屏播放

    Flutter开发过程中,对于视频播放的三方组件有很多,在Android端适配都挺好,但是在适配iPhone手机的时候,如果设置了 UIInterfaceOrientationLandscapeLeft 和 UIInterfaceOrientationLandscapeRight 都为false的情况下,无法做到全屏播放,因为FLutter的 SystemChrome.setPreferredOrientations 方法不适配iOS端

    2024年02月05日
    浏览(47)
  • 零基础用Android Studio实现简单的本地视频播放器

    本文将讲解如何使用Android视频播放器VideoView组件来播放本地视频和网络视频,实现起来还是比较简单的。VideoView组件的作用与ImageView类似,只是ImageView用于显示图片,VideoView用于播放视频。 (本文章的代码参考: https://www.jb51.net/article/122051.htm) 实现效果: 用Android Studio做的

    2024年02月02日
    浏览(68)
  • 【Android入门到项目实战-- 11.4】—— ExoPlayer视频播放器框架的详细使用

    目录 什么是ExoPlayer 一、基本使用  1、添加依赖项  2、布局 3、Activity 二、自定义播放暂停 1、首先如何隐藏默认的开始暂停和快进? 2、自定义 三、控制视频画面旋转和比例调整 四、全屏放大和缩小 1、双击视频放大缩小 2、按钮放大缩小 五、完整的实现代码 XML Activity   

    2024年02月11日
    浏览(57)
  • 使用 LibVLC 构建自定义 Android 视频播放器:分步指南,降低延迟/图像失帧(附源码)

    前言 在这篇博文中,我们将深入探讨使用 LibVLC 库的自定义 Android 视频播放器的实现细节。本分步指南将涵盖设置播放器、处理各种事件以及在您的 Android 应用程序中提供无缝视频播放体验的基本方面。 一、LibVLC 概述: 视频播放是许多 Android 应用程序中的常见功能,从流媒

    2024年02月02日
    浏览(86)
  • 【Unity】代码控制视频的播放(视频播放器-更新)

     结果如上图,之前写过一个使用代码控制视频播放器的Demo,但是好多小伙伴说我附带的链接没法下载,这次我直接做一个完整版的,不用下载,照着一步一步做就能做出来。 之前写了如何设置RawImage进行自动播放,大家可以看一下基础操作这篇文章:,大佬勿怪。 【Unity】

    2024年02月09日
    浏览(59)
  • 【Xgplayer】xgplayer基本使用 | xgplayer使用 | 超好的前端视频播放器 | xgplayer前端最好视频播放器

    开发团队——字节跳动,字节跳动出品,必属精品。 xgplayer是一个超级牛逼的前端视频播放器,以下几个观点足以证明它的强大 大厂出品——稳 简洁 实用 优雅 文档清晰明了 支持弹幕 对移动端非常友好 自定义插件方便且强大 强就是了 xgplayer官网-点我进入 备用地址 https:

    2024年02月06日
    浏览(77)
  • 阿里云视频播放器

    阿里云的视频播放器类比 HTML5视频播放标签video和音频播放标签audio标签 只是阿里云视频播放器是针对阿里云上传的视频进行多功能配置和操作。 最终:阿里云视频播放器就是基于阿里云视频的前端播放标签 阿里云播放器 SDK ( ApsaraVideo Player SDK)是阿里视频服务的重要一环

    2023年04月09日
    浏览(62)
  • 学习笔记(1)——粤嵌gec6818实现电子相册,音乐播放器,视频播放器。

    (1)设计一个初始界面,并且设置电子相册,音乐播放器,视频播放器三个触摸按键。 (2)电子相册——能够实现相册的幻灯片功能,实现相册左右滑动切换相片。 (3)音乐播放器实现——切歌,播放和暂停功能。 (4)视频播放器实现——播放、暂停、音量大小、快进倒

    2024年02月11日
    浏览(61)
  • Android 13.0 系统多个播放器app时,设置默认播放器

     在13.0的系统产品开发中,对于在系统中有多个播放器的时候,这时候如果调用代码打开播放器,会出现多个播放器列表让用户 选择启动哪个播放器,所以产品开发需求需要设置默认播放器,当打开播放器的时候,就直接打开播放器就可以了,所以就需要 了解查询播放器列

    2024年02月08日
    浏览(73)
  • Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器

    Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器实例的示例: 上述代码中,使用 getInstance() 方法获取 AudioPlayer 的单例对象,参数传入 Context 对象。 在 getInstance() 方法中判断单例对象是否为空,如果为空则创建新的 AudioPlayer 对象,否则返回已有的单例对象。 这样

    2024年02月12日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包