很艰辛很痛苦...几次几乎被玩死...代码贴出来...对自己是留念...对别人是引玉...
开始...
首先是视频转码, 多种视频格式都转换成.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;
}
}
分享到:
相关推荐
在C#编程中,线程池(ThreadPool)是一种高效的线程管理机制,它允许开发者创建并管理多个线程,而无需直接操作线程对象。线程池中的线程可以复用,减少了创建和销毁线程的开销。当我们需要执行大量短生命周期的任务...
这时,我们可以利用`curl`的多线程功能来提升性能,构建线程池来更有效地管理这些并发任务。 标题"curl线程池多线程调用"指向的关键技术点包括: 1. **多线程**:多线程是一种并发执行任务的方法,通过创建多个...
线程池管理和多线程上传是并发编程中的一个重要实践,特别是在大数据传输和网络服务中。在Java等编程语言中,线程池通过有效地管理和复用线程资源,避免了频繁创建和销毁线程带来的开销,提升了系统性能。下面将详细...
鱼刺线程池 多线程拨号代码。@L1yp。Tags:鱼刺线程池多线程拨号代码。
在IT行业中,多线程是程序设计中的一个重要概念,特别是在处理并发操作时,如网络服务、数据处理和用户界面更新等。多线程允许程序同时执行...通过源码学习,我们可以深化对多线程和线程池的理解,提升我们的编程能力。
在编程领域,多线程是提高程序执行效率和响应能力的一种常见技术,特别是在处理I/O密集型任务如网络下载时。Qt是一个强大的跨平台应用程序开发框架,提供了丰富的API来支持多线程编程。本篇文章将深入讲解如何使用Qt...
在Android开发中,SwipeRefreshLayout、RecyclerView以及线程池多线程下载是三个非常重要的组件和技术。下面将分别详细讲解这三个知识点及其整合应用。 首先,SwipeRefreshLayout是Android提供的一种下拉刷新布局,...
在IT领域,尤其是在网络编程和高性能服务器开发中,C++线程池和多线程SOCKET服务器框架扮演着至关重要的角色。线程池是一种管理线程的机制,它有效地解决了频繁创建和销毁线程带来的开销,提高了系统资源的利用率。...
在编程领域,线程池和多线程是提高程序并发性能和优化资源管理的重要技术,尤其是在Windows环境下,Visual C++(简称VC)提供了强大的支持。本文将深入探讨线程池和多线程的概念,以及如何在VC环境中实现它们。 ...
### 多线程编程线程池 #### 一、引言 在计算机科学领域,多线程编程是一种广泛采用的技术,旨在通过同时处理多个任务来提高应用程序的性能和响应速度。然而,创建和销毁线程的过程是相对昂贵的,尤其是在处理大量...
线程池是另一种优化多线程并发处理的机制,它通过重用已经创建的线程来减少线程创建和销毁的开销,提高系统效率。在本篇内容中,我们将深入探讨IOCP编程和线程池的概念、原理以及它们如何协同工作,以实现高效的多...
线程池是一种管理线程资源的有效机制,而线程同步则是确保多线程间正确交互的关键概念。本文将深入探讨这些主题。 首先,我们来了解**多线程**。在单线程环境下,程序按顺序执行任务,而在多线程中,程序可以同时...
在IT行业中,多线程和线程池是提高程序并发性能和资源管理的关键技术。尤其在Java编程领域,它们在大型系统和并发密集型应用中扮演着重要角色。本篇文章将详细探讨“常用多线程模板”以及“鱼刺类(Fork/Join框架)...
线程池是多线程编程中的一个重要概念,它是一种线程使用模式,旨在优化系统资源的使用并提高系统的响应速度。在Java中,线程池通过`java.util.concurrent`包中的`ExecutorService`接口和其相关类实现。下面将详细...
线程池是多线程编程中一个重要的概念,它能够优化系统资源的使用,提高系统的响应速度和效率。本篇文章将深入探讨C++中的线程池实现,并通过名为“OEasyPool-1.0”的示例来展示其工作原理。 线程池是预先创建并维护...
C++多线程从原理到线程池实战是一门针对C++程序员设计的课程。通过深入学习多线程的原理和技术,学生将掌握线程管理、同步与互斥、并发编程等核心概念。课程还包括线程池的设计与实践,帮助学生提高程序性能和并行...
Java线程池是Java并发编程中的重要组成部分,它允许开发者高效地管理多个并发执行的线程,有效地控制系统的资源消耗,提高系统性能和稳定性。在Java中,`java.util.concurrent`包提供了`ExecutorService`接口及其...
在C#编程中,多线程和线程池是实现并发执行任务的关键技术,它们能够提升应用程序的性能和响应性。下面将详细讲解这两个概念及其应用。 **一、多线程** 多线程允许程序同时执行多个独立的任务,提高CPU利用率。在...
在IT领域,尤其是在系统编程和并发处理中,C语言多线程编程是一个重要的主题。线程池是一种优化的线程管理技术,它提高了系统资源的利用率,并降低了线程的创建和销毁开销。本文将深入探讨C语言中的线程池及其相关...