package com.casic.endoscope.view import android.annotation.SuppressLint import android.graphics.PixelFormat import android.os.Bundle import android.os.Handler import android.os.Message import android.util.Log import android.view.KeyEvent import android.view.MotionEvent import android.view.SurfaceHolder import android.view.View import androidx.lifecycle.lifecycleScope import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime import com.casic.endoscope.utils.DataBaseManager import com.casic.endoscope.utils.ProjectConstant import com.casic.endoscope.utils.hk.MessageCodeHub import com.casic.endoscope.utils.hk.SDKGuider import com.casic.endoscope.widgets.AddCameraPointDialog import com.gyf.immersionbar.ImmersionBar import com.hikvision.netsdk.HCNetSDK import com.hikvision.netsdk.NET_DVR_JPEGPARA import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.WeakReferenceHandler import com.pengxh.kt.lite.widget.SteeringWheelView import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.Timer import java.util.TimerTask @SuppressLint("all") class MainActivity : KotlinBaseActivity<ActivityMainBinding>(), SurfaceHolder.Callback, Handler.Callback { private val kTag = "MainActivity" private val hkSDK by lazy { HCNetSDK.getInstance() } private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } private val selectedSpeed = 7 private val messageCode = 2024021901 private var clickTime = 0L private var previewHandle = -1 private var selectChannel = -1 private var returnUserId = -1 private var aChannelNum = 0 private var startAChannel = 0 private var dChannelNum = 0 private var startDChannel = 0 private var isPreviewSuccess = false //手指是否已经从方向控制盘抬起 private var isActionUp = true //焦距按钮是否已松开 private var isScaleButtonUp = true private var timer: Timer? = null private var timerTask: TimerTask? = null private var seconds = 0L private var dataBeans: MutableList<CameraPointBean> = ArrayList() private var selectedItems: MutableList<CameraPointBean> = ArrayList() private lateinit var weakReferenceHandler: WeakReferenceHandler private lateinit var dataAdapter: CameraPointAdapter override fun initViewBinding(): ActivityMainBinding { return ActivityMainBinding.inflate(layoutInflater) } override fun initOnCreate(savedInstanceState: Bundle?) { weakReferenceHandler = WeakReferenceHandler(this) dataBeans = DataBaseManager.get.loadAllCameraPoint() //显示数据 weakReferenceHandler.sendEmptyMessage(messageCode) } override fun handleMessage(msg: Message): Boolean { if (msg.what == messageCode) { //绑定数据 dataAdapter = CameraPointAdapter(this, dataBeans) binding.recyclerView.adapter = dataAdapter dataAdapter.setOnItemCheckedListener(object : CameraPointAdapter.OnItemCheckedListener { override fun onItemChecked(position: Int, items: ArrayList<CameraPointBean>) { selectedItems = items } }) } return true } override fun initEvent() { binding.openAlbumButton.setOnClickListener { if (isPreviewSuccess) { "设备预览画面中,无法切换".show(this) return@setOnClickListener } navigatePageTo<AlbumActivity>() } //单张拍照 binding.imageButton.setOnClickListener { if (isPreviewSuccess) { val strJpeg = NET_DVR_JPEGPARA() strJpeg.wPicQuality = 1 strJpeg.wPicSize = 2 val imagePath = "/${createImageFileDir()}/${timeFormat.format(Date())}.png" hkSDK.NET_DVR_CaptureJPEGPicture( returnUserId, selectChannel, strJpeg, imagePath ) if (MessageCodeHub.getErrorCode() == 0) { "画面抓取成功".show(this@MainActivity) } } else { "摄像头预览未打开,无法拍照".show(this) } } //视频录制 binding.videoButton.setOnClickListener { if (isPreviewSuccess) { val videoPath = "/${createVideoFileDir()}/${timeFormat.format(Date())}.mp4" hkSDK.NET_DVR_SaveRealData(returnUserId, videoPath) binding.videoStateView.visibility = View.VISIBLE } else { "摄像头预览未打开,无法录制视频".show(this) } } binding.videoButton.setOnLongClickListener { //停止视频抓取 hkSDK.NET_DVR_StopSaveRealData(returnUserId) binding.videoStateView.visibility = View.INVISIBLE "视频录制成功".show(this@MainActivity) true } //连续拍照 binding.multipleImageButton.setOnClickListener { if (dataBeans.isEmpty()) { "请先设置连续拍照步骤".show(this) return@setOnClickListener } if (isPreviewSuccess) { } else { "摄像头预览未打开,无法拍照".show(this) } } binding.addButton.setOnClickListener { val step = if (dataBeans.isEmpty()) { 0 } else { dataBeans.last().step } AddCameraPointDialog.Builder() .setContext(this) .setLastStep(step) .setNegativeButton("取消") .setPositiveButton("添加") .setOnDialogButtonClickListener(object : AddCameraPointDialog.OnDialogButtonClickListener { override fun onConfirmClick(step: Int, hAngle: Int, vAngle: Int) { DataBaseManager.get.cacheCameraPoint(step, hAngle, vAngle) dataBeans = DataBaseManager.get.loadAllCameraPoint() dataAdapter.setRefreshData(dataBeans) } override fun onCancelClick() { } }).build().show() } binding.deleteButton.setOnClickListener { if (selectedItems.isEmpty()) { "请先选择要删除的步骤".show(this) return@setOnClickListener } DataBaseManager.get.deleteCameraPoints(selectedItems) dataBeans = DataBaseManager.get.loadAllCameraPoint() dataAdapter.setRefreshData(dataBeans) selectedItems.clear() } binding.steeringWheelView.setOnWheelTouchListener(object : SteeringWheelView.OnWheelTouchListener { override fun onCenterClicked() { if (!isPreviewSuccess) { val deviceItem = SDKGuider.sdkGuider.devManageGuider.DeviceItem() deviceItem.szDevName = "" deviceItem.devNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo( ProjectConstant.HK_NET_IP, ProjectConstant.HK_NET_PORT, ProjectConstant.HK_NET_USERNAME, ProjectConstant.HK_NET_PASSWORD ) if (deviceItem.szDevName.isEmpty()) { deviceItem.szDevName = deviceItem.devNetInfo.szIp } val loginV40Jna = SDKGuider.sdkGuider.devManageGuider.login_v40_jna( deviceItem.szDevName, deviceItem.devNetInfo ) if (loginV40Jna) { //配置设备通道 try { val deviceInfo = SDKGuider.sdkGuider.devManageGuider.devList[0] returnUserId = deviceInfo.szUserId aChannelNum = deviceInfo.deviceInfoV40_jna.struDeviceV30.byChanNum.toInt() startAChannel = deviceInfo.deviceInfoV40_jna.struDeviceV30.byStartChan.toInt() dChannelNum = deviceInfo.deviceInfoV40_jna.struDeviceV30.byIPChanNum + deviceInfo.deviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256 startDChannel = deviceInfo.deviceInfoV40_jna.struDeviceV30.byStartChan.toInt() var iAnalogStartChan = startAChannel var iDigitalStartChan = startDChannel val channelList = ArrayList<String>() for (i in 0 until aChannelNum) { channelList.add("ACamera_$iAnalogStartChan") iAnalogStartChan++ } for (i in 0 until dChannelNum) { channelList.add("DCamera_$iDigitalStartChan") iDigitalStartChan++ } selectChannel = Integer.valueOf(channelList[0].getChannel()) val streamList = ArrayList<String>() streamList.add("main_stream") streamList.add("sub_stream") streamList.add("third_stream") //开始预览 if (previewHandle != -1) { SDKGuider.sdkGuider.devPreviewGuider.RealPlay_Stop_jni(previewHandle) } val strutPlayInfo = NET_DVR_PREVIEWINFO() strutPlayInfo.lChannel = selectChannel strutPlayInfo.dwStreamType = 1 strutPlayInfo.bBlocked = 1 strutPlayInfo.hHwnd = binding.surfaceView.holder previewHandle = SDKGuider.sdkGuider.devPreviewGuider.RealPlay_V40_jni( returnUserId, strutPlayInfo, null ) if (previewHandle < 0) { Log.d(kTag, "initEvent: Err:${MessageCodeHub.getErrorCode()}") return } isPreviewSuccess = true "预览开启成功".show(this@MainActivity) //开始计时 timer = Timer() timerTask = object : TimerTask() { override fun run() { seconds++ lifecycleScope.launch(Dispatchers.Main) { binding.runningTimeView.text = seconds.toTime() } } } timer?.schedule(timerTask, 0, 1000) } catch (e: IndexOutOfBoundsException) { e.printStackTrace() "设备未正常连接,无法开启预览".show(this@MainActivity) } } } else { if (!SDKGuider.sdkGuider.devPreviewGuider.RealPlay_Stop_jni(previewHandle)) { return } previewHandle = -1 isPreviewSuccess = false "预览关闭成功".show(this@MainActivity) //停止计时 timerTask?.cancel() timer?.cancel() } } override fun onLeftTurn() { if (isPreviewSuccess && isActionUp) { hkSDK.NET_DVR_PTZControlWithSpeed( previewHandle, PTZCommand.PAN_LEFT, 0, selectedSpeed ) isActionUp = false } } override fun onTopTurn() { if (isPreviewSuccess && isActionUp) { hkSDK.NET_DVR_PTZControlWithSpeed( previewHandle, PTZCommand.TILT_UP, 0, selectedSpeed ) isActionUp = false } } override fun onRightTurn() { if (isPreviewSuccess && isActionUp) { hkSDK.NET_DVR_PTZControlWithSpeed( previewHandle, PTZCommand.PAN_RIGHT, 0, selectedSpeed ) isActionUp = false } } override fun onBottomTurn() { if (isPreviewSuccess && isActionUp) { hkSDK.NET_DVR_PTZControlWithSpeed( previewHandle, PTZCommand.TILT_DOWN, 0, selectedSpeed ) isActionUp = false } } override fun onActionTurnUp(dir: SteeringWheelView.Direction) { when (dir) { SteeringWheelView.Direction.LEFT -> { hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.PAN_LEFT, 1) isActionUp = true } SteeringWheelView.Direction.TOP -> { hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.TILT_UP, 1) isActionUp = true } SteeringWheelView.Direction.RIGHT -> { hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.PAN_RIGHT, 1) isActionUp = true } SteeringWheelView.Direction.BOTTOM -> { hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.TILT_DOWN, 1) isActionUp = true } } } }) binding.upScaleButton.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { if (isPreviewSuccess && isScaleButtonUp) { hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.ZOOM_IN, 0) isScaleButtonUp = false } } MotionEvent.ACTION_UP -> { isScaleButtonUp = true hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.ZOOM_IN, 1) } } false } binding.downScaleButton.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { if (isPreviewSuccess && isScaleButtonUp) { hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.ZOOM_OUT, 0) isScaleButtonUp = false } } MotionEvent.ACTION_UP -> { isScaleButtonUp = true hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.ZOOM_OUT, 1) } } false } } override fun observeRequestState() { } override fun surfaceCreated(holder: SurfaceHolder) { binding.surfaceView.holder.setFormat(PixelFormat.TRANSLUCENT) if (-1 == previewHandle) { return } val surface = holder.surface if (surface.isValid) { if (-1 == SDKGuider.sdkGuider.devPreviewGuider.RealPlaySurfaceChanged_jni( previewHandle, 0, holder ) ) { Log.d(kTag, "surfaceCreated: ${MessageCodeHub.getErrorCode()}") } } } override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { } override fun surfaceDestroyed(holder: SurfaceHolder) { if (-1 == previewHandle) { return } if (holder.surface.isValid) { if (-1 == SDKGuider.sdkGuider.devPreviewGuider.RealPlaySurfaceChanged_jni( previewHandle, 0, null ) ) { Log.d(kTag, "surfaceDestroyed: ${MessageCodeHub.getErrorCode()}") } } } override fun setupTopBarLayout() { ImmersionBar.with(this).statusBarDarkFont(false).init() //根据不同设备状态栏高度设置statusBarView高度 val statusBarHeight = getStatusBarHeight() binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { "再按一次退出应用".show(this) clickTime = System.currentTimeMillis() return true } else { super.onKeyDown(keyCode, event) } } return super.onKeyDown(keyCode, event) } }