Browse Source

feat: 视频alpha 区域支持缩放

hexleo 5 years ago
parent
commit
51617c5130

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

@@ -141,18 +141,15 @@ public class AnimTool {
     }
 
     private void createFrame(CommonArg commonArg, int frameIndex) throws Exception {
-        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, commonArg.wFill, commonArg.hFill, inputFile);
+        GetAlphaFrame.AlphaFrameOut videoFrame = getAlphaFrame.createFrame(commonArg, inputFile);
         if (videoFrame == null) {
             TLog.i(TAG, "frameIndex="+frameIndex +" is empty");
             return;
         }
         // 最后保存图片
-        BufferedImage outBuf = new BufferedImage(videoFrame.outW, videoFrame.outH, BufferedImage.TYPE_INT_ARGB);
-        outBuf.setRGB(0,0, videoFrame.outW, videoFrame.outH, videoFrame.argb, 0, videoFrame.outW);
+        BufferedImage outBuf = new BufferedImage(commonArg.outputW, commonArg.outputH, BufferedImage.TYPE_INT_ARGB);
+        outBuf.setRGB(0,0, commonArg.outputW, commonArg.outputH, videoFrame.argb, 0, commonArg.outputW);
 
         File outputFile = new File(commonArg.frameOutputPath + String.format("%03d", frameIndex) +".png");
         ImageIO.write(outBuf, "PNG", outputFile);
@@ -208,33 +205,13 @@ public class AnimTool {
         String json = "{\"info\":{\"v\":$(v),\"f\":$(f),\"w\":$(w),\"h\":$(h),\"videoW\":$(videoW),\"videoH\":$(videoH),\"orien\":0,\"fps\":$(fps),\"isVapx\":0,\"aFrame\":$(aFrame),\"rgbFrame\":$(rgbFrame)}}";
         json = json.replace("$(v)", String.valueOf(commonArg.version));
         json = json.replace("$(f)", String.valueOf(commonArg.totalFrame));
-        json = json.replace("$(w)", String.valueOf(commonArg.videoW));
-        json = json.replace("$(h)", String.valueOf(commonArg.videoH));
+        json = json.replace("$(w)", String.valueOf(commonArg.rgbPoint.w));
+        json = json.replace("$(h)", String.valueOf(commonArg.rgbPoint.h));
         json = json.replace("$(fps)", String.valueOf(commonArg.fps));
-        int realW = 0;
-        int realH = 0;
-        int cx, cy;
-        String aFrame = "[0,0,"+commonArg.videoW+","+commonArg.videoH+"]";
-        String rgbFrame = "[0,0,0,0]";
-        if (commonArg.orin == CommonArg.ORIN_H) { // 水平对齐
-            realW = 2 * commonArg.videoW + commonArg.gap;
-            realH = commonArg.videoH;
-            cx = commonArg.videoW + commonArg.gap;
-            cy = 0;
-        } else { // 上下对齐
-            realW = commonArg.videoW;
-            realH = 2 * commonArg.videoH + commonArg.gap;
-            cx = 0;
-            cy = commonArg.videoH + commonArg.gap;
-        }
-        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);
-        json = json.replace("$(rgbFrame)", rgbFrame);
+        json = json.replace("$(videoW)", String.valueOf(commonArg.outputW));
+        json = json.replace("$(videoH)", String.valueOf(commonArg.outputH));
+        json = json.replace("$(aFrame)", commonArg.alphaPoint.toString());
+        json = json.replace("$(rgbFrame)", commonArg.rgbPoint.toString());
         try {
             BufferedWriter writer = new BufferedWriter(new FileWriter(commonArg.outputPath + VAPC_JSON_FILE));
             writer.write(json);
@@ -276,9 +253,10 @@ public class AnimTool {
                     "-pix_fmt", "yuv420p",
                     "-vcodec", "libx264",
                     "-b:v", "3000k",
-                    "-profile:v", "baseline",
-                    "-level", "3.0",
+                    "-profile:v", "main",
+                    "-level", "4.0",
                     "-bf", "0",
+                    "-bufsize", "3000k",
                     "-y", videoPath + TEM_VIDEO_FILE};
         }
 

+ 14 - 12
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/CommonArg.java

@@ -15,10 +15,9 @@
  */
 package com.tencent.qgame.playerproj.animtool;
 
-public class CommonArg {
+import com.tencent.qgame.playerproj.animtool.data.PointRect;
 
-    public static final int ORIN_H = 1; // 左右对齐
-    public static final int ORIN_V = 2; // 上下对齐
+public class CommonArg {
 
     public String ffmpegCmd = "ffmpeg"; // ffmpeg 命令地址
 
@@ -30,10 +29,10 @@ public class CommonArg {
 
     public String inputPath; // 输入帧文件地址
 
-
+    public float scale = 1f; // alpha 区域缩放大小
 
     /**
-     * 无需手动配置
+     * 自动填充参数配置
      */
     public String outputPath; // 输出地址
 
@@ -41,19 +40,21 @@ public class CommonArg {
 
     public int version = 2;
 
-    public int orin = ORIN_H;
+    public int gap; // rgb 与 alpha 之间间隔距离
+
+    // public int wFill; // 宽度填充
 
-    public int videoW;
+    // public int hFill; // 高度填充
 
-    public int videoH;
+    public int totalFrame;
 
-    public int gap; // rgb 与 alpha 之间间隔距离
+    public PointRect rgbPoint = new PointRect(); // rgb 区域 原始图像区域
 
-    public int wFill; // 宽度填充
+    public PointRect alphaPoint = new PointRect();  // alpha 区域
 
-    public int hFill; // 高度填充
+    public int outputW = 0; // 输出最终视频的宽高
 
-    public int totalFrame;
+    public int outputH = 0;
 
     @Override
     public String toString() {
@@ -62,6 +63,7 @@ public class CommonArg {
                 ", mp4editCmd='" + mp4editCmd + '\'' +
                 ", enableH265=" + enableH265 +
                 ", fps=" + fps +
+                ", scale=" + scale +
                 ", inputPath='" + inputPath + '\'' +
                 '}';
     }

+ 49 - 19
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/CommonArgTool.java

@@ -43,6 +43,16 @@ class CommonArgTool {
         // 帧图片生成路径
         commonArg.frameOutputPath = commonArg.outputPath + AnimTool.FRAME_IMAGE_DIR;
 
+
+        // 限定scale的值
+        if (commonArg.scale < 0.5f) {
+            commonArg.scale =0.5f;
+        }
+
+        if (commonArg.scale > 1f) {
+            commonArg.scale = 1f;
+        }
+
         // 检查第一帧
         File firstFrame = new File(commonArg.inputPath + "000.png");
         if (!firstFrame.exists()) {
@@ -51,24 +61,48 @@ class CommonArgTool {
         }
         // 获取视频高度
         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);
+        commonArg.rgbPoint.w = inputBuf.getWidth();
+        commonArg.rgbPoint.h = inputBuf.getHeight();
+        if (commonArg.rgbPoint.w <= 0 || commonArg.rgbPoint.h <= 0) {
+            TLog.i(TAG, "error: video size " + commonArg.rgbPoint.w + "x" + commonArg.rgbPoint.h);
             return false;
         }
 
-
-        // 计算视频最佳方向
-        commonArg.orin = commonArg.videoW >= commonArg.videoH ? CommonArg.ORIN_V : CommonArg.ORIN_H;
-
         // 设置元素之间宽度
         commonArg.gap = MIN_GAP;
 
+        // 计算alpha区域大小
+        commonArg.alphaPoint.w = (int) (commonArg.rgbPoint.w * commonArg.scale);
+        commonArg.alphaPoint.h = (int) (commonArg.rgbPoint.h * commonArg.scale);
+
+        // 计算视频最佳方向 (最长边最小原则)
+        int hW = commonArg.rgbPoint.w + commonArg.gap + commonArg.alphaPoint.w;
+        int hH = commonArg.rgbPoint.h;
+        int hMaxLen = Math.max(hW, hH);
+
+        int vW = commonArg.rgbPoint.w;
+        int vH = commonArg.rgbPoint.h + commonArg.gap + commonArg.alphaPoint.h;
+        int vMaxLen = Math.max(vW, vH);
+
+        if (hMaxLen > vMaxLen) { // 竖直布局
+            commonArg.alphaPoint.x = 0;
+            commonArg.alphaPoint.y = commonArg.rgbPoint.h + commonArg.gap;
+
+            commonArg.outputW = commonArg.rgbPoint.w;
+            commonArg.outputH = commonArg.rgbPoint.h + commonArg.gap + commonArg.alphaPoint.h;
+        } else { // 水平布局
+            commonArg.alphaPoint.x = commonArg.rgbPoint.w + commonArg.gap;
+            commonArg.alphaPoint.y = 0;
+
+            commonArg.outputW = commonArg.rgbPoint.w + commonArg.gap + commonArg.alphaPoint.w;
+            commonArg.outputH = commonArg.rgbPoint.h;
+        }
+
         // 计算出 16倍数的视频
-        int[] size = calSizeFill(commonArg.orin, commonArg.gap, commonArg.videoW, commonArg.videoH, 0, 0);
-        commonArg.wFill = size[0];
-        commonArg.hFill = size[1];
+        int[] size = calSizeFill( commonArg.outputW, commonArg.outputH, 0, 0);
+        // 得到最终视频宽高
+        commonArg.outputW += size[0];
+        commonArg.outputH += size[1];
 
 
         // 获取总帧数
@@ -88,26 +122,22 @@ class CommonArgTool {
             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;
+    private static int[] calSizeFill(int outW, int outH, int wFill, int hFill) {
+        boolean wCheck = (outW + wFill)% 16 == 0;
+        boolean hCheck = (outH + hFill) % 16 == 0;
 
-        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);
+        return calSizeFill(outW, outH, wCheck? wFill : wFill + 1, hCheck? hFill : hFill + 1);
     }
 
 

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

@@ -15,7 +15,12 @@
  */
 package com.tencent.qgame.playerproj.animtool;
 
+import com.tencent.qgame.playerproj.animtool.data.PointRect;
+
 import javax.imageio.ImageIO;
+
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
@@ -23,52 +28,26 @@ import java.util.Arrays;
 
 public class GetAlphaFrame {
 
-    public static final int ORIN_H = 1; // 左右对齐
-    public static final int ORIN_V = 2; // 上下对齐
-
-
     public static class AlphaFrameOut {
 
-
-        public int orin;
         public int[] argb;
-        public int w;
-        public int h;
-        public int outW;
-        public int outH;
-        public int gap;
 
-
-        public AlphaFrameOut(int orin, int[] argb, int w, int h, int outW, int outH, int gap) {
-            this.orin = orin;
+        public AlphaFrameOut(int[] argb) {
             this.argb = argb;
-            this.w = w;
-            this.h = h;
-            this.outW = outW;
-            this.outH = outH;
-            this.gap = gap;
         }
 
     }
 
-    /**
-     *
-     * @param orin
-     * @param w 原图像宽
-     * @param h 原图像高
-     * @param gap rgb 与 alpha 之间间隔距离
-     * @param inputFile
-     * @return
-     * @throws IOException
-     */
-    public AlphaFrameOut createFrame(int orin, int w, int h, int gap, int wFill, int hFill, File inputFile) throws IOException {
+    public AlphaFrameOut createFrame(CommonArg commonArg, File inputFile) throws IOException {
 
         if (!inputFile.exists()) {
             return null;
         }
 
-        int outW = (orin == ORIN_H ? (w * 2 + gap) : w) + wFill;
-        int outH = (orin == ORIN_H ? h : (h * 2 + gap)) + hFill;
+        int w = commonArg.rgbPoint.w;
+        int h = commonArg.rgbPoint.h;
+        int outW = commonArg.outputW;
+        int outH = commonArg.outputH;
 
         BufferedImage inputBuf = ImageIO.read(inputFile);
         int[] inputArgb = inputBuf.getRGB(0, 0, w, h, null, 0, w);
@@ -76,23 +55,57 @@ public class GetAlphaFrame {
         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 * outW * (h + gap) + x + y * outW;
-                    if (k == 0) {
-                        int alpha = inputArgb[x + y * w] >>> 24;
-                        // r = g = b
-                        outputArgb[outPoint] = 0xff000000 + (alpha << 16) + (alpha << 8) + alpha;
-                    } else {
-                        outputArgb[outPoint] = blendBg(inputArgb[x + y * w], 0xff000000);
-                    }
+        BufferedImage alphaBuf = inputBuf;
+        int[] alphaArgb = inputArgb;
+
+        if (commonArg.scale < 1f) {
+            AffineTransform at = new AffineTransform();
+            at.scale(commonArg.scale, commonArg.scale);
+
+            alphaBuf = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
+            AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
+            alphaBuf = scaleOp.filter(inputBuf, alphaBuf);
+
+            alphaArgb = alphaBuf.getRGB(0, 0, w, h, null, 0, w);
+        }
+
+        // rgb 区域
+        fillColor(outputArgb, outW, commonArg.rgbPoint, false, inputArgb, w);
+
+        // alpha 区域
+        fillColor(outputArgb, outW, commonArg.alphaPoint, true, alphaArgb, w);
+
+
+        return new AlphaFrameOut(outputArgb);
+
+    }
+
+
+    private void fillColor(int[] outputArgb, int outputW, PointRect point, boolean isAlpha, int[] inputArgb, int inputW) {
+        int outX = 0;
+        int outY = 0;
+        for (int y = 0; y < point.h ; y++) {
+            outY = point.y + y;
+            for (int x = 0; x < point.w ; x++) {
+                outX = point.x + x;
+                int tmpP = x + y * inputW;
+                if (tmpP >= inputArgb.length) {
+                    TLog.i("hexleo_test", "x=" + x + ",y=" + y + ",inputW=" + inputW);
                 }
+                int color = inputArgb[x + y * inputW];
+                outputArgb[outX + outY * outputW] = isAlpha ? getAlpha(color) : getColor(color);
             }
         }
+    }
 
-        return new AlphaFrameOut(orin, outputArgb, w, h, outW, outH, gap);
+    private int getColor(int color) {
+        return blendBg(color, 0xff000000);
+    }
 
+    private int getAlpha(int color) {
+        int alpha = color >>> 24;
+        // r = g = b
+        return 0xff000000 + (alpha << 16) + (alpha << 8) + alpha;
     }
 
     private int blendBg(int color, int colorBg) {

+ 7 - 4
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/Main.java

@@ -23,9 +23,9 @@ public class Main {
 
     public static void main(String[] args) throws Exception {
         // 启动UI界面
-        new ToolUI().run();
+        // new ToolUI().run();
         // java工具
-        // animTool();
+        animTool();
     }
 
 
@@ -62,11 +62,14 @@ public class Main {
          * 优点:压缩率更高,视频更清晰
          * 缺点:Android 4.x系统 & 极少部分低端机 无法播放265视频
          */
-        commonArg.enableH265 = true;
+        commonArg.enableH265 = false;
         // fps
         commonArg.fps = 24;
         // 素材文件路径
-        commonArg.inputPath = "/path/to/your/demo";
+        // commonArg.inputPath = "/path/to/your/demo";
+        commonArg.inputPath = "/Users/hexleo/temp/moon/DemoH/video";
+        // alpha 区域缩放大小  (0.5 - 1)
+        commonArg.scale = 0.5f;
 
         // 开始运行
         AnimTool animTool = new AnimTool();

+ 24 - 0
Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/data/PointRect.java

@@ -0,0 +1,24 @@
+package com.tencent.qgame.playerproj.animtool.data;
+
+public class PointRect {
+
+    public int x = 0;
+    public int y = 0;
+    public int w = 0;
+    public int h = 0;
+
+    public PointRect() {
+    }
+
+    public PointRect(int x, int y, int w, int h) {
+        this.x = x;
+        this.y = y;
+        this.w = w;
+        this.h = h;
+    }
+
+    @Override
+    public String toString() {
+        return "["+ x +","+ y +","+ w +","+ h +"]";
+    }
+}