• 基于FFmpeg的Java视频Mp4转GIF初探


    背景

           在一些业务场景中,会有如下的一些要求:比如有用户需要将Mp4视频转为Gif动图。当然有一些小伙伴说可以使用系统截图,然后使用之前提到过的技术:GIF图像动态生成-JAVA后台生成。需要处理的素材比较少,就一两个视频,确实可以通过这种方式来处理。试想一下,如果需要处理上百个,做处理的小伙伴是不是就抓狂了,这完全是实打实的工作量。那有没有直接从Mp4转成gif动态图的技术呢?运营的小伙伴就能按时下班了。

           经过一番查询,找到一些思路,Mp4视频的组成也是一帧一帧的图像组成的。如果有什么技术可以去动态获取这些数据,通过动态截取每一帧,最后再合成图片。不久解决了吗?FFmpeg变进入技术选型的视野。本文主要讲解如何在Java中,使用FFmpeg进行视频的帧读取,并最终合并成Gif动态图。

    一、FFmpeg是什么?

    1、简介

          FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。FFmpeg在Linux平台下开发,但它同样也可以在其它操作系统环境中编译运行,包括Windows、Max Os等。这个项目最早由Fabrice Bellard发起,2004年至2015年间由Michael Niedermayer主要负责维护。许多FFmpeg的开发人员都来自项目MPlayer,而且当前FFmpeg也是放在MPlayer项目组的服务器上。

    2、FFmpeg功能列表

           FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。它包括了领先的音/视频编码库libavcodec等。

    1. libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构
    2. 和读取音视频帧等功能;
    3. libavcodec:用于各种类型声音/图像编解码;
    4. libavutil:包含一些公共的工具函数;
    5. libswscale:用于视频场景比例缩放、色彩映射转换;
    6. libpostproc:用于后期效果处理;
    7. ffmpeg:该项目提供的一个工具,可用于格式转换、解码;
    8. ffsever:一个 HTTP 多媒体即时广播串流服务器;
    9. ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示;

    二、Java集成JavaCV调用FFmpeg

    1、JavaCv引入

          JavaCv是基于openCv的一个非常强大的库,关于javaCv以后计划做几次讲解,这里不深入,有兴趣的小伙伴可以先行学习。在工程中新建一个Maven工程,在Pom.xml中引入支持,需要注意的是,这里为了演示简单,引入了完整的JavaCv的包,在实际项目中不需要如此,按需引入即可。

    1. <project xmlns="http://maven.apache.org/POM/4.0.0"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0modelVersion>
    5. <groupId>com.yelanggroupId>
    6. <artifactId>mp42gifartifactId>
    7. <version>0.0.1-SNAPSHOTversion>
    8. <dependencies>
    9. <dependency>
    10. <groupId>org.bytedecogroupId>
    11. <artifactId>javacv-platformartifactId>
    12. <version>1.5.2version>
    13. dependency>
    14. <dependency>
    15. <groupId>com.madgaggroupId>
    16. <artifactId>animated-gif-libartifactId>
    17. <version>1.4version>
    18. dependency>
    19. <dependency>
    20. <groupId>junitgroupId>
    21. <artifactId>junitartifactId>
    22. <version>4.11version>
    23. <scope>testscope>
    24. dependency>
    25. <dependency>
    26. <groupId>org.projectlombokgroupId>
    27. <artifactId>lombokartifactId>
    28. <version>1.18.24version>
    29. <scope>providedscope>
    30. dependency>
    31. dependencies>
    32. project>

    2、视频转换读取

    1. public static void main(String[] args) {
    2. // 将指定目录的 MP4 文件生成同名的 gif 文件
    3. File videoDir = new File("E:/testv");
    4. for (File file : videoDir.listFiles()) {
    5. String videoPath = file.getPath();
    6. if (videoPath.endsWith(".mp4")) {
    7. String gifPath = videoPath.substring(0, videoPath.lastIndexOf(".")) + ".gif";
    8. try {
    9. video2Gif(videoPath, gifPath);
    10. System.out.println("转换完成");
    11. } catch (Exception e) {
    12. System.out.println("文件 [" + videoPath + "] 处理异常!");
    13. e.printStackTrace();
    14. }
    15. }
    16. }
    17. }

           上面定义了一个main函数调用,只是一个简单的示例,实际项目需要自己扩展。核心的视频转换函数如下:

    1. private static void video2Gif(String videoPath, String gifPath) throws Exception {
    2. try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoPath);
    3. FileOutputStream targetFile = new FileOutputStream(gifPath)) {
    4. grabber.start();
    5. int frames = grabber.getLengthInFrames();
    6. System.out.println(frames);
    7. AnimatedGifEncoder encoder = new AnimatedGifEncoder();
    8. encoder.setFrameRate(frames);
    9. encoder.start(targetFile);
    10. Java2DFrameConverter converter = new Java2DFrameConverter();
    11. for (int i = 0; i < frames; i += 8) {// 8帧合成1帧?(反正越大动图越小、越快)
    12. encoder.setDelay((int) grabber.getDelayedTime());
    13. encoder.addFrame(converter.convert(grabber.grabImage()));
    14. grabber.setFrameNumber(i);
    15. }
    16. encoder.finish();
    17. }
    18. }

           通过FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoPath);获取视频信息,同时调用grabber.start();进行视频读取(这一步必须要设置,否则会影响后面的结果)。通过int frames = grabber.getLengthInFrames();获取Mp4视频的帧数,再循环帧,即可。上述的代码中不是读取每一帧,这样生成的结果会非常大,建议不要全部读取。

    1. for (int i = 0; i < frames; i += 8) {// 8帧合成1帧)
    2. encoder.setDelay((int) grabber.getDelayedTime());
    3. encoder.addFrame(converter.convert(grabber.grabImage()));
    4. grabber.setFrameNumber(i);
    5. }

    3、运行结果

          使用一段视频来测试相应的功能能否正常生效,在E盘新建一个mp4视频文件。

      使用上述视频来验证代码是否正确运行,通过Debug来观察程序的运行。

            最后在测试的目录中,发现已经成功生成对应的gif图片,拖到浏览器中可以正常展示。

    三、总结

           以上就是今天要讲的内容,本文主要简单介绍了在Java中如何基于FFmpeg进行Mp4视频到Gif动图的转换。首先简单讲解FFmpeg的定义,常用的方法,然后重点介绍JavaCv中FFmpeg具体使用,如果在工作中有这种需要,不妨采用这种方式。希望本文对您有所帮助,欢迎指导交流。

  • 相关阅读:
    Javaweb之HTML,CSS的详细解析
    在Scrum敏捷开发中,开发人员(Developers)的职责
    痞子衡嵌入式:i.MXRT1xxx系列GPIO提早供电会影响上电时序导致内部DCDC启动失败
    python——字符串
    PostgreSQL - tutorial
    公安机关警务vr综合实战模拟训练提高团队合作能力
    常用基本AT指令
    BHQ-3 amine,1661064-89-6可在430nm至730nm范围内猝灭所有普通荧光团
    实现定时器
    腾讯mini项目-【指标监控服务重构】2023-08-26
  • 原文地址:https://blog.csdn.net/yelangkingwuzuhu/article/details/127954389