用Java代码提取视频的缩略图的两种办法

用Java代码提取视频的缩略图的两种办法

今天项目中有个需求,让在后台用Java提取每一个视频的缩略图,然后将图片传给前端页面。在网上搜了一下,发现基本上都是使用ffmpeg工具来进行视频格式转换和提取视频缩略图,这个方法的好处在于代码简单易懂且运行速度快,缺点在于对于已上线的项目来说,在服务器上更新代码时需要装ffmpeg工具,比较麻烦。还有一种方法是使用Javacv来提取视频某些帧的图片并进行保存,此方法的好处在于只用导入Javacv相关的架包而不用安装工具,缺点在于代码稍显复杂且很容易因为几个架包的版本问题而导致编译不通过或者抛classNotFound异常(这个问题困扰了我一下午,下面我会给出解决方案)而且运行速度较慢(测了几个帧都在5秒左右)。下面就是两个方案的具体实现。
一、使用ffmpeg工具:
ffmpeg是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量。
首先要下载ffmpeg工具,下载地址:https://ffmpeg.zeranoe.com/builds/,然后把该文件到bin目录的路径加到环境变量的Path中。
然后就编写如下代码:
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void handler(String ffmpegPath,String upFilePath,String mediaPicPath){
List cutpic = new ArrayList();
cutpic.add(ffmpegPath); // 视频提取工具的位置
cutpic.add(“-i”); // 添加参数"-i",该参数指定要转换的文件
cutpic.add(upFilePath); // 视频文件路径
cutpic.add(“-y”);
cutpic.add(“-f”);
cutpic.add(“image2”);
cutpic.add(“-ss”); // 添加参数"-ss",该参数指定截取的起始时间
cutpic.add(“1”); // 添加起始时间为第1秒
cutpic.add(“-t”); // 添加参数"-t",该参数指定持续时间
cutpic.add(“0.001”); // 添加持续时间为1毫秒
cutpic.add(“-s”); // 添加参数"-s",该参数指定截取的图片大小
cutpic.add(“800*600”); // 添加截取的图片大小为800*600
cutpic.add(mediaPicPath); // 添加截取的图片的保存路径

        boolean mark = true;  
        ProcessBuilder builder = new ProcessBuilder();  
        try {  

            builder.command(cutpic);  
            builder.redirectErrorStream(true);  
            // 如果此属性为 true,则任何由通过此对象的 start() 方法启动的后续子进程生成的错误输出都将与标准输出合并,  
            //因此两者均可使用 Process.getInputStream() 方法读取。这使得关联错误消息和相应的输出变得更容易  
            builder.start();  
        } catch (Exception e) {  
            mark = false;  
            System.out.println(e);  
            e.printStackTrace();  
        }  
     }  

      public static void main(String[] args){  
       handler("D:/ffmpeg-20170811-5859b5b-win64-static/bin/ffmpeg.exe","http://wemewtest.oss-cn-qingdao.aliyuncs.com/2017-06-08-14/wKPPSfepDZ.mp4","D:/new/test7.jpg");  
      } 

}
了解更多ffmpeg内容可以参照:http://www.tuicool.com/articles/fMRRZvY
二、使用Javacv
一开始我手动导的架包,如下:
用Java代码提取视频的缩略图的两种办法_第1张图片
有可能是架包版本问题,一直抛classNotFound异常,怎么试都不行,后面我新建了一个项目,用mawen进行自动导包,马上就解决了,看图
用Java代码提取视频的缩略图的两种办法_第2张图片
只用在pom.xml配置依赖

   
        org.bytedeco
        javacv
        0.8
    

导入0.8版本的javacv就行,mawen会自动将相关的架包导进来。下面是代码:
package com.aliyun.mts;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import org.bytedeco.javacpp.opencv_core.IplImage;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
public class Test {

/**
 * 获取指定视频的帧并保存为图片至指定目录
 * @param videofile  源视频文件路径
 * @param framefile  截取帧的图片存放路径
 * @throws Exception
 */
public static void fetchFrame(String videofile, String framefile)
        throws Exception {
    long start = System.currentTimeMillis();
    File targetFile = new File(framefile);
    FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videofile); 
    ff.start();
    int lenght = ff.getLengthInFrames();
    int i = 0;
    Frame f = null;
    while (i < lenght) {
        // 过滤前5帧,避免出现全黑的图片,依自己情况而定
        f = ff.grabFrame();
        if ((i > 5) && (f.image != null)) {
            break;
        }
        i++;
    }
    IplImage img = f.image;
    int owidth = img.width();
    int oheight = img.height();
    // 对截取的帧进行等比例缩放
    int width = 800;
    int height = (int) (((double) width / owidth) * oheight);
    BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
    bi.getGraphics().drawImage(f.image.getBufferedImage().getScaledInstance(width, height, Image.SCALE_SMOOTH),
            0, 0, null);
    ImageIO.write(bi, "jpg", targetFile);
    //ff.flush();
    ff.stop();
    System.out.println(System.currentTimeMillis() - start);
}

public static void main(String[] args) {
    try {
        Test.fetchFrame("http://wemewtest.oss-cn-qingdao.aliyuncs.com/2017-06-08-14/wKPPSfepDZ.mp4", "D:/new/test4.jpg");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

}

你可能感兴趣的:(每天进步一点)