VideoUtil.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. package com.iden.common.util;
  2. import com.iden.common.enums.TimeoutOption;
  3. import net.bramp.ffmpeg.FFmpeg;
  4. import net.bramp.ffmpeg.FFmpegExecutor;
  5. import net.bramp.ffmpeg.FFprobe;
  6. import net.bramp.ffmpeg.builder.FFmpegBuilder;
  7. import org.bytedeco.javacpp.avcodec;
  8. import org.bytedeco.javacv.*;
  9. import org.bytedeco.javacv.Frame;
  10. import org.slf4j.Logger;
  11. import org.slf4j.LoggerFactory;
  12. import javax.imageio.ImageIO;
  13. import javax.swing.*;
  14. import java.awt.*;
  15. import java.awt.image.BufferedImage;
  16. import java.io.File;
  17. import java.util.*;
  18. import java.util.List;
  19. /**
  20. * 视频工具
  21. *
  22. * @author
  23. */
  24. public class VideoUtil {
  25. private static final int SECOND = 50;
  26. private static final Logger logger = LoggerFactory.getLogger(VideoUtil.class);
  27. /**
  28. * 获取指定视频的帧并保存为图片至指定目录
  29. *
  30. * @param videoFile 源视频文件
  31. * @param saveFile 截取帧的图片存放路径
  32. * @throws Exception
  33. */
  34. public static List<File> fetchPic(File videoFile, String saveFile, int second) throws Exception {
  35. java.util.List<File> files = new ArrayList<>();
  36. FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile);
  37. ff.start();
  38. int lenght = ff.getLengthInAudioFrames();
  39. System.out.println(ff.getFrameRate());
  40. int i = 0;
  41. Frame frame = null;
  42. while (i < lenght) {
  43. // 过滤前5帧,避免出现全黑的图片,依自己情况而定
  44. frame = ff.grabImage();
  45. if (i >= (int) (ff.getFrameRate() * second) && frame.image != null) {
  46. System.out.print(i + ",");
  47. if (frame != null && frame.image != null) {
  48. System.out.println(i);
  49. String fileName = String.valueOf(System.currentTimeMillis()) + i;
  50. files.add(writeToFile(frame, saveFile, fileName));
  51. }
  52. second++;
  53. }
  54. i += second;
  55. }
  56. ff.stop();
  57. return files;
  58. }
  59. private static List<Integer> getList(int count, int length) {
  60. if (count > length) {
  61. count = length;
  62. }
  63. // System.out.println(length);
  64. // System.out.println(count);
  65. int total = (int) (length / count);
  66. List<Integer> list = new ArrayList<>();
  67. for (int i = 0; i < count; i++) {
  68. list.add(i * total);
  69. System.out.println(i * total);
  70. }
  71. return list;
  72. }
  73. public static List<File> fetchPicByCount(File videoFile, String saveDir, int count) throws Exception {
  74. java.util.List<File> files = new ArrayList<>();
  75. FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile);
  76. ff.start();
  77. // 此视频时长(s/秒)
  78. Long duration = ff.getLengthInTime() / (1000 * 1000);
  79. System.out.println("duration==" + duration);
  80. // 视频总帧数
  81. int frameLength = ff.getLengthInFrames();
  82. System.out.println("length==" + frameLength);
  83. List<Integer> list = getList(count, frameLength);
  84. System.out.println("ff.getFrameRate() == " + ff.getFrameRate());
  85. int i = 0;
  86. Frame frame = null;
  87. while (i < frameLength) {
  88. frame = ff.grabImage();
  89. if (list.contains(i)) {
  90. if (frame != null && frame.image != null) {
  91. System.out.println(i);
  92. String fileName = String.valueOf(System.currentTimeMillis()) + i;
  93. files.add(writeToFile(frame, saveDir, fileName));
  94. }
  95. }
  96. i++;
  97. }
  98. ff.stop();
  99. return files;
  100. }
  101. public static Long fetchAllPic(File videoFile, String saveDir, Date shootEndTime) throws Exception {
  102. Long endTime = shootEndTime.getTime() ;
  103. java.util.List<File> files = new ArrayList<>();
  104. FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile);
  105. ff.start();
  106. // 此视频时长(ms/毫秒秒)
  107. Long duration = ff.getLengthInTime() / 1000;
  108. System.out.println("duration==" + duration);
  109. Long beginTime = endTime - duration;
  110. // 视频总帧数
  111. int frameLength = ff.getLengthInFrames();
  112. System.out.println("length==" + frameLength);
  113. //帧率(1秒多少帧)
  114. double framRate = ff.getFrameRate();
  115. int i = 0;
  116. Frame frame = null;
  117. while (i < frameLength) {
  118. frame = ff.grabImage();
  119. if (frame != null && frame.image != null) {
  120. Double time = beginTime + (i * (1000/framRate));
  121. String fileName = DateUtils.formatToDateStr(new Date(time.longValue()),"yyyyMMddHHmmss") + "_" + UUID.randomUUID().toString();
  122. files.add(writeToFile(frame, saveDir, fileName));
  123. }
  124. i++;
  125. }
  126. ff.stop();
  127. return duration;
  128. }
  129. private static File writeToFile(Frame frame, String saveDir, String fileName) throws Exception {
  130. File saveDirFile = new File(saveDir);
  131. if(!saveDirFile.exists()) {
  132. saveDirFile.mkdirs();
  133. }
  134. File targetFile = new File(saveDir + File.separator + fileName + ".jpg");
  135. String imgSuffix = "jpg";
  136. Java2DFrameConverter converter = new Java2DFrameConverter();
  137. BufferedImage srcBi = converter.getBufferedImage(frame);
  138. int owidth = srcBi.getWidth();
  139. int oheight = srcBi.getHeight();
  140. // 对截取的帧进行等比例缩放
  141. int width = 800;
  142. int height = (int) (((double) width / owidth) * oheight);
  143. BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
  144. bi.getGraphics().drawImage(srcBi.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
  145. try {
  146. ImageIO.write(bi, imgSuffix, targetFile);
  147. } catch (Exception e) {
  148. throw new Exception( "截帧失败");
  149. }
  150. return targetFile;
  151. }
  152. /**
  153. * 获取视频时长,单位为秒
  154. *
  155. * @param file
  156. * @return 时长(s)
  157. */
  158. public static Long getVideoTime(File file) {
  159. Long times = 0L;
  160. try {
  161. FFmpegFrameGrabber ff = new FFmpegFrameGrabber(file);
  162. ff.start();
  163. times = ff.getLengthInTime() / (1000 * 1000);
  164. ff.stop();
  165. } catch (Exception e) {
  166. e.printStackTrace();
  167. }
  168. return times;
  169. }
  170. /**
  171. * 视频截取
  172. * @param videoFile
  173. * @throws Exception
  174. */
  175. public static void cut(File videoFile, File outputFile) throws Exception{
  176. boolean isStart = true;// 该变量建议设置为全局控制变量,用于控制录制结束
  177. FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoFile);
  178. // // 微秒 大概为设置时间的两倍
  179. // grabber.setOption(TimeoutOption.RW_TIMEOUT.getKey(), "10000000");
  180. // rtsp 默认udp 丢包 改为tcp
  181. // grabber.setOption("rtsp_transport", "tcp");
  182. grabber.start();
  183. //好多视频熟悉可以获取后打印 示例几个
  184. System.out.println("ImageWidth:" + grabber.getImageWidth());
  185. System.out.println("ImageHeight:" + grabber.getImageHeight());
  186. System.out.println("AudioChannels:" + grabber.getAudioChannels());
  187. System.out.println("Format:" + grabber.getFormat());
  188. FrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(), grabber.getImageHeight(),grabber.getAudioChannels());
  189. recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // avcodec.AV_CODEC_ID_H264,编码
  190. recorder.setFormat("flv");//封装格式,如果是推送到rtmp就必须是flv封装格式
  191. recorder.setFrameRate( grabber.getFrameRate());
  192. recorder.start();//开启录制器
  193. long startTime=0;
  194. long videoTS=0;
  195. CanvasFrame frame = new CanvasFrame("camera", CanvasFrame.getDefaultGamma() / grabber.getGamma());
  196. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  197. frame.setAlwaysOnTop(true);
  198. Frame rotatedFrame= null;
  199. while (frame.isVisible() && (rotatedFrame = grabber.grabFrame()) != null) {
  200. rotatedFrame = grabber.grabFrame();
  201. frame.showImage(rotatedFrame);
  202. if (startTime == 0) {
  203. startTime = System.currentTimeMillis();
  204. }
  205. videoTS = 1000 * (System.currentTimeMillis() - startTime);
  206. recorder.setTimestamp(videoTS);
  207. recorder.record(rotatedFrame);
  208. Thread.sleep(40);
  209. }
  210. frame.dispose();
  211. recorder.stop();
  212. recorder.release();
  213. grabber.stop();
  214. }
  215. /**
  216. * 视频截取
  217. * @param videoFile
  218. * @throws Exception
  219. */
  220. public static void cut2(File videoFile, File outputFile) throws Exception{
  221. boolean isStart = true;// 该变量建议设置为全局控制变量,用于控制录制结束
  222. FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoFile);
  223. // // 微秒 大概为设置时间的两倍
  224. // grabber.setOption(TimeoutOption.RW_TIMEOUT.getKey(), "10000000");
  225. // rtsp 默认udp 丢包 改为tcp
  226. // grabber.setOption("rtsp_transport", "tcp");
  227. grabber.start();
  228. //好多视频熟悉可以获取后打印 示例几个
  229. System.out.println("ImageWidth:" + grabber.getImageWidth());
  230. System.out.println("ImageHeight:" + grabber.getImageHeight());
  231. System.out.println("AudioChannels:" + grabber.getAudioChannels());
  232. System.out.println("Format:" + grabber.getFormat());
  233. FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(), grabber.getImageHeight(),grabber.getAudioChannels());
  234. recorder.setFrameRate(grabber.getFrameRate());
  235. recorder.setAudioBitrate(grabber.getAudioBitrate());
  236. recorder.setSampleRate(grabber.getSampleRate());
  237. // recorder.setGopSize(2);
  238. recorder.setFormat("mp4");
  239. recorder.setAudioCodecName("aac");
  240. recorder.setVideoCodec(grabber.getVideoCodec());
  241. recorder.start();
  242. Frame frame = null;
  243. //如果想截取规定时间段视频 请看系列文章二
  244. while (isStart) {
  245. frame = grabber.grabFrame();
  246. if(frame != null){
  247. recorder.record(frame);
  248. }
  249. }
  250. recorder.stop();
  251. recorder.release();
  252. grabber.stop();
  253. grabber.release();
  254. }
  255. public void cut3() throws Exception{
  256. FFmpeg ffmpeg = new FFmpeg("/path/to/ffmpeg");
  257. FFprobe ffprobe = new FFprobe("/path/to/ffprobe");
  258. FFmpegBuilder builder = new FFmpegBuilder()
  259. .setInput("input.mp4") // Filename, or a FFmpegProbeResult
  260. .overrideOutputFiles(true) // Override the output if it exists
  261. .addOutput("output.mp4") // Filename for the destination
  262. .setFormat("mp4") // Format is inferred from filename, or can be set
  263. .setTargetSize(250_000) // Aim for a 250KB file
  264. .disableSubtitle() // No subtiles
  265. .setAudioChannels(1) // Mono audio
  266. .setAudioCodec("aac") // using the aac codec
  267. .setAudioSampleRate(48_000) // at 48KHz
  268. .setAudioBitRate(32768) // at 32 kbit/s
  269. .setVideoCodec("libx264") // Video using x264
  270. .setVideoFrameRate(24, 1) // at 24 frames per second
  271. .setVideoResolution(640, 480) // at 640x480 resolution
  272. .setStrict(FFmpegBuilder.Strict.EXPERIMENTAL) // Allow FFmpeg to use experimental specs
  273. .done();
  274. FFmpegExecutor executor = new FFmpegExecutor(ffmpeg, ffprobe);
  275. // Run a one-pass encode
  276. executor.createJob(builder).run();
  277. // Or run a two-pass encode (which is better quality at the cost of being slower)
  278. executor.createTwoPassJob(builder).run();
  279. }
  280. public static void main(String[] args) {
  281. try {
  282. //getList(10,113);
  283. File file = new File("e:/20211223123223_76639ced-6400-11ec-b8f9-fa163e4e1e9f.mp4");
  284. // List<File> files = VideoUtil.fetchPicByCount(file, "E:/223", 100);
  285. // System.out.println(files.get(0).getName());
  286. // System.out.println(VideoUtil.getVideoTime(file));
  287. Date shootEndTime = DateUtils.strToDate("20211223123223","yyyyMMddHHmmss");
  288. // fetchAllPic(file,"E:/223",shootEndTime);
  289. // cut3(file,new File("e:/a.mp4"));
  290. } catch (Exception e) {
  291. e.printStackTrace();
  292. }
  293. }
  294. }