音视频 二 看书的笔记 MediaPlayer

此类是用于播放声音和视频的主要 API

对方不想多说向你丢了一个链接 MediaPlayer


  • Idle 空闲状态
  • Initialized 初始化状态 调用 setDataSource() 时会进入此状态 setDataSource必须在Idle 状态下调用,否则就抛出异常了了了了了。
  • Prepared 准备状态 回调监听setOnPreparedListener 进入此状态后 可以设置一些属性 例如音量/循环播放等
  • Started
  • Paused
  • PlaybackCompleted 播放完了状态
  • Stopped
  • End 调用release() 就结束
  • Error 错误状态 播放过程中错误 会 回调到OnErrorListener.onError 此时应嗲用reset方法使MediaPlayer 恢复到Idle状态。

创建 过程

Android MediaPlayer.create(Context context, Uri uri) 的创建过程:

```

public static MediaPlayer create(Context context, Uri uri, SurfaceHolder holder,

AudioAttributes audioAttributes, int audioSessionId) {

复制代码
    try {
        MediaPlayer mp = new MediaPlayer(audioSessionId);
        final AudioAttributes aa = audioAttributes != null ? audioAttributes :
            new AudioAttributes.Builder().build();       //音频属性
        mp.setAudioAttributes(aa);                       //设置音频属性
        mp.native_setAudioSessionId(audioSessionId);     //音频会话ID  
        mp.setDataSource(context, uri);                  //设置资源
        if (holder != null) {                            //控制器 操纵Surface
            mp.setDisplay(holder);
        }
        mp.prepare();                                    //准备
        return mp;
    } catch (IOException ex) {
        Log.d(TAG, "create failed:", ex);
        // fall through
    } catch (IllegalArgumentException ex) {
        Log.d(TAG, "create failed:", ex);
        // fall through
    } catch (SecurityException ex) {
        Log.d(TAG, "create failed:", ex);
        // fall through
    }

    return null;
}


简化过程
val   mediaPlayer = MediaPlayer()
mediaPlayer .setDataSource(file.path)
mediaPlayer .prepare()

说明创建 就需要 new MediaPlayer()

接下来我们看看 MediaPlayer的构造方法?

复制代码
我替大家看了!

定义了个Looper   myLooper不为空赋值    MainLooper不为空赋值
创建EventHandler对象
创建了个TimeProvider  
创建了个Vector<InputStream>
然后native_setup()    

naive方法 都是先加载 native文件

复制代码
static {
        System.loadLibrary("media_jni");
        native_init();
    }

s0 我们先看 native_init()

复制代码
env -> FindClass("android/media/MediaPlayer")  //调用java层,搞到MediaPlayer
env -> GetFieldID(clazz,"mNativeContext","J") 搞到mNativeContext
env -> GetStaticMethodId(clazz,"postEventFromNative","参数类型省略")

就是下边的

复制代码
public class MediaPlayer extends PlayerBase
                         implements SubtitleController.Listener
                                  , VolumeAutomation
                                  , AudioRouting
{

//省略一堆
 private long mNativeContext; // accessed by native methods

/*
     * Called from native code when an interesting event happens.  This method
     * just uses the EventHandler system to post the event back to the main app thread.
     * We use a weak reference to the original MediaPlayer object so that the native
     * code is safe from the object disappearing from underneath it.  (This is
     * the cookie passed to native_setup().)
     */
    private static void postEventFromNative(Object mediaplayer_ref,
                                            int what, int arg1, int arg2, Object obj)
    {
  //省略一堆
  if (mp.mEventHandler != null) {
            Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
            mp.mEventHandler.sendMessage(m);
        }
}
//省略一堆

}

postEventFromNative 把Natvie事件回调到Java层,使用EventHandler post事件到主线程中,软引用指向原生MediaPlayer,保证Native代码的安全。

接下来native_setup 干了啥

复制代码
sp<MediaPlayer>  mp = new MediaPlayer();
sp listener = new  JNIMediaPlayerListener(env,this,weak_this)
mp->setListener(listener)
setMediaPlayer(env,thiz,mp);

就是创建native MediaPlayer 创建回调

setDataSource 过程

文件非 文件 分开判断处理

文件资源 最终调用 _setDataSource 的映射 setDataSoureceFD

复制代码
1 获取MediaPlayer对象
2 获取java.io.FileDescriptor 
3 检测异常及抛出

非文件资源 nativeSetDataSource 映射 setDataSoureceAndHeaders

复制代码
1 获取MediaPlayer对象
2 通过Binder机制   最后强制转换获取IMediaHTTPService
3 检测异常及抛出

setDisplay 设置控制器

prepare后的流程

运行时 MediaPlayer 大致可分为 C S 两个部分,在两个进程中运行,通过Binder机制视频IPC通信。

给播放器设置数据源之后。调用prepare 或 prepareAsync。

文件类型,调用prepare 将暂时阻塞,直到回调onPrepared进入Prepared状态。

复制代码
  public void prepare() throws IOException, IllegalStateException {
        _prepare();
        scanInternalSubtitleTracks();

        // DrmInfo, if any, has been resolved by now.
        synchronized (mDrmLock) {
            mDrmInfoResolved = true;
        }
    }

调用natvie方法prepare()

简单描述(其实也云里雾里),其他自行脑补领悟百度deep,

复制代码
获取mediaplayer
getVideoSurfaceTexture
setVideoSurfaceTexture(上边get到的)
检测异常

prepareAsync()

public native void prepareAsync() throws IllegalStateException;

多了点 锁 判断状态 等待之类的

Start()

stayAwake(true); 屏幕操作

复制代码
    /**
   * Set the low-level power management behavior for this MediaPlayer.  This
   * can be used when the MediaPlayer is not playing through a SurfaceHolder
   * set with {@link #setDisplay(SurfaceHolder)} and thus can use the
   * high-level {@link #setScreenOnWhilePlaying(boolean)} feature.
   *
   * <p>This function has the MediaPlayer access the low-level power manager
   * service to control the device's power usage while playing is occurring.
   * The parameter is a combination of {@link android.os.PowerManager} wake flags.
   * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK}
   * permission.
   * By default, no attempt is made to keep the device awake during playback.
   *
   * @param context the Context to use
   * @param mode    the power/wake mode to set
   * @see android.os.PowerManager
   */
  public void setWakeMode(Context context, int mode) {
      boolean washeld = false;

      /* Disable persistant wakelocks in media player based on property */
      if (SystemProperties.getBoolean("audio.offload.ignore_setawake", false) == true) {
          Log.w(TAG, "IGNORING setWakeMode " + mode);
          return;
      }

      if (mWakeLock != null) {
          if (mWakeLock.isHeld()) {
              washeld = true;
              mWakeLock.release();
          }
          mWakeLock = null;
      }

      PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
      mWakeLock = pm.newWakeLock(mode|PowerManager.ON_AFTER_RELEASE, MediaPlayer.class.getName());
      mWakeLock.setReferenceCounted(false);
      if (washeld) {
          mWakeLock.acquire();
      }
  }

以下是几种模式 对CPS 屏幕 键盘的影响自行搜索

最终调用

private native void _start() throws IllegalStateException;

额 就这吧 瘫了!

相关推荐
_一条咸鱼_38 分钟前
Android Compose 框架的列表与集合模块之列表项动画深入剖析(四十七)
android
行墨42 分钟前
Kotlin语言的run内置函数
android
顾林海44 分钟前
Jetpack Room 使用与原理解析
android·android jetpack
MuYe1 小时前
Android Hook - 动态链接器命名空间机制
android·操作系统
冰糖葫芦三剑客1 小时前
Android 常用工具类记录
android
智联视频超融合平台1 小时前
智能巡检机器人:2025年企业安全运维的“数字哨兵“
运维·安全·机器人·音视频·实时音视频·视频编解码
mex_wayne1 小时前
强化学习课程:stanford_cs234 学习笔记(2)introduction to RL
笔记·学习
许野平1 小时前
Manim 输出视频尺寸设置
音视频·动画·视频·manim
取个名字真难呐1 小时前
GAN随手笔记
人工智能·笔记·生成对抗网络
hanpfei1 小时前
PipeWire 音频设计与实现分析二——SPA 插件
算法·音视频