视频播放
This commit is contained in:
@@ -1,80 +1,251 @@
|
||||
package com.example.defenseapplication.liveVideo
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.media.AudioManager
|
||||
import android.media.MediaPlayer
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.SurfaceHolder
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedDispatcher
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.ui.test.isEnabled
|
||||
import com.example.defenseapplication.databinding.LiveVideoActivityBinding
|
||||
import java.io.IOException
|
||||
|
||||
class LiveVideoActivity : AppCompatActivity() {
|
||||
class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
|
||||
private lateinit var binding: LiveVideoActivityBinding
|
||||
|
||||
private var mediaPlayer: MediaPlayer? = null
|
||||
private var isFullscreen = false
|
||||
private var isPlaying = false
|
||||
private var isVoiceEnabled = false
|
||||
private var isLightOn = false
|
||||
private var isRecording = false
|
||||
private var recordTime = 0
|
||||
private var recordHandler: Handler? = null
|
||||
private var recordRunnable: Runnable? = null
|
||||
|
||||
private var videoWidth = 0
|
||||
private var videoHeight = 0
|
||||
|
||||
private val testVideoUrl = "https://vjs.zencdn.net/v/oceans.mp4"
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = LiveVideoActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
|
||||
|
||||
initSurfaceView()
|
||||
initListener()
|
||||
}
|
||||
|
||||
private fun initSurfaceView() {
|
||||
binding.surfaceView.holder.addCallback(this)
|
||||
}
|
||||
|
||||
override fun surfaceCreated(holder: SurfaceHolder) {
|
||||
initMediaPlayer(holder)
|
||||
}
|
||||
|
||||
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
||||
adjustSurfaceViewSize()
|
||||
}
|
||||
|
||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||
releaseMediaPlayer()
|
||||
}
|
||||
|
||||
private fun initMediaPlayer(holder: SurfaceHolder) {
|
||||
mediaPlayer = MediaPlayer().apply {
|
||||
setDisplay(holder)
|
||||
setAudioStreamType(AudioManager.STREAM_MUSIC)
|
||||
|
||||
try {
|
||||
setDataSource(this@LiveVideoActivity, Uri.parse(testVideoUrl))
|
||||
prepareAsync()
|
||||
|
||||
setOnPreparedListener { mp ->
|
||||
this@LiveVideoActivity.videoWidth = mp.videoWidth
|
||||
this@LiveVideoActivity.videoHeight = mp.videoHeight
|
||||
adjustSurfaceViewSize()
|
||||
mp.isLooping = true
|
||||
mp.start()
|
||||
this@LiveVideoActivity.isPlaying = true
|
||||
Toast.makeText(this@LiveVideoActivity, "视频准备完成", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
setOnCompletionListener {
|
||||
this@LiveVideoActivity.isPlaying = false
|
||||
Toast.makeText(this@LiveVideoActivity, "播放完成", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
setOnErrorListener { _, what, extra ->
|
||||
Toast.makeText(this@LiveVideoActivity, "播放错误: $what, $extra", Toast.LENGTH_SHORT).show()
|
||||
releaseMediaPlayer()
|
||||
true
|
||||
}
|
||||
|
||||
setOnBufferingUpdateListener { _, percent ->
|
||||
if (percent < 100) {
|
||||
Toast.makeText(this@LiveVideoActivity, "缓冲中: $percent%", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(this@LiveVideoActivity, "无法加载视频", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun adjustSurfaceViewSize() {
|
||||
if (videoWidth == 0 || videoHeight == 0) return
|
||||
|
||||
val screenWidth = resources.displayMetrics.widthPixels
|
||||
val screenHeight = resources.displayMetrics.heightPixels
|
||||
val aspectRatio = videoWidth.toFloat() / videoHeight.toFloat()
|
||||
|
||||
val params = binding.surfaceView.layoutParams
|
||||
|
||||
if (isFullscreen) {
|
||||
if (screenWidth.toFloat() / screenHeight.toFloat() > aspectRatio) {
|
||||
params.width = (screenHeight * aspectRatio).toInt()
|
||||
params.height = screenHeight
|
||||
} else {
|
||||
params.width = screenWidth
|
||||
params.height = (screenWidth / aspectRatio).toInt()
|
||||
}
|
||||
} else {
|
||||
val containerHeight = binding.videoContainer.height
|
||||
params.width = (containerHeight * aspectRatio).toInt()
|
||||
params.height = containerHeight
|
||||
}
|
||||
|
||||
binding.surfaceView.layoutParams = params
|
||||
}
|
||||
|
||||
private fun initListener() {
|
||||
// 返回按钮
|
||||
binding.btnBack.setOnClickListener {
|
||||
finish()
|
||||
}
|
||||
|
||||
// 菜单按钮
|
||||
binding.ivMenu.setOnClickListener {
|
||||
Toast.makeText(this, "菜单", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
// 全屏按钮
|
||||
binding.ivFullscreen.setOnClickListener {
|
||||
Toast.makeText(this, "全屏", Toast.LENGTH_SHORT).show()
|
||||
toggleFullscreen()
|
||||
}
|
||||
|
||||
binding.surfaceView.setOnClickListener {
|
||||
togglePlayPause()
|
||||
}
|
||||
|
||||
// 语音按钮
|
||||
binding.llVoice.setOnClickListener {
|
||||
toggleVoice()
|
||||
}
|
||||
|
||||
// 灯光按钮
|
||||
binding.llLight.setOnClickListener {
|
||||
toggleLight()
|
||||
}
|
||||
|
||||
// 录像按钮
|
||||
binding.llRecord.setOnClickListener {
|
||||
toggleRecording()
|
||||
}
|
||||
|
||||
// 告警日志区域
|
||||
binding.llAlarmLog.setOnClickListener {
|
||||
Toast.makeText(this, "查看告警日志", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun togglePlayPause() {
|
||||
mediaPlayer?.let { mp ->
|
||||
if (mp.isPlaying) {
|
||||
mp.pause()
|
||||
isPlaying = false
|
||||
Toast.makeText(this, "已暂停", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
mp.start()
|
||||
isPlaying = true
|
||||
Toast.makeText(this, "继续播放", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleFullscreen() {
|
||||
isFullscreen = !isFullscreen
|
||||
|
||||
if (isFullscreen) {
|
||||
enterFullscreen()
|
||||
} else {
|
||||
exitFullscreen()
|
||||
}
|
||||
}
|
||||
|
||||
private fun enterFullscreen() {
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
||||
|
||||
binding.topBar.visibility = View.GONE
|
||||
binding.bitRateBar.visibility = View.GONE
|
||||
binding.functionBar.visibility = View.GONE
|
||||
|
||||
val alarmLogParent = binding.llAlarmLog.parent.parent as View
|
||||
alarmLogParent.visibility = View.GONE
|
||||
|
||||
val containerParams = binding.videoContainer.layoutParams
|
||||
containerParams.width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
containerParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
binding.videoContainer.layoutParams = containerParams
|
||||
|
||||
val surfaceParams = binding.surfaceView.layoutParams
|
||||
surfaceParams.width = resources.displayMetrics.widthPixels
|
||||
surfaceParams.height = resources.displayMetrics.heightPixels
|
||||
binding.surfaceView.layoutParams = surfaceParams
|
||||
|
||||
binding.ivFullscreen.setImageResource(com.example.defenseapplication.R.drawable.back)
|
||||
|
||||
Toast.makeText(this, "已进入全屏", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun exitFullscreen() {
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
||||
|
||||
binding.topBar.visibility = View.VISIBLE
|
||||
binding.bitRateBar.visibility = View.VISIBLE
|
||||
binding.functionBar.visibility = View.VISIBLE
|
||||
|
||||
val alarmLogParent = binding.llAlarmLog.parent.parent as View
|
||||
alarmLogParent.visibility = View.VISIBLE
|
||||
|
||||
val containerParams = binding.videoContainer.layoutParams
|
||||
containerParams.width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
containerParams.height = (220 * resources.displayMetrics.density).toInt()
|
||||
binding.videoContainer.layoutParams = containerParams
|
||||
|
||||
adjustSurfaceViewSize()
|
||||
|
||||
binding.ivFullscreen.setImageResource(com.example.defenseapplication.R.drawable.full_screen)
|
||||
|
||||
Toast.makeText(this, "已退出全屏", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
private fun toggleVoice() {
|
||||
isVoiceEnabled = !isVoiceEnabled
|
||||
|
||||
if (isVoiceEnabled) {
|
||||
binding.vVoiceActive.visibility = View.VISIBLE
|
||||
binding.ivVoice.setColorFilter(resources.getColor(com.example.defenseapplication.R.color.green))
|
||||
Toast.makeText(this, "语音已开启", Toast.LENGTH_SHORT).show()
|
||||
mediaPlayer?.setVolume(1.0f, 1.0f)
|
||||
binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice_open)
|
||||
Toast.makeText(this, "声音已开启", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
binding.vVoiceActive.visibility = View.INVISIBLE
|
||||
binding.ivVoice.clearColorFilter()
|
||||
Toast.makeText(this, "语音已关闭", Toast.LENGTH_SHORT).show()
|
||||
mediaPlayer?.setVolume(0.0f, 0.0f)
|
||||
binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice)
|
||||
Toast.makeText(this, "声音已关闭", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,12 +253,10 @@ class LiveVideoActivity : AppCompatActivity() {
|
||||
isLightOn = !isLightOn
|
||||
|
||||
if (isLightOn) {
|
||||
binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.light_on)
|
||||
binding.ivLight.setColorFilter(resources.getColor(com.example.defenseapplication.R.color.green))
|
||||
binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.light_on_open)
|
||||
Toast.makeText(this, "灯光已开启", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.low_light)
|
||||
binding.ivLight.clearColorFilter()
|
||||
binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.light_on)
|
||||
Toast.makeText(this, "灯光已关闭", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
@@ -96,38 +265,37 @@ class LiveVideoActivity : AppCompatActivity() {
|
||||
isRecording = !isRecording
|
||||
|
||||
if (isRecording) {
|
||||
recordTime = 0
|
||||
binding.tvRecordTime.text = "00"
|
||||
startRecordTimer()
|
||||
binding.ivRecord.setColorFilter(resources.getColor(com.example.defenseapplication.R.color.red))
|
||||
binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy_open)
|
||||
Toast.makeText(this, "开始录像", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
stopRecordTimer()
|
||||
binding.ivRecord.clearColorFilter()
|
||||
Toast.makeText(this, "停止录像,共录制 ${recordTime} 秒", Toast.LENGTH_SHORT).show()
|
||||
binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy)
|
||||
Toast.makeText(this, "停止录像", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun startRecordTimer() {
|
||||
recordHandler = Handler(Looper.getMainLooper())
|
||||
recordRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
recordTime++
|
||||
binding.tvRecordTime.text = String.format("%02d", recordTime)
|
||||
recordHandler?.postDelayed(this, 1000)
|
||||
private fun releaseMediaPlayer() {
|
||||
mediaPlayer?.let {
|
||||
if (it.isPlaying) {
|
||||
it.stop()
|
||||
}
|
||||
it.release()
|
||||
mediaPlayer = null
|
||||
}
|
||||
recordHandler?.post(recordRunnable!!)
|
||||
}
|
||||
|
||||
private fun stopRecordTimer() {
|
||||
recordRunnable?.let { recordHandler?.removeCallbacks(it) }
|
||||
recordHandler = null
|
||||
recordRunnable = null
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
mediaPlayer?.pause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mediaPlayer?.start()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
releaseMediaPlayer()
|
||||
super.onDestroy()
|
||||
stopRecordTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user