Quellcode durchsuchen

feat: tool support add audio

hexleo vor 5 Jahren
Ursprung
Commit
fe9b96dce7

+ 36 - 14
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/AnimTool.java

@@ -21,13 +21,10 @@ import com.tencent.qgame.playerproj.animtool.vapx.SrcSet;
 
 import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
-import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.concurrent.TimeUnit;
 
 public class AnimTool {
 
@@ -36,7 +33,8 @@ public class AnimTool {
     public static final String OUTPUT_DIR = "output"+ File.separator;
     public static final String FRAME_IMAGE_DIR = "frames"+ File.separator;
     public static final String VIDEO_FILE = "video.mp4";
-    public static final String TEM_VIDEO_FILE = "tmp_video.mp4";
+    public static final String TEMP_VIDEO_FILE = "tmp_video.mp4";
+    public static final String TEMP_VIDEO_AUDIO_FILE = "tmp_video_audio.mp4";
     public static final String VAPC_BIN_FILE = "vapc.bin";
     public static final String VAPC_JSON_FILE = "vapc.json";
 
@@ -204,17 +202,30 @@ public class AnimTool {
                 TLog.i(TAG, "createMp4 fail");
                 return;
             }
+            String tempVideoName = TEMP_VIDEO_FILE;
+            if (commonArg.needAudio) {
+                result = mergeAudio2Mp4(commonArg, tempVideoName);
+                if (!result) {
+                    TLog.i(TAG, "mergeAudio2Mp4 fail");
+                    return;
+                }
+                tempVideoName = TEMP_VIDEO_AUDIO_FILE;
+            }
+
             String input = commonArg.outputPath + VAPC_JSON_FILE;
             // 由json变为bin文件
             String vapcBinPath = mp4BoxTool(input, commonArg.outputPath);
             // 将bin文件合并到mp4里
-            result = mergeBin2Mp4(commonArg, vapcBinPath, commonArg.outputPath);
+            result = mergeBin2Mp4(commonArg, vapcBinPath, tempVideoName, commonArg.outputPath);
             if (!result) {
                 TLog.i(TAG, "mergeBin2Mp4 fail");
                 return;
             }
             // 删除临时视频文件
-            new File(commonArg.outputPath + TEM_VIDEO_FILE).delete();
+            new File(commonArg.outputPath + TEMP_VIDEO_FILE).delete();
+            if (commonArg.needAudio) {
+                new File(commonArg.outputPath + TEMP_VIDEO_AUDIO_FILE).delete();
+            }
             new File(commonArg.outputPath + VAPC_BIN_FILE).delete();
             // 计算文件md5
             String md5 = new Md5Util().getFileMD5(new File(commonArg.outputPath + VIDEO_FILE), commonArg.outputPath);
@@ -274,8 +285,6 @@ public class AnimTool {
 
     /**
      * 创建mp4
-     * @param commonArg
-     * @throws Exception
      */
     private boolean createMp4(CommonArg commonArg, String videoPath, String frameImagePath) throws Exception {
         String[] cmd = null;
@@ -289,7 +298,7 @@ public class AnimTool {
                     "-level", "4.0",
                     "-tag:v", "hvc1",
                     "-bufsize", "2000k",
-                    "-y", videoPath + TEM_VIDEO_FILE};
+                    "-y", videoPath + TEMP_VIDEO_FILE};
         } else {
             cmd = new String[]{commonArg.ffmpegCmd, "-r", String.valueOf(commonArg.fps),
                     "-i", frameImagePath + "%03d.png",
@@ -300,7 +309,7 @@ public class AnimTool {
                     "-level", "4.0",
                     "-bf", "0",
                     "-bufsize", "3000k",
-                    "-y", videoPath + TEM_VIDEO_FILE};
+                    "-y", videoPath + TEMP_VIDEO_FILE};
         }
 
         TLog.i(TAG, "run createMp4");
@@ -309,13 +318,26 @@ public class AnimTool {
         return result == 0;
     }
 
+    /**
+     * 合并音频文件
+     */
+    private boolean mergeAudio2Mp4(CommonArg commonArg, String tempVideoFile) throws Exception {
+        String[] cmd = new String[] {commonArg.ffmpegCmd,
+                "-i", commonArg.audioPath,
+                "-i", commonArg.outputPath + tempVideoFile,
+                "-y", commonArg.outputPath + TEMP_VIDEO_AUDIO_FILE};
+        TLog.i(TAG, "run mergeAudio2Mp4");
+        int result = ProcessUtil.run(cmd);
+        TLog.i(TAG, "mergeAudio2Mp4 result=" + (result == 0? "success" : "fail"));
+        return result == 0;
+    }
+
+
     /**
      * 合并vapc.bin到mp4里
-     * @param inputFile
-     * @throws Exception
      */
-    private boolean mergeBin2Mp4(CommonArg commonArg, String inputFile, String videoPath) throws Exception{
-        String[] cmd = new String[] {commonArg.mp4editCmd, "--insert", ":"+inputFile+":1", videoPath + TEM_VIDEO_FILE, videoPath + VIDEO_FILE};
+    private boolean mergeBin2Mp4(CommonArg commonArg, String inputFile, String tempVideoFile, String videoPath) throws Exception{
+        String[] cmd = new String[] {commonArg.mp4editCmd, "--insert", ":"+inputFile+":1", videoPath + tempVideoFile, videoPath + VIDEO_FILE};
         TLog.i(TAG, "run mergeBin2Mp4");
         int result = ProcessUtil.run(cmd);
         TLog.i(TAG, "mergeBin2Mp4 result=" + (result == 0? "success" : "fail"));

+ 6 - 0
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/CommonArg.java

@@ -56,6 +56,10 @@ public class CommonArg {
 
     public int outputH = 0;
 
+    public boolean needAudio = false;
+
+    public String audioPath; // 音频地址
+
     /**
      * 融合动画相关参数
      */
@@ -74,6 +78,8 @@ public class CommonArg {
                 ", fps=" + fps +
                 ", scale=" + scale +
                 ", inputPath='" + inputPath + '\'' +
+                ", needAudio=" + needAudio + '\'' +
+                ", audioPath='" + audioPath + '\'' +
                 '}';
     }
 }

+ 15 - 1
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/CommonArgTool.java

@@ -39,6 +39,21 @@ class CommonArgTool {
         if (!File.separator.equals(commonArg.inputPath.substring(commonArg.inputPath.length() - 1))) {
             commonArg.inputPath = commonArg.inputPath + File.separator;
         }
+
+        // 检查音频文件是否存在
+        if (commonArg.needAudio) {
+            File audio = new File(commonArg.audioPath);
+            if (!audio.exists() || commonArg.audioPath == null || commonArg.audioPath.length() < 3) {
+                TLog.e(TAG , "audio file not exists " + commonArg.audioPath);
+                return false;
+            }
+            String type = commonArg.audioPath.substring(commonArg.audioPath.length() - 3).toLowerCase();
+            if (!"mp3".equals(type)) {
+                TLog.e(TAG , "audio file must be mp3 file " + commonArg.audioPath);
+                return false;
+            }
+        }
+
         // output path
         commonArg.outputPath = commonArg.inputPath + AnimTool.OUTPUT_DIR;
 
@@ -127,7 +142,6 @@ class CommonArgTool {
         commonArg.outputH += size[1];
 
         if (commonArg.outputW > 1504 || commonArg.outputH > 1504) {
-
             String msg = "[Warning] Output video width:" + commonArg.outputW + " or height:" + commonArg.outputH
                     + " is over 1504. Some devices will display exception, like video turn green!";
             TLog.w(TAG, msg);

+ 72 - 9
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/ui/ToolUI.java

@@ -53,12 +53,16 @@ public class ToolUI {
     private final JTextField textInputPath = new JTextField();
     private final JButton btnCreate = new JButton("create VAP");
     private final JTextArea txtAreaLog = new JTextArea();
+    private final JTextField textAudioPath = new JTextField();
+    private final JPanel panelAudioPath = new JPanel();
+
     private final JLabel labelOutInfo = new JLabel();
     private final Dimension labelSize = new Dimension(100, 20);
     private final Properties props = new Properties();
-
     private final VapxUI vapxUI = new VapxUI();
 
+    private boolean needAudio = false;
+
     public ToolUI() {
         TLog.logger = new TLog.ITLog() {
             @Override
@@ -95,6 +99,7 @@ public class ToolUI {
             group.setSelected(commonArg.enableH265 ? btnH265.getModel() : btnH264.getModel(), true);
             modelFps.setValue(commonArg.fps);
             textInputPath.setText(commonArg.inputPath);
+            textAudioPath.setText(commonArg.audioPath);
             float scale = commonArg.scale;
             for (int i=0; i<scaleArray.length ; i++) {
                 if (scaleArray[i] == scale) {
@@ -142,6 +147,10 @@ public class ToolUI {
         commonArg.fps = (Integer)modelFps.getValue();
         commonArg.inputPath = textInputPath.getText();
         commonArg.scale = scaleArray[boxScale.getSelectedIndex()];
+        if (needAudio) {
+            commonArg.needAudio = true;
+            commonArg.audioPath = textAudioPath.getText();
+        }
 
         TLog.i(TAG, commonArg.toString());
 
@@ -205,6 +214,8 @@ public class ToolUI {
         panel.add(getScaleLayout());
         // path
         panel.add(getPathLayout());
+        // audio path
+        panel.add(getAudioPathLayout());
         // vapx
         panel.add(vapxUI.createUI());
         // create
@@ -263,7 +274,7 @@ public class ToolUI {
         JPanel panel = new JPanel();
 
         panel.setLayout(new FlowLayout(FlowLayout.LEFT));
-        JLabel label = new JLabel("input path");
+        JLabel label = new JLabel("frames path");
         label.setPreferredSize(labelSize);
         panel.add(label);
         JPanel gPanel = new JPanel();
@@ -272,7 +283,7 @@ public class ToolUI {
         BoxLayout layout = new BoxLayout(gPanel, BoxLayout.LINE_AXIS);
         gPanel.setLayout(layout);
 
-        textInputPath.setPreferredSize(new Dimension(300,20));
+        textInputPath.setPreferredSize(new Dimension(400,20));
         gPanel.add(textInputPath);
 
         JButton btnInputPath = new JButton("choose");
@@ -294,6 +305,55 @@ public class ToolUI {
         return panel;
     }
 
+
+    private JPanel getAudioPathLayout() {
+        JPanel panel = new JPanel();
+
+        panel.setLayout(new FlowLayout(FlowLayout.LEFT));
+        JLabel label = new JLabel("audio path");
+        label.setPreferredSize(labelSize);
+        panel.add(label);
+        panel.add(panelAudioPath);
+        final JLabel labelAudioAction = new JLabel("+");
+        panel.add(labelAudioAction);
+        labelAudioAction.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mouseClicked(MouseEvent mouseEvent) {
+                needAudio = !needAudio;
+                panelAudioPath.setVisible(needAudio);
+                labelAudioAction.setText(needAudio ? "x" : "+");
+            }
+        });
+
+        BoxLayout layout = new BoxLayout(panelAudioPath, BoxLayout.LINE_AXIS);
+        panelAudioPath.setLayout(layout);
+
+        textAudioPath.setPreferredSize(new Dimension(400,20));
+        panelAudioPath.add(textAudioPath);
+
+        JButton btnInputPath = new JButton("choose");
+        panelAudioPath.add(btnInputPath);
+        btnInputPath.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent actionEvent) {
+                JFileChooser fileChooser = new JFileChooser();
+                fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+                int returnVal = fileChooser.showOpenDialog(fileChooser);
+                if(returnVal == JFileChooser.APPROVE_OPTION) {
+                    // 文件夹路径
+                    String filePath = fileChooser.getSelectedFile().getAbsolutePath();
+                    textAudioPath.setText(filePath);
+                }
+            }
+        });
+
+        if (!needAudio) {
+            panelAudioPath.setVisible(false);
+        }
+
+        return panel;
+    }
+
     private void setOutput(final String path) {
         labelOutInfo.setText("<html><font color='blue'>open output</font></html>");
         labelOutInfo.addMouseListener(new MouseAdapter() {
@@ -367,13 +427,14 @@ public class ToolUI {
 
     private CommonArg getProperties() {
         CommonArg commonArg = new CommonArg();
-        String version = props.getProperty("version", "0");
-        String enableH265 = props.getProperty("enableH265", Boolean.TRUE.toString());
-        String fps = props.getProperty("fps", String.valueOf(commonArg.fps));
-        String inputPath = props.getProperty("inputPath", "");
-        String scale = props.getProperty("scale", String.valueOf(scaleArray[0]));
-
         try {
+            String version = props.getProperty("version", "0");
+            String enableH265 = props.getProperty("enableH265", Boolean.TRUE.toString());
+            String fps = props.getProperty("fps", String.valueOf(commonArg.fps));
+            String inputPath = props.getProperty("inputPath", "");
+            String scale = props.getProperty("scale", String.valueOf(scaleArray[0]));
+            String audioPath = props.getProperty("audioPath", "");
+
             int v = Integer.parseInt(version);
             // 版本不符直接返回默认值
             if (v != commonArg.version) return commonArg;
@@ -381,6 +442,7 @@ public class ToolUI {
             commonArg.scale = Float.parseFloat(scale);
             commonArg.enableH265 = Boolean.TRUE.toString().equals(enableH265);
             commonArg.inputPath = inputPath;
+            commonArg.audioPath = audioPath;
         } catch (Exception e) {
             TLog.e(TAG, "getProperties error:" + e.getMessage());
         }
@@ -393,6 +455,7 @@ public class ToolUI {
         props.setProperty("enableH265", commonArg.enableH265? Boolean.TRUE.toString() : Boolean.FALSE.toString());
         props.setProperty("fps", commonArg.fps + "");
         props.setProperty("inputPath", commonArg.inputPath == null ? "" : commonArg.inputPath);
+        props.setProperty("audioPath", commonArg.audioPath == null ? "" : commonArg.audioPath);
         props.setProperty("scale", commonArg.scale + "");
         props.store(new FileOutputStream(PROPERTIES_FILE), "");
     }