最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaCV實現(xiàn)讀取視頻信息及自動截取封面圖詳解

 更新時間:2022年06月08日 09:29:58   作者:陜西顏值扛把子  
javacv可以幫助我們在java中很方便的使用OpenCV以及FFmpeg相關(guān)的功能接口。本文將利用Javacv實現(xiàn)在視頻網(wǎng)站中常見的讀取視頻信息和自動獲取封面圖的功能,感興趣的可以了解一下

概述

最近在對之前寫的一個 Spring Boot 的視頻網(wǎng)站項目做功能完善,需要利用 FFmpeg 實現(xiàn)讀取視頻信息和自動截圖的功能,查閱資料后發(fā)現(xiàn)網(wǎng)上這部分的內(nèi)容非常少,于是就有了這篇文章。

視頻網(wǎng)站項目地址

GitHub

碼云

本文將介紹如何利用Javacv實現(xiàn)在視頻網(wǎng)站中常見的讀取視頻信息和自動獲取封面圖的功能。

javacv 介紹

javacv可以幫助我們在java中很方便的使用 OpenCV 以及 FFmpeg 相關(guān)的功能接口

項目地址

引入 javacv

        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>${javacv.version}</version>
        </dependency>

讀取視頻信息

創(chuàng)建 VideoInfo 類

package com.buguagaoshu.porntube.vo;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;

/**
 * @author Pu Zhiwei {@literal puzhiweipuzhiwei@foxmail.com}
 * create          2022-06-06 19:15
 */
@Getter
@Setter
public class VideoInfo {
    /**
     * 總幀數(shù)
     **/
    private int lengthInFrames;

    /**
     * 幀率
     **/
    private double frameRate;

    /**
     * 時長
     **/
    private double duration;

    /**
     * 視頻編碼
     */
    private String videoCode;
    /**
     * 音頻編碼
     */
    private String audioCode;

    private int width;
    private int height;
    private int audioChannel;
    private String md5;
    /**
     * 音頻采樣率
     */
    private Integer sampleRate;

    public String toJson() {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.writeValueAsString(this);
        } catch (Exception e) {
            return "";
        }
    }
}

使用 FFmpegFrameGrabber 讀取視頻信息

 public static VideoInfo getVideoInfo(File file) {
        VideoInfo videoInfo = new VideoInfo();
        FFmpegFrameGrabber grabber = null;
        try {
            grabber = new FFmpegFrameGrabber(file);
            // 啟動 FFmpeg
            grabber.start();

            // 讀取視頻幀數(shù)
            videoInfo.setLengthInFrames(grabber.getLengthInVideoFrames());

			// 讀取視頻幀率
            videoInfo.setFrameRate(grabber.getVideoFrameRate());

            // 讀取視頻秒數(shù)
            videoInfo.setDuration(grabber.getLengthInTime() / 1000000.00);
            
            // 讀取視頻寬度
            videoInfo.setWidth(grabber.getImageWidth());

            // 讀取視頻高度
            videoInfo.setHeight(grabber.getImageHeight());

            
            videoInfo.setAudioChannel(grabber.getAudioChannels());

            videoInfo.setVideoCode(grabber.getVideoCodecName());

            videoInfo.setAudioCode(grabber.getAudioCodecName());
            // String md5 = MD5Util.getMD5ByInputStream(new FileInputStream(file));

            videoInfo.setSampleRate(grabber.getSampleRate());
            return videoInfo;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (grabber != null) {
                    // 此處代碼非常重要,如果沒有,可能造成 FFmpeg 無法關(guān)閉
                    grabber.stop();
                    grabber.release();
                }
            } catch (FFmpegFrameGrabber.Exception e) {
                log.error("getVideoInfo grabber.release failed 獲取文件信息失?。簕}", e.getMessage());
            }
        }
    }

截圖

讀取信息沒有什么難度,但是在對視頻截圖的過程中,出現(xiàn)了一些問題,在我查找截圖實現(xiàn)的代碼時,大多數(shù)的代碼都是這么寫的

    /**
     * 獲取視頻縮略圖
     * @param filePath:視頻路徑
     * @param mod:視頻長度/mod獲取第幾幀
     * @throws Exception
     */
    public static String randomGrabberFFmpegImage(String filePath, int mod) {
        String targetFilePath = "";
        try{
            FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
            ff.start();
            //圖片位置是否正確
            String rotate = ff.getVideoMetadata(ROTATE);
            //獲取幀數(shù)
            int ffLength = ff.getLengthInFrames();
            Frame f;
            int i = 0;
            //設(shè)置截取幀數(shù)
            int index = ffLength / mod;
            while (i < ffLength) {
                f = ff.grabImage();
                if(i == index){
                    if (null != rotate && rotate.length() > 1) {
                        OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
                        IplImage src = converter.convert(f);
                        f = converter.convert(rotate(src, Integer.parseInt(rotate)));
                    }
                    targetFilePath = getImagePath(filePath, i);
                    doExecuteFrame(f, targetFilePath);
                    break;
                }
                i++;
            }
            ff.stop();
        }catch (Exception e){
            log.error("獲取視頻縮略圖異常:" + e.getMessage());
        }
        return targetFilePath;
    }

這樣寫本身沒有什么問題,但是在獲取需要截取幀數(shù)的部分,使用的是通過循環(huán)來一幀一幀的判斷,這樣在視頻較短的時候沒有什么問題,但是如果視頻較長,就會出現(xiàn)嚴重的性能問題。

  while (i < ffLength) {
                f = ff.grabImage();
                if(i == index){
					......
                    break;
                }
                i++;
            }

FFmpeg 的命令行參數(shù)有一個 -ss 的參數(shù),使用 -ss 可以快速的幫助我們跳到視頻的指定位置,完成操作,不用一幀一幀的判斷。

所以現(xiàn)在的問題就是如何在 javacv 中實現(xiàn) -ss 參數(shù)

我在 javacv 的 GitHub Issues 中發(fā)現(xiàn)了這個操作,即使用 setTimestamp() 方法,使用 setTimestamp() 方法可以使 FFmpeg 跳轉(zhuǎn)到指定時間,完成截圖,于是,最后的截圖代碼就變成了這樣

  /**
     * 隨機獲取視頻截圖
     * @param videFile 視頻文件
     * @param count 輸出截圖數(shù)量
     * @return 截圖列表
     * */
    public static List<FileTableEntity> randomGrabberFFmpegImage(File videFile, int count, long userId) {
        FFmpegFrameGrabber grabber = null;

        String path = FileTypeEnum.filePath();
        try {
            List<FileTableEntity> images = new ArrayList<>(count);
            grabber = new FFmpegFrameGrabber(videFile);
            grabber.start();
            // 獲取視頻總幀數(shù)
            // int lengthInVideoFrames = grabber.getLengthInVideoFrames();
            // 獲取視頻時長, / 1000000 將單位轉(zhuǎn)換為秒
            long delayedTime = grabber.getLengthInTime() / 1000000;

            Random random = new Random();
            for (int i = 0; i < count; i++) {
                // 跳轉(zhuǎn)到響應(yīng)時間
                grabber.setTimestamp((random.nextInt((int)delayedTime - 1) + 1) * 1000000L);
                Frame f = grabber.grabImage();
                Java2DFrameConverter converter = new Java2DFrameConverter();
                BufferedImage bi = converter.getBufferedImage(f);
                String imageName = FileTypeEnum.newFilename(SUFFIX);
                File out = Paths.get(path, imageName).toFile();
                ImageIO.write(bi, "jpg", out);
                FileTableEntity fileTable = FileUtils.createFileTableEntity(imageName, SUFFIX, path, f.image.length, "系統(tǒng)生成截圖", userId, FileTypeEnum.VIDEO_PHOTO.getCode());
                images.add(fileTable);
            }
            return images;
        } catch (Exception e) {
            return null;
        } finally {
            try {
                if (grabber != null) {
                    grabber.stop();
                    grabber.release();
                }
            } catch (FFmpegFrameGrabber.Exception e) {
                log.error("getVideoInfo grabber.release failed 獲取文件信息失?。簕}", e.getMessage());
            }
        }
    }

這樣我們就能快速的實現(xiàn)截圖了。

以上就是JavaCV實現(xiàn)讀取視頻信息及自動截取封面圖詳解的詳細內(nèi)容,更多關(guān)于JavaCV讀取視頻信息 自動截圖的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 以實例講解Objective-C中的KVO與KVC機制

    以實例講解Objective-C中的KVO與KVC機制

    這篇文章主要介紹了以實例講解Objective-C中的KVO與KVC機制,即Key-Value-Observing與Key-Value-Coding,需要的朋友可以參考下
    2015-09-09
  • 一文詳解Java攔截器與過濾器的使用

    一文詳解Java攔截器與過濾器的使用

    這篇文章主要為大家詳細介紹了Java中攔截器與過濾器的使用與區(qū)別,文中的示例代碼講解詳細,對我們學(xué)習(xí)有一定參考價值,需要的可以參考一下
    2022-04-04
  • SpringBoot如何使用Undertow做服務(wù)器

    SpringBoot如何使用Undertow做服務(wù)器

    這篇文章主要介紹了SpringBoot如何使用Undertow做服務(wù)器,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • 詳談Array和ArrayList的區(qū)別與聯(lián)系

    詳談Array和ArrayList的區(qū)別與聯(lián)系

    下面小編就為大家?guī)硪黄斦凙rray和ArrayList的區(qū)別與聯(lián)系。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • 淺談Java多線程實現(xiàn)及同步互斥通訊

    淺談Java多線程實現(xiàn)及同步互斥通訊

    下面小編就為大家?guī)硪黄獪\談Java多線程實現(xiàn)及同步互斥通訊。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • SpringBoot war包部署到Tomcat服務(wù)器

    SpringBoot war包部署到Tomcat服務(wù)器

    這篇文章主要介紹了SpringBoot war包部署到Tomcat服務(wù)器,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • 關(guān)于spring boot整合kafka+注解方式

    關(guān)于spring boot整合kafka+注解方式

    這篇文章主要介紹了關(guān)于spring boot整合kafka+注解方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • springboot2.2 集成 activity6實現(xiàn)請假流程(示例詳解)

    springboot2.2 集成 activity6實現(xiàn)請假流程(示例詳解)

    這篇文章主要介紹了springboot2.2 集成 activity6實現(xiàn)請假完整流程示例詳解,本文通過示例代碼圖文相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • MyBatis的通俗理解:SqlSession.getMapper()源碼解讀

    MyBatis的通俗理解:SqlSession.getMapper()源碼解讀

    這篇文章主要介紹了MyBatis的通俗理解:SqlSession.getMapper()源碼解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java DriverManager.getConnection()獲取數(shù)據(jù)庫連接

    Java DriverManager.getConnection()獲取數(shù)據(jù)庫連接

    這篇文章主要介紹了Java DriverManager.getConnection()獲取數(shù)據(jù)庫連接,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評論

璧山县| 忻州市| 莱阳市| 泸溪县| 和田市| 白城市| 呈贡县| 楚雄市| 新绛县| 准格尔旗| 岐山县| 原阳县| 大方县| 齐齐哈尔市| 溧水县| 宁化县| 宜宾市| 通辽市| 广元市| 保定市| 定南县| 疏勒县| 新巴尔虎左旗| 新丰县| 淮阳县| 马尔康县| 宝兴县| 阜宁县| 梁山县| 沅江市| 广汉市| 拉萨市| 深泽县| 磐石市| 长兴县| 六安市| 双鸭山市| 垣曲县| 武汉市| 杭州市| 黄梅县|