update
This commit is contained in:
parent
978ccf22a9
commit
e2b80ce297
|
@ -0,0 +1,124 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
33
pom.xml
33
pom.xml
|
@ -8,10 +8,39 @@
|
|||
<artifactId>onnx-inference4j-play</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<javafx.version>8.0.202</javafx.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/com.microsoft.onnxruntime/onnxruntime_gpu -->
|
||||
<dependency>
|
||||
<groupId>com.microsoft.onnxruntime</groupId>
|
||||
<artifactId>onnxruntime_gpu</artifactId>
|
||||
<version>1.17.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>javacv-platform</artifactId>
|
||||
<version>1.5.7</version>
|
||||
</dependency>
|
||||
<!-- FlatLaf for modern Swing look and feel -->
|
||||
<dependency>
|
||||
<groupId>com.formdev</groupId>
|
||||
<artifactId>flatlaf</artifactId>
|
||||
<version>2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
<artifactId>ffmpeg-platform</artifactId>
|
||||
<version>5.0-1.5.7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
|
@ -1,17 +0,0 @@
|
|||
package com.ly;
|
||||
|
||||
//TIP 要<b>运行</b>代码,请按 <shortcut actionId="Run"/> 或
|
||||
// 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
//TIP 当文本光标位于高亮显示的文本处时按 <shortcut actionId="ShowIntentionActions"/>
|
||||
// 查看 IntelliJ IDEA 建议如何修正。
|
||||
System.out.printf("Hello and welcome!");
|
||||
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
//TIP 按 <shortcut actionId="Debug"/> 开始调试代码。我们已经设置了一个 <icon src="AllIcons.Debugger.Db_set_breakpoint"/> 断点
|
||||
// 但您始终可以通过按 <shortcut actionId="ToggleLineBreakpoint"/> 添加更多断点。
|
||||
System.out.println("i = " + i);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
package com.ly;
|
||||
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.ly.layout.VideoPanel;
|
||||
import com.ly.model_load.ModelManager;
|
||||
import com.ly.play.VideoPlayer;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
|
||||
public class VideoInferenceApp extends JFrame {
|
||||
|
||||
private VideoPanel videoPanel; // 视频显示面板
|
||||
private JPanel controlPanel; // 操作按钮区域
|
||||
private JTextField streamUrlField; // 流地址输入框
|
||||
|
||||
private VideoPlayer videoPlayer;
|
||||
private ModelManager modelManager;
|
||||
|
||||
public VideoInferenceApp() {
|
||||
// 设置窗口标题
|
||||
super("Video Inference Player");
|
||||
|
||||
// 初始化UI组件
|
||||
initializeUI();
|
||||
}
|
||||
|
||||
private void initializeUI() {
|
||||
// 设置 FlatLaf 主题
|
||||
try {
|
||||
UIManager.setLookAndFeel(new FlatLightLaf());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// 设置布局管理器
|
||||
this.setLayout(new BorderLayout());
|
||||
|
||||
// 视频显示区域
|
||||
videoPanel = new VideoPanel();
|
||||
videoPanel.setBackground(Color.BLACK);
|
||||
|
||||
// 初始化 VideoPlayer
|
||||
videoPlayer = new VideoPlayer(videoPanel);
|
||||
|
||||
// 模型列表区域
|
||||
modelManager = new ModelManager();
|
||||
modelManager.setPreferredSize(new Dimension(250, 0)); // 设置模型列表区域的宽度
|
||||
|
||||
// 使用 JSplitPane 分割视频区域和模型列表区域
|
||||
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, videoPanel, modelManager);
|
||||
splitPane.setResizeWeight(0.8); // 视频区域初始占据80%的空间
|
||||
splitPane.setDividerLocation(0.8);
|
||||
this.add(splitPane, BorderLayout.CENTER);
|
||||
|
||||
// 操作按钮区域
|
||||
controlPanel = new JPanel();
|
||||
controlPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 5));
|
||||
|
||||
// 创建控制按钮
|
||||
JButton playButton = new JButton("播放");
|
||||
JButton pauseButton = new JButton("暂停");
|
||||
JButton replayButton = new JButton("重播");
|
||||
JButton fastForward5sButton = new JButton("快进5秒");
|
||||
JButton rewind5sButton = new JButton("后退5秒");
|
||||
|
||||
// 设置按钮的统一高度
|
||||
Dimension buttonSize = new Dimension(100, 30);
|
||||
playButton.setPreferredSize(buttonSize);
|
||||
pauseButton.setPreferredSize(buttonSize);
|
||||
replayButton.setPreferredSize(buttonSize);
|
||||
fastForward5sButton.setPreferredSize(buttonSize);
|
||||
rewind5sButton.setPreferredSize(buttonSize);
|
||||
|
||||
// 添加按钮到控制面板
|
||||
controlPanel.add(playButton);
|
||||
controlPanel.add(pauseButton);
|
||||
controlPanel.add(replayButton);
|
||||
controlPanel.add(rewind5sButton);
|
||||
controlPanel.add(fastForward5sButton);
|
||||
|
||||
this.add(controlPanel, BorderLayout.SOUTH);
|
||||
|
||||
// 顶部部分 - 视频和模型加载,流地址
|
||||
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
|
||||
|
||||
// 视频文件选择按钮
|
||||
JButton loadVideoButton = new JButton("选择视频文件");
|
||||
loadVideoButton.setPreferredSize(new Dimension(150, 30));
|
||||
|
||||
// 模型文件选择按钮
|
||||
JButton loadModelButton = new JButton("选择模型");
|
||||
loadModelButton.setPreferredSize(new Dimension(150, 30));
|
||||
|
||||
// 流地址输入框
|
||||
streamUrlField = new JTextField(15); // 流地址输入框
|
||||
|
||||
// 开始播放按钮
|
||||
JButton startPlayButton = new JButton("开始播放");
|
||||
startPlayButton.setPreferredSize(new Dimension(100, 30));
|
||||
|
||||
// 将按钮和输入框添加到顶部面板
|
||||
topPanel.add(loadVideoButton);
|
||||
topPanel.add(loadModelButton);
|
||||
topPanel.add(new JLabel("流地址:"));
|
||||
topPanel.add(streamUrlField);
|
||||
topPanel.add(startPlayButton);
|
||||
|
||||
this.add(topPanel, BorderLayout.NORTH);
|
||||
|
||||
// 设置窗口属性
|
||||
this.setSize(1280, 720);
|
||||
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
this.setLocationRelativeTo(null); // 居中显示
|
||||
this.setVisible(true);
|
||||
|
||||
// 添加视频加载按钮的行为
|
||||
loadVideoButton.addActionListener(e -> selectVideoFile());
|
||||
|
||||
// 添加模型加载按钮的行为
|
||||
loadModelButton.addActionListener(e -> modelManager.loadModel(this));
|
||||
|
||||
// 播放按钮
|
||||
playButton.addActionListener(e -> videoPlayer.playVideo());
|
||||
|
||||
// 暂停按钮
|
||||
pauseButton.addActionListener(e -> videoPlayer.pauseVideo());
|
||||
|
||||
// 重播按钮
|
||||
replayButton.addActionListener(e -> videoPlayer.replayVideo());
|
||||
|
||||
// 后退5秒
|
||||
rewind5sButton.addActionListener(e -> videoPlayer.rewind(5000));
|
||||
|
||||
// 快进5秒
|
||||
fastForward5sButton.addActionListener(e -> videoPlayer.fastForward(5000));
|
||||
|
||||
// 开始播放按钮的行为
|
||||
startPlayButton.addActionListener(e -> {
|
||||
String streamUrl = streamUrlField.getText().trim();
|
||||
if (!streamUrl.isEmpty()) {
|
||||
try {
|
||||
videoPlayer.loadVideo(streamUrl);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
JOptionPane.showMessageDialog(this, "无法播放流地址: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(this, "请输入流地址或摄像头索引。", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 选择视频文件
|
||||
private void selectVideoFile() {
|
||||
File desktopDir = FileSystemView.getFileSystemView().getHomeDirectory();
|
||||
JFileChooser fileChooser = new JFileChooser(desktopDir);
|
||||
fileChooser.setDialogTitle("选择视频文件");
|
||||
// 设置视频文件过滤器,支持常见的视频格式
|
||||
FileNameExtensionFilter videoFilter = new FileNameExtensionFilter(
|
||||
"视频文件 (*.mp4;*.avi;*.mkv;*.mov;*.flv;*.wmv)", "mp4", "avi", "mkv", "mov", "flv", "wmv");
|
||||
fileChooser.setFileFilter(videoFilter);
|
||||
|
||||
int returnValue = fileChooser.showOpenDialog(this);
|
||||
if (returnValue == JFileChooser.APPROVE_OPTION) {
|
||||
File selectedFile = fileChooser.getSelectedFile();
|
||||
try {
|
||||
videoPlayer.loadVideo(selectedFile.getAbsolutePath());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
JOptionPane.showMessageDialog(this, "加载视频失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SwingUtilities.invokeLater(VideoInferenceApp::new);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.ly.file;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
|
||||
public class FileEditor {
|
||||
public static void openFileEditor(String filePath) {
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
JOptionPane.showMessageDialog(null, "文件不存在:" + filePath, "错误", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
// 仅对文本文件进行编辑
|
||||
if (file.getName().endsWith(".txt")) {
|
||||
JTextArea textArea = new JTextArea();
|
||||
JScrollPane scrollPane = new JScrollPane(textArea);
|
||||
scrollPane.setPreferredSize(new Dimension(600, 400));
|
||||
|
||||
// 读取文件内容
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
textArea.read(reader, null);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
JOptionPane.showMessageDialog(null, "无法读取文件:" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
int result = JOptionPane.showConfirmDialog(null, scrollPane, "编辑文件:" + file.getName(),
|
||||
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
|
||||
if (result == JOptionPane.OK_OPTION) {
|
||||
// 保存文件内容
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||
textArea.write(writer);
|
||||
JOptionPane.showMessageDialog(null, "文件已保存。", "信息", JOptionPane.INFORMATION_MESSAGE);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
JOptionPane.showMessageDialog(null, "无法保存文件:" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(null, "无法编辑非文本文件。", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.ly.layout;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class VideoPanel extends JPanel {
|
||||
private BufferedImage image;
|
||||
|
||||
public void updateImage(BufferedImage img) {
|
||||
this.image = img;
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void clearImage() {
|
||||
this.image = null;
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
if (image != null) {
|
||||
Graphics2D g2d = (Graphics2D) g.create();
|
||||
|
||||
// 启用抗锯齿和高质量渲染
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
// 缩放图片以适应面板大小
|
||||
int panelWidth = this.getWidth();
|
||||
int panelHeight = this.getHeight();
|
||||
double imgAspect = (double) image.getWidth() / image.getHeight();
|
||||
double panelAspect = (double) panelWidth / panelHeight;
|
||||
|
||||
int drawWidth, drawHeight;
|
||||
if (imgAspect > panelAspect) {
|
||||
drawWidth = panelWidth;
|
||||
drawHeight = (int) (panelWidth / imgAspect);
|
||||
} else {
|
||||
drawHeight = panelHeight;
|
||||
drawWidth = (int) (panelHeight * imgAspect);
|
||||
}
|
||||
|
||||
g2d.drawImage(image, (panelWidth - drawWidth) / 2, (panelHeight - drawHeight) / 2,
|
||||
drawWidth, drawHeight, null);
|
||||
|
||||
g2d.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.ly.model_load;
|
||||
|
||||
|
||||
|
||||
import com.ly.file.FileEditor;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
|
||||
public class ModelManager extends JPanel {
|
||||
private DefaultListModel<String> modelListModel;
|
||||
private JList<String> modelList;
|
||||
|
||||
public ModelManager() {
|
||||
setLayout(new BorderLayout());
|
||||
modelListModel = new DefaultListModel<>();
|
||||
modelList = new JList<>(modelListModel);
|
||||
JScrollPane modelScrollPane = new JScrollPane(modelList);
|
||||
add(modelScrollPane, BorderLayout.CENTER);
|
||||
|
||||
// 添加双击事件,编辑标签文件
|
||||
modelList.addMouseListener(new MouseAdapter() {
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
int index = modelList.locationToIndex(e.getPoint());
|
||||
if (index >= 0) {
|
||||
String item = modelListModel.getElementAt(index);
|
||||
// 解析标签文件路径
|
||||
String[] parts = item.split("\n");
|
||||
if (parts.length >= 2) {
|
||||
String labelFilePath = parts[1].replace("标签文件: ", "").trim();
|
||||
FileEditor.openFileEditor(labelFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 加载模型
|
||||
public void loadModel(JFrame parent) {
|
||||
// 获取桌面目录
|
||||
File desktopDir = FileSystemView.getFileSystemView().getHomeDirectory();
|
||||
JFileChooser fileChooser = new JFileChooser(desktopDir);
|
||||
fileChooser.setDialogTitle("选择模型文件");
|
||||
|
||||
// 设置模型文件过滤器,只显示 .onnx 文件
|
||||
FileNameExtensionFilter modelFilter = new FileNameExtensionFilter("ONNX模型文件 (*.onnx)", "onnx");
|
||||
fileChooser.setFileFilter(modelFilter);
|
||||
|
||||
int returnValue = fileChooser.showOpenDialog(parent);
|
||||
if (returnValue == JFileChooser.APPROVE_OPTION) {
|
||||
File modelFile = fileChooser.getSelectedFile();
|
||||
|
||||
// 选择对应的标签文件
|
||||
fileChooser.setDialogTitle("选择标签文件");
|
||||
|
||||
// 设置标签文件过滤器,只显示 .txt 文件
|
||||
FileNameExtensionFilter labelFilter = new FileNameExtensionFilter("标签文件 (*.txt)", "txt");
|
||||
fileChooser.setFileFilter(labelFilter);
|
||||
|
||||
returnValue = fileChooser.showOpenDialog(parent);
|
||||
if (returnValue == JFileChooser.APPROVE_OPTION) {
|
||||
File labelFile = fileChooser.getSelectedFile();
|
||||
|
||||
// 将模型和标签文件添加到列表中
|
||||
String item = "模型文件: " + modelFile.getAbsolutePath() + "\n标签文件: " + labelFile.getAbsolutePath();
|
||||
modelListModel.addElement(item);
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(parent, "未选择标签文件。", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(parent, "未选择模型文件。", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
package com.ly.play;
|
||||
|
||||
import com.ly.layout.VideoPanel;
|
||||
import org.bytedeco.javacv.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class VideoPlayer {
|
||||
private FrameGrabber grabber;
|
||||
private Java2DFrameConverter converter = new Java2DFrameConverter();
|
||||
private boolean isPlaying = false;
|
||||
private boolean isPaused = false;
|
||||
private Thread videoThread;
|
||||
private VideoPanel videoPanel;
|
||||
|
||||
private long videoDuration = 0; // 毫秒
|
||||
private long currentTimestamp = 0; // 毫秒
|
||||
|
||||
public VideoPlayer(VideoPanel videoPanel) {
|
||||
this.videoPanel = videoPanel;
|
||||
}
|
||||
|
||||
// 加载视频或流
|
||||
// 加载视频或流
|
||||
public void loadVideo(String videoFilePathOrStreamUrl) throws Exception {
|
||||
stopVideo();
|
||||
|
||||
|
||||
if (videoFilePathOrStreamUrl.equals("0")) {
|
||||
int cameraIndex = Integer.parseInt(videoFilePathOrStreamUrl);
|
||||
grabber = new OpenCVFrameGrabber(cameraIndex);
|
||||
grabber.start();
|
||||
videoDuration = 0; // 摄像头没有固定的时长
|
||||
playVideo();
|
||||
} else {
|
||||
// 输入不是数字,尝试使用 FFmpegFrameGrabber 打开流或视频文件
|
||||
grabber = new FFmpegFrameGrabber(videoFilePathOrStreamUrl);
|
||||
grabber.start();
|
||||
videoDuration = grabber.getLengthInTime() / 1000; // 转换为毫秒
|
||||
}
|
||||
|
||||
|
||||
// 显示第一帧
|
||||
Frame frame;
|
||||
if (grabber instanceof OpenCVFrameGrabber) {
|
||||
frame = grabber.grab();
|
||||
} else {
|
||||
frame = grabber.grab();
|
||||
}
|
||||
if (frame != null && frame.image != null) {
|
||||
BufferedImage bufferedImage = converter.getBufferedImage(frame);
|
||||
videoPanel.updateImage(bufferedImage);
|
||||
currentTimestamp = 0;
|
||||
}
|
||||
|
||||
// 重置到视频开始位置
|
||||
if (grabber instanceof FFmpegFrameGrabber) {
|
||||
grabber.setTimestamp(0);
|
||||
}
|
||||
currentTimestamp = 0;
|
||||
}
|
||||
|
||||
public void playVideo() {
|
||||
if (grabber == null) {
|
||||
JOptionPane.showMessageDialog(null, "请先加载视频文件或流。", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPlaying) {
|
||||
if (isPaused) {
|
||||
isPaused = false; // 恢复播放
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
isPlaying = true;
|
||||
isPaused = false;
|
||||
|
||||
videoThread = new Thread(() -> {
|
||||
try {
|
||||
if (grabber instanceof OpenCVFrameGrabber) {
|
||||
// 摄像头捕获
|
||||
while (isPlaying) {
|
||||
if (isPaused) {
|
||||
Thread.sleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
Frame frame = grabber.grab();
|
||||
if (frame == null) {
|
||||
isPlaying = false;
|
||||
break;
|
||||
}
|
||||
|
||||
BufferedImage bufferedImage = converter.getBufferedImage(frame);
|
||||
if (bufferedImage != null) {
|
||||
videoPanel.updateImage(bufferedImage);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 视频文件或流
|
||||
double frameRate = grabber.getFrameRate();
|
||||
if (frameRate <= 0 || Double.isNaN(frameRate)) {
|
||||
frameRate = 25; // 默认帧率
|
||||
}
|
||||
long frameInterval = (long) (1000 / frameRate); // 每帧间隔时间(毫秒)
|
||||
long startTime = System.currentTimeMillis();
|
||||
long frameCount = 0;
|
||||
|
||||
while (isPlaying) {
|
||||
if (isPaused) {
|
||||
Thread.sleep(100);
|
||||
startTime += 100; // 调整开始时间以考虑暂停时间
|
||||
continue;
|
||||
}
|
||||
|
||||
Frame frame = grabber.grab();
|
||||
if (frame == null) {
|
||||
// 视频播放结束
|
||||
isPlaying = false;
|
||||
break;
|
||||
}
|
||||
|
||||
BufferedImage bufferedImage = converter.getBufferedImage(frame);
|
||||
if (bufferedImage != null) {
|
||||
videoPanel.updateImage(bufferedImage);
|
||||
|
||||
// 更新当前帧时间戳
|
||||
frameCount++;
|
||||
long expectedTime = frameCount * frameInterval;
|
||||
long actualTime = System.currentTimeMillis() - startTime;
|
||||
|
||||
currentTimestamp = grabber.getTimestamp() / 1000;
|
||||
|
||||
// 如果实际时间落后于预期时间,进行调整
|
||||
if (actualTime < expectedTime) {
|
||||
Thread.sleep(expectedTime - actualTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 视频播放完毕后,停止播放
|
||||
isPlaying = false;
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
videoThread.start();
|
||||
}
|
||||
|
||||
// 暂停视频
|
||||
public void pauseVideo() {
|
||||
if (!isPlaying) {
|
||||
return;
|
||||
}
|
||||
isPaused = true;
|
||||
}
|
||||
|
||||
// 重播视频
|
||||
public void replayVideo() {
|
||||
try {
|
||||
if (grabber instanceof FFmpegFrameGrabber) {
|
||||
grabber.setTimestamp(0); // 重置到视频开始位置
|
||||
grabber.flush(); // 清除缓存
|
||||
currentTimestamp = 0;
|
||||
|
||||
// 显示第一帧
|
||||
Frame frame = grabber.grab();
|
||||
if (frame != null && frame.image != null) {
|
||||
BufferedImage bufferedImage = converter.getBufferedImage(frame);
|
||||
videoPanel.updateImage(bufferedImage);
|
||||
}
|
||||
|
||||
playVideo(); // 开始播放
|
||||
} else if (grabber instanceof OpenCVFrameGrabber) {
|
||||
// 对于摄像头,重播相当于重新开始播放
|
||||
playVideo();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
JOptionPane.showMessageDialog(null, "重播失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
// 停止视频
|
||||
public void stopVideo() {
|
||||
isPlaying = false;
|
||||
isPaused = false;
|
||||
|
||||
if (videoThread != null && videoThread.isAlive()) {
|
||||
try {
|
||||
videoThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (grabber != null) {
|
||||
try {
|
||||
grabber.stop();
|
||||
grabber.release();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
grabber = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 快进或后退
|
||||
public void seekTo(long seekTime) {
|
||||
if (grabber == null) return;
|
||||
if (!(grabber instanceof FFmpegFrameGrabber)) {
|
||||
JOptionPane.showMessageDialog(null, "此操作仅支持视频文件和流。", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
isPaused = false; // 取消暂停
|
||||
isPlaying = false; // 停止当前播放线程
|
||||
if (videoThread != null && videoThread.isAlive()) {
|
||||
videoThread.join();
|
||||
}
|
||||
|
||||
grabber.setTimestamp(seekTime * 1000); // 转换为微秒
|
||||
grabber.flush(); // 清除缓存
|
||||
|
||||
Frame frame;
|
||||
do {
|
||||
frame = grabber.grab();
|
||||
if (frame == null) {
|
||||
break;
|
||||
}
|
||||
} while (frame.image == null); // 跳过没有图像的帧
|
||||
|
||||
if (frame != null && frame.image != null) {
|
||||
BufferedImage bufferedImage = converter.getBufferedImage(frame);
|
||||
videoPanel.updateImage(bufferedImage);
|
||||
|
||||
// 更新当前帧时间戳
|
||||
currentTimestamp = grabber.getTimestamp() / 1000;
|
||||
}
|
||||
|
||||
// 重新开始播放
|
||||
playVideo();
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// 快进
|
||||
public void fastForward(long milliseconds) {
|
||||
if (!(grabber instanceof FFmpegFrameGrabber)) {
|
||||
JOptionPane.showMessageDialog(null, "此操作仅支持视频文件和流。", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
long newTime = Math.min(currentTimestamp + milliseconds, videoDuration);
|
||||
seekTo(newTime);
|
||||
}
|
||||
|
||||
// 后退
|
||||
public void rewind(long milliseconds) {
|
||||
if (!(grabber instanceof FFmpegFrameGrabber)) {
|
||||
JOptionPane.showMessageDialog(null, "此操作仅支持视频文件和流。", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
long newTime = Math.max(currentTimestamp - milliseconds, 0);
|
||||
seekTo(newTime);
|
||||
}
|
||||
|
||||
public long getVideoDuration() {
|
||||
return videoDuration;
|
||||
}
|
||||
|
||||
public FrameGrabber getGrabber() {
|
||||
return grabber;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.ly.utils;
|
||||
|
||||
import org.bytedeco.javacv.FrameGrabber;
|
||||
import org.bytedeco.javacv.VideoInputFrameGrabber;
|
||||
|
||||
public class CameraDeviceLister {
|
||||
public static void main(String[] args) throws FrameGrabber.Exception {
|
||||
String[] deviceDescriptions = VideoInputFrameGrabber.getDeviceDescriptions();
|
||||
for (String deviceDescription : deviceDescriptions) {
|
||||
System.out.println("摄像头索引 " + ": " + deviceDescription);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.ly.utils;
|
||||
|
||||
import org.bytedeco.ffmpeg.global.avcodec;
|
||||
import org.bytedeco.javacv.*;
|
||||
|
||||
public class RTSPStreamer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
String inputFile = "C:\\Users\\ly\\Desktop\\屏幕录制 2024-09-20 225443.mp4"; // 替换为您的本地视频文件路径
|
||||
String rtspUrl = "rtsp://localhost:8554/live"; // 替换为您的 RTSP 服务器地址
|
||||
|
||||
FFmpegFrameGrabber grabber = null;
|
||||
FFmpegFrameRecorder recorder = null;
|
||||
|
||||
try {
|
||||
// 初始化 FFmpegFrameGrabber 以从本地视频文件读取
|
||||
grabber = new FFmpegFrameGrabber(inputFile);
|
||||
grabber.start();
|
||||
|
||||
// 初始化 FFmpegFrameRecorder 以推流到 RTSP 服务器
|
||||
recorder = new FFmpegFrameRecorder(rtspUrl, grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels());
|
||||
recorder.setFormat("rtsp");
|
||||
recorder.setFrameRate(grabber.getFrameRate());
|
||||
recorder.setVideoBitrate(grabber.getVideoBitrate());
|
||||
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 设置视频编码格式
|
||||
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC); // 设置音频编码格式
|
||||
|
||||
// 设置 RTSP 传输选项(如果需要)
|
||||
recorder.setOption("rtsp_transport", "tcp");
|
||||
|
||||
recorder.start();
|
||||
|
||||
Frame frame;
|
||||
while ((frame = grabber.grab()) != null) {
|
||||
recorder.record(frame);
|
||||
}
|
||||
|
||||
System.out.println("推流完成。");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (recorder != null) {
|
||||
recorder.stop();
|
||||
recorder.release();
|
||||
}
|
||||
if (grabber != null) {
|
||||
grabber.stop();
|
||||
grabber.release();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue