1、Exoplayer的基本使用:
- Android ExoPlayer 播放普通视频;
- Android ExoPlayer 播放.m3u8 视频;
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl_root_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black_2"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/rl_vidwo"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/playerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:controller_layout_id="@layout/view_video_play"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="@+id/loading_video_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<ImageView
android:id="@+id/iv_stop_hint"
android:layout_width="@dimen/dp_px_180"
android:layout_height="@dimen/dp_px_180"
android:contentDescription="@null"
android:src="@drawable/fragment_base_video"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
class PreviewActivity : BaseActivity() {
@JvmField
@Autowired(name = "key_video_url")
var videoUrl: String? = null
private var dataModel: JRTemplateModel? = null
private lateinit var binding: ActivityJrTemplatePreviewBinding
private lateinit var viewModel: TemplateViewModel
private lateinit var mExoPlayer: SimpleExoPlayer
override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityJrTemplatePreviewBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel = ViewModelProvider(this)[TemplateViewModel::class.java]
super.onCreate(savedInstanceState)
initializePlayer()
initMyListener()
}
private fun initializePlayer() {
// 本地最多保存512M, 按照LRU原则删除老数据
mExoPlayer = ExoPlayerFactory.newSimpleInstance(this, DefaultRenderersFactory(this),
DefaultTrackSelector(), DefaultLoadControl())
binding.playerView.player = mExoPlayer
mExoPlayer.playWhenReady = true
}
private fun playVideo(videoPath: String) {
mExoPlayer.prepare(buildMediaSource(videoPath))
mExoPlayer.addListener(object : Player.EventListener {
})
mExoPlayer.repeatMode = Player.REPEAT_MODE_ONE
}
/**
* 不同格式的视频,使用不同的MediaSource
*/
private fun buildMediaSource(videoPath: String): MediaSource {
Log.d("caowj", "预览视频:$videoPath")
val userAgent = Util.getUserAgent(this, getString(R.string.app_name))
val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(this, userAgent)
return if (videoPath.endsWith(".m3u8")) {
HlsMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(videoPath))
} else {
ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(videoPath))
}
}
private fun initMyListener() {
binding.playerView.setOnTouchListener { v, event -> //VideoView的点击事件无效,而且只有Down事件,所以用onTouch
if (event.action == MotionEvent.ACTION_DOWN) {
if (mExoPlayer != null && mExoPlayer.isPlaying) {
binding.ivStopHint.visibility = View.VISIBLE
onPlayerPause()
} else {
binding.ivStopHint.visibility = View.GONE
onPlayerPlay()
}
}
false
}
mExoPlayer.addAnalyticsListener(object : AnalyticsListener {
override fun onPlayerStateChanged(eventTime: EventTime, playWhenReady: Boolean,
playbackState: Int) {
if (playbackState == Player.STATE_BUFFERING) {
binding.loadingVideoView.visibility = View.VISIBLE
} else if (playbackState == Player.STATE_READY) {
binding.loadingVideoView.visibility = View.INVISIBLE
}
}
})
}
// "http://1500012508.vod2.myqcloud.com/a2881bc7vodtranssh1500012508/ff111f4b243791581497738888/v.f1416687.m3u8"
playVideo(videoUrl!!)
}
override fun onPause() {
super.onPause()
onPlayerPause()
}
override fun onResume() {
super.onResume()
if (!mExoPlayer.isPlaying) {
binding.ivStopHint.visibility = View.GONE
onPlayerPlay()
}
}
private fun onPlayerPlay() {
mExoPlayer.playWhenReady = true
}
private fun onPlayerPause() {
mExoPlayer.playWhenReady = false
}
override fun onDestroy() {
super.onDestroy()
onPlayerPause()
mExoPlayer.release()
}
}
2、问题
NoSupport [codec.profileLevel, avc1.640034, video/avc] [OMX.MTK.VIDEO.DECODER.AVC, video/avc] [PD2164U, V2164KA, vivo, 30]
详细日志:
NoSupport [codec.profileLevel, avc1.640034, video/avc] [OMX.MTK.VIDEO.DECODER.AVC, video/avc] [PD2164U, V2164KA, vivo, 30]
NoSupport [sizeAndRate.support, 1440x3088x-1.0] [c2.android.avc.decoder, video/avc] [PD2164U, V2164KA, vivo, 30]
NoSupport [sizeAndRate.support, 1440x3088x-1.0] [c2.android.avc.decoder, video/avc] [PD2164U, V2164KA, vivo, 30]
NoSupport [sizeAndRate.support, 1440x3088x-1.0] [OMX.google.h264.decoder, video/avc] [PD2164U, V2164KA, vivo, 30]
NoSupport [codec.profileLevel, avc1.640034, video/avc] [OMX.MTK.VIDEO.DECODER.AVC, video/avc] [PD2164U, V2164KA, vivo, 30]
Renderer error: index=0, type=video, format=Format(0, null, null, video/avc, avc1.640034, -1, null, [1440, 3088, -1.0], [-1, -1]), renderer
com.google.android.exoplayer2.ExoPlaybackException: java.lang.IllegalStateException
at com.google.android.exoplayer2.BaseRenderer.createRendererException(BaseRenderer.java:359)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:723)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:599)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:329)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:257)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: java.lang.IllegalStateException
at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
at android.media.MediaCodec.dequeueOutputBuffer(MediaCodec.java:3505)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.drainOutputBuffer(MediaCodecRenderer.java:1504)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:709)
at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:599)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:329)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:257)
at android.os.HandlerThread.run(HandlerThread.java:67)
Disable failed.
java.lang.IllegalStateException
at android.media.MediaCodec.native_flush(Native Method)
at android.media.MediaCodec.flush(MediaCodec.java:2351)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.flushOrReleaseCodec(MediaCodecRenderer.java:764)
at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.flushOrReleaseCodec(MediaCodecVideoRenderer.java:723)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.onDisabled(MediaCodecRenderer.java:629)
at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.onDisabled(MediaCodecVideoRenderer.java:568)
at com.google.android.exoplayer2.BaseRenderer.disable(BaseRenderer.java:168)
at com.google.android.exoplayer2.ExoPlayerImplInternal.disableRenderer(ExoPlayerImplInternal.java:1136)
at com.google.android.exoplayer2.ExoPlayerImplInternal.resetInternal(ExoPlayerImplInternal.java:891)
at com.google.android.exoplayer2.ExoPlayerImplInternal.stopInternal(ExoPlayerImplInternal.java:850)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:382)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:257)
at android.os.HandlerThread.run(HandlerThread.java:67)
Reset failed.
java.lang.IllegalStateException
at android.media.MediaCodec.native_stop(Native Method)
at android.media.MediaCodec.stop(MediaCodec.java:2294)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.releaseCodec(MediaCodecRenderer.java:659)
at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.releaseCodec(MediaCodecVideoRenderer.java:713)
at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.onReset(MediaCodecRenderer.java:636)
at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.onReset(MediaCodecVideoRenderer.java:577)
at com.google.android.exoplayer2.BaseRenderer.reset(BaseRenderer.java:175)
at com.google.android.exoplayer2.ExoPlayerImplInternal.resetInternal(ExoPlayerImplInternal.java:900)
at com.google.android.exoplayer2.ExoPlayerImplInternal.stopInternal(ExoPlayerImplInternal.java:850)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:382)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:257)
at android.os.HandlerThread.run(HandlerThread.java:67)
onPlayerErrorcom.google.android.exoplayer2.ExoPlaybackException: java.lang.IllegalStateException
原因:
Your video uses H.264 Main Profile (avc1.4D) which is not supported by these particular devices. The minimum requirement for Main Profile is 6.0+.
您的视频使用这些特定设备不支持的 H.264 Main Profile (avc1.4D)。 Main Profile 的最低要求是 6.0+。
https://www.likecs.com/ask-7317119.html
https://github.com/google/ExoPlayer/issues/6433