一手遮天 Android - view(媒体类): MediaPlayer(在 SurfaceView 上播放)
一手遮天 Android - view(媒体类): MediaPlayer(在 SurfaceView 上播放)
示例如下:
/view/media/MediaPlayerDemo1.kt
/**
* MediaPlayer(在 SurfaceView 上播放)
*
* 注:无法对 SurfaceView 截图,如果需要对视频截图的话可以使用 TextureView,参见 MediaPlayerDemo2.kt
*/
package com.webabcd.androiddemo.view.media
import android.content.pm.ActivityInfo
import android.media.MediaPlayer
import android.media.MediaPlayer.*
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.Gravity
import android.view.SurfaceHolder
import android.view.WindowInsets
import android.widget.FrameLayout
import androidx.appcompat.app.AppCompatActivity
import com.webabcd.androiddemo.databinding.ActivityViewMediaMediaplayerdemo1Binding
import java.util.*
import kotlin.math.ceil
import kotlin.math.max
class MediaPlayerDemo1 : AppCompatActivity(), SurfaceHolder.Callback,
OnBufferingUpdateListener,
OnCompletionListener,
OnPreparedListener,
OnErrorListener,
OnInfoListener,
OnSeekCompleteListener,
OnVideoSizeChangedListener {
private val _logTag = "MediaPlayerDemo1"
private lateinit var mBinding: ActivityViewMediaMediaplayerdemo1Binding
private lateinit var _surfaceHolder: SurfaceHolder
private var _mediaPlayer: MediaPlayer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = ActivityViewMediaMediaplayerdemo1Binding.inflate(layoutInflater)
setContentView(mBinding.root)
// 横屏
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
// 隐藏状态栏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val controller = window.insetsController
controller!!.hide(WindowInsets.Type.statusBars())
}
_surfaceHolder = mBinding.surfaceView.holder
_surfaceHolder.addCallback(this)
mBinding.button1.setOnClickListener {
playVideo()
}
mBinding.button2.setOnClickListener {
stopVideo()
}
}
override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) {
}
override fun surfaceDestroyed(p0: SurfaceHolder) {
}
override fun surfaceCreated(p0: SurfaceHolder) {
printLog("surface created")
}
private fun playVideo() {
stopVideo()
try {
_mediaPlayer = MediaPlayer()
_mediaPlayer!!.setDisplay(_surfaceHolder)
_mediaPlayer!!.setOnBufferingUpdateListener(this)
_mediaPlayer!!.setOnPreparedListener(this)
_mediaPlayer!!.setOnCompletionListener(this)
_mediaPlayer!!.setOnErrorListener(this)
_mediaPlayer!!.setOnInfoListener(this)
_mediaPlayer!!.setOnSeekCompleteListener(this)
_mediaPlayer!!.setOnVideoSizeChangedListener(this)
_mediaPlayer!!.setDataSource("https://d2zihajmogu5jn.cloudfront.net/sintel/master.m3u8")
_mediaPlayer!!.prepareAsync()
} catch (ex: Exception) {
printLog("mediaPlayer error: $ex")
}
}
private fun stopVideo() {
if (_mediaPlayer != null) {
_mediaPlayer!!.stop()
_mediaPlayer!!.release()
_mediaPlayer = null
}
}
override fun onPrepared(p0: MediaPlayer?) {
_mediaPlayer!!.start()
}
override fun onInfo(p0: MediaPlayer?, what: Int, extra: Int): Boolean {
printLog(String.format(Locale.US, "onInfo, what:%d, extra:%d", what, extra))
return false
}
override fun onError(p0: MediaPlayer?, what: Int, extra: Int): Boolean {
printLog(String.format(Locale.US, "onError, what:%d, extra:%d", what, extra))
return false
}
override fun onVideoSizeChanged(p0: MediaPlayer?, width: Int, height: Int) {
printLog(String.format(Locale.US, "onVideoSizeChanged, width:%d, height:%d", width, height))
}
override fun onSeekComplete(p0: MediaPlayer?) {
printLog("onSeekComplete")
}
override fun onCompletion(p0: MediaPlayer?) {
printLog("onCompletion")
}
override fun onBufferingUpdate(p0: MediaPlayer?, percent: Int) {
// printLog(String.format(Locale.US, "onBufferingUpdate, percent:%d", percent));
}
private fun printLog(message: String) {
Log.d(_logTag, message)
mBinding.txtLog.post(Runnable {
mBinding.txtLog.append(message)
mBinding.txtLog.append("\n")
val offset: Int = mBinding.txtLog.lineCount * mBinding.txtLog.lineHeight
if (offset > mBinding.txtLog.height) {
mBinding.txtLog.scrollTo(0, offset - mBinding.txtLog.height)
}
})
}
}
/layout/activity_view_media_mediaplayerdemo1.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:id="@+id/buttonContainer"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:alpha="0.85">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_button_background"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textAllCaps="false"
android:text="播放"
android:textColor="#fff" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:background="@drawable/selector_button_background"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:textAllCaps="false"
android:text="停止"
android:textColor="#fff" />
</LinearLayout>
<TextView
android:id="@+id/txtStatus"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="bottom"
android:background="#9933b8fc"
android:gravity="center"
android:textColor="#fff" />
<TextView
android:id="@+id/txtLog"
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_marginBottom="40dp"
android:padding="5dp"
android:layout_gravity="right"
android:background="#7733b8fc"
android:gravity="top"
android:textColor="#fff" />
</FrameLayout>