Android音视频开发之VideoView使用指南

作者:JulyYu 时间:2022-11-20 11:14:52 

VideoView介绍

之前介绍过使用MediaPlayer+SurfaceView实现播放视频功能。无意间发现官方封装了VideoView组件来实现简单视频播放功能,内部同样是使用MediaPlayer+SurfaceView的形式控制MediaPlayer对视频文件进行播放。使用场景比较简单,适用于只是播放视频的场景,其提供能力有限不太适合使用在调节视频亮度等其他功能。

MediaController

除了播放组件VideoView外还有MediaController组件为视频播放提供播放操作栏功能,可支持视频播放、暂停、快进、快退等功能。另外还提供进度条功能可以拖拽到指定位置进行播放视频。

使用

VideoView封装了MediaPlayer同样也提供了类似于MediaPlayer的api。例如start方法同样是播放视频功能,但调用该方法前最好也是通过设置setOnpreparedListener回调结果来执行,当调用setVideoPath后会主动执行prepareAsync方法。在VideoView内部帮助开发者封装实现了很多功能,其实也能借鉴其内部源码来实现功能更全面功能更完备的自制播放器。

常用Api说明
setVideoPath设置视频资源
start播放
pause暂停
resume重播
seekTo指定位置播放
isPlaying视频是否播放
getCurrentPosition获取当前播放位置
setMediaController设置MediaController
setOnpreparedListener监听视频装载完成事件
// 实例化videoView    
videoView = new VideoView(this);
Uri uri = Uri.fromFile(new File("sdcard/DCIM","新世纪福音战士24.mp4"));
//加载视频资源
videoView.setVideoURI(uri);
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.addView(videoView);
setContentView(linearLayout);
//设置监听
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
   @Override
   public void onPrepared(MediaPlayer mp) {
       //回调成功并播放视频
       videoView.start();
   }
});
//创建操作栏
MediaController mediaController = new MediaController(this);
videoView.setMediaController(mediaController);
mediaController.setMediaPlayer(videoView);

Android音视频开发之VideoView使用指南

源码分析

既然封装了VideoViewMediaController两者组件,在使用过程中也发现了许多之前尝试实现的一些功能看看他们又是如何实现的。

进度显示

MediaController显示时调用show方法内部可以看到一个post(mShowProgress);方法

public void show(int timeout) {
   if (!mShowing && mAnchor != null) {
       setProgress();
       if (mPauseButton != null) {
           mPauseButton.requestFocus();
       }
       disableUnsupportedButtons();
       updateFloatingWindowLayout();
       mWindowManager.addView(mDecor, mDecorLayoutParams);
       mShowing = true;
   }
   updatePausePlay();

// cause the progress bar to be updated even if mShowing
   // was already true.  This happens, for example, if we're
   // paused with the progress bar showing the user hits play.
   post(mShowProgress);

if (timeout != 0 && !mAccessibilityManager.isTouchExplorationEnabled()) {
       removeCallbacks(mFadeOut);
       postDelayed(mFadeOut, timeout);
   }
}

可以看到mShowProgress是一个Runnable,内部会延迟不停调用自己来更新setProgress()setProgress()方法就是读取MediaPlayer播放进度从而更新播放信息。

private final Runnable mShowProgress = new Runnable() {
   @Override
   public void run() {
       int pos = setProgress();
       if (!mDragging && mShowing && mPlayer.isPlaying()) {
           postDelayed(mShowProgress, 1000 - (pos % 1000));
       }
   }
};

播放尺寸适配

之前自定义实现播放尺寸适配,在VideoView内部直接帮助开发者实现视频播放适配,详细代码可以直接看onMeasure重写。代码大致算法就是通过比较VideoView布局宽高和视频的宽高进行比例比较来重写计算VideoView的宽高。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
   //        + MeasureSpec.toString(heightMeasureSpec) + ")");

int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
   int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
   if (mVideoWidth > 0 && mVideoHeight > 0) {

int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
       int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
       int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
       int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
           // the size is fixed
           width = widthSpecSize;
           height = heightSpecSize;

// for compatibility, we adjust size based on aspect ratio
           if ( mVideoWidth * height  < width * mVideoHeight ) {
               //Log.i("@@@", "image too wide, correcting");
               width = height * mVideoWidth / mVideoHeight;
           } else if ( mVideoWidth * height  > width * mVideoHeight ) {
               //Log.i("@@@", "image too tall, correcting");
               height = width * mVideoHeight / mVideoWidth;
           }
       } else if (widthSpecMode == MeasureSpec.EXACTLY) {
           // only the width is fixed, adjust the height to match aspect ratio if possible
           width = widthSpecSize;
           height = width * mVideoHeight / mVideoWidth;
           if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
               // couldn't match aspect ratio within the constraints
               height = heightSpecSize;
           }
       } else if (heightSpecMode == MeasureSpec.EXACTLY) {
           // only the height is fixed, adjust the width to match aspect ratio if possible
           height = heightSpecSize;
           width = height * mVideoWidth / mVideoHeight;
           if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
               // couldn't match aspect ratio within the constraints
               width = widthSpecSize;
           }
       } else {
           // neither the width nor the height are fixed, try to use actual video size
           width = mVideoWidth;
           height = mVideoHeight;
           if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
               // too tall, decrease both width and height
               height = heightSpecSize;
               width = height * mVideoWidth / mVideoHeight;
           }
           if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
               // too wide, decrease both width and height
               width = widthSpecSize;
               height = width * mVideoHeight / mVideoWidth;
           }
       }
   } else {
       // no size yet, just adopt the given spec sizes
   }
   setMeasuredDimension(width, height);
}

来源:https://juejin.cn/post/7085243234523283464

标签:Android,VideoView
0
投稿

猜你喜欢

  • Android倒计时的开始与停止 剩余时分秒的展示

    2023-07-20 03:11:31
  • AQS加锁机制Synchronized相似点详解

    2023-08-04 22:36:55
  • Java ConcurrentHashMap的使用示例

    2023-02-04 09:04:29
  • Android 手写热修复dex实例详解

    2022-11-06 08:01:40
  • 模拟打印机排队打印效果

    2023-12-13 13:26:22
  • Android延迟实现的几种解决方法及原理分析

    2023-10-24 18:07:15
  • Android自定view画圆效果

    2021-06-05 21:45:52
  • C#生成随机数功能示例

    2022-03-25 04:52:40
  • java向文件中追加内容与读写文件内容源码实例代码

    2021-11-15 11:45:13
  • Android ListView 条目多样式展示实例详解

    2022-10-22 06:18:41
  • C# 静态变量与静态方法实例研究

    2023-04-23 04:26:00
  • Android Support Annotations资料整理

    2021-09-21 13:39:33
  • Idea springboot springCloud热加载热调试两种常用方式

    2021-06-11 22:20:06
  • 关于activemq安装配置以及启动错误的解决

    2023-11-13 05:18:02
  • Java TreeSet实现学生按年龄大小和姓名排序的方法示例

    2023-01-09 15:25:18
  • 浅谈Java三大框架与应用

    2023-04-16 18:25:01
  • C#使用SQL Dataset数据集代码实例

    2023-02-24 08:23:07
  • 基于Beanutils.copyProperties()的用法及重写提高效率

    2023-04-20 12:10:25
  • MyBatis动态sql查询及多参数查询方式

    2023-05-30 12:20:12
  • 游戏开发之随机概率的选择算法

    2022-08-26 13:21:09
  • asp之家 软件编程 m.aspxhome.com