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

springboot整合JavaCV實(shí)現(xiàn)視頻截取第N幀并保存圖片

 更新時(shí)間:2023年08月25日 08:34:55   作者:myprincess003  
這篇文章主要為大家詳細(xì)介紹了springboot如何整合JavaCV實(shí)現(xiàn)視頻截取第N幀并保存為圖片,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下

前言

springboot(JavaCV )實(shí)現(xiàn)視頻截取第N幀并保存圖片

現(xiàn)在視頻網(wǎng)站展示列表都是用img標(biāo)簽展示的,動(dòng)圖用的是gif,但是我們上傳視頻時(shí)并沒(méi)有視屏封面,就這需要上傳到服務(wù)器時(shí)自動(dòng)生成封面并保存

本博客使用jar包的方式實(shí)現(xiàn)上傳視頻文件并且截取視頻第一幀,保存到阿里云的OSS(也可以保存到本地獲取其他任何地方)。

JavaCV 是一款開(kāi)源的視覺(jué)處理庫(kù),基于GPLv2協(xié)議,對(duì)各種常用計(jì)算機(jī)視覺(jué)庫(kù)封裝后的一組jar包,

封裝了OpenCV、libdc1394、OpenKinect、videoInput和ARToolKitPlus等計(jì)算機(jī)視覺(jué)編程人員常用庫(kù)的接口。

此方法的好處是不需要再服務(wù)器上安裝插件,直接代碼中就可以實(shí)現(xiàn)視頻截取。

我們需要截取視頻第一幀,主要用到了ffmpeg和opencv。

一 、引入jar包

我用到的maven的目前最新javacv版本,1.4.3,它應(yīng)該支持jdk1.7及以上,我項(xiàng)目用的還是jdk1.8.

不過(guò)需要注意的是在使用的過(guò)程當(dāng)中 , maven引入jar的時(shí)候 會(huì)引入所有平臺(tái)的版本

全部引入大小在五百兆左右(不建議使用)

<!--視頻截取第一幀-->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
            <version>1.4.3</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>ffmpeg-platform</artifactId>
            <version>4.0.2-1.4.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>RELEASE</version>
        </dependency>

二、java 代碼實(shí)現(xiàn)

public class ImgTools {
    //util調(diào)用application.properties
    private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle("application");
    private final static String aliyuVideonImg = RESOURCE_BUNDLE.getString("aliyun.video.img");
//    public static void main(String[] args) throws Exception {
//        ImgTools imgTools = new ImgTools();
//        System.out.println(imgTools.randomGrabberFFmpegVideoImage
//                ("視頻地址,可以是網(wǎng)絡(luò)視頻,也可以是本地視頻"));
//    }
    /**
     * 獲取視頻縮略圖
     *
     * @param filePath:視頻路徑
     * @throws Exception
     */
    public String randomGrabberFFmpegVideoImage(String filePath) throws Exception {
        String targetFilePath = "";
        FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
        ff.start();
        //判斷是否是豎屏小視頻
        String rotate = ff.getVideoMetadata("rotate");
        int ffLength = ff.getLengthInFrames();
        Frame f;
        int i = 0;
        int index = 3;//截取圖片第幾幀
        while (i < ffLength) {
            f = ff.grabImage();
            if (i == index) {
                if (null != rotate && rotate.length() > 1) {
                    targetFilePath = doExecuteFrame(f, true);   //獲取縮略圖
                } else {
                    targetFilePath = doExecuteFrame(f, false);   //獲取縮略圖
                }
                break;
            }
            i++;
        }
        ff.stop();
        return targetFilePath;  //返回的是視頻第N幀
    }
    /**
     * 截取縮略圖,存入阿里云OSS(按自己的上傳類型自定義轉(zhuǎn)換文件格式)
     *
     * @param f
     * @return
     * @throws Exception
     */
    public String doExecuteFrame(Frame f, boolean bool) throws Exception {
        if (null == f || null == f.image) {
            return "";
        }
        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage bi = converter.getBufferedImage(f);
        if (bool == true) {
            Image image = (Image) bi;
            bi = rotate(image, 90);//圖片旋轉(zhuǎn)90度
        }
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(bi, "png", os);
        byte[] sdf = os.toByteArray();
        InputStream input = new ByteArrayInputStream(os.toByteArray());
        MultipartFile multipartFile = new MockMultipartFile("temp.jpg", "temp.jpg", "temp.jpg", input);
        Aliyunoss aliyunoss = new Aliyunoss();
        //如需了解阿里云OSS,請(qǐng)?jiān)斪x我的另一篇博客("https://blog.csdn.net/weixin_44401989/article/details/105732856")
        String url = aliyunoss.uploadAli(multipartFile, aliyuVideonImg);
        return url;
    }
    /**
     * 圖片旋轉(zhuǎn)角度
     *
     * @param src   源圖片
     * @param angel 角度
     * @return 目標(biāo)圖片
     */
    public static BufferedImage rotate(Image src, int angel) {
        int src_width = src.getWidth(null);
        int src_height = src.getHeight(null);
        // calculate the new image size
        Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(
                src_width, src_height)), angel);
        BufferedImage res = null;
        res = new BufferedImage(rect_des.width, rect_des.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = res.createGraphics();
        // transform(這里先平移、再旋轉(zhuǎn)比較方便處理;繪圖時(shí)會(huì)采用這些變化,繪圖默認(rèn)從畫(huà)布的左上頂點(diǎn)開(kāi)始繪畫(huà),源圖片的左上頂點(diǎn)與畫(huà)布左上頂點(diǎn)對(duì)齊,然后開(kāi)始繪畫(huà),修改坐標(biāo)原點(diǎn)后,繪畫(huà)對(duì)應(yīng)的畫(huà)布起始點(diǎn)改變,起到平移的效果;然后旋轉(zhuǎn)圖片即可)
        //平移(原理修改坐標(biāo)系原點(diǎn),繪圖起點(diǎn)變了,起到了平移的效果,如果作用于旋轉(zhuǎn),則為旋轉(zhuǎn)中心點(diǎn))
        g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
        //旋轉(zhuǎn)(原理transalte(dx,dy)->rotate(radians)->transalte(-dx,-dy);修改坐標(biāo)系原點(diǎn)后,旋轉(zhuǎn)90度,然后再還原坐標(biāo)系原點(diǎn)為(0,0),但是整個(gè)坐標(biāo)系已經(jīng)旋轉(zhuǎn)了相應(yīng)的度數(shù) )
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
//        //先旋轉(zhuǎn)(以目標(biāo)區(qū)域中心點(diǎn)為旋轉(zhuǎn)中心點(diǎn),源圖片左上頂點(diǎn)對(duì)準(zhǔn)目標(biāo)區(qū)域中心點(diǎn),然后旋轉(zhuǎn))
//        g2.translate(rect_des.width/2,rect_des.height/ 2);
//        g2.rotate(Math.toRadians(angel));
//        //再平移(原點(diǎn)恢復(fù)到源圖的左上頂點(diǎn)處(現(xiàn)在的右上頂點(diǎn)處),否則只能畫(huà)出1/4)
//        g2.translate(-src_width/2,-src_height/2);
        g2.drawImage(src, null, null);
        return res;
    }
    /**
     * 計(jì)算轉(zhuǎn)換后目標(biāo)矩形的寬高
     *
     * @param src   源矩形
     * @param angel 角度
     * @return 目標(biāo)矩形
     */
    private static Rectangle CalcRotatedSize(Rectangle src, int angel) {
        double cos = Math.abs(Math.cos(Math.toRadians(angel)));
        double sin = Math.abs(Math.sin(Math.toRadians(angel)));
        int des_width = (int) (src.width * cos) + (int) (src.height * sin);
        int des_height = (int) (src.height * cos) + (int) (src.width * sin);
        return new java.awt.Rectangle(new Dimension(des_width, des_height));
    }
}
public class ImgTools {
    //util調(diào)用application.properties
    private final static ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle("application");
    private final static String aliyuVideonImg = RESOURCE_BUNDLE.getString("aliyun.video.img");
//    public static void main(String[] args) throws Exception {
//        ImgTools imgTools = new ImgTools();
//        System.out.println(imgTools.randomGrabberFFmpegVideoImage
//                ("視頻地址,可以是網(wǎng)絡(luò)視頻,也可以是本地視頻"));
//    }
    /**
     * 獲取視頻縮略圖
     *
     * @param filePath:視頻路徑
     * @throws Exception
     */
    public String randomGrabberFFmpegVideoImage(String filePath) throws Exception {
        String targetFilePath = "";
        FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
        ff.start();
        //判斷是否是豎屏小視頻
        String rotate = ff.getVideoMetadata("rotate");
        int ffLength = ff.getLengthInFrames();
        Frame f;
        int i = 0;
        int index = 3;//截取圖片第幾幀
        while (i < ffLength) {
            f = ff.grabImage();
            if (i == index) {
                if (null != rotate && rotate.length() > 1) {
                    targetFilePath = doExecuteFrame(f, true);   //獲取縮略圖
                } else {
                    targetFilePath = doExecuteFrame(f, false);   //獲取縮略圖
                }
                break;
            }
            i++;
        }
        ff.stop();
        return targetFilePath;  //返回的是視頻第N幀
    }
    /**
     * 截取縮略圖,存入阿里云OSS(按自己的上傳類型自定義轉(zhuǎn)換文件格式)
     *
     * @param f
     * @return
     * @throws Exception
     */
    public String doExecuteFrame(Frame f, boolean bool) throws Exception {
        if (null == f || null == f.image) {
            return "";
        }
        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage bi = converter.getBufferedImage(f);
        if (bool == true) {
            Image image = (Image) bi;
            bi = rotate(image, 90);//圖片旋轉(zhuǎn)90度
        }
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(bi, "png", os);
        byte[] sdf = os.toByteArray();
        InputStream input = new ByteArrayInputStream(os.toByteArray());
        MultipartFile multipartFile = new MockMultipartFile("temp.jpg", "temp.jpg", "temp.jpg", input);
        Aliyunoss aliyunoss = new Aliyunoss();
        //如需了解阿里云OSS,請(qǐng)?jiān)斪x我的另一篇博客("https://blog.csdn.net/weixin_44401989/article/details/105732856")
        String url = aliyunoss.uploadAli(multipartFile, aliyuVideonImg);
        return url;
    }
    /**
     * 圖片旋轉(zhuǎn)角度
     *
     * @param src   源圖片
     * @param angel 角度
     * @return 目標(biāo)圖片
     */
    public static BufferedImage rotate(Image src, int angel) {
        int src_width = src.getWidth(null);
        int src_height = src.getHeight(null);
        // calculate the new image size
        Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(
                src_width, src_height)), angel);
        BufferedImage res = null;
        res = new BufferedImage(rect_des.width, rect_des.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = res.createGraphics();
        // transform(這里先平移、再旋轉(zhuǎn)比較方便處理;繪圖時(shí)會(huì)采用這些變化,繪圖默認(rèn)從畫(huà)布的左上頂點(diǎn)開(kāi)始繪畫(huà),源圖片的左上頂點(diǎn)與畫(huà)布左上頂點(diǎn)對(duì)齊,然后開(kāi)始繪畫(huà),修改坐標(biāo)原點(diǎn)后,繪畫(huà)對(duì)應(yīng)的畫(huà)布起始點(diǎn)改變,起到平移的效果;然后旋轉(zhuǎn)圖片即可)
        //平移(原理修改坐標(biāo)系原點(diǎn),繪圖起點(diǎn)變了,起到了平移的效果,如果作用于旋轉(zhuǎn),則為旋轉(zhuǎn)中心點(diǎn))
        g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
        //旋轉(zhuǎn)(原理transalte(dx,dy)->rotate(radians)->transalte(-dx,-dy);修改坐標(biāo)系原點(diǎn)后,旋轉(zhuǎn)90度,然后再還原坐標(biāo)系原點(diǎn)為(0,0),但是整個(gè)坐標(biāo)系已經(jīng)旋轉(zhuǎn)了相應(yīng)的度數(shù) )
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
//        //先旋轉(zhuǎn)(以目標(biāo)區(qū)域中心點(diǎn)為旋轉(zhuǎn)中心點(diǎn),源圖片左上頂點(diǎn)對(duì)準(zhǔn)目標(biāo)區(qū)域中心點(diǎn),然后旋轉(zhuǎn))
//        g2.translate(rect_des.width/2,rect_des.height/ 2);
//        g2.rotate(Math.toRadians(angel));
//        //再平移(原點(diǎn)恢復(fù)到源圖的左上頂點(diǎn)處(現(xiàn)在的右上頂點(diǎn)處),否則只能畫(huà)出1/4)
//        g2.translate(-src_width/2,-src_height/2);
        g2.drawImage(src, null, null);
        return res;
    }
    /**
     * 計(jì)算轉(zhuǎn)換后目標(biāo)矩形的寬高
     *
     * @param src   源矩形
     * @param angel 角度
     * @return 目標(biāo)矩形
     */
    private static Rectangle CalcRotatedSize(Rectangle src, int angel) {
        double cos = Math.abs(Math.cos(Math.toRadians(angel)));
        double sin = Math.abs(Math.sin(Math.toRadians(angel)));
        int des_width = (int) (src.width * cos) + (int) (src.height * sin);
        int des_height = (int) (src.height * cos) + (int) (src.width * sin);
        return new java.awt.Rectangle(new Dimension(des_width, des_height));
    }
}

以上就是springboot整合JavaCV實(shí)現(xiàn)視頻截取第N幀并保存圖片的詳細(xì)內(nèi)容,更多關(guān)于springboot JavaCV視頻截取的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JAVA 使用正則提取A標(biāo)簽以及href鏈接

    JAVA 使用正則提取A標(biāo)簽以及href鏈接

    這篇文章主要介紹了JAVA 使用正則提取A標(biāo)簽以及href鏈接的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringBoot3.x集成nacos并實(shí)現(xiàn)多環(huán)境配置的操作步驟

    SpringBoot3.x集成nacos并實(shí)現(xiàn)多環(huán)境配置的操作步驟

    本文詳細(xì)介紹了如何在Springboot3.x中集成Nacos2.x版本,包括nacos的安裝、配置更改,以及在集成過(guò)程中遇到的問(wèn)題,如端口設(shè)置、依賴版本調(diào)整等,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2024-10-10
  • Java enum關(guān)鍵字不識(shí)別的快速解決辦法

    Java enum關(guān)鍵字不識(shí)別的快速解決辦法

    這篇文章主要介紹了Java enum關(guān)鍵字不識(shí)別的快速解決辦法,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧
    2016-09-09
  • Java中List使用stream流轉(zhuǎn)成map的幾種方式詳解

    Java中List使用stream流轉(zhuǎn)成map的幾種方式詳解

    Stream是Java8中處理集合的關(guān)鍵抽象概念,它可以指定你希望對(duì)集合進(jìn)行的操作,可以執(zhí)行非常復(fù)雜的查找、過(guò)濾和映射數(shù)據(jù)等操作,下面這篇文章主要給大家介紹了關(guān)于Java中List使用stream流轉(zhuǎn)成map的幾種方式,需要的朋友可以參考下
    2023-04-04
  • Java Hashtable機(jī)制深入了解

    Java Hashtable機(jī)制深入了解

    HashTable是jdk 1.0中引入的產(chǎn)物,基本上現(xiàn)在很少使用了,但是會(huì)在面試中經(jīng)常被問(wèn)到。本文就來(lái)帶大家一起深入了解一下Hashtable,需要的可以參考一下
    2022-09-09
  • 部署Nacos的源碼環(huán)境搭建過(guò)程

    部署Nacos的源碼環(huán)境搭建過(guò)程

    這篇文章主要為大家介紹了部署Nacos的源碼環(huán)境搭建過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • JAVA實(shí)現(xiàn)網(wǎng)絡(luò)/本地圖片轉(zhuǎn)BASE64存儲(chǔ)代碼示例

    JAVA實(shí)現(xiàn)網(wǎng)絡(luò)/本地圖片轉(zhuǎn)BASE64存儲(chǔ)代碼示例

    這篇文章主要給大家介紹了關(guān)于JAVA實(shí)現(xiàn)網(wǎng)絡(luò)/本地圖片轉(zhuǎn)BASE64存儲(chǔ)的相關(guān)資料,Base64是網(wǎng)絡(luò)上最常見(jiàn)的用于傳輸8Bit字節(jié)碼的編碼方式之一,Base64就是一種基于64個(gè)可打印字符來(lái)表示二進(jìn)制數(shù)據(jù)的方法,需要的朋友可以參考下
    2023-07-07
  • Spring中的@Conditional注解使用和原理詳解

    Spring中的@Conditional注解使用和原理詳解

    這篇文章主要介紹了Spring中的@Conditional注解使用和原理詳解,@Conditional在Spring4.0中被引入,用于開(kāi)發(fā)"If-Then-Else"類型的bean注冊(cè)條件檢查,在@Conditional之前,也有一個(gè)注解@Porfile起到類似的作用,需要的朋友可以參考下
    2024-01-01
  • Spring動(dòng)態(tài)加載bean后調(diào)用實(shí)現(xiàn)方法解析

    Spring動(dòng)態(tài)加載bean后調(diào)用實(shí)現(xiàn)方法解析

    這篇文章主要介紹了Spring動(dòng)態(tài)加載bean后調(diào)用實(shí)現(xiàn)方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Java中ShardingSphere分庫(kù)分表實(shí)戰(zhàn)

    Java中ShardingSphere分庫(kù)分表實(shí)戰(zhàn)

    我們做項(xiàng)目的時(shí)候,數(shù)據(jù)量比較大,單表千萬(wàn)級(jí)別的,需要分庫(kù)分表,本文主要介紹了Java中ShardingSphere分庫(kù)分表實(shí)戰(zhàn),感興趣的可以了解一下
    2021-09-09

最新評(píng)論

沾益县| 土默特左旗| 十堰市| 迭部县| 长治市| 怀仁县| 五家渠市| 眉山市| 辽宁省| 芒康县| 施秉县| 邛崃市| 静乐县| 当雄县| 西乌珠穆沁旗| 广饶县| 天台县| 临潭县| 遂昌县| 定陶县| 泸定县| 青田县| 鹰潭市| 称多县| 浙江省| 林芝县| 大港区| 牟定县| 织金县| 洛南县| 察隅县| 吴川市| 余干县| 东方市| 乐山市| 枣阳市| 松溪县| 故城县| 盐津县| 二连浩特市| 双鸭山市|