javaWeb截取视频中画面并保存为图片,作为视频封面

javaWeb截取视频中画面并保存为图片,作为视频封面

截取视频工具类:


```java
package com.zm.edu.util;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import com.zm.util.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;

/**
 * 描述:截取视频中图片作为封面
 * @author zwh 2021.5.18 10:25
 */

@Slf4j
public class VideoUtils {
    /**
     * main函数中slf4j无法正常显示,这里暂时使用log4j2输出日志,迁移到web项目时,建议使用slf4j
     */
    private static final org.apache.logging.log4j.Logger LOG = org.apache.logging.log4j.LogManager.getLogger();

    /**
     * 视频总帧数
     * */
    public static String VIDEO_LENGTH = "videoLength";
    /**
     *视频的宽
     */
    public static String VIDEO_WIDE = "videoWide";
    /**
     *视频的高
     */
    public static String VIDEO_HIGH = "videoHigh";
    /**
     *视频的旋转度
     */
    public static String ROTATE = "rotate";
    /**
     *视频的格式
     */
    public static String FORMAT = "format";
    /**
     *图片保存路径
     */
    public static String IMG_PATH = "imgPath";
    /**
     *图片名称
     */
    public static String IMG_NAME = "imgName";
    /**
     *此视频时长(s/秒)
     */
    public static String DURATION = "duration";
    /**
     *获取要取得的帧数
     */
    private static final int GET_FRAMES_LENGTH = 1;

    //测试使用main
//    public static void main(String[] args) {
//        Map<String, Object> screenshot = getScreenshot("C:\\Users\\zhangwenhiu\\Videos\\正能量\\日食.mp4");
//        System.out.println(screenshot.toString());
//    }

    /**
     * <h5>功能:获取一张视频截图并保存同名的jpg文件到视频同目录下</h5>
     *
     * @param filePath 视频文件全路径
     * @return
     */
    public static Map<String, Object> getScreenshot(String filePath) {
        return getScreenshot(filePath, null);
    }

    /**
     * <h5>功能:获取一张视频截图并保存同名的jpg文件到指定目录</h5>
     *
     * @param filePath 视频文件地址
     * @param saveImagePath 截图的图片存放路径(绝对路径,不包含文件名称)
     * @return
     */
    public static Map<String, Object> getScreenshot(String filePath, String saveImagePath) {
        LOG.info("视频文件[{}]截图开始", filePath);

        Map<String, Object> result = new HashMap<String, Object>();
        FFmpegFrameGrabber grabber;
        try {
            grabber = FFmpegFrameGrabber.createDefault(filePath);
            // 第一帧图片存储位置(也是视频路径)
            String targerFilePath = filePath.substring(0, filePath.lastIndexOf(FileUtils.DIR_SPERATOR));
            // 视频文件名
            String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.DIR_SPERATOR) + 1);
            // 图片名称
            String targetFileName = fileName.substring(0, fileName.lastIndexOf(FileUtils.TYPE_SEPARATOR));
            //String targetFileName =String.valueOf(System.currentTimeMillis());
            grabber.start();
            // 视频总帧数
            int videoLength = grabber.getLengthInFrames();

            Frame frame = null;
            int i = 0;
            while (i < videoLength) {
                // 过滤前5帧,避免出现全黑的图片,依自己情况而定(每循环一次取一帧)
                frame = grabber.grabFrame();
                if ((i > GET_FRAMES_LENGTH) && (frame.image != null)) {
                    break;
                }
                i++;
            }

            // 视频旋转度
            String rotate = grabber.getVideoMetadata("rotate");
            Java2DFrameConverter converter = new Java2DFrameConverter();
            // 绘制图片
            BufferedImage bi = converter.getBufferedImage(frame);
            if (rotate != null) {
                // 旋转图片
                bi = rotate(bi, Integer.parseInt(rotate));
            }
            // 图片的类型
            String imageMat = "jpg";
            // 图片的完整路径
            String imagePath = targerFilePath + File.separator + targetFileName + FileUtils.TYPE_SEPARATOR + imageMat;
            if (null != saveImagePath && !"".equals(saveImagePath)) {
                // 指定路径
                imagePath = saveImagePath + FileUtils.TYPE_SEPARATOR + imageMat;
            }

            // 创建文件
            File output = new File(imagePath);
            ImageIO.write(bi, imageMat, output);

            // 拼接Map信息
            result.put(VIDEO_LENGTH, videoLength);
            // 视频的宽
            result.put(VIDEO_WIDE, bi.getWidth());
            // 频的高
            result.put(VIDEO_HIGH, bi.getHeight());
            // 此视频时长(s/秒)
            long duration = grabber.getLengthInTime() / (1000 * 1000);
            // 视频的旋转度
            result.put(ROTATE, (null == rotate || "".equals(rotate))? "0" : rotate);
            // 视频的格式
            result.put(FORMAT, grabber.getFormat());
            result.put(IMG_PATH, output.getPath());
            result.put(DURATION, duration);
            result.put(IMG_NAME,targetFileName + FileUtils.TYPE_SEPARATOR + imageMat);
            grabber.stop();
            LOG.info("视频文件[{}]截图结束,图片地址为[{}]", filePath, imagePath);
        } catch (IOException e) {
            LOG.error("视频信息帧数处理发生异常 [{}]", e.getMessage());
            e.printStackTrace();
        }

        return result;
    }

    // ==================== private method ====================

    /**
     * <h5>功能:根据视频旋转度来调整图片</h5>
     *
     * @param src 捕获的图像
     * @param angel 视频旋转度
     * @return BufferedImage
     */
    private static BufferedImage rotate(BufferedImage src, int angel) {
        int src_width = src.getWidth(null);
        int src_height = src.getHeight(null);
        int type = src.getColorModel().getTransparency();
        Rectangle rect_des = calcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel);
        BufferedImage bi = new BufferedImage(rect_des.width, rect_des.height, type);
        Graphics2D g2 = bi.createGraphics();
        g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
        g2.drawImage(src, 0, 0, null);
        g2.dispose();
        return bi;
    }

    /**
     * <h5>功能:计算图片旋转大小</h5>
     *
     * @param src 屏幕坐标中捕获的矩形区域
     * @param angel 视频旋转度
     * @return
     */
    private static Rectangle calcRotatedSize(Rectangle src, int angel) {
        if (angel >= 90) {
            if (angel / 90 % 2 == 1) {
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel % 90;
        }
        double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
        double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
        double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
        double angel_dalta_width = Math.atan((double) src.height / src.width);
        double angel_dalta_height = Math.atan((double) src.width / src.height);
        int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width));
        int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height));
        int des_width = src.width + len_dalta_width * 2;
        int des_height = src.height + len_dalta_height * 2;
        return new java.awt.Rectangle(new Dimension(des_width, des_height));
    }
}

需要引入的maven依赖

```java
<!--获取视频第一帧画面  开始-->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
            <version>1.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacpp</artifactId>
            <version>1.5.2</version>
        </dependency>

        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>ffmpeg</artifactId>
            <version>4.2.1-1.5.2</version>
            <classifier>windows-x86_64</classifier>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>ffmpeg</artifactId>
            <version>4.2.1-1.5.2</version>
            <classifier>linux-x86_64</classifier>
        </dependency>

        <!--获取视频第一帧画面  开始-->

**注意:**参考地址1中引入的jar包会导致打包时生成的文件过大,可参考地址二进行精简,排除不必要的jar包,引入jar包时windows-x86_64可参照图片中jar包名称,根据部署环境不同选择对应版本。
在这里插入图片描述

参考转载:工具类: https://blog.csdn.net/zouliping123456/article/details/114992750
精简jar包:https://blog.csdn.net/qq_39035030/article/details/107793574

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在JavaWeb实现上传视频并播放,可以按照以下步骤进行: 1. 在前端页面添加一个文件上传的表单,并设置enctype为multipart/form-data,以支持文件上传。 2. 在后端编写一个文件上传的Servlet,接收上传的视频文件,并保存到服务器的指定位置。可以使用Apache Commons FileUpload实现文件上传功能。 3. 在上传视频的同时,还需要将视频的相关信息(如视频标题、描述、作者等)保存到数据库,以便后续的视频播放。 4. 在前端页面添加一个视频播放器,并将播放器的src属性设置为上传的视频文件的URL地址。可以使用HTML5的video标签实现视频播放功能。 下面是一个简单的示例,以上传视频信息为例: 1. 前端页面代码: ```html <form action="upload" method="post" enctype="multipart/form-data"> <label for="title">视频标题:</label> <input type="text" name="title"><br> <label for="description">视频描述:</label> <textarea name="description"></textarea><br> <label for="author">视频作者:</label> <input type="text" name="author"><br> <label for="file">上传视频文件:</label> <input type="file" name="file"><br> <input type="submit" value="上传"> </form> <video controls> <source src="video.mp4" type="video/mp4"> Your browser does not support the video tag. </video> ``` 2. 后端Servlet代码: ```java @WebServlet("/upload") @MultipartConfig public class UploadServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String title = request.getParameter("title"); String description = request.getParameter("description"); String author = request.getParameter("author"); Part filePart = request.getPart("file"); String fileName = filePart.getSubmittedFileName(); InputStream fileContent = filePart.getInputStream(); // 保存文件到服务器指定位置 String filePath = "C:/videos/" + fileName; Files.copy(fileContent, Paths.get(filePath), StandardCopyOption.REPLACE_EXISTING); // 将视频信息保存到数据库 Connection conn = null; PreparedStatement stmt = null; try { conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "password"); String sql = "INSERT INTO videos (title, description, author, file_path) VALUES (?, ?, ?, ?)"; stmt = conn.prepareStatement(sql); stmt.setString(1, title); stmt.setString(2, description); stmt.setString(3, author); stmt.setString(4, filePath); stmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { try { if (stmt != null) stmt.close(); if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } // 返回上传成功的提示信息 response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); response.getWriter().write("上传成功!"); } } ``` 在以上示例,我们使用了MySQL数据库来保存上传的视频信息,需要先在MySQL创建一个名为mydb的数据库,并创建一个名为videos的表,包含以下字段: - id:视频ID,自增长 - title:视频标题 - description:视频描述 - author:视频作者 - file_path:视频文件在服务器的路径 3. 播放视频 在前端页面的视频播放器,我们可以将视频的src属性设置为服务器视频文件路径,如下所示: ```html <video controls> <source src="C:/videos/video.mp4" type="video/mp4"> Your browser does not support the video tag. </video> ``` 注意:在实际开发,我们应该将视频文件保存Web应用程序的根目录下,以便可以通过相对路径来访问视频文件。同时,为了保证视频能够在不同浏览器正常播放,应该提供多种格式的视频文件,如MP4、WebM、Ogg等。可以使用FFmpeg等工具将视频文件转换为不同格式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值