package com.iden.common.util; import com.iden.common.enums.TimeoutOption; import net.bramp.ffmpeg.FFmpeg; import net.bramp.ffmpeg.FFmpegExecutor; import net.bramp.ffmpeg.FFprobe; import net.bramp.ffmpeg.builder.FFmpegBuilder; import org.bytedeco.javacpp.avcodec; import org.bytedeco.javacv.*; import org.bytedeco.javacv.Frame; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.util.*; import java.util.List; /** * 视频工具 * * @author */ public class VideoUtil { private static final int SECOND = 50; private static final Logger logger = LoggerFactory.getLogger(VideoUtil.class); /** * 获取指定视频的帧并保存为图片至指定目录 * * @param videoFile 源视频文件 * @param saveFile 截取帧的图片存放路径 * @throws Exception */ public static List fetchPic(File videoFile, String saveFile, int second) throws Exception { java.util.List files = new ArrayList<>(); FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile); ff.start(); int lenght = ff.getLengthInAudioFrames(); System.out.println(ff.getFrameRate()); int i = 0; Frame frame = null; while (i < lenght) { // 过滤前5帧,避免出现全黑的图片,依自己情况而定 frame = ff.grabImage(); if (i >= (int) (ff.getFrameRate() * second) && frame.image != null) { System.out.print(i + ","); if (frame != null && frame.image != null) { System.out.println(i); String fileName = String.valueOf(System.currentTimeMillis()) + i; files.add(writeToFile(frame, saveFile, fileName)); } second++; } i += second; } ff.stop(); return files; } private static List getList(int count, int length) { if (count > length) { count = length; } // System.out.println(length); // System.out.println(count); int total = (int) (length / count); List list = new ArrayList<>(); for (int i = 0; i < count; i++) { list.add(i * total); System.out.println(i * total); } return list; } public static List fetchPicByCount(File videoFile, String saveDir, int count) throws Exception { java.util.List files = new ArrayList<>(); FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile); ff.start(); // 此视频时长(s/秒) Long duration = ff.getLengthInTime() / (1000 * 1000); System.out.println("duration==" + duration); // 视频总帧数 int frameLength = ff.getLengthInFrames(); System.out.println("length==" + frameLength); List list = getList(count, frameLength); System.out.println("ff.getFrameRate() == " + ff.getFrameRate()); int i = 0; Frame frame = null; while (i < frameLength) { frame = ff.grabImage(); if (list.contains(i)) { if (frame != null && frame.image != null) { System.out.println(i); String fileName = String.valueOf(System.currentTimeMillis()) + i; files.add(writeToFile(frame, saveDir, fileName)); } } i++; } ff.stop(); return files; } public static Long fetchAllPic(File videoFile, String saveDir, Date shootEndTime) throws Exception { Long endTime = shootEndTime.getTime() ; java.util.List files = new ArrayList<>(); FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile); ff.start(); // 此视频时长(ms/毫秒秒) Long duration = ff.getLengthInTime() / 1000; System.out.println("duration==" + duration); Long beginTime = endTime - duration; // 视频总帧数 int frameLength = ff.getLengthInFrames(); System.out.println("length==" + frameLength); //帧率(1秒多少帧) double framRate = ff.getFrameRate(); int i = 0; Frame frame = null; while (i < frameLength) { frame = ff.grabImage(); if (frame != null && frame.image != null) { Double time = beginTime + (i * (1000/framRate)); String fileName = DateUtils.formatToDateStr(new Date(time.longValue()),"yyyyMMddHHmmss") + "_" + UUID.randomUUID().toString(); files.add(writeToFile(frame, saveDir, fileName)); } i++; } ff.stop(); return duration; } private static File writeToFile(Frame frame, String saveDir, String fileName) throws Exception { File saveDirFile = new File(saveDir); if(!saveDirFile.exists()) { saveDirFile.mkdirs(); } File targetFile = new File(saveDir + File.separator + fileName + ".jpg"); String imgSuffix = "jpg"; Java2DFrameConverter converter = new Java2DFrameConverter(); BufferedImage srcBi = converter.getBufferedImage(frame); int owidth = srcBi.getWidth(); int oheight = srcBi.getHeight(); // 对截取的帧进行等比例缩放 int width = 800; int height = (int) (((double) width / owidth) * oheight); BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); bi.getGraphics().drawImage(srcBi.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null); try { ImageIO.write(bi, imgSuffix, targetFile); } catch (Exception e) { throw new Exception( "截帧失败"); } return targetFile; } /** * 获取视频时长,单位为秒 * * @param file * @return 时长(s) */ public static Long getVideoTime(File file) { Long times = 0L; try { FFmpegFrameGrabber ff = new FFmpegFrameGrabber(file); ff.start(); times = ff.getLengthInTime() / (1000 * 1000); ff.stop(); } catch (Exception e) { e.printStackTrace(); } return times; } /** * 视频截取 * @param videoFile * @throws Exception */ public static void cut(File videoFile, File outputFile) throws Exception{ boolean isStart = true;// 该变量建议设置为全局控制变量,用于控制录制结束 FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoFile); // // 微秒 大概为设置时间的两倍 // grabber.setOption(TimeoutOption.RW_TIMEOUT.getKey(), "10000000"); // rtsp 默认udp 丢包 改为tcp // grabber.setOption("rtsp_transport", "tcp"); grabber.start(); //好多视频熟悉可以获取后打印 示例几个 System.out.println("ImageWidth:" + grabber.getImageWidth()); System.out.println("ImageHeight:" + grabber.getImageHeight()); System.out.println("AudioChannels:" + grabber.getAudioChannels()); System.out.println("Format:" + grabber.getFormat()); FrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(), grabber.getImageHeight(),grabber.getAudioChannels()); recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // avcodec.AV_CODEC_ID_H264,编码 recorder.setFormat("flv");//封装格式,如果是推送到rtmp就必须是flv封装格式 recorder.setFrameRate( grabber.getFrameRate()); recorder.start();//开启录制器 long startTime=0; long videoTS=0; CanvasFrame frame = new CanvasFrame("camera", CanvasFrame.getDefaultGamma() / grabber.getGamma()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setAlwaysOnTop(true); Frame rotatedFrame= null; while (frame.isVisible() && (rotatedFrame = grabber.grabFrame()) != null) { rotatedFrame = grabber.grabFrame(); frame.showImage(rotatedFrame); if (startTime == 0) { startTime = System.currentTimeMillis(); } videoTS = 1000 * (System.currentTimeMillis() - startTime); recorder.setTimestamp(videoTS); recorder.record(rotatedFrame); Thread.sleep(40); } frame.dispose(); recorder.stop(); recorder.release(); grabber.stop(); } /** * 视频截取 * @param videoFile * @throws Exception */ public static void cut2(File videoFile, File outputFile) throws Exception{ boolean isStart = true;// 该变量建议设置为全局控制变量,用于控制录制结束 FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoFile); // // 微秒 大概为设置时间的两倍 // grabber.setOption(TimeoutOption.RW_TIMEOUT.getKey(), "10000000"); // rtsp 默认udp 丢包 改为tcp // grabber.setOption("rtsp_transport", "tcp"); grabber.start(); //好多视频熟悉可以获取后打印 示例几个 System.out.println("ImageWidth:" + grabber.getImageWidth()); System.out.println("ImageHeight:" + grabber.getImageHeight()); System.out.println("AudioChannels:" + grabber.getAudioChannels()); System.out.println("Format:" + grabber.getFormat()); FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(), grabber.getImageHeight(),grabber.getAudioChannels()); recorder.setFrameRate(grabber.getFrameRate()); recorder.setAudioBitrate(grabber.getAudioBitrate()); recorder.setSampleRate(grabber.getSampleRate()); // recorder.setGopSize(2); recorder.setFormat("mp4"); recorder.setAudioCodecName("aac"); recorder.setVideoCodec(grabber.getVideoCodec()); recorder.start(); Frame frame = null; //如果想截取规定时间段视频 请看系列文章二 while (isStart) { frame = grabber.grabFrame(); if(frame != null){ recorder.record(frame); } } recorder.stop(); recorder.release(); grabber.stop(); grabber.release(); } public void cut3() throws Exception{ FFmpeg ffmpeg = new FFmpeg("/path/to/ffmpeg"); FFprobe ffprobe = new FFprobe("/path/to/ffprobe"); FFmpegBuilder builder = new FFmpegBuilder() .setInput("input.mp4") // Filename, or a FFmpegProbeResult .overrideOutputFiles(true) // Override the output if it exists .addOutput("output.mp4") // Filename for the destination .setFormat("mp4") // Format is inferred from filename, or can be set .setTargetSize(250_000) // Aim for a 250KB file .disableSubtitle() // No subtiles .setAudioChannels(1) // Mono audio .setAudioCodec("aac") // using the aac codec .setAudioSampleRate(48_000) // at 48KHz .setAudioBitRate(32768) // at 32 kbit/s .setVideoCodec("libx264") // Video using x264 .setVideoFrameRate(24, 1) // at 24 frames per second .setVideoResolution(640, 480) // at 640x480 resolution .setStrict(FFmpegBuilder.Strict.EXPERIMENTAL) // Allow FFmpeg to use experimental specs .done(); FFmpegExecutor executor = new FFmpegExecutor(ffmpeg, ffprobe); // Run a one-pass encode executor.createJob(builder).run(); // Or run a two-pass encode (which is better quality at the cost of being slower) executor.createTwoPassJob(builder).run(); } public static void main(String[] args) { try { //getList(10,113); File file = new File("e:/20211223123223_76639ced-6400-11ec-b8f9-fa163e4e1e9f.mp4"); // List files = VideoUtil.fetchPicByCount(file, "E:/223", 100); // System.out.println(files.get(0).getName()); // System.out.println(VideoUtil.getVideoTime(file)); Date shootEndTime = DateUtils.strToDate("20211223123223","yyyyMMddHHmmss"); // fetchAllPic(file,"E:/223",shootEndTime); // cut3(file,new File("e:/a.mp4")); } catch (Exception e) { e.printStackTrace(); } } }