云台控制

This commit is contained in:
2026-05-07 14:22:35 +08:00
parent fd5a5a30d2
commit ae5559e01a
15 changed files with 999 additions and 11 deletions

View File

@@ -1,24 +1,38 @@
package com.example.defenseapplication.liveVideo
import android.Manifest
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.media.AudioManager
import android.media.MediaPlayer
import android.media.MediaRecorder
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.view.SurfaceHolder
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.animation.Animation
import android.view.animation.LinearInterpolator
import android.view.animation.ScaleAnimation
import android.widget.Toast
import androidx.activity.OnBackPressedDispatcher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.ui.test.isEnabled
import androidx.core.content.ContextCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.LiveVideoActivityBinding
import com.gyf.immersionbar.ImmersionBar
import com.gyf.immersionbar.ktx.destroyImmersionBar
import java.io.File
import java.io.IOException
private const val TAG = "LiveVideoActivity"
class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
private lateinit var binding: LiveVideoActivityBinding
@@ -28,11 +42,24 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
private var isVoiceEnabled = false
private var isLightOn = false
private var isRecording = false
private var mediaRecorder: MediaRecorder? = null
private var micPulseAnimation: ScaleAnimation? = null
private var videoWidth = 0
private var videoHeight = 0
private val testVideoUrl = "https://vjs.zencdn.net/v/oceans.mp4"
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
startRecordingMode()
} else {
Toast.makeText(this, "需要录音权限才能使用控制功能", Toast.LENGTH_SHORT).show()
isRecording = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -140,7 +167,8 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
}
binding.ivMenu.setOnClickListener {
Toast.makeText(this, "菜单", Toast.LENGTH_SHORT).show()
val intent = Intent(this, SettingsActivity::class.java)
startActivity(intent)
}
binding.ivFullscreen.setOnClickListener {
@@ -166,6 +194,12 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
binding.llAlarmLog.setOnClickListener {
Toast.makeText(this, "查看告警日志", Toast.LENGTH_SHORT).show()
}
// 点击xq箭头跳转到AlarmLogActivity
binding.xq.setOnClickListener {
val intent = Intent(this, AlarmLogActivity::class.java)
startActivity(intent)
}
}
private fun togglePlayPause() {
@@ -270,14 +304,124 @@ class LiveVideoActivity : AppCompatActivity(), SurfaceHolder.Callback {
}
private fun toggleRecording() {
isRecording = !isRecording
if (isRecording) {
binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy_open)
Toast.makeText(this, "开始录像", Toast.LENGTH_SHORT).show()
if (!isRecording) {
if (checkRecordAudioPermission()) {
startRecordingMode()
} else {
requestRecordAudioPermission()
}
} else {
binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy)
Toast.makeText(this, "停止录像", Toast.LENGTH_SHORT).show()
stopRecordingMode()
}
}
private fun checkRecordAudioPermission(): Boolean {
return ContextCompat.checkSelfPermission(
this,
Manifest.permission.RECORD_AUDIO
) == PackageManager.PERMISSION_GRANTED
}
private fun requestRecordAudioPermission() {
requestPermissionLauncher.launch(Manifest.permission.RECORD_AUDIO)
}
private fun startRecordingMode() {
isRecording = true
binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy_open)
// 隐藏告警日志区域,显示控制台区域
binding.llAlarmLog.visibility = View.GONE
binding.consoleBar.visibility = View.VISIBLE
// 麦克风切换成开启状态
binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice_open)
isVoiceEnabled = true
// 启动语音录制
startVoiceRecording()
// 启动麦克风脉冲动画
startMicPulseAnimation()
Toast.makeText(this, "开始控制模式", Toast.LENGTH_SHORT).show()
}
private fun stopRecordingMode() {
isRecording = false
binding.ivRecord.setImageResource(com.example.defenseapplication.R.drawable.copy)
// 显示告警日志区域,隐藏控制台区域
binding.llAlarmLog.visibility = View.VISIBLE
binding.consoleBar.visibility = View.GONE
// 麦克风切换成关闭状态
binding.ivVoice.setImageResource(com.example.defenseapplication.R.drawable.voice)
isVoiceEnabled = false
// 停止语音录制
stopVoiceRecording()
// 停止麦克风脉冲动画
stopMicPulseAnimation()
Toast.makeText(this, "停止控制模式", Toast.LENGTH_SHORT).show()
}
private fun startMicPulseAnimation() {
micPulseAnimation = ScaleAnimation(
1.0f, 1.3f,
1.0f, 1.3f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
).apply {
duration = 500
repeatCount = Animation.INFINITE
repeatMode = Animation.REVERSE
interpolator = LinearInterpolator()
}
binding.ivVoice.startAnimation(micPulseAnimation)
}
private fun stopMicPulseAnimation() {
micPulseAnimation?.let {
binding.ivVoice.clearAnimation()
micPulseAnimation = null
}
}
private fun startVoiceRecording() {
mediaRecorder = MediaRecorder().apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
val outputDir = getExternalFilesDir(null) ?: filesDir
val audioDir = File(outputDir, "audio")
if (!audioDir.exists()) {
audioDir.mkdirs()
}
val outputFile = File(audioDir, "voice_record_${System.currentTimeMillis()}.3gp")
setOutputFile(outputFile.absolutePath)
setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
try {
prepare()
start()
} catch (e: IOException) {
e.printStackTrace()
Toast.makeText(this@LiveVideoActivity, "录音启动失败", Toast.LENGTH_SHORT).show()
}
}
}
private fun stopVoiceRecording() {
mediaRecorder?.let {
try {
it.stop()
it.release()
} catch (e: Exception) {
e.printStackTrace()
}
mediaRecorder = null
}
}