| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- package com.goafanti.admin.controller;
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.math.BigInteger;
- import java.nio.channels.FileChannel;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.util.Base64;
- import java.util.Calendar;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.FutureTask;
- import java.util.concurrent.TimeUnit;
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletRequest;
- import javax.validation.Valid;
- import net.bramp.ffmpeg.FFmpeg;
- import net.bramp.ffmpeg.FFmpegExecutor;
- import net.bramp.ffmpeg.FFmpegUtils;
- import net.bramp.ffmpeg.FFprobe;
- import net.bramp.ffmpeg.builder.FFmpegBuilder;
- import net.bramp.ffmpeg.job.FFmpegJob;
- import net.bramp.ffmpeg.probe.FFmpegProbeResult;
- import net.bramp.ffmpeg.progress.Progress;
- import net.bramp.ffmpeg.progress.ProgressListener;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.stereotype.Controller;
- import org.springframework.validation.BindingResult;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.ResponseBody;
- import com.goafanti.admin.service.AdminVideoService;
- import com.goafanti.common.bo.Result;
- import com.goafanti.common.constant.ErrorConstants;
- import com.goafanti.common.controller.CertifyApiController;
- import com.goafanti.common.enums.AttachmentType;
- import com.goafanti.common.enums.VideoFields;
- import com.goafanti.common.model.JtVideo;
- import com.goafanti.common.utils.StringUtils;
- import com.goafanti.core.shiro.token.TokenManager;
- @Controller
- @RequestMapping(value = "/api/admin/video")
- public class AdminVideoApiController extends CertifyApiController {
- @Resource
- private AdminVideoService adminVideoService;
- @Value(value = "${ffmpeg.path}")
- private String ffmpegPath = null;
- @Value(value = "${ffprobe.path}")
- private String ffprobePath = null;
- @Value(value = "${video.temppath}")
- private String videoTemppath = null;
-
-
- // 上传视频只做MP4格式的
- @RequestMapping(value = "/upload", method = RequestMethod.POST)
- @ResponseBody
- public Result uploadPicture(HttpServletRequest req, String sign) {
- Result res = new Result();
- AttachmentType attachmentType = AttachmentType.getField(sign);
- if (attachmentType == AttachmentType.VIDEO) {
- // 先将视频存在本地文件中
- String dir = videoTemppath + "/convert_before";
- String filename = handleVideoFiles(res, req, dir);
- res.setData(filename);
- } else if (attachmentType == AttachmentType.VIDEO_COVER) {
- String picturebase = req.getParameter("picturebase");
- String filename = req.getParameter("filename");
- byte[] bs = Base64.getDecoder().decode(picturebase);
- filename = System.nanoTime()
- + filename.substring(filename.indexOf("."));
- res.setData(handleBaseFiles(res, "/video_cover/", false, bs, sign,
- TokenManager.getUserId(), filename));
- } else {
- res.getError().add(
- buildError(ErrorConstants.PARAM_ERROR, "", "文件标示"));
- }
- return res;
- }
- private String createFileName() {
- // 年月日
- Calendar now = Calendar.getInstance();
- int year = now.get(Calendar.YEAR);
- int month = now.get(Calendar.MONTH) + 1;
- int day = now.get(Calendar.DAY_OF_MONTH);
- String dir = "/" + year + "/" + month + "/" + day;
- return dir;
- }
- // 查看所有视频信息
- @RequestMapping(value = "/getVideoList", method = RequestMethod.GET)
- @ResponseBody
- public Result getVideoList(JtVideo video, Integer pageNo, Integer pageSize) {
- Result result = new Result();
- result.setData(adminVideoService.getVideoList(video, pageNo, pageSize,1));
- return result;
- }
- // 查看单个信息
- @RequestMapping(value = "/getVideoById", method = RequestMethod.GET)
- @ResponseBody
- public Result getVideoById(String id) {
- Result result = new Result();
- JtVideo video = new JtVideo();
- video.setId(id);
- result.setData(adminVideoService.getVideoById(video));
- return result;
- }
- // 新增视频信息
- @RequestMapping(value = "/insertVideo", method = RequestMethod.POST)
- @ResponseBody
- public Result insertVideo(@Valid JtVideo video , BindingResult bindingResult) throws IOException,
- InterruptedException, ExecutionException {
- // 数据限制
- Result result = new Result();
- if (bindingResult.hasErrors()) {
- result.getError().add(buildErrorByMsg(bindingResult.getFieldError().getDefaultMessage(),
- VideoFields.getFieldDesc(bindingResult.getFieldError().getField())));
- return result;
- }
- if(StringUtils.isBlank(video.getName())){
- result.getError().add(
- buildError( "视频名称不能是空", "视频名称不能是空"));
- return result;
- }
- //名称重名限制
- if(adminVideoService.nameCheck(video.getName().trim()) > 0){
- result.getError().add(
- buildError(ErrorConstants.PARAM_ERROR, "", "视频名称重复不能新增"));
- return result;
- }
-
- String filename = video.getUrl();
-
- // 生成保存到数据库的url
- String output = System.nanoTime() + ".mp4";
-
- String filepath = createFileName();
- video.setUrl(filepath + "/" + output);
-
- video.setTranscoding(1);
- // 保存到数据库
- result.setData(adminVideoService.insertVideo(video));
- // 压缩视频并将视频存储
-
- FileChannel fc= null;
- try {
- File f= new File(filename);
- if (f.exists() && f.isFile()){
- FileInputStream fis= new FileInputStream(f);
- fc= fis.getChannel();
- Long fsize = fc.size()/1024/1024;
- System.out.println(fc.size());
- if(fsize.longValue() > 50){
- videoChange(filename, output, video.getUrl(), videoTemppath + "/convert_after" + filepath );
- }else{
- copy(filename, output, videoTemppath + "/convert_after" + filepath + "/" );
- //修改数据库
- updateSql(video.getUrl(), videoTemppath + "/convert_after" + filepath ,output);
- }
-
-
- }else{
- System.out.println("file doesn't exist or is not a file");
- }
- } catch (FileNotFoundException e) {
- System.out.println(e);
- } catch (IOException e) {
- System.out.println(e);
- } finally {
- if (null!=fc){
- try{
- fc.close();
- }catch(IOException e){
- System.out.println(e);
- }
- }
- }
-
-
-
- return result;
- }
- // 修改视频
- @RequestMapping(value = "/updateVideo", method = RequestMethod.POST)
- @ResponseBody
- public Result updateVideo(@Valid JtVideo video , BindingResult bindingResult) throws IOException,
- InterruptedException, ExecutionException {
- Result result = new Result();
- if (bindingResult.hasErrors()) {
- result.getError().add(buildErrorByMsg(bindingResult.getFieldError().getDefaultMessage(),
- VideoFields.getFieldDesc(bindingResult.getFieldError().getField())));
- return result;
- }
- JtVideo v = new JtVideo();
- v.setId(video.getId());
- JtVideo oldVideo = adminVideoService.getVideoById(v);
- if (StringUtils.isBlank(video.getId())) {
- result.getError().add(
- buildError(ErrorConstants.PARAM_ERROR, "", "视频id不能为空"));
- return result;
- } else if (null == oldVideo) {
- result.getError().add(
- buildError(ErrorConstants.PARAM_ERROR, "", "视频id不存在"));
- return result;
- }
- if(null != video.getName() && "".equals(video.getName().trim())){
- result.getError().add(
- buildError( "视频名称不能是空", "视频名称不能是空"));
- return result;
- }
- //如果是删除视频
- if(null != video.getStatus() && video.getStatus() == 3){
- if(oldVideo.getStatus() == 1){
- result.getError().add(
- buildError( "视频已经发布不能删除", "视频已经发布不能删除"));
- return result;
- }else{
- deleteFtpVideo( videoTemppath + "/convert_after" + oldVideo.getUrl());
- }
- }
- Boolean flag = false;
- String filepath = "";
- String output = "";
- if (StringUtils.isNotBlank(video.getUrl()) && !video.getUrl().equals(oldVideo.getUrl())) { // 如果修改了视频
- video.setTranscoding(1);
- // 压缩视频并将视频
- String filename = video.getUrl();
- output = System.nanoTime() + ".mp4";
- filepath = createFileName() ;
- video.setUrl(filepath + "/" + output);
- FileChannel fc= null;
- try {
- File f= new File(filename);
- if (f.exists() && f.isFile()){
- FileInputStream fis= new FileInputStream(f);
- fc= fis.getChannel();
- Long fsize = fc.size()/1024/1024;
- System.out.println(fc.size());
- if(fsize.longValue() > 50){
- videoChange(filename, output, video.getUrl(), videoTemppath + "/convert_after" + filepath );
- }else{
- copy(filename, output, videoTemppath + "/convert_after" + filepath + "/" );
- flag = true;
- }
- }else{
- System.out.println("file doesn't exist or is not a file");
- }
- } catch (FileNotFoundException e) {
- System.out.println(e);
- } catch (IOException e) {
- System.out.println(e);
- } finally {
- if (null!=fc){
- try{
- fc.close();
- }catch(IOException e){
- System.out.println(e);
- }
- }
- }
- // videoChange(filename, output, video.getUrl(), videoTemppath + "/convert_after" + filepath);
-
- //删除原来远程的视频
- deleteFtpVideo(videoTemppath + "/convert_after" + oldVideo.getUrl());
- }else{
- video.setUrl(null);
- }
- result.setData(adminVideoService.updateVideo(video));
- if(flag){
- updateSql(video.getUrl(), videoTemppath + "/convert_after" + filepath ,output);
- }
- return result;
- }
-
- private Boolean deleteFtpVideo(String url){
- boolean b = false;
- //判断文件是否存在
- File f= new File(url);
- if(f.exists()){
- System.out.println("+++++++++++++++++++++++++++++文件存在,删除视频"+url);
- b = f.delete();
- }
- return b;
- }
- // 将文件转码
- private String videoChange(String input, String output, String url,String outputdir) throws IOException,
- InterruptedException, ExecutionException {
- File file = new File(outputdir);
- if(!file.isDirectory()){
- file.mkdirs();//创建文件夹
- }
- FFmpeg ffmpeg = new FFmpeg(ffmpegPath);
- FFprobe ffprobe = new FFprobe(ffprobePath);
- FFmpegProbeResult in = ffprobe.probe(input);
- FFmpegBuilder builder = new FFmpegBuilder();
- builder.setInput(in) // 输入文件
- .overrideOutputFiles(true) // 覆盖重复文件
- .addOutput(outputdir + "/" + output) // 输出文件
- .setFormat("mp4") // 设置格式
- .setTargetSize(250_000) // 目标大小
- .disableSubtitle() // 没有子标题
- .setAudioChannels(1) // 声道
- .setAudioSampleRate(48_000) // 音频采样率
- .setAudioBitRate(32768) // 音频传输率
- .setVideoCodec("libx264") // 视频编解码器
- .setVideoFrameRate(24, 1) // 视频帧速率
- .setVideoResolution(640, 480) // 视频分辨率
- .setStrict(FFmpegBuilder.Strict.EXPERIMENTAL) // 严格形式
- .done();
- FFmpegExecutor executor = new FFmpegExecutor(ffmpeg, ffprobe);
- ExecutorService service = Executors.newCachedThreadPool();
- // 3.直接new一个FutureTask
- SubTask subTask = new SubTask(executor, builder, in, url, input, output, outputdir);
- FutureTask<Boolean> result = new FutureTask<Boolean>(subTask);
- // 4.提交任务
- service.submit(result);
- // 5.关闭线程池
- service.shutdown();
- // LOGGER.info("=============返回给前端=============");
-
- //System.out.println("task运行结果" + result.get());
- return "SUCESS";
- }
- private void updateSql(String url, String tempdir, String filename) {
- // 修改数据
- File file = new File(tempdir+"/"+filename);
- JtVideo video = new JtVideo();
- video.setMd5(FileMD5(file));
- video.setTranscoding(2);
- video.setUrl(url);
- url = url.substring(0,url.lastIndexOf("/"));
- System.out.println("修改数据库000000000000000000000"+url);
- adminVideoService.updateByUrl(video);//修改状态
- }
-
- // 获得文件md5
- private String FileMD5(File file) {
- try {
- FileInputStream fis = new FileInputStream(file);
- MessageDigest md = MessageDigest.getInstance("MD5");
- byte[] buffer = new byte[1024];
- int length = -1;
- while ((length = fis.read(buffer, 0, 1024)) != -1) {
- md.update(buffer, 0, length);
- }
- BigInteger bigInt = new BigInteger(1, md.digest());
- return bigInt.toString(16);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
- class SubTask implements Callable<Boolean> {
- private Boolean state = false;
- private FFmpegExecutor executor;
- private FFmpegBuilder builder;
- private FFmpegProbeResult probeResult;
- private String url;
- private String input;
- private String output;
- private String tempdir;
- public SubTask(FFmpegExecutor executor, FFmpegBuilder builder,
- FFmpegProbeResult probeResult, String url, String input,
- String output, String tempdir) {
- this.executor = executor;
- this.builder = builder;
- this.probeResult = probeResult;
- this.url = url;
- this.input = input;
- this.output = output;
- this.tempdir = tempdir;
- }
- public FFmpegExecutor getExecutor() {
- return executor;
- }
- public FFmpegBuilder getBuilder() {
- return builder;
- }
- public String getUrl() {
- return url;
- }
- public String getInput() {
- return input;
- }
- public String getOutput() {
- return output;
- }
- public Boolean getState() {
- return state;
- }
- @Override
- public Boolean call() throws Exception {
- final double duration_ns = probeResult.getFormat().duration
- * TimeUnit.SECONDS.toNanos(1);
- try {
- FFmpegJob job = executor.createJob(builder,
- new ProgressListener() {
- @Override
- public void progress(Progress progress) {
- double percentage = progress.out_time_ns
- / duration_ns;
- System.out.println(String
- .format("[%.0f%%] status:%s frame:%d time:%s ms fps:%.0f speed:%.2fx",
- percentage * 100,
- progress.status,
- progress.frame,
- FFmpegUtils.toTimecode(
- progress.out_time_ns,
- TimeUnit.NANOSECONDS),
- progress.fps.doubleValue(),
- progress.speed));
- }
- });
- job.run();
- // 6.阻塞 call
- // System.out.println("设置 sate");
- // latch.wait();
- state = true;
- updateSql(url, tempdir,output);
- // 删除未压缩的视频
- File f1 = new File(input);
- f1.delete();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return state;
- }
- }
-
- public static void copy(String file1, String file2, String dir) {
- File file = new File(dir);
- if(!file.isDirectory()){
- file.mkdirs();//创建文件夹
- }
- System.out.println(file1);
- System.out.println(file2);
- File src = new File(file1);
- InputStream in = null;
- OutputStream out = null;
- System.out.println(file1.substring(file1.lastIndexOf("/"),file1.length()));//获取单个文件的源文件的名称
- try {
- in = new BufferedInputStream(new FileInputStream(src), 16 * 1024);
- FileOutputStream f = new FileOutputStream(dir+file2);// 一定要加上文件名称
- out = new BufferedOutputStream(f, 16 * 1024);
- byte[] buffer = new byte[16 * 1024];
- int len = 0;
- while ((len = in.read(buffer)) > 0) {
- out.write(buffer, 0, len);
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (null != in) {
- try {
- in.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (null != out) {
- try {
- out.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- public static void main(String[] args) {
- copy("D:/Downloads/环保小视频.mp4","haha.mp4","F:/data/local/video/convert_after/2018/11/9/");
- }
- }
|