使用Ijkplayer播放flv资源

直接按照github上的方案引用 Ijkplayer 会失败 

依赖

build.gradle.kts添加

implementation("tv.danmaku.ijk.media:ijkplayer-java:0.8.8")     // 必选
implementation("tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8")   // 必选
implementation("tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8")    // 可选
implementation("tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8")    // 可选
implementation("tv.danmaku.ijk.media:ijkplayer-x86:0.8.8")      // 可选
implementation("tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8")   // 可选

settings.gradle.kts 添加

maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin")}

使用

package com.example.test.ui.ijk

import android.graphics.Matrix
import android.graphics.SurfaceTexture
import android.os.Bundle
import android.util.Log
import android.view.Surface
import android.view.TextureView
import androidx.activity.ComponentActivity
import com.blankj.utilcode.util.ToastUtils
import com.example.test.databinding.ActivityIjkPlayerBinding
import com.example.util.binding
import tv.danmaku.ijk.media.player.IMediaPlayer
import tv.danmaku.ijk.media.player.IjkMediaPlayer


class IjkPlayerActivity : ComponentActivity() {
    private val TAG = "FlvPlay"
    private val mFlvLink = "...." // 填入自己的flv
    private val mViewBinding: ActivityIjkPlayerBinding by binding()
    private val mMediaPlayer by lazy { IjkMediaPlayer() }
    private var mStartTime = 0L
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initIjkPlayer()
    }

    private fun initIjkPlayer() {
        Log.d(TAG, "开始播放链接 $mFlvLink")
        mStartTime = System.currentTimeMillis()
        mViewBinding.playerView.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
            override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
                Log.d(TAG, "onSurfaceTextureAvailable")
                playLink(surface)
            }

            override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
                Log.d(TAG, "onSurfaceTextureSizeChanged")
            }

            override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
                Log.d(TAG, "onSurfaceTextureDestroyed")
                return true
            }

            override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
                //Log.d(TAG, "onSurfaceTextureUpdated")
            }
        }
    }

    private fun playLink(surface: SurfaceTexture) {
        setupConfig()
        setupListener()
        mMediaPlayer.dataSource = mFlvLink
        mMediaPlayer.setSurface(Surface(surface))
        mMediaPlayer.prepareAsync()
    }

    private fun setupListener() {
        mMediaPlayer.setOnPreparedListener { iMediaPlayer -> iMediaPlayer?.start() }
        mMediaPlayer.setOnCompletionListener { iMediaPlayer ->
            Log.d(TAG, "FLV 播放完成")
            ToastUtils.showShort("播放完成")
        }
        mMediaPlayer.setOnErrorListener { mp, what, extra ->
            Log.d(TAG, "FLV 播放错误,what=${what}, extra=${extra}")
            when (what) {
                IMediaPlayer.MEDIA_ERROR_UNKNOWN -> Log.d(TAG, "FLV 详细错误信息: MEDIA_ERROR_UNKNOWN")
                IMediaPlayer.MEDIA_ERROR_SERVER_DIED -> Log.d(TAG, "FLV 详细错误信息: MEDIA_ERROR_SERVER_DIED")
                IMediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK -> Log.d(TAG, "FLV 详细错误信息: MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK")
                IMediaPlayer.MEDIA_ERROR_IO -> Log.d(TAG, "FLV 详细错误信息: MEDIA_ERROR_IO")
                IMediaPlayer.MEDIA_ERROR_MALFORMED -> Log.d(TAG, "FLV 详细错误信息: MEDIA_ERROR_MALFORMED")
                IMediaPlayer.MEDIA_ERROR_UNSUPPORTED -> Log.d(TAG, "FLV 详细错误信息: MEDIA_ERROR_UNSUPPORTED")
                IMediaPlayer.MEDIA_ERROR_TIMED_OUT -> Log.d(TAG, "FLV 详细错误信息: MEDIA_ERROR_TIMED_OUT")
            }
            return@setOnErrorListener true
        }
        mMediaPlayer.setOnInfoListener { iMediaPlayer, what, extra ->
            Log.d(TAG, "FLV 播放回调,what=${what}, extra=${extra}")
            when (what) {
                IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START -> {
                    val cost = System.currentTimeMillis() - mStartTime
                    Log.d(TAG, "开始第一帧视频, 耗时=${cost}ms")
                    ToastUtils.showShort("加载完成, 耗时=${cost}ms")
                }
            }
            return@setOnInfoListener false
        }
        mMediaPlayer.setOnVideoSizeChangedListener { iMediaPlayer, width, height, sarNum, sarDen ->
            Log.d(TAG, "onVideoSizeChanged, width=${width}, height=${height}, sar_num=${sarNum}, sar_den=${sarDen}")
            if (width == 0 || height == 0) return@setOnVideoSizeChangedListener
            kotlin.runCatching {
                var sx = mViewBinding.playerView.width / width.toFloat()
                var sy = mViewBinding.playerView.height / height.toFloat()

                val maxScale = sx.coerceAtLeast(sy)
                sx = maxScale / sx
                sy = maxScale / sy

                val matrix = Matrix()
                matrix.setScale(sx, sy, mViewBinding.playerView.width / 2f, mViewBinding.playerView.height / 2f)
                mViewBinding.playerView.setTransform(matrix)
            }.onFailure {
                Log.d(TAG, "设置CenterCrop失败, msg=${it.message}")
            }.onSuccess {
                Log.d(TAG, "设置CenterCrop成功")
            }
        }
    }

    private fun setupConfig() {
        // 降低初始缓冲时间 (关键!)
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 1)

        // 减少探测时间 (快速识别FLV格式)
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 1024L)
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzeduration", 100L)

        // 禁用缓冲 (首帧优先)
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0)

        // 设置零缓存策略
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "max-buffer-size", 0)
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", 1)

        // 启用硬件加速 (显著提升解码速度)
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1)
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1)

        // 优化视频帧处理
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 5) // 适度丢帧
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-fps", 0)   // 不限制FPS

        // 网络协议优化
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "reconnect", 1)
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", 3000000) // 3秒超时

        // 直播专属优化
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_clear", 1)
        mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "multiple_requests", 1)
    }


    override fun onDestroy() {
        super.onDestroy()
        mMediaPlayer.stop()
        mMediaPlayer.release()
        IjkMediaPlayer.native_profileEnd()
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值