MediaPlayer+TextureView实现视频播放器

本文介绍了在Android中使用MediaPlayer结合SurfaceView/TextureView实现视频播放器的方法,重点讲解了TextureView的选择原因及其使用,以及MediaPlayer的生命周期和控制操作。详细阐述了从初始化到播放、暂停、停止等过程,并提供了项目结构和播放器功能实现的概述。
摘要由CSDN通过智能技术生成

Android中实现视频播放器的途径有两种:

  • 使用VideoView
  • 通过MediaPlayer + SurfaceView/ TextureView
1. VideoView

VideoView使用比较简单,配合MediaController可以达到控制播放、暂停、快进、快退、切换视频、进度条显示等,具体使用在这里不在赘述了。

2. MediaPlayer + SurfaceView / TextureView

实现一个相对完善的视频播放器,可以使用 MediaPlayer + SurfaceViewMediaPlayer + TextureView

SurfaceView:提供嵌入视图层次结构内部的专用绘图表面,您可以控制此表面的格式,也可以控制其大小,且提供一个辅助线程可以渲染到屏幕中。

TextureViewTextureView可用于显示内容流,这样的内容流可以例如是视频或OpenGL场景、可以来自应用程序的过程以及远程过程。TextureView只能在硬件加速窗口中使用,用软件渲染时,TextureView将不绘制任何内容。与SurfaceView不同,TextureView不会创建单独的窗口,而是充当常规View。此关键区别允许对TextureView进行移动,转换,设置动画等。

在这里选择了后者的原因是TextureView更适合视频流,以及具备普通View的特性,可以在项目中达到想要的变化效果。

TextureView如何使用
可以通过调用getSurfaceTexture()来获取TextureViewSurfaceTexture。重要的是要知道只有在将TextureView附加到窗口(并onAttachedToWindow()已被调用)后,SurfaceTexture才可用。因此,在SurfaceTexture可用时使用TextureView.SurfaceTextureListener来通知。重要的是要注意,只有一个生产者可以使用TextureView。例如,如果使用TextureView显示相机预览,则lockCanvas()无法同时在TextureView上绘制。

  • SurfaceTextureListener的回调。
    override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) {
   
        //SurfaceTexture缓冲区大小更改时调用(这里的width、height是改变后的画布大小)
    }

    override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {
   
       //SurfaceTexture通过更新指定的值 时调用
    }

    override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean {
   
       //当指定的SurfaceTexture对象即将被销毁时调用。返回true,则调用此方法后,
      //表面纹理内不应进行任何渲染。如果返回false,则客户端需要SurfaceTexture.release()。
        return false
    }

    override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
   
        //当TextureView准备使用SurfaceTexture时调用(这里的width、height是原始画布大小)
    }

MediaPlaye如何使用

MediaPlayer可用于控制音频/视频文件和流的播放。

在官网给出的下图显示了受支持的播放控制操作驱动的MediaPlayer对象的生命周期和状态。

  • 椭圆形表示MediaPlayer对象可能驻留的状态。
  • 弧形表示驱动对象状态转换的回放控制操作,有两种类型的弧,具有单箭头的弧表示同步方法调用,而具有双箭头的弧表示异步方法调用。
    MediaPlayer的生命周期和状态

MediaPlayer的生命周期:

  • 当新建对象或者在创建之后调用reset()时,MediaPlayer对象处于Idle状态。在调用 release()之后处于End状态。在这两种状态之间是MediaPlayer对象的生命周期。一旦不再使用MediaPlayer对象,立即调用release()释放资源。MediaPlayer对象处于End状态,就无法再使用它,也无法将其恢复为其他任何状态。

  • 某些回放控制操作可能由于各种原因而失败,例如,不支持的音频/视频格式,音频/视频的交错差,分辨率太高,流式传输超时等。在所有这些错误条件下,如果已经setOnErrorListener(),则内部播放器引擎将调用用户提供的OnErrorListener.onError()方法。

  • setDataSource()用于设置视频资源,只能在Idle状态下调用,其他状态下会抛出IllegalStateException,调用后处于Initialized状态。

  • MediaPlayer需要Initialized状态下才能进行准备工作,提供了两个方法prepare()(同步)、prepareAsync()(异步)使MediaPlayer进入Prepared状态,异步调用可以在OnPreparedListener接口的回调方法onPrepared()中进行Prepared之后的操作。

  • MediaPlayerPrepared状态之后可以调用start()使它进入Started状态,并开始播放视频,isPlaying()可以测试MediaPlayer对象是否处于Started状态。在Started状态时,通过setOnBufferingUpdateListener()可以在其OnBufferingUpdateListener.onBufferingUpdate()回调中获取流式传输 音频/视频 时跟踪缓冲状态。

  • 播放可以暂停和停止,并且可以调整当前播放位置。
    可以通过pause()暂停播放。当调用 pause()返回时,MediaPlayer对象将进入Pause状态。注意在播放器引擎中,从Strated 状态到Pause状态的转换是异步的,可能要花一些时间。调用start()会重新变为Started状态并开始播放。
    可以通过stop()停止播放,StartedPausedPreparedPlaybackCompleted状态的MediaPlayer进入Stopped状态。处于Stopped状态,就无法开始播放,直到调用prepare()prepareAsync()MediaPlayer对象重新设置为Prepared状态。

  • 调整播放位置可以通过seekTo()方法,由于seekTo()是异步的,实际上查找需要一定时间才能完成,实际的查找位置完成时会走setOnSeekCompleteListener()OnSeekComplete.onSeekComplete()回调。
    seekTo()PreparedPausedPlaybackCompleted 状态下执行仍然会保持当前的状态。
    实际的当前播放位置可以通过getCurrentPosition()获取。

  • 当视频播放完成之后默认会走setOnCompletionListener()中的OnCompletion.onCompletion()回调,在回调后处于PlaybackCompleted状态。
    如果设置setLooping()true时,会在播放完成后重新变为Started状态并重新播放视频。
    PlaybackCompleted 状态下,调用start()也可以从音频/视频源的开头重新开始播放。

开始实现视频播放器
这里简单地画了下播放器的流程图(有点丑…)。
流程图

项目结构的话借鉴Goolgle官方MVP模式,能实现视频播放器解耦,功能操作和UI逻辑分离,使用契约类实现PresenterViewsPresenter中实现各种功能逻辑,Views负责UI展示。下面是项目的结构:

JVideoView项目结构

  • 契约类JVideoViewContract的实现,分工明确,在Presenter中实现播放器功能逻辑。
    interface JVideoViewContract {
   
        interface Views {
   
            //设置presenter
            fun setPresenter(presenter: Presenter)
            //设置播放标题
            fun setTitle(title:String)
            //缓冲中
            fun buffering(percent:Int)
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值