视频格式网络地址转换视频到本地,获取封面、时长,其他格式转换成mp4

news2024/11/16 5:44:11

使用ffmpeg软件转换网络视频,先从官网下载对应操作系统环境的包

注意:网络地址需要是视频格式结尾,例如.mp4,.flv 等

官网地址:Download FFmpeg     

window包:

415b5111089d42a4a02116b3fb877065.png

linux包:

39729fa04ffc4bf895ce22971e583292.png

如果下载缓慢,下载迅雷安装使用下载。

解压缩后对应截图:

window:

4cc5ed2dd51f4e6f9c96cb846d54e438.png

linux:

16eb35142ad44511b8c0089bd9437a56.png

在maven项目的pom.xml引入依赖包:

 <dependency>
                <groupId>net.bramp.ffmpeg</groupId>
                <artifactId>ffmpeg</artifactId>
                <version>0.7.0</version>
            </dependency>
 <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>

引入类:

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import net.bramp.ffmpeg.FFmpeg;
import net.bramp.ffmpeg.FFmpegExecutor;
import net.bramp.ffmpeg.FFprobe;
import net.bramp.ffmpeg.builder.FFmpegBuilder;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

网络地址转换成本地视频方法:

 /**
     * 视频链接转换成本地视频
     * @param videoUrl
     * @param downloadPath
     * @return
     */
    public static boolean downVideo(String videoUrl,String downloadPath){
        HttpURLConnection connection = null;
        InputStream inputStream = null;
        RandomAccessFile randomAccessFile = null;
        boolean re;
        try{
            URL url = new URL(videoUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestProperty("Range","bytes=0-");
            connection.connect();
            if (connection.getResponseCode() / 100 != 2){
                System.out.println("链接失败");
                return  false;
            }
            inputStream = connection.getInputStream();
            int downloaded = 0;
            int fileSize = connection.getContentLength();
            randomAccessFile = new RandomAccessFile(downloadPath,"rw");
            while (downloaded < fileSize){
                byte[] buffer = null;
                if (fileSize - downloaded >= 1000000){
                    buffer = new byte[1000000];
                }else{
                    buffer = new byte[fileSize - downloaded];
                }
                int read = -1;
                int currentDownload = 0;
                while (currentDownload < buffer.length){
                    read = inputStream.read();
                    buffer[currentDownload++] = (byte) read;
                }
                randomAccessFile.write(buffer);
                downloaded += currentDownload;
            }
            re = true;
            return re;
        } catch (Exception e) {
            e.printStackTrace();
            re = false;
            return re;
        }finally {
            try{
                connection.disconnect();
                inputStream.close();
                randomAccessFile.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

网站地址转换成本地视频后,再转换成mp4视频方法:

/**
     * 其他视频格式地址转换成mp4
     * @param orginalVideoPath 原视频地址
     * @param newMp4FilePath 新mp4地址
     * @return
     */
    public static boolean otherVideoToMp4(String orginalVideoPath,String newMp4FilePath)  {
        try{
            String ffmpegPath = "";
            String ffprobePath = "";
            if (SystemUtils.isWindows()){
                //目录里放的文件没有提交保存,在本地测试的时候自行添加
                ffmpegPath = VideoCovertUtil.class.getResource("/ffmpegdir/win/bin/ffmpeg.exe").getPath();
                ffprobePath = VideoCovertUtil.class.getResource("/ffmpegdir/win/bin/ffprobe.exe").getPath();
            }else if (SystemUtils.isLinux()){
                /*ffmpegPath = VideoCovertUtil.class.getResource("/ffmpegdir/linux/ffmpeg").getPath();
                ffprobePath = VideoCovertUtil.class.getResource("/ffmpegdir/linux/ffprobe").getPath();*/
                //在linux安装ffmpeg后配置路径
                //安装步骤:https://blog.csdn.net/ysushiwei/article/details/130162831
                ffmpegPath = "/usr/local/bin/ffmpeg";
                ffprobePath = "/usr/local/bin/ffprobe";
            }

            log.info("ffmpegPath:"+ffmpegPath);
            log.info("ffmpegPath:"+ffprobePath);
            FFmpeg fFmpeg = new FFmpeg(ffmpegPath);
            FFprobe fFprobe = new FFprobe(ffprobePath);
            FFmpegBuilder builder = new FFmpegBuilder()
                    .setInput(orginalVideoPath)
                    .addOutput(newMp4FilePath)
                    .done();
            FFmpegExecutor executor = new FFmpegExecutor(fFmpeg,fFprobe);
            executor.createJob(builder).run();
            log.info("执行完毕");
            return  true;
        }catch (IOException e){
            e.printStackTrace();
            return false;
        }
    }

window可以直接放在项目中,但是linux还需要配置。步骤如下。

1、将上方的linux包上传到服务器,解压缩:

tar -xvf ffmpeg-release-amd64-static.tar.xz

2、解压缩后进入根目录分别复制根目录下的ffmpeg和ffprobe到 /usr/local/bin/目录下:

sudo cp 解压缩目录/ffmpeg /usr/local/bin/
sudo cp 解压缩目录/ffprobe /usr/local/bin/

3.还要给文件设置权限,否则运行代码的时候报没有权限:

sudo chmod +x /usr/local/bin/ffmpeg

sudo chmod +x /usr/local/bin/ffprobe

4、最后检查是否配置成功,如果有内容输出来则成功:

ffmpeg -version

ffprobe -version

linux环境配置好后,即可正常解析.

从视频中提取封面和获取时长:

 /**
     * 获取视频的第一帧封面
     * @param filePath 视频地址
     * @param targetPath 视频封面地址
     */
    public static void getCover(String filePath,String targetPath){
        try{
            // 视频地址
            FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(new File(filePath));

            grabber.start();

            Java2DFrameConverter converter = new Java2DFrameConverter();

            BufferedImage image = converter.convert(grabber.grabImage());
            // 本地图片保存地址
            ImageIO.write(image, "png", new File(targetPath));

            grabber.stop();
            image.flush();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     * 使用FFmpeg获取视频时长
     *
     * @param path 视频文件地址
     * @return 时长,单位为秒
     * @throws IOException
     */
    public static String getDuration(String path) {
        // 读取视频文件
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(path);
        try {
            grabber.start();
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        }
        // 获取视频长度(单位:秒)
        int duration = grabber.getLengthInFrames() / (int) grabber.getFrameRate();
        try {
            grabber.stop();
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        }
        return DateUtil.secondToTime(duration);
    }

由于视频转换下载等速度比较慢,推荐使用异步执行。我用的是若依的框架,代码如下。如用其他框架,可自行参考写异步操作

//异步执行方法。不会等待执行完才执行下一位
AsyncManager.me().execute(AsyncFactory.convertVideoNetUrl(video.getVideoPath(),video.getId(),
                Constants.CONVERT_VIDEO_NET_VIDEO_URL));

#在AsyncManager类里自定义一个异步方法如下

 /**
     * 
     * @param videNetUrl 视频网络地址
     * @param id 类id
     * @param entityClazz 类 0:视频 1:文章
     * @return 任务task
     */
    public static TimerTask convertVideoNetUrl(final String videNetUrl,Long id,Integer entityClazz)
    {
        return new TimerTask()
        {
            @Override
            public void run()
            {
                if (entityClazz == null || id == null || StrUtil.isBlank(videNetUrl)){
                    return;
                }
                if (entityClazz == 0){
                    IVideoService videoService =  SpringUtils.getBean(IVideoService.class);
                    Video video = videoService.selectVideoById(id);
                    if (video == null){
                        return;
                    }
                    //现在是上传视频地址
                    //先转换视频地址到服务器
                    //后缀
                    String ext = video.getVideoPath().substring(video.getVideoPath().lastIndexOf("."));
                    String videosubpath = StringUtils.format("{}/{}_{}{}", DateUtils.datePath(),
                            IdUtils.fastSimpleUUID(), Seq.getId(Seq.uploadSeqType), ext);
                    String downloadPath = null;
                    try {
                        downloadPath = FileUploadUtils.getAbsoluteFile(HqaConfig.getUploadPath() + "/", videosubpath).getAbsolutePath();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    boolean downVideo = VideoCovertUtil.downVideo(video.getVideoPath(),downloadPath);
                    if (downVideo && StrUtil.isNotBlank(downloadPath) && downloadPath != null){
                        if (!ext.contains("mp4")){
                            //下载成功后如果不是mp4格式,转换成mp4格式
                            String newVideosubpath = StringUtils.format("{}/{}_{}{}", DateUtils.datePath(),
                                    IdUtils.fastSimpleUUID(), Seq.getId(Seq.uploadSeqType), ".mp4");
                            String newMp4FilePath = null;
                            try {
                                newMp4FilePath = FileUploadUtils.getAbsoluteFile(HqaConfig.getUploadPath() + "/", newVideosubpath).getAbsolutePath();
                            }catch (Exception e){
                                e.printStackTrace();
                            }
                            boolean toMp4 = VideoCovertUtil.otherVideoToMp4(downloadPath,newMp4FilePath);
                            if (toMp4 && StrUtil.isNotBlank(newMp4FilePath) && newMp4FilePath != null){
                                //转换成功后删除之前下载过的视频地址,并且保存新的mp4地址
                                if (new File(downloadPath).exists()){
                                    FileUtils.deleteFile(downloadPath);
                                }
                                if (newMp4FilePath.contains("\\")){
                                    newMp4FilePath = newMp4FilePath.replace("\\","/");
                                }
                                String newPath = newMp4FilePath.replace(HqaConfig.getProfile(),"/profile");
                                video.setVideoPath(newPath);
                            }
                        }else{
                            if (downloadPath.contains("\\")){
                                downloadPath = downloadPath.replace("\\","/");
                            }
                            //保存地址
                            String newPath = downloadPath.replace(HqaConfig.getProfile(),"/profile");
                            video.setVideoPath(newPath);
                        }
                        //视频截图和时长
                        //获取视频第一帧封面
                        String parentPath = HqaConfig.getUploadPath()+"/"+ DateUtils.datePath();
                        String fileName = IdUtils.fastSimpleUUID()+".png";
                        String targetPath = parentPath+"/"+ fileName;
                        try {
                            FileUploadUtils.getAbsoluteFile(parentPath,fileName);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        String filePath = video.getVideoPath().replace("/profile","");
                        filePath=HqaConfig.getProfile()+filePath;
                        VideoCovertUtil.getCover(filePath,targetPath);
                        video.setCover(targetPath.replace(HqaConfig.getProfile(),"/profile"));
                        String  duration = VideoCovertUtil.getDuration(filePath);
                        video.setDuration(duration);
                        videoService.updateVideo(video);
                    }
                }else if (entityClazz == 1){
                    IArticleService articleService = SpringUtils.getBean(IArticleService.class);
                    Article article = articleService.selectArticleById(id);
                    if (article == null){
                        return;
                    }
                    //现在是上传视频地址
                    //先转换视频地址到服务器
                    //后缀
                    String ext = article.getVideoPath().substring(article.getVideoPath().lastIndexOf("."));
                    String videosubpath = StringUtils.format("{}/{}_{}{}", DateUtils.datePath(),
                            IdUtils.fastSimpleUUID(), Seq.getId(Seq.uploadSeqType), ext);
                    String downloadPath = null;
                    try {
                        downloadPath = FileUploadUtils.getAbsoluteFile(HqaConfig.getUploadPath() + "/", videosubpath).getAbsolutePath();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    boolean downVideo = VideoCovertUtil.downVideo(article.getVideoPath(),downloadPath);
                    if (downVideo && StrUtil.isNotBlank(downloadPath) && downloadPath != null){
                        if (!ext.contains("mp4")){
                            //下载成功后如果不是mp4格式,转换成mp4格式
                            String newVideosubpath = StringUtils.format("{}/{}_{}{}", DateUtils.datePath(),
                                    IdUtils.fastSimpleUUID(), Seq.getId(Seq.uploadSeqType), ".mp4");
                            String newMp4FilePath = null;
                            try {
                                newMp4FilePath = FileUploadUtils.getAbsoluteFile(HqaConfig.getUploadPath() + "/", newVideosubpath).getAbsolutePath();
                            }catch (Exception e){
                                e.printStackTrace();
                            }
                            boolean toMp4 = VideoCovertUtil.otherVideoToMp4(downloadPath,newMp4FilePath);
                            if (toMp4 && StrUtil.isNotBlank(newMp4FilePath) && newMp4FilePath != null){
                                //转换成功后删除之前下载过的视频地址,并且保存新的mp4地址
                                if (new File(downloadPath).exists()){
                                    FileUtils.deleteFile(downloadPath);
                                }
                                if (newMp4FilePath.contains("\\")){
                                    newMp4FilePath = newMp4FilePath.replace("\\","/");
                                }
                                String newPath = newMp4FilePath.replace(HqaConfig.getProfile(),"/profile");
                                article.setVideoPath(newPath);
                            }
                        }else{
                            if (downloadPath.contains("\\")){
                                downloadPath = downloadPath.replace("\\","/");
                            }
                            //保存地址
                            String newPath = downloadPath.replace(HqaConfig.getProfile(),"/profile");
                            article.setVideoPath(newPath);
                        }
                        articleService.updateArticle(article);
                    }
                }
            }
        };
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1339335.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RabbitMQ核心概念记录

本文来记录下RabbitMQ核心概念 文章目录 什么叫消息队列为何用消息队列RabbitMQ简介RabbitMQ基本概念RabbitMQ 特点具体特点包括 Rabbitmq的工作过程RabbitMQ集群RabbitMQ 的集群节点包括Rabbit 模式大概分为以下三种单一模式普通模式镜像模式 本文小结 什么叫消息队列 消息&am…

Spring 是如何解决循环依赖问题的方案

文章目录 Spring 是如何解决循环依赖问题的&#xff1f; Spring 是如何解决循环依赖问题的&#xff1f; 我们都知道&#xff0c;如果在代码中&#xff0c;将两个或多个 Bean 互相之间持有对方的引用就会发生循环依赖。循环的依赖将会导致注入死循环。这是 Spring 发生循环依赖…

基于Docker的软件环境部署脚本,持续更新~

使用时CtrlF搜索你想要的环境&#xff0c;如果没有你想要的环境&#xff0c;可以评论留言&#xff0c;会尽力补充。 本文提供的部署脚本默认参数仅适合开发测试&#xff0c;请根据实际情况调节参数。 数据库 MySQL version: 3.9 services:mysql:image: mysql:8.0.35container…

在 iPhone 手机上恢复数据的 7 个有效应用程序

我们的生活离不开 iPhone。无论我们走到哪里&#xff0c;他们都陪伴着我们&#xff0c;让我们保持联系、拍摄照片和视频&#xff0c;并提供娱乐。与此同时&#xff0c;您将计算机安全地放在办公桌上&#xff0c;不受天气影响&#xff0c;也不受伤害。如果您要在任何地方丢失重要…

Jmeter 性能 —— 监控服务器!

Jmeter 监控Linux需要三个文件 JMeterPlugins-Extras.jar (包&#xff1a;JMeterPlugins-Extras-1.4.0.zip)JMeterPlugins-Standard.jar (包&#xff1a;JMeterPlugins-Standard-1.4.0.zip)ServerAgent-2.2.3.zip 1、Jemter 安装插件 在插件管理中心的搜索Servers Performa…

cpp_07_类型转换构造_析构函数_深拷贝_静态成员

1 类型转换构造函数 1.1 why? 基本类型之间的转换&#xff0c;编译器内置转换规则&#xff1a;int -> double 类类型之间的转换&#xff0c;编译器不知道转换规则&#xff0c;需要用户提供&#xff1a;Cat -> Dog // consconv_why.cpp 为什么需要自定义转换 #includ…

多出口-热备---实验

多出口-热备 拓扑 需求 1&#xff09;增加出口路由器&#xff0c;实现路由器冗余&#xff0c;实现出口设备热备份 配置步骤 1&#xff09;SW5和SW6创建vlan25 vlan26 2) SW5配置vlanif 25的IP地址 3&#xff09;S 4&#xff09;统一规划设计一下MSTP 5&#xff09;R2配…

Java中利用Redis,ZooKeeper,数据库等实现分布式锁(遥遥领先)

1. 分布式锁 1.1 什么是分布式锁 在我们进行单机应用开发涉及并发同步的时候&#xff0c;我们往往采用synchronized或者ReentrantLock的方式来解决多线程间的代码同步问题。但是当我们的应用是在分布式集群工作的情况下&#xff0c;那么就需要一种更加高级的锁机制&#xff0…

奇富科技跻身国际AI学术顶级会议ICASSP 2024,AI智能感知能力迈入新纪元

近日&#xff0c;2024年IEEE声学、语音与信号处理国际会议ICASSP 2024&#xff08;2024 IEEE International Conference on Acoustics, Speech, and Signal Processing&#xff09;宣布录用奇富科技关于语音情感计算的最新研究成果论文“MS-SENet: Enhancing Speech Emotion Re…

java设计模式学习之【状态模式】

文章目录 引言状态模式简介定义与用途实现方式 使用场景优势与劣势在Spring框架中的应用状态示例代码地址 引言 设想你正在使用一个在线视频播放器观看电影。随着你的互动&#xff0c;播放器可能处于不同的状态&#xff1a;播放、暂停、缓冲或结束。每个状态下&#xff0c;播放…

IDEA安装教程及使用

一、IDEA简介 ​ IDEA全称IntelliJ IDEA&#xff0c;是用于Java语言开发的集成环境&#xff0c;它是业界公认的目前用于Java程序开发最好的工具。 集成环境&#xff1a;把代码编写&#xff0c;编译&#xff0c;执行&#xff0c;调试等多种功能综合到一起的开发工具。 二、ID…

数据分析之词云图绘制

试验任务概述&#xff1a;如下为所给CSDN博客信息表&#xff0c;分别汇总了ai, algo, big-data, blockchain, hardware, math, miniprog等7个标签的博客。对CSDN不同领域标签类别的博客内容进行词频统计&#xff0c;绘制词频统计图&#xff0c;并根据词频统计的结果绘制词云图。…

使用streampark进行flink on k8s LoadBalancer配置域名访问flink ui

在使用yarn部署flink任务时&#xff0c;yarn自动代理了flink web ui&#xff0c;通过yarn的地址即可访问任务web页面。 k8s模式下想访问flink web ui&#xff0c;要么使用NodePort的方式启动任务&#xff0c;然后通过k8s主机IPNodePort端口来进行访问。但是这种方法&#xff0…

C++构建简单静态库实例(cmakelist)

一、开发实例 通过cmake构建静态开发实例如下: 1.1 代码目录 代码目录结构如下: 1.2 代码内容 1.2.1 CMakeLists.txt # CMake 最低版本要求 cmake_minimum_required(VERSION 3.10)# 项目名称 project(mylib)# 添加源文件 set(SOURCE_FILESsrc/mylib

分布式数据库 GaiaDB-X 通过 GB18030-2022《信息技术 中文编码字符集》最高级别认证

近日&#xff0c;百度智能云分布式数据库GaiaDB-X通过 GB18030-2022《信息技术 中文编码字符集》强制性国家标准测试&#xff0c;达到最高实现级别&#xff08;3级&#xff09;。 据了解&#xff0c;GB18030-2022《信息技术 中文编码字符集》是中文信息技术领域最重要的基础性标…

在 Unity 中获取 Object 对象的编辑器对象

有这个需求的原因是&#xff0c;在编辑器的 Inspector 逻辑中&#xff0c;写了许多生成逻辑。 现在不想挨个在 Inspector 上都点一遍按钮&#xff0c;所以就需要能获取到它们的编辑器对象。 发现可以借助官方的 UnityEditor.Editor.CreateEditor 方法达到目的&#xff0c;如下…

【IoT网络层】STM32 + ESP8266 +MQTT + 阿里云物联网平台 |开源,附资料|

目标&#xff1a;实现STM32连接阿里云物联网平台发送数据同时接收数据&#xff0c;IOT studio界面显示数据。具体来说&#xff1a;使用ESP8266 ESP-01来连接网络&#xff0c;获取设备数据发送到阿里云物联网平台并显示且oled显示屏当前的设备数据&#xff0c;通过IOT studio界面…

OpenHarmony城市技术论坛武汉站:探索大模型时代的终端操作系统创新

2023年12月23日下午,OpenHarmony城市技术论坛(以下简称“技术论坛”)——第6期(武汉站)于华中科技大学梧桐语问学中心明德报告厅圆满举办。本次技术论坛聚焦“大模型时代的系统软件”,旨在探索AI大模型在终端操作系统领域的创新趋势和挑战。论坛从“终端操作系统十大技术挑战”…

亿赛通电子文档安全管理系统 linkfilterservice 未授权漏洞

产品简介 亿赛通电子文档安全管理系统&#xff0c;&#xff08;简称&#xff1a;CDG&#xff09;是一款电子文档安全加密软件&#xff0c;该系统利用驱动层透明加密技术&#xff0c;通过对电子文档的加密保护&#xff0c;防止内部员工泄密和外部人员非法窃取企业核心重要数据资…

php 之 redisk 扩展问题

系统&#xff1a; ARM V10 server &#xff08;1229&#xff09; 软件&#xff1a; php、phpdevel redis5.1.0RC1 redis5.1.0RC1.tgz phpredis 编译&#xff1a; 解压进入目录内&#xff1a; # phpize # ./configure withphpconfig/usr/bin/phpconfig # make # make ins…