环境配置参考:http://www.gaohaiyan.com/3201.html
本例仅录制视频,没有音频。
用到的xuggle库jar:
从 https://mvnrepository.com/ 搜索下载
https://www.dcm4che.org/maven2/xuggle/xuggle-xuggler/5.4/xuggle-xuggler-5.4.jar
https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.32/slf4j-api-1.7.32.jar
https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.2.6/logback-core-1.2.6.jar
https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.2.6/logback-classic-1.2.6.jar
xuggle的java文档:http://www.xuggle.com/public/documentation/java/api/
opencv录制编码格式参考:https://www.fourcc.org/codecs.php
1.可播放视频的JPanel类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
import java.awt.Graphics; import java.awt.image.BufferedImage; import javax.swing.JPanel; import org.opencv.core.Mat; // 可使用opencv的Mat作为图像 public class CVPanel extends JPanel { private BufferedImage image; @Override protected void paintComponent(Graphics g) { super.paintComponent(g); BufferedImage img = getImage(); if (null != img) { g.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), this); } } private BufferedImage getImage() { return image; } public void setImageWithMat(Mat mat) { image = mat2BufferedImage(mat); } public BufferedImage mat2BufferedImage(Mat mat) { int rows = mat.rows(); // 行 int cols = mat.cols(); // 列 int elemSize = (int) mat.elemSize(); // 每个元素大小,单位字节 byte[] data = new byte[cols * rows * elemSize]; // 目标图像数据 int type = BufferedImage.TYPE_BYTE_GRAY; mat.get(0, 0, data); // 将mat数据放入数组 int channels = mat.channels(); if (3 == channels) { type = BufferedImage.TYPE_3BYTE_BGR; byte b; for (int i = 0; i < data.length; i += 3) { // BGR 2 RGB。交换红蓝通道 b = data[i]; data[i] = data[i + 2]; data[i + 2] = b; } } BufferedImage img = new BufferedImage(cols, rows, type); // 宽高,图像类型 img.getRaster().setDataElements(0, 0, cols, rows, data); // 加载图像数据 return img; } } |
2.opencv封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
import java.awt.FlowLayout; import java.awt.HeadlessException; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import org.opencv.core.Mat; import org.opencv.videoio.VideoCapture; public abstract class BaseFrame extends JFrame { protected boolean isRecording = true; protected VideoCapture videoCapture; protected CVPanel videoPlayer; protected JButton button; // @param videoPath 视频文件保存路径 // @throws HeadlessException public BaseFrame(String videoPath) throws HeadlessException { super(); Mat mat = initCapture(); if (null == mat){ exit(); } initUI(mat); initWriter(mat, videoPath); } // 初始化UI public abstract void initWriter(Mat mat, String path); // 录制 public abstract void record(); // 按钮事件 public void setActionListener(ActionListener listener) { button.addActionListener(listener); } // 开始录制 public void run() throws InterruptedException { this.setVisible(true); record(); exit(); } // 停止录制 public void stop() { isRecording = false; } // 初始化摄像头 private Mat initCapture() { videoCapture = new VideoCapture(); // 摄像头 videoCapture.open(0); // 电脑的第一个摄像头,通常是自带的前置摄像头。系统偏好设置,安全性与隐私,隐私,摄像头,勾选"IntelliJ IDEA" if (!videoCapture.isOpened()) { System.err.println("相机未打开"); return null; } Mat mat = new Mat(); videoCapture.read(mat); // 从摄像头读取流。 return mat; } // 初始化UI private void initUI(Mat mat) { button = new JButton("停止录制"); button.setBounds(0, 0, 60, 35); this.setTitle("录制视频"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER)); videoPlayer = new CVPanel(); this.setContentPane(videoPlayer); this.getContentPane().add(button); this.setSize(mat.width(), mat.height()); // 调整窗体显示完整视频画面-摄像头像素宽高 } // 退出程序 private void exit() { System.out.println("录制结束"); videoCapture.release(); // 释放摄像头 this.setVisible(false); this.dispose(); System.exit(0); } } |
3.使用xuggle进行录制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
import com.xuggle.mediatool.IMediaWriter; import com.xuggle.mediatool.ToolFactory; import com.xuggle.xuggler.IRational; import java.awt.HeadlessException; import java.awt.image.BufferedImage; import java.util.concurrent.TimeUnit; import org.opencv.core.Mat; public class EncodeVideoTest extends BaseFrame { private IMediaWriter mediaWriter; private IRational frameRate = IRational.make(30, 1); // 帧速率30。创建一个有理数对象(分子,分母),结果值尽可能的小,但不小于分母。 private int streamIndex = 0; public EncodeVideoTest(String videoPath) throws HeadlessException { super(videoPath); } @Override public void record() { long startTime = System.nanoTime(); Mat captureMat = new Mat(); int i = 0; while (isRecording) { videoCapture.read(captureMat); // 持续将最新的画面存到mat中 videoPlayer.setImageWithMat(captureMat); // 显示最新画面到窗体 this.repaint(); long timeStamp = System.nanoTime() - startTime; // 图片的时间戳 BufferedImage bufferedImage = videoPlayer.mat2BufferedImage(captureMat); // mat数据转image数据 mediaWriter.encodeVideo(streamIndex, bufferedImage, timeStamp, TimeUnit.NANOSECONDS); // 使用指定索引的流,将图片编码后写入到文件 i++; System.out.println("帧:" + i); try { Thread.sleep((long) (1000 / frameRate.getDouble())); } catch (InterruptedException e) { e.printStackTrace(); } } mediaWriter.close(); // 关闭流 } @Override public void initWriter(Mat mat, String path) { int inputIndex = 0; // 设定一个输入索引 int streamId = 0; // 设定一个视频流索引 int width = mat.width(); // 设定视频宽度 int height = mat.height(); // 设定视频高度 mediaWriter = ToolFactory.makeWriter(path); // 保存视频到某个文件的写入器。默认覆盖已存在的文件。 streamIndex = mediaWriter.addVideoStream(inputIndex, streamId, frameRate, width, height);// 添加视频流。 } } |
4.使用opencv进行录制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import java.awt.HeadlessException; import org.opencv.core.Mat; import org.opencv.core.Size; import org.opencv.videoio.VideoWriter; public class WriteTest extends BaseFrame { private VideoWriter videoWriter; public WriteTest(String videoPath) throws HeadlessException { super(videoPath); } @Override public void record() { Mat captureMat = new Mat(); int i = 0; while (isRecording) { videoCapture.read(captureMat); // 持续将最新的画面存到mat中 videoPlayer.setImageWithMat(captureMat); // 显示最新画面到窗体 this.repaint(); videoWriter.write(captureMat); i++; System.out.println("帧:" + i); } videoWriter.release(); } @Override public void initWriter(Mat mat, String filename) { int fourcc = VideoWriter.fourcc('M','J','P','G'); // 影片编码格式。https://www.fourcc.org/codecs.php 格式不支持的不创建文件 double fps = 30; // 帧频 int width = mat.width(); int height = mat.height(); Size frameSize = new Size(width, height); // 影片宽高 boolean isColor = true; videoWriter = new VideoWriter(filename, fourcc, fps, frameSize, isColor); } } |
5.测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import org.opencv.core.Core; public class Index { static { System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } public static void main(String[] args) throws InterruptedException { //EncodeVideoTest test1 = new EncodeVideoTest("./tmp.mp4"); //test1.setActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // test1.stop(); // } //}); //test1.run(); WriteTest test2 = new WriteTest("./tmp.mp4"); test2.setActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { test2.stop(); } }); test2.run(); } } |
- end
本文由崔维友 威格灵 cuiweiyou vigiles cuiweiyou 原创,转载请注明出处:http://www.gaohaiyan.com/3216.html
承接App定制、企业web站点、办公系统软件 设计开发,外包项目,毕设