Package ffmpeg

Source Code of ffmpeg.FFMpeg

/*
*  Multiconvert
*  Multiconvert is a lightweight and plattform independent Video conversion tool
*  based on ffmpeg and written in Java.
*
*  Copyright (C) 2010 Sebastian Weidenbach
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*  ----------------------------------------------------------------------------------
*  Historie:
*  2010���02���17 Erste Fassung              <sebastianwe@users.sourceforge.net>
*/

package ffmpeg;

import gui.FFMpegGui;

import java.awt.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.util.Iterator;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JOptionPane;

import language.Language;
import util.Constants;
import util.ConvertUtils;
import util.Downloader;

/**
* Objects of FFMpeg represant an interface the ffmpeg program
* @author SebastianWe
*
*/
public class FFMpeg implements Runnable
{
  /*
   * FFMpeg-Objects have an inputMedium and outputMedium that include the conversion files
   * It has a CodecVector of supported codecs
   * The path to ffmpeg is saved in <path>
   * An instance of a FFMpegProgressReceiver is saved as recv and receives conversion state in percent
   * Also FFMpeg-Objects need a Language
   */
  private InputMedium inputMedium;
  private OutputMedium outputMedium;
  private CodecVector supportedCodecs;
  private String path;
  private FFMpegProgressReceiver recv;
  public static int AUDIO = 1;
  public static int VIDEO = 2;
  private Language lang;
 
  /**
   * Constructs a new Object of FFMpeg
   * @param path
   *         The path to ffmpeg
   * @param lang
   *         Language
   * @param recv
   *         Receiver of conversion state
   * @throws IOException
   *         when ffmpeg binary was not found
   */
  public FFMpeg(String path, Language lang, FFMpegProgressReceiver recv) throws IOException
 
    this.path = path;
    this.recv = recv;
    this.lang = lang;
    supportedCodecs = new CodecVector(lang);
   
    scan();
  }
 
  /**
   * Returns a CodecVector of supported Codecs
   * @return CodecVector
   */
  public CodecVector getSupportedCodecs()
  {
    return supportedCodecs;
  }
 
  /**
   * Return a String array that represents a Codec List
   * @param type
   *       specify the kind of codec
   *       1 = audio
   *       2 = video
   * @return
   *       String array of codecs from <type>
   */
  public String[] getSupportedCodecsList(int type)
  {
    Vector<Codec> tmp = new Vector<Codec>();
   
    Iterator<Codec> i = supportedCodecs.iterator();
   
    while(i.hasNext())
    {
      Codec t = i.next();
      if(type == AUDIO)
      {
        if(t.isAudioCodec() && t.isEncodeable())
          tmp.add(t);
      }
      else if(type == VIDEO)
      {
        if(t.isVideoCodec() && t.isEncodeable())
          tmp.add(t);
      }
    }
   
    String[] codecs = new String[tmp.size()];
   
    for(int j = 0; j < tmp.size(); j++)
      codecs[j] = tmp.get(j).getShortDescription();
   
    return codecs;
  }
 
  /**
   *
   * @param path
   *         Path to ffmpeg
   * @throws IOException
   *         when ffmpeg binary was not found
   */
  public void setPath(String path) throws IOException
  {
    this.path = path;
    scan();
  }
 
  /**
   * Scans for codecs
   * @throws IOException
   *             on errors with ffmpeg process
   */
  private void scan() throws IOException
  {
    Runtime rt = Runtime.getRuntime();
   
    Process p = rt.exec(new String[] {path,"-formats"});
   
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
     
    String line;
    boolean scan = false;
   
    while((line = br.readLine()) != null)
    {
      if(Constants.debug)
        System.out.println(line);
     
      if(scan)
      {
        if(line.length() == 0)
        {
          scan = false;
          break;
        }
        String flags = line.substring(1, 7);

        supportedCodecs.add(new Codec(flags.charAt(0) == 'D',
                        flags.charAt(1) == 'E',
                        flags.charAt(2) == 'V',
                        flags.charAt(2) == 'A',
                        flags.charAt(2) == 'S',
                        flags.charAt(3) == 'S',
                        flags.charAt(4) == 'D',
                        flags.charAt(5) == 'T',
                        line.substring(8, 24).trim(),
                        line.substring(24).trim()));
      }
     
      if(line.contains("Codecs:"))
        scan = true;
     
    }
  }
 
  /**
   * Sets a new inputMedium
   * @param input
   *         Path to input file
   * @param caller
   *         Caller of the method
   * @param recv
   *         Download-State Receiver
   * @throws IOException
   *         when video url is incorrect or there are problems with the input medium format
   */
  public void setInput(String input, Component caller, FFMpegProgressReceiver recv) throws IOException
  {
    inputMedium = null;
 
    if(input.contains("youtube"))
    {
      URL url = new URL(input);
      InputStreamReader read = new InputStreamReader(url.openStream());
      BufferedReader in = new BufferedReader(read);
     
      String inputLine;
      String line = null;
      String vid = input.substring(input.indexOf("?v=") + 3);
      if(vid.indexOf("&") != -1)
        vid = vid.substring(0, vid.indexOf("&"));
     
     
      while ((inputLine = in.readLine()) != null)
      {
        if(inputLine.contains("\"t\": \""))
        {
          line = inputLine.substring(inputLine.indexOf("\"t\": \"")+6);
          line = line.substring(0, line.indexOf("\""));
          break;
        }
      }
      in.close();
     
      if(line == null)
        throw new IOException("Could not find flv-Video");
     
      Downloader dl = new Downloader("http://www.youtube.com/get_video?video_id=" + vid + "&t=" + line, recv, lang);
      dl.start();
     
      return;
    }
   
    Runtime rt = Runtime.getRuntime();

    Process p = rt.exec(new String[] {path, "-i", input});
   
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
     
    String line;
   
    Codec videoCodec = null;
    Codec audioCodec = null;
   
    double duration = -1;
   
    String aspectRatio = null;
    String scala = null;
    String colorSpace = null;
    String rate = null;
    String mrate = null;
    String aRate = null;
    String aFreq = null;
    String aChannel = null;
   
    try
    {
      while((line = br.readLine()) != null)
      {
        if(Constants.debug)
          System.out.println(line);
       
        if(line.contains("Duration:"))
        {
          int hours = Integer.parseInt(line.substring(12, 14));
          int mins = Integer.parseInt(line.substring(15,17));
          double secs = Double.parseDouble(line.substring(18,line.indexOf(',')));
          duration = secs + 60 * mins + hours * 60 * 60;
       
          Pattern pat = Pattern.compile("[0-9]+ kb/s");
          Matcher m = pat.matcher(line);
       
          if(m.find())
            mrate = line.substring(m.start(), m.end());
        }
        if(line.contains("Video:"))
        {
          String info = line.substring(24);
          String parts[] = info.split(", ");
          Pattern pat = Pattern.compile("Video: [a-zA-Z0-9]+,");
          Matcher m = pat.matcher(line);
         
          String codec = "";
         
          if(m.find())
            codec = line.substring(m.start(), m.end());
         
          videoCodec = supportedCodecs.getCodecByName(codec.replace("Video: ","").replace(",",""));
          colorSpace = parts[1];

          pat = Pattern.compile("[0-9]+x[0-9]+");
           m = pat.matcher(info);
       
          if(m.find())
            scala = info.substring(m.start(), m.end());
       
          pat = Pattern.compile("DAR [0-9]+:[0-9]+");
          m = pat.matcher(info);
       
          if(m.find())
            aspectRatio = info.substring(m.start(), m.end()).replace("DAR ", "");
          else if(scala != null)
            aspectRatio = String.valueOf((double) (Math.round(((double) ConvertUtils.getWidthFromScala(scala) / (double) ConvertUtils.getHeightFromScala(scala)) * 100)) / 100);
       
          pat = Pattern.compile("[0-9]+ kb/s");
          m = pat.matcher(info);
       
          if(m.find())
            rate = info.substring(m.start(), m.end());
        }
        else if(line.contains("Audio:"))
        {
          String info = line.substring(24);
       
          Pattern pat = Pattern.compile("Audio: [a-zA-Z0-9]+,");
          Matcher m = pat.matcher(line);
       
          String codec = "";
         
          if(m.find())
            codec = line.substring(m.start(), m.end()).replace("Audio: ", "").replace(",", "");
         
          if(codec.equals("mp3"))
            codec = "libmp3lame";
       
          audioCodec = supportedCodecs.getCodecByName(codec);
         
          pat = Pattern.compile("[0-9]+ kb/s");
          m = pat.matcher(info);
       
          if(m.find())
            aRate = info.substring(m.start(), m.end());
         
          pat = Pattern.compile("[0-9]+ Hz");
          m = pat.matcher(info);
       
          if(m.find())
            aFreq = info.substring(m.start(), m.end());
         
          if(line.contains("5.1"))
            aChannel = "5.1";
          else if(line.contains("2.1"))
            aChannel = "2.1";
          else if(line.contains("stereo"))
            aChannel = "Stereo";
          else if(line.contains("mono"))
            aChannel = "Mono";
        }
        if(videoCodec != null && audioCodec != null && duration != -1)
        {
          /* maybe incorrect!! (videoRate = mainRate - audioRate) */
          if(rate == null && mrate != null && aRate != null)
            rate = String.valueOf(ConvertUtils.getRateFromRateString(mrate) - ConvertUtils.getRateFromRateString(aRate)) + " kb/s";
          inputMedium = new InputMedium(audioCodec, videoCodec, input, duration, colorSpace, aspectRatio, scala, rate, mrate, aRate, aFreq, aChannel);
          break;
        }
      }
      if((videoCodec != null || audioCodec != null) && duration != -1)
        inputMedium = new InputMedium(audioCodec, videoCodec, input, duration, colorSpace, aspectRatio, scala, rate, mrate, aRate, aFreq, aChannel);
    }
    catch(Exception exc)
    {
      if(caller != null)
        JOptionPane.showMessageDialog(caller, lang.inputerror + " Audiocodec? " + (audioCodec != null) + " Videocodec? " + (videoCodec != null), lang.error, JOptionPane.ERROR_MESSAGE);
     
      if(Constants.debug)
        System.out.println("Audiocodec: " + audioCodec + "\nVideocodec: " + videoCodec);
     
      if(Constants.debug)
        exc.printStackTrace();
     
      throw new IOException("Input file error");
    }   
    if(inputMedium == null)
    {
      if(caller != null)
        JOptionPane.showMessageDialog(caller, lang.inputerror + " Audiocodec? " + (audioCodec != null) + " Videocodec? " + (videoCodec != null), lang.error, JOptionPane.ERROR_MESSAGE);
     
      if(Constants.debug)
        System.out.println("Audiocodec: " + audioCodec + "\nVideocodec: " + videoCodec);
     
      throw new IOException("Input file error");
    }
  }
 
  /**
   * Sets a new output medium
   * @param output
   *         Path to output file
   * @param audio
   *         audio codec short description
   * @param video
   *         video codec short description
   * @param aspect
   *         aspect ratio
   * @param scala
   *         scala (e.g. 123x234)
   * @param rate
   *         video bitrate
   * @param arate
   *         audio bitrate
   * @param type
   *         encoding type (vcd, svcd, dvd, user defined[, ...])
   * @param bps
   *         frames per second
   */
  public void setOutput(String output, String audio, String video, String aspect, String scala, String rate, String arate, int type, String bps, String channels)
  {
    outputMedium = new OutputMedium(supportedCodecs.getCodecByName(audio), supportedCodecs.getCodecByName(video), output, null, aspect, scala, rate, null , arate, null, channels, type, bps);
  }
 
  /**
   * Starts conversion
   * @pre Should be invoked by an extra Thread
   * @throws IOException
   */
  private void convert() throws IOException
  {
    Runtime rt = Runtime.getRuntime();
    String[] cmd;
   
    int channels = Integer.parseInt(outputMedium.getAChannel());
   
    switch(channels)
    {
      case 1: channels = 1; break;
      case 2: channels = 2; break;
      case 3: channels = 3; break;
      case 4: channels = 6; break;
      default: channels = 0; break;
    }
   
    if(outputMedium.getType() == 0)
      cmd = new String[] {path, "-i", inputMedium.getPath(), "-target", "pal-vcd", outputMedium.getPath()};
    else if(outputMedium.getType() == 1)
      cmd = new String[] {path, "-i", inputMedium.getPath(), "-target", "pal-svcd", outputMedium.getPath()};
    else if(outputMedium.getType() == 2)
      cmd = new String[] {path, "-i", inputMedium.getPath(), "-target", "pal-dvd", outputMedium.getPath()};
    else
    {
      if(!outputMedium.getAspectRatio().equals(lang.automatic))
      {
        if(outputMedium.getARate().isEmpty())
        {
          if(outputMedium.getBPS().equals("0"))
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-aspect", outputMedium.getAspectRatio(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), outputMedium.getPath()};
          else
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-r", outputMedium.getBPS(), "-aspect", outputMedium.getAspectRatio(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), outputMedium.getPath()};
        }
        else if(outputMedium.getAChannel().equals("0"))
        {
          if(outputMedium.getBPS().equals("0"))
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-aspect", outputMedium.getAspectRatio(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), "-ab", Integer.parseInt(outputMedium.getARate().trim()) * 1000 + "", outputMedium.getPath()};
          else
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-r", outputMedium.getBPS(), "-aspect", outputMedium.getAspectRatio(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), "-ab", Integer.parseInt(outputMedium.getARate().trim()) * 1000 + "", outputMedium.getPath()};
        }
        else
        {
          if(outputMedium.getBPS().equals("0"))
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-aspect", outputMedium.getAspectRatio(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), "-ac", channels + "", "-ab", Integer.parseInt(outputMedium.getARate().trim()) * 1000 + "", outputMedium.getPath()};
          else
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-r", outputMedium.getBPS(), "-aspect", outputMedium.getAspectRatio(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), "-ac", channels + "", "-ab", Integer.parseInt(outputMedium.getARate().trim()) * 1000 + "", outputMedium.getPath()};
        }
      }   
      else
      {
        if(outputMedium.getARate().isEmpty())
        {
          if(outputMedium.getBPS().equals("0"))
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), outputMedium.getPath()};
          else
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-r", outputMedium.getBPS(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), outputMedium.getPath()};
        }
        else if(outputMedium.getAChannel().equals("0"))
        {
          if(outputMedium.getBPS().equals("0"))
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), "-ab", Integer.parseInt(outputMedium.getARate().trim()) * 1000 + "", outputMedium.getPath()};
          else
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-r", outputMedium.getBPS(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), "-ab", Integer.parseInt(outputMedium.getARate().trim()) * 1000 + "", outputMedium.getPath()};
        }
        else
        {
          if(outputMedium.getBPS().equals("0"))
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), "-ac", channels + "", "-ab", Integer.parseInt(outputMedium.getARate().trim()) * 1000 + "", outputMedium.getPath()};
          else
            cmd = new String[] {path, "-i", inputMedium.getPath(), "-vcodec", outputMedium.getVideoCodec().getShortDescription(), "-s", outputMedium.getScala(), "-r", outputMedium.getBPS(), "-b", Integer.parseInt(outputMedium.getRate().trim()) * 1000 + "", "-acodec", outputMedium.getAudioCodec().getShortDescription(), "-ac", channels + "", "-ab", Integer.parseInt(outputMedium.getARate().trim()) * 1000 + "", outputMedium.getPath()};
        }
      }
    }
   
    if(Constants.debug)
    {
      for(int i = 0; i < cmd.length; i++)
        System.out.print(cmd[i] + " ");
      System.out.println();
    }
   
    Process p = rt.exec(cmd);
   
    int exit = 0;
   
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
   
    try
    {
      OutputStreamWriter osw = new OutputStreamWriter(p.getOutputStream());
      osw.write("y");
      osw.flush();
    }
    catch(Exception exc)
    {
      exit = 1;
      if(Constants.debug)
        System.out.println(exc.getMessage());
    }
   
    String line, lastline = "";
   
    if(recv != null)
    {
      int i = 0;
      while((line = br.readLine()) != null)
      {
        lastline = line;
       
        if(Constants.debug)
          System.out.println(line);
       
        if(Thread.currentThread().isInterrupted())
        {
          recv.setProgress(102);
          p.destroy();
          return;
        }
        if(line.contains("frame="))
        {
          i++;
          double time = Double.parseDouble(line.substring(line.indexOf("time=") + 5, line.indexOf("bitrate=") - 1));
          int progress = (int) (time / inputMedium.getDuration() * 100);
          if(progress >= 0 && progress < 100)
            recv.setProgress(progress);
          else
            recv.setProgress(100);
        }
      }
           
      try
      {
        Thread.sleep(500);
        exit = p.exitValue();
      }
      catch(Exception exc)
      {
        if(Constants.debug)
          System.out.println(exc.getMessage());
      }
      if(i == 0)
      {
        if(recv instanceof FFMpegGui)
          JOptionPane.showMessageDialog((FFMpegGui) recv, lastline, "FFMpeg Error", JOptionPane.ERROR_MESSAGE);
        recv.setProgress(103);
      }
      else if(exit != 0)
        recv.setProgress(105);
      else
        recv.setProgress(101);
    }
  }
 
  @Override
  public void run()
  {
    try
    {
      convert();
    }
    catch(Exception exc)
    {
      if(Constants.debug)
      {
        System.out.println("Conversion failed! " + exc.getMessage());
        exc.printStackTrace();
      }
    }
  }
 
  /**
   * Return the inputMedium
   * @return inputMedium or null if no inputMedium is set
   */
  public InputMedium getInputMedium()
  {
    return inputMedium;
  }
 
  /**
   * Returns the path to ffmpeg
   * @return path
   */
  public String getPath()
  {
    return path;
  }
}
TOP

Related Classes of ffmpeg.FFMpeg

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.