feat(webcam): 新增摄像头功能
- 添加摄像头相关类和方法,实现摄像头图像采集和传输- 新增 CamSocketServer 类处理摄像头数据传输 - 修改 Main 类,添加摄像头任务和 Socket 连接 - 更新 Operational 类,增加摄像头操作处理 - 新增 Control 类统一控制摄像头状态 - 修改 TrayFrame 和 TrayFrameUtf8 类,支持摄像头服务启动和停止- 新增 WatchDog 类监控摄像头状态并自动重启任务
This commit is contained in:
parent
4d0a511186
commit
6cc8f1913b
Binary file not shown.
21
pom.xml
21
pom.xml
|
@ -64,7 +64,26 @@
|
||||||
<artifactId>slf4j-simple</artifactId>
|
<artifactId>slf4j-simple</artifactId>
|
||||||
<version>2.0.13</version>
|
<version>2.0.13</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.eduramiba</groupId>
|
||||||
|
<artifactId>webcam-capture-driver-native</artifactId>
|
||||||
|
<version>1.2.0-8</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-cli</groupId>
|
||||||
|
<artifactId>commons-cli</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.humble</groupId>
|
||||||
|
<artifactId>humble-video-all</artifactId>
|
||||||
|
<version>0.3.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.sarxos</groupId>
|
||||||
|
<artifactId>webcam-capture</artifactId>
|
||||||
|
<version>0.3.12</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<!-- <build>-->
|
<!-- <build>-->
|
||||||
|
|
|
@ -2,16 +2,28 @@ package org.aohe;
|
||||||
|
|
||||||
import com.formdev.flatlaf.FlatDarculaLaf;
|
import com.formdev.flatlaf.FlatDarculaLaf;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.aohe.show.TrayFrame;
|
import org.aohe.constant.SocketEnum;
|
||||||
|
import org.aohe.daemon.WatchDog;
|
||||||
import org.aohe.show.TrayFrameUtf8;
|
import org.aohe.show.TrayFrameUtf8;
|
||||||
|
import org.aohe.web.SocketUtils;
|
||||||
|
import org.aohe.webcam.WebcamShowTask;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import org.aohe.constant.Control;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
UIManager.setLookAndFeel(new FlatDarculaLaf());
|
UIManager.setLookAndFeel(new FlatDarculaLaf());
|
||||||
log.info("启动成功");
|
log.info("启动成功");
|
||||||
new TrayFrameUtf8().initSystemTrayUTF8();
|
SocketUtils.start(SocketEnum.CAM_SOCKET);
|
||||||
|
Control.WEBCAM_SHOW_TASK = new WebcamShowTask();
|
||||||
|
Control.WEBCAM_SHOW_TASK.start();
|
||||||
|
WatchDog watchDog = new WatchDog();
|
||||||
|
watchDog.setDaemon(true);
|
||||||
|
watchDog.start();
|
||||||
|
TrayFrameUtf8.initSystemTrayUTF8();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package org.aohe.constant;
|
||||||
|
|
||||||
|
import org.aohe.webcam.WebcamShowTask;
|
||||||
|
import org.aohe.webcam.WebcamWebTask;
|
||||||
|
|
||||||
|
public class Control {
|
||||||
|
public static boolean SHOW_CAMERA = false;
|
||||||
|
|
||||||
|
public static WebcamShowTask WEBCAM_SHOW_TASK;
|
||||||
|
|
||||||
|
public static WebcamWebTask WEBCAM_WEB_TASK;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.aohe.constant;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum SocketEnum {
|
||||||
|
CAM_SOCKET("CAM_SOCKET", 8998),
|
||||||
|
SCAN_SOCKET("SCAN_SOCKET", 8997);
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
SocketEnum(String name, int port) {
|
||||||
|
this.name = name;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import org.aohe.core.twain.*;
|
||||||
import org.aohe.exceptions.TwainException;
|
import org.aohe.exceptions.TwainException;
|
||||||
import org.aohe.result.R;
|
import org.aohe.result.R;
|
||||||
import org.aohe.scan.Source;
|
import org.aohe.scan.Source;
|
||||||
|
import org.aohe.webcam.WebCamUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -23,36 +24,24 @@ public class Operational {
|
||||||
|
|
||||||
//操作符
|
//操作符
|
||||||
String function = json.getString("function");
|
String function = json.getString("function");
|
||||||
|
String type = json.getString("type");
|
||||||
|
if("ping".equals(type)){
|
||||||
|
return R.ok().toJsonStr();
|
||||||
|
}
|
||||||
|
if(function == null){
|
||||||
|
return R.fail("操作符为空").toJsonStr();
|
||||||
|
}
|
||||||
//参数符
|
//参数符
|
||||||
JSONObject param = json.getJSONObject("params");
|
JSONObject param = json.getJSONObject("params");
|
||||||
|
|
||||||
R r = R.ok();
|
R r = R.ok();
|
||||||
try {
|
try {
|
||||||
if("001001".equals(function)){
|
if(function.startsWith("001")){
|
||||||
//获取扫描仪列表
|
r = operationalScan(function, r, param);
|
||||||
r = getDevices();
|
}else if (function.startsWith("002")){
|
||||||
} else if ("001002".equals(function)) {
|
r = operationalCamera(function, r, param);
|
||||||
//选择扫描仪
|
|
||||||
r = setScanner(param.getString("scannerId"));
|
|
||||||
}else if ("001003".equals(function)){
|
|
||||||
//获取扫描仪操作符列表
|
|
||||||
r = getDeviceOperations();
|
|
||||||
}else if ("001004".equals(function)){
|
|
||||||
//r = setDeviceOperations();
|
|
||||||
}else if ("001007".equals(function)){
|
|
||||||
r = setDeviceOperations(param);
|
|
||||||
}else if ("001008".equals(function)){
|
|
||||||
r = startScan(param.getString("scannerId"));
|
|
||||||
}else if ("001012".equals(function)){
|
|
||||||
closeTwSource();
|
|
||||||
}else if ("001013".equals(function)){
|
|
||||||
closeTwSource();
|
|
||||||
}else if ("001015".equals(function)){
|
|
||||||
r = startScan(param.getString("scannerId"),true);
|
|
||||||
}else if ("001016".equals(function)){
|
|
||||||
r = startScan(param.getString("scannerId"),true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (TwainException e) {
|
} catch (TwainException e) {
|
||||||
log.error("获取驱动列表失败");
|
log.error("获取驱动列表失败");
|
||||||
log.error(e.getMessage());
|
log.error(e.getMessage());
|
||||||
|
@ -66,6 +55,62 @@ public class Operational {
|
||||||
return r.toJsonStr();
|
return r.toJsonStr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static R operationalCamera(String function, R r, JSONObject param){
|
||||||
|
if("002001".equals(function)){
|
||||||
|
r = R.ok(WebCamUtils.getWebcams());
|
||||||
|
}else if ("002002".equals(function)){
|
||||||
|
//设置webcam
|
||||||
|
WebCamUtils.setWebcam(param.getString("name"));
|
||||||
|
r = R.ok(WebCamUtils.getViewSizes());
|
||||||
|
}else if("002003".equals(function)){
|
||||||
|
//获取摄像头分辨率
|
||||||
|
r = R.ok(WebCamUtils.getViewSizes());
|
||||||
|
}else if ("002004".equals(function)){
|
||||||
|
//获取摄像头图片
|
||||||
|
r = R.ok(Base64.encode(WebCamUtils.getImageInputStream()));
|
||||||
|
}else if("002005".equals(function)){
|
||||||
|
//打开摄像头传输流
|
||||||
|
WebCamUtils.openWebcamTransfer();
|
||||||
|
}else if ("002006".equals(function)){
|
||||||
|
//设置分辨率
|
||||||
|
WebCamUtils.setViewSizes(param.getInteger("width"), param.getInteger("height"));
|
||||||
|
r = R.ok();
|
||||||
|
}else if("002007".equals(function)){
|
||||||
|
//打开摄像头传输流
|
||||||
|
WebCamUtils.closeWebcamTransfer();
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static R operationalScan(String function, R r, JSONObject param) throws TwainException, InterruptedException {
|
||||||
|
if("001001".equals(function)){
|
||||||
|
//获取扫描仪列表
|
||||||
|
r = getDevices();
|
||||||
|
} else if ("001002".equals(function)) {
|
||||||
|
//选择扫描仪
|
||||||
|
r = setScanner(param.getString("scannerId"));
|
||||||
|
}else if ("001003".equals(function)){
|
||||||
|
//获取扫描仪操作符列表
|
||||||
|
r = getDeviceOperations();
|
||||||
|
}else if ("001004".equals(function)){
|
||||||
|
//r = setDeviceOperations();
|
||||||
|
}else if ("001007".equals(function)){
|
||||||
|
r = setDeviceOperations(param);
|
||||||
|
}else if ("001008".equals(function)){
|
||||||
|
r = startScan(param.getString("scannerId"));
|
||||||
|
}else if ("001012".equals(function)){
|
||||||
|
closeTwSource();
|
||||||
|
}else if ("001013".equals(function)){
|
||||||
|
closeTwSource();
|
||||||
|
}else if ("001015".equals(function)){
|
||||||
|
r = startScan(param.getString("scannerId"),true);
|
||||||
|
}else if ("001016".equals(function)){
|
||||||
|
r = startScan(param.getString("scannerId"),true);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 001001
|
* 001001
|
||||||
* 获取连接到当前终端的所有扫描仪并返回设备的SN号
|
* 获取连接到当前终端的所有扫描仪并返回设备的SN号
|
||||||
|
@ -85,7 +130,6 @@ public class Operational {
|
||||||
if(name == null || name.isEmpty()){
|
if(name == null || name.isEmpty()){
|
||||||
return R.fail("扫描仪名字为空");
|
return R.fail("扫描仪名字为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
TwainScanner.getScanner().select(name);
|
TwainScanner.getScanner().select(name);
|
||||||
Twain.getSourceManager().selectSource(name);
|
Twain.getSourceManager().selectSource(name);
|
||||||
|
|
||||||
|
@ -186,16 +230,6 @@ public class Operational {
|
||||||
return R.ok(base64Files);
|
return R.ok(base64Files);
|
||||||
}
|
}
|
||||||
|
|
||||||
// public static void main(String[] args) throws TwainException, InterruptedException {
|
|
||||||
// List<String> list = (List<String>) getDevices().getData();
|
|
||||||
// System.out.println(list.get(0));
|
|
||||||
// R r = setScanner(list.get(0));
|
|
||||||
// //System.out.println(getDeviceOperations());
|
|
||||||
// System.out.println(startScan(list.get(0), false));
|
|
||||||
// ;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开接口
|
* 打开接口
|
||||||
* @return twSource
|
* @return twSource
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package org.aohe.daemon;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aohe.constant.Control;
|
||||||
|
import org.aohe.constant.SocketEnum;
|
||||||
|
import org.aohe.web.SocketServer;
|
||||||
|
import org.aohe.web.SocketUtils;
|
||||||
|
import org.aohe.webcam.WebCamUtils;
|
||||||
|
import org.aohe.webcam.WebcamShowTask;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.aohe.constant.Control.WEBCAM_SHOW_TASK;
|
||||||
|
@Slf4j
|
||||||
|
public class WatchDog extends Thread{
|
||||||
|
|
||||||
|
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
scheduler.scheduleAtFixedRate (() -> {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
SocketServer camSocket = SocketUtils.get(SocketEnum.CAM_SOCKET.getName());
|
||||||
|
//清理拍照资源
|
||||||
|
if(camSocket == null || camSocket.getConnections().isEmpty()){
|
||||||
|
if(!Control.SHOW_CAMERA){
|
||||||
|
//图片传输循环未关闭
|
||||||
|
WebCamUtils.closeWebcamTransfer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(WEBCAM_SHOW_TASK == null || !WEBCAM_SHOW_TASK.isAlive()){
|
||||||
|
System.gc();
|
||||||
|
WEBCAM_SHOW_TASK = new WebcamShowTask();
|
||||||
|
WEBCAM_SHOW_TASK.start();
|
||||||
|
}
|
||||||
|
}, 0, 100, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.currentThread().join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error("Main thread interrupted", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package org.aohe.show;
|
package org.aohe.show;
|
||||||
|
|
||||||
import cn.hutool.core.io.resource.ResourceUtil;
|
import cn.hutool.core.io.resource.ResourceUtil;
|
||||||
|
import org.aohe.constant.SocketEnum;
|
||||||
import org.aohe.web.SocketUtils;
|
import org.aohe.web.SocketUtils;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -10,7 +11,7 @@ public class TrayFrame {
|
||||||
|
|
||||||
public void create() throws Exception {
|
public void create() throws Exception {
|
||||||
//创建Socket连接,默认是执行了start操作
|
//创建Socket连接,默认是执行了start操作
|
||||||
SocketUtils.start(8997);
|
SocketUtils.start(SocketEnum.SCAN_SOCKET);
|
||||||
|
|
||||||
// 确保事件调度线程(EDT)创建和显示GUI
|
// 确保事件调度线程(EDT)创建和显示GUI
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
@ -77,7 +78,7 @@ public class TrayFrame {
|
||||||
|
|
||||||
startServiceItem.addActionListener(e -> {
|
startServiceItem.addActionListener(e -> {
|
||||||
try {
|
try {
|
||||||
SocketUtils.start(8997);
|
SocketUtils.start(SocketEnum.SCAN_SOCKET);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
|
@ -87,7 +88,7 @@ public class TrayFrame {
|
||||||
});
|
});
|
||||||
|
|
||||||
stopServiceItem.addActionListener(e -> {
|
stopServiceItem.addActionListener(e -> {
|
||||||
SocketUtils.safeStop();
|
SocketUtils.safeStop(SocketEnum.SCAN_SOCKET);
|
||||||
startServiceItem.setEnabled(true);
|
startServiceItem.setEnabled(true);
|
||||||
stopServiceItem.setEnabled(false);
|
stopServiceItem.setEnabled(false);
|
||||||
System.out.println("服务已停止");
|
System.out.println("服务已停止");
|
||||||
|
@ -95,7 +96,7 @@ public class TrayFrame {
|
||||||
|
|
||||||
exitItem.addActionListener(e -> {
|
exitItem.addActionListener(e -> {
|
||||||
tray.remove(trayIcon);
|
tray.remove(trayIcon);
|
||||||
SocketUtils.safeStop();
|
SocketUtils.safeStop(SocketEnum.SCAN_SOCKET);
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package org.aohe.show;
|
package org.aohe.show;
|
||||||
|
|
||||||
import cn.hutool.core.io.resource.ResourceUtil;
|
import cn.hutool.core.io.resource.ResourceUtil;
|
||||||
import com.formdev.flatlaf.FlatDarculaLaf;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aohe.constant.SocketEnum;
|
||||||
import org.aohe.web.SocketUtils;
|
import org.aohe.web.SocketUtils;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -11,6 +11,7 @@ import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 中文系统托盘弹出菜单不乱码。
|
* 中文系统托盘弹出菜单不乱码。
|
||||||
|
@ -18,8 +19,8 @@ import java.net.MalformedURLException;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class TrayFrameUtf8 {
|
public class TrayFrameUtf8 {
|
||||||
|
|
||||||
public static void initSystemTrayUTF8() throws MalformedURLException {
|
public static void initSystemTrayUTF8() {
|
||||||
SocketUtils.start(8997);
|
SocketUtils.start(SocketEnum.SCAN_SOCKET);
|
||||||
//使用 JDialog 作为 JPopupMenu 载体
|
//使用 JDialog 作为 JPopupMenu 载体
|
||||||
JDialog jDialog = new JDialog();
|
JDialog jDialog = new JDialog();
|
||||||
//关闭 JDialog 的装饰器
|
//关闭 JDialog 的装饰器
|
||||||
|
@ -60,7 +61,7 @@ public class TrayFrameUtf8 {
|
||||||
stopServiceItem.setEnabled(true);
|
stopServiceItem.setEnabled(true);
|
||||||
startServiceItem.addActionListener(e ->{
|
startServiceItem.addActionListener(e ->{
|
||||||
try {
|
try {
|
||||||
SocketUtils.start(8997);
|
SocketUtils.start(SocketEnum.SCAN_SOCKET);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +71,7 @@ public class TrayFrameUtf8 {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
stopServiceItem.addActionListener(e -> {
|
stopServiceItem.addActionListener(e -> {
|
||||||
SocketUtils.safeStop();
|
SocketUtils.safeStop(SocketEnum.SCAN_SOCKET);
|
||||||
startServiceItem.setEnabled(true);
|
startServiceItem.setEnabled(true);
|
||||||
stopServiceItem.setEnabled(false);
|
stopServiceItem.setEnabled(false);
|
||||||
log.info("服务已停止");
|
log.info("服务已停止");
|
||||||
|
@ -132,12 +133,7 @@ public class TrayFrameUtf8 {
|
||||||
* @return UTF-8 编码的字符串
|
* @return UTF-8 编码的字符串
|
||||||
*/
|
*/
|
||||||
private static String getUTF8String(String str) {
|
private static String getUTF8String(String str) {
|
||||||
try {
|
return new String(str.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
|
||||||
return new String(str.getBytes("UTF-8"), "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
package org.aohe.web;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aohe.result.R;
|
||||||
|
import org.aohe.webcam.WebCamUtils;
|
||||||
|
import org.java_websocket.WebSocket;
|
||||||
|
import org.java_websocket.handshake.ClientHandshake;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class CamSocketServer extends SocketServer {
|
||||||
|
|
||||||
|
private static final Map<String, WebSocket> map = new HashMap<>();
|
||||||
|
|
||||||
|
public CamSocketServer(int port) throws UnknownHostException {
|
||||||
|
super(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CamSocketServer(InetSocketAddress address) {
|
||||||
|
super(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(WebSocket conn, ClientHandshake handshake) {
|
||||||
|
log.info("Cam-ws用户连接 {}", conn.getProtocol().toString());
|
||||||
|
map.put("zero", conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
|
||||||
|
log.info("Cam-ws用户关闭连接");
|
||||||
|
if(map.get("zero") == conn){
|
||||||
|
WebCamUtils.closeWebcamTransfer();
|
||||||
|
}
|
||||||
|
//这里执行关闭连接
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(WebSocket conn, String message) {
|
||||||
|
log.info("用户发送了数据:\n {}", message);
|
||||||
|
conn.send(R.ok().toJsonStr());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(WebSocket conn, Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
log.info(ex.getMessage());
|
||||||
|
if (conn != null) {
|
||||||
|
conn.send(R.fail("error").toJsonStr());
|
||||||
|
//绑定不到就退出
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
log.info("Server started!");
|
||||||
|
setConnectionLostTimeout(0);
|
||||||
|
setConnectionLostTimeout(100);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void broadcastNew(String message) {
|
||||||
|
if (message == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WebSocket zero = map.get("zero");
|
||||||
|
if(zero!=null && zero.isOpen()){
|
||||||
|
map.get("zero").send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void broadcastNew(byte[] bytes) {
|
||||||
|
if (bytes == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WebSocket zero = map.get("zero");
|
||||||
|
if(zero != null && zero.isOpen()){
|
||||||
|
zero.send(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -64,4 +64,10 @@ public class SocketServer extends WebSocketServer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void broadcastNew(String message) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void broadcastNew(byte[] bytes) {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,52 @@
|
||||||
package org.aohe.web;
|
package org.aohe.web;
|
||||||
|
|
||||||
|
import org.aohe.constant.SocketEnum;
|
||||||
|
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class SocketUtils {
|
public class SocketUtils {
|
||||||
private static SocketServer server;
|
|
||||||
|
private static final HashMap<String, SocketServer> map = new HashMap<>();
|
||||||
|
|
||||||
public SocketUtils() throws Exception {
|
public SocketUtils() throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SocketServer get() {
|
public static SocketServer get(String name ) {
|
||||||
return server;
|
return map.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void start(int port) {
|
public static void start(String name ,int port) {
|
||||||
try {
|
try {
|
||||||
server = new SocketServer(port);
|
SocketServer server = new SocketServer(port);
|
||||||
server.start();
|
server.start();
|
||||||
|
map.put(name, server);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void safeStop() {
|
public static void start(SocketEnum socketEnum) {
|
||||||
|
try {
|
||||||
|
SocketServer server = get(socketEnum.getName());
|
||||||
|
if(server != null){
|
||||||
|
//不为空 则先关闭再启动
|
||||||
|
safeStop(socketEnum);
|
||||||
|
}
|
||||||
|
if(SocketEnum.CAM_SOCKET.equals(socketEnum)){
|
||||||
|
server = new CamSocketServer(socketEnum.getPort());
|
||||||
|
}else{
|
||||||
|
server = new SocketServer(socketEnum.getPort());
|
||||||
|
}
|
||||||
|
server.start();
|
||||||
|
map.put(socketEnum.getName(), server);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void safeStop(String name) {
|
||||||
|
SocketServer server = map.get(name);
|
||||||
if(server != null){
|
if(server != null){
|
||||||
try {
|
try {
|
||||||
server.stop(1000);
|
server.stop(1000);
|
||||||
|
@ -31,4 +56,18 @@ public class SocketUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void safeStop(SocketEnum socketEnum) {
|
||||||
|
SocketServer server = map.get(socketEnum.getName());
|
||||||
|
if(server != null){
|
||||||
|
try {
|
||||||
|
server.stop(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void safeStopAll(){
|
||||||
|
map.forEach((k,v)-> safeStop(k));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package org.aohe.webcam;
|
||||||
|
|
||||||
|
import com.github.sarxos.webcam.Webcam;
|
||||||
|
import com.github.sarxos.webcam.WebcamResolution;
|
||||||
|
import io.humble.video.*;
|
||||||
|
import io.humble.video.awt.MediaPictureConverter;
|
||||||
|
import io.humble.video.awt.MediaPictureConverterFactory;
|
||||||
|
import org.aohe.constant.SocketEnum;
|
||||||
|
import org.aohe.web.SocketUtils;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class WebCam {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException, IOException {
|
||||||
|
|
||||||
|
SocketUtils.start(SocketEnum.CAM_SOCKET);
|
||||||
|
|
||||||
|
Webcam webcam = Webcam.getDefault();
|
||||||
|
Dimension[] viewSizes = webcam.getViewSizes();
|
||||||
|
Dimension bigSize = WebcamResolution.VGA.getSize();
|
||||||
|
for (Dimension d : viewSizes){
|
||||||
|
//获取最大分辨率
|
||||||
|
if(bigSize.getWidth()<d.getWidth()){
|
||||||
|
bigSize = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
webcam.setViewSize(bigSize);
|
||||||
|
webcam.open();
|
||||||
|
|
||||||
|
Rational framerate = Rational.make(1, 10); // 10 fps
|
||||||
|
int width = webcam.getViewSize().width;
|
||||||
|
int height = webcam.getViewSize().height;
|
||||||
|
|
||||||
|
Muxer muxer = Muxer.make("output.mp4", null, "mp4");
|
||||||
|
Codec codec = Codec.findEncodingCodec(Codec.ID.CODEC_ID_H264);
|
||||||
|
Encoder encoder = Encoder.make(codec);
|
||||||
|
encoder.setWidth(width);
|
||||||
|
encoder.setHeight(height);
|
||||||
|
encoder.setTimeBase(framerate);
|
||||||
|
encoder.setPixelFormat(PixelFormat.Type.PIX_FMT_YUV420P);
|
||||||
|
encoder.setFlag(Encoder.Flag.FLAG_GLOBAL_HEADER, true);
|
||||||
|
encoder.open(null, null);
|
||||||
|
|
||||||
|
MuxerStream muxerStream = muxer.addNewStream(encoder);
|
||||||
|
muxer.open(null, null);
|
||||||
|
|
||||||
|
MediaPicture picture = MediaPicture.make(
|
||||||
|
encoder.getWidth(),
|
||||||
|
encoder.getHeight(),
|
||||||
|
encoder.getPixelFormat());
|
||||||
|
picture.setTimeBase(framerate);
|
||||||
|
|
||||||
|
MediaPacket packet = MediaPacket.make();
|
||||||
|
|
||||||
|
System.out.println("BufferedImage Type: " + webcam.getImage().getType());
|
||||||
|
BufferedImage screen = convertToType(webcam.getImage(), BufferedImage.TYPE_3BYTE_BGR);
|
||||||
|
MediaPictureConverter converter = MediaPictureConverterFactory.createConverter(screen, picture);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
System.out.println("frame 循环");
|
||||||
|
BufferedImage frame = convertToType(webcam.getImage(), BufferedImage.TYPE_3BYTE_BGR);
|
||||||
|
converter.toPicture(picture, frame, 0);
|
||||||
|
|
||||||
|
do {
|
||||||
|
System.out.println("packet 循环");
|
||||||
|
encoder.encode(packet, picture);
|
||||||
|
if (packet.isComplete()) {
|
||||||
|
System.out.println("packet size: " + packet.getSize());
|
||||||
|
SocketUtils.get(SocketEnum.CAM_SOCKET.getName())
|
||||||
|
.broadcast(packet.getData().getByteBuffer(0, packet.getSize()));
|
||||||
|
muxer.write(packet, false);
|
||||||
|
}
|
||||||
|
} while (packet.isComplete());
|
||||||
|
|
||||||
|
Thread.sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BufferedImage convertToType(BufferedImage sourceImage,
|
||||||
|
int targetType) {
|
||||||
|
BufferedImage image;
|
||||||
|
// if the source image is already the target type, return the source image
|
||||||
|
if (sourceImage.getType() == targetType)
|
||||||
|
image = sourceImage;
|
||||||
|
// otherwise create a new image of the target type and draw the new
|
||||||
|
// image
|
||||||
|
else {
|
||||||
|
image = new BufferedImage(sourceImage.getWidth(),
|
||||||
|
sourceImage.getHeight(), targetType);
|
||||||
|
image.getGraphics().drawImage(sourceImage, 0, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
package org.aohe.webcam;
|
||||||
|
|
||||||
|
import com.github.eduramiba.webcamcapture.drivers.NativeDriver;
|
||||||
|
import com.github.sarxos.webcam.Webcam;
|
||||||
|
import com.github.sarxos.webcam.WebcamResolution;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aohe.constant.Control;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class WebCamUtils {
|
||||||
|
|
||||||
|
static{
|
||||||
|
//设置默认驱动
|
||||||
|
Webcam.setDriver(new NativeDriver());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Webcam webcam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取webcam
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static Webcam initWebcam(){
|
||||||
|
if(webcam == null){
|
||||||
|
//没有设置摄像头就取默认的
|
||||||
|
setWebcam(null);
|
||||||
|
}
|
||||||
|
Dimension[] viewSizes = webcam.getViewSizes();
|
||||||
|
Dimension bigSize = WebcamResolution.VGA.getSize();
|
||||||
|
for (Dimension d : viewSizes){
|
||||||
|
//获取最大分辨率
|
||||||
|
if(bigSize.getWidth()<d.getWidth()){
|
||||||
|
bigSize = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setViewSizes(bigSize.width, bigSize.height);
|
||||||
|
return webcam;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置摄像头
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
public static void setWebcam(String name){
|
||||||
|
if(webcam!=null && webcam.isOpen()){
|
||||||
|
webcam.close();
|
||||||
|
}
|
||||||
|
if(name != null){
|
||||||
|
webcam = Webcam.getWebcamByName(name);
|
||||||
|
}else{
|
||||||
|
webcam = Webcam.getDefault();
|
||||||
|
}
|
||||||
|
webcam = initWebcam();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取摄像头列表
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static List<String> getWebcams(){
|
||||||
|
List<Webcam> webcamList = Webcam.getWebcams();
|
||||||
|
return webcamList.stream().map(Webcam::getName).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BufferedImage getImage(){
|
||||||
|
if (!webcam.isOpen()){
|
||||||
|
webcam.open();
|
||||||
|
}
|
||||||
|
return webcam.getImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream getImageInputStream() {
|
||||||
|
BufferedImage bi = getImage();
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
ImageIO.write(bi, "png", os);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return new ByteArrayInputStream(os.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开摄像头
|
||||||
|
*/
|
||||||
|
public static void open(){
|
||||||
|
if (!webcam.isOpen()){
|
||||||
|
webcam.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭摄像头
|
||||||
|
*/
|
||||||
|
public static void close(){
|
||||||
|
if (webcam!=null && webcam.isOpen()){
|
||||||
|
webcam.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Webcam get(){
|
||||||
|
return webcam;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取摄像头分辨率
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static List<String> getViewSizes(){
|
||||||
|
List<Dimension> viewSizes = Arrays.asList(webcam.getViewSizes());
|
||||||
|
return viewSizes.stream().map(dimension -> (int)dimension.getWidth()+"x"+(int)dimension.getHeight()).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setViewSizes(int width, int height){
|
||||||
|
Control.SHOW_CAMERA = false;
|
||||||
|
if (webcam.isOpen()){
|
||||||
|
webcam.close();
|
||||||
|
}
|
||||||
|
webcam.setViewSize(new Dimension(width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void openWebcamTransfer(){
|
||||||
|
Control.SHOW_CAMERA = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeWebcamTransfer(){
|
||||||
|
//死循环控制器置为false
|
||||||
|
Control.SHOW_CAMERA = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package org.aohe.webcam;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aohe.constant.Control;
|
||||||
|
import org.aohe.constant.SocketEnum;
|
||||||
|
import org.aohe.result.R;
|
||||||
|
import org.aohe.web.SocketUtils;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class WebcamShowTask extends Thread {
|
||||||
|
|
||||||
|
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
scheduler.scheduleAtFixedRate(() -> {
|
||||||
|
try {
|
||||||
|
while (Control.SHOW_CAMERA) {
|
||||||
|
WebCamUtils.open();
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
BufferedImage bi = WebCamUtils.getImage();
|
||||||
|
try {
|
||||||
|
ImageIO.write(bi, "JPG", baos);
|
||||||
|
} catch (IOException e) {
|
||||||
|
//log.error(e.getMessage(), e);
|
||||||
|
}finally {
|
||||||
|
if (bi != null){
|
||||||
|
bi.flush();
|
||||||
|
bi = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String base64 = null;
|
||||||
|
try {
|
||||||
|
base64 = new String(Base64.getEncoder().encode(baos.toByteArray()), "UTF8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}finally {
|
||||||
|
baos.close();
|
||||||
|
}
|
||||||
|
SocketUtils.get(SocketEnum.CAM_SOCKET.getName()).broadcastNew(R.ok(base64).toJsonStr());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}, 0, 100, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.currentThread().join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error("Main thread interrupted", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SocketUtils.start(SocketEnum.CAM_SOCKET);
|
||||||
|
File file = new File("\"C:\\Users\\JianGuo\\Pictures\\Screenshots\\abc.png");
|
||||||
|
while (true){
|
||||||
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
BufferedImage image = ImageIO.read(file);
|
||||||
|
ImageIO.write(image, "PNG", baos);
|
||||||
|
} catch (IOException e) {
|
||||||
|
//log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String base64 = null;
|
||||||
|
base64 = new String(Base64.getEncoder().encode(baos.toByteArray()), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
SocketUtils.get(SocketEnum.CAM_SOCKET.getName()).broadcastNew(base64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package org.aohe.webcam;
|
||||||
|
|
||||||
|
import com.github.sarxos.webcam.util.ImageUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aohe.constant.Control;
|
||||||
|
import org.aohe.constant.SocketEnum;
|
||||||
|
import org.aohe.web.SocketUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 二进制流传输
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class WebcamWebTask extends Thread {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
while (Control.SHOW_CAMERA) {
|
||||||
|
WebCamUtils.open();
|
||||||
|
SocketUtils.get(SocketEnum.CAM_SOCKET.getName())
|
||||||
|
.broadcastNew(ImageUtils.toByteArray(WebCamUtils.getImage(), "jpg"));
|
||||||
|
//等待0.09秒
|
||||||
|
Thread.sleep(90);
|
||||||
|
}
|
||||||
|
//等待0.1秒
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue