zoukankan      html  css  js  c++  java
  • java 用ffmpeg和mencoder进行视频转码


    1.准备阶段:首先需要ffmpeg.exe和mencoder.exe,java需要调用这两个文件来进行转码。

     

     drv43260.dll,pncrt.dll,pthreadGC2.dll  为动态链接库   必须有 ,否则 rm格式 文件利用mencoder转换avi时会报如下错误

    Opening video decoder: [realvid] RealVideo decoder
    Error loading dll
    ERROR: Could not open required DirectShow codec drvc.so.
    Read the RealVideo section of the DOCS!
    VDecoder init failed :(
    Opening video decoder: [realvid] RealVideo decoder
    Error loading dll
    ERROR: Could not open required DirectShow codec drv4.so.6.0.
    Read the RealVideo section of the DOCS!
    VDecoder init failed :(
    Opening video decoder: [realvid] RealVideo decoder
    Error loading dll
    ERROR: Could not open required DirectShow codec drv43260.dll.
    Read the RealVideo section of the DOCS!
    VDecoder init failed :(
    Opening video decoder: [realvid] RealVideo decoder
    Error loading dll
    ERROR: Could not open required DirectShow codec drvc.bundle/Contents/MacOS/drvc.

    Read the RealVideo section of the DOCS!
    VDecoder init failed :(
    Cannot find codec matching selected -vo and video format 0x30345652.
    Read DOCS/HTML/en/codecs.html!

     --------------------------------------------------------------------------------------------------------------------

    2.编码阶段:

    转码类------FileUploadTools

    package com.test.util;
    
    import it.sauronsoftware.jave.AudioAttributes;
    import it.sauronsoftware.jave.Encoder;
    import it.sauronsoftware.jave.EncoderException;
    import it.sauronsoftware.jave.EncodingAttributes;
    import it.sauronsoftware.jave.InputFormatException;
    import it.sauronsoftware.jave.MultimediaInfo;
    import it.sauronsoftware.jave.VideoAttributes;
    import it.sauronsoftware.jave.VideoSize;
    
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.sql.Timestamp;
    import java.text.DecimalFormat;
    import java.text.SimpleDateFormat;
    import java.util.Arrays;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    import org.apache.commons.fileupload.disk.DiskFileItem;
    import org.apache.http.HttpRequest;
    import org.springframework.web.multipart.MultipartFile;
    import org.springframework.web.multipart.commons.CommonsMultipartFile;
    
    public class FileUploadTool {
    TransfMediaTools transfMediaTools=new TransfMediaTools();
    //文件最大200M
    private static long upload_maxsize=200*1024*1024;
    // 文件允许格式
    private static String[] allowFiles = { ".rar", ".doc", ".docx", ".zip",
    ".pdf", ".txt", ".swf", ".xlsx", ".gif", ".png", ".jpg", ".jpeg",
    ".bmp", ".xls", ".mp4", ".flv", ".ppt", ".avi", ".mpg", ".wmv",
    ".3gp", ".mov", ".asf", ".asx", ".vob", ".wmv9", ".rm", ".rmvb" };
    //视频格式
    private static String[] videoFiles={".swf",".mp4", ".flv",".avi", ".mpg", ".wmv",".3gp", ".mov", ".asf", ".asx", ".vob", ".wmv9", ".rm", ".rmvb"};
    //图片格式
    private static String[] photoFiles={".gif", ".png", ".jpg", ".jpeg",".bmp"};
    // 允许转码的视频格式(ffmpeg)
    private static String[] allowFLV = { ".avi", ".mpg", ".wmv", ".3gp",".mov", ".asf", ".asx", ".vob" ,".mp4"};
    // 允许的视频转码格式(mencoder)
    private static String[] allowAVI = { ".wmv9", ".rm", ".rmvb" };
    //视频时长 秒
    private static int max_time=180;
    
    
    
    public Object createFile(MultipartFile multipartFile,HttpServletRequest request,HttpSession session){
    Map<String, Object> map=new HashMap<String, Object>();
    
    FileEntity entity=new FileEntity();
    boolean bflag=false;
    
    int minute=0;
    int seconde=0;
    int time=0;
    
    String fileName=multipartFile.getOriginalFilename().toString();
    //判断文件不能为空
    if(multipartFile.getSize()!=0 && !multipartFile.isEmpty()){
    bflag=true;
    //判断文件大小
    if(multipartFile.getSize()<=upload_maxsize){
    bflag=true;
    //文件类型判断
    if(this.checkFileType(fileName)){
    bflag=true;
    
    try {
    //获取文件时长
    CommonsMultipartFile cf=(CommonsMultipartFile) multipartFile;
    DiskFileItem fi=(DiskFileItem) cf.getFileItem();
    File source=fi.getStoreLocation();
    Encoder encoder=new Encoder();
    
    MultimediaInfo m=encoder.getInfo(source);
    System.out.println("-------"+m.getDuration());
    long ls=m.getDuration()/1000;
    minute=(int) ((ls%3600)/60);
    seconde=(int)(ls-minute*60);
    time=(int) ls;    
    System.out.println("此视频时长:"+minute+"分"+seconde+"秒, 总时长"+ls+"秒");
    System.out.println("此视频格式:"+m.getFormat());
    } catch (InputFormatException e1) {
    e1.printStackTrace();
    } catch (EncoderException e1) {
    e1.printStackTrace();
    }
    
    if(time<=max_time){
    bflag=true;
    }else{
    bflag=false;
    System.out.println("视频时间过长");
    map.put("code", 0);
    map.put("msg", "视频时间过长");
    }
    }else{
    bflag=false;
    System.out.println("文件类型不允许");
    map.put("code", 0);
    map.put("msg", "文件类型不允许");
    }
    }else{
    bflag=false;
    System.out.println("文件大小超范围");
    map.put("code", 0);
    map.put("msg", "文件大小超范围");
    }
    
    }else{
    bflag=false;
    System.out.println("文件为空");
    map.put("code", 0);
    map.put("msg", "文件为空");
    }
    
    
    if(bflag){
    String path = "F://video/";
    
    // 新的文件名
    String newFileName = this.getName(fileName);
    //文件扩展名
    String fileEnd=this.getFileExt(fileName);
    
    //上传文件夹
    File targetFile = new File(path,newFileName+fileEnd);
    //1.采用transferTo方法 上传文件
    //2.采用流方法上传文件 防止 文件过大 网络连接断开上传失败
    if (!targetFile.exists()) {
    targetFile.mkdirs();
    } 
    try {
    multipartFile.transferTo(targetFile);
    
    //    BufferedOutputStream stream = new BufferedOutputStream(
    // new FileOutputStream(targetFile));
    // int length=0;
    // byte[] buffer = new byte[1024];
    // InputStream inputStream = multipartFile.getInputStream();
    // while ((length = inputStream.read(buffer)) != -1) {
    // stream.write(buffer, 0, length);
    // }
    // 
    // stream.flush();
    // stream.close();
    
    } catch (Exception e) {
    e.printStackTrace();
    }
    
    // 1.边上传 边压缩
    // File yasFile=new File(path+"123.mp4");
    
    // try {
    // // 音频编码设置
    // AudioAttributes audio = new AudioAttributes();
    // audio.setCodec("libmp3lame");
    // audio.setBitRate(new Integer(64000));
    // audio.setChannels(new Integer(1));
    // audio.setSamplingRate(new Integer(22050));
    
    // // 视频编码设置
    // VideoAttributes video = new VideoAttributes();
    // video.setCodec("flv");
    // video.setBitRate(new Integer(160000));
    // video.setFrameRate(new Integer(15));
    // video.setSize(new VideoSize(400, 300));
    
    // // 视频转码编码设置
    // EncodingAttributes attrs = new EncodingAttributes();
    // attrs.setFormat("flv");
    // attrs.setAudioAttributes(audio);
    // attrs.setVideoAttributes(video);
    
    // // 编码器
    // Encoder encoder = new Encoder();
    // encoder.encode(targetFile, yasFile, attrs);
    //
    // System.out.println("压缩完成...");
    // } catch (EncoderException e) {
    // e.printStackTrace();
    //
    // }
    
    
    
    //2. 先上传 后压缩 采用工具压缩
    String name = fileName.substring(0, fileName.lastIndexOf("."));
    //压缩文件夹
    File yasuoFile=new File(path+"yasuo/");
    if(!yasuoFile.exists()){
    yasuoFile.mkdirs();
    }
    
    // 相对路径
    entity.setType(fileEnd);
    String finalFileDir= "/filedizhi/video/yasuo/"+newFileName+fileEnd;
    String size=this.getSize(targetFile);
    String aviPath=targetFile.getAbsolutePath();
    System.out.println("aviPath:"+aviPath);
    
    //转码avi
    if(this.checkAVIType(fileEnd)){
    // 设置转换为AVI格式后文件的保存路径
    String codcAviPath = path +"yasuo/"+ File.separator + newFileName + ".avi";
    System.out.println("codcAviPath:"+codcAviPath);
    // 获取配置的转换工具(mencoder.exe)的存放路径  tools文件夹存放在WebContent下
    String mencoderPath = request.getSession().getServletContext().getRealPath("tools/mencoder.exe");
    aviPath = transfMediaTools.processAVI(mencoderPath, targetFile.getAbsolutePath(), codcAviPath);
    fileEnd = this.getFileExt(codcAviPath);
    }
    
    if(aviPath!=null){
    //转码Flv
    if (this.checkMediaType(fileEnd)) {
    try {
    // 设置转换为flv格式后文件的保存路径
    String codcFilePath = path +"yasuo/"+ File.separator + newFileName + ".flv";
    System.out.println("codcFilePath:"+codcFilePath);
    // 获取配置的转换工具(ffmpeg.exe)的存放路径
    
    String ffmpegPath =request.getSession().getServletContext().getRealPath("tools/ffmpeg.exe");
    transfMediaTools.processFLV(ffmpegPath, aviPath, codcFilePath);
    finalFileDir = "/filedizhi/video/yasuo/" + newFileName + ".flv";
    
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    entity.setSize(size);
    entity.setPath(finalFileDir);
    entity.setTitleOrig(name);
    entity.setTitleAlter(newFileName);
    Timestamp timestamp = new Timestamp(System.currentTimeMillis());
    entity.setUploadTime(timestamp);
    
    map.put("code", 1);
    map.put("msg", "上传成功");
    map.put("data", entity);
    
    return map;
    
    }else{
    return null;
    }
    }else{
    return map;
    }
    }
    
    
    /**
    * 视频文件类型判断
    *
    * @param fileName
    * @return
    */
    private boolean checkFileType(String fileName) {
    Iterator<String> type = Arrays.asList(videoFiles).iterator();
    while (type.hasNext()) {
    String ext = type.next();
    if (fileName.toLowerCase().endsWith(ext)) {
    return true;
    }
    }
    return false;
    }
    /**
    * 图片文件类型判断
    *
    * @param fileName
    * @return
    */
    public boolean checkPhotoFileType(String fileName) {
    Iterator<String> type = Arrays.asList(photoFiles).iterator();
    while (type.hasNext()) {
    String ext = type.next();
    if (fileName.toLowerCase().endsWith(ext)) {
    return true;
    }
    }
    return false;
    }
    
    /**
    * 视频类型判断(flv)
    *
    * @param fileName
    * @return
    */
    private boolean checkMediaType(String fileEnd) {
    Iterator<String> type = Arrays.asList(allowFLV).iterator();
    while (type.hasNext()) {
    String ext = type.next();
    if (fileEnd.equals(ext)) {
    return true;
    }
    }
    return false;
    }
    
    /**
    * 视频类型判断(AVI)
    *
    * @param fileName
    * @return
    */
    private boolean checkAVIType(String fileEnd) {
    Iterator<String> type = Arrays.asList(allowAVI).iterator();
    while (type.hasNext()) {
    String ext = type.next();
    if (fileEnd.equals(ext)) {
    return true;
    }
    }
    return false;
    }
    
    /**
    * 获取文件扩展名
    *
    * @return string
    */
    private String getFileExt(String fileName) {
    return fileName.substring(fileName.lastIndexOf("."));
    }
    
    /**
    * 依据原始文件名生成新文件名
    * @return
    */
    private String getName(String fileName) {
    Date date = new Date();
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HH~mm~ss");
    Iterator<String> type = Arrays.asList(allowFiles).iterator();
    while (type.hasNext()) {
    String ext = type.next();
    if (fileName.contains(ext)) {
    String newFileName = formatter.format(date) + "_" + stringfilString(fileName.substring(0, fileName.lastIndexOf(ext)));
    return newFileName;
    }
    }
    return "";
    }
    
    public static String stringfilString(String str){
    // 只允许字母和数字 // String regEx = "[^a-zA-Z0-9]";
    // 清除掉所有特殊字符
    String regEx = "[`~!@#$%^&*()+=|{}':;',\[\]<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]";
    Pattern p = Pattern.compile(regEx);
    Matcher m = p.matcher(str);
    return filterChinese(m.replaceAll("").trim());
    }
    public static String filterChinese(String chin){    
    return chin.replaceAll("[\u4e00-\u9fa5]", "");
    }
    
    /**
    * 文件大小,返回kb.mb
    *
    * @return
    */
    private String getSize(File file) {
    String size = "";
    long fileLength = file.length();
    DecimalFormat df = new DecimalFormat("#.00");
    if (fileLength < 1024) {
    size = df.format((double) fileLength) + "BT";
    } else if (fileLength < 1048576) {
    size = df.format((double) fileLength / 1024) + "KB";
    } else if (fileLength < 1073741824) {
    size = df.format((double) fileLength / 1048576) + "MB";
    } else {
    size = df.format((double) fileLength / 1073741824) + "GB";
    }
    return size;
    }
    
    
    }

    3.实体类

    public class FileEntity {
    private String type;
    private String size;
    private String path;
    private String titleOrig;
    private String titleAlter;
    private Timestamp uploadTime;
    public String getType() {
    return type;
    }
    public void setType(String type) {
    this.type = type;
    }
    public String getSize() {
    return size;
    }
    public void setSize(String size) {
    this.size = size;
    }
    public String getPath() {
    return path;
    }
    public void setPath(String path) {
    this.path = path;
    }
    public String getTitleOrig() {
    return titleOrig;
    }
    public void setTitleOrig(String titleOrig) {
    this.titleOrig = titleOrig;
    }
    public String getTitleAlter() {
    return titleAlter;
    }
    public void setTitleAlter(String titleAlter) {
    this.titleAlter = titleAlter;
    }
    public Timestamp getUploadTime() {
    return uploadTime;
    }
    public void setUploadTime(Timestamp uploadTime) {
    this.uploadTime = uploadTime;
    }
    }

    4.设置编码格式

    package com.test.util;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;
    
    public class TransfMediaTools {
    
    /**
    * 视频转码flv
    *
    * @param ffmpegPath
    * 转码工具的存放路径
    * @param upFilePath
    * 用于指定要转换格式的文件,要截图的视频源文件
    * @param codcFilePath
    * 格式转换后的的文件保存路径
    * @return
    * @throws Exception
    */
    public void processFLV(String ffmpegPath, String upFilePath, String codcFilePath) {
    // 创建一个List集合来保存转换视频文件为flv格式的命令
    List<String> convert = new ArrayList<String>();
    convert.add(ffmpegPath); // 添加转换工具路径
    convert.add("-i"); // 添加参数"-i",该参数指定要转换的文件
    convert.add(upFilePath); // 添加要转换格式的视频文件的路径
    convert.add("-ab");
    convert.add("56");
    convert.add("-ar");
    convert.add("22050");
    convert.add("-q:a");
    convert.add("8");
    convert.add("-r");
    convert.add("15");
    convert.add("-s");
    convert.add("600*500");
    
    /*
    * convert.add("-qscale"); // 指定转换的质量 convert.add("6");
    * convert.add("-ab"); // 设置音频码率 convert.add("64"); convert.add("-ac");
    * // 设置声道数 convert.add("2"); convert.add("-ar"); // 设置声音的采样频率
    * convert.add("22050"); convert.add("-r"); // 设置帧频 convert.add("24");
    * convert.add("-y"); // 添加参数"-y",该参数指定将覆盖已存在的文件
    */
    convert.add(codcFilePath);
    try {
    Process videoProcess = new ProcessBuilder(convert).redirectErrorStream(true).start();
    new PrintStream(videoProcess.getInputStream()).start();
    videoProcess.waitFor();
    } catch (IOException e1) {
    e1.printStackTrace();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    
    /**
    * 对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等), 先用mencoder转换为avi(ffmpeg能解析的)格式
    *
    * @param mencoderPath
    * 转码工具的存放路径
    * @param upFilePath
    * 用于指定要转换格式的文件,要截图的视频源文件
    * @param codcFilePath
    * 格式转换后的的文件保存路径
    * @return
    * @throws Exception
    */
    public String processAVI(String mencoderPath, String upFilePath, String codcAviPath) {
    // boolean flag = false;
    List<String> commend = new ArrayList<String>();
    commend.add(mencoderPath);
    commend.add(upFilePath);
    commend.add("-oac");
    commend.add("mp3lame");
    // commend.add("lavc");
    commend.add("-lameopts");
    commend.add("preset=64");
    commend.add("-lavcopts");
    commend.add("acodec=mp3:abitrate=64");
    commend.add("-ovc");
    commend.add("xvid");
    commend.add("-xvidencopts");
    commend.add("bitrate=600");
    commend.add("-of");
    commend.add("avi");
    commend.add("-o");
    commend.add(codcAviPath);
    try {
    // 预处理进程
    ProcessBuilder builder = new ProcessBuilder();
    builder.command(commend);
    builder.redirectErrorStream(true);
    
    // 进程信息输出到控制台
    Process p = builder.start();
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
    String line = null;
    while ((line = br.readLine()) != null) {
    System.out.println(line);
    }
    p.waitFor();// 直到上面的命令执行完,才向下执行
    return codcAviPath;
    } catch (Exception e) {
    e.printStackTrace();
    return null;
    }
    }
    
    }
    
    class PrintStream extends Thread {
    java.io.InputStream __is = null;
    
    public PrintStream(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();
    }
    }
    
    }

    5.调用接口上传

    /**
    * 上传视频
    * @param file
    * @param request
    * @param model
    * @param session
    * @param response
    * @return
    */
    @RequestMapping("/uploadflv")
    @ResponseBody
    public Object uploadflv(@RequestParam("file") MultipartFile file, HttpServletRequest request, Model model, HttpSession session, HttpServletResponse response){
    FileUploadTool fileUploadTool=new FileUploadTool();
    Object map=fileUploadTool.createFile(file, request, session);
    
    return map;
    
    }



    本文来自博客园,作者:Forever丶随风,转载请注明原文链接:https://www.cnblogs.com/Forever-wind/p/11730874.html

  • 相关阅读:
    《软件项目成功之道》阅读笔记02
    每日日报47
    每日日报46
    每日日报45
    WAMPSERVER打开phpmyadmin时遇到404错误——解决办法
    每日日报44
    每日日报43
    简单的利用Layui来实现登录功能
    01函数式编程概念
    03适配器模式
  • 原文地址:https://www.cnblogs.com/Forever-wind/p/11730874.html
Copyright © 2011-2022 走看看