线程池多线程视频转码(完整版)

很艰辛很痛苦...几次几乎被玩死...代码贴出来...对自己是留念...对别人是引玉...
开始...
首先是视频转码, 多种视频格式都转换成.flv格式. ConvertVideo.java
package com.enorth.lichen.transcode;

import java.io.File;
import java.util.List;

public class ConvertVideo {

   //原始文件
   private String videoPath;
   //目标文件
   private String targetPath;
    
   public ConvertVideo(String videoPath , String targetPath){
     this.videoPath=videoPath;
     this.targetPath=targetPath;
   }
    
   public synchronized void process() {
     int type = checkContentType();
     if (type == 0) {
       this.ffmpegTransVideo();
       this.ffmpegTransImage();
     } else if (type == 1) {
       this.mencoderTransVideo();
     }
   }

   public synchronized int checkContentType() {
     String type = videoPath.substring(videoPath.lastIndexOf( ".") + 1, videoPath.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;
   }

   public synchronized static boolean checkfile(String path) {
     File file = new File(path);
     if (!file.isFile()) {
       return false;
     }
     return true;
   }
    
   /**
     * 使用mencoder转码
     * @param videoPath 源路径 -- 要转换的视频文件
     * @param targetPath 目标路径 -- 转换后的视频flv
     * @return 返回目标路径
     */

   public synchronized     String mencoderTransVideo() {
     List<String> commend = new java.util.ArrayList<String>();
     commend.add( "d:\\flv\\MediaCoder\\codecs\\mencoder.exe");    
     commend.add(videoPath);
     //音频采用mp3编码
     commend.add( "-oac");
     commend.add( "mp3lame");
     //采用高质DivX视频编码,视频码率为112kbps
     commend.add( "-ovc");
     commend.add( "lavc");
     commend.add( "-lavcopts");
     commend.add( "vcodec=flv:vbitrate=500:mbd=2:mv0:trell:v4mv:cbp:last_pred=3:dia=-1:cmp=3:vb_strategy=1");
     commend.add( "-lameopts");
     commend.add( "abr:br=56");
     //声音采样频率设置,现为22K    
     commend.add( "-srate");
     commend.add( "22050");
     //-sws就是用来设置品质的,默认值为2
     commend.add( "-sws");
     commend.add( "3");
     //宽度为208,高度自动调整保持比例;
     //-vf scale=-3:176宽度自动调整保持比例,高度为176;如果想保持原来的大小可以不要这个参数    
     commend.add( "-vf");
     commend.add( "scale=512:-3");
     // 帧速率设置
     commend.add( "-ofps");
     commend.add( "18");
     /*
     * mode=3:cbr:br=24单声道
     * 音频码率为24kbps;-lameopts mode=0:cbr:br=24立体声,音频码率为24kbps;    
     * 还可设置音量,-lameopts mode=3:cbr:br=32:vol=1,设置范置为1~10,但不宜设得太高
     */

     commend.add( "-lameopts");
     commend.add( "vbr=3:br=128");
     commend.add( "-o");
     commend.add(targetPath);
     //控制台显示执行的命令
     //System.out.println(commend);
     try {
       ProcessBuilder builder = new ProcessBuilder();
       builder.command(commend);
       builder.start();
       return targetPath;
     } catch (Exception e) {
       e.printStackTrace();
       return null;
     }
   }
    
    
    
   public synchronized String ffmpegTransVideo() {
//     if (!checkfile(videoPath)) {
//       System.out.println(videoPath + " is not file aaa");
//       return false;
//     }
     List<String> commend = new java.util.ArrayList<String>();
     commend.add( "d:\\flv\\MediaCoder\\codecs\\ffmpeg.exe");    
     commend.add( "-i");
     commend.add(videoPath);
     commend.add( "-ab");
     commend.add( "64");
//     commend.add(" -acodec ");
//     commend.add("codec");
     commend.add( "-ac");
     commend.add( "2");
     commend.add( "-ar");
     commend.add( "22050");
     //清晰度     -qscale 4 为最好可是文件大, -qscale 6就可以了
     commend.add( "-qscale");
     commend.add( "6");
//     commend.add("-b");
//     commend.add("768");
//     commend.add("230");
//     commend.add("-s");
//     commend.add("352x240");
//     commend.add("-r");
//     commend.add("29.97");
     commend.add( "-y");
     commend.add(targetPath);
     System.out.println(commend);
     try {
       ProcessBuilder builder = new ProcessBuilder();
       builder.command(commend);
       builder.start();
       return targetPath;
     } catch (Exception e) {
       e.printStackTrace();
       return null;
     }
   }
// 生成图片 参数String newfilename, String newimg
   public synchronized boolean ffmpegTransImage() {
     List<String> commend = new java.util.ArrayList<String>();
     commend.add( "d:\\flv\\MediaCoder\\codecs\\ffmpeg.exe");
     commend.add( "-i");
     commend.add( "d:\\test\\a.mpg");
     commend.add( "-y");
     commend.add( "-f");
     commend.add( "image2");
     commend.add( "-ss");
     commend.add( "38");
     commend.add( "-t");
     commend.add( "0.001");
     commend.add( "-s");
     commend.add( "320x240");
     commend.add( "d:\\test\\b.jpg");
     try {
       ProcessBuilder builder = new ProcessBuilder();
       builder.command(commend);
       builder.start();
       return true;
     } catch (Exception e) {
       e.printStackTrace();
       return false;
     }
   }
    
}
然后是把这个转码做成线程 ThreadTransCode.java
package com.enorth.lichen.transcode;

public class ThreadTransCode implements Runnable {

   //原始文件
   private String videoPath;
   //目标文件
   private String targetPath;

   public ThreadTransCode(String videoPath, String targetPath) {
     this.videoPath = videoPath;
     this.targetPath = targetPath;
   }

   @Override
   public void run() {
     synchronized ( this) {
       System.out.println( "转码开始..............");
       ConvertVideo cv = new ConvertVideo(videoPath, targetPath);
       cv.process();
     }
   }
}
下来就是线程池了, 自己写的先贴上 ThreadPool.java
package com.enorth.lichen.transcode;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPool {
    
   public static ExecutorService exec = Executors.newFixedThreadPool(3);
    
   public static synchronized void trans(String videoPath,String targetPath){
     ThreadTransCode trans= new ThreadTransCode(videoPath,targetPath);
     exec.execute(trans);
   }
}  
最后就是在action里调用了,action 里只需要以下

     /**
     * 自己写的线程池
     */

     ThreadPool.trans(videoPath, targetPath);
就可以了.
另一种是spring封装的线程池, 其余部分不变,只是线程池就不用自己写了
   < bean id ="taskExecutor"
     class ="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" >
     < property name ="corePoolSize" value ="3" />
     < property name ="keepAliveSeconds" value ="200" />
     < property name ="maxPoolSize" value ="5" />
     < property name ="queueCapacity" value ="25" />
   </ bean >
这样配置之后.记得要在action里注入
     < bean id ="saveVideoAction" class ="com.enorth.lichen.action.video.SaveVideoAction" scope ="prototype" >
       < property name ="taskExecutor" >
         < ref bean ="taskExecutor" />
       </ property >
     </ bean >
最后在action里写一句
     /**
     * 使用spring封装的线程池
     */

     taskExecutor.execute( new ThreadTransCode(videoPath,targetPath));
以上就是使用线程池 多线程视频转码...

值得留念...

 

---------------------------------------------------
重要说明: 如果遇到停掉tomcat才能进行转码的情况. 并不是线程死锁的原因(最初我是这样认为的,所以所有的synchronized可以去除了), 是ffmpeg错误流缓冲区的问题, 感觉算ffmpeg的bug.
解决方法:
在转码的类中 ConvertVideo.java 修改ffmpegTransVideo()方法
   public String ffmpegTransVideo() {
     // if (!checkfile(videoPath)) {
     // System.out.println(videoPath + " is not file aaa");
     // return false;
     // }
     List<String> commend = new java.util.ArrayList<String>();
     commend.add( "d:\\flv\\MediaCoder\\codecs\\ffmpeg.exe");
     commend.add( "-i");
     commend.add(videoPath);
     commend.add( "-ab");
     commend.add( "64");
     // commend.add(" -acodec ");
     // commend.add("codec");
     commend.add( "-ac");
     commend.add( "2");
     commend.add( "-ar");
     commend.add( "22050");
     // 清晰度 -qscale 4 为最好可是文件大, -qscale 6就可以了
     commend.add( "-qscale");
     commend.add( "6");
     // commend.add("-b");
     // commend.add("768");
     // commend.add("230");
     // commend.add("-s");
     // commend.add("352x240");
     // commend.add("-r");
     // commend.add("29.97");
     commend.add( "-y");
     commend.add(targetPath);
     System.out.println(commend);
     try {
       ProcessBuilder builder = new ProcessBuilder();
       builder.command(commend);
       Process process = builder.start();
       InputStream is = process.getErrorStream();
       InputStreamReader inputStreamReader = new InputStreamReader(is);
       BufferedReader inputBufferedReader = new BufferedReader(
           inputStreamReader);
       String line = null;
       StringBuilder stringBuilder = new StringBuilder();
      while ((line = inputBufferedReader.readLine()) != null) {
         stringBuilder.append(line);
       }
       inputBufferedReader.close();
       inputBufferedReader = null;
       inputStreamReader.close();
       inputStreamReader = null;
       is.close();
       is = null;
       return targetPath;
     } catch (Exception e) {
       e.printStackTrace();
       return null;
     }
   }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值