IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【Android】记录一次调用IjkPlayer -> 正文阅读

[移动开发]【Android】记录一次调用IjkPlayer

IjkPlayer是B站开源的项目,很多年了。这次记录一下我再4.4上使用的用的坑。

显示引入支持

    // required, enough for most devices.
    implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'

    // required, enough for most devices.
    implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'

    // Other ABIs: optional
    implementation 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'
    //implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
    implementation 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'
    //implementation 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'

    // ExoPlayer as IMediaPlayer: optional, experimental
    implementation 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'

上面会有两个地方

  1. 有两个64的扩展被我注释掉了,因为我的4.4好像不支持64位CPU?不注释掉,Build的时候会爆红,过不去。
  2. 要在库配置里增加jcenter()。就是google()mavenCentral()的那个配置文件。settings.gradle

在layout文件中先写入一个SurfaceView控件

 <SurfaceView
     android:id="@+id/sv_camera"
     android:layout_width="match_parent"
     android:layout_height="520dp"/>

就当个普通的View控件来设置就好了,没有什么特别的。 这个控件将会被当做视频播放的容器来使用(也可以理解成视口,搞过Canvas的会很容易理解)。

为SurfaceView设置生命周期方法

        svCamera = findViewById(R.id.sv_camera);
        svCamera.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
            	// 播放器容器初始化完毕后创建播放器实例
                ijkMediaPlayer = new IjkMediaPlayer();
                IjkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {
                //ijkMediaPlayer.setSurface(svCamera.getHolder().getSurface());
            }

            @Override
            public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
            	// 播放器容器销毁时 释放播放器容器
                ijkMediaPlayer.release();
            }
        });

在要放播放器的Activity的onCreate方法中初始化播放器

// 对于这个播放器实例到底是放到哪里实例化,有什么差别,这个我没去检查有什么区别,都能用。
// 实例化Ijkplayer
IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();

// 配置实例 日志输出
IjkMediaPlayer .native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);

在播放按钮事件中配置并播放流

// 先重置一下播放器(每次点击播放按钮都要重置一下播放器,然后重新配置参数,不容易出一些奇奇怪怪的问题)
ijkMediaPlayer.reset();
// 启用硬件解码(看别人都是这么写的)
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
// 设置视频源地址(这里有个坑,不要传URI对象,就直接写进去字符串地址就行,起码对于SRS生成的flv是如此。)
try {
	ijkMediaPlayer.setDataSource("http://xxx/xxx.flv");
} catch (IOException e) {
    e.printStackTrace();
}
// 设置异步播放模式(这个一定要在设置完视频源之后才行,我的这个SRS源,不调用这个方法,不能正常播放)
ijkMediaPlayer.prepareAsync();

/**
用了preparAsync之后就不需要再调用start()方法了,这个方法会自动播放视频。
**/

在停止播放按钮上增加STOP方法的调用即可

// 播放停止(网上很对资料说是停止之后 再调用start()就可以恢复播放,尝试并不能。不如直接reset播放器,之后重新配置数据源)
ijkMediaPlayer.stop();

这个释放播放器资源 前边已经调用了

// 释放播放器资源
ijkMediaPlayer.release();

上面的代码,是经过十几次试错之后,才成功的。都是弯路。虽然是很老的播放器,但是仍然很好用。从网上搜到的资料,大部分播放器都是几年前的代码,近两年都没有什么新鲜的东西出来。

下面贴一下最终实现的代码

import tv.danmaku.ijk.media.player.IjkMediaPlayer;

public class WashesShoesActivity extends MainActivity {
    private static final String TAG = "WashesShoesActivity";

    LinearLayout llHeadBox,llMsgBox, llOrderBox;
    FrameLayout flLiveBox;
    TextView  tvLiveState;

    SurfaceView svCamera;
    Button btnLiveFull, btnLiveStart;

    IjkMediaPlayer ijkMediaPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;

        // 设置主界面
        setContentView(R.layout.activity_washes_shoes);

        // 获得头部容器
        llHeadBox = findViewById(R.id.ll_head_box);
        llMsgBox = findViewById(R.id.ll_msg_box);
        llOrderBox = findViewById(R.id.ll_order_box);

        // 获得播放窗口容器
        flLiveBox = findViewById(R.id.fl_live_box);

        // 播放窗口大小控制按钮
        btnLiveFull = findViewById(R.id.btn_live_full);
        btnLiveFull.setOnClickListener(view-> changeLiveFull());

        // 直播状态 显示与修改
        tvLiveState = findViewById(R.id.tv_live_state);
        tvLiveState.setTextColor(getResources().getColor(R.color.white));
        tvLiveState.setText(R.string.is_not_live);

        // 直播按钮事件绑定
        btnLiveStart = findViewById(R.id.btn_live_start);
        btnLiveStart.setOnClickListener(view-> changeLiveStatus());

        // 获得用来显示视频的控件 作为视频容器
        svCamera = findViewById(R.id.sv_camera);
        svCamera.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
            	// 容器初始化完毕 就 初始化播放器
                ijkMediaPlayer = new IjkMediaPlayer();
                IjkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {
            	// 容器发生改变 就重新初始化播放器(其实没必要,也许播放本地视频时可以这么做)
                //ijkMediaPlayer.setSurface(svCamera.getHolder().getSurface());
            }

            @Override
            public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
            	// 容器销毁时 释放播放器资源
                ijkMediaPlayer.release();
            }
        });
    }

    // 全屏播放切换
    private void changeLiveFull(){
        ViewGroup.LayoutParams layoutParams = flLiveBox.getLayoutParams();
        if (layoutParams.width == 640){
            // 从小到大
            llHeadBox.setVisibility(ViewGroup.GONE);
            llMsgBox.setVisibility(ViewGroup.GONE);
            llOrderBox.setVisibility(ViewGroup.GONE);

			// 根据实际机器来设置的 如果是未知的机器 需要计算取得
            layoutParams.width = 1024;
            layoutParams.height = 768;

            btnLiveFull.setText(R.string.btn_live_ori);
        }else{
            // 从大到小
            llHeadBox.setVisibility(View.VISIBLE);
            llMsgBox.setVisibility(View.VISIBLE);
            llOrderBox.setVisibility(View.VISIBLE);

            layoutParams.width = 640;
            layoutParams.height = 360;

            btnLiveFull.setText(R.string.btn_live_full);
        }
        flLiveBox.setLayoutParams(layoutParams);
    }

    // 直播状态切换
    private void changeLiveStatus(){
        if (!ijkMediaPlayer.isPlaying()) {
            mLiveStatus = true;

            // 停止中 到 直播
            ijkMediaPlayer.reset();
            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
            ijkMediaPlayer.setVolume(0.0F, 0.0F);
            ijkMediaPlayer.setDisplay(svCamera.getHolder());

            try {
                ijkMediaPlayer.setDataSource("http://114.117.1.115:8080/live/livestream/office.flv");
                ijkMediaPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
            }

            // 修改文字显示
            tvLiveState.setTextColor(getResources().getColor(R.color.yellow));
            tvLiveState.setText(R.string.is_live);

            // 停止直播按钮显示
            btnLiveStart.setText(R.string.btn_live_stop);

        }else{
            mLiveStatus = false;
            // 直播中 到 停止
            ijkMediaPlayer.stop();

            // 修改文字显示
            tvLiveState.setTextColor(getResources().getColor(R.color.white));
            tvLiveState.setText(R.string.is_not_live);

            // 修改按钮显示 开始直播按钮显示
            btnLiveStart.setText(R.string.btn_live_start);

            // 将播放窗口清空
            // TODO:播放停止后怎么让窗口变黑? 2022-9-4 15:01:54
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        KeyInput.press(keyCode, event, KeyInput.Type.ALL);
        return true;
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        KeyInput.press(keyCode, event, KeyInput.Type.ALL);
        return true;
    }
}

上述代码仅供参考,最终还是封装成一个工具类或者是一个自定义控件,应该用起来会更舒服一些。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 11:27:25  更:2022-09-13 11:29:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 4:34:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码