最近有視頻處理的需求,本身調研javaCV。java
官網沒有詳細的API,各類輪子翻遍了也沒找到幾個有用的,如下是本身整理一些視頻處理功能:截取視頻指定幀生成gif,將圖片旋轉指定度,截取視頻指定幀保存爲指定格式的圖片(圖片保存在視頻同文件夾下),調整視頻清晰度(只能下降),視頻轉音頻。apache
先上代碼。canvas
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);
}
}
}
相關依賴: