Java 利用ffmpeg工具实现视频MP4转m3u8(一)

  • 前言
  • (一)ffmpeg工具转码
    • 1.如何安装ffmpeg工具
    • 2.如何使用ffmpeg工具进行视频转码
  • (二)播放m3u8文件
    • 1.video.js
    • 2.具体使用
      • 1)静态数据
      • 2)动态数据
  • (三)Java程序上传本地视频地址并通过ffmpeg工具转成m3u8文件
  • (四)上传m3u8文件至OSS需要注意的问题

前言

ffmpeg工具实现视频转码网上有很多教程,但大多不够具体。本博客综合了下网上教程,从ffmpeg工具转码,ffmpeg视频播放,java语言操控ffmpeg转码,转码后视频上传阿里云oss,四个方面完整记录下这个流程,内容是基于我项目中的需求而定,不能使用所有情况,仅供参考。
        具体技术原理不做描述,如有兴趣可自行研究。

(一)ffmpeg工具转码

1.如何安装ffmpeg工具

官网下载地址: https://ffmpeg.zeranoe.com/builds/
我是用的ffmpeg是windows版本,linux自行研究

下载完成后解压压缩包,完成后bin目录下ffmpeg.exe文件是之后程序启动时需要使用的

配置环境变量,至此ffmpeg工具安装到此结束

2.如何使用ffmpeg工具进行视频转码

打开cmd黑窗口,输入以下指令
ffmpeg -i xxxxxxx.mp4 -c:v libx264 -hls_time 60 -hls_list_size 0 -c:a aac -strict -2 -f hls xxxxxxx.m3u8
地址既可以写相对地址 ,也可以写绝对地址,看你自己情况
这条指令参数具体含义自行百度,这里只介绍几个重要的
参数解析:
-re :该参数表示ffmpeg将会按照当前视频的播放速率进行转码,这样就不会说切片的速度和播放速度不一致。不加这个参数,切片速度会非常快,客户端还来不及播放,列表已经被更新了。
-hls_time n :设置每片的长度,默认值为2,单位为秒。
-hls_list_size n :设置m3u8文件播放列表保存的最多条目,设置为0会保存有所片信息,默认值为5。一般用于直播流,点播文件可以设置成0,即全部保存。
-hls_wrap n :设置多少片之后开始覆盖,设置为0则不会覆盖,默认值为0。这个选项能够避免在磁盘上存储过多的片,而且能够限制写入磁盘的最多的片的数量。
以上参数可以自己尝试调整看看效果。

这是成功执行命令后,ffmpeg执行过程,出现这个界面没报错,就恭喜你成功了,安静等待工具切片就行了

工具执行完毕之后,输出路径文件夹中会多出一个m3u8文件和若干ts文件,至此第一部分圆满成功

(二)播放m3u8文件

1.video.js

Video.js 是一个通用的在网页上嵌入视频播放器的 JS 库,Video.js 自动检测浏览器对 HTML5 的支持情况,如果不支持 HTML5 则自动使用 Flash 播放器。(要支持ie低版本请下载5.4.3版 )

官网地址: https://videojs.com
API地址:https://docs.videojs.com/index.html

2.具体使用

1)静态数据

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><meta http-equiv="X-UA-COMPATIBLE" CONTENT="IE=edge,chrome=1"><link href="css/style.css" rel="stylesheet" /><link href="js/video-js.css" rel="stylesheet"><!-- If you'd like to support IE8 (for Video.js versions prior to v7) --><script src="js/videojs-ie8.min.js"></script></head><body><video id="myVideo" class="video-js vjs-default-skin vjs-big-play-centered"><source type="application/x-mpegURL"></source></video></body><script type="text/javascript" src="js/jquery-3.3.1.js"></script><script src='js/video.js'></script><script>videojs(document.querySelector('.video-js'), {controls: true,autoplay: false,preload: 'auto',sources: [{src: "video/20191010173819_cjOaOJ.mp4",type: "application/x-mpegURL"}]});</script></html>

2)动态数据

动态数据赋值有个src方法,但是我使用的时候容易报错,用的vue框架,且视频地址是oss地址。
就想了个折中的方法,每次url变化的时候销毁原始video对象,重新初始化。
最近还在研究,如果有好方法会再更新上来。如有解决方案也可以留言我。

videojs(document.querySelector('.video-js'),{}).ready(function(){    var myPlayer = this;myPlayer.src("http://www.example.com/path/to/video.mp4");myPlayer.play();
});

需要注意,如果是在Vue里使用,建议用ref获取元素,我这里标出初始化播放器方法代码

initPalyer(){const videoDom = this.$refs.myVideo;   //不能用document 获取节点let myPlayer = videojs( videoDom, {controls: true,autoplay: false,preload: 'auto',sources: [{src: vm.yfVideoDetail.videoUrl,type: "application/x-mpegURL"}]});}

Api上有着详细的使用方法的介绍,我这里因为只用到这些所以就只写了这部分代码,如果想进一步深入,可以自行研究。

更新播放方法:

const vue = new Vue({el: ".body",data: {myPlayer: null},methods: {initPalyer() {const videoDom = this.$refs.myVideo; //不能用document 获取节点if(vurl) {vue.myPlayer = videojs(videoDom, {controls: true,autoplay: false,preload: 'auto',sources: [{src: vurl,  //视频urltype: "application/x-mpegURL"}]});}},//切换视频switchVideo(item) {vue.myPlayer.reset(); //重置 videovue.myPlayer.src([{src: item.videoUrl  //新视频url}, ]);vue.myPlayer.load(item.videoUrl);vue.myPlayer.currentTime(0);}}
})

(三)Java程序上传本地视频地址并通过ffmpeg工具转成m3u8文件

实现前提:笔者用的是springboot框架,,前端上传视频用的是elementui里的上传组件.

以下代码是根据网上已有的源码结合自身需求做了改变,仅供参考,请勿直接copy,直接copy报错了不要怪我哦。需要根据自身需求进行改变。

后台实现上传代码:

public R saveVideo(@RequestParam  MultipartFile file) {// TODO Auto-generated method stubString url=null;try {String f = file.getOriginalFilename(); //获取文件名String suffix = StringUtils.substringAfter(f, "."); //获取文件后缀String filename = FileUtils.getFileName(null, null);  //我自己封装的方法,给文件重新起个名字,文件名不带后缀/*********本地上传(Tomcat配置映射C:/upload/file)*********///先将文件本地上传后,调用ffmpeg切片转成m3u8,在将转换后文件上传到oss上去/*我的思路就是根据我重新起的名字,生成对应文件夹,将mp4视频和转换后的m3u8以及ts放在一起,然后遍历文件目录,将文件上传后,删除本地文件夹和文件*/String folderUrl = FileUtils.localPath+filename; //文件夹路径String fileName = filename+"."+suffix;   //文件名带后缀String uploadPath= folderUrl + "/" + fileName;  //上传后路径File fileFolder = new File(folderUrl);if (!fileFolder.exists()) {fileFolder.mkdirs();}File newFile = new File(uploadPath);file.transferTo(newFile);//mp4转m3u8boolean b = convertM3U8.convertOss(folderUrl + "/", fileName);if (!b){return R.error("上传失败!系统转码异常!");}//访问本地上传文件夹所有文件,依次上传至oss服务器File[] files = fileFolder.listFiles();if (null == files || files.length == 0) {return null;}boolean flag = true;for (int i = 0; i < files.length ; i++) {if (!files[i].isDirectory()) {//上传String name = files[i].getName();String suf = StringUtils.substringAfter(name, ".");String pre = StringUtils.substringBefore(name, ".");FileInputStream fis = new FileInputStream(files[i]);if ("m3u8".equals(suf)){if (flag && filename.equals(pre)){//这是封装的上传阿里云oss的方法url = OSSFactory.build().upload(fis, "video/" + filename + "/" + name);flag = false;}} else if ("ts".equals(suf)){OSSFactory.build().uploadPublic(fis, "video/" + filename + "/" + name);}fis.close();FileUtils.deletefile(files[i]);}}//删除文件夹fileFolder.delete();/*********本地上传(Tomcat配置映射C:/upload/file)*********/} catch (Exception e) {e.printStackTrace();R.error("上传异常");}return R.ok().put("data",url);}

ffmpeg视频转码工具类:

/***  mp4转换m3u8工具类*/
@Component
public class ConvertM3U8 {@Value("${m3u8.ffmpegpath}")private String ffmpegpath; // ffmpeg.exe的目录public boolean convertOss(String folderUrl,String fileName){if (!checkfile(folderUrl + fileName)){System.out.println("文件不存在!");return false;}//验证文件后缀String suffix = StringUtils.substringAfter(fileName, ".");String fileFullName = StringUtils.substringBefore(fileName, ".");if (!validFileType(suffix)){return false;}return  processM3U8(folderUrl,fileName,fileFullName);}/*** 验证上传文件后缀* @param type* @return*/private boolean validFileType ( String type ) {if ("mp4".equals(type)){return true;}return false;}/*** 验证是否是文件格式* @param path* @return*/private boolean checkfile(String path) {File file = new File(path);if (!file.isFile()) {return false;} else {return true;}}// ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)/*** ffmpeg程序转换m3u8* @param folderUrl* @param fileName* @param fileFullName* @return*/private boolean processM3U8(String folderUrl,String fileName, String fileFullName) {//这里就写入执行语句就可以了List commend = new java.util.ArrayList();commend.add(ffmpegpath);commend.add("-i");commend.add(folderUrl+fileName);commend.add("-c:v");commend.add("libx264");commend.add("-hls_time");commend.add("20");commend.add("-hls_list_size");commend.add("0");commend.add("-c:a");commend.add("aac");commend.add("-strict");commend.add("-2");commend.add("-f");commend.add("hls");commend.add(folderUrl+ fileFullName +".m3u8");try {ProcessBuilder builder = new ProcessBuilder();//javabuilder.command(commend);Process p = builder.start();int i = doWaitFor(p);System.out.println("------>"+i);p.destroy();return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 监听ffmpeg运行过程* @param p* @return*/public int doWaitFor(Process p) {InputStream in = null;InputStream err = null;int exitValue = -1; // returned to caller when p is finishedtry {System.out.println("comeing");in = p.getInputStream();err = p.getErrorStream();boolean finished = false; // Set to true when p is finishedwhile (!finished) {try {while (in.available() > 0) {Character c = new Character((char) in.read());System.out.print(c);}while (err.available() > 0) {Character c = new Character((char) err.read());System.out.print(c);}exitValue = p.exitValue();finished = true;} catch (IllegalThreadStateException e) {Thread.currentThread().sleep(500);}}} catch (Exception e) {System.err.println("doWaitFor();: unexpected exception - "+ e.getMessage());} finally {try {if (in != null) {in.close();}} catch (IOException e) {System.out.println(e.getMessage());}if (err != null) {try {err.close();} catch (IOException e) {System.out.println(e.getMessage());}}}return exitValue;}}

(四)上传m3u8文件至OSS需要注意的问题

1.同一个视频的m3u8格式文件以及ts文件需要放在同一级目录。最好是一个视频的相关文件放入以文件名命名的路径下以示区别

2.m3u8链接无法播放,video.js提示无法访问对应资源,需要在阿里云oss上设置跨域。bucket空间—>基础设置—>跨域设置


3.ts文件的读写权限需要公共读不然video.js访问不到的,然后为了防止视频被恶意下载可以设置防盗链

参考资料:
1.网站播放视频较慢,利用mp4转m3u8解决
2.m3u8结构以及hls协议简单解析
3.windows使用ffmpeg转m3u8使用参数详解

Java 利用ffmpeg工具实现视频MP4转m3u8相关推荐

  1. java利用ffmpeg追加合并视频文件

    java利用ffmpeg追加合并视频文件 首先要用到ffmpeg,可以根据操作系统自行下载 每个视频格式要一样,分辨率要一样 多个视频地址以list存放,直接上代码 /*** 合并视频文件* @par ...

  2. 利用FFmpeg转码生成MP4文件

    利用FFmpeg转码生成MP4文件 2017年06月24日 14:42:53 阅读数:2401 项目中,需要把一路音频流及一路视频流分别转码,生成指定格式(MP4)文件.在使用ffmpeg转码生成mp ...

  3. Java 利用hutool工具实现导出excel并合并单元格

    Java 利用hutool工具实现导出excel并合并单元格 controller层调用service,就一个核心方法,没错就下面这个代码就能实现了.前提是项目里面要引用hutool包.把我这个复制到 ...

  4. java利用core 工具实现二维码的生成与解析

    java利用core 工具实现二维码的生成与解析 简单介绍下二维码:二维码其实就是一种编码技术,只是这种编码技术是用在图片上了,将给定的一些文字,数字转换为一张经过特定编码的图片,而解析二维码则相反, ...

  5. java利用FFMpeg将mp4转换为gif

    网上和官方资料整合 存在问题,在不丢帧的情况下转换后的gif会比原始mp4文件大很多. package jinx; import java.io.BufferedReader; import java ...

  6. 使用java调用ffmpeg命令将视频分屏并音视频同时播放(二分屏)

    实现想法 使用ffmpeg命令中的filter_complex(滤镜)参数来进行展示 引入javacv版本 <dependency><groupId>org.bytedeco& ...

  7. JAVA调用FFmpeg实现音视频转码加水印功能

    目录 目录 写在前面 MAVEN引用 获取音视频基本信息 音频转码成Mp3格式 视频转码成Mp4格式 视频转码成Mp4并添加文字水印 视频转码成Mp4并添加图片水印 测试代码 写在前面 如今各大云厂商 ...

  8. (三)利用ffmpeg实现简单的MP4推流

    首先的话,我想写感谢一个带我进入音视频处理领域的人,虽然从未谋面,但是是他的博客指引了我学习音视频开发的道路,启蒙了一个曾经迷茫的程序员.但是很可惜,他已经在2016年不幸离开了我们,他是雷霄骅,一位 ...

  9. 利用ffmpeg+QSV进行视频处理

    引言 ffmpeg是一个视频处理领域的"瑞士军刀",在很多应用中都会用到,这里就不详细介绍它的使用啦,有需要的可以参考其官方文档和大量网上的资料. 这里着重介绍一下qsv这个东东, ...

最新文章

  1. SAP产品概念及版本简介
  2. TestFlight
  3. mysql和oracle数据库兼容性_oracle数据库兼容mysql的差异写法
  4. [每日一题] OCP1z0-047 :2013-07-14 正则表达式
  5. Java面试知识点手工笔记(推荐)(转)
  6. 计算机随机储存器是什么,随机存储器是什么
  7. python123随机密码生成_Python生成对应随机密码文件
  8. [飘渺女声]罗琳娜 麦肯尼(Loreena McKennitt)
  9. 如何快速打出希腊字母
  10. 67 Ways to Increase Conversion with Cognitive Biases
  11. 转载:林锐:大学十年(一个程序员的路程)(全)
  12. python 分类问题 画roc曲线实战
  13. visual c++ 动态链接库调用总结
  14. 学习游戏软件开发需要哪些基础知识
  15. 搭建S60手机端Python软件运行,开发,发布平台
  16. 联想服务器提示系统初始化,联想服务器故障
  17. Juniper认证,网络工程师的第二语言
  18. 生成对抗网络(GAN)简单梳理
  19. V4d:4d Convolutional Neural Networks For Video-level Representation Learning
  20. 订餐APP肥了餐馆饿了自己

热门文章

  1. SQL计算月环比、月同比
  2. access的否定形式_雅思考试对于新手有多难?
  3. RGMII_PHY测试笔记1 基于开发板MiS603-X25
  4. 【网络工程】二层与三层交换机都知道 那么四层交换机是什么?
  5. 低调的华丽:从服务器开发的角度认识 asp.net 中的回调技术
  6. 【ZT】【详细教程】WPS如何关闭自动更新和WPS热点?(ksomisc.exe)
  7. [Linux] WIN7下Virtualbox虚拟Ubuntu共享文件夹设置
  8. 几种能让Mac“飞”起来的系统空间清理方法
  9. 【Ubuntu】普通用户修改了/etc/sudoers文件权限导致的问题
  10. 与你的梦,种植于青山绿水间