package com.css.common.util.imageConvertor;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 图片转换
*
* 这里的图片转换是 利用 java 调用外部程序 ffmpeg 进行处理.
* ffmpeg.exe能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
* 对ffmpeg.exe无法解析的文件格式(wmv9,rm,rmvb等),
* 可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式;
* mencoder.exe;
* drv43260.dll;
* pncrt.dll
* 以上这3个文件是为文件格式(wmv9,rm,rmvb等)
* 转换为avi(ffmpeg能解析的)格式准备的;再把转换好的avi文件再用ffmpeg.exe转换成flv格式的视频文件
*
* @author huayi
*
*/
public class ImageConvertor {
private static final String FILE_SEPARATOR = File.separator;
private static boolean isSurpportedType(String type){
Pattern pattern = Pattern.compile("(asx|asf|mpg|wmv|3gp|mp4|mov|avi|flv){1}$",Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(type);
return matcher.find();
}
/**
*
* @param sourceFile 将要被转换的目标文件
* @param desctination 转换之后文件的存放路径
* ffmpeg commandLine:
* ffmpeg -y -i /usr/local/bin/lh.mp4 -ab 56 -ar 22050 -b 500 -s 320x240 /usr/local/bin/lh.flv
* @throws IOException
*/
public static void converToFlv(String ffmpegPath ,File sourceFile,String destination) throws IOException {
if(!sourceFile.exists()) throw new IOException("invalid file path");
if(!new File(destination).exists()) throw new IOException("invalid file path "+destination);
String fileName = sourceFile.getName();
String surffix = fileName.substring(fileName.lastIndexOf(".")+1);
if(!isSurpportedType(surffix)) throw new RuntimeException("unsurpported file type "+surffix);
List cmdParam = new LinkedList();
cmdParam.add(ffmpegPath);
cmdParam.add("-y");
cmdParam.add("-i");
cmdParam.add(sourceFile.getAbsolutePath());
cmdParam.add("-ab");
cmdParam.add("56");
cmdParam.add("-ar");
cmdParam.add("22050");
cmdParam.add("-b");
cmdParam.add("500");
cmdParam.add("-s");
cmdParam.add("320*240");
cmdParam.add(destination+FILE_SEPARATOR+fileName.substring(0,fileName.lastIndexOf("."))+".flv");
execCmd(cmdParam);
}
/**
*
* 获取图片的第一帧
* ffmpeg commandLine:
* ffmpeg -y -i /usr/local/bin/lh.3gp -vframes 1 -r 1 -ac 1 -ab 2 -s 320x240 -f image2 /usr/local/bin/lh.jpg
*
* @param sourceFile 源文件
* @param destination 目标文件
* @param surfix 要保存的图片格式:jpg,jpeg,gif
* @throws IOException
*/
public static void captureFirstFrame(String ffmpegPath ,File sourceFile ,String destination,String surfix) throws IOException{
if(!sourceFile.exists()) throw new IOException("invalid file path");
if(!new File(destination).exists()) throw new IOException("invalid file path "+destination);
String fileName = sourceFile.getName();
String surffix = fileName.substring(fileName.lastIndexOf(".")+1);
if(!isSurpportedType(surffix)) throw new RuntimeException("unsurpported file type "+surffix);
List cmd = new LinkedList();
cmd.add(ffmpegPath);
cmd.add("-y");
cmd.add("-i");
cmd.add(sourceFile.getAbsolutePath());
cmd.add("-vframes");
cmd.add("1");
cmd.add("-r");
cmd.add("1");
cmd.add("-ac");
cmd.add("1");
cmd.add("-ab");
cmd.add("2");
cmd.add("-s");
cmd.add("320*240");
cmd.add("-f");
cmd.add("image2");
cmd.add(destination+FILE_SEPARATOR+fileName.substring(0,fileName.lastIndexOf("."))+"."+surfix);
execCmd(cmd);
}
/**
*
* @param cmd
*/
private static void execCmd(List cmd){
final ProcessBuilder pb = new ProcessBuilder();
//每个进程都有标准的输入、输出、和错误流。(stdin ,stdout ,stderr)
//合并子进程的 【错误流】和 常规的 【输出流】
pb.redirectErrorStream(true);
pb.command(cmd);
try {
final Process p = pb.start();
OutputStream os = p.getOutputStream();
InputStream in = p.getInputStream();
//开启单独的线程来处理输入和输出流,避免缓冲区满导致线程阻塞.
new Thread( new Receiver(in)).start();
new Thread( new Sender(os)).start();
try{
p.waitFor();
}catch(InterruptedException e){
e.printStackTrace();
//唤醒当前线程
Thread.currentThread().interrupt();
}
System.out.println( "Child done" );
// at this point the child is complete. All of its output may or may not have been processed however.
// The Receiver thread will continue until it has finished processing it.
// You must close the streams even if you never use them! In this case the threads close is and os.
p.getErrorStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* wrapper for Runtime.exec.
* No input/output. Optionally wait for child to finish.
* @param command fully qualified *.exe or *.com command
* @param wait true if you want to wait for the child to finish.
*/
public static Process exec ( String command, boolean wait ){
Process p;
try{
p = Runtime.getRuntime().exec( command );
}catch ( IOException e ){
return null;
}
if ( wait ){
try{
p.waitFor();
}catch ( InterruptedException e ){
Thread.currentThread().interrupt();
}
}
// You must close these even if you never use them!
try {
p.getInputStream().close();
p.getOutputStream().close();
p.getErrorStream().close();
} catch (IOException e) {
e.printStackTrace();
}
return p;
}
public static void main(String[] args) {
String ffmpegPath = "D:\\workspace\\EnterpriceWebService\\src\\com\\css\\common\\util\\imageConvertor\\ffmpeg.exe";
File file = new File("F:\\\\3gp\\t12.3gp");
try {
converToFlv(ffmpegPath,file,"F:\\\\3gp\\flv\\");
} catch (IOException e) {
e.printStackTrace();
}
/*
for(int i=0;i<12;i++){
File file = new File("F:\\\\3gp\\t"+(i+1)+".3gp");
getFirstFrame(ffmpegPath, file,"F:\\\\3gp\\image\\","jpg");
}
*/
}
}
final class Sender implements Runnable{
private static final String lineSeparator = System.getProperty( "line.separator" );
private final OutputStream os;
public void run() {
try {
final BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( os ), 500 );
for ( int i = 99; i >= 0; i-- ) {
bw.write( "There are " + i + " bottles of beer on the wall, " + i + " bottles of beer." );
bw.write( lineSeparator );
}
bw.close();
} catch ( IOException e ) {
throw new IllegalArgumentException( "IOException sending data to child process." );
}
}
Sender( OutputStream os ) {
this.os = os;
}
}
final class Receiver implements Runnable {
private final InputStream is;
public void run() {
try {
final BufferedReader br = new BufferedReader( new InputStreamReader( is ), 500 );
String line;
while ( ( line = br.readLine() ) != null ) {
System.out.println( line );
}
br.close();
} catch ( IOException e ) {
throw new IllegalArgumentException( "IOException receiving data from child process." );
}
}
Receiver( InputStream is ) { this.is = is; } }