当前位置:   article > 正文

FFmpeg获取视频详情_ffmpeg 查看视频详情

ffmpeg 查看视频详情

话不多说,直接上代码:

pom依赖

  1. <!--视频多媒体工具包 包含 FFmpeg、OpenCV-->
  2. <dependency>
  3. <groupId>org.bytedeco</groupId>
  4. <artifactId>javacv-platform</artifactId>
  5. <version>1.5.3</version>
  6. </dependency>
  7. <!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
  8. <dependency>
  9. <groupId>commons-lang</groupId>
  10. <artifactId>commons-lang</artifactId>
  11. <version>2.6</version>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.projectlombok</groupId>
  15. <artifactId>lombok</artifactId>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.openjfx</groupId>
  19. <artifactId>javafx-controls</artifactId>
  20. <version>16</version>
  21. </dependency>

工具类:

  1. package com.example.mybatisdemo02.util;
  2. import com.example.mybatisdemo02.model.VideoInfoVO;
  3. import javafx.application.Application;
  4. import javafx.geometry.Pos;
  5. import javafx.scene.Scene;
  6. import javafx.scene.control.Slider;
  7. import javafx.scene.layout.BorderPane;
  8. import javafx.scene.layout.HBox;
  9. import javafx.scene.media.Media;
  10. import javafx.scene.media.MediaPlayer;
  11. import javafx.scene.media.MediaView;
  12. import javafx.stage.Stage;
  13. import org.apache.commons.lang.StringUtils;
  14. import org.bytedeco.javacv.FFmpegFrameGrabber;
  15. import org.bytedeco.javacv.Frame;
  16. import org.bytedeco.javacv.FrameGrabber;
  17. import org.bytedeco.javacv.Java2DFrameConverter;
  18. import javafx.scene.control.Button;
  19. import javax.imageio.ImageIO;
  20. import javax.imageio.ImageReader;
  21. import javax.imageio.stream.ImageInputStream;
  22. import javax.swing.*;
  23. import java.awt.*;
  24. import java.awt.image.BufferedImage;
  25. import java.io.*;
  26. import java.math.BigDecimal;
  27. import java.net.HttpURLConnection;
  28. import java.net.MalformedURLException;
  29. import java.net.URL;
  30. import java.nio.channels.FileChannel;
  31. import java.util.UUID;
  32. public class FFmpegUtil {
  33. private static final String IMAGE_SUFFIX = "png";
  34. /**
  35. * 获取视频时长,单位为秒S
  36. * @return
  37. */
  38. public static long getVideoTime( String localPath) throws FrameGrabber.Exception {
  39. // String localPath = "C:/Users/Administrator/Desktop/dab2d14cad0244229e228e7bf297dd9a.flv";
  40. FFmpegFrameGrabber grabber = FFmpegFrameGrabber.createDefault(localPath);
  41. grabber.start();
  42. long duration = grabber.getLengthInTime() / (1000 * 1000);
  43. grabber.stop();
  44. System.out.println("此视频时长(s/秒):"+duration);
  45. return duration;
  46. }
  47. /**
  48. * 获取视频帧图片
  49. * @param file 视频源
  50. * @param number 第几帧
  51. * @param dir 文件存放根目录
  52. * @param args 文件存放根目录
  53. * @return
  54. */
  55. @SuppressWarnings("resource")
  56. public static String videoImage(File file, Integer number, String dir, String args) {
  57. String picPath = StringUtils.EMPTY;
  58. FFmpegFrameGrabber ff = new FFmpegFrameGrabber(file);
  59. try {
  60. ff.start();
  61. int i = 0;
  62. int length = ff.getLengthInFrames();
  63. Frame frame = null;
  64. while (i < length) {
  65. frame = ff.grabFrame();
  66. //截取第几帧图片
  67. if ((i > number) && (frame.image != null)) {
  68. //获取生成图片的路径
  69. picPath = getImagePath(args);
  70. //执行截图并放入指定位置
  71. doExecuteFrame(frame, dir + File.separator + picPath);
  72. break;
  73. }
  74. i++;
  75. }
  76. ff.stop();
  77. } catch (FrameGrabber.Exception e) {
  78. e.printStackTrace();
  79. }
  80. return picPath;
  81. }
  82. /**
  83. * 截取缩略图
  84. * @param frame
  85. * @param targerFilePath 图片存放路径
  86. */
  87. public static void doExecuteFrame(Frame frame, String targerFilePath) {
  88. //截取的图片
  89. if (null == frame || null == frame.image) {
  90. return;
  91. }
  92. Java2DFrameConverter converter = new Java2DFrameConverter();
  93. BufferedImage srcImage = converter.getBufferedImage(frame);
  94. int srcImageWidth = srcImage.getWidth();
  95. int srcImageHeight = srcImage.getHeight();
  96. //对帧图片进行等比例缩放(缩略图)
  97. int width = 480;
  98. int height = (int) (((double) width / srcImageWidth) * srcImageHeight);
  99. BufferedImage thumbnailImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
  100. thumbnailImage.getGraphics().drawImage(srcImage.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
  101. File output = new File(targerFilePath);
  102. try {
  103. ImageIO.write(thumbnailImage, IMAGE_SUFFIX, output);
  104. } catch (IOException e) {
  105. e.printStackTrace();
  106. }
  107. }
  108. /**
  109. * 生成图片的相对路径
  110. * @param args 传入生成图片的名称、为空则用UUID命名
  111. * @return 例如 upload/images.png
  112. */
  113. public static String getImagePath(String args) {
  114. if (StringUtils.isNotEmpty(args)) {
  115. return args + "." + IMAGE_SUFFIX;
  116. }
  117. return getUUID() + "." + IMAGE_SUFFIX;
  118. }
  119. /**
  120. * 生成唯一的uuid
  121. * @return uuid
  122. */
  123. public static String getUUID(){
  124. return UUID.randomUUID().toString().replace("-","");
  125. }
  126. /**
  127. * 时长格式换算
  128. * @param duration 时长
  129. * @return HH:mm:ss
  130. */
  131. public static String formatDuration(Long duration) {
  132. String formatTime = StringUtils.EMPTY;
  133. double time = Double.valueOf(duration);
  134. if (time > -1) {
  135. int hour = (int) Math.floor(time / 3600);
  136. int minute = (int) (Math.floor(time / 60) % 60);
  137. int second = (int) (time % 60);
  138. if (hour < 10) {
  139. formatTime = "0";
  140. }
  141. formatTime += hour + ":";
  142. if (minute < 10) {
  143. formatTime += "0";
  144. }
  145. formatTime += minute + ":";
  146. if (second < 10) {
  147. formatTime += "0";
  148. }
  149. formatTime += second;
  150. }
  151. return formatTime;
  152. }
  153. /**
  154. * 获取图片大小Kb
  155. * @param urlPath
  156. * @return
  157. */
  158. public static String getImageSize(String urlPath){
  159. // 得到数据
  160. byte[] imageFromURL = getImageFromURL(urlPath);
  161. // 转换
  162. String byte2kb = bytes2kb(imageFromURL.length);
  163. return byte2kb;
  164. }
  165. /**
  166. * 根据图片地址获取图片信息
  167. *
  168. * @param urlPath 网络图片地址
  169. * @return
  170. */
  171. public static byte[] getImageFromURL(String urlPath) {
  172. // 字节数组
  173. byte[] data = null;
  174. // 输入流
  175. InputStream is = null;
  176. // Http连接对象
  177. HttpURLConnection conn = null;
  178. try {
  179. // Url对象
  180. URL url = new URL(urlPath);
  181. // 打开连接
  182. conn = (HttpURLConnection) url.openConnection();
  183. // 打开读取 写入是setDoOutput
  184. // conn.setDoOutput(true);
  185. conn.setDoInput(true);
  186. // 设置请求方式
  187. conn.setRequestMethod("GET");
  188. // 设置超时时间
  189. conn.setConnectTimeout(6000);
  190. // 得到访问的数据流
  191. is = conn.getInputStream();
  192. // 验证访问状态是否是200 正常
  193. if (conn.getResponseCode() == 200) {
  194. data = readInputStream(is);
  195. } else {
  196. data = null;
  197. }
  198. } catch (MalformedURLException e) {
  199. e.printStackTrace();
  200. } catch (IOException e) {
  201. e.printStackTrace();
  202. } finally {
  203. try {
  204. if (is != null) {
  205. // 关闭流
  206. is.close();
  207. }
  208. } catch (IOException e) {
  209. e.printStackTrace();
  210. }
  211. // 关闭连接
  212. conn.disconnect();
  213. }
  214. return data;
  215. }
  216. /**
  217. * 将流转换为字节
  218. *
  219. * @param is
  220. * @return
  221. */
  222. public static byte[] readInputStream(InputStream is) {
  223. /**
  224. * 捕获内存缓冲区的数据,转换成字节数组
  225. * ByteArrayOutputStream类是在创建它的实例时,程序内部创建一个byte型别数组的缓冲区,然后利用ByteArrayOutputStream和ByteArrayInputStream的实例向数组中写入或读出byte型数据。
  226. * 在网络传输中我们往往要传输很多变量,我们可以利用ByteArrayOutputStream把所有的变量收集到一起,然后一次性把数据发送出去。
  227. */
  228. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  229. // 创建字节数组 1024 = 1M
  230. byte[] buffer = new byte[1024];
  231. // 防止无限循环
  232. int length = -1;
  233. try {
  234. // 循环写入数据到字节数组
  235. while ((length = is.read(buffer)) != -1) {
  236. baos.write(buffer, 0, length);
  237. }
  238. // 强制刷新,扫尾工作,主要是为了,让数据流在管道的传输工程中全部传输过去,防止丢失数据
  239. baos.flush();
  240. } catch (IOException e) {
  241. e.printStackTrace();
  242. }
  243. // 字节流转换字节数组
  244. byte[] data = baos.toByteArray();
  245. try {
  246. // 关闭读取流
  247. is.close();
  248. // 关闭写入流
  249. baos.close();
  250. } catch (IOException e) {
  251. e.printStackTrace();
  252. }
  253. return data;
  254. }
  255. /**
  256. * 获取本地图片的字节数
  257. *
  258. * @param imgPath
  259. * @return
  260. */
  261. public static String pathSize(String imgPath) {
  262. File file = new File(imgPath);
  263. FileInputStream fis;
  264. int fileLen = 0;
  265. try {
  266. fis = new FileInputStream(file);
  267. fileLen = fis.available();
  268. } catch (FileNotFoundException e) {
  269. e.printStackTrace();
  270. } catch (IOException e) {
  271. e.printStackTrace();
  272. }
  273. return bytes2kb(fileLen);
  274. }
  275. /**
  276. * 将获取到的字节数转换为KB,MB模式
  277. *
  278. * @param bytes
  279. * @return
  280. */
  281. public static String bytes2kb(long bytes) {
  282. BigDecimal filesize = new BigDecimal(bytes);
  283. // BigDecimal megabyte = new BigDecimal(1024 * 1024);
  284. // float returnValue = filesize.divide(megabyte, 2, BigDecimal.ROUND_UP).floatValue();
  285. // if (returnValue > 1)
  286. // return (returnValue + "MB");
  287. // BigDecimal kilobyte = new BigDecimal(1024);
  288. // returnValue = filesize.divide(kilobyte, 2, BigDecimal.ROUND_UP).floatValue();
  289. // return (returnValue + "KB");
  290. return filesize.toString();
  291. }
  292. public static String getImageFormat(String imagePath) throws IOException {
  293. // 字节数组
  294. byte[] data = null;
  295. String format = null;
  296. // 输入流
  297. InputStream is = null;
  298. // Http连接对象
  299. HttpURLConnection conn = null;
  300. ImageInputStream imageInputStream = null;
  301. try {
  302. // Url对象
  303. URL url = new URL(imagePath);
  304. // 打开连接
  305. conn = (HttpURLConnection) url.openConnection();
  306. // 打开读取 写入是setDoOutput
  307. // conn.setDoOutput(true);
  308. conn.setDoInput(true);
  309. // 设置请求方式
  310. conn.setRequestMethod("GET");
  311. // 设置超时时间
  312. conn.setConnectTimeout(6000);
  313. // 得到访问的数据流
  314. is = conn.getInputStream();
  315. // 验证访问状态是否是200 正常
  316. if (conn.getResponseCode() == 200) {
  317. imageInputStream = ImageIO.createImageInputStream(is);
  318. ImageReader imageReader = ImageIO.getImageReaders(imageInputStream).next();
  319. format = imageReader.getFormatName();
  320. } else {
  321. format = null;
  322. }
  323. } catch (MalformedURLException e) {
  324. e.printStackTrace();
  325. } catch (IOException e) {
  326. e.printStackTrace();
  327. } finally {
  328. try {
  329. if (is != null) {
  330. // 关闭流
  331. is.close();
  332. }
  333. if(imageInputStream != null){
  334. imageInputStream.close();
  335. }
  336. } catch (IOException e) {
  337. e.printStackTrace();
  338. }
  339. // 关闭连接
  340. conn.disconnect();
  341. }
  342. return format;
  343. }
  344. /**
  345. * 将inputStream转化为file
  346. * @param is
  347. * @param file 要输出的文件目录
  348. */
  349. public static void inputStream2File(InputStream is, File file) throws IOException {
  350. OutputStream os = null;
  351. try {
  352. os = new FileOutputStream(file);
  353. int len = 0;
  354. byte[] buffer = new byte[8192];
  355. while ((len = is.read(buffer)) != -1) {
  356. os.write(buffer, 0, len);
  357. }
  358. } finally {
  359. os.close();
  360. is.close();
  361. }
  362. }
  363. /**
  364. * 获取视频详情
  365. * @param file
  366. * @return
  367. */
  368. public static VideoInfoVO getVideoInfo(String file) {
  369. VideoInfoVO videoInfoVO = new VideoInfoVO();
  370. FFmpegFrameGrabber grabber = null;
  371. try {
  372. grabber = FFmpegFrameGrabber.createDefault(file);
  373. // 启动 FFmpeg
  374. grabber.start();
  375. // 读取视频帧数
  376. videoInfoVO.setLengthInFrames(grabber.getLengthInVideoFrames());
  377. // 读取视频帧率
  378. videoInfoVO.setFrameRate(grabber.getVideoFrameRate());
  379. // 读取视频秒数
  380. videoInfoVO.setDuration(grabber.getLengthInTime() / 1000000.00);
  381. // 读取视频宽度
  382. videoInfoVO.setWidth(grabber.getImageWidth());
  383. // 读取视频高度
  384. videoInfoVO.setHeight(grabber.getImageHeight());
  385. videoInfoVO.setAudioChannel(grabber.getAudioChannels());
  386. videoInfoVO.setVideoCode(grabber.getVideoCodecName());
  387. videoInfoVO.setAudioCode(grabber.getAudioCodecName());
  388. // String md5 = MD5Util.getMD5ByInputStream(new FileInputStream(file));
  389. videoInfoVO.setSampleRate(grabber.getSampleRate());
  390. return videoInfoVO;
  391. } catch (Exception e) {
  392. e.printStackTrace();
  393. return null;
  394. } finally {
  395. try {
  396. if (grabber != null) {
  397. // 此处代码非常重要,如果没有,可能造成 FFmpeg 无法关闭
  398. grabber.stop();
  399. grabber.release();
  400. }
  401. } catch (FFmpegFrameGrabber.Exception e) {
  402. e.printStackTrace();
  403. }
  404. }
  405. }
  406. /**
  407. * 截取视频获得指定帧的图片(截取视频帧封面)
  408. *
  409. * @param video 源视频文件
  410. */
  411. public void getVideoPic(InputStream video) {
  412. FFmpegFrameGrabber ff = new FFmpegFrameGrabber(video);
  413. try {
  414. ff.start();
  415. // 截取中间帧图片(具体依实际情况而定)
  416. int i = 0;
  417. int length = ff.getLengthInFrames();
  418. // int middleFrame = length / 2;
  419. int middleFrame = 5;
  420. Frame frame = null;
  421. while (i < length) {
  422. frame = ff.grabFrame();
  423. if ((i > middleFrame) && (frame.image != null)) {
  424. break;
  425. }
  426. i++;
  427. }
  428. // 截取的帧图片
  429. Java2DFrameConverter converter = new Java2DFrameConverter();
  430. BufferedImage srcImage = converter.getBufferedImage(frame);
  431. int srcImageWidth = srcImage.getWidth();
  432. int srcImageHeight = srcImage.getHeight();
  433. BufferedImage image = new BufferedImage(srcImageWidth, srcImageHeight, BufferedImage.TYPE_INT_ARGB);
  434. Graphics2D g2d = image.createGraphics();
  435. g2d.setColor(Color.RED);
  436. g2d.fillRect(0, 0, srcImageWidth, srcImageHeight);
  437. g2d.setColor(Color.WHITE);
  438. g2d.drawString("Hello, World!", 50, 100);
  439. g2d.dispose();
  440. File file = new File("image.png");
  441. try {
  442. ImageIO.write(image, "png", file);
  443. } catch (IOException e) {
  444. e.printStackTrace();
  445. }
  446. ff.stop();
  447. } catch (java.lang.Exception e) {
  448. e.printStackTrace();
  449. System.out.println(e);
  450. }
  451. }
  452. /**
  453. * 获取文件大小
  454. * @param inputStream
  455. * @return
  456. */
  457. public String getFileSize(InputStream inputStream){
  458. FileChannel fc = null;
  459. String size = "0";
  460. try {
  461. FileInputStream fis = convertToFileInputStream(inputStream);
  462. fc = fis.getChannel();
  463. BigDecimal fileSize = new BigDecimal(fc.size());
  464. size = String.valueOf(fileSize);
  465. } catch (FileNotFoundException e) {
  466. e.printStackTrace();
  467. } catch (IOException e) {
  468. e.printStackTrace();
  469. } finally {
  470. if (null != fc) {
  471. try {
  472. fc.close();
  473. } catch (IOException e) {
  474. e.printStackTrace();
  475. }
  476. }
  477. }
  478. return size;
  479. }
  480. /**
  481. * inputStream转FileInputStream
  482. * @param inputStream
  483. * @return
  484. * @throws IOException
  485. */
  486. public static FileInputStream convertToFileInputStream(InputStream inputStream) throws IOException {
  487. File tempFile = File.createTempFile("temp", ".tmp");
  488. tempFile.deleteOnExit();
  489. try (FileOutputStream outputStream = new FileOutputStream(tempFile)) {
  490. byte[] buffer = new byte[1024];
  491. int bytesRead;
  492. while ((bytesRead = inputStream.read(buffer)) != -1) {
  493. outputStream.write(buffer, 0, bytesRead);
  494. }
  495. }
  496. return new FileInputStream(tempFile);
  497. }
  498. public void start(Stage primaryStage) {
  499. String videoPath = "C:\\Users\\DELL\\Desktop\\test.mp4";
  500. double position = 1200.0; // 播放位置(以秒为单位)
  501. // 创建媒体播放器
  502. Media media = new Media(new File(videoPath).toURI().toString());
  503. MediaPlayer mediaPlayer = new MediaPlayer(media);
  504. mediaPlayer.setOnReady(() -> {
  505. mediaPlayer.seek(mediaPlayer.getTotalDuration().multiply(position / mediaPlayer.getTotalDuration().toSeconds()));
  506. mediaPlayer.play();
  507. });
  508. mediaPlayer.setAutoPlay(true);
  509. // 创建媒体视图
  510. MediaView mediaView = new MediaView(mediaPlayer);
  511. // 创建控制按钮
  512. Button playButton = new Button("播放");
  513. Button pauseButton = new Button("暂停");
  514. Button stopButton = new Button("停止");
  515. // 播放按钮点击事件
  516. playButton.setOnAction(event -> mediaPlayer.play());
  517. // 暂停按钮点击事件
  518. pauseButton.setOnAction(event -> mediaPlayer.pause());
  519. // 停止按钮点击事件
  520. stopButton.setOnAction(event -> mediaPlayer.stop());
  521. // 创建音量调节滑块
  522. Slider volumeSlider = new Slider(0, 1, 0.5);
  523. volumeSlider.setPrefWidth(100);
  524. mediaPlayer.volumeProperty().bind(volumeSlider.valueProperty());
  525. // 创建按钮布局
  526. HBox buttonBox = new HBox(10);
  527. buttonBox.setAlignment(Pos.CENTER);
  528. buttonBox.getChildren().addAll(playButton, pauseButton, stopButton);
  529. // 创建根布局
  530. BorderPane root = new BorderPane();
  531. root.setCenter(mediaView);
  532. root.setBottom(volumeSlider);
  533. root.setTop(buttonBox);
  534. // 创建场景
  535. Scene scene = new Scene(root, 800, 600);
  536. // 设置舞台
  537. primaryStage.setScene(scene);
  538. primaryStage.setTitle("Video Player");
  539. primaryStage.show();
  540. }
  541. }
实体VideoInfoVO类:
  1. package com.example.mybatisdemo02.model;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import lombok.Getter;
  4. import lombok.Setter;
  5. @Getter
  6. @Setter
  7. public class VideoInfoVO {
  8. /**
  9. * 总帧数
  10. **/
  11. private int lengthInFrames;
  12. /**
  13. * 帧率
  14. **/
  15. private double frameRate;
  16. /**
  17. * 时长
  18. **/
  19. private double duration;
  20. /**
  21. * 视频编码
  22. */
  23. private String videoCode;
  24. /**
  25. * 音频编码
  26. */
  27. private String audioCode;
  28. private int width;
  29. private int height;
  30. private int audioChannel;
  31. private String md5;
  32. /**
  33. * 音频采样率
  34. */
  35. private Integer sampleRate;
  36. private Double fileSize;
  37. public String toJson() {
  38. try {
  39. ObjectMapper objectMapper = new ObjectMapper();
  40. return objectMapper.writeValueAsString(this);
  41. } catch (Exception e) {
  42. return "";
  43. }
  44. }
  45. }

调用

  1. public class Main {
  2. public static void main(String[] args) {
  3. VideoInfoVO videoInfoVO = FFmpegUtil.getVideoInfo("C:\\Users\\DELL\\Desktop\\test.mp4");
  4. int date = videoInfoVO.getLengthInFrames();
  5. double shichang = videoInfoVO.getDuration();
  6. System.out.println("帧数:"+date+"时长:"+shichang);
  7. }
  8. }

结果如下图:

欢迎给个关注:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/815348
推荐阅读
  

闽ICP备14008679号