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>
|
||||
<version>2.0.13</version>
|
||||
</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>
|
||||
|
||||
<!-- <build>-->
|
||||
|
|
|
@ -2,16 +2,28 @@ package org.aohe;
|
|||
|
||||
import com.formdev.flatlaf.FlatDarculaLaf;
|
||||
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.web.SocketUtils;
|
||||
import org.aohe.webcam.WebcamShowTask;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import org.aohe.constant.Control;
|
||||
|
||||
@Slf4j
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
UIManager.setLookAndFeel(new FlatDarculaLaf());
|
||||
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.result.R;
|
||||
import org.aohe.scan.Source;
|
||||
import org.aohe.webcam.WebCamUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
@ -23,36 +24,24 @@ public class Operational {
|
|||
|
||||
//操作符
|
||||
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");
|
||||
|
||||
R r = R.ok();
|
||||
try {
|
||||
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);
|
||||
if(function.startsWith("001")){
|
||||
r = operationalScan(function, r, param);
|
||||
}else if (function.startsWith("002")){
|
||||
r = operationalCamera(function, r, param);
|
||||
}
|
||||
|
||||
} catch (TwainException e) {
|
||||
log.error("获取驱动列表失败");
|
||||
log.error(e.getMessage());
|
||||
|
@ -66,6 +55,62 @@ public class Operational {
|
|||
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
|
||||
* 获取连接到当前终端的所有扫描仪并返回设备的SN号
|
||||
|
@ -85,7 +130,6 @@ public class Operational {
|
|||
if(name == null || name.isEmpty()){
|
||||
return R.fail("扫描仪名字为空");
|
||||
}
|
||||
|
||||
TwainScanner.getScanner().select(name);
|
||||
Twain.getSourceManager().selectSource(name);
|
||||
|
||||
|
@ -186,16 +230,6 @@ public class Operational {
|
|||
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
|
||||
|
|
|
@ -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;
|
||||
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import org.aohe.constant.SocketEnum;
|
||||
import org.aohe.web.SocketUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
|
@ -10,7 +11,7 @@ public class TrayFrame {
|
|||
|
||||
public void create() throws Exception {
|
||||
//创建Socket连接,默认是执行了start操作
|
||||
SocketUtils.start(8997);
|
||||
SocketUtils.start(SocketEnum.SCAN_SOCKET);
|
||||
|
||||
// 确保事件调度线程(EDT)创建和显示GUI
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
|
@ -77,7 +78,7 @@ public class TrayFrame {
|
|||
|
||||
startServiceItem.addActionListener(e -> {
|
||||
try {
|
||||
SocketUtils.start(8997);
|
||||
SocketUtils.start(SocketEnum.SCAN_SOCKET);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
@ -87,7 +88,7 @@ public class TrayFrame {
|
|||
});
|
||||
|
||||
stopServiceItem.addActionListener(e -> {
|
||||
SocketUtils.safeStop();
|
||||
SocketUtils.safeStop(SocketEnum.SCAN_SOCKET);
|
||||
startServiceItem.setEnabled(true);
|
||||
stopServiceItem.setEnabled(false);
|
||||
System.out.println("服务已停止");
|
||||
|
@ -95,7 +96,7 @@ public class TrayFrame {
|
|||
|
||||
exitItem.addActionListener(e -> {
|
||||
tray.remove(trayIcon);
|
||||
SocketUtils.safeStop();
|
||||
SocketUtils.safeStop(SocketEnum.SCAN_SOCKET);
|
||||
System.exit(0);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package org.aohe.show;
|
||||
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import com.formdev.flatlaf.FlatDarculaLaf;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aohe.constant.SocketEnum;
|
||||
import org.aohe.web.SocketUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
|
@ -11,6 +11,7 @@ import java.awt.event.MouseAdapter;
|
|||
import java.awt.event.MouseEvent;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 中文系统托盘弹出菜单不乱码。
|
||||
|
@ -18,8 +19,8 @@ import java.net.MalformedURLException;
|
|||
@Slf4j
|
||||
public class TrayFrameUtf8 {
|
||||
|
||||
public static void initSystemTrayUTF8() throws MalformedURLException {
|
||||
SocketUtils.start(8997);
|
||||
public static void initSystemTrayUTF8() {
|
||||
SocketUtils.start(SocketEnum.SCAN_SOCKET);
|
||||
//使用 JDialog 作为 JPopupMenu 载体
|
||||
JDialog jDialog = new JDialog();
|
||||
//关闭 JDialog 的装饰器
|
||||
|
@ -60,7 +61,7 @@ public class TrayFrameUtf8 {
|
|||
stopServiceItem.setEnabled(true);
|
||||
startServiceItem.addActionListener(e ->{
|
||||
try {
|
||||
SocketUtils.start(8997);
|
||||
SocketUtils.start(SocketEnum.SCAN_SOCKET);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
@ -70,7 +71,7 @@ public class TrayFrameUtf8 {
|
|||
}
|
||||
);
|
||||
stopServiceItem.addActionListener(e -> {
|
||||
SocketUtils.safeStop();
|
||||
SocketUtils.safeStop(SocketEnum.SCAN_SOCKET);
|
||||
startServiceItem.setEnabled(true);
|
||||
stopServiceItem.setEnabled(false);
|
||||
log.info("服务已停止");
|
||||
|
@ -132,12 +133,7 @@ public class TrayFrameUtf8 {
|
|||
* @return UTF-8 编码的字符串
|
||||
*/
|
||||
private static String getUTF8String(String str) {
|
||||
try {
|
||||
return new String(str.getBytes("UTF-8"), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
return new String(str.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
import org.aohe.constant.SocketEnum;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class SocketUtils {
|
||||
private static SocketServer server;
|
||||
|
||||
private static final HashMap<String, SocketServer> map = new HashMap<>();
|
||||
|
||||
public SocketUtils() throws Exception {
|
||||
}
|
||||
|
||||
public static SocketServer get() {
|
||||
return server;
|
||||
public static SocketServer get(String name ) {
|
||||
return map.get(name);
|
||||
}
|
||||
|
||||
public static void start(int port) {
|
||||
public static void start(String name ,int port) {
|
||||
try {
|
||||
server = new SocketServer(port);
|
||||
SocketServer server = new SocketServer(port);
|
||||
server.start();
|
||||
map.put(name, server);
|
||||
} catch (UnknownHostException 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){
|
||||
try {
|
||||
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