91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaCV如何實現讀取視頻信息及自動截取封面圖

發布時間:2022-06-08 10:35:16 來源:億速云 閱讀:206 作者:iii 欄目:開發技術

這篇文章主要介紹了JavaCV如何實現讀取視頻信息及自動截取封面圖的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇JavaCV如何實現讀取視頻信息及自動截取封面圖文章都會有所收獲,下面我們一起來看看吧。

    javacv 介紹

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

    項目地址

    引入 javacv

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

    讀取視頻信息

    創建 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 {
        /**
         * 總幀數
         **/
        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();
    
                // 讀取視頻幀數
                videoInfo.setLengthInFrames(grabber.getLengthInVideoFrames());
    
    			// 讀取視頻幀率
                videoInfo.setFrameRate(grabber.getVideoFrameRate());
    
                // 讀取視頻秒數
                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 無法關閉
                        grabber.stop();
                        grabber.release();
                    }
                } catch (FFmpegFrameGrabber.Exception e) {
                    log.error("getVideoInfo grabber.release failed 獲取文件信息失敗:{}", e.getMessage());
                }
            }
        }

    截圖

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

        /**
         * 獲取視頻縮略圖
         * @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);
                //獲取幀數
                int ffLength = ff.getLengthInFrames();
                Frame f;
                int i = 0;
                //設置截取幀數
                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;
        }

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

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

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

    所以現在的問題就是如何在 javacv 中實現 -ss 參數

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

      /**
         * 隨機獲取視頻截圖
         * @param videFile 視頻文件
         * @param count 輸出截圖數量
         * @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();
                // 獲取視頻總幀數
                // int lengthInVideoFrames = grabber.getLengthInVideoFrames();
                // 獲取視頻時長, / 1000000 將單位轉換為秒
                long delayedTime = grabber.getLengthInTime() / 1000000;
    
                Random random = new Random();
                for (int i = 0; i < count; i++) {
                    // 跳轉到響應時間
                    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, "系統生成截圖", 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());
                }
            }
        }

    這樣我們就能快速的實現截圖了。

    JavaCV如何實現讀取視頻信息及自動截取封面圖

    關于“JavaCV如何實現讀取視頻信息及自動截取封面圖”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“JavaCV如何實現讀取視頻信息及自動截取封面圖”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    绥化市| 沧州市| 巢湖市| 宾川县| 迭部县| 蓬溪县| 辽中县| 嵊州市| 邯郸市| 遵义市| 南溪县| 天气| 怀仁县| 新竹县| 金昌市| 友谊县| 柞水县| 海宁市| 马龙县| 馆陶县| 霍林郭勒市| 资兴市| 班玛县| 和顺县| 五寨县| 凯里市| 齐河县| 侯马市| 资阳市| 广东省| 赣州市| 乐安县| 龙井市| 永嘉县| 城固县| 民县| 北川| 云安县| 长治县| 边坝县| 晋江市|