直接按照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()
}
}