[JAVA]-视频url获取指定帧数的图片

  1. 依赖
  2. 相关代码

通过视频地址,获取指定N帧的图片,并且上传到阿里云oss

参考地址:http://www.fixbbs.com/p/01439272.html

依赖

<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>

相关代码

    @Override
    public Response upload(MultipartFile file) {
        if (file == null) {
            return Response.fail().message("缺少必要参数!");
        }

        //获取文件名加后缀
        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            return Response.fail().message("上传异常!");
        }
        //获取文件后缀
        String suffix = "";

        int index = fileName.lastIndexOf(".");
        if (index > 0) {
            suffix = file.getOriginalFilename().substring(index, fileName.length());
        }

        String contentType = file.getContentType();
        String resources = ALYConstants.OSS_PUBLIC_PICTURE + "other/";
        if (contentType != null) {
            if (contentType.contains("video")) {
                resources = ALYConstants.OSS_PUBLIC_PICTURE + "video/";
            } else if (contentType.contains("image")) {
                resources = ALYConstants.OSS_PUBLIC_PICTURE + "image/";
                if (StringUtils.isBlank(suffix)) {
                    suffix = ".jpg";
                }
            }
        }

        //组合新的文件名
        String imgName = DateUtils.dateTimeNow() + "-" + IdUtils.fastSimpleUUID() + suffix;

        resources = resources + DateUtils.dateTime() + "/";

        try {
            boolean state = this.oss(file.getBytes(), resources + imgName);
            if (!state) {
                return Response.fail().message("文件上传失败!");
            }
        } catch (IOException e) {
            log.error("【oss上传资源异常,异常信息:[{}]】", e.getMessage());
        }
        String url = ALYConstants.OSS_STATIC_MAIN_LINK + resources + imgName;

        this.insert(file, url, imgName, suffix, contentType);

        return Response.ok().content(new JSONObject() {{
            put("url", url);
        }});
    }

    @Override
    public String videoToImage(String url) throws Exception {
        String targetFilePath = "";
        FFmpegFrameGrabber grabber = FFmpegFrameGrabber.createDefault(url);
        grabber.start();

        //判断是否是竖屏小视频
        String rotate = grabber.getVideoMetadata("rotate");
        int lengthInFrames = grabber.getLengthInFrames();

        Frame frame;

        int i = 0;
        int index = 3;//截取图片第几帧
        while (i < lengthInFrames) {
            frame = grabber.grabImage();
            if (i == index) {
                if (null != rotate && rotate.length() > 1) {
                    targetFilePath = doExecuteFrame(frame, true);   //获取缩略图
                } else {
                    targetFilePath = doExecuteFrame(frame, false);   //获取缩略图
                }
                break;
            }
            i++;
        }

        grabber.stop();

        return targetFilePath;  //返回的是视频第N帧
    }

    private void insert(MultipartFile file, String url, String newName, String suffix, String contentType) {
        String memberId = memberService.infoId();

        CpFile cpFile = new CpFile();
        cpFile.setId(IdUtils.getSnowFlakeId());
        cpFile.setMemberId(memberId);
        cpFile.setName(file.getOriginalFilename());
        cpFile.setNewName(newName);
        cpFile.setUrl(url);
        cpFile.setType(contentType);
        cpFile.setSize(file.getSize());
        cpFile.setSuffix(suffix);
        cpFile.setCreateTime(DateUtils.getNowDate());
        this.baseMapper.insert(cpFile);

        log.info("【文件上传,上传用户:[{}],地址:[{}]】", memberId, url);

    }

    private boolean oss(byte[] file, String name) {
        String oss = ALYConstants.OSS_STATIC_POSITION;
        String endpoint = ALYConstants.OSS_ENDPOINT;
        String accessKeyId = ALYConstants.OSS_ACCESS_KEY;
        String accessKeySecret = ALYConstants.OSS_ACCESS_SECRET;
        try {
            //创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            //传Byte数组。
            ossClient.putObject(oss, name, new ByteArrayInputStream(file));
            //关闭OSSClient。
            ossClient.shutdown();

            return true;
        } catch (Exception e) {
            log.error("【文件上传失败,错误信息:[{}]】", e.getMessage());
        }

        return false;
    }

    /**
     * 截取缩略图,存入阿里云OSS(按自己的上传类型自定义转换文件格式)
     *
     * @return 图片地址
     * @throws Exception
     */
    public String doExecuteFrame(Frame f, boolean direction) throws Exception {
        if (null == f || null == f.image) {
            return "";
        }

        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage bi = converter.getBufferedImage(f);
        if (direction) {
            Image image = (Image) bi;
            bi = rotate(image, 90);//图片旋转90度
        }
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(bi, "png", os);

        InputStream input = new ByteArrayInputStream(os.toByteArray());
        MultipartFile multipartFile = new MockMultipartFile("temp.jpg", "temp.jpg", "temp.jpg", input);

        Response data = this.upload(multipartFile);
        Object content = data.getContent();

        return JSONObject.parseObject(String.valueOf(content)).getString("url");
    }

    /**
     * 图片旋转角度
     *
     * @param src   源图片
     * @param angel 角度
     * @return 目标图片
     */
    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 rectangle = CalcRotatedSize(new Rectangle(new Dimension(
                src_width, src_height)), angel);

        BufferedImage res;
        res = new BufferedImage(rectangle.width, rectangle.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = res.createGraphics();

        // transform(这里先平移、再旋转比较方便处理;绘图时会采用这些变化,绘图默认从画布的左上顶点开始绘画,源图片的左上顶点与画布左上顶点对齐,然后开始绘画,修改坐标原点后,绘画对应的画布起始点改变,起到平移的效果;然后旋转图片即可)
        //平移(原理修改坐标系原点,绘图起点变了,起到了平移的效果,如果作用于旋转,则为旋转中心点)
        g2.translate((rectangle.width - src_width) / 2, (rectangle.height - src_height) / 2);
        // 旋转(原理transalte(dx,dy)->rotate(radians)->transalte(-dx,-dy);修改坐标系原点后,旋转90度,然后再还原坐标系原点为(0,0),但是整个坐标系已经旋转了相应的度数 )
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
        // 先旋转(以目标区域中心点为旋转中心点,源图片左上顶点对准目标区域中心点,然后旋转)
        // g2.translate(rect_des.width/2,rect_des.height/ 2);
        // g2.rotate(Math.toRadians(angel));
        // 再平移(原点恢复到源图的左上顶点处(现在的右上顶点处),否则只能画出1/4)
        // g2.translate(-src_width/2,-src_height/2);
        g2.drawImage(src, null, null);

        return res;
    }

    /**
     * 计算转换后目标矩形的宽高
     *
     * @param src   源矩形
     * @param angel 角度
     * @return 目标矩形
     */
    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));
    }

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 xiaoxin1218@qq.com

文章标题:[JAVA]-视频url获取指定帧数的图片

文章字数:1.2k

本文作者:周信

发布时间:2021-03-17, 16:00:25

最后更新:2023-05-03, 10:25:35

原始链接:http://zx21.xyz/2021/03/17/JAVA-视频url获取指定帧数的图片/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

可为我打赏鼓励~