学习目标:
6-26 使用ffmpeg生成截图
6-27 上传视频流程整合视频截图功能
6-28 小程序端与后台联调测试上传流程
学习内容:
6-26 使用ffmpeg生成截图
1、在cmd命令中使用ffmpeg生成截图:尽量生成jpg,不占内存
2、在spring boot实现这个命令:
首先新建FetchVideoCover.java工具类:
代码如下:
package com.asayi.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
/**
*
* @Description: 获取视频的信息
*/
public class FetchVideoCover {
// 视频路径
private String ffmpegEXE;
public void getCover(String videoInputPath, String coverOutputPath) throws IOException, InterruptedException {
// ffmpeg.exe -ss 00:00:01 -i spring.mp4 -vframes 1 bb.jpg
List<String> command = new java.util.ArrayList<String>();
command.add(ffmpegEXE);
// 指定截取第1秒
command.add("-ss");
command.add("00:00:01");
command.add("-y");
command.add("-i");
command.add(videoInputPath);
command.add("-vframes");
command.add("1");
command.add(coverOutputPath);
for (String c : command) {
System.out.print(c + " ");
}
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
InputStream errorStream = process.getErrorStream();
InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
BufferedReader br = new BufferedReader(inputStreamReader);
String line = "";
while ( (line = br.readLine()) != null ) {
}
if (br != null) {
br.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (errorStream != null) {
errorStream.close();
}
}
public String getFfmpegEXE() {
return ffmpegEXE;
}
public void setFfmpegEXE(String ffmpegEXE) {
this.ffmpegEXE = ffmpegEXE;
}
public FetchVideoCover() {
super();
}
public FetchVideoCover(String ffmpegEXE) {
this.ffmpegEXE = ffmpegEXE;
}
public static void main(String[] args) {
// 获取视频信息。
FetchVideoCover videoInfo = new FetchVideoCover("F:\\JavaEE\\ffmpeg-4.3.1\\bin\\ffmpeg.exe");
try {
videoInfo.getCover("F:\\JavaEE\\ffmpeg-4.3.1\\bin\\springday.mp4",
"F:\\JavaEE\\ffmpeg-4.3.1\\bin\\111.jpg");
} catch (Exception e) {
e.printStackTrace();
}
}
}
对上述代码,右键测试运行:
6-27 上传视频流程整合视频截图功能
更改VideoController.java的代码如下,新增上传视频到数据库的部分
package com.asayi.controller;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Date;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.druid.util.StringUtils;
import com.asayi.enums.VideoStatusEnum;
import com.asayi.pojo.AsayiUsers;
import com.asayi.pojo.Bgm;
import com.asayi.pojo.Videos;
import com.asayi.service.BgmService;
import com.asayi.service.VideoService;
import com.asayi.utils.FetchVideoCover;
import com.asayi.utils.IMoocJSONResult;
import com.asayi.utils.MergeVideoMp3;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@RestController
@Api(value = "视频相关业务的接口",tags = {
"视频相关业务的controller"})
@RequestMapping("/video")
public class VideoController extends BasicController{
@Autowired
private BgmService BgmService;
@Autowired
private VideoService videoService;
@ApiOperation(value = "用户上传视频",notes = "用户上传视频的接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId",value = "用户id",required = true,
dataType = "String",paramType = "form"),
@ApiImplicitParam(name = "bgmId",value = "背景音乐id",required = false,
dataType = "String",paramType = "form"),
@ApiImplicitParam(name = "videoSeconds",value = "背景音乐播放长度",required = true,
dataType = "double",paramType = "form"),
@ApiImplicitParam(name = "videoWidth",value = "视频宽度",required = true,
dataType = "int",paramType = "form"),
@ApiImplicitParam(name = "videoHeight",value = "视频高度",required = true,
dataType = "int",paramType = "form"),
@ApiImplicitParam(name = "desc",value = "视频描述",required = false,
dataType = "String",paramType = "form")
})
@PostMapping(value = "/upload" , headers="content-type=multipart/form-data")
public IMoocJSONResult uploadFace(String userId,
String bgmId,double videoSeconds,int videoWidth,int videoHeight,
String desc,
@ApiParam(value = "短视频",required = true)//必须要选择文件才能通过接口
MultipartFile file) throws Exception {
if(StringUtils.isEmpty(userId)) {
return IMoocJSONResult.errorMsg("用户id不能为空...");
}
// //文件保存的命名空间
// String fileSpace="F:/武汉理工风景/大四上/毕业设计/user_videos_dev";
//保存到数据库中的相对路径
String uploadPathDB="/"+userId+"/video";
String coverPathDB="/"+userId+"/video";
FileOutputStream fileOutputStream=null;
InputStream inputStream=null;
//文件上传的最终保存路径
String finalVideoPath="";
try {
if (file!=null) {
String fileName=file.getOriginalFilename();
//abc.mp4
String fileNamePrefix=fileName.split("\\.")[0];
if(!StringUtils.isEmpty(fileName)) {
finalVideoPath=FILE_SPACE+uploadPathDB+"/"+fileName;
//设置数据库保存的路径
uploadPathDB+=("/"+fileName);
coverPathDB=coverPathDB+"/"+fileNamePrefix+".jpg";
File outFile=new File(finalVideoPath);
if(outFile.getParentFile()!=null||!outFile.getParentFile().isDirectory()) {
//创建父文件夹
outFile.getParentFile().mkdirs();
}
fileOutputStream=new FileOutputStream(outFile);
inputStream=file.getInputStream();
IOUtils.copy(inputStream, fileOutputStream);
}
}else {
return IMoocJSONResult.errorMsg("上传出错...");
}
} catch (Exception e) {
e.printStackTrace();
return IMoocJSONResult.errorMsg("上传出错...");
}finally {
if(fileOutputStream!=null) {
fileOutputStream.flush();
fileOutputStream.close();
}
}
//判断bgmId是否为空,如果不为空,
//那就查询bgm的信息,并且合并视频,生成新的视频到数据库。
if(!StringUtils.isEmpty(bgmId)) {
Bgm bgm=BgmService.queryBgmById(bgmId);
String mp3InputPath=FILE_SPACE+bgm.getPath();
MergeVideoMp3 tool=new MergeVideoMp3(FFMPEG_EXE);
//去除原视频的音频前的路径
String videoBgmInputPath=finalVideoPath;
//去除原视频的音频后的路径
String videoBgmOutputName=UUID.randomUUID().toString()+".mp4";
uploadPathDB="/"+userId+"/video"+"/"+videoBgmOutputName;
String videoBgmOutputPath=FILE_SPACE+uploadPathDB;
//音视频合并前的路径=去除原视频的音频后的路径
String videoInputPath=videoBgmOutputPath;
//音视频合并后的路径
String videoOutputName=UUID.randomUUID().toString()+".mp4";
uploadPathDB="/"+userId+"/video"+"/"+videoOutputName;
finalVideoPath=FILE_SPACE+uploadPathDB;
tool.deleteBgm(videoBgmInputPath, videoBgmOutputPath);
tool.convertor(videoInputPath, mp3InputPath, videoSeconds, finalVideoPath);
}
System.out.println("uploadPathDB="+uploadPathDB);
System.out.println("finalVideoPath="+finalVideoPath);
//对视频进行截图
FetchVideoCover videoInfo = new FetchVideoCover(FFMPEG_EXE);
videoInfo.getCover(finalVideoPath,FILE_SPACE+coverPathDB);
//保存视频信息到数据库
Videos video=new Videos();
video.setAudioId(bgmId);
video.setUserId(userId);
video.setVideoSeconds((float)videoSeconds);
video.setVideoHeight(videoHeight);
video.setVideoWidth(videoWidth);
video.setVideoDesc(desc);
video.setVideoPath(uploadPathDB);
video.setCoverPath(coverPathDB);
video.setStatus(VideoStatusEnum.SUCCESS.value);
video.setCreateTime(new Date());
String videoId =videoService.saveVideo(video);
return IMoocJSONResult.ok(videoId);
}
@ApiOperation(value = "用户上传视频封面",notes = "用户上传视频封面的接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId",value = "用户id",required = true,
dataType = "String",paramType = "form"),
@ApiImplicitParam(name = "videoId",value = "视频主键id",required = true,
dataType = "String",paramType = "form")
})
@PostMapping(value = "/uploadCover" , headers="content-type=multipart/form-data")
public IMoocJSONResult uploadCover(String userId,String videoId,
@ApiParam(value = "短视频封面",required = true)//必须要选择文件才能通过接口
MultipartFile file) throws Exception {
if(StringUtils.isEmpty(videoId)||StringUtils.isEmpty(userId)) {
return IMoocJSONResult.errorMsg("视频主键id或用户id不能为空...");
}
// //文件保存的命名空间
// String fileSpace="F:/武汉理工风景/大四上/毕业设计/user_videos_dev";
//保存到数据库中的相对路径
String uploadPathDB="/"+userId+"/video";
FileOutputStream fileOutputStream=null;
InputStream inputStream=null;
//文件上传的最终保存路径
String finalCoverPath="";
try {
if (file!=null) {
String fileName=file.getOriginalFilename();
if(!StringUtils.isEmpty(fileName)) {
finalCoverPath=FILE_SPACE+uploadPathDB+"/"+fileName;
//设置数据库保存的路径
uploadPathDB+=("/"+fileName);
File outFile=new File(finalCoverPath);
if(outFile.getParentFile()!=null||!outFile.getParentFile().isDirectory()) {
//创建父文件夹
outFile.getParentFile().mkdirs();
}
fileOutputStream=new FileOutputStream(outFile);
inputStream=file.getInputStream();
IOUtils.copy(inputStream, fileOutputStream);
}
}else {
return IMoocJSONResult.errorMsg("上传出错...");
}
} catch (Exception e) {
e.printStackTrace();
return IMoocJSONResult.errorMsg("上传出错...");
}finally {
if(fileOutputStream!=null) {
fileOutputStream.flush();
fileOutputStream.close();
}
}
videoService.updateVideo(videoId, uploadPathDB);
return IMoocJSONResult.ok();
}
}
6-28 小程序端与后台联调测试上传流程
chooseBgm.js的代码如下:
const app = getApp()
Page({
data: {
bgmList:[],
serverUrl:"",
videoParams:{
}
},
onLoad: function (params) {
var me=this;
console.log(params);
me.setData({
videoParams:params
});
wx.showLoading({
title: '请等待...',
});
var serverUrl=app.serverUrl;
//调用后端
wx.request({
url: serverUrl+'/bgm/list',
method:"POST",
header:{
'content-type':'application/json'//默认值
},
success:function(res){
console.log(res.data);
wx.hideLoading();
if(res.data.status==200){
var bgmList=res.data.data;
me.setData({
bgmList:bgmList,
serverUrl:serverUrl
});
}
}
})
},
upload:function(e){
var me=this;
var bgmId=e.detail.value.bgmId;
var desc=e.detail.value.desc;
console.log("bgmId:"+bgmId);
console.log("desc:"+desc);
var duration=me.data.videoParams.duration;
var tmpheight=me.data.videoParams.tmpheight;
var tmpwidth=me.data.videoParams.tmpwidth;
var tmpVideoUrl=me.data.videoParams.tmpVideoUrl;
var tmpCoverUrl = me.data.videoParams.tmpCoverUrl;
//上传短视频
wx.showLoading({
title: '上传中...',
})
var serverUrl=app.serverUrl;
wx.uploadFile({
url: serverUrl+'/video/upload',
formData:{
userId:app.userInfo.id,
bgmId:bgmId,
desc:desc,
videoSeconds:duration,
videoHeight:tmpheight,
videoWidth:tmpwidth
},
filePath: tmpVideoUrl,
name: 'file',
header:{
'content-type':'application/json'//默认值
},
success (res){
var data = JSON.parse(res.data);
wx.hideLoading();
if(data.status==200){
wx.showToast({
title: '上传成功!',
icon:'success'
});
// 上传成功后跳回之前的页面
wx.navigateBack({
delta: 1
})
// //上传封面
// var videoId=data.data;
// debugger;
// wx.showLoading({
// title: '上传中...',
// })
// wx.uploadFile({
// url:serverUrl+'/video/uploadCover',
// formData:{
// userId:app.userInfo.id,
// videoId:videoId
// },
// filePath:tmpCoverUrl,
// name:'file',
// header:{
// 'content-type':'application/json'
// },
// success(res){
// var data=JSON.parse(res.data);
// wx.hideLoading();
// if(data.status==200){
// wx.showToast({
// title: '上传成功!',
// icon:'success'
// });
// wx.navigateBack({
// delta: 1,
// })
// }else{
// wx.showToast({
// title: '上传失败!',
// icon:'loading'
// });
// }
// }
// })
}else{
wx.showToast({
title: '上传失败!',
icon:'loading'
});
}
}
})
}
})
上一章最后的问题,问啥总是显示上传失败,明明都已经全部上传到数据库里面了,原来是我状态获取错了!
转载:https://blog.csdn.net/weixin_43820675/article/details/116349226
查看评论