-
2021-02-12 10:29:44
原始视频通常需要经过编码处理,生成m3u8和ts文件方可基于HLS协议播放视频。通常用户上传原始视频,系统 自动处理成标准格式,系统对用户上传的视频自动编码、转换,最终生成m3u8文件和ts文件,
处理流程如下:
1、用户上传视频成功
2、系统对上传成功的视频自动开始编码处理
3、用户查看视频处理结果,没有处理成功的视频用户可在管理界面再次触发处理
4、视频处理完成将视频地址及处理结果保存到数据库
VideoUtil
package com.xuecheng.framework.utils;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* 此文件作为视频文件处理父类,提供:
* 1、查看视频时长
* 2、校验两个视频的时长是否相等
*
*/
public class VideoUtil {
String ffmpeg_path = "D:\\Program Files\\ffmpeg-20180227-fa0c9d6-win64-static\\bin\\ffmpeg.exe";//ffmpeg的安装位置
public VideoUtil(String ffmpeg_path){
this.ffmpeg_path = ffmpeg_path;
}
//检查视频时间是否一致
public Boolean check_video_time(String source,String target) {
String source_time = get_video_time(source);
//取出时分秒
source_time = source_time.substring(0,source_time.lastIndexOf("."));
String target_time = get_video_time(target);
//取出时分秒
target_time = target_time.substring(0,target_time.lastIndexOf("."));
if(source_time == null || target_time == null){
return false;
}
if(source_time.equals(target_time)){
return true;
}
return false;
}
//获取视频时间(时:分:秒:毫秒)
public String get_video_time(String video_path) {
/*
ffmpeg -i lucene.mp4
*/
List commend = new ArrayList();
commend.add(ffmpeg_path);
commend.add("-i");
commend.add(video_path);
try {
ProcessBuilder builder = new ProcessBuilder();
builder.command(commend);
//将标准输入流和错误输入流合并,通过标准输入流程读取信息
builder.redirectErrorStream(true);
Process p = builder.start();
String outstring = waitFor(p);
System.out.println(outstring);
int start = outstring.trim().indexOf("Duration: ");
if(start>=0){
int end = outstring.trim().indexOf(", start:");
if(end>=0){
String time = outstring.substring(start+10,end);
if(time!=null && !time.equals("")){
return time.trim();
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public String waitFor(Process p) {
InputStream in = null;
InputStream error = null;
String result = "error";
int exitValue = -1;
StringBuffer outputString = new StringBuffer();
try {
in = p.getInputStream();
error = p.getErrorStream();
boolean finished = false;
int maxRetry = 600;//每次休眠1秒,最长执行时间10分种
int retry = 0;
while (!finished) {
if (retry > maxRetry) {
return "error";
}
try {
while (in.available() > 0) {
Character c = new Character((char) in.read());
outputString.append(c);
System.out.print(c);
}
while (error.available() > 0) {
Character c = new Character((char) in.read());
outputString.append(c);
System.out.print(c);
}
//进程未结束时调用exitValue将抛出异常
exitValue = p.exitValue();
finished = true;
} catch (IllegalThreadStateException e) {
Thread.currentThread().sleep(1000);//休眠1秒
retry++;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
return outputString.toString();
}
public static void main(String[] args) throws IOException {
String ffmpeg_path = "D:\\Program Files\\ffmpeg-20180227-fa0c9d6-win64-static\\bin\\ffmpeg.exe";//ffmpeg的安装位置
VideoUtil videoUtil = new VideoUtil(ffmpeg_path);
String video_time = videoUtil.get_video_time("E:\\ffmpeg_test\\1.avi");
System.out.println(video_time);
}
}
Mp4VideoUtil
package com.xuecheng.framework.utils;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* Created by admin on 2018/3/6.
*/
public class Mp4VideoUtil extends VideoUtil {
String ffmpeg_path = "D:\\Program Files\\ffmpeg-20180227-fa0c9d6-win64-static\\bin\\ffmpeg.exe";//ffmpeg的安装位置
String video_path = "D:\\BaiduNetdiskDownload\\test1.avi";
String mp4_name = "test1.mp4";
String mp4folder_path = "D:/BaiduNetdiskDownload/Movies/test1/";
public Mp4VideoUtil(String ffmpeg_path, String video_path, String mp4_name, String mp4folder_path){
super(ffmpeg_path);
this.ffmpeg_path = ffmpeg_path;
this.video_path = video_path;
this.mp4_name = mp4_name;
this.mp4folder_path = mp4folder_path;
}
//清除已生成的mp4
private void clear_mp4(String mp4_path){
//删除原来已经生成的m3u8及ts文件
File mp4File = new File(mp4_path);
if(mp4File.exists() && mp4File.isFile()){
mp4File.delete();
}
}
/**
* 视频编码,生成mp4文件
* @return 成功返回success,失败返回控制台日志
*/
public String generateMp4(){
//清除已生成的mp4
clear_mp4(mp4folder_path+mp4_name);
/*
ffmpeg.exe -i lucene.avi -c:v libx264 -s 1280x720 -pix_fmt yuv420p -b:a 63k -b:v 753k -r 18 .\lucene.mp4
*/
List commend = new ArrayList();
//commend.add("D:\\Program Files\\ffmpeg-20180227-fa0c9d6-win64-static\\bin\\ffmpeg.exe");
commend.add(ffmpeg_path);
commend.add("-i");
// commend.add("D:\\BaiduNetdiskDownload\\test1.avi");
commend.add(video_path);
commend.add("-c:v");
commend.add("libx264");
commend.add("-y");//覆盖输出文件
commend.add("-s");
commend.add("1280x720");
commend.add("-pix_fmt");
commend.add("yuv420p");
commend.add("-b:a");
commend.add("63k");
commend.add("-b:v");
commend.add("753k");
commend.add("-r");
commend.add("18");
commend.add(mp4folder_path + mp4_name );
String outstring = null;
try {
ProcessBuilder builder = new ProcessBuilder();
builder.command(commend);
//将标准输入流和错误输入流合并,通过标准输入流程读取信息
builder.redirectErrorStream(true);
Process p = builder.start();
outstring = waitFor(p);
} catch (Exception ex) {
ex.printStackTrace();
}
Boolean check_video_time = this.check_video_time(video_path, mp4folder_path + mp4_name);
if(!check_video_time){
return outstring;
}else{
return "success";
}
}
public static void main(String[] args) throws IOException {
String ffmpeg_path = "D:\\Program Files\\ffmpeg-20180227-fa0c9d6-win64-static\\bin\\ffmpeg.exe";//ffmpeg的安装位置
String video_path = "E:\\ffmpeg_test\\1.avi";
String mp4_name = "809694a6a974c35e3a36f36850837d7c.mp4";
String mp4_path = "F:/develop/upload/8/0/809694a6a974c35e3a36f36850837d7c/";
Mp4VideoUtil videoUtil = new Mp4VideoUtil(ffmpeg_path,video_path,mp4_name,mp4_path);
String s = videoUtil.generateMp4();
System.out.println(s);
}
}
HlsVideoUtil
package com.xuecheng.framework.utils;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* 此文件用于视频文件处理,步骤如下:
* 1、生成mp4
* 2、生成m3u8
*
*/
public class HlsVideoUtil extends VideoUtil {
String ffmpeg_path = "D:\\Program Files\\ffmpeg-20180227-fa0c9d6-win64-static\\bin\\ffmpeg.exe";//ffmpeg的安装位置
String video_path = "D:\\BaiduNetdiskDownload\\test1.avi";
String m3u8_name = "test1.m3u8";
String m3u8folder_path = "D:/BaiduNetdiskDownload/Movies/test1/";
public HlsVideoUtil(String ffmpeg_path, String video_path, String m3u8_name,String m3u8folder_path){
super(ffmpeg_path);
this.ffmpeg_path = ffmpeg_path;
this.video_path = video_path;
this.m3u8_name = m3u8_name;
this.m3u8folder_path = m3u8folder_path;
}
private void clear_m3u8(String m3u8_path){
//删除原来已经生成的m3u8及ts文件
File m3u8dir = new File(m3u8_path);
if(!m3u8dir.exists()){
m3u8dir.mkdirs();
}
/* if(m3u8dir.exists()&&m3u8_path.indexOf("/hls/")>=0){//在hls目录方可删除,以免错误删除
String[] children = m3u8dir.list();
//删除目录中的文件
for (int i = 0; i < children.length; i++) {
File file = new File(m3u8_path, children[i]);
file.delete();
}
}else{
m3u8dir.mkdirs();
}*/
}
/**
* 生成m3u8文件
* @return 成功则返回success,失败返回控制台日志
*/
public String generateM3u8(){
//清理m3u8文件目录
clear_m3u8(m3u8folder_path);
/*
ffmpeg -i lucene.mp4 -hls_time 10 -hls_list_size 0 -hls_segment_filename ./hls/lucene_%05d.ts ./hls/lucene.m3u8
*/
// String m3u8_name = video_name.substring(0, video_name.lastIndexOf("."))+".m3u8";
List commend = new ArrayList();
commend.add(ffmpeg_path);
commend.add("-i");
commend.add(video_path);
commend.add("-hls_time");
commend.add("10");
commend.add("-hls_list_size");
commend.add("0");
commend.add("-hls_segment_filename");
// commend.add("D:/BaiduNetdiskDownload/Movies/test1/test1_%05d.ts");
commend.add(m3u8folder_path + m3u8_name.substring(0,m3u8_name.lastIndexOf(".")) + "_%05d.ts");
// commend.add("D:/BaiduNetdiskDownload/Movies/test1/test1.m3u8");
commend.add(m3u8folder_path + m3u8_name );
String outstring = null;
try {
ProcessBuilder builder = new ProcessBuilder();
builder.command(commend);
//将标准输入流和错误输入流合并,通过标准输入流程读取信息
builder.redirectErrorStream(true);
Process p = builder.start();
outstring = waitFor(p);
} catch (Exception ex) {
ex.printStackTrace();
}
//通过查看视频时长判断是否成功
Boolean check_video_time = check_video_time(video_path, m3u8folder_path + m3u8_name);
if(!check_video_time){
return outstring;
}
//通过查看m3u8列表判断是否成功
List ts_list = get_ts_list();
if(ts_list == null){
return outstring;
}
return "success";
}
/**
* 检查视频处理是否完成
* @return ts列表
*/
public List get_ts_list() {
// String m3u8_name = video_name.substring(0, video_name.lastIndexOf("."))+".m3u8";
List fileList = new ArrayList();
List tsList = new ArrayList();
String m3u8file_path =m3u8folder_path + m3u8_name;
BufferedReader br = null;
String str = null;
String bottomline = "";
try {
br = new BufferedReader(new FileReader(m3u8file_path));
while ((str = br.readLine()) != null) {
bottomline = str;
if(bottomline.endsWith(".ts")){
tsList.add(bottomline);
}
//System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(br!=null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (bottomline.contains("#EXT-X-ENDLIST")) {
// fileList.add(hls_relativepath+m3u8_name);
fileList.addAll(tsList);
return fileList;
}
return null;
}
public static void main(String[] args) throws IOException {
String ffmpeg_path = "D:\\Program Files\\ffmpeg-20180227-fa0c9d6-win64-static\\bin\\ffmpeg.exe";//ffmpeg的安装位置
String video_path = "E:\\ffmpeg_test\\1.mp4";
String m3u8_name = "1.m3u8";
String m3u8_path = "E:\\ffmpeg_test\\1\\";
HlsVideoUtil videoUtil = new HlsVideoUtil(ffmpeg_path,video_path,m3u8_name,m3u8_path);
String s = videoUtil.generateM3u8();
System.out.println(s);
System.out.println(videoUtil.get_ts_list());
}
}
MediaProcessTask
package com.xuecheng.manage_media_processor.mq;
import com.alibaba.fastjson.JSON;
import com.xuecheng.framework.domain.media.MediaFile;
import com.xuecheng.framework.domain.media.MediaFileProcess_m3u8;
import com.xuecheng.framework.utils.HlsVideoUtil;
import com.xuecheng.framework.utils.Mp4VideoUtil;
import com.xuecheng.manage_media_processor.dao.MediaFileMapper;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
/**
* Created by Administrator on 2020/6/7 0007.
*/
@Component
public class MediaProcessTask {
@Value("${xc-service-manage-media.ffmpeg-path}")
String ffmpeg_path;
//上传文件根目录
@Value("${xc-service-manage-media.video-location}")
String serverPath;
@Autowired
private MediaFileMapper mediaFileMapper;
//接收视频处理消息进行视频处理
@RabbitListener(queues = "${xc-service-manage-media.mq.queue-media-video-processor}")
public void receiveMediaProcessTask(String msg ){
//1.解析消息内容,得到mediaId
Map map = JSON.parseObject(msg, Map.class);
String mediaId = (String) map.get("mediaId");
//2.拿到mediaId从数据库中查询文件信息
MediaFile mediaFile = mediaFileMapper.findByFileId(mediaId);
if(null == mediaFile){
return;
}
//文件类型
String fileType = mediaFile.getFileType();
if(!fileType.equals("avi")){
mediaFile.setProcessStatus("303004");//无需处理
mediaFileMapper.save(mediaFile);
return ;
}else{
//需要处理
mediaFile.setProcessStatus("303001");//处理中
mediaFileMapper.save(mediaFile);
}
//3.使用工具类将avi文件生成mp4
//String ffmpeg_path, String video_path, String mp4_name, String mp4folder_path
//要处理的视频文件的路径
String video_path = serverPath + mediaFile.getFilePath() + mediaFile.getFileName();
//生成的mp4的文件名称
String mp4_name = mediaFile.getFileId() + ".mp4";
//生成的mp4所在的路径
String mp4folder_path = serverPath + mediaFile.getFilePath();
Mp4VideoUtil mp4VideoUtil = new Mp4VideoUtil(ffmpeg_path,video_path,mp4_name,mp4folder_path);
//进行处理
String result = mp4VideoUtil.generateMp4();
if(result == null || !result.equals("success")){
//处理失败
mediaFile.setProcessStatus("303003");
//定义mediaFileProcess_m3u8
MediaFileProcess_m3u8 mediaFileProcess_m3u8 = new MediaFileProcess_m3u8();
//记录失败原因
mediaFileProcess_m3u8.setErrormsg(result);
mediaFile.setMediaFileProcess_m3u8(mediaFileProcess_m3u8);
mediaFileMapper.save(mediaFile);
return ;
}
//4.将mp4生成m3u8和ts文件
//String ffmpeg_path, String video_path, String m3u8_name,String m3u8folder_path
//mp4视频文件路径
String mp4_video_path = serverPath + mediaFile.getFilePath() + mp4_name;
//m3u8_name文件名称
String m3u8_name = mediaFile.getFileId() +".m3u8";
//m3u8文件所在目录
String m3u8folder_path = serverPath + mediaFile.getFilePath() + "hls/";
HlsVideoUtil hlsVideoUtil = new HlsVideoUtil(ffmpeg_path,mp4_video_path,m3u8_name,m3u8folder_path);
//生成m3u8和ts文件
String tsResult = hlsVideoUtil.generateM3u8();
if(tsResult == null || !tsResult.equals("success")){
//处理失败
mediaFile.setProcessStatus("303003");
//定义mediaFileProcess_m3u8
MediaFileProcess_m3u8 mediaFileProcess_m3u8 = new MediaFileProcess_m3u8();
//记录失败原因
mediaFileProcess_m3u8.setErrormsg(result);
mediaFile.setMediaFileProcess_m3u8(mediaFileProcess_m3u8);
mediaFileMapper.save(mediaFile);
return ;
}
//处理成功
//获取ts文件列表
List ts_list = hlsVideoUtil.get_ts_list();
mediaFile.setProcessStatus("303002");
//定义mediaFileProcess_m3u8
MediaFileProcess_m3u8 mediaFileProcess_m3u8 = new MediaFileProcess_m3u8();
mediaFileProcess_m3u8.setTslist(ts_list);
mediaFile.setMediaFileProcess_m3u8(mediaFileProcess_m3u8);
//保存fileUrl(此url就是视频播放的相对路径)
String fileUrl =mediaFile.getFilePath() + "hls/"+m3u8_name;
mediaFile.setFileUrl(fileUrl);
mediaFileMapper.save(mediaFile);
}
}
更多相关内容 -
Java编写的Java视频处理程序
2021-03-16 06:04:07Java编写的Java视频处理程序,用Java仅仅写一个播放媒体文件的程序似乎不过瘾,能不能自己动手来处理媒体数据,达到“奇特”的播放效果呢?答案是可以的,而且还是比较容易的,这得归功于JMF API 提供的方便的接口。... -
java(springBoot)视频处理,视频剪辑(对视频,音频,字幕等处理)
2021-07-01 21:59:07源码中有说明文档,按照文档...源码中包括有视频合成,视频加背景音乐,多图片+音频合并为视频,音频合并,视频加字幕,视频去声音,视频格式转换,视频播放,视频裁剪,获取音频或视频信息,定义视频大小,视频截图 -
java使用ffmpeg处理视频的方法
2020-08-24 22:52:00主要介绍了java使用ffmpeg处理视频的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下 -
java操作视频处理功能API
2018-12-29 16:45:15本代码示例包含JAVA调用ffmpeg的SDK直接处理上传视频的功能,示例代码里面有截图处理功能,其他功能大家可以直接按照这个流程调用SDK的不同对应的API就可以处理了。具体API可以参考ffmpeg的API接口定义。 -
Java编写的Java视频处理程序.rar
2019-07-10 09:48:21Java编写的Java视频处理程序,用Java仅仅写一个播放媒体文件的程序似乎不过瘾,能不能自己动手来处理媒体数据,达到“奇特”的播放效果呢?答案是可以的,而且还是比较容易的,这得归功于JMF API 提供的方便的接口。... -
java操作视频文件
2018-08-31 18:57:48AVE(Java Audio Video Encoder)是ffmpeg项目的一个Java封装。可以利用JAVE在不同的视频与音频格式之间相互转换。比如能够将AVI文件转换成MPEG格式的文件,分离和转换视频与音频轨道,压缩视频,改变大小和比例。 -
java视频音频的处理.pdf
2016-01-09 10:09:29是java编程处理音频视频的文档。pdf -
java ffmpeg实现视屏剪辑、srt字幕嵌入、视频合成、图片转视频
2020-05-19 19:10:02java ffmpeg实现视屏剪辑、srt字幕嵌入、视频合成、图片转视频 通过test类运行。demo基于jave的源码。对ffmpeg的两种系统下的执行文件进行了替换。所以ffmpeg版本是最新的。可以执行ffmpeg官网上大多数的命令 -
Java使用FFmpeg处理视频文件的方法教程
2020-08-26 06:32:44主要给大家介绍了关于Java使用FFmpeg处理视频文件的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧 -
javacv视频抽帧的实现过程详解(附代码)
2020-08-25 20:21:45主要介绍了javacv视频抽帧的实现过程详解(附代码),视频抽帧可以做一些处理,比如水印,去水印等操作,然后再合成视频,需要的朋友可以参考下 -
Java 使用 FFmpeg 处理视频文件示例代码详解
2020-08-24 22:50:16主要介绍了Java 使用 FFmpeg 处理视频文件示例代码,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下 -
java 服务器使用ffmpeg处理视频工具类
2020-05-11 12:21:08java 服务器处理使用ffmpeg处理视频工具类,使用前先按照ffmpeg,并将其安装目录的bin路径加入环境变量,目前主要实现压缩,转码,增加字幕(可设定字体及位置),获取视频时长及源数据信息等功能,也可再此基础上... -
Java视频特效处理(超全)/PC版美颜相机-附件资源
2021-03-05 15:21:22Java视频特效处理(超全)/PC版美颜相机-附件资源 -
java使用ffmpeg进行视频处理
2022-04-22 16:20:17使用FFmpeg进行视频解析上传视频数据 package com.greathiit.videoupload.ffmpeg; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.util.LinkedList; import ...使用FFmpeg进行视频解析上传视频数据
package com.greathiit.videoupload.ffmpeg; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class VideoFFmpeg { public static void main(String[] args) { String path="E:\\视频批量上传项目\\视频"; String timeLength = getVideoTime("E:\\视频批量上传项目\\视频\\aa.mp4","D:\\learn\\FFmpeg\\ffmpeg-N-102841-g041267b558-win64-lgpl-shared\\bin\\ffmpeg.exe"); if(timeLength.length()>0){//字符串截取 timeLength =timeLength.substring(0,timeLength.indexOf(".")); } System.out.println("视频时长:"+timeLength); traverseFolder1(path); } /** *获取视频时间 * @param video_path 视频路径 * @param ffmpeg_path ffmpeg安装路径 * @return */ public static String getVideoTime(String video_path, String ffmpeg_path) { List<String> commands = new java.util.ArrayList<String>(); commands.add(ffmpeg_path); commands.add("-i"); commands.add(video_path); System.out.println("命令行:"+ffmpeg_path+" -i "+video_path); try { ProcessBuilder builder = new ProcessBuilder(); builder.command(commands); final Process p = builder.start(); //从输入流中读取视频信息 BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream())); StringBuffer sb = new StringBuffer(); String line = ""; while ((line = br.readLine()) != null) { sb.append(line); } br.close(); //从视频信息中解析时长 String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s"; Pattern pattern = Pattern.compile(regexDuration); Matcher m = pattern.matcher(sb.toString()); if (m.find()) { System.out.println(video_path+",视频时长:"+m.group(1)+", 开始时间:"+m.group(2)+",比特率:"+m.group(3)+"kb/s"); return m.group(1); } } catch (Exception e) { e.printStackTrace(); } return ""; } public static void traverseFolder1(String path) { int fileNum = 0, folderNum = 0; File file = new File(path); if (file.exists()) { LinkedList<File> list = new LinkedList<File>(); File[] files = file.listFiles(); for (File file2 : files) { if (file2.isDirectory()) { System.out.println("文件夹:" + file2.getAbsolutePath()); list.add(file2); folderNum++; } else { System.out.println("文件:" + file2.getAbsolutePath()); fileNum++; } } File temp_file; while (!list.isEmpty()) { temp_file = list.removeFirst(); files = temp_file.listFiles(); for (File file2 : files) { if (file2.isDirectory()) { System.out.println("文件夹:" + file2.getAbsolutePath()); list.add(file2); folderNum++; } else { System.out.println("文件:" + file2.getAbsolutePath()); fileNum++; } } } } else { System.out.println("文件不存在!"); } System.out.println("文件夹共有:" + folderNum + ",文件共有:" + fileNum); } }
使用ffmpeg来获取文件的时长
https://www.cnblogs.com/firstdream/p/7676732.html : 遍历文件夹中的目录和文件
https://www.jb51.net/article/122711.htm :文件名称修改
遇到问题: 在视频修改的时候由于遍历文件目录和文件名称的时候A层目录修改了到遍历A下一层目录或者文件的时候由于保存在List集合中的绝对路径并没有发生变化就会出现文件找不到的问题。例如:
第一次修改的目录:F:\BaiduNetdiskDownload\mksz355 - 编程必备基础 计算机组成原理+操作系统+计算机网络(更多IT教程 微信352852792)==》F:\BaiduNetdiskDownload\mksz355 - 编程必备基础 计算机组成原理+操作系统+计算机网络
第遍历下一层目录:F:\BaiduNetdiskDownload\mksz355 - 编程必备基础 计算机组成原理+操作系统+计算机网络**(更多IT教程 微信352852792)**\第1章 编程必备基础:计算机组成原理、操作系统、计算机网络(更多IT教程 微信352852792) 此时加黑部分文字已经被第一次修改这时如果执行文件修改就会出现文件找不到的异常
解决办法: 使用回调函数当第一次进行修改后跳出循环重新遍历保存到List集合中如果上一次没有做修改则继续循环
具体逻辑代码如下:
package com.greathiit.videoupload.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.greathiit.videoupload.entity.Course; import com.greathiit.videoupload.entity.Lesson; import com.greathiit.videoupload.entity.Section; import com.greathiit.videoupload.mapper.CourseMapper; import com.greathiit.videoupload.service.ICourseService; import com.greathiit.videoupload.service.ILessonService; import com.greathiit.videoupload.service.ISectionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * <p> * 服务实现类 * </p> * * @author wtong * @since 2022-04-13 */ @Service public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService { private String NO="no"; @Autowired private ILessonService lessonService; @Autowired private ISectionService statisticsService; @Override public void saveCourse(String path) { // String timeLength = getVideoTime("E:\\视频批量上传项目\\视频\\aa.mp4","D:\\learn\\FFmpeg\\ffmpeg-N-102841-g041267b558-win64-lgpl-shared\\bin\\ffmpeg.exe"); // if(timeLength.length()>0){//字符串截取 // timeLength =timeLength.substring(0,timeLength.indexOf(".")); // } // System.out.println("视频时长:"+timeLength); traverseFolder1(path); } private void dataEntry(List<String> stringList) { // System.out.println(stringList.get(4)); System.out.println(stringList); Course course = new Course(); course.setTitle(stringList.get(0)); course.setDescription("<p>"+stringList.get(0)+"<br>></p>"); course.setLanguage("chinese"); course.setCategoryId(4); course.setSubCategoryId(3); course.setSection("[]"); course.setRequirements("[]"); course.setLevel("beginner"); course.setUserId(85); course.setDateAdded(1623999600); course.setIsAdmin(0); course.setStatus("active"); course.setMetaKeywords(stringList.get(0)); course.setIsFreeCourse(1); // //保存章节 QueryWrapper<Course> queryWrapper=new QueryWrapper<>(); queryWrapper.lambda().eq(Course::getTitle,course.getTitle()); // this.saveOrUpdate(course,queryWrapper); Section section=new Section(); section.setTitle(stringList.get(1)); section.setCourseId(417); try { section.setOrder(Integer.parseInt(section.getTitle().substring(1,3))); }catch (NumberFormatException e){ section.setOrder(Integer.parseInt(section.getTitle().substring(1,2))); } QueryWrapper<Section> sectionQueryWrapper=new QueryWrapper<>(); sectionQueryWrapper.lambda().eq(Section::getTitle,section.getTitle()); // statisticsService.saveOrUpdate(section,sectionQueryWrapper); Lesson lesson = new Lesson(); lesson.setTitle(stringList.get(2)); lesson.setDuration(stringList.get(3)); lesson.setVideoUrl(stringList.get(6).replace("F:\\BaiduNetdiskDownload","")); lesson.setVideoUrlForMobileApplication(stringList.get(6).replace("F:\\BaiduNetdiskDownload","")); Long dateAdded = System.currentTimeMillis(); // String s = dateAdded.toString(); // Integer sp = Integer.parseInt(s); // lesson.setDateAdded(sp); lesson.setLessonType("video"); lesson.setAttachmentType("url"); try { lesson.setOrder(Integer.parseInt(lesson.getTitle().substring(2,4))); }catch (NumberFormatException e){ lesson.setOrder(Integer.parseInt(lesson.getTitle().substring(2,3))); } lesson.setVideoType("Vimeo"); lesson.setVideoTypeForMobileApplication("html5"); Course one = this.getOne(queryWrapper); lesson.setCourseId(one.getId()); Section one1 = statisticsService.getOne(sectionQueryWrapper); lesson.setSectionId(one1.getId()); lesson.setVideoTypeForMobileApplication(stringList.get(6).replace("F:\\BaiduNetdiskDownload","")); QueryWrapper<Lesson> queryWrapperlqueryWrap=new QueryWrapper<>(); queryWrapperlqueryWrap.lambda().eq(Lesson::getTitle,lesson.getTitle()); lessonService.saveOrUpdate(lesson,queryWrapperlqueryWrap); System.out.println(lesson.toString()); } // public static void main(String[] args) { // String path="F:\\BaiduNetdiskDownload\\mksz355 - 编程必备基础 计算机组成原理+操作系统+计算机网络"; String timeLength = getVideoTime("E:\\视频批量上传项目\\视频\\aa.mp4","D:\\learn\\FFmpeg\\ffmpeg-N-102841-g041267b558-win64-lgpl-shared\\bin\\ffmpeg.exe"); if(timeLength.length()>0){//字符串截取 timeLength =timeLength.substring(0,timeLength.indexOf(".")); } System.out.println("视频时长:"+timeLength); // traverseFolder1(path); // // // } /** *获取视频时间 * @param video_path 视频路径 * @param ffmpeg_path ffmpeg安装路径 * @return */ public String getVideoTime(String video_path, String ffmpeg_path) { //将命令行拼接到list集合中 List<String> commands = new java.util.ArrayList<String>(); commands.add(ffmpeg_path); commands.add("-i"); commands.add(video_path); // System.out.println("命令行:"+ffmpeg_path+" -i "+video_path); try { ProcessBuilder builder = new ProcessBuilder(); builder.command(commands); final Process p = builder.start(); //从输入流中读取视频信息 BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream())); StringBuffer sb = new StringBuffer(); String line = ""; while ((line = br.readLine()) != null) { sb.append(line); } br.close(); //从视频信息中解析时长 String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*) kb\\/s"; Pattern pattern = Pattern.compile(regexDuration); Matcher m = pattern.matcher(sb.toString()); if (m.find()) { List<String > re=replace(video_path); // System.out.println(re.toString()); System.out.println(video_path+",视频时长:"+m.group(1)+", 开始时间:"+m.group(2)+",比特率:"+m.group(3)+"kb/s" ); re.add(m.group(1)); re.add(m.group(2)); re.add(m.group(3)); re.add(video_path); dataEntry(re); return m.group(1); } } catch (Exception e) { e.printStackTrace(); } return ""; } /** * 字符串分割 * @param video_path 需要分割的绝对路径 * @return 返回分割好的数据列表 */ private List<String> replace(String video_path) { String replace = video_path.replace("F:\\BaiduNetdiskDownload\\mksz355 - ", ""); Character a=92; String am=a.toString(); System.out.println(replace); System.out.println(""); String[] split1 = replace.split("\\\\"); int ac=split1.length; System.out.println(ac); String course = split1[0];//课程名称 String chapter = split1[1];//章节 String blues = split1[2]; String[] split2 = blues.split("\\."); blues = split2[0]; //集数 List<String> list=new ArrayList<>(); list.add(course); list.add(chapter); list.add(blues); return list; } public void traverseFolder1(String path) { int fileNum = 0, folderNum = 0; File file = new File(path); LinkedList<File> rnameList = new LinkedList<>(); if (file.exists()) { LinkedList<File> list = new LinkedList<File>(); File[] files = file.listFiles(); for (File file2 : files) { if (file2.isDirectory()) { // System.out.println("文件夹:" + file2.getAbsolutePath()); list.add(file2); rnameList.add(file2); folderNum++; } else { // System.out.println("文件1:" + file2.getAbsolutePath()); rnameList.add(file2); fileNum++; } } File temp_file; while (!list.isEmpty()) { temp_file = list.removeFirst(); files = temp_file.listFiles(); for (File file2 : files) { rnameList.add(file2); if (file2.isDirectory()) { // System.out.println("文件夹:" + file2.getAbsolutePath()); list.add(file2); folderNum++; } else { // System.out.println("文件2:" + file2.getAbsolutePath()); fileNum++; } } } } else { System.out.println("文件不存在!"); } System.out.println("文件夹共有:" + folderNum + ",文件共有:" + fileNum); int msize = 0; for (File file1 : rnameList) { String absolutePath = file1.getAbsolutePath(); String timeLength = getVideoTime(absolutePath,"D:\\learn\\FFmpeg\\ffmpeg-N-102841-g041267b558-win64-lgpl-shared\\bin\\ffmpeg.exe"); if(timeLength.length()>0){//字符串截取 timeLength =timeLength.substring(0,timeLength.indexOf(".")); } // System.out.println("视频时长:"+timeLength+"path"+absolutePath); // String result = rName(file1); // if(!result.equals(NO)){ // traverseFolder1( path); // break; // // } msize++; } } private String rName(File file2) { String absolutePath = file2.getAbsolutePath(); String[] split = absolutePath.split(File.pathSeparator); String s = split[split.length - 1]; String replace = s.replace("(更多IT教程 微信352852792)", ""); if(s.equals(replace)){ return NO; } File file1 = new File(replace); if(file2.renameTo(file1)){ System.out.println("修改成功"); }else { System.out.println("修改失败"); } return replace; } }
数据录入成功后的效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eE1EckoD-1650615602204)(C:\Users\29701\AppData\Roaming\Typora\typora-user-images\1649984062864.png)]
最后还有一个就是前期构建项目的时候遇到的小问题:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qadBEruP-1650615602206)(C:\Users\29701\AppData\Roaming\Typora\typora-user-images\1649984159309.png)]
mapper路径和上边的mapper路径冲突,spring容器前期构建的时候找不到mapper包下的bean解决办法修改为maqqer
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i1d20n1P-1650615602206)(C:\Users\29701\AppData\Roaming\Typora\typora-user-images\1649984317865.png)]
lace);
if(file2.renameTo(file1)){
System.out.println(“修改成功”);
}else {
System.out.println(“修改失败”);
}
return replace;
}
}数据录入成功后的效果 [外链图片转存中...(img-eE1EckoD-1650615602204)] 最后还有一个就是前期构建项目的时候遇到的小问题: [外链图片转存中...(img-qadBEruP-1650615602206)] mapper路径和上边的mapper路径冲突,spring容器前期构建的时候找不到mapper包下的bean解决办法修改为maqqer [外链图片转存中...(img-i1d20n1P-1650615602206)] mysql关键字加``解决 进行视频批量处理因为视频缺少h264加入h264生成新的文件后缀多.mp4
function recursive_list_dir(){
for file_or_dir inls $1
do
if [ -d 1 " / " 1"/" 1"/"file_or_dir ]
then
recursive_list_dir 1 " / " 1"/" 1"/"file_or_dir
else
file= 1 " / " 1"/" 1"/"file_or_dirif [ "${file##*.}" = "mp4" ] then aa="${file##*/}" if [ "${aa##*.}" = "mp4.mp4" ] then echo "ii" else docker run -it --name app_ffmpeg -v $PWD:/tmp/workdir jrottenberg/ffmpeg -i ${file:3} -vcodec h264 ${file:3}.mp4 docker rm -f app_ffmpeg fi fi fi done
}
recursive_list_dir $1 -
OpenCV3.2 Java图像处理视频学习教程
2021-06-09 11:26:37OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授... -
java如何对视频文件处理?包括拉流推流视频截取等?
2021-03-05 20:17:38推流过程首先为了将来可以扩展多种协议(TRSP、RTMP)的视频推流功能,我们创建BStreamer基类。/**1.基础视频流*/publicclassBStreamer{privateintwidth=640;privateintheight=480;privateStringurl;publicBStreamer...推流过程首先为了将来可以扩展多种协议(TRSP、RTMP)的视频推流功能,我们创建BStreamer基类。/**
1. 基础视频流
*/
public class BStreamer {
private int width = 640;
private int height = 480;
private String url;
public BStreamer(String url) {
this.url = url;
}
public BStreamer(String url, int w, int h) {
this.url = url;
if (w > 0 && h > 0) {
this.width = w;
this.height = h;
}
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}}12345678910111213141516171819202122232425262728293031323334353637383940414243根据上面BStreamer基类,我们扩展实现RTSP协议的视频推流器,由于本实例是采用FFMPEG为推流手段,所以我们下面创建FFmpegPusher实体类。public class FFmpegPusher extends BStreamer {
public FFmpegPusher(String url) {
super(url);
}
public FFmpegPusher(String url, int w, int h) {
super(url, w, h);
}
private Process process;
public void push(){
String basePath="F:\\ffmpeg-4.2.1-win64-shared\\bin";
String videoPath=String.format("%s\\test.mp4",basePath);
String ffmpegPath=String.format("%s\\ffmpeg",basePath);
try {
// 视频切换时,先销毁进程,全局变量Process process,方便进程销毁重启,即切换推流视频
if(process != null){
process.destroy();
System.out.println(">>>>>>>>>>推流视频切换<<<<<<<<
public static void main(String[] args) throws Exception {
String url="rtsp://192.168.56.1/test";
FFmpegPusher pusher=new FFmpegPusher(url);
pusher.push();
}}1234567运行以上测试程序得到如下结果
在服务端查看推流结果(服务下载地址:http://www.easydarwin.org/)
客户端测试拉取上面的视频流进行直播显示
-
javacv1.4版本视频处理主要使用的jar
2018-10-01 11:53:04最新的javacv1.4的最小的包,有看过我的博客中关于处理视频流或者截取图片的朋友,在自己找的包会经常出现问题。可以下载这个最新的包。相当稳定 -
Java 处理视频 、音频文件(读取视频时长等) - JAVE-附件资源
2021-03-02 15:04:35Java 处理视频 、音频文件(读取视频时长等) - JAVE-附件资源 -
Javacv处理视频,提取成帧图片,生成gif
2019-07-18 19:13:46提取本地视频的帧图片,根据本地视频生成gif,jar版本是1.4.1,maven项目 -
Java 实现视频裁剪(附代码) | Java工具类
2022-01-23 22:21:06本文提供将视频按照自定义尺寸进行裁剪的Java工具类,一如既往的实用主义。目录
前言
本文提供将视频按照自定义尺寸进行裁剪的Java工具类,一如既往的实用主义。
Maven依赖
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1.1-jre</version> </dependency> <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.5.5</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.5.2</version> </dependency>
代码
不废话,上代码。
package ai.guiji.csdn.tool; import cn.hutool.core.util.IdUtil; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import org.bytedeco.javacpp.Loader; import java.io.File; import java.text.MessageFormat; import java.util.Arrays; import java.util.List; /** * @Program: csdn @ClassName: CutOutTool @Author: 剑客阿良_ALiang @Date: 2022-01-23 18:27 @Description: * 裁剪工具 @Version: V1.0 */ public class CutOutTool { /** * 视频裁剪 * * @param videoPath 视频地址 * @param outputDir 临时目录 * @param startX 裁剪起始x坐标 * @param startY 裁剪起始y坐标 * @param weight 裁剪宽度 * @param height 裁剪高度 * @throws Exception 异常 */ public static String cutOutVideo( String videoPath, String outputDir, Integer startX, Integer startY, Integer weight, Integer height) throws Exception { List<String> paths = Splitter.on(".").splitToList(videoPath); String ext = paths.get(paths.size() - 1); if (!Arrays.asList("mp4", "avi", "flv").contains(ext)) { throw new Exception("format error"); } String resultPath = Joiner.on(File.separator).join(Arrays.asList(outputDir, IdUtil.simpleUUID() + "." + ext)); String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class); ProcessBuilder builder = new ProcessBuilder( ffmpeg, "-i", videoPath, "-vf", MessageFormat.format( "crop={0}:{1}:{2}:{3}", String.valueOf(weight), String.valueOf(height), String.valueOf(startX), String.valueOf(startY)), "-b", "2000k", "-y", "-threads", "5", "-preset", "ultrafast", "-strict", "-2", resultPath); builder.inheritIO().start().waitFor(); return resultPath; } public static void main(String[] args) throws Exception { System.out.println( cutOutVideo("C:\\Users\\yi\\Desktop\\3.mp4", "C:\\Users\\yi\\Desktop\\", 0, 0, 960, 1080)); } }
代码说明:
1、cutOutVideo方法参数分别为视频路径、输出临时目录、起始坐标x值、起始坐标y值、裁剪宽度、裁剪高度。
2、采用uuid作为临时输出唯一id,避免重复。
3、对文件后缀格式做了校验,可以按照需求自行调整。
4、裁剪尺寸不能超出视频分辨率限制,按照需求自行调整。
验证一下
准备的视频如下
执行结果
ffmpeg version 4.3.2 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 10.2.0 (Rev5, Built by MSYS2 project)
configuration: --prefix=.. --disable-iconv --disable-opencl --disable-sdl2 --disable-bzlib --disable-lzma --disable-linux-perf --enable-shared --enable-version3 --enable-runtime-cpudetect --enable-zlib --enable-libmp3lame --enable-libspeex --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libvo-amrwbenc --enable-openssl --enable-libopenh264 --enable-libvpx --enable-libfreetype --enable-libopus --enable-cuda --enable-cuvid --enable-nvenc --enable-libmfx --enable-w32threads --enable-indev=dshow --target-os=mingw32 --cc='gcc -m64' --extra-cflags=-I../include/ --extra-ldflags=-L../lib/ --extra-libs='-static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lgcc_eh -lWs2_32 -lcrypt32 -lpthread -lz -lm -Wl,-Bdynamic -lole32 -luuid'
libavutil 56. 51.100 / 56. 51.100
libavcodec 58. 91.100 / 58. 91.100
libavformat 58. 45.100 / 58. 45.100
libavdevice 58. 10.100 / 58. 10.100
libavfilter 7. 85.100 / 7. 85.100
libswscale 5. 7.100 / 5. 7.100
libswresample 3. 7.100 / 3. 7.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\Users\yi\Desktop\3.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.45.100
Duration: 00:00:31.02, start: 0.000000, bitrate: 3666 kb/s
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 3278 kb/s, 24 fps, 24.42 tbr, 19536 tbn, 48.84 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 384 kb/s (default)
Metadata:
handler_name : SoundHandler
Please use -b:a or -b:v, -b is ambiguous
Codec AVOption preset (Set the encoding preset) specified for output file #0 (C:\Users\yi\Desktop\\0ba24b19db0c47faa2cd25bcaee8a3ed.mp4) has not been used for any stream. The most likely reason is either wrong type (e.g. a video option with no video streams) or that it is a private option of some encoder which was not actually used for any stream.
Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> mpeg4 (native))
Stream #0:1 -> #0:1 (aac (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, mp4, to 'C:\Users\yi\Desktop\\0ba24b19db0c47faa2cd25bcaee8a3ed.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf58.45.100
Stream #0:0(und): Video: mpeg4 (mp4v / 0x7634706D), yuv420p, 960x1080 [SAR 1:1 DAR 8:9], q=2-31, 2000 kb/s, 24.42 fps, 19536 tbn, 24.42 tbc (default)
Metadata:
handler_name : VideoHandler
encoder : Lavc58.91.100 mpeg4
Side data:
cpb: bitrate max/min/avg: 0/0/2000000 buffer size: 0 vbv_delay: N/A
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default)
Metadata:
handler_name : SoundHandler
encoder : Lavc58.91.100 aac
frame= 732 fps=251 q=1.6 Lsize= 7575kB time=00:00:30.01 bitrate=2067.5kbits/s dup=13 drop=0 speed=10.3x
video:7087kB audio:470kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.249497%
[aac @ 0000022b33400c40] Qavg: 197.756
C:\Users\yi\Desktop\\0ba24b19db0c47faa2cd25bcaee8a3ed.mp4Process finished with exit code 0
结果视频如下
OK,没什么问题!
总结
没什么好总结的,注意尺寸,注意尺寸,注意尺寸。
分享
当情绪化的狂热平静下来,拥有推理习惯的人就会去为他自己的信仰寻找逻辑支持。——罗素
如果本文对你有帮助的话,点个赞吧,谢谢!!
-
Java 基于 OpenCV4.4 - 视频流处理教程 (六)
2020-11-07 23:11:04一、处理视频流 Java版本的OpenCV提供了一个videoio包,以及一个特定的VideoCapture对象,它提供了多种方法来直接从连接的视频设备中读取矩阵对象。首先,你会看到如何从视频设备中获取一个特定大小的矩阵对象,... -
Java OpenCV 图像处理30 视频分析和对象跟踪 视频读取
2019-03-14 12:03:36Java OpenCV-4.0.0 视频分析和对象跟踪30 视频读取 Java OpenCV-4.0.0 视频分析和对象跟踪 视频读取 package com.xu.object; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.... -
java实现视频压缩
2018-07-11 10:08:19利用java技术,来实现对视频处理 对视频进行压缩处理。 -
WebRTC+java实现多人视频通讯
2021-04-24 21:13:49通过WebRTC实时通讯技术,配合后端java websocket实现多人视频。局域网内视频没问题,公网需要自行穿透NAT,项目整体为SpringBoot 外置Tomcat 启动 -
视频技术处理之javaCV视频图像灰度处理,附代码
2021-05-24 18:04:54视频灰度处理效果 Java spring boot项目或者maven项目的pom文件中添加以下依赖 <!-- https://mvnrepository.com/artifact/org.bytedeco/javacv-platform --> <dependency> <groupId>... -
这款开源java版的视频管理系统真的很不错
2022-04-18 22:25:37第一款面向大众的java版的视频管理系统。妖气山视频管理系统理论上可以制作任何类型的视频网站。 软件架构 前端:javaex 后端:ssm 数据库:sql server 2012以上 编译器:eclipse JDK:1.8 tomcat:tomcat8 后台...