2023年5月20日16:51:49 添加视频转码
parent
a2fb170794
commit
c92785953d
4
pom.xml
4
pom.xml
|
|
@ -448,6 +448,10 @@
|
|||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>xuggle repo</id>
|
||||
<url>http://xuggle.googlecode.com/svn/trunk/repo/share/java/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jitpack.io</id>
|
||||
<url>https://jitpack.io</url>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ public class Constants {
|
|||
|
||||
|
||||
public enum Type {
|
||||
Music
|
||||
Music,
|
||||
VideoTranscoder
|
||||
}
|
||||
|
||||
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) {
|
||||
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 vip_parser;
|
||||
private AnchorPane music_parser;
|
||||
private AnchorPane video_transcoder;
|
||||
|
||||
private MusicController musicController;
|
||||
private VideoController videoController;
|
||||
private MusicDownloadController musicDownloadController;
|
||||
private VideoTranscoderController videoTranscoderController;
|
||||
|
||||
@FXML
|
||||
private ListView<ResourcesUtils.Player> listView;
|
||||
|
|
@ -115,6 +117,9 @@ public class PlayerController {
|
|||
Constants.setRoot(Constants.Type.Music,music);
|
||||
}
|
||||
|
||||
if (video_transcoder != null){
|
||||
Constants.setRoot(Constants.Type.VideoTranscoder,video_transcoder);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
|
|
@ -336,6 +341,13 @@ public class PlayerController {
|
|||
}
|
||||
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 VipParser -> 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();
|
||||
}
|
||||
|
||||
//视频转码
|
||||
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) {
|
||||
listView.getSelectionModel().select(2);
|
||||
|
||||
|
|
@ -655,4 +691,12 @@ public class PlayerController {
|
|||
public void socket_client_nio_menu_item(ActionEvent event) {
|
||||
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),
|
||||
VipParser("vip解析", 2),
|
||||
MusicParser("音乐解析", 3),
|
||||
VideoTranscoder("视频转码",4)
|
||||
;
|
||||
|
||||
Player(String title, int index) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
<MenuItem mnemonicParsing="false" text="音乐播放" onAction="#music_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="#video_transcoder_menu_item"/>
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="常用小工具">
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
<MenuItem mnemonicParsing="false" text="音乐播放" onAction="#music_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="#video_transcoder_menu_item"/>
|
||||
</items>
|
||||
</Menu>
|
||||
<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