`

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

阅读更多
很艰辛很痛苦...几次几乎被玩死...代码贴出来...对自己是留念...对别人是引玉...
开始...
首先是视频转码, 多种视频格式都转换成.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;
     }
   }
分享到:
评论

相关推荐

    精易模块[源码] V5.15

    1、新增“线程_枚举”枚举指定进程ID中所有线程列表,成功返回线程数量,失败返回零。 2、删除“文件_取图标”与"文件_取图标句柄"功能重复。 3、优化“系统_创建桌面快捷方式”流程代码,感谢易友[ds9660]反馈。 4...

    安川MP7系列工控系统源码解析:关键算法与硬件交互揭秘

    内容概要:本文深入剖析了安川MP7系列工业控制系统的关键源码,重点介绍了运动轨迹规划、通信协议处理以及故障处理机制等方面的技术细节。通过对实际代码片段的解读,揭示了该系统在硬件寄存器直接访问、特殊功能码处理等方面的独特之处。同时,文中还分享了一些基于实践经验得出的重要参数设置及其背后的故事,如特定摩擦补偿系数的选择原因等。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对安川产品有一定了解并希望深入了解其内部工作机制的专业人士。 使用场景及目标:帮助读者掌握安川MP7系列控制器的工作原理,提高对类似系统的维护能力和故障排查效率。对于想要进一步研究或二次开发该系统的开发者来说,也能提供宝贵的参考资料。 其他说明:文章不仅限于理论讲解,还包括了许多来自一线的实际案例和经验教训,使读者能够更好地理解和应用所学知识。

    自动化测试与脚本开发_Python3_pynput_键盘鼠标操作录制执行代码生成工具_用于自动化测试_脚本录制_重复操作模拟_宏命令生成_提高工作效率_支持GUI界面_跨平台兼容_.zip

    自动化测试与脚本开发_Python3_pynput_键盘鼠标操作录制执行代码生成工具_用于自动化测试_脚本录制_重复操作模拟_宏命令生成_提高工作效率_支持GUI界面_跨平台兼容_

    嵌入式八股文面试题库资料知识宝典-深入分析Windows和Linux动态库应用异同.zip

    嵌入式八股文面试题库资料知识宝典-深入分析Windows和Linux动态库应用异同.zip

    嵌入式八股文面试题库资料知识宝典-C语言总结.zip

    嵌入式八股文面试题库资料知识宝典-C语言总结.zip

    风储直流微电网母线电压控制策略与双闭环MPPT技术研究

    内容概要:本文详细探讨了风储直流微电网中母线电压控制的关键技术。首先介绍了风储直流微电网的背景和发展现状,强调了母线电压控制的重要性。接着阐述了永磁风机储能并网技术,解释了永磁风机如何通过直接驱动发电机将风能转化为电能,并确保与电网的同步性和稳定性。然后深入讨论了双闭环控制MPPT技术,这是一种通过内外两个闭环控制系统来实现实时调整发电机运行参数的技术,确保风机始终处于最大功率点附近。最后,文章探讨了储能控制母线电压平衡的方法,即通过储能系统的充放电操作来维持母线电压的稳定。结论部分指出,通过这些技术的有机结合,可以实现对风储直流微电网的有效管理和优化控制。 适合人群:从事新能源技术研发的专业人士、电气工程研究人员、风电系统工程师。 使用场景及目标:适用于希望深入了解风储直流微电网母线电压控制策略的研究人员和技术人员,旨在帮助他们掌握最新的控制技术和方法,以提高系统的稳定性和效率。 其他说明:文章还对未来风储直流微电网的发展进行了展望,指出了智能化和自动化的趋势,以及储能技术的进步对系统性能的影响。

    嵌入式八股文面试题库资料知识宝典-C++object-oriented.zip

    嵌入式八股文面试题库资料知识宝典-C++object-oriented.zip

    【操作系统开发】HarmonyOS目录结构详解:构建高效开发环境与跨设备协同应用

    内容概要:文章详细介绍了HarmonyOS的目录结构及其重要性,从整体框架到核心目录的具体功能进行了全面剖析。HarmonyOS凭借其分布式架构和跨设备协同能力迅速崛起,成为全球操作系统领域的重要力量。文章首先概述了HarmonyOS的背景和发展现状,强调了目录结构对开发的重要性。接着,具体介绍了根目录文件、AppScope、entry和oh_modules等核心目录的功能和作用。例如,AppScope作为全局资源配置中心,存放应用级的配置文件和公共资源;entry目录是应用的核心入口,负责源代码和界面开发。此外,文章还对比了HarmonyOS与Android、iOS目录结构的异同,突出了HarmonyOS的独特优势。最后,通过旅游应用和电商应用的实际案例,展示了HarmonyOS目录结构在资源管理和代码组织方面的应用效果。; 适合人群:具备一定编程基础,尤其是对移动操作系统开发感兴趣的开发者,包括初学者和有一定经验的研发人员。; 使用场景及目标:①帮助开发者快速理解HarmonyOS的目录结构,提高开发效率;②为跨设备应用开发提供理论和技术支持;③通过实际案例学习资源管理和代码组织的最佳实践。; 其他说明:HarmonyOS的目录结构设计简洁明了,模块职责划分明确,有助于开发者更好地管理和组织代码和资源。随着万物互联时代的到来,HarmonyOS有望在开发便利性和生态建设方面取得更大进展,吸引更多开发者加入其生态系统。

    飞轮储能充放电控制Simulink仿真模型:基于永磁同步电机的矢量控制与dq轴解耦

    内容概要:本文详细介绍了飞轮储能充放电控制的Simulink仿真模型,重点在于采用永磁同步电机的矢量控制和dq轴解耦控制策略。充电时,外环控制转速,内环控制dq轴电流;放电时,外环控制直流母线电压,内环同样控制dq轴电流。文中还讨论了硬件与软件环境的选择,以及仿真模型的调试与运行情况,最终得出该模型具有良好的跟随性能和波形完美度。 适用人群:从事电力电子系统、储能技术和Simulink仿真的研究人员和技术人员。 使用场景及目标:适用于需要对飞轮储能系统进行深入研究和仿真的场合,旨在提高充放电效率和稳定性,满足不同应用场景的需求。 其他说明:该仿真模型已调试完成,可以直接用于进一步的研究和实际应用,为未来的飞轮储能技术研发提供了有价值的参考。

    嵌入式八股文面试题库资料知识宝典-北京瑞德方科技.zip

    嵌入式八股文面试题库资料知识宝典-北京瑞德方科技.zip

    嵌入式八股文面试题库资料知识宝典-同方万维硬件测试工程师.zip

    嵌入式八股文面试题库资料知识宝典-同方万维硬件测试工程师.zip

    1_15套python PDF格式.zip

    1_15套python PDF格式.zip

    三相三电平整流器仿真:基于电压电流双闭环控制与SPWM调制的性能分析

    内容概要:本文详细介绍了三相三电平整流器的仿真过程及其性能分析。文中首先概述了三相三电平整流器的基本概念及其在电力系统中的重要作用,接着重点探讨了电压电流双闭环控制方式的工作原理和优势,以及SPWM调制技术的具体应用。通过仿真文件展示了整流器在不同条件下的响应情况,验证了这两种技术的有效性和优越性。最后,作者表达了对未来实际应用的期望。 适合人群:从事电力电子研究的技术人员、高校相关专业师生、对电力控制系统感兴趣的工程爱好者。 使用场景及目标:适用于希望深入了解三相三电平整流器工作原理和技术细节的研究人员;目标是在理论基础上掌握电压电流双闭环控制和SPWM调制的实际应用方法。 其他说明:本文提供的仅为仿真文件,未涉及实物实验数据。

    嵌入式八股文面试题库资料知识宝典-恒光科技.zip

    嵌入式八股文面试题库资料知识宝典-恒光科技.zip

    嵌入式八股文面试题库资料知识宝典-北京天华威视科技有限公司面试题.zip

    嵌入式八股文面试题库资料知识宝典-北京天华威视科技有限公司面试题.zip

    嵌入式八股文面试题库资料知识宝典-微软研究院笔试题目的答案.zip

    嵌入式八股文面试题库资料知识宝典-微软研究院笔试题目的答案.zip

    Arduino UART实验例程【正点原子EPS32S3】

    Arduino UART实验例程,开发板:正点原子EPS32S3,本人主页有详细实验说明可供参考。

    嵌入式八股文面试题库资料知识宝典-朝歌数码.zip

    嵌入式八股文面试题库资料知识宝典-朝歌数码.zip

    嵌入式八股文面试题库资料知识宝典-Cortex系列.zip

    嵌入式八股文面试题库资料知识宝典-Cortex系列.zip

Global site tag (gtag.js) - Google Analytics