使用JavaCV对视频截取图片,生成视频JPG封面图和GIF动态图(可以兼容windows和linux,无需安装ffmpeg软件)...

首先要是Maven项目,然后导入JavaCV的相关jar包,即在pom.xml文件加入以下配置:

<dependency>
	<groupId>org.bytedeco</groupId>
	<artifactId>javacpp</artifactId>
	<version>1.4.1</version>
</dependency>

<dependency>
	<groupId>org.bytedeco</groupId>
	<artifactId>javacv</artifactId>
	<version>1.4.1</version>
</dependency>

<dependency>
	<groupId>org.bytedeco.javacpp-presets</groupId>
	<artifactId>opencv-platform</artifactId>
	<version>3.4.1-1.4.1</version>
</dependency>

<dependency>
	<groupId>org.bytedeco.javacpp-presets</groupId>
	<artifactId>ffmpeg-platform</artifactId>
	<version>3.4.2-1.4.1</version>
</dependency>

封装好的工具类 (JavacvUtils):

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;

import javax.imageio.ImageIO;

import org.apache.commons.io.FileUtils;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacpp.opencv_core.IplImage;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber.Exception;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.utils.gif.AnimatedGifEncoder;

public class JavacvUtils {

	private static final Logger log = LoggerFactory.getLogger(JavacvUtils.class);

	private static final String IMAGEMAT = "jpg";

	private static final String ROTATE = "rotate";

	private static final Integer GIF_FRAME_NUMBER = 3;

	private static final Integer GIF_FRAME_INTERVAL = 50;

	public static void main(String[] args) throws Exception {
		makePicFromVideo("C:/Users/admin/Desktop/VID_20180605_165453.mp4", "d://test2.jpg");
		makeGifFromVideo("C:/Users/admin/Desktop/VID_20180605_165453.mp4", "d://test2.gif");
	}

	public static void makeGifFromVideo(String filePath, String targetPath) throws Exception {
		String picList[] = new String[GIF_FRAME_NUMBER];

		int index = targetPath.lastIndexOf(".");
		String prefix = targetPath.substring(0, index);

		// 生成多个图片
		for (int i = 0; i < GIF_FRAME_NUMBER; i++) {
			String temTargetPath = prefix + "_" + i + "." + IMAGEMAT;
			picList[i] = temTargetPath;
		}

		FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
		ff.start();

		String rotate = ff.getVideoMetadata(ROTATE);
		double ffLength = getDivideValue(ff.getLengthInTime(), 1000000);
		log.info("视频旋转度:" + rotate + " 视频时长:" + ffLength);

		int frameLength = ff.getLengthInFrames();
		int j = 0;

		for (int i = 0; i < frameLength && j < GIF_FRAME_NUMBER; i++) {
			if (i % GIF_FRAME_INTERVAL == 0) {
				Frame f = ff.grabImage();
				OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
				IplImage src = converter.convert(f);

				if (null != rotate && rotate.length() > 1) {
					f = converter.convert(rotate(src, Integer.valueOf(rotate)));
				}

				makePicFormFrame(f, picList[j]);
				j++;
			}
		}

		ff.stop();

		// 合并为一个图片
		jpgToGif(picList, targetPath);

		// 删除之前的图片
		for (int i = 0; i < GIF_FRAME_NUMBER; i++) {
			FileUtils.deleteQuietly(new File(picList[i]));
		}
	}

	/**
	 * 将多个jpg图片合并为一个gif图片
	 * 
	 */
	private static void jpgToGif(String pic[], String newPic) {
		AnimatedGifEncoder encoder = new AnimatedGifEncoder();
		encoder.setRepeat(0);
		encoder.start(newPic);
		BufferedImage src[] = new BufferedImage[pic.length];
		for (int i = 0; i < src.length; i++) {
			encoder.setDelay(200); // 设置播放的延迟时间
			try {
				src[i] = ImageIO.read(new File(pic[i]));
			} catch (IOException e) {
				log.error("图片读取异常", e);
			} // 读入需要播放的jpg文件
			encoder.addFrame(src[i]); // 添加到帧中
		}
		encoder.finish();
	}

	public static void makePicFromVideo(String filePath, String targetPath) throws Exception {
		FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
		ff.start();

		String rotate = ff.getVideoMetadata(ROTATE);
		double ffLength = getDivideValue(ff.getLengthInTime(), 1000000);
		log.info("视频旋转度:" + rotate + " 视频时长:" + ffLength);

		Frame f = ff.grabImage();
		OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
		IplImage src = converter.convert(f);

		if (null != rotate && rotate.length() > 1) {
			f = converter.convert(rotate(src, Integer.valueOf(rotate)));
		}

		makePicFormFrame(f, targetPath);
		ff.stop();
	}

	/**
	 * 旋转图片
	 * 
	 */
	public static IplImage rotate(IplImage src, int angle) {
		IplImage img = IplImage.create(src.height(), src.width(), src.depth(), src.nChannels());
		opencv_core.cvTranspose(src, img);
		opencv_core.cvFlip(img, img, angle);
		return img;
	}

	/**
	 * 生成缩略图
	 * 
	 */
	public static void makePicFormFrame(Frame f, String targetPath) {
		if (null == f || null == f.image) {
			return;
		}

		Java2DFrameConverter converter = new Java2DFrameConverter();
		BufferedImage bi = converter.getBufferedImage(f);

		BufferedImage newbi = scaleImage(bi, 800, 800, IMAGEMAT);

		File output = new File(targetPath);
		try {
			ImageIO.write(newbi, IMAGEMAT, output);
		} catch (IOException e) {
			log.error("生成缩略图失败", e);
		}
	}

	/**
	 * 根据比例处理图片
	 * 
	 */
	public static BufferedImage scaleImage(BufferedImage bufferedImage, int width, int height, String format) {
		ArrayList<Integer> paramsArrayList = getAutoWidthAndHeight(bufferedImage, width, height);
		width = paramsArrayList.get(0);
		height = paramsArrayList.get(1);
		log.info("自动调整比例,width=" + width + " height=" + height);

		Image image = bufferedImage.getScaledInstance(width, height, Image.SCALE_DEFAULT);
		BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Graphics graphics = outputImage.getGraphics();
		graphics.drawImage(image, 0, 0, null);
		graphics.dispose();
		return outputImage;
	}

	/***
	 * @param bufferedImage
	 *            要缩放的图片对象
	 * @param widthScale
	 *            要缩放到的宽度
	 * @param heightScale
	 *            要缩放到的高度
	 * @return 一个集合,第一个元素为宽度,第二个元素为高度
	 * 
	 */
	private static ArrayList<Integer> getAutoWidthAndHeight(BufferedImage bufferedImage, int widthScale,
			int heightScale) {
		ArrayList<Integer> arrayList = new ArrayList<Integer>();
		int width = bufferedImage.getWidth();
		int height = bufferedImage.getHeight();
		double scaleW = getDivideValue(widthScale, width);
		double scaleH = getDivideValue(heightScale, height);

		if (scaleW < scaleH) {
			arrayList.add(parseDoubleToInt(scaleW * width));
			arrayList.add(parseDoubleToInt(scaleW * height));
		} else {
			arrayList.add(parseDoubleToInt(scaleH * width));
			arrayList.add(parseDoubleToInt(scaleH * height));
		}
		return arrayList;

	}

	/**
	 * 将double类型的数据转换为int
	 * 
	 */
	private static int parseDoubleToInt(double sourceDouble) {
		return (int) sourceDouble;
	}

	/**
	 * 获取两数相除的结果,保留两位小数
	 * 
	 */
	public static double getDivideValue(int num1, int num2) {
		BigDecimal bigDecimal1 = new BigDecimal(num1);
		BigDecimal bigDecimal2 = new BigDecimal(num2);
		BigDecimal result = bigDecimal1.divide(bigDecimal2, 2, BigDecimal.ROUND_HALF_UP);
		return result.doubleValue();
	}

	/**
	 * 获取两数相除的结果,保留两位小数
	 * 
	 */
	public static double getDivideValue(long num1, long num2) {
		BigDecimal bigDecimal1 = new BigDecimal(num1);
		BigDecimal bigDecimal2 = new BigDecimal(num2);
		BigDecimal result = bigDecimal1.divide(bigDecimal2, 2, BigDecimal.ROUND_HALF_UP);
		return result.doubleValue();
	}

}

将多个图片制作为gif图片,需要用的工具类(AnimatedGifEncoder、LZWEncoder、NeuQuant):

package com.utils.gif;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.BufferedOutput
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值