diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
index 7582a1f..eb6a592 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
@@ -17,13 +17,19 @@
object RetrofitServiceManager {
+ private val gson by lazy { Gson() }
+
private val api by lazy {
val httpConfig = SaveKeyValues.getValue(
LocaleConstant.DEFAULT_SERVER_CONFIG, LocaleConstant.SERVER_BASE_URL
) as String
RetrofitFactory.createRetrofit(httpConfig)
}
- private val gson by lazy { Gson() }
+
+ private val regionApi by lazy {
+ val httpConfig = "http://192.168.10.104:5000"
+ RetrofitFactory.createRetrofit(httpConfig)
+ }
/**
* 验证PublicKey
@@ -171,4 +177,16 @@
)
return api.enter(AuthenticationHelper.token!!, requestBody)
}
+
+ suspend fun postRegion(code: String, color: String, position: String): String {
+ val param = JsonObject()
+ param.addProperty("code", code)
+ param.addProperty("color", color)
+ param.addProperty("position", position)
+
+ val requestBody = param.toString().toRequestBody(
+ "application/json;charset=UTF-8".toMediaType()
+ )
+ return regionApi.postRegion(requestBody)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
index 7582a1f..eb6a592 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
@@ -17,13 +17,19 @@
object RetrofitServiceManager {
+ private val gson by lazy { Gson() }
+
private val api by lazy {
val httpConfig = SaveKeyValues.getValue(
LocaleConstant.DEFAULT_SERVER_CONFIG, LocaleConstant.SERVER_BASE_URL
) as String
RetrofitFactory.createRetrofit(httpConfig)
}
- private val gson by lazy { Gson() }
+
+ private val regionApi by lazy {
+ val httpConfig = "http://192.168.10.104:5000"
+ RetrofitFactory.createRetrofit(httpConfig)
+ }
/**
* 验证PublicKey
@@ -171,4 +177,16 @@
)
return api.enter(AuthenticationHelper.token!!, requestBody)
}
+
+ suspend fun postRegion(code: String, color: String, position: String): String {
+ val param = JsonObject()
+ param.addProperty("code", code)
+ param.addProperty("color", color)
+ param.addProperty("position", position)
+
+ val requestBody = param.toString().toRequestBody(
+ "application/json;charset=UTF-8".toMediaType()
+ )
+ return regionApi.postRegion(requestBody)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
index f40c29f..9fc0a85 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
@@ -13,6 +13,7 @@
import android.util.Log
import android.view.SurfaceHolder
import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.addAll
import com.casic.br.operationsite.extensions.getChannel
import com.casic.br.operationsite.extensions.initLayoutImmersionBar
import com.casic.br.operationsite.model.DeviceConfigModel
@@ -26,6 +27,7 @@
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertColor
import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.widget.SteeringWheelController
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
@@ -208,6 +210,10 @@
}
}
})
+
+ videoRegionLayout.setOnClickListener {
+ navigatePageTo(addAll(hostModel.host, hostModel.port.toString()))
+ }
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
index 7582a1f..eb6a592 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
@@ -17,13 +17,19 @@
object RetrofitServiceManager {
+ private val gson by lazy { Gson() }
+
private val api by lazy {
val httpConfig = SaveKeyValues.getValue(
LocaleConstant.DEFAULT_SERVER_CONFIG, LocaleConstant.SERVER_BASE_URL
) as String
RetrofitFactory.createRetrofit(httpConfig)
}
- private val gson by lazy { Gson() }
+
+ private val regionApi by lazy {
+ val httpConfig = "http://192.168.10.104:5000"
+ RetrofitFactory.createRetrofit(httpConfig)
+ }
/**
* 验证PublicKey
@@ -171,4 +177,16 @@
)
return api.enter(AuthenticationHelper.token!!, requestBody)
}
+
+ suspend fun postRegion(code: String, color: String, position: String): String {
+ val param = JsonObject()
+ param.addProperty("code", code)
+ param.addProperty("color", color)
+ param.addProperty("position", position)
+
+ val requestBody = param.toString().toRequestBody(
+ "application/json;charset=UTF-8".toMediaType()
+ )
+ return regionApi.postRegion(requestBody)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
index f40c29f..9fc0a85 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
@@ -13,6 +13,7 @@
import android.util.Log
import android.view.SurfaceHolder
import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.addAll
import com.casic.br.operationsite.extensions.getChannel
import com.casic.br.operationsite.extensions.initLayoutImmersionBar
import com.casic.br.operationsite.model.DeviceConfigModel
@@ -26,6 +27,7 @@
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertColor
import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.widget.SteeringWheelController
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
@@ -208,6 +210,10 @@
}
}
})
+
+ videoRegionLayout.setOnClickListener {
+ navigatePageTo(addAll(hostModel.host, hostModel.port.toString()))
+ }
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
diff --git a/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
new file mode 100644
index 0000000..33f6970
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
@@ -0,0 +1,203 @@
+package com.casic.br.operationsite.view
+
+import android.graphics.PixelFormat
+import android.util.Log
+import android.view.SurfaceHolder
+import androidx.lifecycle.ViewModelProvider
+import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.getChannel
+import com.casic.br.operationsite.extensions.initLayoutImmersionBar
+import com.casic.br.operationsite.extensions.reformatFloatArray
+import com.casic.br.operationsite.utils.LocaleConstant
+import com.casic.br.operationsite.utils.hk.MessageCodeHub
+import com.casic.br.operationsite.utils.hk.SDKGuider
+import com.casic.br.operationsite.vm.RegionViewModel
+import com.gyf.immersionbar.ImmersionBar
+import com.hikvision.netsdk.NET_DVR_PREVIEWINFO
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.utils.Constant
+import kotlinx.android.synthetic.main.activity_video_region.*
+import kotlinx.android.synthetic.main.include_base_title.leftBackView
+import kotlinx.android.synthetic.main.include_base_title.titleView
+import kotlinx.android.synthetic.main.include_option_title.*
+
+class VideoRegionActivity : KotlinBaseActivity(), SurfaceHolder.Callback {
+
+ private val kTag = "VideoRegionActivity"
+ private val context = this@VideoRegionActivity
+ 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 lateinit var params: ArrayList
+ private lateinit var regionViewModel: RegionViewModel
+
+ override fun initData() {
+ params = intent.getStringArrayListExtra(Constant.INTENT_PARAM)!!
+
+ regionViewModel = ViewModelProvider(this)[RegionViewModel::class.java]
+ regionViewModel.postResult.observe(this) {
+ if (it.code == 200) {
+ "区域配置成功".show(this)
+ finish()
+ }
+ }
+ }
+
+ override fun initEvent() {
+ openCameraButton.setOnClickListener {
+ openHikVisionCamera(params[0], params[1])
+ }
+
+ closeCameraButton.setOnClickListener {
+ if (!SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)) {
+ return@setOnClickListener
+ }
+ previewHandle = -1
+ isPreviewSuccess = false
+
+ regionView.clearRoutePath()
+ }
+
+ configButton.setOnClickListener {
+ val region = regionView.getConfirmedPoints()
+ val data = region.reformatFloatArray()
+
+ //发送数据的时候需要断开视频
+ regionViewModel.postRegion("11,12", "#FF0000", data)
+ }
+ }
+
+ override fun initLayoutView(): Int = R.layout.activity_video_region
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+ ImmersionBar.with(this).statusBarDarkFont(false)
+ .statusBarColor(R.color.mainThemeColor).init()
+ initLayoutImmersionBar(rootView)
+
+ leftBackView.setOnClickListener { finish() }
+ titleView.text = "区域规划"
+ rightOptionView.text = "重画"
+ rightOptionView.setOnClickListener {
+ regionView.clearRoutePath()
+ }
+ }
+
+ private fun openHikVisionCamera(host: String, port: String) {
+ val deviceItem = SDKGuider.g_sdkGuider.m_comDMGuider.DeviceItem()
+ deviceItem.m_szDevName = ""
+ deviceItem.m_struNetInfo = SDKGuider.g_sdkGuider.m_comDMGuider.DevNetInfo(
+ host, port, LocaleConstant.HK_NET_USERNAME, LocaleConstant.HK_NET_PASSWORD
+ )
+ if (deviceItem.m_szDevName.isEmpty()) {
+ deviceItem.m_szDevName = deviceItem.m_struNetInfo.m_szIp
+ }
+
+ val loginV40Jna = SDKGuider.g_sdkGuider.m_comDMGuider.login_v40_jna(
+ deviceItem.m_szDevName, deviceItem.m_struNetInfo
+ )
+ if (loginV40Jna) {
+ //配置设备通道
+ try {
+ val deviceInfo = SDKGuider.g_sdkGuider.m_comDMGuider.devList[0]
+ returnUserID = deviceInfo.m_lUserID
+
+ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt()
+ startAChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum +
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256
+ startDChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ var iAnalogStartChan = startAChannel
+ var iDigitalStartChan = startDChannel
+
+ val channelList = ArrayList()
+
+ 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()
+ streamList.add("main_stream")
+ streamList.add("sub_stream")
+ streamList.add("third_stream")
+
+ //开始预览
+ if (previewHandle != -1) {
+ SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)
+ }
+ val strutPlayInfo = NET_DVR_PREVIEWINFO()
+ strutPlayInfo.lChannel = selectChannel
+ strutPlayInfo.dwStreamType = 1
+ strutPlayInfo.bBlocked = 1
+ strutPlayInfo.hHwnd = videoSurfaceView.holder
+ previewHandle = SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_V40_jni(
+ returnUserID, strutPlayInfo, null
+ )
+ if (previewHandle < 0) {
+ Log.d(
+ kTag,
+ "configDevice: NET_DVR_RealPlay_V40 fail, Err:${MessageCodeHub.getErrorCode()}"
+ )
+ return
+ }
+ isPreviewSuccess = true
+ } catch (e: IndexOutOfBoundsException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ videoSurfaceView.holder.setFormat(PixelFormat.TRANSLUCENT)
+ if (-1 == previewHandle) {
+ return
+ }
+ val surface = holder.surface
+ if (surface.isValid) {
+ if (-1 == SDKGuider.g_sdkGuider.m_comPreviewGuider.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.g_sdkGuider.m_comPreviewGuider.RealPlaySurfaceChanged_jni(
+ previewHandle, 0, null
+ )
+ ) {
+ Log.d(kTag, "surfaceCreated: ${MessageCodeHub.getErrorCode()}")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
index 7582a1f..eb6a592 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
@@ -17,13 +17,19 @@
object RetrofitServiceManager {
+ private val gson by lazy { Gson() }
+
private val api by lazy {
val httpConfig = SaveKeyValues.getValue(
LocaleConstant.DEFAULT_SERVER_CONFIG, LocaleConstant.SERVER_BASE_URL
) as String
RetrofitFactory.createRetrofit(httpConfig)
}
- private val gson by lazy { Gson() }
+
+ private val regionApi by lazy {
+ val httpConfig = "http://192.168.10.104:5000"
+ RetrofitFactory.createRetrofit(httpConfig)
+ }
/**
* 验证PublicKey
@@ -171,4 +177,16 @@
)
return api.enter(AuthenticationHelper.token!!, requestBody)
}
+
+ suspend fun postRegion(code: String, color: String, position: String): String {
+ val param = JsonObject()
+ param.addProperty("code", code)
+ param.addProperty("color", color)
+ param.addProperty("position", position)
+
+ val requestBody = param.toString().toRequestBody(
+ "application/json;charset=UTF-8".toMediaType()
+ )
+ return regionApi.postRegion(requestBody)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
index f40c29f..9fc0a85 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
@@ -13,6 +13,7 @@
import android.util.Log
import android.view.SurfaceHolder
import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.addAll
import com.casic.br.operationsite.extensions.getChannel
import com.casic.br.operationsite.extensions.initLayoutImmersionBar
import com.casic.br.operationsite.model.DeviceConfigModel
@@ -26,6 +27,7 @@
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertColor
import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.widget.SteeringWheelController
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
@@ -208,6 +210,10 @@
}
}
})
+
+ videoRegionLayout.setOnClickListener {
+ navigatePageTo(addAll(hostModel.host, hostModel.port.toString()))
+ }
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
diff --git a/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
new file mode 100644
index 0000000..33f6970
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
@@ -0,0 +1,203 @@
+package com.casic.br.operationsite.view
+
+import android.graphics.PixelFormat
+import android.util.Log
+import android.view.SurfaceHolder
+import androidx.lifecycle.ViewModelProvider
+import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.getChannel
+import com.casic.br.operationsite.extensions.initLayoutImmersionBar
+import com.casic.br.operationsite.extensions.reformatFloatArray
+import com.casic.br.operationsite.utils.LocaleConstant
+import com.casic.br.operationsite.utils.hk.MessageCodeHub
+import com.casic.br.operationsite.utils.hk.SDKGuider
+import com.casic.br.operationsite.vm.RegionViewModel
+import com.gyf.immersionbar.ImmersionBar
+import com.hikvision.netsdk.NET_DVR_PREVIEWINFO
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.utils.Constant
+import kotlinx.android.synthetic.main.activity_video_region.*
+import kotlinx.android.synthetic.main.include_base_title.leftBackView
+import kotlinx.android.synthetic.main.include_base_title.titleView
+import kotlinx.android.synthetic.main.include_option_title.*
+
+class VideoRegionActivity : KotlinBaseActivity(), SurfaceHolder.Callback {
+
+ private val kTag = "VideoRegionActivity"
+ private val context = this@VideoRegionActivity
+ 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 lateinit var params: ArrayList
+ private lateinit var regionViewModel: RegionViewModel
+
+ override fun initData() {
+ params = intent.getStringArrayListExtra(Constant.INTENT_PARAM)!!
+
+ regionViewModel = ViewModelProvider(this)[RegionViewModel::class.java]
+ regionViewModel.postResult.observe(this) {
+ if (it.code == 200) {
+ "区域配置成功".show(this)
+ finish()
+ }
+ }
+ }
+
+ override fun initEvent() {
+ openCameraButton.setOnClickListener {
+ openHikVisionCamera(params[0], params[1])
+ }
+
+ closeCameraButton.setOnClickListener {
+ if (!SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)) {
+ return@setOnClickListener
+ }
+ previewHandle = -1
+ isPreviewSuccess = false
+
+ regionView.clearRoutePath()
+ }
+
+ configButton.setOnClickListener {
+ val region = regionView.getConfirmedPoints()
+ val data = region.reformatFloatArray()
+
+ //发送数据的时候需要断开视频
+ regionViewModel.postRegion("11,12", "#FF0000", data)
+ }
+ }
+
+ override fun initLayoutView(): Int = R.layout.activity_video_region
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+ ImmersionBar.with(this).statusBarDarkFont(false)
+ .statusBarColor(R.color.mainThemeColor).init()
+ initLayoutImmersionBar(rootView)
+
+ leftBackView.setOnClickListener { finish() }
+ titleView.text = "区域规划"
+ rightOptionView.text = "重画"
+ rightOptionView.setOnClickListener {
+ regionView.clearRoutePath()
+ }
+ }
+
+ private fun openHikVisionCamera(host: String, port: String) {
+ val deviceItem = SDKGuider.g_sdkGuider.m_comDMGuider.DeviceItem()
+ deviceItem.m_szDevName = ""
+ deviceItem.m_struNetInfo = SDKGuider.g_sdkGuider.m_comDMGuider.DevNetInfo(
+ host, port, LocaleConstant.HK_NET_USERNAME, LocaleConstant.HK_NET_PASSWORD
+ )
+ if (deviceItem.m_szDevName.isEmpty()) {
+ deviceItem.m_szDevName = deviceItem.m_struNetInfo.m_szIp
+ }
+
+ val loginV40Jna = SDKGuider.g_sdkGuider.m_comDMGuider.login_v40_jna(
+ deviceItem.m_szDevName, deviceItem.m_struNetInfo
+ )
+ if (loginV40Jna) {
+ //配置设备通道
+ try {
+ val deviceInfo = SDKGuider.g_sdkGuider.m_comDMGuider.devList[0]
+ returnUserID = deviceInfo.m_lUserID
+
+ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt()
+ startAChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum +
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256
+ startDChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ var iAnalogStartChan = startAChannel
+ var iDigitalStartChan = startDChannel
+
+ val channelList = ArrayList()
+
+ 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()
+ streamList.add("main_stream")
+ streamList.add("sub_stream")
+ streamList.add("third_stream")
+
+ //开始预览
+ if (previewHandle != -1) {
+ SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)
+ }
+ val strutPlayInfo = NET_DVR_PREVIEWINFO()
+ strutPlayInfo.lChannel = selectChannel
+ strutPlayInfo.dwStreamType = 1
+ strutPlayInfo.bBlocked = 1
+ strutPlayInfo.hHwnd = videoSurfaceView.holder
+ previewHandle = SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_V40_jni(
+ returnUserID, strutPlayInfo, null
+ )
+ if (previewHandle < 0) {
+ Log.d(
+ kTag,
+ "configDevice: NET_DVR_RealPlay_V40 fail, Err:${MessageCodeHub.getErrorCode()}"
+ )
+ return
+ }
+ isPreviewSuccess = true
+ } catch (e: IndexOutOfBoundsException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ videoSurfaceView.holder.setFormat(PixelFormat.TRANSLUCENT)
+ if (-1 == previewHandle) {
+ return
+ }
+ val surface = holder.surface
+ if (surface.isValid) {
+ if (-1 == SDKGuider.g_sdkGuider.m_comPreviewGuider.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.g_sdkGuider.m_comPreviewGuider.RealPlaySurfaceChanged_jni(
+ previewHandle, 0, null
+ )
+ ) {
+ Log.d(kTag, "surfaceCreated: ${MessageCodeHub.getErrorCode()}")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
index 5dff823..513db5e 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
@@ -151,14 +151,13 @@
fenceTextView.setOnClickListener {
BottomActionSheet.Builder()
.setContext(this)
- .setActionItemTitle(arrayListOf("区域规划", "监控角度", "云台角度"))
+ .setActionItemTitle(arrayListOf("监控区域", "云台角度"))
.setItemTextColor(R.color.mainThemeColor.convertColor(this))
.setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener {
override fun onActionItemClick(position: Int) {
when (position) {
- 0 -> ""
- 1 -> navigatePageTo()
- 2 -> navigatePageTo()
+ 0 -> navigatePageTo()
+ 1 -> navigatePageTo()
}
}
}).build().show()
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
index 7582a1f..eb6a592 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
@@ -17,13 +17,19 @@
object RetrofitServiceManager {
+ private val gson by lazy { Gson() }
+
private val api by lazy {
val httpConfig = SaveKeyValues.getValue(
LocaleConstant.DEFAULT_SERVER_CONFIG, LocaleConstant.SERVER_BASE_URL
) as String
RetrofitFactory.createRetrofit(httpConfig)
}
- private val gson by lazy { Gson() }
+
+ private val regionApi by lazy {
+ val httpConfig = "http://192.168.10.104:5000"
+ RetrofitFactory.createRetrofit(httpConfig)
+ }
/**
* 验证PublicKey
@@ -171,4 +177,16 @@
)
return api.enter(AuthenticationHelper.token!!, requestBody)
}
+
+ suspend fun postRegion(code: String, color: String, position: String): String {
+ val param = JsonObject()
+ param.addProperty("code", code)
+ param.addProperty("color", color)
+ param.addProperty("position", position)
+
+ val requestBody = param.toString().toRequestBody(
+ "application/json;charset=UTF-8".toMediaType()
+ )
+ return regionApi.postRegion(requestBody)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
index f40c29f..9fc0a85 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
@@ -13,6 +13,7 @@
import android.util.Log
import android.view.SurfaceHolder
import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.addAll
import com.casic.br.operationsite.extensions.getChannel
import com.casic.br.operationsite.extensions.initLayoutImmersionBar
import com.casic.br.operationsite.model.DeviceConfigModel
@@ -26,6 +27,7 @@
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertColor
import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.widget.SteeringWheelController
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
@@ -208,6 +210,10 @@
}
}
})
+
+ videoRegionLayout.setOnClickListener {
+ navigatePageTo(addAll(hostModel.host, hostModel.port.toString()))
+ }
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
diff --git a/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
new file mode 100644
index 0000000..33f6970
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
@@ -0,0 +1,203 @@
+package com.casic.br.operationsite.view
+
+import android.graphics.PixelFormat
+import android.util.Log
+import android.view.SurfaceHolder
+import androidx.lifecycle.ViewModelProvider
+import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.getChannel
+import com.casic.br.operationsite.extensions.initLayoutImmersionBar
+import com.casic.br.operationsite.extensions.reformatFloatArray
+import com.casic.br.operationsite.utils.LocaleConstant
+import com.casic.br.operationsite.utils.hk.MessageCodeHub
+import com.casic.br.operationsite.utils.hk.SDKGuider
+import com.casic.br.operationsite.vm.RegionViewModel
+import com.gyf.immersionbar.ImmersionBar
+import com.hikvision.netsdk.NET_DVR_PREVIEWINFO
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.utils.Constant
+import kotlinx.android.synthetic.main.activity_video_region.*
+import kotlinx.android.synthetic.main.include_base_title.leftBackView
+import kotlinx.android.synthetic.main.include_base_title.titleView
+import kotlinx.android.synthetic.main.include_option_title.*
+
+class VideoRegionActivity : KotlinBaseActivity(), SurfaceHolder.Callback {
+
+ private val kTag = "VideoRegionActivity"
+ private val context = this@VideoRegionActivity
+ 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 lateinit var params: ArrayList
+ private lateinit var regionViewModel: RegionViewModel
+
+ override fun initData() {
+ params = intent.getStringArrayListExtra(Constant.INTENT_PARAM)!!
+
+ regionViewModel = ViewModelProvider(this)[RegionViewModel::class.java]
+ regionViewModel.postResult.observe(this) {
+ if (it.code == 200) {
+ "区域配置成功".show(this)
+ finish()
+ }
+ }
+ }
+
+ override fun initEvent() {
+ openCameraButton.setOnClickListener {
+ openHikVisionCamera(params[0], params[1])
+ }
+
+ closeCameraButton.setOnClickListener {
+ if (!SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)) {
+ return@setOnClickListener
+ }
+ previewHandle = -1
+ isPreviewSuccess = false
+
+ regionView.clearRoutePath()
+ }
+
+ configButton.setOnClickListener {
+ val region = regionView.getConfirmedPoints()
+ val data = region.reformatFloatArray()
+
+ //发送数据的时候需要断开视频
+ regionViewModel.postRegion("11,12", "#FF0000", data)
+ }
+ }
+
+ override fun initLayoutView(): Int = R.layout.activity_video_region
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+ ImmersionBar.with(this).statusBarDarkFont(false)
+ .statusBarColor(R.color.mainThemeColor).init()
+ initLayoutImmersionBar(rootView)
+
+ leftBackView.setOnClickListener { finish() }
+ titleView.text = "区域规划"
+ rightOptionView.text = "重画"
+ rightOptionView.setOnClickListener {
+ regionView.clearRoutePath()
+ }
+ }
+
+ private fun openHikVisionCamera(host: String, port: String) {
+ val deviceItem = SDKGuider.g_sdkGuider.m_comDMGuider.DeviceItem()
+ deviceItem.m_szDevName = ""
+ deviceItem.m_struNetInfo = SDKGuider.g_sdkGuider.m_comDMGuider.DevNetInfo(
+ host, port, LocaleConstant.HK_NET_USERNAME, LocaleConstant.HK_NET_PASSWORD
+ )
+ if (deviceItem.m_szDevName.isEmpty()) {
+ deviceItem.m_szDevName = deviceItem.m_struNetInfo.m_szIp
+ }
+
+ val loginV40Jna = SDKGuider.g_sdkGuider.m_comDMGuider.login_v40_jna(
+ deviceItem.m_szDevName, deviceItem.m_struNetInfo
+ )
+ if (loginV40Jna) {
+ //配置设备通道
+ try {
+ val deviceInfo = SDKGuider.g_sdkGuider.m_comDMGuider.devList[0]
+ returnUserID = deviceInfo.m_lUserID
+
+ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt()
+ startAChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum +
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256
+ startDChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ var iAnalogStartChan = startAChannel
+ var iDigitalStartChan = startDChannel
+
+ val channelList = ArrayList()
+
+ 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()
+ streamList.add("main_stream")
+ streamList.add("sub_stream")
+ streamList.add("third_stream")
+
+ //开始预览
+ if (previewHandle != -1) {
+ SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)
+ }
+ val strutPlayInfo = NET_DVR_PREVIEWINFO()
+ strutPlayInfo.lChannel = selectChannel
+ strutPlayInfo.dwStreamType = 1
+ strutPlayInfo.bBlocked = 1
+ strutPlayInfo.hHwnd = videoSurfaceView.holder
+ previewHandle = SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_V40_jni(
+ returnUserID, strutPlayInfo, null
+ )
+ if (previewHandle < 0) {
+ Log.d(
+ kTag,
+ "configDevice: NET_DVR_RealPlay_V40 fail, Err:${MessageCodeHub.getErrorCode()}"
+ )
+ return
+ }
+ isPreviewSuccess = true
+ } catch (e: IndexOutOfBoundsException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ videoSurfaceView.holder.setFormat(PixelFormat.TRANSLUCENT)
+ if (-1 == previewHandle) {
+ return
+ }
+ val surface = holder.surface
+ if (surface.isValid) {
+ if (-1 == SDKGuider.g_sdkGuider.m_comPreviewGuider.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.g_sdkGuider.m_comPreviewGuider.RealPlaySurfaceChanged_jni(
+ previewHandle, 0, null
+ )
+ ) {
+ Log.d(kTag, "surfaceCreated: ${MessageCodeHub.getErrorCode()}")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
index 5dff823..513db5e 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
@@ -151,14 +151,13 @@
fenceTextView.setOnClickListener {
BottomActionSheet.Builder()
.setContext(this)
- .setActionItemTitle(arrayListOf("区域规划", "监控角度", "云台角度"))
+ .setActionItemTitle(arrayListOf("监控区域", "云台角度"))
.setItemTextColor(R.color.mainThemeColor.convertColor(this))
.setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener {
override fun onActionItemClick(position: Int) {
when (position) {
- 0 -> ""
- 1 -> navigatePageTo()
- 2 -> navigatePageTo()
+ 0 -> navigatePageTo()
+ 1 -> navigatePageTo()
}
}
}).build().show()
diff --git a/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
new file mode 100644
index 0000000..d3a8181
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
@@ -0,0 +1,39 @@
+package com.casic.br.operationsite.vm
+
+import androidx.lifecycle.MutableLiveData
+import com.casic.br.operationsite.base.BaseApplication
+import com.casic.br.operationsite.extensions.separateResponseCode
+import com.casic.br.operationsite.extensions.toErrorMessage
+import com.casic.br.operationsite.model.CommonResultModel
+import com.casic.br.operationsite.retrofit.RetrofitServiceManager
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import com.pengxh.kt.lite.extensions.launch
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.vm.BaseViewModel
+import com.pengxh.kt.lite.vm.LoadState
+
+class RegionViewModel : BaseViewModel() {
+
+ private val gson by lazy { Gson() }
+ val postResult = MutableLiveData()
+
+ fun postRegion(code: String, color: String, position: String) = launch({
+ loadState.value = LoadState.Loading
+ val response = RetrofitServiceManager.postRegion(code, color, position)
+ val responseCode = response.separateResponseCode()
+ if (responseCode == 200) {
+ loadState.value = LoadState.Success
+ postResult.value = gson.fromJson(
+ response, object : TypeToken() {}.type
+ )
+ } else {
+ loadState.value = LoadState.Fail
+ response.toErrorMessage().show(BaseApplication.get())
+ }
+ }, {
+ loadState.value = LoadState.Fail
+ it.cause.toString().show(BaseApplication.get())
+ it.printStackTrace()
+ })
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
index 7582a1f..eb6a592 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
@@ -17,13 +17,19 @@
object RetrofitServiceManager {
+ private val gson by lazy { Gson() }
+
private val api by lazy {
val httpConfig = SaveKeyValues.getValue(
LocaleConstant.DEFAULT_SERVER_CONFIG, LocaleConstant.SERVER_BASE_URL
) as String
RetrofitFactory.createRetrofit(httpConfig)
}
- private val gson by lazy { Gson() }
+
+ private val regionApi by lazy {
+ val httpConfig = "http://192.168.10.104:5000"
+ RetrofitFactory.createRetrofit(httpConfig)
+ }
/**
* 验证PublicKey
@@ -171,4 +177,16 @@
)
return api.enter(AuthenticationHelper.token!!, requestBody)
}
+
+ suspend fun postRegion(code: String, color: String, position: String): String {
+ val param = JsonObject()
+ param.addProperty("code", code)
+ param.addProperty("color", color)
+ param.addProperty("position", position)
+
+ val requestBody = param.toString().toRequestBody(
+ "application/json;charset=UTF-8".toMediaType()
+ )
+ return regionApi.postRegion(requestBody)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
index f40c29f..9fc0a85 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
@@ -13,6 +13,7 @@
import android.util.Log
import android.view.SurfaceHolder
import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.addAll
import com.casic.br.operationsite.extensions.getChannel
import com.casic.br.operationsite.extensions.initLayoutImmersionBar
import com.casic.br.operationsite.model.DeviceConfigModel
@@ -26,6 +27,7 @@
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertColor
import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.widget.SteeringWheelController
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
@@ -208,6 +210,10 @@
}
}
})
+
+ videoRegionLayout.setOnClickListener {
+ navigatePageTo(addAll(hostModel.host, hostModel.port.toString()))
+ }
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
diff --git a/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
new file mode 100644
index 0000000..33f6970
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
@@ -0,0 +1,203 @@
+package com.casic.br.operationsite.view
+
+import android.graphics.PixelFormat
+import android.util.Log
+import android.view.SurfaceHolder
+import androidx.lifecycle.ViewModelProvider
+import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.getChannel
+import com.casic.br.operationsite.extensions.initLayoutImmersionBar
+import com.casic.br.operationsite.extensions.reformatFloatArray
+import com.casic.br.operationsite.utils.LocaleConstant
+import com.casic.br.operationsite.utils.hk.MessageCodeHub
+import com.casic.br.operationsite.utils.hk.SDKGuider
+import com.casic.br.operationsite.vm.RegionViewModel
+import com.gyf.immersionbar.ImmersionBar
+import com.hikvision.netsdk.NET_DVR_PREVIEWINFO
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.utils.Constant
+import kotlinx.android.synthetic.main.activity_video_region.*
+import kotlinx.android.synthetic.main.include_base_title.leftBackView
+import kotlinx.android.synthetic.main.include_base_title.titleView
+import kotlinx.android.synthetic.main.include_option_title.*
+
+class VideoRegionActivity : KotlinBaseActivity(), SurfaceHolder.Callback {
+
+ private val kTag = "VideoRegionActivity"
+ private val context = this@VideoRegionActivity
+ 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 lateinit var params: ArrayList
+ private lateinit var regionViewModel: RegionViewModel
+
+ override fun initData() {
+ params = intent.getStringArrayListExtra(Constant.INTENT_PARAM)!!
+
+ regionViewModel = ViewModelProvider(this)[RegionViewModel::class.java]
+ regionViewModel.postResult.observe(this) {
+ if (it.code == 200) {
+ "区域配置成功".show(this)
+ finish()
+ }
+ }
+ }
+
+ override fun initEvent() {
+ openCameraButton.setOnClickListener {
+ openHikVisionCamera(params[0], params[1])
+ }
+
+ closeCameraButton.setOnClickListener {
+ if (!SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)) {
+ return@setOnClickListener
+ }
+ previewHandle = -1
+ isPreviewSuccess = false
+
+ regionView.clearRoutePath()
+ }
+
+ configButton.setOnClickListener {
+ val region = regionView.getConfirmedPoints()
+ val data = region.reformatFloatArray()
+
+ //发送数据的时候需要断开视频
+ regionViewModel.postRegion("11,12", "#FF0000", data)
+ }
+ }
+
+ override fun initLayoutView(): Int = R.layout.activity_video_region
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+ ImmersionBar.with(this).statusBarDarkFont(false)
+ .statusBarColor(R.color.mainThemeColor).init()
+ initLayoutImmersionBar(rootView)
+
+ leftBackView.setOnClickListener { finish() }
+ titleView.text = "区域规划"
+ rightOptionView.text = "重画"
+ rightOptionView.setOnClickListener {
+ regionView.clearRoutePath()
+ }
+ }
+
+ private fun openHikVisionCamera(host: String, port: String) {
+ val deviceItem = SDKGuider.g_sdkGuider.m_comDMGuider.DeviceItem()
+ deviceItem.m_szDevName = ""
+ deviceItem.m_struNetInfo = SDKGuider.g_sdkGuider.m_comDMGuider.DevNetInfo(
+ host, port, LocaleConstant.HK_NET_USERNAME, LocaleConstant.HK_NET_PASSWORD
+ )
+ if (deviceItem.m_szDevName.isEmpty()) {
+ deviceItem.m_szDevName = deviceItem.m_struNetInfo.m_szIp
+ }
+
+ val loginV40Jna = SDKGuider.g_sdkGuider.m_comDMGuider.login_v40_jna(
+ deviceItem.m_szDevName, deviceItem.m_struNetInfo
+ )
+ if (loginV40Jna) {
+ //配置设备通道
+ try {
+ val deviceInfo = SDKGuider.g_sdkGuider.m_comDMGuider.devList[0]
+ returnUserID = deviceInfo.m_lUserID
+
+ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt()
+ startAChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum +
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256
+ startDChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ var iAnalogStartChan = startAChannel
+ var iDigitalStartChan = startDChannel
+
+ val channelList = ArrayList()
+
+ 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()
+ streamList.add("main_stream")
+ streamList.add("sub_stream")
+ streamList.add("third_stream")
+
+ //开始预览
+ if (previewHandle != -1) {
+ SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)
+ }
+ val strutPlayInfo = NET_DVR_PREVIEWINFO()
+ strutPlayInfo.lChannel = selectChannel
+ strutPlayInfo.dwStreamType = 1
+ strutPlayInfo.bBlocked = 1
+ strutPlayInfo.hHwnd = videoSurfaceView.holder
+ previewHandle = SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_V40_jni(
+ returnUserID, strutPlayInfo, null
+ )
+ if (previewHandle < 0) {
+ Log.d(
+ kTag,
+ "configDevice: NET_DVR_RealPlay_V40 fail, Err:${MessageCodeHub.getErrorCode()}"
+ )
+ return
+ }
+ isPreviewSuccess = true
+ } catch (e: IndexOutOfBoundsException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ videoSurfaceView.holder.setFormat(PixelFormat.TRANSLUCENT)
+ if (-1 == previewHandle) {
+ return
+ }
+ val surface = holder.surface
+ if (surface.isValid) {
+ if (-1 == SDKGuider.g_sdkGuider.m_comPreviewGuider.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.g_sdkGuider.m_comPreviewGuider.RealPlaySurfaceChanged_jni(
+ previewHandle, 0, null
+ )
+ ) {
+ Log.d(kTag, "surfaceCreated: ${MessageCodeHub.getErrorCode()}")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
index 5dff823..513db5e 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
@@ -151,14 +151,13 @@
fenceTextView.setOnClickListener {
BottomActionSheet.Builder()
.setContext(this)
- .setActionItemTitle(arrayListOf("区域规划", "监控角度", "云台角度"))
+ .setActionItemTitle(arrayListOf("监控区域", "云台角度"))
.setItemTextColor(R.color.mainThemeColor.convertColor(this))
.setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener {
override fun onActionItemClick(position: Int) {
when (position) {
- 0 -> ""
- 1 -> navigatePageTo()
- 2 -> navigatePageTo()
+ 0 -> navigatePageTo()
+ 1 -> navigatePageTo()
}
}
}).build().show()
diff --git a/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
new file mode 100644
index 0000000..d3a8181
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
@@ -0,0 +1,39 @@
+package com.casic.br.operationsite.vm
+
+import androidx.lifecycle.MutableLiveData
+import com.casic.br.operationsite.base.BaseApplication
+import com.casic.br.operationsite.extensions.separateResponseCode
+import com.casic.br.operationsite.extensions.toErrorMessage
+import com.casic.br.operationsite.model.CommonResultModel
+import com.casic.br.operationsite.retrofit.RetrofitServiceManager
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import com.pengxh.kt.lite.extensions.launch
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.vm.BaseViewModel
+import com.pengxh.kt.lite.vm.LoadState
+
+class RegionViewModel : BaseViewModel() {
+
+ private val gson by lazy { Gson() }
+ val postResult = MutableLiveData()
+
+ fun postRegion(code: String, color: String, position: String) = launch({
+ loadState.value = LoadState.Loading
+ val response = RetrofitServiceManager.postRegion(code, color, position)
+ val responseCode = response.separateResponseCode()
+ if (responseCode == 200) {
+ loadState.value = LoadState.Success
+ postResult.value = gson.fromJson(
+ response, object : TypeToken() {}.type
+ )
+ } else {
+ loadState.value = LoadState.Fail
+ response.toErrorMessage().show(BaseApplication.get())
+ }
+ }, {
+ loadState.value = LoadState.Fail
+ it.cause.toString().show(BaseApplication.get())
+ it.printStackTrace()
+ })
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt b/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt
new file mode 100644
index 0000000..72b7d5e
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt
@@ -0,0 +1,136 @@
+package com.casic.br.operationsite.widgets
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import com.casic.br.operationsite.model.Point
+import com.pengxh.kt.lite.extensions.dp2px
+import com.pengxh.kt.lite.extensions.getScreenWidth
+
+class VideoRegionView(private val ctx: Context, attrs: AttributeSet) : View(ctx, attrs) {
+
+ private val routePath: Path = Path()
+ private val rectPath: Path = Path()
+ private val routePaint: Paint = Paint()
+ private val borderPaint: Paint = Paint()
+ private var routes = ArrayList()
+
+ init {
+ routePaint.isAntiAlias = true
+ routePaint.color = Color.RED
+ routePaint.style = Paint.Style.STROKE
+ routePaint.strokeWidth = 7f //设置线宽
+ routePaint.isAntiAlias = true
+
+ borderPaint.isAntiAlias = true
+ borderPaint.color = Color.BLUE
+ borderPaint.style = Paint.Style.STROKE
+ borderPaint.strokeWidth = 7f //设置线宽
+ borderPaint.isAntiAlias = true
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ canvas.drawPath(routePath, routePaint)
+
+ canvas.drawPath(rectPath, borderPaint)
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+
+ val x = event.x
+ val y = event.y
+ routes.add(Point(x, y))
+
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> routePath.moveTo(x, y)
+ MotionEvent.ACTION_MOVE -> routePath.lineTo(x, y)
+ MotionEvent.ACTION_UP -> {
+ routePath.lineTo(x, y)
+
+ /**
+ * 找出最大的(x1,y1)和最小的(x2,y2)
+ *
+ * 左上(x2,y2)
+ * 右上(x1,y2)
+ * 左下(x2,y1)
+ * 右下(x1,y1)
+ * */
+ val sortedX = routes.sortedBy { point -> point.x }
+ val sortedY = routes.sortedBy { point -> point.y }
+ val xMaxPoint = sortedX.last()
+ val xMinPoint = sortedX.first()
+
+ val yMaxPoint = sortedY.last()
+ val yMinPoint = sortedY.first()
+
+ /**
+ * 画出外接矩形
+ * */
+ val leftTop = Point(xMinPoint.x, yMinPoint.y)
+ val rightTop = Point(xMaxPoint.x, yMinPoint.y)
+ val leftBottom = Point(xMinPoint.x, yMaxPoint.y)
+ val rightBottom = Point(xMaxPoint.x, yMaxPoint.y)
+ rectPath.moveTo(leftTop.x, leftTop.y)
+ rectPath.lineTo(rightTop.x, rightTop.y)
+ rectPath.lineTo(rightBottom.x, rightBottom.y)
+ rectPath.lineTo(leftBottom.x, leftBottom.y)
+ rectPath.lineTo(leftTop.x, leftTop.y)
+
+ /**
+ * 计算出点的相对位置返回给一体机计算
+ * */
+ val width = ctx.getScreenWidth() - 14f.dp2px(ctx)
+ val height = 855
+
+ /**
+ * 区域
+ * */
+ if (region.isNotEmpty()) {
+ region.clear()
+ }
+ region.add(Point(leftTop.x / width, leftTop.y / height))
+ region.add(Point(rightTop.x / width, rightTop.y / height))
+ region.add(Point(leftBottom.x / width, leftBottom.y / height))
+ region.add(Point(rightBottom.x / width, rightBottom.y / height))
+
+ /**
+ * 点集合
+ * */
+ if (points.isNotEmpty()) {
+ points.clear()
+ }
+ points.add(floatArrayOf(leftTop.x / width, leftTop.y / height))
+ points.add(floatArrayOf(rightTop.x / width, rightTop.y / height))
+ points.add(floatArrayOf(leftBottom.x / width, leftBottom.y / height))
+ points.add(floatArrayOf(rightBottom.x / width, rightBottom.y / height))
+ }
+ }
+ invalidate()
+ return true
+ }
+
+ fun clearRoutePath() {
+ routePath.reset()
+ rectPath.reset()
+ routes.clear()
+ invalidate()
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private var region = ArrayList()
+
+ fun getConfirmedRegion(): ArrayList = region
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private var points = ArrayList()
+
+ fun getConfirmedPoints(): ArrayList = points
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
index 7582a1f..eb6a592 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
@@ -17,13 +17,19 @@
object RetrofitServiceManager {
+ private val gson by lazy { Gson() }
+
private val api by lazy {
val httpConfig = SaveKeyValues.getValue(
LocaleConstant.DEFAULT_SERVER_CONFIG, LocaleConstant.SERVER_BASE_URL
) as String
RetrofitFactory.createRetrofit(httpConfig)
}
- private val gson by lazy { Gson() }
+
+ private val regionApi by lazy {
+ val httpConfig = "http://192.168.10.104:5000"
+ RetrofitFactory.createRetrofit(httpConfig)
+ }
/**
* 验证PublicKey
@@ -171,4 +177,16 @@
)
return api.enter(AuthenticationHelper.token!!, requestBody)
}
+
+ suspend fun postRegion(code: String, color: String, position: String): String {
+ val param = JsonObject()
+ param.addProperty("code", code)
+ param.addProperty("color", color)
+ param.addProperty("position", position)
+
+ val requestBody = param.toString().toRequestBody(
+ "application/json;charset=UTF-8".toMediaType()
+ )
+ return regionApi.postRegion(requestBody)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
index f40c29f..9fc0a85 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
@@ -13,6 +13,7 @@
import android.util.Log
import android.view.SurfaceHolder
import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.addAll
import com.casic.br.operationsite.extensions.getChannel
import com.casic.br.operationsite.extensions.initLayoutImmersionBar
import com.casic.br.operationsite.model.DeviceConfigModel
@@ -26,6 +27,7 @@
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertColor
import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.widget.SteeringWheelController
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
@@ -208,6 +210,10 @@
}
}
})
+
+ videoRegionLayout.setOnClickListener {
+ navigatePageTo(addAll(hostModel.host, hostModel.port.toString()))
+ }
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
diff --git a/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
new file mode 100644
index 0000000..33f6970
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
@@ -0,0 +1,203 @@
+package com.casic.br.operationsite.view
+
+import android.graphics.PixelFormat
+import android.util.Log
+import android.view.SurfaceHolder
+import androidx.lifecycle.ViewModelProvider
+import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.getChannel
+import com.casic.br.operationsite.extensions.initLayoutImmersionBar
+import com.casic.br.operationsite.extensions.reformatFloatArray
+import com.casic.br.operationsite.utils.LocaleConstant
+import com.casic.br.operationsite.utils.hk.MessageCodeHub
+import com.casic.br.operationsite.utils.hk.SDKGuider
+import com.casic.br.operationsite.vm.RegionViewModel
+import com.gyf.immersionbar.ImmersionBar
+import com.hikvision.netsdk.NET_DVR_PREVIEWINFO
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.utils.Constant
+import kotlinx.android.synthetic.main.activity_video_region.*
+import kotlinx.android.synthetic.main.include_base_title.leftBackView
+import kotlinx.android.synthetic.main.include_base_title.titleView
+import kotlinx.android.synthetic.main.include_option_title.*
+
+class VideoRegionActivity : KotlinBaseActivity(), SurfaceHolder.Callback {
+
+ private val kTag = "VideoRegionActivity"
+ private val context = this@VideoRegionActivity
+ 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 lateinit var params: ArrayList
+ private lateinit var regionViewModel: RegionViewModel
+
+ override fun initData() {
+ params = intent.getStringArrayListExtra(Constant.INTENT_PARAM)!!
+
+ regionViewModel = ViewModelProvider(this)[RegionViewModel::class.java]
+ regionViewModel.postResult.observe(this) {
+ if (it.code == 200) {
+ "区域配置成功".show(this)
+ finish()
+ }
+ }
+ }
+
+ override fun initEvent() {
+ openCameraButton.setOnClickListener {
+ openHikVisionCamera(params[0], params[1])
+ }
+
+ closeCameraButton.setOnClickListener {
+ if (!SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)) {
+ return@setOnClickListener
+ }
+ previewHandle = -1
+ isPreviewSuccess = false
+
+ regionView.clearRoutePath()
+ }
+
+ configButton.setOnClickListener {
+ val region = regionView.getConfirmedPoints()
+ val data = region.reformatFloatArray()
+
+ //发送数据的时候需要断开视频
+ regionViewModel.postRegion("11,12", "#FF0000", data)
+ }
+ }
+
+ override fun initLayoutView(): Int = R.layout.activity_video_region
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+ ImmersionBar.with(this).statusBarDarkFont(false)
+ .statusBarColor(R.color.mainThemeColor).init()
+ initLayoutImmersionBar(rootView)
+
+ leftBackView.setOnClickListener { finish() }
+ titleView.text = "区域规划"
+ rightOptionView.text = "重画"
+ rightOptionView.setOnClickListener {
+ regionView.clearRoutePath()
+ }
+ }
+
+ private fun openHikVisionCamera(host: String, port: String) {
+ val deviceItem = SDKGuider.g_sdkGuider.m_comDMGuider.DeviceItem()
+ deviceItem.m_szDevName = ""
+ deviceItem.m_struNetInfo = SDKGuider.g_sdkGuider.m_comDMGuider.DevNetInfo(
+ host, port, LocaleConstant.HK_NET_USERNAME, LocaleConstant.HK_NET_PASSWORD
+ )
+ if (deviceItem.m_szDevName.isEmpty()) {
+ deviceItem.m_szDevName = deviceItem.m_struNetInfo.m_szIp
+ }
+
+ val loginV40Jna = SDKGuider.g_sdkGuider.m_comDMGuider.login_v40_jna(
+ deviceItem.m_szDevName, deviceItem.m_struNetInfo
+ )
+ if (loginV40Jna) {
+ //配置设备通道
+ try {
+ val deviceInfo = SDKGuider.g_sdkGuider.m_comDMGuider.devList[0]
+ returnUserID = deviceInfo.m_lUserID
+
+ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt()
+ startAChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum +
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256
+ startDChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ var iAnalogStartChan = startAChannel
+ var iDigitalStartChan = startDChannel
+
+ val channelList = ArrayList()
+
+ 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()
+ streamList.add("main_stream")
+ streamList.add("sub_stream")
+ streamList.add("third_stream")
+
+ //开始预览
+ if (previewHandle != -1) {
+ SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)
+ }
+ val strutPlayInfo = NET_DVR_PREVIEWINFO()
+ strutPlayInfo.lChannel = selectChannel
+ strutPlayInfo.dwStreamType = 1
+ strutPlayInfo.bBlocked = 1
+ strutPlayInfo.hHwnd = videoSurfaceView.holder
+ previewHandle = SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_V40_jni(
+ returnUserID, strutPlayInfo, null
+ )
+ if (previewHandle < 0) {
+ Log.d(
+ kTag,
+ "configDevice: NET_DVR_RealPlay_V40 fail, Err:${MessageCodeHub.getErrorCode()}"
+ )
+ return
+ }
+ isPreviewSuccess = true
+ } catch (e: IndexOutOfBoundsException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ videoSurfaceView.holder.setFormat(PixelFormat.TRANSLUCENT)
+ if (-1 == previewHandle) {
+ return
+ }
+ val surface = holder.surface
+ if (surface.isValid) {
+ if (-1 == SDKGuider.g_sdkGuider.m_comPreviewGuider.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.g_sdkGuider.m_comPreviewGuider.RealPlaySurfaceChanged_jni(
+ previewHandle, 0, null
+ )
+ ) {
+ Log.d(kTag, "surfaceCreated: ${MessageCodeHub.getErrorCode()}")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
index 5dff823..513db5e 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
@@ -151,14 +151,13 @@
fenceTextView.setOnClickListener {
BottomActionSheet.Builder()
.setContext(this)
- .setActionItemTitle(arrayListOf("区域规划", "监控角度", "云台角度"))
+ .setActionItemTitle(arrayListOf("监控区域", "云台角度"))
.setItemTextColor(R.color.mainThemeColor.convertColor(this))
.setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener {
override fun onActionItemClick(position: Int) {
when (position) {
- 0 -> ""
- 1 -> navigatePageTo()
- 2 -> navigatePageTo()
+ 0 -> navigatePageTo()
+ 1 -> navigatePageTo()
}
}
}).build().show()
diff --git a/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
new file mode 100644
index 0000000..d3a8181
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
@@ -0,0 +1,39 @@
+package com.casic.br.operationsite.vm
+
+import androidx.lifecycle.MutableLiveData
+import com.casic.br.operationsite.base.BaseApplication
+import com.casic.br.operationsite.extensions.separateResponseCode
+import com.casic.br.operationsite.extensions.toErrorMessage
+import com.casic.br.operationsite.model.CommonResultModel
+import com.casic.br.operationsite.retrofit.RetrofitServiceManager
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import com.pengxh.kt.lite.extensions.launch
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.vm.BaseViewModel
+import com.pengxh.kt.lite.vm.LoadState
+
+class RegionViewModel : BaseViewModel() {
+
+ private val gson by lazy { Gson() }
+ val postResult = MutableLiveData()
+
+ fun postRegion(code: String, color: String, position: String) = launch({
+ loadState.value = LoadState.Loading
+ val response = RetrofitServiceManager.postRegion(code, color, position)
+ val responseCode = response.separateResponseCode()
+ if (responseCode == 200) {
+ loadState.value = LoadState.Success
+ postResult.value = gson.fromJson(
+ response, object : TypeToken() {}.type
+ )
+ } else {
+ loadState.value = LoadState.Fail
+ response.toErrorMessage().show(BaseApplication.get())
+ }
+ }, {
+ loadState.value = LoadState.Fail
+ it.cause.toString().show(BaseApplication.get())
+ it.printStackTrace()
+ })
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt b/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt
new file mode 100644
index 0000000..72b7d5e
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt
@@ -0,0 +1,136 @@
+package com.casic.br.operationsite.widgets
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import com.casic.br.operationsite.model.Point
+import com.pengxh.kt.lite.extensions.dp2px
+import com.pengxh.kt.lite.extensions.getScreenWidth
+
+class VideoRegionView(private val ctx: Context, attrs: AttributeSet) : View(ctx, attrs) {
+
+ private val routePath: Path = Path()
+ private val rectPath: Path = Path()
+ private val routePaint: Paint = Paint()
+ private val borderPaint: Paint = Paint()
+ private var routes = ArrayList()
+
+ init {
+ routePaint.isAntiAlias = true
+ routePaint.color = Color.RED
+ routePaint.style = Paint.Style.STROKE
+ routePaint.strokeWidth = 7f //设置线宽
+ routePaint.isAntiAlias = true
+
+ borderPaint.isAntiAlias = true
+ borderPaint.color = Color.BLUE
+ borderPaint.style = Paint.Style.STROKE
+ borderPaint.strokeWidth = 7f //设置线宽
+ borderPaint.isAntiAlias = true
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ canvas.drawPath(routePath, routePaint)
+
+ canvas.drawPath(rectPath, borderPaint)
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+
+ val x = event.x
+ val y = event.y
+ routes.add(Point(x, y))
+
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> routePath.moveTo(x, y)
+ MotionEvent.ACTION_MOVE -> routePath.lineTo(x, y)
+ MotionEvent.ACTION_UP -> {
+ routePath.lineTo(x, y)
+
+ /**
+ * 找出最大的(x1,y1)和最小的(x2,y2)
+ *
+ * 左上(x2,y2)
+ * 右上(x1,y2)
+ * 左下(x2,y1)
+ * 右下(x1,y1)
+ * */
+ val sortedX = routes.sortedBy { point -> point.x }
+ val sortedY = routes.sortedBy { point -> point.y }
+ val xMaxPoint = sortedX.last()
+ val xMinPoint = sortedX.first()
+
+ val yMaxPoint = sortedY.last()
+ val yMinPoint = sortedY.first()
+
+ /**
+ * 画出外接矩形
+ * */
+ val leftTop = Point(xMinPoint.x, yMinPoint.y)
+ val rightTop = Point(xMaxPoint.x, yMinPoint.y)
+ val leftBottom = Point(xMinPoint.x, yMaxPoint.y)
+ val rightBottom = Point(xMaxPoint.x, yMaxPoint.y)
+ rectPath.moveTo(leftTop.x, leftTop.y)
+ rectPath.lineTo(rightTop.x, rightTop.y)
+ rectPath.lineTo(rightBottom.x, rightBottom.y)
+ rectPath.lineTo(leftBottom.x, leftBottom.y)
+ rectPath.lineTo(leftTop.x, leftTop.y)
+
+ /**
+ * 计算出点的相对位置返回给一体机计算
+ * */
+ val width = ctx.getScreenWidth() - 14f.dp2px(ctx)
+ val height = 855
+
+ /**
+ * 区域
+ * */
+ if (region.isNotEmpty()) {
+ region.clear()
+ }
+ region.add(Point(leftTop.x / width, leftTop.y / height))
+ region.add(Point(rightTop.x / width, rightTop.y / height))
+ region.add(Point(leftBottom.x / width, leftBottom.y / height))
+ region.add(Point(rightBottom.x / width, rightBottom.y / height))
+
+ /**
+ * 点集合
+ * */
+ if (points.isNotEmpty()) {
+ points.clear()
+ }
+ points.add(floatArrayOf(leftTop.x / width, leftTop.y / height))
+ points.add(floatArrayOf(rightTop.x / width, rightTop.y / height))
+ points.add(floatArrayOf(leftBottom.x / width, leftBottom.y / height))
+ points.add(floatArrayOf(rightBottom.x / width, rightBottom.y / height))
+ }
+ }
+ invalidate()
+ return true
+ }
+
+ fun clearRoutePath() {
+ routePath.reset()
+ rectPath.reset()
+ routes.clear()
+ invalidate()
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private var region = ArrayList()
+
+ fun getConfirmedRegion(): ArrayList = region
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private var points = ArrayList()
+
+ fun getConfirmedPoints(): ArrayList = points
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_right.xml b/app/src/main/res/drawable/ic_right.xml
new file mode 100644
index 0000000..e5aafca
--- /dev/null
+++ b/app/src/main/res/drawable/ic_right.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
index 7582a1f..eb6a592 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
@@ -17,13 +17,19 @@
object RetrofitServiceManager {
+ private val gson by lazy { Gson() }
+
private val api by lazy {
val httpConfig = SaveKeyValues.getValue(
LocaleConstant.DEFAULT_SERVER_CONFIG, LocaleConstant.SERVER_BASE_URL
) as String
RetrofitFactory.createRetrofit(httpConfig)
}
- private val gson by lazy { Gson() }
+
+ private val regionApi by lazy {
+ val httpConfig = "http://192.168.10.104:5000"
+ RetrofitFactory.createRetrofit(httpConfig)
+ }
/**
* 验证PublicKey
@@ -171,4 +177,16 @@
)
return api.enter(AuthenticationHelper.token!!, requestBody)
}
+
+ suspend fun postRegion(code: String, color: String, position: String): String {
+ val param = JsonObject()
+ param.addProperty("code", code)
+ param.addProperty("color", color)
+ param.addProperty("position", position)
+
+ val requestBody = param.toString().toRequestBody(
+ "application/json;charset=UTF-8".toMediaType()
+ )
+ return regionApi.postRegion(requestBody)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
index f40c29f..9fc0a85 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
@@ -13,6 +13,7 @@
import android.util.Log
import android.view.SurfaceHolder
import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.addAll
import com.casic.br.operationsite.extensions.getChannel
import com.casic.br.operationsite.extensions.initLayoutImmersionBar
import com.casic.br.operationsite.model.DeviceConfigModel
@@ -26,6 +27,7 @@
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertColor
import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.widget.SteeringWheelController
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
@@ -208,6 +210,10 @@
}
}
})
+
+ videoRegionLayout.setOnClickListener {
+ navigatePageTo(addAll(hostModel.host, hostModel.port.toString()))
+ }
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
diff --git a/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
new file mode 100644
index 0000000..33f6970
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
@@ -0,0 +1,203 @@
+package com.casic.br.operationsite.view
+
+import android.graphics.PixelFormat
+import android.util.Log
+import android.view.SurfaceHolder
+import androidx.lifecycle.ViewModelProvider
+import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.getChannel
+import com.casic.br.operationsite.extensions.initLayoutImmersionBar
+import com.casic.br.operationsite.extensions.reformatFloatArray
+import com.casic.br.operationsite.utils.LocaleConstant
+import com.casic.br.operationsite.utils.hk.MessageCodeHub
+import com.casic.br.operationsite.utils.hk.SDKGuider
+import com.casic.br.operationsite.vm.RegionViewModel
+import com.gyf.immersionbar.ImmersionBar
+import com.hikvision.netsdk.NET_DVR_PREVIEWINFO
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.utils.Constant
+import kotlinx.android.synthetic.main.activity_video_region.*
+import kotlinx.android.synthetic.main.include_base_title.leftBackView
+import kotlinx.android.synthetic.main.include_base_title.titleView
+import kotlinx.android.synthetic.main.include_option_title.*
+
+class VideoRegionActivity : KotlinBaseActivity(), SurfaceHolder.Callback {
+
+ private val kTag = "VideoRegionActivity"
+ private val context = this@VideoRegionActivity
+ 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 lateinit var params: ArrayList
+ private lateinit var regionViewModel: RegionViewModel
+
+ override fun initData() {
+ params = intent.getStringArrayListExtra(Constant.INTENT_PARAM)!!
+
+ regionViewModel = ViewModelProvider(this)[RegionViewModel::class.java]
+ regionViewModel.postResult.observe(this) {
+ if (it.code == 200) {
+ "区域配置成功".show(this)
+ finish()
+ }
+ }
+ }
+
+ override fun initEvent() {
+ openCameraButton.setOnClickListener {
+ openHikVisionCamera(params[0], params[1])
+ }
+
+ closeCameraButton.setOnClickListener {
+ if (!SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)) {
+ return@setOnClickListener
+ }
+ previewHandle = -1
+ isPreviewSuccess = false
+
+ regionView.clearRoutePath()
+ }
+
+ configButton.setOnClickListener {
+ val region = regionView.getConfirmedPoints()
+ val data = region.reformatFloatArray()
+
+ //发送数据的时候需要断开视频
+ regionViewModel.postRegion("11,12", "#FF0000", data)
+ }
+ }
+
+ override fun initLayoutView(): Int = R.layout.activity_video_region
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+ ImmersionBar.with(this).statusBarDarkFont(false)
+ .statusBarColor(R.color.mainThemeColor).init()
+ initLayoutImmersionBar(rootView)
+
+ leftBackView.setOnClickListener { finish() }
+ titleView.text = "区域规划"
+ rightOptionView.text = "重画"
+ rightOptionView.setOnClickListener {
+ regionView.clearRoutePath()
+ }
+ }
+
+ private fun openHikVisionCamera(host: String, port: String) {
+ val deviceItem = SDKGuider.g_sdkGuider.m_comDMGuider.DeviceItem()
+ deviceItem.m_szDevName = ""
+ deviceItem.m_struNetInfo = SDKGuider.g_sdkGuider.m_comDMGuider.DevNetInfo(
+ host, port, LocaleConstant.HK_NET_USERNAME, LocaleConstant.HK_NET_PASSWORD
+ )
+ if (deviceItem.m_szDevName.isEmpty()) {
+ deviceItem.m_szDevName = deviceItem.m_struNetInfo.m_szIp
+ }
+
+ val loginV40Jna = SDKGuider.g_sdkGuider.m_comDMGuider.login_v40_jna(
+ deviceItem.m_szDevName, deviceItem.m_struNetInfo
+ )
+ if (loginV40Jna) {
+ //配置设备通道
+ try {
+ val deviceInfo = SDKGuider.g_sdkGuider.m_comDMGuider.devList[0]
+ returnUserID = deviceInfo.m_lUserID
+
+ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt()
+ startAChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum +
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256
+ startDChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ var iAnalogStartChan = startAChannel
+ var iDigitalStartChan = startDChannel
+
+ val channelList = ArrayList()
+
+ 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()
+ streamList.add("main_stream")
+ streamList.add("sub_stream")
+ streamList.add("third_stream")
+
+ //开始预览
+ if (previewHandle != -1) {
+ SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)
+ }
+ val strutPlayInfo = NET_DVR_PREVIEWINFO()
+ strutPlayInfo.lChannel = selectChannel
+ strutPlayInfo.dwStreamType = 1
+ strutPlayInfo.bBlocked = 1
+ strutPlayInfo.hHwnd = videoSurfaceView.holder
+ previewHandle = SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_V40_jni(
+ returnUserID, strutPlayInfo, null
+ )
+ if (previewHandle < 0) {
+ Log.d(
+ kTag,
+ "configDevice: NET_DVR_RealPlay_V40 fail, Err:${MessageCodeHub.getErrorCode()}"
+ )
+ return
+ }
+ isPreviewSuccess = true
+ } catch (e: IndexOutOfBoundsException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ videoSurfaceView.holder.setFormat(PixelFormat.TRANSLUCENT)
+ if (-1 == previewHandle) {
+ return
+ }
+ val surface = holder.surface
+ if (surface.isValid) {
+ if (-1 == SDKGuider.g_sdkGuider.m_comPreviewGuider.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.g_sdkGuider.m_comPreviewGuider.RealPlaySurfaceChanged_jni(
+ previewHandle, 0, null
+ )
+ ) {
+ Log.d(kTag, "surfaceCreated: ${MessageCodeHub.getErrorCode()}")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
index 5dff823..513db5e 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
@@ -151,14 +151,13 @@
fenceTextView.setOnClickListener {
BottomActionSheet.Builder()
.setContext(this)
- .setActionItemTitle(arrayListOf("区域规划", "监控角度", "云台角度"))
+ .setActionItemTitle(arrayListOf("监控区域", "云台角度"))
.setItemTextColor(R.color.mainThemeColor.convertColor(this))
.setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener {
override fun onActionItemClick(position: Int) {
when (position) {
- 0 -> ""
- 1 -> navigatePageTo()
- 2 -> navigatePageTo()
+ 0 -> navigatePageTo()
+ 1 -> navigatePageTo()
}
}
}).build().show()
diff --git a/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
new file mode 100644
index 0000000..d3a8181
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
@@ -0,0 +1,39 @@
+package com.casic.br.operationsite.vm
+
+import androidx.lifecycle.MutableLiveData
+import com.casic.br.operationsite.base.BaseApplication
+import com.casic.br.operationsite.extensions.separateResponseCode
+import com.casic.br.operationsite.extensions.toErrorMessage
+import com.casic.br.operationsite.model.CommonResultModel
+import com.casic.br.operationsite.retrofit.RetrofitServiceManager
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import com.pengxh.kt.lite.extensions.launch
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.vm.BaseViewModel
+import com.pengxh.kt.lite.vm.LoadState
+
+class RegionViewModel : BaseViewModel() {
+
+ private val gson by lazy { Gson() }
+ val postResult = MutableLiveData()
+
+ fun postRegion(code: String, color: String, position: String) = launch({
+ loadState.value = LoadState.Loading
+ val response = RetrofitServiceManager.postRegion(code, color, position)
+ val responseCode = response.separateResponseCode()
+ if (responseCode == 200) {
+ loadState.value = LoadState.Success
+ postResult.value = gson.fromJson(
+ response, object : TypeToken() {}.type
+ )
+ } else {
+ loadState.value = LoadState.Fail
+ response.toErrorMessage().show(BaseApplication.get())
+ }
+ }, {
+ loadState.value = LoadState.Fail
+ it.cause.toString().show(BaseApplication.get())
+ it.printStackTrace()
+ })
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt b/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt
new file mode 100644
index 0000000..72b7d5e
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt
@@ -0,0 +1,136 @@
+package com.casic.br.operationsite.widgets
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import com.casic.br.operationsite.model.Point
+import com.pengxh.kt.lite.extensions.dp2px
+import com.pengxh.kt.lite.extensions.getScreenWidth
+
+class VideoRegionView(private val ctx: Context, attrs: AttributeSet) : View(ctx, attrs) {
+
+ private val routePath: Path = Path()
+ private val rectPath: Path = Path()
+ private val routePaint: Paint = Paint()
+ private val borderPaint: Paint = Paint()
+ private var routes = ArrayList()
+
+ init {
+ routePaint.isAntiAlias = true
+ routePaint.color = Color.RED
+ routePaint.style = Paint.Style.STROKE
+ routePaint.strokeWidth = 7f //设置线宽
+ routePaint.isAntiAlias = true
+
+ borderPaint.isAntiAlias = true
+ borderPaint.color = Color.BLUE
+ borderPaint.style = Paint.Style.STROKE
+ borderPaint.strokeWidth = 7f //设置线宽
+ borderPaint.isAntiAlias = true
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ canvas.drawPath(routePath, routePaint)
+
+ canvas.drawPath(rectPath, borderPaint)
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+
+ val x = event.x
+ val y = event.y
+ routes.add(Point(x, y))
+
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> routePath.moveTo(x, y)
+ MotionEvent.ACTION_MOVE -> routePath.lineTo(x, y)
+ MotionEvent.ACTION_UP -> {
+ routePath.lineTo(x, y)
+
+ /**
+ * 找出最大的(x1,y1)和最小的(x2,y2)
+ *
+ * 左上(x2,y2)
+ * 右上(x1,y2)
+ * 左下(x2,y1)
+ * 右下(x1,y1)
+ * */
+ val sortedX = routes.sortedBy { point -> point.x }
+ val sortedY = routes.sortedBy { point -> point.y }
+ val xMaxPoint = sortedX.last()
+ val xMinPoint = sortedX.first()
+
+ val yMaxPoint = sortedY.last()
+ val yMinPoint = sortedY.first()
+
+ /**
+ * 画出外接矩形
+ * */
+ val leftTop = Point(xMinPoint.x, yMinPoint.y)
+ val rightTop = Point(xMaxPoint.x, yMinPoint.y)
+ val leftBottom = Point(xMinPoint.x, yMaxPoint.y)
+ val rightBottom = Point(xMaxPoint.x, yMaxPoint.y)
+ rectPath.moveTo(leftTop.x, leftTop.y)
+ rectPath.lineTo(rightTop.x, rightTop.y)
+ rectPath.lineTo(rightBottom.x, rightBottom.y)
+ rectPath.lineTo(leftBottom.x, leftBottom.y)
+ rectPath.lineTo(leftTop.x, leftTop.y)
+
+ /**
+ * 计算出点的相对位置返回给一体机计算
+ * */
+ val width = ctx.getScreenWidth() - 14f.dp2px(ctx)
+ val height = 855
+
+ /**
+ * 区域
+ * */
+ if (region.isNotEmpty()) {
+ region.clear()
+ }
+ region.add(Point(leftTop.x / width, leftTop.y / height))
+ region.add(Point(rightTop.x / width, rightTop.y / height))
+ region.add(Point(leftBottom.x / width, leftBottom.y / height))
+ region.add(Point(rightBottom.x / width, rightBottom.y / height))
+
+ /**
+ * 点集合
+ * */
+ if (points.isNotEmpty()) {
+ points.clear()
+ }
+ points.add(floatArrayOf(leftTop.x / width, leftTop.y / height))
+ points.add(floatArrayOf(rightTop.x / width, rightTop.y / height))
+ points.add(floatArrayOf(leftBottom.x / width, leftBottom.y / height))
+ points.add(floatArrayOf(rightBottom.x / width, rightBottom.y / height))
+ }
+ }
+ invalidate()
+ return true
+ }
+
+ fun clearRoutePath() {
+ routePath.reset()
+ rectPath.reset()
+ routes.clear()
+ invalidate()
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private var region = ArrayList()
+
+ fun getConfirmedRegion(): ArrayList = region
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private var points = ArrayList()
+
+ fun getConfirmedPoints(): ArrayList = points
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_right.xml b/app/src/main/res/drawable/ic_right.xml
new file mode 100644
index 0000000..e5aafca
--- /dev/null
+++ b/app/src/main/res/drawable/ic_right.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_hikvision.xml b/app/src/main/res/layout/activity_hikvision.xml
index 752d62c..8b4f9fc 100644
--- a/app/src/main/res/layout/activity_hikvision.xml
+++ b/app/src/main/res/layout/activity_hikvision.xml
@@ -20,10 +20,10 @@
android:layout_marginHorizontal="@dimen/dp_7"
android:layout_marginTop="@dimen/dp_7"
android:background="@drawable/bg_solid_layout_white_radius_10"
- android:orientation="vertical">
+ android:orientation="horizontal">
+ android:orientation="horizontal">
+
+
+
+
+
+
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
index 7582a1f..eb6a592 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
@@ -17,13 +17,19 @@
object RetrofitServiceManager {
+ private val gson by lazy { Gson() }
+
private val api by lazy {
val httpConfig = SaveKeyValues.getValue(
LocaleConstant.DEFAULT_SERVER_CONFIG, LocaleConstant.SERVER_BASE_URL
) as String
RetrofitFactory.createRetrofit(httpConfig)
}
- private val gson by lazy { Gson() }
+
+ private val regionApi by lazy {
+ val httpConfig = "http://192.168.10.104:5000"
+ RetrofitFactory.createRetrofit(httpConfig)
+ }
/**
* 验证PublicKey
@@ -171,4 +177,16 @@
)
return api.enter(AuthenticationHelper.token!!, requestBody)
}
+
+ suspend fun postRegion(code: String, color: String, position: String): String {
+ val param = JsonObject()
+ param.addProperty("code", code)
+ param.addProperty("color", color)
+ param.addProperty("position", position)
+
+ val requestBody = param.toString().toRequestBody(
+ "application/json;charset=UTF-8".toMediaType()
+ )
+ return regionApi.postRegion(requestBody)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
index f40c29f..9fc0a85 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
@@ -13,6 +13,7 @@
import android.util.Log
import android.view.SurfaceHolder
import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.addAll
import com.casic.br.operationsite.extensions.getChannel
import com.casic.br.operationsite.extensions.initLayoutImmersionBar
import com.casic.br.operationsite.model.DeviceConfigModel
@@ -26,6 +27,7 @@
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertColor
import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.widget.SteeringWheelController
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
@@ -208,6 +210,10 @@
}
}
})
+
+ videoRegionLayout.setOnClickListener {
+ navigatePageTo(addAll(hostModel.host, hostModel.port.toString()))
+ }
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
diff --git a/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
new file mode 100644
index 0000000..33f6970
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
@@ -0,0 +1,203 @@
+package com.casic.br.operationsite.view
+
+import android.graphics.PixelFormat
+import android.util.Log
+import android.view.SurfaceHolder
+import androidx.lifecycle.ViewModelProvider
+import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.getChannel
+import com.casic.br.operationsite.extensions.initLayoutImmersionBar
+import com.casic.br.operationsite.extensions.reformatFloatArray
+import com.casic.br.operationsite.utils.LocaleConstant
+import com.casic.br.operationsite.utils.hk.MessageCodeHub
+import com.casic.br.operationsite.utils.hk.SDKGuider
+import com.casic.br.operationsite.vm.RegionViewModel
+import com.gyf.immersionbar.ImmersionBar
+import com.hikvision.netsdk.NET_DVR_PREVIEWINFO
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.utils.Constant
+import kotlinx.android.synthetic.main.activity_video_region.*
+import kotlinx.android.synthetic.main.include_base_title.leftBackView
+import kotlinx.android.synthetic.main.include_base_title.titleView
+import kotlinx.android.synthetic.main.include_option_title.*
+
+class VideoRegionActivity : KotlinBaseActivity(), SurfaceHolder.Callback {
+
+ private val kTag = "VideoRegionActivity"
+ private val context = this@VideoRegionActivity
+ 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 lateinit var params: ArrayList
+ private lateinit var regionViewModel: RegionViewModel
+
+ override fun initData() {
+ params = intent.getStringArrayListExtra(Constant.INTENT_PARAM)!!
+
+ regionViewModel = ViewModelProvider(this)[RegionViewModel::class.java]
+ regionViewModel.postResult.observe(this) {
+ if (it.code == 200) {
+ "区域配置成功".show(this)
+ finish()
+ }
+ }
+ }
+
+ override fun initEvent() {
+ openCameraButton.setOnClickListener {
+ openHikVisionCamera(params[0], params[1])
+ }
+
+ closeCameraButton.setOnClickListener {
+ if (!SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)) {
+ return@setOnClickListener
+ }
+ previewHandle = -1
+ isPreviewSuccess = false
+
+ regionView.clearRoutePath()
+ }
+
+ configButton.setOnClickListener {
+ val region = regionView.getConfirmedPoints()
+ val data = region.reformatFloatArray()
+
+ //发送数据的时候需要断开视频
+ regionViewModel.postRegion("11,12", "#FF0000", data)
+ }
+ }
+
+ override fun initLayoutView(): Int = R.layout.activity_video_region
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+ ImmersionBar.with(this).statusBarDarkFont(false)
+ .statusBarColor(R.color.mainThemeColor).init()
+ initLayoutImmersionBar(rootView)
+
+ leftBackView.setOnClickListener { finish() }
+ titleView.text = "区域规划"
+ rightOptionView.text = "重画"
+ rightOptionView.setOnClickListener {
+ regionView.clearRoutePath()
+ }
+ }
+
+ private fun openHikVisionCamera(host: String, port: String) {
+ val deviceItem = SDKGuider.g_sdkGuider.m_comDMGuider.DeviceItem()
+ deviceItem.m_szDevName = ""
+ deviceItem.m_struNetInfo = SDKGuider.g_sdkGuider.m_comDMGuider.DevNetInfo(
+ host, port, LocaleConstant.HK_NET_USERNAME, LocaleConstant.HK_NET_PASSWORD
+ )
+ if (deviceItem.m_szDevName.isEmpty()) {
+ deviceItem.m_szDevName = deviceItem.m_struNetInfo.m_szIp
+ }
+
+ val loginV40Jna = SDKGuider.g_sdkGuider.m_comDMGuider.login_v40_jna(
+ deviceItem.m_szDevName, deviceItem.m_struNetInfo
+ )
+ if (loginV40Jna) {
+ //配置设备通道
+ try {
+ val deviceInfo = SDKGuider.g_sdkGuider.m_comDMGuider.devList[0]
+ returnUserID = deviceInfo.m_lUserID
+
+ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt()
+ startAChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum +
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256
+ startDChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ var iAnalogStartChan = startAChannel
+ var iDigitalStartChan = startDChannel
+
+ val channelList = ArrayList()
+
+ 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()
+ streamList.add("main_stream")
+ streamList.add("sub_stream")
+ streamList.add("third_stream")
+
+ //开始预览
+ if (previewHandle != -1) {
+ SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)
+ }
+ val strutPlayInfo = NET_DVR_PREVIEWINFO()
+ strutPlayInfo.lChannel = selectChannel
+ strutPlayInfo.dwStreamType = 1
+ strutPlayInfo.bBlocked = 1
+ strutPlayInfo.hHwnd = videoSurfaceView.holder
+ previewHandle = SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_V40_jni(
+ returnUserID, strutPlayInfo, null
+ )
+ if (previewHandle < 0) {
+ Log.d(
+ kTag,
+ "configDevice: NET_DVR_RealPlay_V40 fail, Err:${MessageCodeHub.getErrorCode()}"
+ )
+ return
+ }
+ isPreviewSuccess = true
+ } catch (e: IndexOutOfBoundsException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ videoSurfaceView.holder.setFormat(PixelFormat.TRANSLUCENT)
+ if (-1 == previewHandle) {
+ return
+ }
+ val surface = holder.surface
+ if (surface.isValid) {
+ if (-1 == SDKGuider.g_sdkGuider.m_comPreviewGuider.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.g_sdkGuider.m_comPreviewGuider.RealPlaySurfaceChanged_jni(
+ previewHandle, 0, null
+ )
+ ) {
+ Log.d(kTag, "surfaceCreated: ${MessageCodeHub.getErrorCode()}")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
index 5dff823..513db5e 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
@@ -151,14 +151,13 @@
fenceTextView.setOnClickListener {
BottomActionSheet.Builder()
.setContext(this)
- .setActionItemTitle(arrayListOf("区域规划", "监控角度", "云台角度"))
+ .setActionItemTitle(arrayListOf("监控区域", "云台角度"))
.setItemTextColor(R.color.mainThemeColor.convertColor(this))
.setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener {
override fun onActionItemClick(position: Int) {
when (position) {
- 0 -> ""
- 1 -> navigatePageTo()
- 2 -> navigatePageTo()
+ 0 -> navigatePageTo()
+ 1 -> navigatePageTo()
}
}
}).build().show()
diff --git a/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
new file mode 100644
index 0000000..d3a8181
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
@@ -0,0 +1,39 @@
+package com.casic.br.operationsite.vm
+
+import androidx.lifecycle.MutableLiveData
+import com.casic.br.operationsite.base.BaseApplication
+import com.casic.br.operationsite.extensions.separateResponseCode
+import com.casic.br.operationsite.extensions.toErrorMessage
+import com.casic.br.operationsite.model.CommonResultModel
+import com.casic.br.operationsite.retrofit.RetrofitServiceManager
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import com.pengxh.kt.lite.extensions.launch
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.vm.BaseViewModel
+import com.pengxh.kt.lite.vm.LoadState
+
+class RegionViewModel : BaseViewModel() {
+
+ private val gson by lazy { Gson() }
+ val postResult = MutableLiveData()
+
+ fun postRegion(code: String, color: String, position: String) = launch({
+ loadState.value = LoadState.Loading
+ val response = RetrofitServiceManager.postRegion(code, color, position)
+ val responseCode = response.separateResponseCode()
+ if (responseCode == 200) {
+ loadState.value = LoadState.Success
+ postResult.value = gson.fromJson(
+ response, object : TypeToken() {}.type
+ )
+ } else {
+ loadState.value = LoadState.Fail
+ response.toErrorMessage().show(BaseApplication.get())
+ }
+ }, {
+ loadState.value = LoadState.Fail
+ it.cause.toString().show(BaseApplication.get())
+ it.printStackTrace()
+ })
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt b/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt
new file mode 100644
index 0000000..72b7d5e
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt
@@ -0,0 +1,136 @@
+package com.casic.br.operationsite.widgets
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import com.casic.br.operationsite.model.Point
+import com.pengxh.kt.lite.extensions.dp2px
+import com.pengxh.kt.lite.extensions.getScreenWidth
+
+class VideoRegionView(private val ctx: Context, attrs: AttributeSet) : View(ctx, attrs) {
+
+ private val routePath: Path = Path()
+ private val rectPath: Path = Path()
+ private val routePaint: Paint = Paint()
+ private val borderPaint: Paint = Paint()
+ private var routes = ArrayList()
+
+ init {
+ routePaint.isAntiAlias = true
+ routePaint.color = Color.RED
+ routePaint.style = Paint.Style.STROKE
+ routePaint.strokeWidth = 7f //设置线宽
+ routePaint.isAntiAlias = true
+
+ borderPaint.isAntiAlias = true
+ borderPaint.color = Color.BLUE
+ borderPaint.style = Paint.Style.STROKE
+ borderPaint.strokeWidth = 7f //设置线宽
+ borderPaint.isAntiAlias = true
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ canvas.drawPath(routePath, routePaint)
+
+ canvas.drawPath(rectPath, borderPaint)
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+
+ val x = event.x
+ val y = event.y
+ routes.add(Point(x, y))
+
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> routePath.moveTo(x, y)
+ MotionEvent.ACTION_MOVE -> routePath.lineTo(x, y)
+ MotionEvent.ACTION_UP -> {
+ routePath.lineTo(x, y)
+
+ /**
+ * 找出最大的(x1,y1)和最小的(x2,y2)
+ *
+ * 左上(x2,y2)
+ * 右上(x1,y2)
+ * 左下(x2,y1)
+ * 右下(x1,y1)
+ * */
+ val sortedX = routes.sortedBy { point -> point.x }
+ val sortedY = routes.sortedBy { point -> point.y }
+ val xMaxPoint = sortedX.last()
+ val xMinPoint = sortedX.first()
+
+ val yMaxPoint = sortedY.last()
+ val yMinPoint = sortedY.first()
+
+ /**
+ * 画出外接矩形
+ * */
+ val leftTop = Point(xMinPoint.x, yMinPoint.y)
+ val rightTop = Point(xMaxPoint.x, yMinPoint.y)
+ val leftBottom = Point(xMinPoint.x, yMaxPoint.y)
+ val rightBottom = Point(xMaxPoint.x, yMaxPoint.y)
+ rectPath.moveTo(leftTop.x, leftTop.y)
+ rectPath.lineTo(rightTop.x, rightTop.y)
+ rectPath.lineTo(rightBottom.x, rightBottom.y)
+ rectPath.lineTo(leftBottom.x, leftBottom.y)
+ rectPath.lineTo(leftTop.x, leftTop.y)
+
+ /**
+ * 计算出点的相对位置返回给一体机计算
+ * */
+ val width = ctx.getScreenWidth() - 14f.dp2px(ctx)
+ val height = 855
+
+ /**
+ * 区域
+ * */
+ if (region.isNotEmpty()) {
+ region.clear()
+ }
+ region.add(Point(leftTop.x / width, leftTop.y / height))
+ region.add(Point(rightTop.x / width, rightTop.y / height))
+ region.add(Point(leftBottom.x / width, leftBottom.y / height))
+ region.add(Point(rightBottom.x / width, rightBottom.y / height))
+
+ /**
+ * 点集合
+ * */
+ if (points.isNotEmpty()) {
+ points.clear()
+ }
+ points.add(floatArrayOf(leftTop.x / width, leftTop.y / height))
+ points.add(floatArrayOf(rightTop.x / width, rightTop.y / height))
+ points.add(floatArrayOf(leftBottom.x / width, leftBottom.y / height))
+ points.add(floatArrayOf(rightBottom.x / width, rightBottom.y / height))
+ }
+ }
+ invalidate()
+ return true
+ }
+
+ fun clearRoutePath() {
+ routePath.reset()
+ rectPath.reset()
+ routes.clear()
+ invalidate()
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private var region = ArrayList()
+
+ fun getConfirmedRegion(): ArrayList = region
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private var points = ArrayList()
+
+ fun getConfirmedPoints(): ArrayList = points
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_right.xml b/app/src/main/res/drawable/ic_right.xml
new file mode 100644
index 0000000..e5aafca
--- /dev/null
+++ b/app/src/main/res/drawable/ic_right.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_hikvision.xml b/app/src/main/res/layout/activity_hikvision.xml
index 752d62c..8b4f9fc 100644
--- a/app/src/main/res/layout/activity_hikvision.xml
+++ b/app/src/main/res/layout/activity_hikvision.xml
@@ -20,10 +20,10 @@
android:layout_marginHorizontal="@dimen/dp_7"
android:layout_marginTop="@dimen/dp_7"
android:background="@drawable/bg_solid_layout_white_radius_10"
- android:orientation="vertical">
+ android:orientation="horizontal">
+ android:orientation="horizontal">
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_video_region.xml b/app/src/main/res/layout/activity_video_region.xml
new file mode 100644
index 0000000..35a7996
--- /dev/null
+++ b/app/src/main/res/layout/activity_video_region.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a966f73..84ac96a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -63,6 +63,7 @@
+
.reformatFloatArray(): String {
+ if (this.isEmpty()) return ""
+ val builder = StringBuilder()
+ //循环遍历元素,同时得到元素index(下标)
+ this.forEachIndexed { index, it ->
+ if (index == this.size - 1) {
+ builder.append(it.toJson())
+ } else {
+ builder.append(it.toJson()).append(",")
+ }
+ }
+ return builder.toString()
+}
+
+fun addAll(vararg args: String): ArrayList {
+ val result = ArrayList()
+ args.forEach {
+ result.add(it)
+ }
+ return result
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/model/Point.kt b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
new file mode 100644
index 0000000..fae29c7
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/model/Point.kt
@@ -0,0 +1,3 @@
+package com.casic.br.operationsite.model
+
+data class Point(val x: Float, val y: Float)
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
index a6bcfb4..54093a7 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitService.kt
@@ -90,4 +90,10 @@
*/
@POST("/worker/add")
suspend fun enter(@Header("token") token: String, @Body requestBody: RequestBody): String
+
+ /**
+ * 提交算法区域
+ */
+ @POST("/set_position")
+ suspend fun postRegion(@Body requestBody: RequestBody): String
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
index 7582a1f..eb6a592 100644
--- a/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
+++ b/app/src/main/java/com/casic/br/operationsite/retrofit/RetrofitServiceManager.kt
@@ -17,13 +17,19 @@
object RetrofitServiceManager {
+ private val gson by lazy { Gson() }
+
private val api by lazy {
val httpConfig = SaveKeyValues.getValue(
LocaleConstant.DEFAULT_SERVER_CONFIG, LocaleConstant.SERVER_BASE_URL
) as String
RetrofitFactory.createRetrofit(httpConfig)
}
- private val gson by lazy { Gson() }
+
+ private val regionApi by lazy {
+ val httpConfig = "http://192.168.10.104:5000"
+ RetrofitFactory.createRetrofit(httpConfig)
+ }
/**
* 验证PublicKey
@@ -171,4 +177,16 @@
)
return api.enter(AuthenticationHelper.token!!, requestBody)
}
+
+ suspend fun postRegion(code: String, color: String, position: String): String {
+ val param = JsonObject()
+ param.addProperty("code", code)
+ param.addProperty("color", color)
+ param.addProperty("position", position)
+
+ val requestBody = param.toString().toRequestBody(
+ "application/json;charset=UTF-8".toMediaType()
+ )
+ return regionApi.postRegion(requestBody)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
index f40c29f..9fc0a85 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/HikVisionActivity.kt
@@ -13,6 +13,7 @@
import android.util.Log
import android.view.SurfaceHolder
import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.addAll
import com.casic.br.operationsite.extensions.getChannel
import com.casic.br.operationsite.extensions.initLayoutImmersionBar
import com.casic.br.operationsite.model.DeviceConfigModel
@@ -26,6 +27,7 @@
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.convertColor
import com.pengxh.kt.lite.extensions.getSystemService
+import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.widget.SteeringWheelController
import com.pengxh.kt.lite.widget.dialog.BottomActionSheet
@@ -208,6 +210,10 @@
}
}
})
+
+ videoRegionLayout.setOnClickListener {
+ navigatePageTo(addAll(hostModel.host, hostModel.port.toString()))
+ }
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
diff --git a/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
new file mode 100644
index 0000000..33f6970
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/view/VideoRegionActivity.kt
@@ -0,0 +1,203 @@
+package com.casic.br.operationsite.view
+
+import android.graphics.PixelFormat
+import android.util.Log
+import android.view.SurfaceHolder
+import androidx.lifecycle.ViewModelProvider
+import com.casic.br.operationsite.R
+import com.casic.br.operationsite.extensions.getChannel
+import com.casic.br.operationsite.extensions.initLayoutImmersionBar
+import com.casic.br.operationsite.extensions.reformatFloatArray
+import com.casic.br.operationsite.utils.LocaleConstant
+import com.casic.br.operationsite.utils.hk.MessageCodeHub
+import com.casic.br.operationsite.utils.hk.SDKGuider
+import com.casic.br.operationsite.vm.RegionViewModel
+import com.gyf.immersionbar.ImmersionBar
+import com.hikvision.netsdk.NET_DVR_PREVIEWINFO
+import com.pengxh.kt.lite.base.KotlinBaseActivity
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.utils.Constant
+import kotlinx.android.synthetic.main.activity_video_region.*
+import kotlinx.android.synthetic.main.include_base_title.leftBackView
+import kotlinx.android.synthetic.main.include_base_title.titleView
+import kotlinx.android.synthetic.main.include_option_title.*
+
+class VideoRegionActivity : KotlinBaseActivity(), SurfaceHolder.Callback {
+
+ private val kTag = "VideoRegionActivity"
+ private val context = this@VideoRegionActivity
+ 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 lateinit var params: ArrayList
+ private lateinit var regionViewModel: RegionViewModel
+
+ override fun initData() {
+ params = intent.getStringArrayListExtra(Constant.INTENT_PARAM)!!
+
+ regionViewModel = ViewModelProvider(this)[RegionViewModel::class.java]
+ regionViewModel.postResult.observe(this) {
+ if (it.code == 200) {
+ "区域配置成功".show(this)
+ finish()
+ }
+ }
+ }
+
+ override fun initEvent() {
+ openCameraButton.setOnClickListener {
+ openHikVisionCamera(params[0], params[1])
+ }
+
+ closeCameraButton.setOnClickListener {
+ if (!SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)) {
+ return@setOnClickListener
+ }
+ previewHandle = -1
+ isPreviewSuccess = false
+
+ regionView.clearRoutePath()
+ }
+
+ configButton.setOnClickListener {
+ val region = regionView.getConfirmedPoints()
+ val data = region.reformatFloatArray()
+
+ //发送数据的时候需要断开视频
+ regionViewModel.postRegion("11,12", "#FF0000", data)
+ }
+ }
+
+ override fun initLayoutView(): Int = R.layout.activity_video_region
+
+ override fun observeRequestState() {
+
+ }
+
+ override fun setupTopBarLayout() {
+ ImmersionBar.with(this).statusBarDarkFont(false)
+ .statusBarColor(R.color.mainThemeColor).init()
+ initLayoutImmersionBar(rootView)
+
+ leftBackView.setOnClickListener { finish() }
+ titleView.text = "区域规划"
+ rightOptionView.text = "重画"
+ rightOptionView.setOnClickListener {
+ regionView.clearRoutePath()
+ }
+ }
+
+ private fun openHikVisionCamera(host: String, port: String) {
+ val deviceItem = SDKGuider.g_sdkGuider.m_comDMGuider.DeviceItem()
+ deviceItem.m_szDevName = ""
+ deviceItem.m_struNetInfo = SDKGuider.g_sdkGuider.m_comDMGuider.DevNetInfo(
+ host, port, LocaleConstant.HK_NET_USERNAME, LocaleConstant.HK_NET_PASSWORD
+ )
+ if (deviceItem.m_szDevName.isEmpty()) {
+ deviceItem.m_szDevName = deviceItem.m_struNetInfo.m_szIp
+ }
+
+ val loginV40Jna = SDKGuider.g_sdkGuider.m_comDMGuider.login_v40_jna(
+ deviceItem.m_szDevName, deviceItem.m_struNetInfo
+ )
+ if (loginV40Jna) {
+ //配置设备通道
+ try {
+ val deviceInfo = SDKGuider.g_sdkGuider.m_comDMGuider.devList[0]
+ returnUserID = deviceInfo.m_lUserID
+
+ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt()
+ startAChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum +
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256
+ startDChannel =
+ deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt()
+
+ var iAnalogStartChan = startAChannel
+ var iDigitalStartChan = startDChannel
+
+ val channelList = ArrayList()
+
+ 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()
+ streamList.add("main_stream")
+ streamList.add("sub_stream")
+ streamList.add("third_stream")
+
+ //开始预览
+ if (previewHandle != -1) {
+ SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_Stop_jni(previewHandle)
+ }
+ val strutPlayInfo = NET_DVR_PREVIEWINFO()
+ strutPlayInfo.lChannel = selectChannel
+ strutPlayInfo.dwStreamType = 1
+ strutPlayInfo.bBlocked = 1
+ strutPlayInfo.hHwnd = videoSurfaceView.holder
+ previewHandle = SDKGuider.g_sdkGuider.m_comPreviewGuider.RealPlay_V40_jni(
+ returnUserID, strutPlayInfo, null
+ )
+ if (previewHandle < 0) {
+ Log.d(
+ kTag,
+ "configDevice: NET_DVR_RealPlay_V40 fail, Err:${MessageCodeHub.getErrorCode()}"
+ )
+ return
+ }
+ isPreviewSuccess = true
+ } catch (e: IndexOutOfBoundsException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ videoSurfaceView.holder.setFormat(PixelFormat.TRANSLUCENT)
+ if (-1 == previewHandle) {
+ return
+ }
+ val surface = holder.surface
+ if (surface.isValid) {
+ if (-1 == SDKGuider.g_sdkGuider.m_comPreviewGuider.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.g_sdkGuider.m_comPreviewGuider.RealPlaySurfaceChanged_jni(
+ previewHandle, 0, null
+ )
+ ) {
+ Log.d(kTag, "surfaceCreated: ${MessageCodeHub.getErrorCode()}")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
index 5dff823..513db5e 100644
--- a/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
+++ b/app/src/main/java/com/casic/br/operationsite/view/WorkSiteTabActivity.kt
@@ -151,14 +151,13 @@
fenceTextView.setOnClickListener {
BottomActionSheet.Builder()
.setContext(this)
- .setActionItemTitle(arrayListOf("区域规划", "监控角度", "云台角度"))
+ .setActionItemTitle(arrayListOf("监控区域", "云台角度"))
.setItemTextColor(R.color.mainThemeColor.convertColor(this))
.setOnActionSheetListener(object : BottomActionSheet.OnActionSheetListener {
override fun onActionItemClick(position: Int) {
when (position) {
- 0 -> ""
- 1 -> navigatePageTo()
- 2 -> navigatePageTo()
+ 0 -> navigatePageTo()
+ 1 -> navigatePageTo()
}
}
}).build().show()
diff --git a/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
new file mode 100644
index 0000000..d3a8181
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/vm/RegionViewModel.kt
@@ -0,0 +1,39 @@
+package com.casic.br.operationsite.vm
+
+import androidx.lifecycle.MutableLiveData
+import com.casic.br.operationsite.base.BaseApplication
+import com.casic.br.operationsite.extensions.separateResponseCode
+import com.casic.br.operationsite.extensions.toErrorMessage
+import com.casic.br.operationsite.model.CommonResultModel
+import com.casic.br.operationsite.retrofit.RetrofitServiceManager
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import com.pengxh.kt.lite.extensions.launch
+import com.pengxh.kt.lite.extensions.show
+import com.pengxh.kt.lite.vm.BaseViewModel
+import com.pengxh.kt.lite.vm.LoadState
+
+class RegionViewModel : BaseViewModel() {
+
+ private val gson by lazy { Gson() }
+ val postResult = MutableLiveData()
+
+ fun postRegion(code: String, color: String, position: String) = launch({
+ loadState.value = LoadState.Loading
+ val response = RetrofitServiceManager.postRegion(code, color, position)
+ val responseCode = response.separateResponseCode()
+ if (responseCode == 200) {
+ loadState.value = LoadState.Success
+ postResult.value = gson.fromJson(
+ response, object : TypeToken() {}.type
+ )
+ } else {
+ loadState.value = LoadState.Fail
+ response.toErrorMessage().show(BaseApplication.get())
+ }
+ }, {
+ loadState.value = LoadState.Fail
+ it.cause.toString().show(BaseApplication.get())
+ it.printStackTrace()
+ })
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt b/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt
new file mode 100644
index 0000000..72b7d5e
--- /dev/null
+++ b/app/src/main/java/com/casic/br/operationsite/widgets/VideoRegionView.kt
@@ -0,0 +1,136 @@
+package com.casic.br.operationsite.widgets
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Path
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import com.casic.br.operationsite.model.Point
+import com.pengxh.kt.lite.extensions.dp2px
+import com.pengxh.kt.lite.extensions.getScreenWidth
+
+class VideoRegionView(private val ctx: Context, attrs: AttributeSet) : View(ctx, attrs) {
+
+ private val routePath: Path = Path()
+ private val rectPath: Path = Path()
+ private val routePaint: Paint = Paint()
+ private val borderPaint: Paint = Paint()
+ private var routes = ArrayList()
+
+ init {
+ routePaint.isAntiAlias = true
+ routePaint.color = Color.RED
+ routePaint.style = Paint.Style.STROKE
+ routePaint.strokeWidth = 7f //设置线宽
+ routePaint.isAntiAlias = true
+
+ borderPaint.isAntiAlias = true
+ borderPaint.color = Color.BLUE
+ borderPaint.style = Paint.Style.STROKE
+ borderPaint.strokeWidth = 7f //设置线宽
+ borderPaint.isAntiAlias = true
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ canvas.drawPath(routePath, routePaint)
+
+ canvas.drawPath(rectPath, borderPaint)
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+
+ val x = event.x
+ val y = event.y
+ routes.add(Point(x, y))
+
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> routePath.moveTo(x, y)
+ MotionEvent.ACTION_MOVE -> routePath.lineTo(x, y)
+ MotionEvent.ACTION_UP -> {
+ routePath.lineTo(x, y)
+
+ /**
+ * 找出最大的(x1,y1)和最小的(x2,y2)
+ *
+ * 左上(x2,y2)
+ * 右上(x1,y2)
+ * 左下(x2,y1)
+ * 右下(x1,y1)
+ * */
+ val sortedX = routes.sortedBy { point -> point.x }
+ val sortedY = routes.sortedBy { point -> point.y }
+ val xMaxPoint = sortedX.last()
+ val xMinPoint = sortedX.first()
+
+ val yMaxPoint = sortedY.last()
+ val yMinPoint = sortedY.first()
+
+ /**
+ * 画出外接矩形
+ * */
+ val leftTop = Point(xMinPoint.x, yMinPoint.y)
+ val rightTop = Point(xMaxPoint.x, yMinPoint.y)
+ val leftBottom = Point(xMinPoint.x, yMaxPoint.y)
+ val rightBottom = Point(xMaxPoint.x, yMaxPoint.y)
+ rectPath.moveTo(leftTop.x, leftTop.y)
+ rectPath.lineTo(rightTop.x, rightTop.y)
+ rectPath.lineTo(rightBottom.x, rightBottom.y)
+ rectPath.lineTo(leftBottom.x, leftBottom.y)
+ rectPath.lineTo(leftTop.x, leftTop.y)
+
+ /**
+ * 计算出点的相对位置返回给一体机计算
+ * */
+ val width = ctx.getScreenWidth() - 14f.dp2px(ctx)
+ val height = 855
+
+ /**
+ * 区域
+ * */
+ if (region.isNotEmpty()) {
+ region.clear()
+ }
+ region.add(Point(leftTop.x / width, leftTop.y / height))
+ region.add(Point(rightTop.x / width, rightTop.y / height))
+ region.add(Point(leftBottom.x / width, leftBottom.y / height))
+ region.add(Point(rightBottom.x / width, rightBottom.y / height))
+
+ /**
+ * 点集合
+ * */
+ if (points.isNotEmpty()) {
+ points.clear()
+ }
+ points.add(floatArrayOf(leftTop.x / width, leftTop.y / height))
+ points.add(floatArrayOf(rightTop.x / width, rightTop.y / height))
+ points.add(floatArrayOf(leftBottom.x / width, leftBottom.y / height))
+ points.add(floatArrayOf(rightBottom.x / width, rightBottom.y / height))
+ }
+ }
+ invalidate()
+ return true
+ }
+
+ fun clearRoutePath() {
+ routePath.reset()
+ rectPath.reset()
+ routes.clear()
+ invalidate()
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private var region = ArrayList()
+
+ fun getConfirmedRegion(): ArrayList = region
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ private var points = ArrayList()
+
+ fun getConfirmedPoints(): ArrayList = points
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_right.xml b/app/src/main/res/drawable/ic_right.xml
new file mode 100644
index 0000000..e5aafca
--- /dev/null
+++ b/app/src/main/res/drawable/ic_right.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_hikvision.xml b/app/src/main/res/layout/activity_hikvision.xml
index 752d62c..8b4f9fc 100644
--- a/app/src/main/res/layout/activity_hikvision.xml
+++ b/app/src/main/res/layout/activity_hikvision.xml
@@ -20,10 +20,10 @@
android:layout_marginHorizontal="@dimen/dp_7"
android:layout_marginTop="@dimen/dp_7"
android:background="@drawable/bg_solid_layout_white_radius_10"
- android:orientation="vertical">
+ android:orientation="horizontal">
+ android:orientation="horizontal">
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_video_region.xml b/app/src/main/res/layout/activity_video_region.xml
new file mode 100644
index 0000000..35a7996
--- /dev/null
+++ b/app/src/main/res/layout/activity_video_region.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 64de5e8..92ba91d 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -86,6 +86,16 @@
- @color/mainBackColor
+
+
+