从视频中截取指定帧图片

这篇具有很好参考价值的文章主要介绍了从视频中截取指定帧图片。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:
我们在很多时候需要对视频文件进行分析,或者对视频产生缩略图。因此视频截取技术必不可少。文章来源地址https://www.toymoban.com/news/detail-820041.html

从本地文件中读取视频帧

导包

 		<dependency>
            <groupId>org.jcodec</groupId>
            <artifactId>jcodec</artifactId>
            <version>0.2.5</version>
        </dependency>
        <dependency>
            <groupId>org.jcodec</groupId>
            <artifactId>jcodec-javase</artifactId>
            <version>0.2.5</version>
        </dependency>
        <!-- http://repo1.maven.org/maven2/commons-io/commons-io/2.6/commons-io-2.6.jar -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

读取视频帧工具类

package com.wkl.testdemo.vedio;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.jcodec.api.FrameGrab;
import org.jcodec.api.JCodecException;
import org.jcodec.common.model.Picture;
import org.jcodec.scale.AWTUtil;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.UUID;

/**
 * 视频操作工具类
 */
@Slf4j
public class VideoUtils {
 
    /*** 图片格式*/
    private static final String FILE_EXT = "jpg";
 
    /*** 帧数-第几帧*/
    private static final int THUMB_FRAME = 500;
 
    /**
     * 获取指定视频的帧并保存为图片至指定目录
     *
     * @param videoFilePath 源视频文件路径
     * @param frameFilePath 截取帧的图片存放路径
     */
    public static void fetchFrame(String videoFilePath, String frameFilePath) throws Exception {
        File videoFile = new File(videoFilePath);
        File frameFile = new File(frameFilePath);
        getThumbnail(videoFile, frameFile);
    }
 
    /**
     * 获取指定视频的帧并保存为图片至指定目录
     *
     * @param videoFile  源视频文件
     * @param targetFile 截取帧的图片
     */
    public static void fetchFrame(MultipartFile videoFile, File targetFile) throws Exception {
        File file = new File(videoFile.getName());
        FileUtils.copyInputStreamToFile(videoFile.getInputStream(), file);
        getThumbnail(file, targetFile);
    }
 
    /**
     * 获取指定视频的帧并保存为图片至指定目录
     *
     * @param videoFile 源视频文件
     */
    public static File fetchFrame(MultipartFile videoFile) {
        String originalFilename = videoFile.getOriginalFilename();
        File file = new File(originalFilename);
        File targetFile = null;
        try {
            FileUtils.copyInputStreamToFile(videoFile.getInputStream(), file);
 
            int i = originalFilename.lastIndexOf(".");
            String imageName;
 
            if (i > 0) {
                imageName = originalFilename.substring(0, i);
            } else {
                imageName = UUID.randomUUID().toString().replace("-", "");
            }
            imageName = imageName + ".jpg";
            targetFile = new File(imageName);
            getThumbnail(file, targetFile);
        } catch (Exception e) {
            log.error("获取视频指定帧异常:", e);
        } finally {
            if (file.exists()) {
                file.delete();
            }
        }
        log.debug("视频文件 - 帧截取 - 处理结束");
        return targetFile;
    }
 
    /**
     * 获取第一帧缩略图
     *
     * @param videoFile  视频路径
     * @param targetFile 缩略图目标路径
     */
    public static void getThumbnail(File videoFile, File targetFile) {
        try {
            // 根据扩展名创建一个新文件路径
            Picture picture = FrameGrab.getFrameFromFile(videoFile, THUMB_FRAME);
            BufferedImage bufferedImage = AWTUtil.toBufferedImage(picture);
            ImageIO.write(bufferedImage, FILE_EXT, targetFile);
        } catch (IOException | JCodecException e) {
            e.printStackTrace();
            log.error("获取第一帧缩略图异常:", e);
        }
    }
 
    public static void main(String[] args) {
        try {
            long startTime = System.currentTimeMillis();
            getThumbnail(new File("D:\\Videos\\2023112911533869304715.mp4"), new File("D:\\Videos\\test1.jpg"));

            System.out.println("截取图片耗时:" + (System.currentTimeMillis() - startTime));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void saveImage(String imageUrl, String destinationFile) throws IOException {
        URL url = new URL(imageUrl);
        InputStream is = url.openStream();
        OutputStream os = new FileOutputStream(destinationFile);

        byte[] b = new byte[2048];
        int length;

        while ((length = is.read(b)) != -1) {
            os.write(b, 0, length);
        }

        is.close();
        os.close();
    }
 
}

从网络url 读取视频帧-ffmpeg

导包

 <!-- 获取视频第一帧依赖 -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacpp</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>ffmpeg-platform</artifactId>
            <version>3.4.2-1.4.1</version>
        </dependency>

工具类

package com.wkl.testdemo.vedio;

import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;
 
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
 
/**
 * 视频抽帧工具
 */
@Slf4j
public class VideoFrame {


    //传入包含特定时间的Frame ,读取图片
    public static BufferedImage doExecuteFrame(Frame frame, int index) {
        if (frame == null || frame.image == null) {
            return null;
        }
        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage bi = converter.getBufferedImage(frame);
        return bi;
    }

    /*
     * @description:  读取视频第n秒的图片帧
     * @author: wangkanglu
     * @date: 2023/12/8 15:05
     * @param: [videoUrl, stepSecond]
     * @return: java.awt.image.BufferedImage
     **/
    public static BufferedImage doExecuteFrameByTime(String videoUrl, Integer stepSecond) {
        FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoUrl);
        ff.setOption("timeout", "40000000");
        long timestamp =  stepSecond * 1000000L;    //视频是按照微秒计算的,10的6次方分之一秒
        try {
            ff.start();
            ff.setTimestamp(timestamp);
            Frame frame = ff.grabImage();
            if (frame == null || frame.image == null) {
                return null;
            }
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage bi = converter.getBufferedImage(frame);
            ff.stop();
            return bi;
        } catch (FrameGrabber.Exception e) {
            throw new RuntimeException(e);
        }

    }
 
    /**
     * 视频文件边下载边抽帧1秒1帧
     *
     * @param videoUrl   网络视频文件URL
     * @param stepSecond 每隔几秒取一帧,默认1s
     * @param count      需要截取的帧个数
     * @return
     */
    public static Map<Integer, BufferedImage> videoUrlIntercept(String videoUrl, Integer stepSecond, Integer count) {
        Map<Integer, BufferedImage> files = new HashMap<>();
        stepSecond = stepSecond == null ? 1 : stepSecond;
        FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoUrl);
        // 设置超时时间为40秒
        ff.setOption("timeout", "40000000");
//        ff.setOption("user_agent", UserAgent.getUserAgent());
 
        try {
            ff.start();
            long timeLength = ff.getLengthInTime();
            Frame frame = ff.grabImage();
            long startTime = frame.timestamp;
            long timestamp = 0; //视频的当前时长
            int second = 0;  //过了几个时间间隔
            int picNum = 0;//第n张帧
            while (timestamp <= timeLength) {
                log.info("抽取第{}帧,video_url:{}",picNum,videoUrl);
                timestamp = startTime + second * 1000000L;    //视频是按照微秒计算的,10的6次方分之一秒
                ff.setTimestamp(timestamp);
                frame = ff.grabImage();
                if (frame != null) {
                    if (frame.image != null) {
                        BufferedImage bufferedImage = doExecuteFrame(frame, picNum);
                        if (bufferedImage != null) {
                            files.put(picNum, bufferedImage);
                        }
                        picNum++;
                        if (count != null && picNum == count) {
                            break;
                        }
                    }
                }
                second += stepSecond;
                if(picNum > 60) {
                    break;
                }
            }
            ff.stop();
 
        } catch (Exception e) {
            log.error("下载抽帧失败,ipPort:{},videoUrl:{},msg:{}", null, videoUrl, e.getMessage());
            e.printStackTrace();
        }
 
        return files;
    }
 
    /**
     * 视频文件指定时间段的帧截取
     *
     * @param videoUrl  视频文件URL
     * @param start     视频开始的帧
     * @param count     需要截取的帧个数
     * @param isAvgTime 在截帧时 是否均匀分布计算时间
     * @return
     */
    public static Map<Integer, BufferedImage> videoIntercept(String videoUrl, int start, int count, boolean isAvgTime) {
        log.info("开始抽取视频帧数,videoUrl:{}",videoUrl);
        Frame frame = null;
        //<时间, 图片流>
        Map<Integer, BufferedImage> files = new HashMap<>();
        FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(videoUrl);
        fFmpegFrameGrabber.setOption("timeout", "40000000");
 
        try {
            fFmpegFrameGrabber.start();
            long frameTime = 1;
            if (isAvgTime) {
                frameTime = fFmpegFrameGrabber.getLengthInTime() / count / 1000000L;
                if (frameTime < 0) {
                    frameTime = 1;
                }
            }
            for (int i = start; i <= count; i++) {
                fFmpegFrameGrabber.setTimestamp(i * frameTime * 1000 * 1000);
                frame = fFmpegFrameGrabber.grabImage();
                BufferedImage bufferedImage = doExecuteFrame(frame, i);
                if (bufferedImage != null) {
                    files.put(i, bufferedImage);
                }
            }
            fFmpegFrameGrabber.stop();
        } catch (Exception E) {
            log.info("下载的视频抽帧失败,msg:" + E.getMessage());
            E.printStackTrace();
        }
        return files;
    }

    

    /*
     * @description:  BufferedImage 转 inputStream
     * @author: wangkanglu
     * @date: 2023/12/8 14:52
     * @param: [image]
     * @return: java.io.InputStream
     **/
    public static InputStream bufferedImageToInputStream(BufferedImage image) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "jpg", os);
            InputStream input = new ByteArrayInputStream(os.toByteArray());
            return input;
        } catch (IOException e) {
        }
        return null;
    }
 
    public static void main(String[] args) throws IOException {
        String videoUrl = "http://vd2.bdstatic.com/mda-pej1ztfufz8axvtu/360p/h264/1684545921389774683/mda-pej1ztfufz8axvtu.mp4";
        Map<Integer, BufferedImage> integerInputStreamMap = videoUrlIntercept(videoUrl, 1, 13);
        System.out.println(integerInputStreamMap.size());
        for (Integer seconds : integerInputStreamMap.keySet()) {
            BufferedImage bufferedImage = integerInputStreamMap.get(seconds);
            String fileName = System.currentTimeMillis()+"抖音测试3" + "_" + seconds + ".jpg";
            String filePath = "D:\\Videos\\"+fileName;
            //本地磁盘存储
            // 本地图片保存地址
            ImageIO.write(bufferedImage, "png", new File(filePath));
 
            System.out.println("seconds: " + seconds + ", uploadURL: " + filePath);
        }
 
    }
}

附赠压缩图片工具类


package com.wkl.testdemo.vedio;

import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.stereotype.Component;

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

@Slf4j
@Component
public class VideoFrameGrabber {

    public static void main(String[] args) throws Exception {
        // 视频地址
        String vedioUrl = "http://vd2.bdstatic.com/mda-pej1ztfufz8axvtu/360p/h264/1684545921389774683/mda-pej1ztfufz8axvtu.mp4";
        BufferedImage image = doExecuteFrameByTime(vedioUrl, 10);
        double targetSize = 10*1024;
        while (imageToBytes(image).length > targetSize) {
            float reduceMultiple = 0.5f;
            image = resizeImage(image, reduceMultiple);
        }
        // 本地图片保存地址
        ImageIO.write(image, "png", new File("D:\\Videos\\test6.jpg"));

    }



    /*
     * @description:  读取视频第n秒的图片帧
     * @author: wangkanglu
     * @date: 2023/12/8 15:05
     * @param: [videoUrl, stepSecond]
     * @return: java.awt.image.BufferedImage
     **/
    public static BufferedImage doExecuteFrameByTime(String videoUrl, Integer stepSecond) {
        FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoUrl);
        ff.setOption("timeout", "40000000");
        long timestamp =  stepSecond * 1000000L;    //视频是按照微秒计算的,10的6次方分之一秒
        try {
            ff.start();
            ff.setTimestamp(timestamp);
            Frame frame = ff.grabImage();
            if (frame == null || frame.image == null) {
                return null;
            }
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage bi = converter.getBufferedImage(frame);
            ff.stop();
            return bi;
        } catch (FrameGrabber.Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 通过BufferedImage图片流调整图片大小
     * 指定压缩后长宽
     */
    public static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws IOException {
        Image resultingImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_AREA_AVERAGING);
        BufferedImage outputImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
        outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
        return outputImage;
    }

    /**
     * 通过BufferedImage图片流调整图片大小
     * @param originalImage
     * @param reduceMultiple 缩小倍数
     * @return
     * @throws IOException
     */
    public static BufferedImage resizeImage(BufferedImage originalImage, float reduceMultiple) throws IOException {
        int width = (int) (originalImage.getWidth() * reduceMultiple);
        int height = (int) (originalImage.getHeight() * reduceMultiple);
        Image resultingImage = originalImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
        BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
        return outputImage;
    }

    /**
     * 压缩图片到指定大小
     * @param srcImgData
     * @param reduceMultiple 每次压缩比率
     * @return
     * @throws IOException
     */
    public static byte[] resizeImage(byte[] srcImgData, float reduceMultiple) throws IOException {
        BufferedImage bi = ImageIO.read(new ByteArrayInputStream(srcImgData));
        int width = (int) (bi.getWidth() * reduceMultiple); // 源图宽度
        int height = (int) (bi.getHeight() * reduceMultiple); // 源图高度
        Image image = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = tag.getGraphics();
        g.setColor(Color.RED);
        g.drawImage(image, 0, 0, null); // 绘制处理后的图
        g.dispose();
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        ImageIO.write(tag, "JPEG", bOut);
        return bOut.toByteArray();
    }


    /**
     * BufferedImage图片流转byte[]数组
     */
    public static byte[] imageToBytes(BufferedImage bImage) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            ImageIO.write(bImage, "jpg", out);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return out.toByteArray();
    }


    /**
     * byte[]数组转BufferedImage图片流
     */
    private static BufferedImage bytesToBufferedImage(byte[] ImageByte) {
        ByteArrayInputStream in = new ByteArrayInputStream(ImageByte);
        BufferedImage image = null;
        try {
            image = ImageIO.read(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return image;
    }

}


到了这里,关于从视频中截取指定帧图片的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • get两个js小技能——JS截取视频第一帧&图片转Base64

    由于开发之前做的VisualDrag拖拽模板优化的时候,拖拽进去的图片、视频文件等需要进行截图作为封面,目前采用的截图方法是htme2canvas,使用canvas进行的截图操作,所以就会遇到这样的问题,视频和图片图床简单的使用标签加入canvas画布里面无法正确的截图成功。最后采取的

    2024年02月12日
    浏览(37)
  • opencv视频截取每一帧并保存为图片python代码CV2实现练习

    当涉及到视频处理时,Python中的OpenCV库提供了强大的功能,可以方便地从视频中截取每一帧并将其保存为图片。这是一个很有趣的练习,可以让你更深入地了解图像处理和多媒体操作。 使用OpenCV库,你可以轻松地读取视频文件,并在循环中逐帧读取视频的每一帧。随后,你可

    2024年02月12日
    浏览(55)
  • 从视频中截取指定帧图片

    前言: 我们在很多时候需要对视频文件进行分析,或者对视频产生缩略图。因此视频截取技术必不可少。

    2024年01月24日
    浏览(32)
  • Java实现截取视频第一帧

    目录 前言 一、通过Java借助第三方库实现 1.引用ffmpeg 使用maven,导入pom依赖:  工具类 2.引用jcodec 二、使用第三方存储自带的方法实现(如阿里云OSS、华为云OBS) 在实际项目中,会遇到上传视频后,需要截取视频的首帧或指定帧为图片,作为展示使用的需求。这个需求本身

    2024年02月06日
    浏览(43)
  • 前端截取视频第一帧作为封面

    概述 1.做项目的时候突然想截取视频第一帧,作为视频的封面,然后搜了很多博客都发现得到空白的图片,最后得到了解决。 2.方法:通过创建canvas标签,利用其drawImage() 方法在画布上绘制该视频,然后运用toDataURL方法转换canvas上的图片为base64格式,并将base64格式的图片作为

    2023年04月23日
    浏览(43)
  • FFmpeg批量提取视频的某一帧作为封面

    命令是这样的: 说明: -i input.flv 截取的视频的名字 -ss 00:00:02 这是视频的第2秒 -frames:v 1 这代表单独这1帧 out.png 要保存的截取的封面文件 整个命令实现的是:截取input视频从第2秒,然后只截取这1帧,作为画面,保存到out.png 上面这个已经满足了我想批量生成视频封面的目

    2024年02月09日
    浏览(44)
  • 提取视频中的某一帧画面,留住视频中的美好瞬间

    你是否曾经被视频中的某一帧画面深深吸引,却又惋惜于无法将其永久保存?现在,有了我们【媒体梦工厂】,这一遗憾将成为过去,这个软件可以提取视频中的某一帧保存为图片,为你留住那些稍纵即逝的美好。 所需工具: 一个【媒体梦工厂】软件 视频素材 操作步骤:

    2024年01月25日
    浏览(42)
  • vue实现截取视频第一帧作为封面

    在Vue中实现截取视频第一帧作为视频封面可以通过以下步骤: 在Vue组件中引入video.js和videojs-contrib-hls插件。 在Vue组件中声明一个video元素,并给其添加id。 在Vue组件中初始化video.js插件,并监听loadedmetadata事件。 编写captureVideoThumbnail方法来截取视频第一帧。 在Vue组件中使用

    2024年02月12日
    浏览(39)
  • 纯前端播放文件流视频并预览并截取视频第一帧

    1、把文件流转为本地可以播放地址 调用 getFileURL 并传入文件流会返回一个地址,将地址赋值给 video 的 src 即可播放视频,无需上传至服务器。 2、截取视频第一帧 调用 getVideoBase64 并将第一步得到的url转给 getVideoBase64 即可得到视频第一帧图片, getVideoBase64 返回的片为 base64

    2023年04月09日
    浏览(40)
  • js(ts)截取视频第一帧作为封面图

    直接上代码: 这里有三个地方需要注意: 1. 需要加上 preload 属性 这是防止截图结果为黑屏的关键一步 2. canvas宽高的设置 网络上其它文章的代码都直接读取 video.width 和 video.height ,会导致如果是竖视频截取出来的封面图在横显示时会变形 3. 判断图片有效性 有时候截取到的图

    2024年02月10日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包