本文介绍: 尝试用MediaPlayer写了一个播放demo实现网络流和本地流的播放。由于本人对app开发一窍不通,所以demo中很多内容是边查资料边写的,写的也比较杂乱,能够帮助理解api就行。这一节主要会记录demo开发中学到的内容,以及了解MediaPlayer Api

尝试用MediaPlayer写了一个播放demo实现网络流和本地流的播放。由于本人对app开发一窍不通,所以demo中很多内容是边查资料边写的,写的也比较杂乱,能够帮助理解api就行。这一节主要会记录demo开发中学到的内容,以及了解MediaPlayer Api

1、demo效果

由于Android Studio虚拟设备支持API 30,所以demo的编写基于Android R的,但是后续看的代码还是会基于Android T,这部分应该差的不是很多。

demo代码没有完善(已发现问题还没处理),目前实现效果如下包含有以下几个内容:

代码可在github下载MediaPlayerDemo-github
积分小伙伴也可在CSDN下载MediaPlayerDemo-CSDN


2、demo实现过程中学到的相关内容

2.1、layout

    public static int dp2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

2.2、Manifest

如果需要访问内部存储,需要添加以下权限

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />

同时application中还要添加

android:requestLegacyExternalStorage="true"

打开app后需要给app赋予权限,否则仍不能访问存储

访问Internet需要赋予如下权限

<uses-permission android:name="android.permission.INTERNET" />

有了如上设定播放网络流仍会失败,还需在application添加

android:usesCleartextTraffic="true"

播放页面横屏不能结束当前activity生命周期,需要在activity添加如下配置

android:configChanges="orientation|screenSize"

android app默认主题颜色是紫色,并且会有标题栏我们可以修改 application 中的 theme主题,主题设置themes.xml中。

2.3、Activity

这里要了解的是与Activity相关方法,例如 onCreate、onStart、onPause、onResume、onDestory等,这些方法可以在Activity的基类AppCompatActivity查找到,注意Override这些方法时需要调用它们的 super 方法。

启动MainActivity时,执行顺序如下

2023-08-12 22:52:20.240 1790-1790/com.example.mediademo D/Demo_MainActivity: onCreate
2023-08-12 22:52:20.323 1790-1790/com.example.mediademo D/Demo_MainActivity: onPause
2023-08-12 22:52:20.324 1790-1790/com.example.mediademo D/Demo_MainActivity: onResume

启动VideoActivity时,执行顺序如下

2023-08-12 22:59:32.992 1928-1928/com.example.mediademo D/Demo_MainActivity: onPause
2023-08-12 22:59:33.539 1928-1928/com.example.mediademo D/Demo_MainActivity: onStop

回到之前MainActivity时:

2023-08-12 22:59:41.757 1928-1928/com.example.mediademo D/Demo_MainActivity: onPause
2023-08-12 22:59:41.758 1928-1928/com.example.mediademo D/Demo_MainActivity: onResume

退出app时(按返回键或者退出后台),会多执行一个 onDestroy 销毁资源

2023-08-12 23:06:09.275 2334-2334/com.example.mediademo D/Demo_MainActivity: dispatchKeyEvent, keycode = 4
2023-08-12 23:06:09.275 2334-2334/com.example.mediademo D/Demo_MainActivity: keyCode = 4
2023-08-12 23:06:09.383 2334-2334/com.example.mediademo D/Demo_MainActivity: dispatchKeyEvent, keycode = 4
2023-08-12 23:06:09.394 2334-2334/com.example.mediademo D/Demo_MainActivity: onPause
2023-08-12 23:06:09.940 2334-2334/com.example.mediademo D/Demo_MainActivity: onStop
2023-08-12 23:06:09.941 2334-2334/com.example.mediademo D/Demo_MainActivity: onDestroy

2.4、Handler Looper and Thread

由于我不是很熟悉java,也不是专业的android app开发工程师,所以关于这一小节的理解可能会有错误,如有小伙伴看到欢迎指出。以下是我对Thread、Handler、Looper的理解

这里来看 MediaPlayer.java 中给我门提供的示例

这里创建了一个 HandlerThread,来执行 addTrack 任务任务执行完成后调用 Looper.quit退出线程。

        final HandlerThread thread = new HandlerThread("SubtitleReadThread",
              Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
        thread.start();
        Handler handler = new Handler(thread.getLooper());
        handler.post(new Runnable() {
        	...
     	    public void run() {
                int res = addTrack();
                if (mEventHandler != null) {
                    Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null);
                    mEventHandler.sendMessage(m);
                }
                thread.getLooper().quitSafely();
            }
        });

还有另外一个示例,MediaPlayer创建过程中会创建一个EventHandler,reset 时会调用 Handler.removeCallbacksAndMessages清除 MessageQueue 中由 EventHandler 发送的消息。如果 Handler 用的主线程 Looper,那么主线程可以安全退出;如果用的子线程 Looper,还需要调用该线程的 quit 方法打断 loop

	public MediaPlayer() {
		....
        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }
    }
    
    public void reset() {
    		...
            if (mEventHandler != null) {
            mEventHandler.removeCallbacksAndMessages(null);
        }
    }

如需更深入了解 Handler Looper and Thread 机制可以查看源码,也可以查看之前的 native AHandler ALooper 机制,原理大致是相同的 。


3、MediaPlayer Api分析

一节主要是了解 MediaPlayer有什么api,我这里将api进行了罗列分组,并且贴出了他们的功能,至于他们要怎么用,有什么注意点,与生命周期相关的内容会在下一篇内容中了解。

首先是播放控制api,这类api用于播放参数设定,以及Player生命周期管理

num methods Func
1 setDataSource 设置数据源
2 prepare 准备
3 prepareAsync 准备
4 start 开始播放
5 stop 停止播放
6 pause 暂停播放
7 release 释放当前播放器持有的资源
8 reset 重置播放器
9 finalize
10 setPlaybackParams 设置播放参数,例如倍速、Audio mode
11 setSyncParams 设置Avsync mode,有4种sync模式
12 seekTo 定位,有4种seek mode
13 setDisplay 设置 SurfaceHolder
14 setSurface 设置 Surface
15 setVideoScalingMode 设置缩放模式
16 setAudioStreamType 设置音频类型
17 invoke 调用指定函数,no public,不支持App使用
18 setParameter 设定参数no public,不支持App使用
19 setVolume 设置音量
20 setAudioSessionId 设置AudioSessionId
21 selectTrack 指定播放的track或者是切换当前播放的track

以下是参数获取api,用他们可以获取到播放状态、播放参数等信息

num methods Func
1 getVideoWidth 获取宽度
2 getVideoHeight 获取高度
3 isPlaying 是否正在播放
4 getPlaybackParams 获取播放参数
5 getSyncParams 获取Avsync参数,里面包含有帧率等信息
6 getTimestamp 获取当前播放时间
7 getCurrentPosition 获取当前播放时间单位是msec,getTimestamp是基于这个方法的
8 getDuration 获取视频时长
9 getMetadata 获取当前播放流的信息,no public,不支持app使用,包含 bitrate、mine、codectype等信息
10 notifyAt 设置pts更新频率
11 getAudioSessionId 获取AudioSessionId
12 getTrackInfo 获取当前Track的媒体格式
13 getSelectedTrack 获取当前选择的track

下面两个api用于循环播放或者是快速播放:

num methods Func
1 setNextMediaPlayer 设置下一个要播放的MediaPlayer,自动播放
2 setLooping 设置循环播放

以下类和方法用于回调事件的上抛与处理:

num class/function Func
1 EventHandler framework回调事件的处理
2 postEventFromNative native callback to framework

以方法用于将回调事件进一步上抛给app层,app做相应动作

num class Func
1 OnPreparedListener prepareAsync完成,搭配start使用
2 OnCompletionListener 当前码流播放完成
3 OnBufferingUpdateListener 缓冲进度更新
4 OnSeekCompleteListener seek完成
5 OnVideoSizeChangedListener 视频的宽高发生变化,搭配 getVideoWidth 和 getVideoHeight使用
6 OnErrorListener 错误事件回调
7 OnTimedTextListener
8 OnTimedMetaDataAvailableListener
9 OnInfoListener 播放器信息回调

原文地址:https://blog.csdn.net/qq_41828351/article/details/132013218

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_17349.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注