2023年5月20日16:51:49 添加视频转码

master
zhangmeng 2023-05-20 16:52:17 +08:00
parent a2fb170794
commit c92785953d
9 changed files with 278 additions and 1 deletions

View File

@ -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>

View File

@ -14,7 +14,8 @@ public class Constants {
public enum Type {
Music
Music,
VideoTranscoder
}
public static Map<Type, AnchorPane> pane_map = new HashMap<>();

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}
}

View File

@ -87,6 +87,7 @@ public class ResourcesUtils {
Music("音乐播放", 1),
VipParser("vip解析", 2),
MusicParser("音乐解析", 3),
VideoTranscoder("视频转码",4)
;
Player(String title, int index) {

View File

@ -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="常用小工具">

View File

@ -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="常用小工具">

View File

@ -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>