最近有视频处理的需求,自己调研javaCV。
官网没有详细的API,各种轮子翻遍了也没找到几个有用的,以下是自己整理一些视频处理功能:截取视频指定帧生成gif,将图片旋转指定度,截取视频指定帧保存为指定格式的图片(图片保存在视频同文件夹下),_调整视频清晰度(只能降低),_视频转音频__。
先上代码。
package com.richinfo.media.utils;import com.madgag.gif.fmsware.AnimatedGifEncoder;import org.bytedeco.javacv.FFmpegFrameGrabber;import org.bytedeco.javacv.Frame;import org.bytedeco.javacv.Java2DFrameConverter;import javax.imageio.ImageIO;import java.awt.*;import java.awt.image.BufferedImage;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;/** * @author */public class VideoUtils { /** * 截取视频指定帧生成gif * * @param videofile 视频文件 * @param startFrame 开始帧 * @param frameCount 截取帧数 * @param frameRate 帧频率(默认:3) * @param margin 每截取一次跳过多少帧(默认:3) * @throws java.io.IOException 截取的长度超过视频长度 */ public static void buildGif(String videofile, int startFrame, int frameCount, Integer frameRate, Integer margin) throws IOException { if (margin == null) { margin = 3; } if (frameRate == null) { frameRate = 3; } FileOutputStream targetFile = new FileOutputStream(videofile.substring(0, videofile.lastIndexOf(".")) + ".gif"); FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videofile); Java2DFrameConverter converter = new Java2DFrameConverter(); ff.start(); try { if (startFrame > ff.getLengthInFrames() & (startFrame + frameCount) > ff.getLengthInFrames()) { throw new RuntimeException("视频太短了"); } ff.setFrameNumber(startFrame); AnimatedGifEncoder en = new AnimatedGifEncoder(); en.setFrameRate(frameRate); en.start(targetFile); for (int i = 0; i < frameCount; i++) { en.addFrame(converter.convert(ff.grabImage())); ff.setFrameNumber(ff.getFrameNumber() + margin); } en.finish(); } finally { ff.stop(); ff.close(); } } /** * 将图片旋转指定度 * * @param bufferedimage 图片 * @param degree 旋转角度 * @return */ public static BufferedImage rotateImage(BufferedImage bufferedimage, int degree) { // 得到图片宽度。 int w = bufferedimage.getWidth(); // 得到图片高度。 int h = bufferedimage.getHeight(); // 得到图片透明度。 int type = bufferedimage.getColorModel().getTransparency(); // 空的图片。 BufferedImage img; // 空的画笔。 Graphics2D graphics2d; (graphics2d = (img = new BufferedImage(w, h, type)) .createGraphics()).setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); // 旋转,degree是整型,度数,比如垂直90度。 graphics2d.rotate(Math.toRadians(degree), w / 2, h / 2); // 从bufferedimagecopy图片至img,0,0是img的坐标。 graphics2d.drawImage(bufferedimage, 0, 0, null); graphics2d.dispose(); // 返回复制好的图片,原图片依然没有变,没有旋转,下次还可以使用。 return img; } /** * 截取视频指定帧保存为指定格式的图片(图片保存在视频同文件夹下) * * @param videofile 视频地址 * @param imgSuffix 图片格式 * @param indexFrame 第几帧(默认:5) * @throws Exception */ public static void fetchFrame(String videofile, String imgSuffix, Integer indexFrame) throws Exception { if (indexFrame == null) { indexFrame = 5; } Integer suffixIndex = videofile.lastIndexOf("."); File targetFile = new File((suffixIndex != -1 ? videofile.substring(0, suffixIndex) : videofile) + imgSuffix); try (FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videofile); OutputStream outputStream = new FileOutputStream(targetFile)) { ff.start(); ff.setFrameNumber(indexFrame); Frame f = ff.grabImage(); Java2DFrameConverter converter = new Java2DFrameConverter(); BufferedImage fecthedImage = converter.getBufferedImage(f); ImageIO.write(fecthedImage, "jpg", outputStream); } } public static void main(String[] args) { try { fetchFrame("C:\\Users\\Desktop\\b9aef3a28becab2e9e3c544caf70bfde.mp4", ".jpg", 100); buildGif("C:\\Users\\Desktop\\b9aef3a28becab2e9e3c544caf70bfde.mp4", 50, 10, 3, 50); } catch (Exception e) { e.printStackTrace(); } }}
package com.richinfo.media.utils;import lombok.SneakyThrows;import org.apache.commons.io.IOUtils;import org.bytedeco.javacpp.avcodec;import org.bytedeco.javacv.CanvasFrame;import org.bytedeco.javacv.FFmpegFrameGrabber;import org.bytedeco.javacv.FFmpegFrameRecorder;import org.bytedeco.javacv.Frame;import javax.swing.*;/** * @author * @create */public class Test { private static boolean isStart = true; @SneakyThrows public static void main(String[] args) { frameRecord("C:\\Users\\Desktop\\b9aef3a28becab2e9e3c544caf70bfde.mp4", "C:\\Users\\Desktop\\b9aef3a28becab2e9e3c544caf70bf602.mp4"); } public static void frameRecord(String inputFile, String outputFile) throws Exception, org.bytedeco.javacv.FrameRecorder.Exception { // 获取视频源 FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile); grabber.setOption("rtsp_transport", "tcp");// //速度// grabber.setFrameRate(30);// //码率// grabber.setVideoBitrate(3000000); // 流媒体输出地址,分辨率(长,高),是否录制音频(0:不录制/1:录制) FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, 2);// recorder.setFrameRate(30); recorder.setVideoBitrate(720 * 576); //编码格式 recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); //avcodec.AV_CODEC_ID_H264 //AV_CODEC_ID_MPEG4 recordByFrame(grabber, recorder); } private static void recordByFrame(FFmpegFrameGrabber grabber, FFmpegFrameRecorder recorder) throws Exception, org.bytedeco.javacv.FrameRecorder.Exception { try {// 建议在线程中使用该方法 grabber.start();// CanvasFrame canvas = new CanvasFrame("摄像头");//新建一个窗口// canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// canvas.setAlwaysOnTop(true); recorder.setImageHeight(grabber.getImageHeight()); recorder.setImageWidth(grabber.getImageWidth()); recorder.start(); long t1 = System.currentTimeMillis(); Frame frame = null; while (isStart && (frame = grabber.grabFrame()) != null) { long t2 = System.currentTimeMillis(); if (t2 - t1 > 2 * 60 * 60 * 1000) { break; } else {//视频转音频 grabber.grabSamples(); recorder.record(frame); //TODO your work } //canvas.showImage(grabber.grab());//获取摄像头图像并放到窗口上显示, 这里的Frame frame=grabber.grab(); frame是一帧视频图像 } recorder.stop(); grabber.stop(); } finally { IOUtils.closeQuietly(recorder); IOUtils.closeQuietly(grabber); } }}相关依赖:<!-- 视频截图 --><dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.4.4</version></dependency><!-- gif --><dependency> <groupId>com.madgag</groupId> <artifactId>animated-gif-lib</artifactId> <version>1.4</version></dependency><!--lombok --><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.8</version></dependency>
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version></dependency>