2023年5月20日16:51:49 添加视频转码
parent
a2fb170794
commit
c92785953d
4
pom.xml
4
pom.xml
|
|
@ -448,6 +448,10 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
<repositories>
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>xuggle repo</id>
|
||||||
|
<url>http://xuggle.googlecode.com/svn/trunk/repo/share/java/</url>
|
||||||
|
</repository>
|
||||||
<repository>
|
<repository>
|
||||||
<id>jitpack.io</id>
|
<id>jitpack.io</id>
|
||||||
<url>https://jitpack.io</url>
|
<url>https://jitpack.io</url>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ public class Constants {
|
||||||
|
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
Music
|
Music,
|
||||||
|
VideoTranscoder
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Type, AnchorPane> pane_map = new HashMap<>();
|
public static Map<Type, AnchorPane> pane_map = new HashMap<>();
|
||||||
|
|
|
||||||
|
|
@ -570,4 +570,8 @@ public class HomeController implements Serializable {
|
||||||
public void sql_query_gen_menu_item(ActionEvent event) {
|
public void sql_query_gen_menu_item(ActionEvent event) {
|
||||||
load_sql_tools(3);
|
load_sql_tools(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void video_transcoder_menu_item(ActionEvent event) {
|
||||||
|
load_player(4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,10 +76,12 @@ public class PlayerController {
|
||||||
private AnchorPane music;
|
private AnchorPane music;
|
||||||
private AnchorPane vip_parser;
|
private AnchorPane vip_parser;
|
||||||
private AnchorPane music_parser;
|
private AnchorPane music_parser;
|
||||||
|
private AnchorPane video_transcoder;
|
||||||
|
|
||||||
private MusicController musicController;
|
private MusicController musicController;
|
||||||
private VideoController videoController;
|
private VideoController videoController;
|
||||||
private MusicDownloadController musicDownloadController;
|
private MusicDownloadController musicDownloadController;
|
||||||
|
private VideoTranscoderController videoTranscoderController;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ListView<ResourcesUtils.Player> listView;
|
private ListView<ResourcesUtils.Player> listView;
|
||||||
|
|
@ -115,6 +117,9 @@ public class PlayerController {
|
||||||
Constants.setRoot(Constants.Type.Music,music);
|
Constants.setRoot(Constants.Type.Music,music);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (video_transcoder != null){
|
||||||
|
Constants.setRoot(Constants.Type.VideoTranscoder,video_transcoder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
|
|
@ -336,6 +341,13 @@ public class PlayerController {
|
||||||
}
|
}
|
||||||
music_parser(flag);
|
music_parser(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newValue.getIndex() == 4) {
|
||||||
|
if (video_transcoder != null) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
video_transcoder(flag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -346,6 +358,7 @@ public class PlayerController {
|
||||||
case Music -> new Image(ImagePath.path(ImagePath.ImagePathType.MUSIC_PLAYER));
|
case Music -> new Image(ImagePath.path(ImagePath.ImagePathType.MUSIC_PLAYER));
|
||||||
case VipParser -> new Image(ImagePath.path(ImagePath.ImagePathType.VIP_PLAYER));
|
case VipParser -> new Image(ImagePath.path(ImagePath.ImagePathType.VIP_PLAYER));
|
||||||
case MusicParser -> new Image(ImagePath.path(ImagePath.ImagePathType.VIP_PLAYER));
|
case MusicParser -> new Image(ImagePath.path(ImagePath.ImagePathType.VIP_PLAYER));
|
||||||
|
case VideoTranscoder -> new Image(ImagePath.path(ImagePath.ImagePathType.VIP_PLAYER));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -429,6 +442,29 @@ public class PlayerController {
|
||||||
common_method();
|
common_method();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//视频转码
|
||||||
|
private void video_transcoder(boolean flag) {
|
||||||
|
listView.getSelectionModel().select(4);
|
||||||
|
if (!flag) {
|
||||||
|
if (Constants.getRoot(Constants.Type.VideoTranscoder) != null){
|
||||||
|
root = Constants.getRoot(Constants.Type.VideoTranscoder);
|
||||||
|
video_transcoder = root;
|
||||||
|
}else {
|
||||||
|
try {
|
||||||
|
FXMLLoader load = new FXMLLoader(ResourcesUtils.getResource("video-transcoder"));
|
||||||
|
root = load.load();
|
||||||
|
videoTranscoderController = load.getController();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
video_transcoder = root;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
root = video_transcoder;
|
||||||
|
}
|
||||||
|
common_method();
|
||||||
|
}
|
||||||
|
|
||||||
private void vip_parser(boolean flag) {
|
private void vip_parser(boolean flag) {
|
||||||
listView.getSelectionModel().select(2);
|
listView.getSelectionModel().select(2);
|
||||||
|
|
||||||
|
|
@ -655,4 +691,12 @@ public class PlayerController {
|
||||||
public void socket_client_nio_menu_item(ActionEvent event) {
|
public void socket_client_nio_menu_item(ActionEvent event) {
|
||||||
load_server_tools(7);
|
load_server_tools(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void video_transcoder_menu_item(ActionEvent event) {
|
||||||
|
boolean flag = false;
|
||||||
|
if (video_transcoder != null){
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
video_transcoder(flag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,198 @@
|
||||||
|
package com.zhangmeng.tools.controller;
|
||||||
|
|
||||||
|
import com.zhangmeng.tools.utils.AlertUtils;
|
||||||
|
import com.zhangmeng.tools.utils.ImagePath;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.concurrent.Task;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.ProgressBar;
|
||||||
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.media.Media;
|
||||||
|
import javafx.scene.media.MediaPlayer;
|
||||||
|
import javafx.stage.DirectoryChooser;
|
||||||
|
import javafx.stage.FileChooser;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.bytedeco.ffmpeg.global.avcodec;
|
||||||
|
import org.bytedeco.javacv.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import static org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_MPEG4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : 芊芊墨客
|
||||||
|
* @version : 1.0
|
||||||
|
* @date : 2023-05-20 12:18
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class VideoTranscoderController {
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public TextField input_file;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public TextField output_file;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public TextField output_file_name;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public Button output_file_button;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public Button input_file_button;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public Button start_button;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public ProgressBar progressbar;
|
||||||
|
|
||||||
|
public SimpleObjectProperty<File> in_file = new SimpleObjectProperty<>();
|
||||||
|
public SimpleObjectProperty<File> out_file = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
init_but(input_file_button);
|
||||||
|
init_but(output_file_button);
|
||||||
|
init_choose_dir_manager();
|
||||||
|
init_choose_file_manager();
|
||||||
|
|
||||||
|
this.start_button.setOnAction(event -> {
|
||||||
|
|
||||||
|
if (input_file.getText().length() == 0){
|
||||||
|
AlertUtils.alert_warning("请选择转码文件!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output_file.getText().length() == 0){
|
||||||
|
AlertUtils.alert_warning("输出文件目录不能为空!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output_file_name.getText().length() == 0){
|
||||||
|
AlertUtils.alert_warning("输出文件名称不能为空!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
in_file.setValue(new File(input_file.getText()));
|
||||||
|
|
||||||
|
String out_file_path = output_file.getText() + output_file_name.getText();
|
||||||
|
|
||||||
|
File file = new File(out_file_path);
|
||||||
|
if (!file.exists()){
|
||||||
|
try {
|
||||||
|
boolean newFile = file.createNewFile();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out_file.set(new File(out_file_path));
|
||||||
|
//转码
|
||||||
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
executor.submit(new TranscodeTask());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void init_choose_dir_manager(){
|
||||||
|
this.output_file_button.setOnAction(event -> {
|
||||||
|
Stage stage = new Stage();
|
||||||
|
DirectoryChooser dc = new DirectoryChooser();
|
||||||
|
dc.setTitle("文件夹选择器");
|
||||||
|
File file = dc.showDialog(stage);
|
||||||
|
if (file != null){
|
||||||
|
String path = file.getAbsolutePath();
|
||||||
|
output_file.setText(path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init_choose_file_manager(){
|
||||||
|
|
||||||
|
this.input_file_button.setOnAction(event -> {
|
||||||
|
Stage stage = new Stage();
|
||||||
|
FileChooser fc = new FileChooser();
|
||||||
|
fc.setTitle("单选文件");
|
||||||
|
fc.getExtensionFilters().addAll(
|
||||||
|
new FileChooser.ExtensionFilter("视频类型", "*.avi", "*.mp4","*.flv")
|
||||||
|
);
|
||||||
|
|
||||||
|
File file = fc.showOpenDialog(stage);
|
||||||
|
if (file == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
input_file.setText(file.getAbsolutePath());
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init_but(Button input_file_button){
|
||||||
|
input_file_button.setText(null);
|
||||||
|
ImageView iv = new ImageView(new Image(ImagePath.path(ImagePath.ImagePathType.IMAGE_FILE)));
|
||||||
|
iv.setPreserveRatio(true);
|
||||||
|
iv.setFitWidth(18);
|
||||||
|
input_file_button.setGraphic(iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TranscodeTask extends Task<Void> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void call() throws Exception {
|
||||||
|
try {
|
||||||
|
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(in_file.get());
|
||||||
|
grabber.setVideoCodec(AV_CODEC_ID_MPEG4);
|
||||||
|
grabber.start();
|
||||||
|
|
||||||
|
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(out_file.get(), grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels());
|
||||||
|
recorder.setFormat("avi");
|
||||||
|
recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4);
|
||||||
|
recorder.setFrameRate(grabber.getFrameRate());
|
||||||
|
recorder.start();
|
||||||
|
|
||||||
|
int totalFrames = grabber.getLengthInFrames();
|
||||||
|
int currentFrame = 0;
|
||||||
|
|
||||||
|
while (currentFrame < totalFrames) {
|
||||||
|
Frame frame = grabber.grab();
|
||||||
|
updateProgress(currentFrame, totalFrames);
|
||||||
|
recorder.record(frame);
|
||||||
|
// 处理视频帧
|
||||||
|
currentFrame++;
|
||||||
|
}
|
||||||
|
|
||||||
|
grabber.stop();
|
||||||
|
recorder.stop();
|
||||||
|
} catch (FrameGrabber.Exception | FrameRecorder.Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void succeeded() {
|
||||||
|
progressbar.setProgress(1);
|
||||||
|
AlertUtils.alert_msg("转码完成!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void failed() {
|
||||||
|
getException().printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateProgress(long current, long total) {
|
||||||
|
double progress = (double) current / total;
|
||||||
|
Platform.runLater(() -> progressbar.setProgress(progress));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -87,6 +87,7 @@ public class ResourcesUtils {
|
||||||
Music("音乐播放", 1),
|
Music("音乐播放", 1),
|
||||||
VipParser("vip解析", 2),
|
VipParser("vip解析", 2),
|
||||||
MusicParser("音乐解析", 3),
|
MusicParser("音乐解析", 3),
|
||||||
|
VideoTranscoder("视频转码",4)
|
||||||
;
|
;
|
||||||
|
|
||||||
Player(String title, int index) {
|
Player(String title, int index) {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
<MenuItem mnemonicParsing="false" text="音乐播放" onAction="#music_menu_item"/>
|
<MenuItem mnemonicParsing="false" text="音乐播放" onAction="#music_menu_item"/>
|
||||||
<MenuItem mnemonicParsing="false" text="vip 视频解析" onAction="#vip_parser_menu_item"/>
|
<MenuItem mnemonicParsing="false" text="vip 视频解析" onAction="#vip_parser_menu_item"/>
|
||||||
<MenuItem mnemonicParsing="false" text="音乐解析" onAction="#music_parser_menu_item"/>
|
<MenuItem mnemonicParsing="false" text="音乐解析" onAction="#music_parser_menu_item"/>
|
||||||
|
<MenuItem mnemonicParsing="false" text="视频转码" onAction="#video_transcoder_menu_item"/>
|
||||||
</items>
|
</items>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Menu mnemonicParsing="false" text="常用小工具">
|
<Menu mnemonicParsing="false" text="常用小工具">
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
<MenuItem mnemonicParsing="false" text="音乐播放" onAction="#music_menu_item"/>
|
<MenuItem mnemonicParsing="false" text="音乐播放" onAction="#music_menu_item"/>
|
||||||
<MenuItem mnemonicParsing="false" text="vip 视频解析" onAction="#vip_parser_menu_item"/>
|
<MenuItem mnemonicParsing="false" text="vip 视频解析" onAction="#vip_parser_menu_item"/>
|
||||||
<MenuItem mnemonicParsing="false" text="音乐解析" onAction="#music_parser_menu_item"/>
|
<MenuItem mnemonicParsing="false" text="音乐解析" onAction="#music_parser_menu_item"/>
|
||||||
|
<MenuItem mnemonicParsing="false" text="视频转码" onAction="#video_transcoder_menu_item"/>
|
||||||
</items>
|
</items>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Menu mnemonicParsing="false" text="常用小工具">
|
<Menu mnemonicParsing="false" text="常用小工具">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.control.ProgressBar?>
|
||||||
|
<?import javafx.scene.control.TextField?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
|
||||||
|
|
||||||
|
<AnchorPane prefHeight="649.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.zhangmeng.tools.controller.VideoTranscoderController">
|
||||||
|
<children>
|
||||||
|
<Label layoutX="73.0" layoutY="148.0" text="请选择将要转码的视频文件:" />
|
||||||
|
<Label layoutX="97.0" layoutY="198.0" text="转码后文件的输出目录:" />
|
||||||
|
<Label layoutX="798.0" layoutY="198.0" text="文件名:" />
|
||||||
|
<TextField fx:id="input_file" layoutX="321.0" layoutY="144.0" prefHeight="25.0" prefWidth="449.0" />
|
||||||
|
<TextField fx:id="output_file" layoutX="321.0" layoutY="194.0" prefHeight="25.0" prefWidth="449.0" />
|
||||||
|
<TextField fx:id="output_file_name" layoutX="855.0" layoutY="194.0" />
|
||||||
|
<Button fx:id="output_file_button" layoutX="248.0" layoutY="194.0" mnemonicParsing="false" text="Button" />
|
||||||
|
<Button fx:id="input_file_button" layoutX="248.0" layoutY="144.0" mnemonicParsing="false" text="Button" />
|
||||||
|
<Button fx:id="start_button" layoutX="496.0" layoutY="477.0" mnemonicParsing="false" text="开始转码" />
|
||||||
|
<ProgressBar fx:id="progressbar" layoutX="50.0" layoutY="352.0" prefHeight="9.0" prefWidth="1100.0" progress="0.0" AnchorPane.leftAnchor="50.0" AnchorPane.rightAnchor="50.0" />
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
Loading…
Reference in New Issue