FFmpeg截屏、剪切一段视频、或者压缩视频

这篇具有很好参考价值的文章主要介绍了FFmpeg截屏、剪切一段视频、或者压缩视频。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

网上大多是通过命令的显示操作ffmpeg,不太灵活
这里我给出剪切视频的一段代码,缺点是无法精确,比如我想剪切20秒,但是可能剪切好的是23秒。
其中FFmpegFrameRecorder(outputstream)操作流会报错。原因未知。

import cn.hutool.core.io.FileUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.util.MapUtil;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;
import org.opencv.video.Video;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.;
import java.security.SecureRandom;
import java.util.
;

@Slf4j
public class VideoUtils {

public static void main(String[] args) throws Exception {

// t1();
cutVideo(new FileInputStream(“C:\Users\Xpdn\Videos\3.mp4”),
new File(“C:\Users\Xpdn\Videos\output.mp4”), 30L, 900L);

// t2();
}

public static File cutVideo(InputStream inputStream, File outFile, long beginSecond, long endSecond) throws Exception {
    FFmpegFrameGrabber grabber = null;
    FFmpegFrameRecorder recorder = null;
    try {
        grabber = new FFmpegFrameGrabber(inputStream);
        grabber.start();
        if (beginSecond < 0 || (grabber.getLengthInTime() / 1000000L) <= endSecond) {
            return null;
        }
        long numFrame = (long) ((endSecond - beginSecond) * grabber.getFrameRate()) * 2; // 120 * 25

// grabber.setVideoTimestamp(beginSecond * 1000000L);
grabber.setVideoFrameNumber((int) (grabber.getFrameRate() * beginSecond)); // 第分钟开始

        recorder = new FFmpegFrameRecorder(outFile, grabber.getImageWidth(), grabber.getImageHeight());
        recorder.setFormat("mp4");
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        recorder.setVideoBitrate(grabber.getVideoBitrate());
        recorder.setFrameRate(grabber.getFrameRate());
        recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
        recorder.setAudioChannels(2);
        recorder.start();

        Frame frame;
        long num = 0;
        while ((frame = grabber.grabFrame()) != null && (numFrame >= num)) {
            num++;
            // 处理每一帧的图像或音频数据
            recorder.record(frame);
        }
        return outFile;
    }catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (grabber != null) {
                grabber.stop();
                grabber.release();
            }
            if (recorder != null) {
                recorder.stop();
                recorder.release();
            }
        } catch (FFmpegFrameGrabber.Exception e1) {
            e1.printStackTrace();
        }
    }
    return null;
}

我的完整的工具类

package com.ruoyi.file.utils;

import cn.hutool.core.io.FileUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.util.MapUtil;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;
import org.opencv.video.Video;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.;
import java.security.SecureRandom;
import java.util.
;

@Slf4j
public class VideoUtils {

public static void main(String[] args) throws Exception {

// t1();
cutVideo(new FileInputStream(“C:\Users\Xpdn\Videos\3.mp4”),
new File(“C:\Users\Xpdn\Videos\output.mp4”), 30L, 900L);

// t2();
}

public static File cutVideo(InputStream inputStream, File outFile, long beginSecond, long endSecond) throws Exception {
    FFmpegFrameGrabber grabber = null;
    FFmpegFrameRecorder recorder = null;
    try {
        grabber = new FFmpegFrameGrabber(inputStream);
        grabber.start();
        if (beginSecond < 0 || (grabber.getLengthInTime() / 1000000L) <= endSecond) {
            return null;
        }
        long numFrame = (long) ((endSecond - beginSecond) * grabber.getFrameRate()) * 2; // 120 * 25

// grabber.setVideoTimestamp(beginSecond * 1000000L);
grabber.setVideoFrameNumber((int) (grabber.getFrameRate() * beginSecond)); // 第1分钟开始

        recorder = new FFmpegFrameRecorder(outFile, grabber.getImageWidth(), grabber.getImageHeight());
        recorder.setFormat("mp4");
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        recorder.setVideoBitrate(grabber.getVideoBitrate());
        recorder.setFrameRate(grabber.getFrameRate());
        recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
        recorder.setAudioChannels(2);
        recorder.start();

        Frame frame;
        long num = 0;
        while ((frame = grabber.grabFrame()) != null && (numFrame >= num)) {
            num++;
            // 处理每一帧的图像或音频数据
            recorder.record(frame);
        }
        return outFile;
    }catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (grabber != null) {
                grabber.stop();
                grabber.release();
            }
            if (recorder != null) {
                recorder.stop();
                recorder.release();
            }
        } catch (FFmpegFrameGrabber.Exception e1) {
            e1.printStackTrace();
        }
    }
    return null;
}


public static void t2() throws Exception {

// OutputStream outputStream = new FileOutputStream(“C:\Users\Xpdn\Videos\1xxx.mp4”);
OutputStream outputStream = new ByteArrayOutputStream(1024102410);

    FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("C:\\Users\\Xpdn\\Videos\\1.mp4");
    grabber.start();
    long beginSecond = 60;
    long endSecond = 120;
    long numFrame = (long) ((endSecond - beginSecond) * grabber.getFrameRate());// 60 * 25
    grabber.setVideoTimestamp(beginSecond * 1000000L);
    //grabber.setVideoFrameNumber((int) (25 * beginSecond)); // 2分钟开始
    File file = new File("C:\\Users\\Xpdn\\Videos\\1xxx.mp4");
    FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputStream, grabber.getImageWidth(),
            grabber.getImageHeight(), grabber.getAudioChannels());
    recorder.setFormat("mp4");

// recorder.setOption();
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
recorder.setVideoBitrate(grabber.getVideoBitrate());
recorder.setFrameRate(grabber.getFrameRate());
recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
recorder.start();

    Frame frame;

    long num = 0;
    while ((frame = grabber.grabFrame()) != null && (numFrame >= num)) {
        num++;
        // 处理每一帧的图像或音频数据
        recorder.record(frame);
    }

    recorder.stop();
    recorder.release();
}

public static void t1() throws Exception {
    FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("C:\\Users\\Xpdn\\Videos\\VCG42N1340724607.mp4");
    avutil.av_log_set_level(avutil.AV_LOG_ERROR);
    FFmpegLogCallback.set();

    grabber.start();
    int lengthInVideoFrames = grabber.getLengthInVideoFrames();
    long lengthInTime = grabber.getLengthInTime();
    double videoFrameRate = grabber.getVideoFrameRate();
    grabber.setVideoTimestamp(1 * 1000000L);
    grabber.setVideoFrameNumber(25 * 120);
    FileOutputStream outputStream = new FileOutputStream("C:\\\\Users\\\\Xpdn\\\\Videos\\\\VCG42N1340724607xx.mp4");
    FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputStream, grabber.getImageWidth(),
            grabber.getImageHeight(),grabber.getAudioChannels());
    recorder.setFormat("mp4");
    recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);

// recorder.setVideoCodec(grabber.getVideoCodec());
recorder.setAudioCodec(grabber.getAudioCodec());
recorder.setVideoBitrate(grabber.getVideoBitrate());
recorder.setFrameRate(grabber.getFrameRate());
recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
recorder.start();

    Frame frame;
    while ((frame = grabber.grabFrame()) != null) {
        // 处理每一帧的图像或音频数据
        recorder.record(frame);
    }

// recorder.stop();
// recorder.release();
}

public static Map<String, InputStream> clipVideo(InputStream inputStream, Map<Long,Long> timePeriod) throws Exception {
    boolean isStart = true;// 该变量建议设置为全局控制变量,用于控制录制结束
    FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputStream);
    grabber.start();


    //好多视频熟悉可以获取后打印 示例几个
    log.info("ImageWidth:" + grabber.getImageWidth());
    log.info("ImageHeight:" + grabber.getImageHeight());
    log.info("AudioChannels:" + grabber.getAudioChannels());
    log.info("Format:" + grabber.getFormat());
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputStream, grabber.getAudioChannels());
    recorder.setFrameRate(grabber.getFrameRate());

// recorder.setAudioBitrate(grabber.getAudioBitrate());
// recorder.setSampleRate(grabber.getSampleRate());
// recorder.setGopSize(2);
recorder.setFormat(grabber.getFormat());
recorder.setAudioCodecName(“aac”);
recorder.setVideoCodec(grabber.getVideoCodec());
Frame f = null;
//如果想截取规定时间段视频 请看系列文章二
while (isStart) {
f = grabber.grabFrame();
recorder.record(f);
}
recorder.stop();
recorder.release();
grabber.stop();
grabber.release();
return null;
}

/**
 * 将视频文件inputStream流截屏
 *
 * @param inputStream
 * @param seconds     截屏的数量以及秒数
 * @return
 */
public static Map<String, InputStream> generateCover(InputStream inputStream, List<Long> seconds) {
    // 生成封面
    HashMap<String, InputStream> hashMap = new HashMap<>();
    FFmpegFrameGrabber grabber = null;
    try {
        // 初始化FFmpegFrameGrabber
        grabber = new FFmpegFrameGrabber(inputStream);
        grabber.start();
        // 获取截取秒数,循环生成封面
        for (Long second : seconds) {
            // 设置封面截取时间
            grabber.setTimestamp(second * 1000000L);
            Frame f = grabber.grabImage();
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage bi = converter.getBufferedImage(f);
            // 指定封面保存地址
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            // 生成封面图片
            ImageIO.write(bi, "jpg", os);
            InputStream input = new ByteArrayInputStream(os.toByteArray());
            hashMap.put(String.valueOf(second), input);
        }
        return hashMap;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (grabber != null) {
                grabber.stop();
                grabber.release();
            }
        } catch (FFmpegFrameGrabber.Exception e) {
            e.printStackTrace();
        }
    }
    return null;
}

/**
 * 将视频文件inputStream流截屏,可以指定随机或者平均
 * @param inputStream
 * @param num
 * @param isRandom
 * @return
 */
public static Map<String, InputStream> generateCover(InputStream inputStream, Long num, boolean isRandom) {
    // 生成封面
    HashMap<String, InputStream> hashMap = new HashMap<>();
    FFmpegFrameGrabber grabber = null;
    try {
        // 初始化FFmpegFrameGrabber
        grabber = new FFmpegFrameGrabber(inputStream);
        grabber.start();
        Set<Long> seconds = null;
        if (isRandom) {
            seconds = generateSecondList(grabber, num, true);
        } else {
            seconds = averageSecondList(grabber, num);
        }
        // 获取截取秒数,循环生成封面
        for (Long second : seconds) {
            // 设置封面截取时间
            grabber.setTimestamp(second * 1000000L);
            Frame f = grabber.grabImage();
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage bi = converter.getBufferedImage(f);
            // 指定封面保存地址
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            // 生成封面图片
            ImageIO.write(bi, "jpg", os);
            InputStream input = new ByteArrayInputStream(os.toByteArray());
            hashMap.put(String.valueOf(second), input);
        }
        return hashMap;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (grabber != null) {
                grabber.stop();
                grabber.release();
            }
        } catch (FFmpegFrameGrabber.Exception e) {
            e.printStackTrace();
        }
    }
    return null;
}


/**
 * 生成视频封面
 *
 * @param videoFile 视频全路径,目前发现支持mp4、webm,其他的需要自己去尝试
 * @param coverPath
 * @param coverNum  封面数量
 * @param random    是否随机生成封面
 * @return map,其中key是秒数,而value是图片全路径
 **/
public static Map<String, String> generateCover(File videoFile, String coverPath, long coverNum, boolean random, Set<Long> seconds) {
    // 验证视频
    if (!(videoFile != null && videoFile.isFile() && videoFile.exists())) {
        throw new RuntimeException("参数:videoFile 不符合要求");
    }
    // 验证封面数量
    if (coverNum <= 0) {
        throw new RuntimeException("参数:coverNum 必须大于0");
    }
    // 存储封面
    Map<String, String> coverMap = new TreeMap<>();
    // 生成封面
    FFmpegFrameGrabber grabber = null;
    try {
        // 初始化FFmpegFrameGrabber
        grabber = new FFmpegFrameGrabber(videoFile);
        grabber.start();
        // 获取截取秒数
        Set<Long> secondSet = seconds == null ? generateSecondList(grabber, coverNum, random) : seconds;
        // 循环生成封面
        for (Long second : secondSet) {
            // 设置封面截取时间
            grabber.setTimestamp(second * 1000000L);
            Frame f = grabber.grabImage();
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage bi = converter.getBufferedImage(f);
            // 指定封面保存地址

// File imgFile = createTempFile(“cover.jpg”);
String videoFileName = videoFile.getName();
File imgFile = new File(coverPath, videoFileName.substring(0, videoFileName.lastIndexOf(“.”)) + “.jpg”);
// 生成封面图片
ImageIO.write(bi, “jpg”, imgFile);
String s = toBase64Img(imgFile);
coverMap.put(“imgBase64”, s);
imgFile.delete();
// 装载封面图片
// coverMap.put(second, imgFile.getAbsolutePath());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (grabber != null) {
grabber.stop();
grabber.release();
}
} catch (FFmpegFrameGrabber.Exception e) {
e.printStackTrace();
}
}

    return coverMap;
}

/**
 * 图片转换成base64格式
 *
 * @param file
 * @return
 */
public static String toBase64Img(File file) {
    FileInputStream fileInputStream = null;
    String s = null;
    try {
        fileInputStream = new FileInputStream(file);
        byte[] encode = Base64.getEncoder().encode(fileInputStream.readAllBytes());
        s = new String(encode);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fileInputStream != null) {
            try {
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return "data:image/jpg;base64," + s;
}

public static Long getVideoTotalSecond(InputStream inputStream) {
    // 生成封面
    FFmpegFrameGrabber grabber = null;
    try {
        // 初始化FFmpegFrameGrabber
        grabber = new FFmpegFrameGrabber(inputStream);
        grabber.start();
        return grabber.getLengthInTime() / 1000000;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (grabber != null) {
                grabber.stop();
                grabber.release();
            }
        } catch (FFmpegFrameGrabber.Exception e) {
            e.printStackTrace();
        }
    }
    return -1L;
}

/**
 * 随机获取封面截图秒数集合
 *
 * @param grabber  FFmpegFrameGrabber对象
 * @param coverNum 封面数量
 * @param random   是否随机生成封面
 * @return 封面截图秒数集合
 * @author 明快de玄米61
 * @date 2022/12/4 17:51
 **/
@SneakyThrows
private static Set<Long> generateSecondList(FFmpegFrameGrabber grabber, long coverNum, boolean random) {
    // 存储封面截图秒数集合
    Set<Long> secondSet = new TreeSet<>();
    // 获取视频时长秒数;说明:除以1000000可以获取秒数
    long totalVideoSecond = grabber.getLengthInTime() / 1000000;
    // 随机生成截图时间
    if (random) {
        Random secureRandom = SecureRandom.getInstanceStrong();
        for (int i = 1; i <= coverNum; i++) {
            secondSet.add((long) (secureRandom.nextInt((int) totalVideoSecond - 1) + 1));
        }
    } else {
        // 自定义截图时间
        coverNum = totalVideoSecond > coverNum ? coverNum : totalVideoSecond;
        for (long i = 1; i <= coverNum; i++) {
            secondSet.add(i);
        }
    }
    return secondSet;
}

/**
 * 平均获取视频的秒数集合
 *
 * @param grabber
 * @param coverNum
 * @return
 */
private static Set<Long> averageSecondList(FFmpegFrameGrabber grabber, long coverNum) {
    // 存储封面截图秒数集合
    Set<Long> secondSet = new TreeSet<>();
    // 获取视频时长秒数;说明:除以1000000可以获取秒数
    long totalVideoSecond = grabber.getLengthInTime() / 1000000;
    long l = totalVideoSecond / (coverNum + 1); // 平均的秒数间隔
    for (long i = 0; i < coverNum; i++) {
        secondSet.add((i + 1) * l);
    }
    return secondSet;
}

}文章来源地址https://www.toymoban.com/news/detail-663798.html

到了这里,关于FFmpeg截屏、剪切一段视频、或者压缩视频的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【FFmpeg】音视频录制 ① ( 查询系统中 ffmpeg 可录制的音视频输入设备 | 使用 ffmpeg 命令录制音视频数据 | 录制视频数据命令 |录制音频数据| 同时录制音频和视频数据命令 )

    在 Windows 系统中 , 使用 ffmpeg 命令 录制 音视频 , 需要先获取 系统的 音视频设备 信息 , 录制 音视频 本质上是从 系统音视频设备 中获取数据 ; 执行 命令 , 可以获取 系统中 ffmpeg 可用的 DirectShow 音视频输入设备 ; 命令参数解析 : -list_devices true : 列出所有 ffmpeg 的 指定类型的可

    2024年04月25日
    浏览(92)
  • 音视频 ffmpeg视频裁剪

    将输入视频帧的宽度和高度从x和y值表示的位置裁剪到指定的宽度和高度;x和y是输出的左上角坐标,协调系统的中心是输入视频帧的左上角。 如果使用了可选的keep_aspect参数,将会改变输出SAR(样本宽比)以补偿新的DAR(显示长宽比) 推荐一个零声学院项目课,个人觉得老师讲得不

    2024年02月10日
    浏览(52)
  • 音视频 FFmpeg音视频处理流程

    推荐一个零声学院项目课,个人觉得老师讲得不错,分享给大家: 零声白金学习卡(含基础架构/高性能存储/golang云原生/音视频/Linux内核) https://xxetb.xet.tech/s/VsFMs

    2024年02月12日
    浏览(69)
  • ffmpeg@音视频工具@音视频合并

    FFmpeg中文网 (github.net.cn) FFmpeg 是一款强大的开源跨平台音视频处理工具集,它包含了一系列命令行工具以及用于音频和视频编码解码、格式转换、抓取、流化等功能的库。FFmpeg 支持多种视频、音频格式和编解码器,能够进行音视频的压缩、封装、转码、分割、合并、过滤、抓

    2024年03月17日
    浏览(79)
  • 音视频 ffmpeg命令提取音视频数据

    保留封装格式 提取视频 提取音频 推荐一个零声学院项目课,个人觉得老师讲得不错,分享给大家: 零声白金学习卡(含基础架构/高性能存储/golang云原生/音视频/Linux内核) https://xxetb.xet.tech/s/VsFMs

    2024年02月10日
    浏览(62)
  • 音视频 ffmpeg命令视频录制(Windows)

    先安装dshow软件 Screen Capturer Recorder, 项目地址:https://sourceforge.net/projects/screencapturer/files/ 然后查看可用设备名字:ffmpeg -list_devices true -f dshow -i dummy 录制视频(默认参数) 录制声音(默认参数) 同时录制声音和视频(默认参数) 查看视频录制的可选参数 查看视频录制的可

    2024年02月10日
    浏览(71)
  • [一]ffmpeg音视频解码

    (1)下载FFmpeg源码(v3.3.6) 下载地址( http://www.ffmpeg.org/download.html#releases ) (2)下载NDK(r14b) 下载地址( https://developer.android.google.cn/ndk/downloads/index.html) (3)编写Android编译脚本 (1)用ftp上传到Ubuntu中 (2)解压Ffmpeg(tar -zxvf ffmpeg-3.3.6.tar.gz) (3)解压NDK(unzip andro

    2024年01月19日
    浏览(267)
  • 基于新版FFmpeg(FFmpeg 6.1)的音视频复用(不涉及编解码)

    FFmpeg库常用函数介绍(一)-CSDN博客 FFmpeg库常用函数介绍(二)-CSDN博客 FFmpeg库常用函数介绍(三)-CSDN博客 这篇文章介绍的是基于新版FFmpeg(FFmpeg 6.1)的音视频复用器的实现,可以实现音频和视频文件复用为一个视频文件,具体功能如下表所示。 输入视频文件 输入音频文

    2024年01月17日
    浏览(74)
  • 音视频 ffmpeg命令图片与视频互转

    截取一张图片 转换视频为图片(每帧一张图): 图片转换为视频: 从视频中生成GIF图片 将 GIF 转化为 视频 推荐一个零声学院项目课,个人觉得老师讲得不错,分享给大家: 零声白金学习卡(含基础架构/高性能存储/golang云原生/音视频/Linux内核) https://xxetb.xet.tech/s/VsFMs

    2024年02月10日
    浏览(57)
  • 【FFmpeg】ffmpeg 命令行参数 ⑧ ( 使用 ffmpeg 转换封装格式 | 音视频编解码器参数设置 | 视频 帧率 / 码率 / 分辨率 设置 | 音频 码率 / 采样率 设置 )

    音视频 文件 从 采样 - 处理 - 得到原始数据帧队列 - 音视频编码 - 音视频包队列 - 格式封装 的过程如下 : 封装格式 参考 【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装

    2024年04月17日
    浏览(85)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包