前言:
依赖版本:
implementation 'com.google.android.exoplayer:exoplayer-core:2.13.3'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.13.3'
自定义统一接口IPlayer (interface)
interface IPlayer {
companion object {
const val PLAYER_NULL = -1
const val PLAYER_INIT = 0
const val PLAYER_PREPARE = 1
const val PLAYER_PLAY = 2
const val PLAYER_PAUSE = 3
const val PLAYER_STOP = 4
const val PLAYER_RELEASE = 7
const val PLAYER_SET_SURFACE = 8
}
fun play()
fun setRepeatMode(mode: Int) {
}
fun getRepeatMode(): Int {
return 0
}
//异步
fun prepare(url: String)
fun stop()
fun pause()
fun release()
fun seekTo(time: Long, autoPlay: Boolean = true)
fun getCurrentPosition(): Long
fun getDuration(): Long {
return 0L
}
fun getVolume(): Float {
return 0F
}
fun setVolume(value: Float): Boolean {
return false
}
}
封装 ExoPlayer
封装参考:SimpleExoPlayer extends BasePlayer
class ExoPlayer(private val context: Context) : IPlayer {
private var currentPlayerUrl = ""
private var playStatus = PLAYER_PLAY
private var exoPlayer: SimpleExoPlayer? = null
private var contentFrame: AspectRatioFrameLayout? = null
private var surfaceView: View? = null
private var textureViewRotation = 0
private var repeatMode = Player.REPEAT_MODE_ONE
private var currentVolume = 0F
private var mComponentListener: ComponentListener? = null
private var mPlayerEventListener: PlayerEventListener? = null
init {
// val extractors = DefaultExtractorsFactory()
// exoPlayer = SimpleExoPlayer.Builder(
// context,
// DefaultRenderersFactory(context),
// DefaultTrackSelector(context),
// DefaultMediaSourceFactory(context, extractors),
// TmpLoadControl(),
// DefaultBandwidthMeter.getSingletonInstance(context),
// AnalyticsCollector(Clock.DEFAULT)
// ).build()
exoPlayer = SimpleExoPlayer.Builder(context).build()
}
fun setVideoTextureView(view: TextureView) {
surfaceView = view
mComponentListener = ComponentListener()
exoPlayer?.let {
it.setVideoTextureView(view)
it.videoComponent?.let { component ->
component.addVideoListener(mComponentListener!!)
}
it.addListener(mComponentListener!!)
}
}
fun setAspectRatioFrameLayout(view: AspectRatioFrameLayout?) {
contentFrame = view
}
override fun play() {
exoPlayer?.let {
playStatus = PLAYER_PLAY
it.play()
currentVolume = it.volume
}
}
/**
*
*/
override fun setRepeatMode(mode: Int) {
var tmp = Player.REPEAT_MODE_ONE
when (mode) {
0 -> {
tmp = Player.REPEAT_MODE_OFF
}
}
this.repeatMode = tmp
}
override fun getRepeatMode(): Int {
var tmp = 0
exoPlayer?.let {
when (it.repeatMode) {
Player.REPEAT_MODE_ONE -> {
tmp = 1
}
Player.REPEAT_MODE_OFF -> {
tmp = 0
}
}
}
return tmp
}
override fun getVolume(): Float {
return currentVolume
}
override fun setVolume(value: Float): Boolean {
exoPlayer?.volume = value
return true
}
override fun prepare(url: String) {
currentPlayerUrl = url
playStatus = PLAYER_PREPARE
val mediaItem = MediaItem.fromUri(url)
exoPlayer?.let {
it.setMediaItem(mediaItem)
it.repeatMode = repeatMode
it.playWhenReady = false
it.prepare()
IKLog.d("$TAG prepare volume:${it.volume}")
}
}
override fun stop() {
exoPlayer?.let {
playStatus = PLAYER_STOP
it.stop()
}
}
override fun pause() {
exoPlayer?.let { player ->
playStatus = PLAYER_PAUSE
player.pause()
}
}
override fun release() {
exoPlayer?.let { player ->
playStatus = PLAYER_RELEASE
mComponentListener?.let {
player.removeListener(it)
}
player.stop()
player.release()
exoPlayer = null
}
}
override fun seekTo(time: Long, autoPlay: Boolean) {
exoPlayer?.let {
it.seekTo(time)
if (autoPlay) {
it.play()
}
}
}
override fun getCurrentPosition(): Long {
return exoPlayer?.contentPosition ?: 0L
}
override fun getDuration(): Long {
return exoPlayer?.duration ?: 0L
}
private inner class ComponentListener : Player.EventListener, VideoListener, View.OnLayoutChangeListener {
override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) {
var videoAspectRatio: Float = if (height == 0 || width == 0) 1F else width * pixelWidthHeightRatio / height
surfaceView?.let { view ->
if (view is TextureView) {
if (unappliedRotationDegrees == 90 || unappliedRotationDegrees == 270) {
videoAspectRatio = 1 / videoAspectRatio
}
if (textureViewRotation != 0) {
view.removeOnLayoutChangeListener(this)
}
textureViewRotation = unappliedRotationDegrees
if (textureViewRotation != 0) {
view.addOnLayoutChangeListener(this)
}
PlayerUtils.applyTextureViewRotation(view, textureViewRotation)
}
}
onContentAspectRatioChanged(videoAspectRatio, contentFrame, surfaceView)
}
override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) {
PlayerUtils.applyTextureViewRotation(v as TextureView, textureViewRotation)
}
override fun onEvents(player: Player, events: Player.Events) {
super.onEvents(player, events)
IKLog.d(TAG, "onEvents: events:${events} ${events.contains(Player.EVENT_PLAYER_ERROR)} ")
if (events.contains(Player.EVENT_PLAYER_ERROR)) {
IKLog.e("$TAG onEvents: playerError:${player.playerError}")
}
mPlayerEventListener?.onEvent(events)
}
override fun onRenderedFirstFrame() {
super.onRenderedFirstFrame()
IKLog.d("$TAG onRenderedFirstFrame")
mPlayerEventListener?.onRenderedFirstFrame()
}
override fun onPlaybackStateChanged(state: Int) {
super.onPlaybackStateChanged(state)
IKLog.e(TAG, "onEvents: events:${state}")
mPlayerEventListener?.onPlaybackStateChanged(state)
}
}
private fun onContentAspectRatioChanged(
contentAspectRatio: Float,
contentFrame: AspectRatioFrameLayout?,
contentView: View?
) {
contentFrame?.setAspectRatio(
if (contentView is SphericalGLSurfaceView) 0F else contentAspectRatio
)
}
fun setPlayerEventListener(listener: PlayerEventListener) {
mPlayerEventListener = listener
}
interface PlayerEventListener {
fun onEvent(events: Player.Events)
fun onPlaybackStateChanged(state: Int) {
}
fun onRenderedFirstFrame() {
}
}
}
其中:图像纠正相关
ComponentListener{
onVideoSizeChanged
onLayoutChange
}
PlayerUtils
object PlayerUtils {
fun applyTextureViewRotation(textureView: TextureView, textureViewRotation: Int) {
val transformMatrix = Matrix()
val textureViewWidth = textureView.width.toFloat()
val textureViewHeight = textureView.height.toFloat()
if (textureViewWidth != 0f && textureViewHeight != 0f && textureViewRotation != 0) {
val pivotX = textureViewWidth / 2
val pivotY = textureViewHeight / 2
transformMatrix.postRotate(textureViewRotation.toFloat(), pivotX, pivotY)
// After rotation, scale the rotated texture to fit the TextureView size.
val originalTextureRect = RectF(0F, 0F, textureViewWidth, textureViewHeight)
val rotatedTextureRect = RectF()
transformMatrix.mapRect(rotatedTextureRect, originalTextureRect)
transformMatrix.postScale(
textureViewWidth / rotatedTextureRect.width(),
textureViewHeight / rotatedTextureRect.height(),
pivotX,
pivotY
)
}
textureView.setTransform(transformMatrix)
}
}
网友评论