目地:写一个java制作视频的网站。

大致流程:用户上传n张图片和背景音乐,网站返回一个视频。

大家都知道,java是通过命令行来调用ffmpeg的,java没有现成的比较好的封装ffmpeg的jar包。

所以,我们需要自己写调用ffmpeg的接口。

我采用的是spring boot架构。

首先配置pom文件

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--configuration--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!--jpa--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--start:视频获取某一帧的图片--><!--<dependency>--><!--<groupId>org.bytedeco</groupId>--><!--<artifactId>javacv</artifactId>--><!--<version>1.4.3</version>--><!--</dependency>--><!--<dependency>--><!--<groupId>org.bytedeco.javacpp-presets</groupId>--><!--<artifactId>ffmpeg-platform</artifactId>--><!--<version>4.0.2-1.4.3</version>--><!--</dependency>--><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.1.8.RELEASE</version></dependency><!--end:视频获取某一帧的图片--><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version></dependency><!--导入jsp相关包--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><!-- jsp 依赖的jar包start--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.1</version></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency></dependencies>

注意:整个项目全部依赖此pom文件,后面不再更改。

我们还需要一个命令行处理器,创建一个CmdExecuter

package com.example.demo.util;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
public class CmdExecuter {public static String exec(List<String> cmd) {String converted_time = null;Process proc =null;BufferedReader stdout = null;try {ProcessBuilder builder = new ProcessBuilder();builder.command(cmd);builder.redirectErrorStream(true);proc = builder.start();stdout = new BufferedReader(new InputStreamReader(proc.getInputStream()));String line;int lineNumber=1;List<String> returnStringList = new LinkedList<String>();
//            命令行信息for(String attribute : cmd) {System.out.println(attribute);}
//            命令行调试信息while ((line = stdout.readLine()) != null) {System.out.println("第"+lineNumber+"行:"+line);lineNumber=lineNumber+1;returnStringList.add(FFMPEG.dealString(line));}String info = "";for (int i = returnStringList.size() - 1; i >= 0; i--) {if (null != returnStringList.get(i) && returnStringList.get(i).startsWith("frame=")) {info = returnStringList.get(i);break;}}if (null != info) {converted_time = info.split("time=")[1].split("bitrate=")[0].trim();}} catch (IndexOutOfBoundsException ex) {converted_time = null;} catch (Exception e) {e.printStackTrace();}finally{try {proc.waitFor();stdout.close();} catch (Exception e) {e.printStackTrace();}}return converted_time;}}

随后我们需要一个配置地址的类PropertyPlaceholder

package com.example.demo.entity;import org.springframework.stereotype.Component;/*** @program: javavc* @author: wlr* @create: 2019-07-26 10:20* @description:**/
@Component
//@ConfigurationProperties(prefix = "person")
public class PropertyPlaceholder {
//    根目录static String rootdir=System.getProperty("user.dir");
//    ffmpeg路径private String ffmpegpath="\\src\\main\\java\\com\\example\\demo\\tool\\bin\\ffmpeg.exe";
//    图片输入目录private String pictureInput="\\src\\main\\resources\\picture\\input";
//    图片输出目录private String pictureOut="\\src\\main\\resources\\picture\\out";
//    视频输入目录private String mp4Input="\\src\\main\\resources\\mp4\\input";
//    视频输出目录private String mp4Out="\\src\\main\\resources\\mp4\\out";//    private String videoPath=mp4Input;
//    private String videoFramesPath=mp4Out;public static String getRootdir() {return rootdir;}public String getFfmpegpath() {return rootdir+ffmpegpath;}public void setFfmpegpath(String ffmpegpath) {this.ffmpegpath = ffmpegpath;}public String getPictureInput() {return rootdir+pictureInput;}public void setPictureInput(String pictureInput) {this.pictureInput = pictureInput;}public String getPictureOut() {return rootdir+pictureOut;}public void setPictureOut(String pictureOut) {this.pictureOut = pictureOut;}public String getMp4Input() {return rootdir+mp4Input;}public void setMp4Input(String mp4Input) {this.mp4Input = mp4Input;}public String getMp4Out() {return rootdir+mp4Out;}public void setMp4Out(String mp4Out) {this.mp4Out = mp4Out;}//    public String getVideoPath() {
//        return rootdir+videoPath;
//    }
//
//    public void setVideoPath(String videoPath) {
//        this.videoPath = videoPath;
//    }
//
//    public String getVideoFramesPath() {
//        return rootdir+videoFramesPath;
//    }
//
//    public void setVideoFramesPath(String videoFramesPath) {
//        this.videoFramesPath = videoFramesPath;
//    }public String getPictureOut(String img_path) {return rootdir+pictureOut+"\\"+img_path;}
}

接下来我们需要在PropertyPlaceholder类指向ffmpeg的地址放放置ffmpeg的解压版

下载地址:http://www.ffmpeg.org/download.html

新建一个FFMPEG,通过命令行调用ffmpeg.exe。

package com.example.demo.util;import com.example.demo.entity.PropertyPlaceholder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@Component
public class FFMPEG {@AutowiredPropertyPlaceholder propertyPlaceholder;public static String dealString(String str) {Matcher m = java.util.regex.Pattern.compile("^frame=.*").matcher(str);String msg = "";while (m.find()) {msg = m.group();}return msg;}/*** 如果是数字就是成功的时间(秒数)** @param str* @return*/public static boolean isNumeric(String str) {Pattern pattern = Pattern.compile("[0-9]*");Matcher isNum = pattern.matcher(str);if (!isNum.matches()) {return false;}return true;}/***   如果返回不是null的值就是成功(值为转换用时单位:秒)** @param instr* @return*/public static String returnSecond(String instr) {String returnValue = null;if (null != instr) {String[] a = instr.split("\\.");String[] b = a[0].split(":");// 返回秒int returnNumber = 0;if (null != instr && b[0].length() != 0) {returnNumber = Integer.valueOf(b[0]) * 60 * 60 + Integer.valueOf(b[1]) * 60 + Integer.valueOf(b[2]);returnValue = String.valueOf(returnNumber);} else {returnValue = null;}}return returnValue;}/*** 获取视频格式(转码前的格式和转码后的格式都可以调用)** @param outputPath* @return*/public static String returnVideoFormat(String outputPath) {return outputPath.substring(outputPath.lastIndexOf(".") + 1);}public String jpgTomp4(HashMap<String, String> dto){List<String> cmd = new ArrayList<String>();cmd.add(dto.get("ffmpeg_path"));cmd.add("-y");cmd.add("-i");cmd.add(dto.get("input_path"));if (null != dto.get("screen_size")) {cmd.add("-s");cmd.add(dto.get("screen_size"));}if (null != dto.get("logo")) {String logo = dto.get("logo");cmd.add("-vf");String xaxis = dto.get("xaxis");String yaxis = dto.get("yaxis");xaxis = xaxis != null && !xaxis.equals("") ? xaxis : "0";yaxis = yaxis != null && !yaxis.equals("") ? yaxis : "0";String logoString = "movie=" + logo + "[logo],[in][logo]overlay=x=" + xaxis + ":y=" + yaxis + "[out]";cmd.add(logoString);}cmd.add("-strict");cmd.add("-2");if (null != dto.get("vb") && !dto.get("vb").equals("")) {cmd.add("-vb");cmd.add(dto.get("vb") + "k");}if (null != dto.get("ab") && !dto.get("ab").equals("")) {cmd.add("-ab");cmd.add(dto.get("ab") + "k");}cmd.add("-q:v");cmd.add("4");cmd.add(dto.get("video_converted_path"));String converted_time = CmdExecuter.exec(cmd);return returnSecond(converted_time);//获取转换时间}/*** @ HashMap<String,String> dto 参数传递对象<br>* dto中包含的参数<br>* (必填)1.ffmpeg_path:ffmpeg执行文件地址,如 d:\\ffmpeg\\ffmpeg.exe Linux下直接调用ffmpeg命令(当然你事先已经有这个程序了)<br>* (必填)2.input_path:原视频路径<br>* (必填)3.video_converted_path:转换后视频输出路径<br>* (可选)4.screen_size:视频尺寸 长度乘宽度 乘号用英文小写"x"如 512x480<br>* (可选)5.logo:水印地址(其实在ffmpeg中有一个专门的watermark参数,logo跟它有何不同,我还没看,不过对我来说效果一样 貌似需要png图片才行)<br>* (可选,如果填写必须有logo才行,默认为0)6.xaxis:水印logo的横坐标(只有logo参数为一个正确路径才行) 比如0<br>* (可选,如果填写必须有logo才行,默认为0)6.yaxis:水印logo的纵坐标(只有logo参数为一个正确路径才行) 比如0<br>* (可选)vb:视频比特率,传入一个数值,单位在程序里面拼接了k* (可选)ab:音频比特率,传入一个数值,单位在程序里面拼接了k*/public String videoTransfer(HashMap<String, String> dto) {
//  String ffmpeg_path,String input_path,String video_converted_path,String logo,String screen_size,String xaxis,String yaxis,String vb,String abList<String> cmd = new ArrayList<String>();cmd.add(dto.get("ffmpeg_path"));cmd.add("-y");cmd.add("-i");cmd.add(dto.get("input_path"));if (null != dto.get("screen_size")) {cmd.add("-s");cmd.add(dto.get("screen_size"));}if (null != dto.get("logo")) {String logo = dto.get("logo");cmd.add("-vf");String xaxis = dto.get("xaxis");String yaxis = dto.get("yaxis");xaxis = xaxis != null && !xaxis.equals("") ? xaxis : "0";yaxis = yaxis != null && !yaxis.equals("") ? yaxis : "0";String logoString = "movie=" + logo + "[logo],[in][logo]overlay=x=" + xaxis + ":y=" + yaxis + "[out]";cmd.add(logoString);}cmd.add("-strict");cmd.add("-2");if (null != dto.get("vb") && !dto.get("vb").equals("")) {cmd.add("-vb");cmd.add(dto.get("vb") + "k");}if (null != dto.get("ab") && !dto.get("ab").equals("")) {cmd.add("-ab");cmd.add(dto.get("ab") + "k");}cmd.add("-q:v");cmd.add("4");cmd.add(dto.get("video_converted_path"));String converted_time = CmdExecuter.exec(cmd);return returnSecond(converted_time);//获取转换时间}/** 给一张图片添加图片水印* */public void makeWatermask(String inputImage0,String inputImage1,int width,int height,int x,int y,String outputPath){List<String> cmd = new ArrayList<String>();cmd.add(propertyPlaceholder.getFfmpegpath());cmd.add("-i");cmd.add(inputImage0);cmd.add("-vf");cmd.add("movie='"+inputImage1.replace("\\","\\\\").replace(":","\\:")+"',"+"scale="+width+":"+height+"[watermask];[in][watermask]"+"overlay="+x+":"+y+"[out]");cmd.add("-y");cmd.add(outputPath);CmdExecuter.exec(cmd);}/** 给1张图片添加2张图片水印* */public void makeWatermask(String inputImage0,String inputImage1,int width,int height,int x,int y,String inputImage2,int width1,int height1,int x1,int y1,String outputPath){List<String> cmd = new ArrayList<String>();cmd.add(propertyPlaceholder.getFfmpegpath());cmd.add("-i");cmd.add(inputImage0);cmd.add("-vf");cmd.add("movie='"+inputImage1.replace("\\","\\\\").replace(":","\\:")+"',"+"scale="+width+":"+height+"[1watermask];movie='"+inputImage2.replace("\\","\\\\").replace(":","\\:")+"',"+"scale="+width+":"+height+"[2watermask];[in][1watermask]"+"overlay="+x+":"+y+"[int];[int][2watermask]overlay="+x1+":"+y1+"[out]");cmd.add("-y");cmd.add(outputPath);CmdExecuter.exec(cmd);}/*** @param input_path 图片输入正则路径* @param video_converted_path 视频输出路径*//*在input_path文件夹下,将1.png~n.png的图片转化为视频,注意,这里的图片必须是1.png起始* */public void imageToMp4(String input_path,String video_converted_path){List<String> cmd = new ArrayList<String>();cmd.add(propertyPlaceholder.getFfmpegpath());cmd.add("-f");cmd.add("image2");cmd.add("-i");cmd.add(input_path);cmd.add("-vcodec");cmd.add("libx264");cmd.add("-r");cmd.add("25");cmd.add("-b");cmd.add("382k");cmd.add("-y");cmd.add(video_converted_path);CmdExecuter.exec(cmd);}/*给视频添加水印input_path:视频输入路径video_converted_path:视频转换路径logo:logo图片转换路径xaxis:logo图片相对于视频的横坐标yaxis:logo图片相对于视频的纵坐标* */public void addWatermark(String input_path,String video_converted_path,String logo,String xaxis,String yaxis){HashMap<String, String> dto = new HashMap<String, String>();dto.put("ffmpeg_path", propertyPlaceholder.getFfmpegpath());//必填dto.put("input_path", input_path);//必填dto.put("video_converted_path", video_converted_path);//必填dto.put("logo", "C\\\\:/Users/WLR/Desktop/project/video_demo/src/oyuemeili.png");//可选(注意windows下面的logo地址前面要写4个反斜杠,如果用浏览器里面调用servlet并传参只用两个,如 d:\\:/ffmpeg/input/logo.png)dto.put("xaxis",xaxis);dto.put("yaxis",yaxis);String secondsString = new FFMPEG().videoTransfer(dto);System.out.println("转换共用:" + secondsString + "秒");}/*** 将.MP4转化为.ts* @param mp4Address    mp4地址* @param tsAddress     ts地址*/public void mp4ToTs(String mp4Address, String tsAddress) {List<String> cmd = new ArrayList<String>();cmd.add(propertyPlaceholder.getFfmpegpath());cmd.add("-i");cmd.add(mp4Address);cmd.add("-vcodec");cmd.add("copy");cmd.add("-vbsf");cmd.add("h264_mp4toannexb ");cmd.add("-y");cmd.add(tsAddress);CmdExecuter.exec(cmd);}/*** 将多个.ts转换为.mp4* @param tsName* @param outTsAddress*/public void addTsToMP4(ArrayList<String> tsName, String outTsAddress) {List<String> cmd = new ArrayList<String>();cmd.add(propertyPlaceholder.getFfmpegpath());cmd.add("-i");int size=tsName.size();String concat="\"concat:";for (int i=0;i<size-1;i++){concat=concat+(String) tsName.remove(0)+"|";}concat=concat+(String) tsName.remove(0)+"\"";cmd.add(concat);cmd.add("-c");cmd.add("copy");cmd.add("-bsf:a");cmd.add("aac_adtstoasc");cmd.add("-movflags");cmd.add("faststart");cmd.add("-y");cmd.add(outTsAddress);cmd.add("-y");CmdExecuter.exec(cmd);}/*** 给MP4视频添加背景音乐* @param mp3Address* @param mp4Address*/public void addMp3(String mp3Address,String mp4Address,String output){List<String> cmd=new ArrayList<>();cmd.add(propertyPlaceholder.getFfmpegpath());cmd.add("-i");cmd.add(mp3Address);cmd.add("-i");cmd.add(mp4Address);cmd.add("-y");cmd.add(output);CmdExecuter.exec(cmd);}
//    public static void main(String[] arg) {
//        HashMap<String, String> dto = new HashMap<String, String>();
//        dto.put("ffmpeg_path", "C:\\Users\\WLR\\Desktop\\project\\ffmpeg-20190628-098ab93-win64-static\\ffmpeg-20190628-098ab93-win64-static\\bin\\ffmpeg.exe");//必填
//        dto.put("input_path", "C:\\Users\\WLR\\Desktop\\project\\video_demo\\src\\瓯越文化.mp4");//必填
//        dto.put("video_converted_path", "C:\\Users\\WLR\\Desktop\\project\\video_demo\\src\\aaa.mp4");//必填
//        dto.put("logo", "C\\\\:/Users/WLR/Desktop/project/video_demo/src/oyuemeili.png");//可选(注意windows下面的logo地址前面要写4个反斜杠,如果用浏览器里面调用servlet并传参只用两个,如 d:\\:/ffmpeg/input/logo.png)
//        dto.put("xaxis","100");
//        dto.put("yaxis","100");
//        String secondsString = new FFMPEG().videoTransfer(dto);
//        System.out.println("转换共用:" + secondsString + "秒");
//    }}

创建一个 接口MarkText,用来调用FFMPEG工具

package com.example.demo.service;import java.awt.*;
import java.util.ArrayList;
import java.util.Queue;public interface MarkText {//加文字水印void mark(String imgPath, String outImgPath, String text, Font font, Color color, int x, int y);//加图片水印void mark(String inputImg, String markImg, String outputImg, int width, int height, int x, int y);//通过gotravale视频模版在文件夹下生成视频帧的图片void makePictureInDirByGotravale(String username, ArrayList filename);//制作视频void makeMp4(String imgDir,String mp3);
}

用类MarkText4J实现 接口MarkText

package com.example.demo.service.impl;import com.example.demo.entity.PropertyPlaceholder;
import com.example.demo.service.MarkText;
import com.example.demo.util.FFMPEG;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;/*** @program: demo* @author: wlr* @create: 2019-06-29 21:28* @description:水印图片的四种方式**/
@Service
public class MarkText4J implements MarkText {@AutowiredPropertyPlaceholder propertyPlaceholder;@AutowiredFFMPEG ffmpeg;//静态资源文件本地路径(非target)String localAddress=propertyPlaceholder.getRootdir()+"\\src\\main\\resources";// 加文字水印public void mark(BufferedImage bufImg, Image img, String text, Font font, Color color, int x, int y) {Graphics2D g = bufImg.createGraphics();g.drawImage(img, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);g.setColor(color);g.setFont(font);g.drawString(text, x, y);g.dispose();}// 加图片水印public void mark(BufferedImage bufImg, Image img, Image markImg, int width, int height, int x, int y) {Graphics2D g = bufImg.createGraphics();g.drawImage(img, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);g.drawImage(markImg, x, y, width, height, null);g.dispose();}/*** 给图片增加文字水印** @param imgPath*            -要添加水印的图片路径* @param outImgPath*            -输出路径* @param text-文字* @param font*            -字体* @param color*            -颜色* @param x*            -文字位于当前图片的横坐标* @param y*            -文字位于当前图片的竖坐标*/public void mark(String imgPath, String outImgPath, String text, Font font, Color color, int x, int y) {try {// 读取原图片信息File imgFile = null;Image img = null;if (imgPath != null) {imgFile = new File(imgPath);}if (imgFile != null && imgFile.exists() && imgFile.isFile() && imgFile.canRead()) {img = ImageIO.read(imgFile);}int imgWidth = img.getWidth(null);int imgHeight = img.getHeight(null);// 加水印BufferedImage bufImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);mark(bufImg, img, text, font, color, x, y);// 输出图片FileOutputStream outImgStream = new FileOutputStream(outImgPath);ImageIO.write(bufImg, "jpg", outImgStream);outImgStream.flush();outImgStream.close();} catch (Exception e) {e.printStackTrace();}}/*** 给图片增加图片水印** @param inputImg*            -源图片,要添加水印的图片* @param markImg*            - 水印图片* @param outputImg*            -输出图片(可以是源图片)* @param width*            - 水印图片宽度* @param height*            -水印图片高度* @param x*            -图片相对于原图片横坐标* @param y*            -图片相对于原图片纵坐标*/public void mark(String inputImg, String markImg, String outputImg, int width, int height, int x, int y) {// 读取原图片信息File inputImgFile = null;File markImgFile = null;Image img = null;Image mark = null;try {if (inputImg != null && markImg != null) {inputImgFile = new File(inputImg);markImgFile = new File(markImg);}if (inputImgFile != null && inputImgFile.exists() && inputImgFile.isFile() && inputImgFile.canRead()) {img = ImageIO.read(inputImgFile);}if (markImgFile != null && markImgFile.exists() && markImgFile.isFile() && markImgFile.canRead()) {mark = ImageIO.read(markImgFile);}int imgWidth = img.getWidth(null);int imgHeight = img.getHeight(null);BufferedImage bufImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);mark(bufImg, img, mark, width, height, x, y);FileOutputStream outImgStream = new FileOutputStream(outputImg);ImageIO.write(bufImg, "png", outImgStream);outImgStream.flush();outImgStream.close();} catch (IOException e) {e.printStackTrace();}}public void  makeVideoframe1Aboutgotravale(String username,String inputImg,String sep,int pictureNum){ffmpeg.makeWatermask(localAddress+"\\moban\\gotravale\\blank.png",localAddress+"\\user\\"+username+"\\picture\\input\\"+inputImg,725,418,221,76,localAddress+"\\user\\"+username+"\\picture\\out\\"+inputImg);
//        mark( localAddress+"\\moban\\gotravale\\blank.png",localAddress+"\\user\\"+username+"\\picture\\input\\"+inputImg, localAddress+"\\user\\"+username+"\\picture\\out\\"+inputImg, 725, 418, 221, 76);makeVideoframeAboutgotravale(username,inputImg,sep,pictureNum);}public void  makeVideoframe2Aboutgotravale(String username,String inputImg,String inputImg1,String sep,int pictureNum){ffmpeg.makeWatermask(localAddress+"\\moban\\gotravale\\blank.png",localAddress+"\\user\\"+username+"\\picture\\input\\"+inputImg,411,399,58,38,localAddress+"\\user\\"+username+"\\picture\\input\\"+inputImg1,343,301,499,165,localAddress+"\\user\\"+username+"\\picture\\out\\"+inputImg);
//        mark( localAddress+"\\moban\\gotravale\\blank.png",localAddress+"\\user\\"+username+"\\picture\\input\\"+inputImg, localAddress+"\\user\\"+username+"\\picture\\out\\"+inputImg, 411, 399, 58, 38);
//        mark( localAddress+"\\user\\"+username+"\\picture\\out\\"+inputImg,localAddress+"\\user\\"+username+"\\picture\\input\\"+inputImg1, localAddress+"\\user\\"+username+"\\picture\\out\\"+inputImg, 343, 301, 499, 165);makeVideoframeAboutgotravale(username,inputImg,sep,pictureNum);}public void makeVideoframeAboutgotravale(String username,String inputImg,String sep,int pictureNum){for (int num=1;num<=pictureNum;){ffmpeg.makeWatermask(localAddress+"\\user\\"+username+"\\picture\\out\\"+inputImg,localAddress+"\\moban\\gotravale\\"+sep+"\\"+num+".png",998,560,0,0,localAddress+"\\user\\"+username+"\\picture\\"+sep+"\\"+num+".jpg");
//            mark(localAddress+"\\user\\"+username+"\\picture\\out\\"+inputImg, localAddress+"\\moban\\gotravale\\"+sep+"\\"+num+".png", localAddress+"\\user\\"+username+"\\picture\\"+sep+"\\"+num+".png", 998, 560, 0, 0);num++;}}public void  makeVideoframe3Aboutgotravale(String username,String inputImg,String sep,int pictureNum){mark( localAddress+"\\moban\\gotravale\\blank.png",localAddress+"\\user\\"+username+"\\picture\\input\\"+inputImg, localAddress+"\\user\\"+username+"\\picture\\out\\"+inputImg, 754, 442, 214, 53);makeVideoframeAboutgotravale(username,inputImg,sep,pictureNum);}/*** @param username 用户名* @param filename   输入图片名的集合*///給特定一个文件夹下的图片添加水印@Overridepublic void makePictureInDirByGotravale(String username, ArrayList filename) {/** 生成sep1文件夹关键帧* *///将用户上传的图片水印到空白图片上String inputImg=(String) filename.remove(0);makeVideoframe1Aboutgotravale(username,inputImg,"sep1",85);/** 生成sep2文件夹关键帧* */inputImg=(String) filename.remove(0);String inputImg1=(String) filename.remove(0);makeVideoframe2Aboutgotravale(username,inputImg,inputImg1,"sep2",166);/** 生成sep3文件夹关键帧* */inputImg=(String) filename.remove(0);makeVideoframe3Aboutgotravale(username,inputImg,"sep3",82);/*将图片生成对应的MP4文件* */ffmpeg.imageToMp4(localAddress+"\\user\\"+username+"\\picture\\sep1\\%d.jpg",localAddress+"\\user\\"+username+"\\mp4\\input\\sep1.mp4");ffmpeg.imageToMp4(localAddress+"\\user\\"+username+"\\picture\\sep2\\%d.jpg",localAddress+"\\user\\"+username+"\\mp4\\input\\sep2.mp4");ffmpeg.imageToMp4(localAddress+"\\user\\"+username+"\\picture\\sep3\\%d.jpg",localAddress+"\\user\\"+username+"\\mp4\\input\\sep3.mp4");/** 将mp4转化为ts文件* */ffmpeg.mp4ToTs(localAddress+"\\user\\"+username+"\\mp4\\input\\sep1.mp4",localAddress+"\\user\\"+username+"\\ts\\sep1.ts");ffmpeg.mp4ToTs(localAddress+"\\user\\"+username+"\\mp4\\input\\sep2.mp4",localAddress+"\\user\\"+username+"\\ts\\sep2.ts");ffmpeg.mp4ToTs(localAddress+"\\user\\"+username+"\\mp4\\input\\sep3.mp4",localAddress+"\\user\\"+username+"\\ts\\sep3.ts");/** 将ts文件黏连在一起,转化为mp4* */ArrayList<String> tsName = new ArrayList<>();tsName.add(localAddress+"\\moban\\gotravale\\ts\\start.ts");tsName.add(localAddress+"\\moban\\gotravale\\ts\\start_font.ts");tsName.add(localAddress+"\\moban\\gotravale\\ts\\start_end.ts");tsName.add(localAddress+"\\moban\\gotravale\\ts\\sep1start.ts");tsName.add(localAddress+"\\user\\"+username+"\\ts\\sep1.ts");tsName.add(localAddress+"\\moban\\gotravale\\ts\\sep1end.ts");tsName.add(localAddress+"\\moban\\gotravale\\ts\\sep2start.ts");tsName.add(localAddress+"\\user\\"+username+"\\ts\\sep2.ts");tsName.add(localAddress+"\\moban\\gotravale\\ts\\sep2end.ts");tsName.add(localAddress+"\\moban\\gotravale\\ts\\sep3start.ts");tsName.add(localAddress+"\\user\\"+username+"\\ts\\sep3.ts");tsName.add(localAddress+"\\moban\\gotravale\\ts\\sep3end.ts");tsName.add(localAddress+"\\moban\\gotravale\\ts\\end.ts");tsName.add(localAddress+"\\moban\\gotravale\\ts\\end_font.ts");ffmpeg.addTsToMP4(tsName,localAddress+"\\user\\"+username+"\\mp4\\input\\input.mp4");/** 给MP4视频添加背景音乐* */ffmpeg.addMp3(localAddress+"\\user\\"+username+"\\mp3\\"+filename.remove(0),localAddress+"\\user\\"+username+"\\mp4\\input\\input.mp4",localAddress+"\\user\\"+username+"\\mp4\\out\\output.mp4");}@Overridepublic void makeMp4(String imgDir, String mp3) {
//        ffmpeg.imageToMp4(imgDir,);}
}

最后,通过VideoController调用MarkText4J

package com.example.demo.controller;import com.example.demo.service.impl.MarkText4J;
//import com.example.demo.util.VideoProcessing;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.Queue;@RestController
public class VideoController {@AutowiredMarkText4J mark;
//    将视频用图片的形式保存
//    @RequestMapping(value = "/grabberVideoFrame")
//    public void grabberVideoFrame(String videoFileName){
//        videoProcessing.grabberVideoFramer(videoFileName);
//    }
//      将图片生成视频@RequestMapping(value = "/makeVideo")public void makeVideo(){ArrayList<String> filename = new ArrayList<>();filename.add("1.png");filename.add("2.png");filename.add("3.png");filename.add("4.png");filename.add("culture.mp3");mark.makePictureInDirByGotravale("www",filename);}
}

以下是我的文件放置方式,方便大家实现demo 

application.properties

#环境为springboot2.0.6
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB
spring.servlet.multipart.resolve-lazily=false
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
spring.jpa.open-in-view=false

application.yml

spring:#配置属性文件profiles:active: dev
#  配置默认访问路径resources:static-locations: classpath:/#配置MySQLdatasource:#添加驱动器名称driver-class-name: com.mysql.cj.jdbc.Driver#添加数据库连接的urlurl: jdbc:mysql://127.0.0.1:3306/pyt?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC#配置数据库用户名username: #配置数据库密码password: #配置jpajpa:hibernate:#ddl-auto属性:#   create 启动时删数据库中的表,然后创建,退出时不删除数据表#   create-drop 启动时删数据库中的表,然后创建,退出时删除数据表 如果表不存在报错#   update 如果启动时表格式不一致则更新表,原有数据保留#   validate 项目启动表结构进行校验 如果不一致则报错ddl-auto: update#改属性值若为true,操作数据库时,可打印SQL语句到控制台show-sql: true

由于图片,视频等资源过大,我将其上传到我的博客中大家可以自行下载。目前在intel i7 7700的cpu下需要40秒左右生成一个4.76MB的视频,项目算法正在优化中。

在下一篇文章中,将会阐述视频制作逻辑

java在线制作视频,调用ffmpeg(一)相关推荐

  1. java在线制作视频,调用ffmpeg(具备影大师、爱美客在线制作视频等功能)

    最近在学校准备一个乡土文化教育竞赛项目,大部分的项目交互都是采用的论坛的形式展现,我打算采用视频交互的形式,针对于大部分人群,他们没有视频制作基础,视频制作对于他们来说太过于困难,为了服务这部分人群, ...

  2. java flv转mp3_Java调用ffmpeg转换视频格式为flv的示例详解

    这篇文章主要介绍了 详解java调用ffmpeg转换视频格式为flv的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下 详解java调用ffmpeg转换视频格式为flv 注意:下面的程序是在L ...

  3. 怎样在线制作视频二维码?多种类型二维码一键生成技巧

    二维码作为现在一种常用的内容载体工具,可以用来储存不同的内容,比如文件.视频.音频.图片等等都可以生成二维码.那么视频文件是如何生成二维码的呢?下面教大家使用二维码生成器(二维码在线制作-二维码生成器 ...

  4. java flv转mp3_java调用FFmpeg及mencoder转换视频为FLV并截图

    Conver.java package com.ll19.flv;public classConver {public voidrun() {try{//转换并截图 String filePath = ...

  5. 开题报告:基于java在线教育视频学习点播系统 毕业设计论文开题报告模板

    开发操作系统:windows10 + 4G内存 + 500G 开发环境:JDK1.8 + Tomcat8 开发语言:Java 开发框架:springboot 模板引擎:Thymeleaf 开发工具:I ...

  6. java ffmpeg 合并视频_android ffmpeg视频剪切与合并

    android-ffmpeg-java-demo 说明 以前一直希望可以做一个播放器,所以当时就接触了ffmpeg这个库,当时打算使用JNI的方式进行底层的调用,无奈整个逻辑比较麻烦,因此进度一再搁浅 ...

  7. mysql+视频文件转成流_详解java调用ffmpeg转换视频格式为flv

    详解java调用ffmpeg转换视频格式为flv 注意:下面的程序是在Linux下运行的,如果在windows下rmvb转换成avi会出现问题,想成功需要下载下个drv43260.dll东西放到C:W ...

  8. 如何用java代码调用ffmpeg进行视频转码

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/lushizhuo9655/articl ...

  9. Java调用ffmpeg进行视频.H264抽帧,并保存为图片

    Java调用ffmpeg进行视频.H264抽帧,并保存为图片 1. 需求 2. 解决 3. 源码 参考 1. 需求 对视频 D:\data\01-test.H264进行抽帧并保存为图片,图片命名为1. ...

最新文章

  1. Java项目:学生信息管理系统(java+SSM+JSP+layui+maven+mysql)
  2. 端口聚合有哪几种方式?
  3. JSP的四个作用域(转载)
  4. 分享:几款代码混淆器(DotFuscator, .NET Reactor, xenocode)
  5. websocket后台推送数据
  6. C++|STL学习笔记-map的基本操作(插入,删除,遍历,大到小输出)【仿大佬写法】
  7. .net 中debug 微软内部代码
  8. npm、webpack、vue-cli
  9. Jenkins 自动化集成之路 Linux 安装 maven
  10. 【总结】大规模数据(300万条)测试时,需要注意的问题。
  11. python中open打开路径问题_Python学习笔记之open()函数打开文件路径报错问题
  12. linux boa post方式失败,移植boa出现的错误及解决方法
  13. sprint() 和 snprint()
  14. 传奇添加地图与配置参数详解
  15. A4纸张缩印怎么只打印一半A4纸的内容
  16. [CF1463F]Max Correct Set
  17. 手指在屏幕上滑动,红色的小球始终跟随手指移动。
  18. Diagrams(draw.io)-怎样实现跨线
  19. 中医四大经典著作之一《神农本草经》
  20. CANoe.DiVa操作指南-运行环境搭建

热门文章

  1. 手机彩铃java工程项目_4G中手机彩铃业务信令过程简述
  2. 下载bilibi视频 下载B站视频
  3. Peterson算法的简单分析
  4. 从唱歌到作诗书法,腾讯AI Lab虚拟人艾灵技能再进化
  5. java3D桌球7723_极品桌球3D豪华版
  6. Windows Server 2022 简体中文版、英文版下载 (updated Jun 2022)
  7. DT时代,大数据分析都包含了哪些技术?
  8. Python运维开发工程师养成记(python continue语句)
  9. 智慧养老解决方案之非接触式查房系统
  10. 社工库最新免费机器人分享