1. 程式人生 > >java對視訊進行轉碼

java對視訊進行轉碼

這裡有兩個方案:

1.利用國外一個大佬寫的jar包jave,裡面集成了ffmpeg,目前原始碼應該是更新到1.0.2,看了下原始碼應該發現,這個功能還是非常強大的,如果不需要轉碼,只需要獲取下圖片,視訊資訊,更是方便= = 。

    JAVE(Java Audio Video Encoder),是一個包涵ffmpeg專案庫。開發這可以運用它去實現音訊(Audio)與視訊(Video)檔案的轉碼。例如你要把AVI格式檔案轉為MPEG檔案、WAV格式檔案轉為MP3格式檔案,同時你還能調整檔案大小與比例。JAVE相容和支援很多格式之間的轉碼……

轉碼的方法:

  1. public void encode(java.io.File source,  
  2.                    java.io.File target,  
  3.                    it.sauronsoftware.jave.EncodingAttributes attributes)  
  4.             throws java.lang.IllegalArgumentException,  
  5.                    it.sauronsoftware.jave.InputFormatException,  
  6.                    it.sauronsoftware.jave.EncoderException  


  1. File source = new File("source.avi");  
  2. File target = new File("target.mp4");  

  3. AudioAttributes audio = new AudioAttributes();  
  4. audio.setCodec("libmp3lame");  
  5. audio.setBitRate(new Integer(56000));  
  6. audio.setChannels(new Integer(1));  
  7. audio.setSamplingRate(new Integer(22050));  

  8. VideoAttributes video = new VideoAttributes();  
  9. video.setCodec("libx264");  

  10. EncodingAttributes attrs = new EncodingAttributes();  
  11. attrs.setFormat("mp4");  //h264編碼
  12. attrs.setAudioAttributes(audio);  
  13. attrs.setVideoAttributes(video);  
  14. Encoder encoder = new Encoder();  
  15. encoder.encode(source, target, attrs);  
借鑑的這篇部落格:https://blog.csdn.net/qllinhongyu/article/details/29817297  裡面介紹jave更詳細點

2.利用ffmpeg進行轉碼,有壞處:

  •  windows伺服器還比較簡單,直接下載ffmpeg可以直接進行轉碼了,但是linux伺服器的ffmpeg的安裝真的挺麻煩的。。我用了3個小時裝好。
  • 需要呼叫java執行外部程式Runtime類或者ProcessBuilder去構建Process,據說呼叫多了,非常損耗效能。
  • Runtime runtime = Runtime.getRuntime();
    Process p = runtime.exec(cmd);
    • 1
    • 2
    Process p=new ProcessBuilder(cmd).start();

這裡有一點需要注意,runtime執行執行命令,processBuilder需要具體的檔案

runtime的cmd: String copy="cp -rf "+source+" "+target;

processBuilder的cmd: 這裡讀的是配置檔案中的

video.ffmpeg.linux.path=/usr/local/ffmpegRedHat/bin/./ffmpeg
video.ffmpeg.windows.path=D:\\project\\solr\\changToH264\\src\\ffmpeg.exe

開頭不太一樣。。

我目前直接用的ffmpeg,這裡粘一下我的原始碼,可以做一下參考

@Override
public boolean startChangeToH264(String inputPath, String outPath) throws Exception{
    // ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
    if (!checkfile(inputPath)) {
        System.out.println(inputPath + " is not file");
        throw new Exception("檔案不存在");
    }
    if(checkContentType(inputPath)!=0){
        throw new Exception("檔案型別無法解析");
    }
    VideoFormatToH264 videoFormatToH264=new VideoFormatToH264(inputPath,outPath);
    videoFormatToH264.run();
    return true;
}


private static boolean checkfile(String path) {
    File file = new File(path);
    if (!file.isFile() || (!file.exists())) {
        return false;
    }
    return true;
}

private static int checkContentType(String inputPath) {
    String type = inputPath.substring(inputPath.lastIndexOf(".") + 1, inputPath.length())
            .toLowerCase();
    // ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
    if (type.equals("avi")) {
        return 0;
    } else if (type.equals("mpg")) {
        return 0;
    } else if (type.equals("wmv")) {
        return 0;
    } else if (type.equals("3gp")) {
        return 0;
    } else if (type.equals("mov")) {
        return 0;
    } else if (type.equals("mp4")) {
        return 0;
    } else if (type.equals("asf")) {
        return 0;
    } else if (type.equals("asx")) {
        return 0;
    } else if (type.equals("flv")) {
        return 0;
    }
    // 對ffmpeg無法解析的檔案格式(wmv9,rm,rmvb等),
    // 可以先用別的工具(mencoder)轉換為avi(ffmpeg能解析的)格式.
    else if (type.equals("wmv9")) {
        return 1;
    } else if (type.equals("rm")) {
        return 1;
    } else if (type.equals("rmvb")) {
        return 1;
    }
    return 9;
}
/**
 * Created by zhangluyao on 2018/6/12.
 */
public class VideoFormatToH264 {
    private String filePath;
    private String OutfilePath;
    private List<String> command;
    public VideoFormatToH264(String filePath,String OutfilePath){
        this.OutfilePath=OutfilePath;
        this.filePath=filePath;
    }
    public VideoFormatToH264(String filePath,String OutfilePath, List<String> command){
        this.OutfilePath=OutfilePath;
        this.filePath=filePath;
        this.command=command;
    }

    public void run(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor=(ThreadPoolTaskExecutor)SpringUtil.getBean("threadPoolTaskExecutor");
        ChangeVideoTask changeVideoTask=new ChangeVideoTask(this.getFilePath(),this.getOutfilePath());
        threadPoolTaskExecutor.execute(changeVideoTask);
    }
    public void runCommand()throws Exception{
        if(this.command!=null){
            ThreadPoolTaskExecutor threadPoolTaskExecutor=(ThreadPoolTaskExecutor)SpringUtil.getBean("threadPoolTaskExecutor");
            ChangeVideoTask changeVideoTask=new ChangeVideoTask(this.getFilePath(),this.getOutfilePath(),this.command);
            threadPoolTaskExecutor.execute(changeVideoTask);
        }else{
            System.out.print("command為空");
            throw new Exception("command為空");
        }
    }
    private class ChangeVideoTask implements Runnable{
        private String filePath;
        private String outFilePath;
        private List<String> command;
        ChangeVideoTask(String path,String outFilePath){
            this.outFilePath=outFilePath;
            this.filePath=path;
        }
        ChangeVideoTask(String path,String outFilePath,List<String> command){
            this.outFilePath=outFilePath;
            this.filePath=path;
            this.command=command;
        }
        @Override
        public  void run() {
            try {
                //命令是空時,執行視訊轉換成H264
                if(CollectionUtils.isEmpty(command)){
                    command=new ArrayList<String>();
                    command.add(Const.getFFMPEGPath());
                    command.add("-i");
                    command.add(filePath);
                    command.add("-y");
                    command.add("-vcodec");
                    command.add("h264");
                    command.add("-preset");
                    command.add("ultrafast");
                    command.add("-profile:v");
                    command.add("baseline");
                    command.add("-acodec");
                    command.add("aac");
                    command.add("-strict");
                    command.add("experimental");
                    command.add("-s");
                    command.add("640*480");
                    command.add("-b");
                    command.add("568k");
                    command.add("-ab");
                    command.add("128k");
                    if(System.getProperty("os.name").toLowerCase().indexOf("windows")>-1){
                        command.add(outFilePath.substring(1));
                    }else{
                        command.add(outFilePath);
                    }
                }

                System.out.println("開始轉換");
                Process videoProcess = new ProcessBuilder(command).redirectErrorStream(true).start();

                new PrintStream(videoProcess.getErrorStream()).start();

                new PrintStream(videoProcess.getInputStream()).start();

                videoProcess.waitFor();//等待程序結束
                CacheService cacheService=(CacheService) SpringUtil.getBean("cacheService");
                String sourceName=filePath.substring(filePath.lastIndexOf("/")+1);
                //轉換成功,去掉redis中的key
                cacheService.remove(sourceName);
                System.out.println("轉換成功");
                FileUtils.delFile(filePath);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }



    private class PrintStream extends Thread
    {
        java.io.InputStream __is = null;
        public PrintStream(java.io.InputStream is)
        {
            __is = is;
        }

        public void run()
        {
            try
            {
                while(this != null)
                {
                    int _ch = __is.read();
                    if(_ch != -1)
                        System.out.print((char)_ch);
                    else break;
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }
    public String getFilePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public String getOutfilePath() {
        return OutfilePath;
    }

    public void setOutfilePath(String outfilePath) {
        OutfilePath = outfilePath;
    }

    public List<String> getCommand() {
        return command;
    }

    public void setCommand(List<String> command) {
        this.command = command;
    }

加點東西。 

ffmpeg轉換成mp4檔案以後,視訊的元資料在末尾,jwplayer播放的時候需要全部緩衝結束才能開始播放,使用者體驗及其的不好~~   更改後的程式碼先不貼上來了,就說下方法。

ffmpeg資料夾中,編譯前的資料夾,tools下面有一個qt-faststart.c



執行下make qt-faststart 會生成一個qt-faststart 命令

然後程式碼中對檔案 再執行一下 qt-faststart inputPath outPath 命令 就可以了

會生成一個新的檔案,這個檔案的元資料在開頭,可以直接播放的~~~