feat(webcam): 新增摄像头功能

- 添加摄像头相关类和方法,实现摄像头图像采集和传输- 新增 CamSocketServer 类处理摄像头数据传输
- 修改 Main 类,添加摄像头任务和 Socket 连接
- 更新 Operational 类,增加摄像头操作处理
- 新增 Control 类统一控制摄像头状态
- 修改 TrayFrame 和 TrayFrameUtf8 类,支持摄像头服务启动和停止- 新增 WatchDog 类监控摄像头状态并自动重启任务
This commit is contained in:
JianGuo 2025-02-07 11:24:51 +08:00
parent 4d0a511186
commit 6cc8f1913b
16 changed files with 692 additions and 59 deletions

Binary file not shown.

21
pom.xml
View File

@ -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>-->

View File

@ -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();
} }
} }

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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);
}); });
}); });

View File

@ -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;
} }
} }

View File

@ -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);
}
}
}

View File

@ -64,4 +64,10 @@ public class SocketServer extends WebSocketServer {
} }
public void broadcastNew(String message) {
}
public void broadcastNew(byte[] bytes) {
}
} }

View File

@ -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));
}
} }

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}
}