2019年11月2日 星期六

ExoPlayer使用Bitmap完成影片模糊


最近接到一個需求:要播放影片,並且對影片做模糊處理。

9102年都快過了,好ExoPlayer不玩嗎

廢話不多,先上GitHub:
https://github.com/AndyAWD/ExoPlayerBlur

用ExoPlayer播影片並不是什麼難事,上面的GitHub有基本顯示的實作方法,而且還是2.10.5最新版的寫法,別的地方應該還找不到,但影片模糊處理就有點麻煩,最早我用"exoplayer blur"當關鍵字找到一篇用OpenGL的寫法。

基於exoplayer播放器的高斯模糊視頻濾鏡
https://blog.csdn.net/liosen/article/details/83896721

他的寫法是把整個ExpPlayer抓下來壓成aar檔,複製其中的某些類別手動新增模糊的ArrayList,但這樣的問題是以後無法升級ExoPlayer的版本,我程度不夠用繼承改寫也失敗

不過他的寫法也發現ExoPlayer可以將影像傳到TextureView上,TextureView也能用監聽的方式取得影片每一幀的Bitmap,再對Bitmap做特效處理後顯示在ImageView上,一切都是那麼美好。


簡單教學:
第一步,建立Xml,Blogger貼Xml會有問題,只好貼圖請見諒,PlayerView要額外設定surface_type="texture_view"

第二步,初始化ExoPlayer然後和TextureView建立關連
private var textureView: TextureView? = null
private var imageView: ImageView? = null
private var simpleExoPlayer: SimpleExoPlayer? = null

private fun initExoPlayer() {
    val videoTrackSelectionFactory: TrackSelection.Factory = AdaptiveTrackSelection.Factory()
    val trackSelector: TrackSelector = DefaultTrackSelector(videoTrackSelectionFactory)
    val loadControl = DefaultLoadControl()
    simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(applicationContext, trackSelector, loadControl)

    simpleExoPlayer?.prepare(mediaSource("VideoUrl"))
    simpleExoPlayer?.addListener(this)
    simpleExoPlayer?.playWhenReady = true
    simpleExoPlayer?.repeatMode = Player.REPEAT_MODE_ALL

    textureView.alpha = 0.0f    //把TextureView設為透明,這樣模糊失敗的話也看不到影片
}

private fun mediaSource(uri: Uri): ProgressiveMediaSource {
    val defaultBandwidthMeter: DefaultBandwidthMeter = DefaultBandwidthMeter.Builder(applicationContext).build()
    val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(applicationContext, Util.getUserAgent(applicationContext, resources.getString(R.string.app_name)), defaultBandwidthMeter)
    val extractorsFactory: ExtractorsFactory = DefaultExtractorsFactory()

    return ProgressiveMediaSource.Factory(dataSourceFactory,extractorsFactory).setLoadErrorHandlingPolicy(this).createMediaSource(uri)
}

第三步,監聽TextureView,把處理後的圖片顯示出來
這邊我偷懶直接用別人寫好的模糊第三方EasyBlur,他的模糊可以在1~25調整,如果覺得不夠可以再調整壓縮比讓圖片更霧,如果要自己寫的話要記得先壓縮得到的Bitmap,不然還沒處理模糊就會oom
textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
    override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) {
        return
    }

    override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {
        //使用EasyBlur處理Bitmap
        val bitmapBlur = EasyBlur.with(EBApplication.context()).bitmap(textureView.bitmap).scale(10).radius(25).blur()
        imageView.setImageBitmap(bitmapBlur)
    }

    override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean {
        return false
    }

    override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) {
        simpleExoPlayer.setVideoSurface(Surface(surface))
    }
}


後記:
寫完這篇後我不小心在GitHub上用"ExoPlayer Filter"去找,結果找到一篇用OpenGL寫好的ExoPlayer第三方套件ExoPlayerFilter,所以說寫程式英文真的很重要,直接影響Google的基本能力


沒有留言:

張貼留言