当前位置: 首页 > article >正文

音视频 二 看书的笔记 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;

额 就这吧 瘫了!


http://www.kler.cn/a/612261.html

相关文章:

  • 阿里Qwen2.5-Omni:全能型多模态模型登场,视频实时互动碾压Gemini
  • Rust从入门到精通之精通篇:23.高级并发模式
  • FPGA中串行执行方式之使用时钟分频或延迟的方式
  • 光流 | 基于KLT算法的人脸检测与跟踪原理及公式,算法改进,matlab代码
  • Git入门——常用指令汇总
  • STM32 ADC 温度采集 可穿戴体温测量仪LMT70
  • Qt弹出新窗口并关闭(两个按钮)
  • 资本运营:基于Python实现的资本运作模拟
  • Java中用Stream流取出分组后每组最大值对象的ID
  • AI编辑器-Trae 玩转AI 编程
  • 在rockylinux9.4安装mongodb报错:缺少:libcrypto.so.10文件库
  • 【docker】Dockerfile中ENTRYPOINT和CMD区别理解
  • 如何使用DeepSeek编写测试用例?
  • 2025年前端八股文整理持续更新中(css+js+vue)
  • 23种设计模式-创建型模式-建造者
  • Linux 指令篇:tar 命令详解与实战
  • ADB->查看具体应用包名、安装路径、所有应用包名输出到文件
  • 蓝桥杯--bfs专题第二个题目(leetcode103二叉树)
  • [操作系统] 进程间通信:命名管道原理与操作
  • 使用ProcessBuilder执行FFmpeg命令,进程一直处于阻塞状态,一直没有返回执行结果