如何使用Java + x264从图像制作视频;需要跨平台解决方案

时间:2014-08-14 06:59:57

标签: java image x264

我制作了一个软件,将我整天录制成一段视频。 示例视频:https://www.youtube.com/watch?v=ITZYMMcubdw(注意:> 16小时压缩2分钟,视频速度太高,可能会导致癫痫:P)

我现在使用的方法是Avisynth + x264 + Java。 这非常非常有效。整天的视频创建时间为3-4分钟,缩小为40-50MB。这是完美的,唯一的问题是这个解决方案不是跨平台的。 有没有人有更好的主意?

我尝试使用基于java的x246库但是

  1. 他们很慢,因为地狱
  2. 视频输出尺寸太大
  3. 视频质量不理想。
  4. 某些网站建议使用如下命令:

    x264.exe --crf 18 --fps 24 --input-res 1920x1080 --input-csp rgb -o "T:\crf18.mkv" "T:\___BBB\big_buck_bunny_%05d.png"
    

    这种方法存在两个问题。

    1. 据我所知,x264接受图像序列作为输入,ffmpeg接受
    2. 输入图像没有按顺序命名,如image01.png,image02.png等。它们被命名为timestamp_as_longinteger.png。因此,为了允许x264接受这些图像作为输入,我必须重命名所有这些(我为新文件夹中的所有图像创建一个符号链接)。这种方法再次不能令人满意,因为我需要更灵活地选择/取消选择将转换为视频的文件。现在我的方法是黑客攻击。
    3. 最好的解决方案是x264。但不知道如何从Java发送图像序列。这也是没有以顺序方式命名的图像。


      BTW制作视频的目的是追溯到时间,并找出时间花费/浪费的时间。 该软件知道用户正在做什么。所以使用这个我可以(在视觉上)找出一个班级如何随着时间的推移而演变。我花在特定课程/包/模块/项目/客户上的时间。现在的粒度达到了班级水平,我希望把它带到功能级别。该软件名为jitendriya。

      Here is a sample graph http://neembuu.com/now/tempimages/firefox.png


      这是一个解决方案 How does one encode a series of images into H264 using the x264 C API?

      但这是针对C.如果我必须在java中做同样的事情,并且采用跨平台的方式,我将不得不求助于JNA / JNI。 JNA可能会有重大的性能影响。 JNI会更加努力。 FFMpeg看起来也是一个不错的选择,但我仍然不满意任何这些解决方案的优缺点。


      解决方案已适应。

      package weeklyvideomaker;
      
      import java.awt.AWTException;
      import java.awt.Rectangle;
      import java.awt.Robot;
      import java.awt.Toolkit;
      import java.awt.image.BufferedImage;
      import java.io.File;
      import java.io.IOException;
      import java.io.OutputStream;
      import java.util.Calendar;
      import java.util.LinkedList;
      import java.util.logging.Level;
      import java.util.logging.Logger;
      import neembuu.release1.util.StreamGobbler;
      import org.shashaank.activitymonitor.ScreenCaptureHandler;
      import org.shashaank.jitendriya.JitendriyaParams;
      
      /**
       *
       * @author Shashank
       */
      public class DirectVideoScreenHandler implements ScreenCaptureHandler {
          private final JitendriyaParams  jp;
      
          private String extension="264";
          private boolean lossless=false;
          private String fps="24/1";
      
          private Process p = null;
          private Rectangle r1;
          private Robot r;
      
          private int currentDay;
      
          private static final String[]weeks={"sun","mon","tue","wed","thu","fri","sat"};
      
          public DirectVideoScreenHandler(JitendriyaParams jp) {
              this.jp = jp;
          }
      
          public String getExtension() {
              return extension;
          }
      
          public void setExtension(String extension) {
              this.extension = extension;
          }
      
          public boolean isLossless() {
              return lossless;
          }
      
          public void setLossless(boolean lossless) {
              this.lossless = lossless;
          }
      
          public String getFps() {
              return fps;
          }
      
          public void setFps(String fps) {
              this.fps = fps;
          }
      
          private static int getday(){
              return Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1;
          }
      
          public void make()throws IOException,AWTException{
              currentDay = getday();
              File week = jp.getWeekFolder();
      
              String destinationFile = week+"\\videos\\"+weeks[currentDay]+"_"+System.currentTimeMillis()+"_direct."+extension;
      
              r = new Robot();
              r1 = getScreenSize();
      
              ProcessBuilder pb = makeProcess(destinationFile, 0, r1.width, r1.height);
      
              p = pb.start();
              StreamGobbler out = new StreamGobbler(p.getInputStream(), "out");
              StreamGobbler err = new StreamGobbler(p.getErrorStream(), "err");
              out.start();err.start();
          }
      
          private static Rectangle getScreenSize(){
              return new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
          }
      
          private void screenShot(OutputStream os)throws IOException{        
              BufferedImage bi = r.createScreenCapture(r1);
              int[]intRawData = ((java.awt.image.DataBufferInt)
                      bi.getRaster().getDataBuffer()).getData();
              byte[]rawData = new byte[intRawData.length*3];
              for (int i = 0; i < intRawData.length; i++) {
                  int rgb = intRawData[i];
                  rawData[ i*3 + 0 ] = (byte) (rgb >> 16);
                  rawData[ i*3 + 1 ] = (byte) (rgb >> 8);
                  rawData[ i*3 + 2 ] = (byte) (rgb);
              }
              os.write(rawData);
          }
      
          private ProcessBuilder makeProcess(String destinationFile, int numberOfFrames,
                  int width, int height){
              LinkedList<String> commands = new LinkedList<>();
              commands.add("\""+encoderPath()+"\"");
              if(true){
                  commands.add("-");
                  if(lossless){
                      commands.add("--qp");
                      commands.add("0");
                  }
                  commands.add("--keyint");
                  commands.add("240");
                  commands.add("--sar");
                  commands.add("1:1");
                  commands.add("--output");
                  commands.add("\""+destinationFile+"\"");
                  if(numberOfFrames>0){
                      commands.add("--frames");
                      commands.add(String.valueOf(numberOfFrames));
                  }else{
                      commands.add("--stitchable");
                  }
                  commands.add("--fps");
                  commands.add(fps);
                  commands.add("--input-res");
                  commands.add(width+"x"+height);
                  commands.add("--input-csp");
                  commands.add("rgb");//i420
              }
              return new ProcessBuilder(commands);
          }
      
          private String encoderPath(){
              return jp.getToolsPath()+File.separatorChar+"x264_64.exe";
          }
      
          @Override public void run() {
              try {
                  if(p==null){
                      make();
                  }
                  if(currentDay!=getday()){// day changed
                      destroy(); 
                      return;
                  }
                  if(!r1.equals(getScreenSize())){// screensize changed
                      destroy();
                      return;
                  }
                  screenShot(p.getOutputStream());
              } catch (Exception ex) {
                  Logger.getLogger(DirectVideoScreenHandler.class.getName()).log(Level.SEVERE, null, ex);
              }
          }
      
          private void destroy()throws Exception{
              p.getOutputStream().flush();
              p.getOutputStream().close();
              p.destroy();
              p = null;
          }
      
      }
      

      package weeklyvideomaker;
      
      import org.shashaank.jitendriya.JitendriyaParams;
      
      /**
       *
       * @author Shashank
       */
      public class DirectVideoScreenHandlerTest {
          public static void main(String[] args)throws Exception {
              JitendriyaParams  jp = new JitendriyaParams.Builder()
                      .setToolsPath("F:\\GeneralProjects\\JReminder\\development_environment\\tools")
                      .setOsDependentDataFolderPath("J:\\jt_data")
                      .build();
              DirectVideoScreenHandler w = new DirectVideoScreenHandler(jp);
              w.setExtension("264");
              w.setFps("24/1");
              w.setLossless(false);
              w.make();
      
              for (int i = 0; ; i++) {
                  w.run();
                  Thread.sleep(1000);
              }
          }
      }
      

0 个答案:

没有答案