ExoPlayer播放视频的简单使用及播放视频宽高设置的源码分析

前言

本篇博文主要是对播放视频宽高设置的源码进行分析,为了方便讲解,提前也会对EXOPlayer的使用做简单概述。

使用ExoPlayer播放视频

1.首先我们需要在布局管理器中添加如下xml代码:

<com.google.android.exoplayer2.ui.SimpleExoPlayerView
        android:id="@+id/play_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
    </com.google.android.exoplayer2.ui.SimpleExoPlayerView>

这是exoPlayer的播放控件。
2.创建一个SimpleExoPlayer对象。并把SimpleExoPlayer与SimpleExoPlayerView关联起来。代码如下:

BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        TrackSelection.Factory trackFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
        TrackSelector trackSelector = new DefaultTrackSelector(trackFactory);
        player = ExoPlayerFactory.newSimpleInstance(this, trackSelector);
        simpleExoPlayerView.setPlayer(player);

3.最后来创建MediaSource对象,准备播放。

private void preparePlay() {
        DefaultBandwidthMeter defaultBandwidthMeter = new DefaultBandwidthMeter();
        DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(MainActivity.this
                , Util.getUserAgent(MainActivity.this, "exoplayer_sample")
                , defaultBandwidthMeter);
        ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
        Uri uri = Uri.parse("http://mvvideo11.meitudata.com/59fd64eac92fb5968_H264_3.mp4?k=b953933ba73a3271c9c7d926a0c54fb4&t=5a0a97c9");
        MediaSource mediaSource = new ExtractorMediaSource(uri
                , dataSourceFactory, extractorsFactory, null, null);
        //player.addListener(this);
        player.prepare(mediaSource);
    }

这里的视频Uri是我从网上找的一个mp4格式的视频,通过EXOplayer的开发者文档我们知道,多媒体的格式和MediaSource实现类的对应关系是:
DASH (DashMediaSource),
SmoothStreaming (SsMediaSource),
HLS (HlsMediaSource),
除此之外其他的格式使用 (ExtractorMediaSource).
通过EXOPLAYER Support Formats 一文我们知道MP4格式应该使用ExtractorMediaSource。
现在我们可以运行程序了(别忘了添加网络权限)。运行效果如下:
这里写图片描述

控制器是SimpleExoPlayerView自带的一个默认控制器。看到这我们发现一个问题,就是明明我们在布局管理器添加SimpleExoPlayerView控件的时候,设置它的宽高都是match_parent啊,怎么它的宽度并没有填充父布局?
让它充满屏幕的代码很简单,有两种方式。可以用代码实现如下:

        simpleExoPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL);

或者通过xml文件的属性设置:

app:resize_mode="fill"

设置之后,我们再看一下效果:
这里写图片描述

通过gif图我们看到,确实,变成了全屏。那我们现在就来分析一下为什么会这样。

源码分析

我们看关键语句:

simpleExoPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL);

看看setResizeMode的内部实现:

public void setResizeMode(@ResizeMode int resizeMode) {
    Assertions.checkState(contentFrame != null);
    contentFrame.setResizeMode(resizeMode);
  }

这里调用了contentFrame的setResizeMode方法,contentFrame是AspectRatioFrameLayout对象。我们来看看AspectRatioFrameLayout里面的setResizeMode方法。

public void setResizeMode(@ResizeMode int resizeMode) {
    if (this.resizeMode != resizeMode) {
      this.resizeMode = resizeMode;
      requestLayout();
    }
  }

这里是把resizeMode的值传了进来,我们看一下resizeMode值在AspectRatioFrameLayout类中到底起着什么作用吧。

public AspectRatioFrameLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    resizeMode = RESIZE_MODE_FIT;
    if (attrs != null) {
      TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
          R.styleable.AspectRatioFrameLayout, 0, 0);
      try {
        resizeMode = a.getInt(R.styleable.AspectRatioFrameLayout_resize_mode, RESIZE_MODE_FIT);
      } finally {
        a.recycle();
      }
    }
  }

在AspectRatioFrameLayou的构造方法中,我们看到,resizeMode的默认值是RESIZE_MODE_FIT。这里提到了RESIZE_MODE_FIT,我们就谈谈AspectRatioFrameLayou类中的几种计算视频宽高的模式。

  • RESIZE_MODE_FIT 表示通过减少视频的宽度或者高度,来达到想要的视频宽高比。
  • RESIZE_MODE_FIXED_WIDTH 表示宽度是固定的,通过减少或者增加高度的值来实现想要的宽高比。
  • RESIZE_MODE_FIXED_HEIGHT 表示高度是固定的,通过减少或者增加宽度的值来实现想要的宽高比。
  • RESIZE_MODE_FILL 表示不考虑指定的宽高比。
  • RESIZE_MODE_ZOOM 表示通过增加宽度或者高度,来达到想要的视频宽高比。

上面呢我演示了设置模式为setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL);
的效果,其余的四种效果大家可以自己设置演示,会存在变形的情况哦,所以这玩意还得合理运用。

接下来我们看看resizeMode在哪里使用的,我们看如下代码:

@Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    if (resizeMode == RESIZE_MODE_FILL || videoAspectRatio <= 0) {
      // Aspect ratio not set.
      return;
    }

    int width = getMeasuredWidth();
    int height = getMeasuredHeight();
    float viewAspectRatio = (float) width / height;
    float aspectDeformation = videoAspectRatio / viewAspectRatio - 1;
    if (Math.abs(aspectDeformation) <= MAX_ASPECT_RATIO_DEFORMATION_FRACTION) {
      // We're within the allowed tolerance.
      return;
    }

    switch (resizeMode) {
      case RESIZE_MODE_FIXED_WIDTH:
        height = (int) (width / videoAspectRatio);
        break;
      case RESIZE_MODE_FIXED_HEIGHT:
        width = (int) (height * videoAspectRatio);
        break;
      case RESIZE_MODE_ZOOM:
        if (aspectDeformation > 0) {
          width = (int) (height * videoAspectRatio);
        } else {
          height = (int) (width / videoAspectRatio);
        }
        break;
      default:
        if (aspectDeformation > 0) {
          height = (int) (width / videoAspectRatio);
        } else {
          width = (int) (height * videoAspectRatio);
        }
        break;
    }
    super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
  }

这是AspectRatioFrameLayout的onMeasure方法,我们来分析下。
通过代码,我们看到当resizeMode的值为RESIZE_MODE_FILL或者videoAspectRatio<=0时,就return,也就表示它会执行,外面所设置宽高。videoAspectRatio表示想要的视频宽高比。我们接着看,注意到一个if的判断语句。这里的意思是如果想要的宽高比和视频的宽高比的差值如果小于这个临界值MAX_ASPECT_RATIO_DEFORMATION_FRACTION的话,那AspectRatioFrameLayout不需要从新计算他的宽高。这里MAX_ASPECT_RATIO_DEFORMATION_FRACTION=0.01f。
接着我们看switch语句中,对于不同的resizeMode,宽高做了对应的计算。最后把计算的值通过:

super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));

设置进去。
那最后我们再看下videoAspectRatio这个想要的宽高比是在哪里设置的呢,我们发现在SimpleExoPlayerView中有设置:

@Override
    public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
        float pixelWidthHeightRatio) {
      if (contentFrame != null) {
        float aspectRatio = height == 0 ? 1 : (width * pixelWidthHeightRatio) / height;
        contentFrame.setAspectRatio(aspectRatio);
      }
    }

onVideoSizeChanged方法是在视频渲染期间视频的size值变化的时候会回调,pixelWidthHeightRatio这个参数表示每一个像素的宽高比。

总结

这里对播放视频的宽高设置源码分析到此结束了,后需还有对EXOPlayer的其他分析。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ExoPlayer是一个基于Android平台的开源媒体播放器,它使用Android本身的MediaCodec来解码视频和音频,并且提供了一些方便的API接口以及默认实现的播放器控件,可以帮助开发者快速地集成视频播放功能。 以下是使用ExoPlayer2播放视频的基本步骤: 1. 添加依赖库:在项目的build.gradle文件中添加以下依赖库: ``` implementation 'com.google.android.exoplayer:exoplayer-core:2.X.X' implementation 'com.google.android.exoplayer:exoplayer-ui:2.X.X' ``` 其中,2.X.X是ExoPlayer的版本号。 2. 实例化ExoPlayer:在代码中创建ExoPlayer实例,并设置需要播放的媒体源,如下所示: ``` SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build(); MediaItem mediaItem = MediaItem.fromUri(uri); player.setMediaItem(mediaItem); player.prepare(); player.play(); ``` 其中,context是上下文对象,uri是需要播放的媒体文件的URI。 3. 显示播放器控件:如果需要显示播放器控件,可以使用ExoPlayer提供的默认实现,如下所示: ``` PlayerView playerView = findViewById(R.id.player_view); playerView.setPlayer(player); ``` 其中,player_view是在布局文件中定义的ExoPlayer控件的ID。 4. 控制播放器:ExoPlayer提供了一些API接口以控制播放器的播放、暂停、停止、快进、快退等操作,如下所示: ``` player.play(); player.pause(); player.stop(); player.seekTo(positionMs); ``` 其中,positionMs是需要跳转到的播放位置的毫秒数。 以上是使用ExoPlayer2播放视频的基本步骤,你可以根据自己的需求进行适当的调整和修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值