Spring视频转码工具类ffmpeg

使用的是ffmepg,需要先下载,然后解压到指定文件夹,
其中的变量ffmpegPath指定的是ffmepg解压后的exe路径

这里看到processVideoFormat()方法中,推荐一律使用MgrPrintStream的方式进行使用而不是用doWaitFor,
如果用doWaitFor方法,可能会导致程序执行完了,线程还没有执行完,转码失败
工具类ConverVideoUtils

值得一提的是:ffmpeg默认就会转成h264,
如果有出现视频看不了但是有声音,可以尝试转码

package com.haoyu.framework.modules.file.utils;


import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 视频转码工具类
 *
 * @author jwc
 */
@Component
public class ConverVideoUtils {


	protected final Logger logger = LoggerFactory.getLogger(this.getClass());


	/**
	 * 转换视频格式
	 *
	 * @param sourceVideoPath 视频地址
	 * @return
	 */
	public String beginConver(String sourceVideoPath) {
		//转码格式
		String targetExtension = ".mp4";
		//是否删除原文件
		Boolean isDeleteResult = false;
		File fi = new File(sourceVideoPath);
		String fileName = fi.getName();
		//文件名不带扩展名
		String fileRealName = fileName.substring(0, fileName.lastIndexOf("."));
		logger.info("接收到文件(" + sourceVideoPath + ")需要转换");
		if (!checkfile(sourceVideoPath)) {
			logger.error(sourceVideoPath + "文件不存在" + " ");
			return "";
		}
		long beginTime = System.currentTimeMillis();
		logger.info("开始转文件(" + sourceVideoPath + ")");
		String path = process(fileRealName, sourceVideoPath, targetExtension, isDeleteResult);
		if (StrUtil.isNotEmpty(path)) {
			logger.info("转换成功");
			long endTime = System.currentTimeMillis();
			long timeCha = (endTime - beginTime);
			String totalTime = sumTime(timeCha);
			logger.info("转换视频格式共用了:" + totalTime + " ");
			if (isDeleteResult) {
				deleteFile(sourceVideoPath);
			}
			return path;
		} else {
			return "";
		}
	}

	/**
	 * 实际转换视频格式的方法
	 *
	 * @param fileRealName    文件名不带扩展名
	 * @param sourceVideoPath 原文件地址
	 * @param targetExtension 目标视频扩展名
	 * @param isDeleteResult  转换完成后是否删除源文件
	 * @return
	 */
	private String process(String fileRealName, String sourceVideoPath, String targetExtension, boolean isDeleteResult) {
		int type = checkContentType(sourceVideoPath);
		String path = "";
		if (type == 0) {
			//如果type为0用ffmpeg直接转换
			path = processVideoFormat(sourceVideoPath, fileRealName, targetExtension, isDeleteResult);
		}
		return path;
	}

	/**
	 * 检查文件类型
	 *
	 * @param sourceVideoPath 原文件地址
	 * @return
	 */
	private int checkContentType(String sourceVideoPath) {
		String type = sourceVideoPath.substring(sourceVideoPath.lastIndexOf(".") + 1).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;
	}

	/**
	 * 检查文件是否存在
	 *
	 * @param path 文件地址
	 * @return
	 */
	private boolean checkfile(String path) {
		File file = new File(path);
		if (!file.isFile()) {
			return false;
		} else {
			return true;
		}
	}


	/**
	 * 转换为指定格式
	 * ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
	 *
	 * @param oldFilePath     源文件地址
	 * @param fileRealName    文件名不带扩展名
	 * @param targetExtension 目标格式扩展名 .xxx
	 * @return
	 */
	private String processVideoFormat(String oldFilePath, String fileRealName, String targetExtension, Boolean isDeleteResult) {
		/**
		 * ffmpeg.exe的地址
		 */
//		String ffmpegPath = "D:\\ffmpeg\\bin\\ffmpeg.exe";
		String ffmpegPath = "E:\\ffmpeg-20171225-be2da4c-win64-static\\bin\\ffmpeg.exe";
		/**
		 * 转码后的存放视频地址 mp4格式
		 */
//		String targetFolder = "C:\\Users\\Administrator\\Desktop\\test\\";
		String targetFolder = "E:\\testzhuanma\\";
		if (!checkfile(oldFilePath)) {
			logger.error(oldFilePath + "文件不存在");
			return "";
		}
		List<String> commend = new ArrayList<>();
		commend.add(ffmpegPath);
		commend.add("-i");
		commend.add(oldFilePath);
		commend.add("-threads");
		commend.add("5");
		commend.add("-preset");
		commend.add("-ultrafast");
		commend.add("-vcodec");
		commend.add("copy");
		commend.add(targetFolder + fileRealName + targetExtension);
		try {
//			ProcessBuilder builder = new ProcessBuilder(commend);
//			builder.command(commend);
//			builder.redirectErrorStream(true);
//			Process p = builder.start();
//			doWaitFor(p);
//			p.destroy();


			Process videoProcess = new ProcessBuilder(commend).redirectErrorStream(true).start();
			new MgrPrintStream(videoProcess.getErrorStream()).start();
			new MgrPrintStream(videoProcess.getInputStream()).start();
			videoProcess.waitFor();

			String videoPath = targetFolder + fileRealName + targetExtension;
//			String path = this.processVideoFormatH264(videoPath, ffmpegPath, targetFolder, targetExtension, isDeleteResult);
			return videoPath;
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		}
	}

	/**
	 * 将mpeg4转为h264编码 为了支持播放器
	 *
	 * @param path
	 * @param ffmpegPath
	 * @return
	 */
	private String processVideoFormatH264(String path, String ffmpegPath, String targetFolder, String targetExtension, Boolean isDeleteResult) {
		if (!checkfile(path)) {
			logger.error(path + "文件不存在");
			return "";
		}
		String newFilePath = targetFolder + UUID.randomUUID().toString() + targetExtension;
		List<String> commend = new ArrayList<>();
		commend.add(ffmpegPath);
		commend.add("-i");
		commend.add(path);
		commend.add("-threads");
		commend.add("5");
		commend.add("-preset");
		commend.add("-ultrafast");
		commend.add("-vcodec");
		commend.add("h264");
		commend.add("-q");
		commend.add("0");
		commend.add("-y");
		commend.add(newFilePath);
		try {
			ProcessBuilder builder = new ProcessBuilder();
			builder.command(commend);
			Process p = builder.start();
			doWaitFor(p);
			p.destroy();
			if (isDeleteResult) {
				deleteFile(path);
			}
			return newFilePath;
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		}
	}



	public int doWaitFor(Process p) {
		InputStream in = null;
		InputStream err = null;
		int exitValue = -1;
		try {
			in = p.getInputStream();
			err = p.getErrorStream();
			boolean finished = false;

			while (!finished) {
				try {
					while (in.available() > 0) {
						in.read();
					}
					while (err.available() > 0) {
						err.read();
					}

//					exitValue = p.exitValue();
					finished = true;

				} catch (IllegalThreadStateException e) {
					Thread.sleep(500);
				}
			}
		} catch (Exception e) {
			logger.error("doWaitFor();: unexpected exception - " + e.getMessage());
		} finally {
			try {
				if (in != null) {
					in.close();
				}

			} catch (IOException e) {
				logger.info(e.getMessage());
			}
			if (err != null) {
				try {
					err.close();
				} catch (IOException e) {
					logger.info(e.getMessage());
				}
			}
		}
		return exitValue;
	}
	/**
	 * 保存视频缩略图
	 * @throws IOException
	 */
	public static void saveVideoThumbnail(String ffmpegPath,String videoPath, String imagePath) {
		try{
			//ffmpeg -i xxx.mp4 -y -f image2 -t 0.001 -s 125x125 xxx.jpg
			List<String> cmd = new java.util.ArrayList<String>();
//            cmd.add("ffmpeg");// 视频提取工具的位置
			cmd.add(ffmpegPath + "ffmpeg");// 视频提取工具的位置
			cmd.add("-i");
			cmd.add(videoPath);
			cmd.add("-y");
			cmd.add("-f");
			cmd.add("image2");
			cmd.add("-t");
			cmd.add("0.001");
			cmd.add("-s");
			cmd.add("125x125");
			cmd.add(imagePath);
//            ProcessBuilder builder = new ProcessBuilder();
//            builder.command(cmd);
//            builder.start();
			// 方案2
			Process videoProcess = new ProcessBuilder(cmd).redirectErrorStream(true).start();

			new MgrPrintStream(videoProcess.getErrorStream()).start();

			new MgrPrintStream(videoProcess.getInputStream()).start();

			videoProcess.waitFor();


		}catch (Exception e){
			System.out.println("图片转换失败");
		}

	}
	/**
	 * 删除文件方法
	 *
	 * @param filepath
	 */
	public void deleteFile(String filepath) {
		File file = new File(filepath);
		if (file.delete()) {
			logger.info("文件" + filepath + "已删除");
		}
	}

	/**
	 * 计算转码时间
	 *
	 * @param ms
	 * @return
	 */
	public String sumTime(long ms) {
		int ss = 1000;
		long mi = ss * 60;
		long hh = mi * 60;
		long dd = hh * 24;

		long day = ms / dd;
		long hour = (ms - day * dd) / hh;
		long minute = (ms - day * dd - hour * hh) / mi;
		long second = (ms - day * dd - hour * hh - minute * mi) / ss;
		long milliSecond = ms - day * dd - hour * hh - minute * mi - second
				* ss;

		String strDay = day < 10 ? "0" + day + "天" : "" + day + "天";
		String strHour = hour < 10 ? "0" + hour + "小时" : "" + hour + "小时";
		String strMinute = minute < 10 ? "0" + minute + "分" : "" + minute + "分";
		String strSecond = second < 10 ? "0" + second + "秒" : "" + second + "秒";
		String strMilliSecond = milliSecond < 10 ? "0" + milliSecond : ""
				+ milliSecond;
		strMilliSecond = milliSecond < 100 ? "0" + strMilliSecond + "毫秒" : ""
				+ strMilliSecond + " 毫秒";
		return strDay + " " + strHour + ":" + strMinute + ":" + strSecond + " "
				+ strMilliSecond;

	}
}

MgrPrintStream

package com.haoyu.framework.modules.file.utils;

public class MgrPrintStream extends Thread
{
    java.io.InputStream __is = null;
    public MgrPrintStream(java.io.InputStream is)
    {
        __is = is;
    }

    public void run()
    {
        try
        {
            while(this != null)
            {
                int _ch = __is.read();
                if(_ch != -1)
                    System.out.print((char)_ch);
                else break;
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

MgrPrintStream 的使用参考的是

https://blog.csdn.net/qq_32230309/article/details/78875607

中的PrintStream,改了个名字改成MgrPrintStream(因为spring里已经有PrintStream了)

测试类

@Slf4j
public class myTest {

    @Test
    public void test4(){
        ConverVideoUtils converVideoUtils = new ConverVideoUtils();
        // 转视频
        converVideoUtils.beginConver("E:\\testfile\\test_vedio.mp4");
//       获取视频的第一张缩略图
        converVideoUtils.saveVideoThumbnail("E:\\ffmpeg-20171225-be2da4c-win64-static\\bin\\","E:\\testfile\\test_vedio.mp4","E:\\testzhuanma\\cc.jpeg");
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值