2012年8月4日星期六

[20120805]關於mediainfo.dll,JNative.jar和一圖流視頻

最近由於某個魔炮廚(注:不是zbwmqlw)拜託我做一組一圖流視頻,然後我看到一共57首mp3然後我就傻了,於是就想做個批量的工具批量處理掉.
[地球人]都知道,ffmpeg可以用來生成一圖流視頻,但是,一個很禿的一點是,ffmpeg生成視頻需要手動輸入視頻時間.然後如果單純的用bat執行的話沒法獲得音頻的時間,所以我就傻了.
無奈於是只好考慮寫一個程序解決掉.[地球人]都知道.java裏面可以用Rumtime.getRuntime.exec("cmd /c "+command)來執行cmd命令,所以問題的關鍵就是,如何獲取要處理的音頻的長度.
一開始,我準備用javax.sound.sample.AudioFileFormat來獲取音頻的時間長度,結果後來很快發現,AudioFileFormat竟然連mp3格式都不支持,於是我就傻了
要 處理mp3格式還需要額外安置解碼器,出於節省cpu消耗的考慮我最後果斷放棄了AudioFileFormat,轉而考慮mediainfo.一開始我 考慮的是運行mediainfo.exe,獲取其stderr,并進行字符串處理獲取時間長度.不過很禿的是我懶得寫字符串處理,於是我最後決定使用 mediainfo.dll,藉助mediainfo直接獲取音頻長度.
[地球人]都知道,java要使用dll需要JNI,或者 JNative.爲了方便,於是我選用的JNative.mediainfo在其dll的下載包中附帶了一個 MediaInfoDLL.JNative.java,作為java調用mediainfo的API.有了這個,程序就好寫多了.獲取音頻長度之後運行 ffmpeg,程序的主體就完成了.
最後再加點細節,程序最後就完工了

package JMake;
import java.io.*;
import java.util.*;
import java.util.regex.*;
import javax.sound.sampled.*;
import org.xvolks.jnative.*;
import org.xvolks.jnative.exceptions.*;
import org.xvolks.jnative.pointers.*;
import JMake.*;
public class JMake{
  static MediaInfo mediainfo;
  static int find(String args[],String s){
    if(args==null)
      return -1;
    if(s==null)
      return -1;
    for(int i=0;i<args.length;i++)
      if(s.compareTo(args[i])==0)
        return i;
    return -1;
  }
  static ArrayList getPatternFiles(File file,Pattern p,boolean subDir){
    if(file==null)
      return null;
    if(file.isFile()){
      Matcher fMatcher=p.matcher(file.getName());
      if(fMatcher.matches()){
        ArrayList list=new ArrayList();
        list.add(file);
        return list;
      }
    }
    if(file.isDirectory()){
      File[] files=file.listFiles();
      if((files!=null)&&(files.length>0)){
        ArrayList list=new ArrayList();
        for(int i=0;i<files.length;i++){
          if(files[i].isDirectory()&&(!subDir))
            continue;
          ArrayList tmp=getPatternFiles(files[i],p,subDir);
          if(tmp!=null)
            list.addAll(tmp);
        }
        return list;
      }
    }
    return null;
  }
  static File[] getFiles(String dir,String s,boolean subDir){
    File file=new File(dir);
    s=s.replace('.','#');
    s=s.replaceAll("#", "\\\\.");
    s=s.replace('*','#');
    s=s.replaceAll("#",".*");
    s=s.replace('?','#');
    s=s.replaceAll("#",".?");
    s="^"+s+"$";
    Pattern p=Pattern.compile(s);
    ArrayList files=getPatternFiles(file,p,subDir);
    File[] ret=new File[files.size()];
    files.toArray(ret);
    return ret;
  }
  static void runCommand(Runtime run,String s)throws Exception{
    Process process=run.exec("cmd /c "+s);
    Scanner in=new Scanner(process.getErrorStream());
    for(;in.hasNext();System.out.println(in.nextLine()));
    in.close();
    process.waitFor();
    return;
  }
  static void generateFLV(String pic,String audio)throws Exception{
    long len=0;
    mediainfo.Open(audio);
    mediainfo.Option("Complete","0");
    String len1=mediainfo.Get(MediaInfo.Stream_General,0,"Duration",MediaInfo.Info_Text,MediaInfo.Info_Name);
    len=(long)(Math.floor((Long.parseLong(len1)/1000)))+1;
    StringBuffer command1=new StringBuffer("ffmpeg ");
    command1.append("-loop_input -r 1 -t "+Long.toString(len)+" ");
    command1.append("-i \""+pic+"\" ");
    command1.append("-vcodec libx264 ");
    command1.append("-crf 24 -coder 1 -flags +loop -cmp +chroma ");
    command1.append("-partitions +parti8x8+parti4x4+partp8x8+partb8x8 -me_method umh -subq 7 -me_range 16 ");
    command1.append("-g 250 -keyint_min 1 -sc_threshold 40 -b_strategy 2 -bf 0 -refs 6 ");
    command1.append("-qcomp 0.6 -qdiff 4 ");
    command1.append("-directpred 3 -trellis 2 -flags2 +wpred+mixed_refs+dct8x8+fastpskip ");
    command1.append("-y -f mp4 \""+audio+".mp4\"");
    StringBuffer command2=new StringBuffer("ffmpeg ");
    command2.append("-vcodec copy -i \""+audio+".mp4\" ");
    command2.append("-acodec copy -i \""+audio+"\" ");
    command2.append("-y -f flv \""+audio+".flv\"");
    System.out.println(command1);
    System.out.println(command2);
    Runtime run=Runtime.getRuntime();
    runCommand(run,command1.toString());
    runCommand(run,command2.toString());
    return;
  }
  public static void main(String args[])throws Exception{
    int picPattern=find(args,"--pic")+1;
    if(picPattern==0)
      return;
    int audioPattern=find(args,"--audio")+1;
    if(audioPattern==0)
      return;
    boolean subPicDir=(find(args,"--sub-pic-dir")+1!=0);
    boolean subAudioDir=(find(args,"--sub-audio-dir")+1!=0);
    File tmpPic=new File(args[picPattern]);
    File[] pics=getFiles(tmpPic.getParent(),tmpPic.getName(),subPicDir);
    File tmpAudio=new File(args[audioPattern]);
    File[] audios=getFiles(tmpAudio.getParent(),tmpAudio.getName(),subAudioDir);
    String dllPath="MediaInfo.dll";
    mediainfo=new MediaInfo(dllPath);
    for(int i=0;i<Math.min(pics.length,audios.length);i++)
      generateFLV(pics[i].getPath(),audios[i].getPath());
    if(pics.length<audios.length)
      for(int i=pics.length;i<audios.length;i++)
        generateFLV(pics[pics.length-1].getPath(),audios[i].getPath());
    if(pics.length>audios.length)
      for(int i=audios.length;i<pics.length;i++)
        generateFLV(pics[i].getPath(),audios[audios.length-1].getPath());
    return;
  }
}