|
13 | 13 | import com.dynamsoft.license.LicenseException; |
14 | 14 | import com.dynamsoft.license.LicenseManager; |
15 | 15 | import com.dynamsoft.utility.MultiFrameResultCrossFilter; |
| 16 | + |
| 17 | +import org.bytedeco.ffmpeg.global.avutil; |
| 18 | +import org.bytedeco.javacv.FFmpegFrameGrabber; |
| 19 | +import org.bytedeco.javacv.Frame; |
| 20 | +import org.bytedeco.javacv.OpenCVFrameConverter; |
16 | 21 | import org.bytedeco.opencv.opencv_core.Mat; |
17 | 22 | import org.bytedeco.opencv.opencv_videoio.VideoCapture; |
18 | 23 |
|
| 24 | +import java.awt.GraphicsEnvironment; |
| 25 | +import java.nio.Buffer; |
| 26 | +import java.nio.ByteBuffer; |
19 | 27 | import java.nio.file.Files; |
20 | 28 | import java.nio.file.Paths; |
21 | 29 | import java.util.Scanner; |
22 | 30 |
|
| 31 | +import org.bytedeco.javacv.CanvasFrame; |
23 | 32 | import static org.bytedeco.opencv.global.opencv_highgui.*; |
24 | | -import static org.bytedeco.opencv.global.opencv_videoio.CAP_PROP_FRAME_HEIGHT; |
25 | | -import static org.bytedeco.opencv.global.opencv_videoio.CAP_PROP_FRAME_WIDTH; |
26 | 33 |
|
27 | 34 | class MyCapturedResultReceiver extends CapturedResultReceiver { |
28 | 35 |
|
@@ -86,43 +93,116 @@ private static void decodeVideo(boolean useVideoFile, String videoFilePath) { |
86 | 93 | return; |
87 | 94 | } |
88 | 95 |
|
89 | | - try (VideoCapture vc = !useVideoFile ? new VideoCapture(0) : new VideoCapture(videoFilePath)) { |
90 | | - int videoWidth = (int) vc.get(CAP_PROP_FRAME_WIDTH); |
91 | | - int videoHeight = (int) vc.get(CAP_PROP_FRAME_HEIGHT); |
92 | | - vc.set(CAP_PROP_FRAME_WIDTH, videoWidth); |
93 | | - vc.set(CAP_PROP_FRAME_HEIGHT, videoHeight); |
94 | | - |
95 | | - if (!vc.isOpened()) { |
96 | | - cvRouter.stopCapturing(); |
97 | | - return; |
| 96 | + CanvasFrame canvas = null; |
| 97 | + VideoCapture vc = null; |
| 98 | + FFmpegFrameGrabber grabber = null; |
| 99 | + OpenCVFrameConverter.ToMat converter = null; |
| 100 | + String windowName = "Video Barcode Reader"; |
| 101 | + try { |
| 102 | + if (useVideoFile) { |
| 103 | + avutil.av_log_set_level(avutil.AV_LOG_QUIET); |
| 104 | + grabber = new FFmpegFrameGrabber(videoFilePath); |
| 105 | + try { |
| 106 | + grabber.start(); |
| 107 | + } catch (Exception e) { |
| 108 | + System.out.println("Error: " + e.getMessage()); |
| 109 | + return; |
| 110 | + } |
| 111 | + } else { |
| 112 | + vc = new VideoCapture(0); |
| 113 | + if (!vc.isOpened()) { |
| 114 | + System.out.println("Error: Cannot open camera."); |
| 115 | + return; |
| 116 | + } |
98 | 117 | } |
99 | 118 |
|
100 | | - String windowName = "Video Barcode Reader"; |
| 119 | + boolean isHeadless = GraphicsEnvironment.isHeadless(); |
| 120 | + if (!isHeadless) { |
| 121 | + canvas = new CanvasFrame(windowName, 1); |
| 122 | + canvas.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); |
| 123 | + canvas.setAlwaysOnTop(true); |
| 124 | + canvas.setVisible(true); |
| 125 | + canvas.setAlwaysOnTop(false); |
| 126 | + } |
101 | 127 |
|
102 | 128 | int imageId = 0; |
103 | | - Mat frame = new Mat(); |
104 | | - while (true) { |
| 129 | + Frame frame; |
| 130 | + converter = new OpenCVFrameConverter.ToMat(); |
| 131 | + while (canvas == null || canvas.isVisible()) { |
105 | 132 | imageId++; |
106 | | - boolean rval = vc.read(frame); |
107 | | - if (!rval) { |
| 133 | + if (grabber != null) { |
| 134 | + frame = grabber.grab(); |
| 135 | + } else if (vc != null) { |
| 136 | + Mat mat = new Mat(); |
| 137 | + if (!vc.read(mat)) { |
| 138 | + break; |
| 139 | + } |
| 140 | + |
| 141 | + if (mat.empty()) { |
| 142 | + System.out.println("Error: Frame is empty."); |
| 143 | + break; |
| 144 | + } |
| 145 | + |
| 146 | + frame = converter.convert(mat); |
| 147 | + } else { |
| 148 | + System.out.println("Error: No video source available."); |
| 149 | + break; |
| 150 | + } |
| 151 | + |
| 152 | + if (frame == null) { |
| 153 | + break; |
| 154 | + } else if (frame.image == null) { |
| 155 | + continue; |
| 156 | + } |
| 157 | + |
| 158 | + byte[] byteArray; |
| 159 | + Buffer buffer = frame.image[0]; |
| 160 | + if (buffer instanceof ByteBuffer) { |
| 161 | + ByteBuffer byteBuffer = (ByteBuffer)buffer; |
| 162 | + byteBuffer.rewind(); |
| 163 | + byteArray = new byte[byteBuffer.remaining()]; |
| 164 | + byteBuffer.get(byteArray); |
| 165 | + } else { |
| 166 | + System.out.println("Error: Frame is not a ByteBuffer."); |
108 | 167 | break; |
109 | 168 | } |
110 | 169 |
|
111 | 170 | FileImageTag tag = new FileImageTag("", 0, 0); |
112 | 171 | tag.setImageId(imageId); |
113 | | - byte[] byteArray = new byte[(int) (frame.total() * frame.channels())]; |
114 | | - frame.data().get(byteArray); |
115 | | - ImageData image = new ImageData(byteArray, frame.cols(), frame.rows(), (int) frame.step(), EnumImagePixelFormat.IPF_RGB_888, 0, tag); |
| 172 | + ImageData image = new ImageData(byteArray, frame.imageWidth, frame.imageHeight, frame.imageStride, EnumImagePixelFormat.IPF_RGB_888, 0, tag); |
116 | 173 | fetcher.addImageToBuffer(image); |
117 | 174 |
|
118 | | - imshow(windowName, frame); |
119 | | - int key = waitKey(1); |
120 | | - if (key == 27) |
121 | | - break; |
| 175 | + if (canvas != null) { |
| 176 | + canvas.showImage(frame); |
| 177 | + } |
| 178 | + } |
| 179 | + |
| 180 | + } catch (Exception e) { |
| 181 | + e.printStackTrace(); |
| 182 | + } finally { |
| 183 | + if (canvas != null) { |
| 184 | + if (canvas.isVisible()) { |
| 185 | + canvas.setVisible(false); |
| 186 | + } |
| 187 | + canvas.dispose(); |
| 188 | + } |
| 189 | + |
| 190 | + if (converter != null) { |
| 191 | + converter.close(); |
| 192 | + } |
| 193 | + |
| 194 | + try { |
| 195 | + if (useVideoFile && grabber != null) { |
| 196 | + grabber.stop(); |
| 197 | + grabber.release(); |
| 198 | + } else if (vc != null) { |
| 199 | + vc.release(); |
| 200 | + } |
| 201 | + } catch (Exception e) { |
| 202 | + e.printStackTrace(); |
122 | 203 | } |
123 | 204 |
|
124 | 205 | cvRouter.stopCapturing(); |
125 | | - destroyWindow(windowName); |
126 | 206 | } |
127 | 207 | } |
128 | 208 |
|
@@ -162,24 +242,42 @@ public static void main(String[] args) { |
162 | 242 | System.out.println("1. Decode video from camera."); |
163 | 243 | System.out.println("2. Decode video from file."); |
164 | 244 | System.out.println(">> 1 or 2:"); |
165 | | - int mode = scanner.nextInt(); |
166 | | - scanner.nextLine(); |
167 | | - |
168 | | - if (mode == 1 || mode == 2) { |
169 | | - if (mode == 1) { |
170 | | - useVideoFile = false; |
171 | | - } else { |
172 | | - useVideoFile = true; |
173 | | - while (true) { |
| 245 | + String strChoice = scanner.nextLine(); |
| 246 | + if (strChoice.trim().isEmpty()) { |
| 247 | + continue; |
| 248 | + } |
| 249 | + |
| 250 | + boolean choosedMode = false; |
| 251 | + try { |
| 252 | + int mode = Integer.parseInt(strChoice.trim()); |
| 253 | + if (mode == 1 || mode == 2) { |
| 254 | + useVideoFile = mode == 2; |
| 255 | + choosedMode = true; |
| 256 | + } |
| 257 | + } catch (NumberFormatException e) { |
| 258 | + videoFilePath = strChoice.replaceAll("^\"|\"$", ""); |
| 259 | + useVideoFile = true; |
| 260 | + } |
| 261 | + |
| 262 | + if (useVideoFile) { |
| 263 | + do { |
| 264 | + if (videoFilePath.isEmpty()) { |
174 | 265 | System.out.println(">> Input your video full path:"); |
175 | 266 | videoFilePath = scanner.nextLine(); |
176 | | - videoFilePath = videoFilePath.replaceAll("^\"|\"$", ""); |
177 | | - if (Files.exists(Paths.get(videoFilePath))) { |
178 | | - break; |
| 267 | + if (videoFilePath.trim().isEmpty()) { |
| 268 | + continue; |
179 | 269 | } |
180 | | - System.out.println("Error: File not found"); |
| 270 | + videoFilePath = videoFilePath.replaceAll("^\"|\"$", ""); |
181 | 271 | } |
182 | | - } |
| 272 | + if (Files.exists(Paths.get(videoFilePath))) { |
| 273 | + break; |
| 274 | + } |
| 275 | + System.out.println("Error: File not found"); |
| 276 | + videoFilePath = ""; |
| 277 | + } while (choosedMode); |
| 278 | + } |
| 279 | + |
| 280 | + if ((!useVideoFile && choosedMode) || !videoFilePath.isEmpty()) { |
183 | 281 | break; |
184 | 282 | } |
185 | 283 | } catch (Exception ignored) { |
|
0 commit comments