截图保存 录制视频
This commit is contained in:
parent
ebb61c87f0
commit
d179e541b6
BIN
hisense_dh.db
BIN
hisense_dh.db
Binary file not shown.
|
@ -4,6 +4,8 @@ import com.hazelcast.config.*
|
|||
import com.hisense.dahua_video.modules.device.Device
|
||||
import com.hisense.dahua_video.modules.device.DeviceChannel
|
||||
import com.hisense.dahua_video.modules.device.Organization
|
||||
import com.hisense.dahua_video.modules.media.ScreenshotPicture
|
||||
import com.hisense.dahua_video.modules.media.ScreenshotVideo
|
||||
import com.hisense.dahua_video.modules.monitor.MonitorUser
|
||||
import com.hisense.dahua_video.modules.monitor.MonitorUserToken
|
||||
import com.hisense.dahua_video.modules.sys.SysUser
|
||||
|
@ -167,6 +169,8 @@ class MainVerticle : AbstractVerticle() {
|
|||
val organization = Organization()
|
||||
val device = Device()
|
||||
val deviceChannel = DeviceChannel()
|
||||
val screenshotPicture = ScreenshotPicture()
|
||||
val screenshotVideo = ScreenshotVideo()
|
||||
logger.info("开始创表" + LocalDateTime.now().toString())
|
||||
Database.connect(
|
||||
HikariDataSource(dbConfig)
|
||||
|
@ -174,14 +178,25 @@ class MainVerticle : AbstractVerticle() {
|
|||
logger.info("连接完成" + LocalDateTime.now().toString())
|
||||
transaction {
|
||||
addLogger(StdOutSqlLogger)
|
||||
SchemaUtils.create(monitorUser, monitorUserToken, sysUser, organization, device, deviceChannel)
|
||||
SchemaUtils.create(
|
||||
monitorUser,
|
||||
monitorUserToken,
|
||||
sysUser,
|
||||
organization,
|
||||
device,
|
||||
deviceChannel,
|
||||
screenshotPicture,
|
||||
screenshotVideo
|
||||
)
|
||||
SchemaUtils.createMissingTablesAndColumns(
|
||||
monitorUser,
|
||||
monitorUserToken,
|
||||
sysUser,
|
||||
organization,
|
||||
device,
|
||||
deviceChannel
|
||||
deviceChannel,
|
||||
screenshotPicture,
|
||||
screenshotVideo
|
||||
)
|
||||
logger.info("创表成功" + LocalDateTime.now().toString())
|
||||
}
|
||||
|
|
|
@ -83,6 +83,16 @@ enum class EventBusAddress(val address: String) {
|
|||
/**
|
||||
* 获取在线设备通道
|
||||
*/
|
||||
SYS_DEVICE_CHANNEL_ONLINE("MSG://EVENT/BUS/SQL/SYS/SYS_DEVICE_CHANNEL_ONLINE")
|
||||
SYS_DEVICE_CHANNEL_ONLINE("MSG://EVENT/BUS/SQL/SYS/SYS_DEVICE_CHANNEL_ONLINE"),
|
||||
|
||||
/**
|
||||
* 设备通道截图保存
|
||||
*/
|
||||
SYS_DEVICE_CHANNEL_SCREENSHOT_PICTURE_SAVE("MSG://EVENT/BUS/SQL/SYS/SYS_DEVICE_CHANNEL_SCREENSHOT_PICTURE_SAVE"),
|
||||
|
||||
/**
|
||||
* 设备通道截取视频
|
||||
*/
|
||||
SYS_DEVICE_CHANNEL_SCREENSHOT_VIDEO_SAVE("MSG://EVENT/BUS/SQL/SYS/SYS_DEVICE_CHANNEL_SCREENSHOT_VIDEO_SAVE")
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package com.hisense.dahua_video.dao
|
||||
|
||||
import com.hisense.dahua_video.consts.EventBusAddress
|
||||
import com.hisense.dahua_video.modules.device.DeviceChannel
|
||||
import com.hisense.dahua_video.modules.media.ScreenshotPicture
|
||||
import io.vertx.core.Vertx
|
||||
import io.vertx.core.eventbus.EventBus
|
||||
import io.vertx.core.impl.logging.Logger
|
||||
import io.vertx.core.impl.logging.LoggerFactory
|
||||
import io.vertx.core.json.JsonObject
|
||||
import org.jetbrains.exposed.sql.StdOutSqlLogger
|
||||
import org.jetbrains.exposed.sql.addLogger
|
||||
import org.jetbrains.exposed.sql.insert
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import java.time.LocalDateTime
|
||||
|
||||
|
||||
/**
|
||||
* 截图 dao
|
||||
*/
|
||||
class ScreenshotPictureDao(event_: EventBus?, vertx: Vertx) {
|
||||
private val logger: Logger = LoggerFactory.getLogger(ScreenshotPictureDao::class.java)
|
||||
private val cpuNum = Runtime.getRuntime().availableProcessors()
|
||||
private var event: EventBus? = null
|
||||
private var vertx: Vertx? = null
|
||||
private val screenshotPicture = ScreenshotPicture()
|
||||
private val deviceChannel = DeviceChannel()
|
||||
|
||||
init {
|
||||
this.event = event_
|
||||
this.vertx = vertx
|
||||
savePicture()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存截图图片
|
||||
*/
|
||||
private fun savePicture() {
|
||||
/**
|
||||
* 只处理本地事件
|
||||
*/
|
||||
event!!.localConsumer<JsonObject>(EventBusAddress.SYS_DEVICE_CHANNEL_SCREENSHOT_PICTURE_SAVE.address)
|
||||
?.handler { replay ->
|
||||
val message = replay.body()
|
||||
logger.info("savePicture:" + message.encode())
|
||||
val channelId = transaction {
|
||||
addLogger(StdOutSqlLogger)
|
||||
deviceChannel.slice(deviceChannel.id).select { deviceChannel.channelNo eq message.getString("channelNo") }
|
||||
.withDistinct().map { it[deviceChannel.id] }.firstOrNull()?.value
|
||||
}
|
||||
transaction {
|
||||
addLogger(StdOutSqlLogger)
|
||||
screenshotPicture.insert {
|
||||
it[screenshotPicture.channelId] = channelId!!.toInt()
|
||||
it[screenshotPicture.channelNo] = message.getString("channelNo")
|
||||
it[screenshotPicture.createTime] = LocalDateTime.now()
|
||||
it[screenshotPicture.filePath] = message.getString("filePath")
|
||||
it[screenshotPicture.fileSize] = message.getLong("fileSize")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.hisense.dahua_video.dao
|
||||
|
||||
import io.vertx.core.Vertx
|
||||
import io.vertx.core.eventbus.EventBus
|
||||
import io.vertx.core.impl.logging.Logger
|
||||
import io.vertx.core.impl.logging.LoggerFactory
|
||||
|
||||
/**
|
||||
* 截取短视频功能dao
|
||||
*/
|
||||
class ScreenshotVideoDao(event_: EventBus?, vertx: Vertx) {
|
||||
private val logger: Logger = LoggerFactory.getLogger(ScreenshotVideoDao::class.java)
|
||||
private val cpuNum = Runtime.getRuntime().availableProcessors()
|
||||
private var event: EventBus? = null
|
||||
private var vertx: Vertx? = null
|
||||
|
||||
init {
|
||||
this.event = event_
|
||||
this.vertx = vertx
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* 第三方设备、设备通道
|
||||
*/
|
||||
package com.hisense.dahua_video.modules.device;
|
|
@ -0,0 +1,17 @@
|
|||
package com.hisense.dahua_video.modules.media
|
||||
|
||||
import com.hisense.dahua_video.modules.device.DeviceChannel
|
||||
import org.jetbrains.exposed.dao.id.IntIdTable
|
||||
import org.jetbrains.exposed.sql.javatime.datetime
|
||||
|
||||
/**
|
||||
* 设备通道截图保存
|
||||
*/
|
||||
class ScreenshotPicture : IntIdTable("sys_device_channel_screenshot_picture") {
|
||||
private val deviceChannel = DeviceChannel()
|
||||
val channelId = integer("channel_id").references(deviceChannel.id).index() // 所属设备通道(外键)。
|
||||
val channelNo = text("channel_no") // 通道编码
|
||||
val createTime = datetime("create_time").nullable() // 创建时间
|
||||
val filePath = text("file_path") // 文件本地路径
|
||||
val fileSize = long("file_size") // 文件大小(单位.比特)
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.hisense.dahua_video.modules.media
|
||||
|
||||
import com.hisense.dahua_video.modules.device.DeviceChannel
|
||||
import org.jetbrains.exposed.dao.id.IntIdTable
|
||||
import org.jetbrains.exposed.sql.javatime.datetime
|
||||
|
||||
|
||||
/**
|
||||
* 视频通道截取视频
|
||||
*/
|
||||
class ScreenshotVideo : IntIdTable("sys_device_channel_screenshot_video") {
|
||||
private val deviceChannel = DeviceChannel()
|
||||
val channelId = integer("channel_id").references(deviceChannel.id).index() // 所属设备通道(外键)。
|
||||
val channelNo = text("channel_no") // 通道编码
|
||||
val createTime = datetime("create_time").nullable() // 创建时间
|
||||
val filePath = text("file_path") // 文件本地路径
|
||||
val fileSize = long("file_size") // 文件大小(单位.比特)
|
||||
val duration = long("duration") // 文件时长
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* 第三方通道截取媒体
|
||||
*/
|
||||
package com.hisense.dahua_video.modules.media;
|
|
@ -28,6 +28,8 @@ class ScreenshotUtil(vertx: Vertx) {
|
|||
private val logger = LoggerFactory.getLogger(DevicesManagerUtil::class.java)
|
||||
private val cpuNum = Runtime.getRuntime().availableProcessors()
|
||||
|
||||
var taskCount = AtomicInteger(0)
|
||||
|
||||
private var vertx: Vertx
|
||||
private var event: EventBus? = null
|
||||
private var client: WebClient? = null
|
||||
|
@ -40,6 +42,7 @@ class ScreenshotUtil(vertx: Vertx) {
|
|||
record =
|
||||
vertx.orCreateContext.config().getString("recroot", System.getProperty("user.dir") + File.separator + "record")
|
||||
screenshot()
|
||||
recordVideo()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,8 +101,6 @@ class ScreenshotUtil(vertx: Vertx) {
|
|||
* 截图通道画面
|
||||
*/
|
||||
private fun screenshot() {
|
||||
var taskCount = AtomicInteger(0)
|
||||
|
||||
/**
|
||||
* 执行截图
|
||||
*/
|
||||
|
@ -132,13 +133,20 @@ class ScreenshotUtil(vertx: Vertx) {
|
|||
File(filePath).mkdir()
|
||||
}
|
||||
val fileName =
|
||||
record + File.separator + screenshot.getString("channelId") + File.separator + screenshot.getString("channelId") + "_" + DateTimeFormatter.ofPattern(
|
||||
record + File.separator + screenshot.getString("channelId") +
|
||||
File.separator + screenshot.getString("channelId") + "_" + DateTimeFormatter.ofPattern(
|
||||
"yyyyMMddHHmmss-HHmmss"
|
||||
)
|
||||
.format(LocalDateTime.now()) + ".jpg"
|
||||
logger.info("保存地址:$fileName")
|
||||
ImageIO.write(bufferedImage, "jpg", File(fileName))
|
||||
logger.info("图片保存成功:$fileName")
|
||||
event!!.publish(
|
||||
EventBusAddress.SYS_DEVICE_CHANNEL_SCREENSHOT_PICTURE_SAVE.address,
|
||||
JsonObject().put("fileSize", File(fileName).length())
|
||||
.put("channelNo", screenshot.getString("channelId"))
|
||||
.put("filePath", fileName)
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -150,6 +158,7 @@ class ScreenshotUtil(vertx: Vertx) {
|
|||
grabber.stop()
|
||||
grabber.release()
|
||||
taskCount.getAndAdd(-1)
|
||||
logger.info("本地ffmpeg工作队列数量:${taskCount.get()}")
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
@ -198,4 +207,73 @@ class ScreenshotUtil(vertx: Vertx) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*进行视频录制
|
||||
*/
|
||||
private fun recordVideo() {
|
||||
/**
|
||||
* 执行截图
|
||||
*/
|
||||
fun recordAction(screenshot: JsonObject): JsonObject {
|
||||
taskCount.getAndAdd(1)
|
||||
val url = screenshot.getString("url")
|
||||
logger.info("抓取url:$url")
|
||||
val result = JsonObject()
|
||||
result.put("startTime", LocalDateTime.now().toString())
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
val grabber = FFmpegFrameGrabber(url)// 使用协程
|
||||
val converter = Java2DFrameConverter()
|
||||
try {
|
||||
if (screenshot.getString("scheme") == MonitorScheme.RTSP.scheme) {
|
||||
grabber.setOption("rtsp_transport", "tcp")
|
||||
}
|
||||
grabber.setOption("stimeout", "2000000")
|
||||
grabber.start()
|
||||
logger.info("grabber启动成功")
|
||||
while (true) {
|
||||
when (val frame = grabber.grabImage()) {
|
||||
null -> {
|
||||
logger.info("截图取帧失败")
|
||||
}
|
||||
|
||||
else -> {
|
||||
val bufferedImage = converter.getBufferedImage(frame)
|
||||
val filePath = record + File.separator + screenshot.getString("channelId")
|
||||
if (!File(filePath).exists()) {
|
||||
File(filePath).mkdir()
|
||||
}
|
||||
val fileName =
|
||||
record + File.separator + screenshot.getString("channelId") +
|
||||
File.separator + screenshot.getString("channelId") + "_" + DateTimeFormatter.ofPattern(
|
||||
"yyyyMMddHHmmss-HHmmss"
|
||||
)
|
||||
.format(LocalDateTime.now()) + ".jpg"
|
||||
logger.info("保存地址:$fileName")
|
||||
ImageIO.write(bufferedImage, "jpg", File(fileName))
|
||||
logger.info("图片保存成功:$fileName")
|
||||
event!!.publish(
|
||||
EventBusAddress.SYS_DEVICE_CHANNEL_SCREENSHOT_PICTURE_SAVE.address,
|
||||
JsonObject().put("fileSize", File(fileName).length())
|
||||
.put("channelNo", screenshot.getString("channelId"))
|
||||
.put("filePath", fileName)
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("抓取截图·失败·", e)
|
||||
} finally {
|
||||
converter.close()
|
||||
grabber.stop()
|
||||
grabber.release()
|
||||
taskCount.getAndAdd(-1)
|
||||
logger.info("本地ffmpeg工作队列数量:${taskCount.get()}")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@ class SqlFactoryVerticle : CoroutineVerticle() {
|
|||
shareDate.getLocalLock(EventBusAddress.SYS_MONITOR_USER_TOKEN_SAVE_NEW.address)
|
||||
.onSuccess {
|
||||
val monitorUserTokenDao = MonitorUserTokenDao(this.event)
|
||||
val cleanfailtokenTaskId = vertx.setPeriodic(5 * 60 * 1000) { // 每间隔5分钟进行一次失效token清理
|
||||
|
||||
val cleanfailtokenTaskId = vertx.setPeriodic(30 * 60 * 1000) { // 每间隔30分钟进行一次失效token清理
|
||||
logger.info("--------------------------定时清理失效token----------------------")
|
||||
event!!.publish(EventBusAddress.SYS_MONITOR_CLEANFAILTOKEN.address, JsonObject())
|
||||
}
|
||||
|
@ -42,6 +43,8 @@ class SqlFactoryVerticle : CoroutineVerticle() {
|
|||
.onSuccess {
|
||||
val deviceDao = DeviceDao(this.event, this.vertx)
|
||||
val deviceChannelDao = DeviceChannelDao(this.event)
|
||||
val screenshotPictureDao = ScreenshotPictureDao(this.event, this.vertx)
|
||||
val screenshotVideoDao = ScreenshotVideoDao(this.event, this.vertx)
|
||||
}
|
||||
startFuture?.complete()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue