云台控制

This commit is contained in:
2026-07-01 17:59:23 +08:00
parent 02fc928f20
commit 6942abca3b
4 changed files with 252 additions and 1 deletions

View File

@@ -548,6 +548,8 @@ class HomeMenuFragment : Fragment() {
val intent = Intent(requireContext(), LiveVideoActivity::class.java)
intent.putExtra("device_id", device.deviceId)
intent.putExtra("device_name", device.name)
intent.putExtra("deviceNo", device.deviceNo)
intent.putExtra("light", device.light)
startActivity(intent)
} else {
showDefenseDialog(

View File

@@ -5,6 +5,8 @@ import android.content.res.Configuration
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@@ -22,6 +24,9 @@ import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
import com.shuyu.gsyvideoplayer.utils.OrientationUtils
import kotlinx.coroutines.launch
import androidx.lifecycle.lifecycleScope
import android.os.Handler
import android.os.Looper
import com.ckkj.defense_device.view.MyGSYVideoPlayerLive
class LiveVideoActivity : BaseActivity() {
private lateinit var binding: LiveVideoActivityBinding
@@ -30,6 +35,7 @@ class LiveVideoActivity : BaseActivity() {
private var isLightOn = false
private var isConsoleVisible = false
private var deviceId: String? = null
private var deviceNo: String? = null
private var alarmList: MutableList<DeviceAlarmBean> = mutableListOf()
private var alarmAdapter: AlarmLogHorizontalAdapter? = null
private var currentPage = 1
@@ -39,6 +45,8 @@ class LiveVideoActivity : BaseActivity() {
private var isLoading = false
private var orientationUtils: OrientationUtils? = null
private val ptzHandler = Handler(Looper.getMainLooper())
private var currentPtzDirection: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -54,6 +62,8 @@ class LiveVideoActivity : BaseActivity() {
deviceId = intent.getStringExtra("device_id")
val deviceName = intent.getStringExtra("device_name")
deviceNo = intent.getStringExtra("deviceNo")
val light = intent.getStringExtra("light")
if (!deviceName.isNullOrEmpty()) {
binding.tvTitle.text = deviceName
}
@@ -112,6 +122,21 @@ class LiveVideoActivity : BaseActivity() {
hidePlayerControls()
binding.exoPlayContextId.startPlayLogic()
binding.exoPlayContextId.fullscreenButton.setOnClickListener {
binding.exoPlayContextId.onPtzControlListener =
object : MyGSYVideoPlayerLive.OnPtzControlListener {
override fun onStartPtz(direction: String) {
val no = deviceNo ?: return
startPtz(deviceNo = no, direction = direction)
}
override fun onStopPtz() {
stopCurrentPtz()
}
override fun onShoot() {
deviceNo?.let { shoot(it) }
}
}
orientationUtils?.resolveByClick()
binding.exoPlayContextId.startWindowFullscreen(this, true, true)
}
@@ -237,6 +262,114 @@ class LiveVideoActivity : BaseActivity() {
binding.ivVoice.setImageResource(R.mipmap.voice)
}
}
binding.ivUp.setOnTouchListener { v, event ->
handlePtzTouch(
view = v,
event = event,
direction = "up",
action = { deviceNo }
)
}
binding.ivDown.setOnTouchListener { v, event ->
handlePtzTouch(
view = v,
event = event,
direction = "down",
action = { deviceNo }
)
}
binding.ivLeft.setOnTouchListener { v, event ->
handlePtzTouch(
view = v,
event = event,
direction = "left",
action = { deviceNo }
)
}
binding.ivRight.setOnTouchListener { v, event ->
handlePtzTouch(
view = v,
event = event,
direction = "right",
action = { deviceNo }
)
}
}
private fun handlePtzTouch(
view: View,
event: MotionEvent,
direction: String,
action: () -> String?
): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
view.isPressed = true
val deviceNo = action()
if (!deviceNo.isNullOrEmpty()) {
startPtz(deviceNo = deviceNo, direction = direction)
}
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
view.isPressed = false
stopCurrentPtz()
}
}
return true
}
private fun startPtz(deviceNo: String, direction: String) {
stopCurrentPtz()
currentPtzDirection = direction
lifecycleScope.launch {
try {
val response = when (direction) {
"up" -> RetrofitNetwork.getNetworkService().ptzUp(deviceNo)
"down" -> RetrofitNetwork.getNetworkService().ptzDown(deviceNo)
"left" -> RetrofitNetwork.getNetworkService().ptzLeft(deviceNo)
"right" -> RetrofitNetwork.getNetworkService().ptzRight(deviceNo)
else -> null
}
Log.d("LV", "PTZ $direction start response: ${response?.code}")
} catch (e: Exception) {
Log.e("LV", "PTZ $direction start failed", e)
}
}
}
private fun shoot(deviceNo: String) {
Log.d("LV", "btnCapture click, deviceNo=$deviceNo, duration=0")
lifecycleScope.launch {
try {
val response = RetrofitNetwork.getNetworkService().ptzShoot(
deviceNo = deviceNo,
duration = "0"
)
Log.d("LV", "PTZ shoot response: code=${response.code}, msg=${response.msg}")
} catch (e: Exception) {
Log.e("LV", "PTZ shoot failed", e)
}
}
}
private fun stopCurrentPtz() {
val direction = currentPtzDirection ?: return
currentPtzDirection = null
lifecycleScope.launch {
try {
val response = RetrofitNetwork.getNetworkService().ptzStop(deviceNo ?: return@launch)
Log.d("LV", "PTZ $direction stop response: ${response.code}")
} catch (e: Exception) {
Log.e("LV", "PTZ $direction stop failed", e)
}
}
}
private fun fetchAlarmList(page: Int = 1) {
@@ -284,6 +417,7 @@ class LiveVideoActivity : BaseActivity() {
override fun onDestroy() {
super.onDestroy()
ptzHandler.removeCallbacksAndMessages(null)
orientationUtils?.releaseListener()
binding.exoPlayContextId.release()
}

View File

@@ -271,5 +271,62 @@ interface ApiService {
@POST("/app/joinTheFamily")
suspend fun joinTheFamily(@Body request: JoinTheFamilyBean): GetCodeBean<Any>
/**
* PTZ向上控制
*/
@POST("/app/ptz/{deviceNo}/up")
suspend fun ptzUp(
@retrofit2.http.Path("deviceNo") deviceNo: String,
@Query("speed") speed: String = "5",
@Query("duration") duration: String = "0"
): GetCodeBean<Any>
/**
* PTZ向下控制
*/
@POST("/app/ptz/{deviceNo}/down")
suspend fun ptzDown(
@retrofit2.http.Path("deviceNo") deviceNo: String,
@Query("speed") speed: String = "5",
@Query("duration") duration: String = "0"
): GetCodeBean<Any>
/**
* PTZ向左控制
*/
@POST("/app/ptz/{deviceNo}/left")
suspend fun ptzLeft(
@retrofit2.http.Path("deviceNo") deviceNo: String,
@Query("speed") speed: String = "5",
@Query("duration") duration: String = "0"
): GetCodeBean<Any>
/**
* PTZ向右控制
*/
@POST("/app/ptz/{deviceNo}/right")
suspend fun ptzRight(
@retrofit2.http.Path("deviceNo") deviceNo: String,
@Query("speed") speed: String = "5",
@Query("duration") duration: String = "0"
): GetCodeBean<Any>
/**
* PTZ停止控制
*/
@POST("/app/ptz/{deviceNo}/stop")
suspend fun ptzStop(
@retrofit2.http.Path("deviceNo") deviceNo: String,
): GetCodeBean<Any>
/**
* PTZ控制水枪喷水
*/
@POST("/app/ptz/{deviceNo}/shoot")
suspend fun ptzShoot(
@retrofit2.http.Path("deviceNo") deviceNo: String,
@Query("duration") duration: String,
): GetCodeBean<Any>
}

View File

@@ -1,8 +1,10 @@
package com.ckkj.defense_device.view
import android.util.Log
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import com.ckkj.defense_device.R
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
@@ -12,6 +14,18 @@ class MyGSYVideoPlayerLive @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : StandardGSYVideoPlayer(context, attrs) {
companion object {
private const val TAG = "MyGSYVideoPlayerLive"
}
interface OnPtzControlListener {
fun onStartPtz(direction: String)
fun onStopPtz()
fun onShoot()
}
var onPtzControlListener: OnPtzControlListener? = null
override fun init(context: Context) {
super.init(context)
startButton.visibility = View.GONE
@@ -76,10 +90,54 @@ class MyGSYVideoPlayerLive @JvmOverloads constructor(
overlay.findViewById<View>(R.id.btnCapture)
?.setOnClickListener {
Log.d("MyGSYVideoPlayerLive", "btnCapture clicked, onShoot invoked")
onPtzControlListener?.onShoot()
}
player.initPtzControls(overlay)
return player
}
private fun initPtzControls(overlay: View) {
val ptzListener = onPtzControlListener
overlay.findViewById<View>(R.id.ivUp)?.setOnTouchListener { v, event ->
handlePtzTouch(v, event, "up", ptzListener)
}
overlay.findViewById<View>(R.id.ivDown)?.setOnTouchListener { v, event ->
handlePtzTouch(v, event, "down", ptzListener)
}
overlay.findViewById<View>(R.id.ivLeft)?.setOnTouchListener { v, event ->
handlePtzTouch(v, event, "left", ptzListener)
}
overlay.findViewById<View>(R.id.ivRight)?.setOnTouchListener { v, event ->
handlePtzTouch(v, event, "right", ptzListener)
}
}
private fun handlePtzTouch(
view: View,
event: MotionEvent,
direction: String,
listener: OnPtzControlListener?
): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
Log.d(TAG, "全屏PTZ长按开始 direction=$direction")
view.isPressed = true
listener?.onStartPtz(direction)
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
Log.d(TAG, "全屏PTZ长按结束 direction=$direction")
view.isPressed = false
listener?.onStopPtz()
}
}
return true
}
}