Browse Source

feat: 更新java工具

hexleo 5 years ago
parent
commit
f5db58db86

+ 8 - 34
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/AnimTool.java

@@ -44,7 +44,7 @@ public class AnimTool {
      * @param commonArg
      * @param needVideo true 生成完整视频 false 只合成帧图片
      */
-    public void create(final CommonArg commonArg, final boolean needVideo) {
+    public void create(final CommonArg commonArg, final boolean needVideo) throws Exception{
         createAllFrameImage(commonArg, new Runnable() {
             @Override
             public void run() {
@@ -61,39 +61,11 @@ public class AnimTool {
      * @param commonArg
      * @return
      */
-    private boolean checkCommonArg(CommonArg commonArg) {
-        if (commonArg.totalFrame <= 0) {
-            TLog.i(TAG, "error: totalFrame=" + commonArg.totalFrame);
-            return false;
-        }
-
-        if (commonArg.videoW <= 0 || commonArg.videoH <= 0) {
-            TLog.i(TAG, "error: video size " + commonArg.videoW + "x" + commonArg.videoH);
-            return false;
-        }
-
-        // 宽高必须是16的倍数,某些机行会进行对齐
-        /*if (commonArg.videoW % 16 != 0 || commonArg.videoH % 16 != 0) {
-            TLog.i(TAG, "error: video size " + commonArg.videoW + "x" + commonArg.videoH + " can not be divisible by 16");
-            return false;
-        }*/
-
-        File input = new File(commonArg.inputPath);
-        if (!input.exists()) {
-            TLog.i(TAG, "error: input path invalid " + commonArg.inputPath);
-            return false;
-        }
-
-        if (!File.separator.equals(commonArg.inputPath.substring(commonArg.inputPath.length() - 1))) {
-            commonArg.inputPath = commonArg.inputPath + File.separator;
-        }
-        if (!File.separator.equals(commonArg.outputPath.substring(commonArg.outputPath.length() - 1))) {
-            commonArg.outputPath = commonArg.outputPath + File.separator;
-        }
-        return true;
+    private boolean checkCommonArg(CommonArg commonArg) throws Exception {
+        return CommonArgTool.autoFillAndCheck(commonArg);
     }
 
-    private void createAllFrameImage(final CommonArg commonArg, final Runnable finishRunnable) {
+    private void createAllFrameImage(final CommonArg commonArg, final Runnable finishRunnable) throws Exception{
         if (!checkCommonArg(commonArg)) {
             return;
         }
@@ -102,7 +74,6 @@ public class AnimTool {
 
         // 检测output文件是否存在,不存在则生成
         checkDir(commonArg.outputPath);
-        commonArg.frameOutputPath = commonArg.outputPath + FRAME_IMAGE_DIR;
         checkDir(commonArg.frameOutputPath);
 
         totalP = 0;
@@ -154,7 +125,8 @@ public class AnimTool {
         int w = commonArg.videoW;
         int h = commonArg.videoH;
         File inputFile = new File(commonArg.inputPath + String.format("%03d", frameIndex)+".png");
-        GetAlphaFrame.AlphaFrameOut videoFrame = getAlphaFrame.createFrame(commonArg.orin,w, h, commonArg.gap, inputFile);
+        GetAlphaFrame.AlphaFrameOut videoFrame = getAlphaFrame.createFrame(commonArg.orin, w, h,
+                commonArg.gap, commonArg.wFill, commonArg.hFill, inputFile);
         if (videoFrame == null) {
             TLog.i(TAG, "frameIndex="+frameIndex +" is empty");
             return;
@@ -238,6 +210,8 @@ public class AnimTool {
         }
         rgbFrame = "["+cx+","+cy+","+commonArg.videoW+","+commonArg.videoH+"]";
 
+        realW += commonArg.wFill;
+        realH += commonArg.hFill;
         json = json.replace("$(videoW)", String.valueOf(realW));
         json = json.replace("$(videoH)", String.valueOf(realH));
         json = json.replace("$(aFrame)", aFrame);

+ 4 - 1
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/CommonArg.java

@@ -26,7 +26,6 @@ public class CommonArg {
 
     public boolean enableH265 = false; // 是否开启h265
 
-
     public int fps = 0;
 
     public String inputPath; // 输入帧文件地址
@@ -49,6 +48,10 @@ public class CommonArg {
 
     public int gap; // rgb 与 alpha 之间间隔距离
 
+    public int wFill; // 宽度填充
+
+    public int hFill; // 高度填充
+
     public int totalFrame;
 
 }

+ 108 - 0
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/CommonArgTool.java

@@ -0,0 +1,108 @@
+package com.tencent.qgame.playerproj.animtool;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+
+import javax.imageio.ImageIO;
+
+/**
+ * 构造参数
+ */
+class CommonArgTool {
+
+    private static final String TAG = "CommonArgTool";
+    private static final int MIN_GAP = 4; // 元素最小间隙 防止编码与光栅化导致边界模糊问题
+
+    /**
+     * 参数自动填充
+     * @param commonArg
+     */
+    static boolean autoFillAndCheck(CommonArg commonArg) throws Exception {
+
+        //  路径检查
+        File input = new File(commonArg.inputPath);
+        if (!input.exists()) {
+            TLog.i(TAG, "error: input path invalid " + commonArg.inputPath);
+            return false;
+        }
+
+        if (!File.separator.equals(commonArg.inputPath.substring(commonArg.inputPath.length() - 1))) {
+            commonArg.inputPath = commonArg.inputPath + File.separator;
+        }
+        if (!File.separator.equals(commonArg.outputPath.substring(commonArg.outputPath.length() - 1))) {
+            commonArg.outputPath = commonArg.outputPath + File.separator;
+        }
+
+
+        // 帧图片生成路径
+        commonArg.frameOutputPath = commonArg.outputPath + AnimTool.FRAME_IMAGE_DIR;
+
+        // 检查第一帧
+        File firstFrame = new File(commonArg.inputPath + "000.png");
+        if (!firstFrame.exists()) {
+            TLog.i(TAG, "first frame 000.png does not exist");
+            return false;
+        }
+        // 获取视频高度
+        BufferedImage inputBuf = ImageIO.read(firstFrame);
+        commonArg.videoW = inputBuf.getWidth();
+        commonArg.videoH = inputBuf.getHeight();
+        if (commonArg.videoW <= 0 || commonArg.videoH <= 0) {
+            TLog.i(TAG, "error: video size " + commonArg.videoW + "x" + commonArg.videoH);
+            return false;
+        }
+
+
+        // 计算视频最佳方向
+        commonArg.orin = commonArg.videoW >= commonArg.videoH ? CommonArg.ORIN_V : CommonArg.ORIN_H;
+
+        // 设置元素之间宽度
+        commonArg.gap = MIN_GAP;
+
+        // 计算出 16倍数的视频
+        int[] size = calSizeFill(commonArg.orin, commonArg.gap, commonArg.videoW, commonArg.videoH, 0, 0);
+        commonArg.wFill = size[0];
+        commonArg.hFill = size[1];
+
+
+        // 获取总帧数
+        commonArg.totalFrame = 0;
+        for (int i=0; i<=999; i++) {
+            File frameFile = new File(commonArg.inputPath + String.format("%03d", i) + ".png");
+            // 顺序检查
+            if (!frameFile.exists()) {
+                break;
+            }
+            commonArg.totalFrame++;
+        }
+
+
+        if (commonArg.totalFrame <= 0) {
+            TLog.i(TAG, "error: totalFrame=" + commonArg.totalFrame);
+            return false;
+        }
+
+
+
+        return true;
+    }
+
+    /**
+     * 寻找最小wFill & hFill情况下 整个视频宽高能被16整除
+     */
+    private static int[] calSizeFill(int orin, int gap, int w, int h, int wFill, int hFill) {
+        int outW = (orin == CommonArg.ORIN_H ? (w * 2 + gap) : w) + wFill;
+        int outH = (orin == CommonArg.ORIN_H ? h : (h * 2 + gap)) + hFill;
+
+        boolean wCheck = outW % 16 == 0;
+        boolean hCheck = outH % 16 == 0;
+        if (wCheck && hCheck) {
+            return new int[]{wFill, hFill};
+        }
+
+        // 递归计算
+        return calSizeFill(orin, gap, w, h, wCheck? wFill : wFill + 1, hCheck? hFill : hFill + 1);
+    }
+
+
+}

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

@@ -19,6 +19,7 @@ import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
+import java.util.Arrays;
 
 public class GetAlphaFrame {
 
@@ -60,26 +61,25 @@ public class GetAlphaFrame {
      * @return
      * @throws IOException
      */
-    public AlphaFrameOut createFrame(int orin, int w, int h, int gap, File inputFile) throws IOException {
+    public AlphaFrameOut createFrame(int orin, int w, int h, int gap, int wFill, int hFill, File inputFile) throws IOException {
 
         if (!inputFile.exists()) {
             return null;
         }
 
-        int outW = orin == ORIN_H ? (w * 2 + gap) : w;
-        int outH = orin == ORIN_H ? h : (h * 2 + gap);
+        int outW = (orin == ORIN_H ? (w * 2 + gap) : w) + wFill;
+        int outH = (orin == ORIN_H ? h : (h * 2 + gap)) + hFill;
 
         BufferedImage inputBuf = ImageIO.read(inputFile);
         int[] inputArgb = inputBuf.getRGB(0, 0, w, h, null, 0, w);
 
-
         int[] outputArgb = new int[outW * outH];
-
+        Arrays.fill(outputArgb, 0xff000000);
 
         for (int k=0; k<2; k++) {
             for (int x = 0; x < w; x++) {
                 for (int y = 0; y < h; y++) {
-                    int outPoint = orin == ORIN_H ? k * (w + gap) + x + y * outW : k * w * (h + gap) + x + y * w;
+                    int outPoint = orin == ORIN_H ? k * (w + gap) + x + y * outW : k * outW * (h + gap) + x + y * outW;
                     if (k == 0) {
                         int alpha = inputArgb[x + y * w] >>> 24;
                         // r = g = b

+ 13 - 9
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/Main.java

@@ -21,7 +21,11 @@ public class Main {
 
 
     public static void main(String[] args) throws Exception {
-        animTool();
+        try {
+            animTool();
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
     }
 
 
@@ -46,20 +50,19 @@ public class Main {
      *
      * ps: 项目是普通的java程序,需要在Run Configuration 里加入Application运行项目,并选择animtool项目,接下来按提示配置即可
      */
-    public static void animTool() {
+    public static void animTool() throws Exception {
         final CommonArg commonArg = new CommonArg();
         // ffmpeg 命令路径
         commonArg.ffmpegCmd = "ffmpeg";
         // bento4 mp4edit 命令路径
         commonArg.mp4editCmd = "mp4edit";
 
-        // 视频对齐方式 ORIN_H = 左右对齐, ORIN_V 上下对齐
-        commonArg.orin = CommonArg.ORIN_H;
-        // 素材宽高 px
-        commonArg.videoW = 672;
-        commonArg.videoH = 1504;
-        // 总帧数
-        commonArg.totalFrame = 240;
+        /*
+         * 是否开启h265(默认关闭)
+         * 优点:压缩率更高,视频更清晰
+         * 缺点:Android 4.x系统 & 部分低端机 无法播放265视频
+         */
+        commonArg.enableH265 = true;
         // fps
         commonArg.fps = 24;
         // 素材文件路径
@@ -67,6 +70,7 @@ public class Main {
         // 中间素材输出路径
         commonArg.outputPath = commonArg.inputPath + "/output";
 
+
         // 开始运行
         AnimTool animTool = new AnimTool();
         // needVideo true 直接生成video false 生成帧图片,由用户手动生成最终视频文件