Java獲取視頻第一幀做為封面圖片

POM依賴

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv</artifactId>
    <version>0.8</version>
</dependency>

工具類

VideoCaptureUtils

package com.hsqyz.video.utils;

import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

/**
 * 視頻截取指定幀圖片
 */
@Slf4j
public class VideoCaptureUtils {

    /*默認(rèn)圖片格式 jpg*/
    public static String DEFAULT_IMG_FORMAT = "jpg";
    /*圖片格式 png*/
    public static String IMG_FORMAT_PNG = "png";
    /*圖片格式 jpg*/
    public static String IMG_FORMAT_JPG = "jpg";
    /*第一幀*/
    public final static int FIRST = 0;
    /*最后一幀*/
    public final static int LAST = Integer.MAX_VALUE;

    /**
     * 獲取指定視頻的幀并保存為圖片JPG格式至指定文件
     *
     * @param videoFile  源視頻文件路徑
     * @param targetFile 截取幀的圖片存放路徑
     * @param frameNum   截取第幾幀
     * @throws Exception
     */
    public static void fetchFrameToFile(String videoFile, String targetFile, int frameNum) throws FrameGrabber.Exception, IOException {
        //校驗(yàn)輸入和輸出
        checkInAnOut(videoFile, targetFile);
        try {
            File frameFile = new File(targetFile);
            FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile);
            ff.start();
            int length = ff.getLengthInFrames();
            /*第幾幀判斷設(shè)置*/
            if (frameNum < 0) {
                frameNum = 0;
            }
            if (frameNum > length) {
                frameNum = length - 5;
            }
            //指定第幾幀
            ff.setFrameNumber(frameNum);
            int i = 0;
            Frame f = null;
            while (i < length) {
                // 過濾前5幀裂明,避免出現(xiàn)全黑的圖片,依自己情況而定
                f = ff.grabFrame();
                if ((i >= 5) && (f.image != null)) {
                    break;
                }
                i++;
            }
            opencv_core.IplImage img = f.image;
            int width = img.width();
            int height = img.height();
            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
            bi.getGraphics().drawImage(f.image.getBufferedImage().getScaledInstance(width, height, Image.SCALE_SMOOTH),
                    0, 0, null);
            ff.flush();
            ff.stop();
            ImageIO.write(bi, DEFAULT_IMG_FORMAT, frameFile);
        } catch (Exception e) {
            throw new RuntimeException("轉(zhuǎn)換視頻圖片異常");
        }

    }

    /**
     * 獲取指定視頻的幀并保存為圖片自定義類型至指定文件
     *
     * @param videoFile  源視頻文件路徑
     * @param targetFile 截取幀的圖片存放文件路徑
     * @param outImgFormat 輸出圖片格式
     * @param frameNum   截取第幾幀
     * @throws Exception
     */
    public static void fetchFrameToFile(String videoFile, String targetFile, String outImgFormat, int frameNum) throws FrameGrabber.Exception, IOException {
        //校驗(yàn)輸入和輸出
        checkInAnOut(videoFile, targetFile);
        try {
            File frameFile = new File(targetFile);
            FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile);
            ff.start();
            int length = ff.getLengthInFrames();
            /*第幾幀判斷設(shè)置*/
            if (frameNum < 0) {
                frameNum = 0;
            }
            if (frameNum > length) {
                frameNum = length - 5;
            }
            //指定第幾幀
            ff.setFrameNumber(frameNum);
            int i = 0;
            Frame f = null;
            while (i < length) {
                // 過濾前5幀蚣驼,避免出現(xiàn)全黑的圖片望艺,依自己情況而定
                f = ff.grabFrame();
                if ((i >= 5) && (f.image != null)) {
                    break;
                }
                i++;
            }
            opencv_core.IplImage img = f.image;
            int width = img.width();
            int height = img.height();
            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
            bi.getGraphics().drawImage(f.image.getBufferedImage().getScaledInstance(width, height, Image.SCALE_SMOOTH),
                    0, 0, null);
            ff.flush();
            ff.stop();
            ImageIO.write(bi, outImgFormat, frameFile);
        } catch (Exception e) {
            throw new RuntimeException("轉(zhuǎn)換視頻圖片異常");
        }
    }

    /**
     * 獲取指定視頻的幀圖片,并轉(zhuǎn)換為base64字符串
     *
     * @param videoFile 源視頻文件路徑
     * @param frameNum  截取第幾幀
     * @throws Exception
     */
    public static String fetchFrameToBase64(String videoFile, int frameNum) throws FrameGrabber.Exception, IOException {
        //校驗(yàn)輸入
        checkVideoFile(videoFile);
        try (ByteArrayOutputStream output = new ByteArrayOutputStream();) {
            FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile);
            ff.start();
            int length = ff.getLengthInFrames();
            /*第幾幀判斷設(shè)置*/
            if (frameNum < 0) {
                frameNum = 0;
            }
            if (frameNum > length) {
                frameNum = length - 5;
            }
            //指定第幾幀
            ff.setFrameNumber(frameNum);
            int i = 0;
            Frame f = null;
            while (i < length) {
                // 過濾前5幀唯笙,避免出現(xiàn)全黑的圖片螟蒸,依自己情況而定
                f = ff.grabFrame();
                if ((i >= 5) && (f.image != null)) {
                    break;
                }
                i++;
            }
            opencv_core.IplImage img = f.image;
            int width = img.width();
            int height = img.height();
            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
            bi.getGraphics().drawImage(f.image.getBufferedImage().getScaledInstance(width, height, Image.SCALE_SMOOTH),
                    0, 0, null);
            ImageIO.write(bi, DEFAULT_IMG_FORMAT, output);
            // 這里需要獲取圖片的base64數(shù)據(jù)串盒使,所以將圖片寫到流里面
            ff.flush();
            ff.stop();
            return new BASE64Encoder().encode(output.toByteArray());
        } catch (Exception e) {
            throw new RuntimeException("轉(zhuǎn)換視頻圖片異常");
        }
    }


    /**
     * 校驗(yàn)輸入輸出
     *
     * @param videoFile
     * @param targetFile
     */
    public static void checkInAnOut(String videoFile, String targetFile) {
        checkVideoFile(videoFile);
        checkTargetFileDir(targetFile);
    }

    /**
     * 驗(yàn)證文件目錄是否存在,不存在就創(chuàng)建
     *
     * @param targetFile 文件路徑
     * @return
     */
    public static void checkTargetFileDir(String targetFile) {
        String dirPath = targetFile.substring(0, targetFile.lastIndexOf(File.separator) + 1);
        File dir = new File(dirPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
    }

    /**
     * 檢驗(yàn)文件是否存在
     *
     * @param videoFile
     */
    public static void checkVideoFile(String videoFile) {
        File file = new File(videoFile);
        if (!file.exists()) {
            throw new RuntimeException("文件不存在");
        }
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末七嫌,一起剝皮案震驚了整個(gè)濱河市少办,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌诵原,老刑警劉巖英妓,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異绍赛,居然都是意外死亡鞋拟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門惹资,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贺纲,“玉大人,你說我怎么就攤上這事褪测『锾埽” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵侮措,是天一觀的道長懈叹。 經(jīng)常有香客問我,道長分扎,這世上最難降的妖魔是什么澄成? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮畏吓,結(jié)果婚禮上墨状,老公的妹妹穿的比我還像新娘。我一直安慰自己菲饼,他們只是感情好肾砂,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宏悦,像睡著了一般镐确。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上饼煞,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天源葫,我揣著相機(jī)與錄音,去河邊找鬼砖瞧。 笑死息堂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芭届。 我是一名探鬼主播储矩,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼感耙,長吁一口氣:“原來是場噩夢啊……” “哼褂乍!你這毒婦竟也來了持隧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤逃片,失蹤者是張志新(化名)和其女友劉穎屡拨,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體褥实,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡呀狼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了损离。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哥艇。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖僻澎,靈堂內(nèi)的尸體忽然破棺而出貌踏,到底是詐尸還是另有隱情浩蓉,我是刑警寧澤竹观,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布迫摔,位于F島的核電站棺聊,受9級特大地震影響恩急,放射性物質(zhì)發(fā)生泄漏掖看。R本人自食惡果不足惜芹枷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一弟孟、第九天 我趴在偏房一處隱蔽的房頂上張望汁咏。 院中可真熱鬧亚斋,春花似錦、人聲如沸攘滩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轰驳。三九已至厚掷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間级解,已是汗流浹背冒黑。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勤哗,地道東北人抡爹。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像芒划,于是被迫代替她去往敵國和親冬竟。 傳聞我的和親對象是個(gè)殘疾皇子欧穴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容