码迷,mamicode.com
首页 > 微信 > 详细

小程序短视频项目———ffmpeg

时间:2018-10-05 23:03:32      阅读:349      评论:0      收藏:0      [点我收藏+]

标签:users   tst   create   edr   arraylist   gms   over   stat   相对路径   

视音频处理工具

技术分享图片

技术分享图片

 

二、ffmpeg与java的结合

首先在com.imooc.utils新建FFMpegTest类

package com.imooc.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class FFMpegTest {

    private String ffmpegEXE;
    
    
    public FFMpegTest(String ffmpegEXE) {
        super();
        this.ffmpegEXE = ffmpegEXE;
    }
    
    public void convertor(String videoInputPath, String videoOutputPath) throws Exception {
//        ffmpeg -i input.mp4 output.avi
        /*
         * java调用cmd命令
         */
        List<String> command = new ArrayList<>();
        command.add(ffmpegEXE);
        
        command.add("-i");
        command.add(videoInputPath);
        command.add(videoOutputPath);
        
        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 static void main(String[] args) {
        FFMpegTest ffmpeg = new FFMpegTest("D:\\ffmpeg\\bin\\ffmpeg.exe");
        try {
            ffmpeg.convertor("C:\\Users\\Administrator\\Pictures\\单挑.mp4", 
                    "C:\\Users\\Administrator\\Pictures\\斗牛.avi");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 

三、java合并视音频

MergeVideoMp3.class
package com.imooc.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class MergeVideoMp3 {

    private String ffmpegEXE;
    
    public MergeVideoMp3(String ffmpegEXE) {
        super();
        this.ffmpegEXE = ffmpegEXE;
    }
    
    public void convertor(String videoInputPath, String mp3InputPath,
            double seconds, String videoOutputPath) throws Exception {
//        ffmpeg.exe -i 苏州大裤衩.mp4 -i bgm.mp3 -t 7 -y 新的视频.mp4
        List<String> command = new ArrayList<>();
        command.add(ffmpegEXE);
        
        command.add("-i");
        command.add(videoInputPath);
        
        command.add("-i");
        command.add(mp3InputPath);
        
        command.add("-t");
        command.add(String.valueOf(seconds));
        
        command.add("-y");
        command.add(videoOutputPath);
        
//        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 static void main(String[] args) {
        MergeVideoMp3 ffmpeg = new MergeVideoMp3("D:\\ffmpeg\\bin\\ffmpeg.exe");
        try {
            ffmpeg.convertor("C:\\鬼.mp4", "C:\\music.mp3", 7.1, "C:\\这是通过java生产的视频.mp4");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 

package com.imooc.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class FFMpegTest {

    private String ffmpegEXE;
    
    public FFMpegTest(String ffmpegEXE) {
        super();
        this.ffmpegEXE = ffmpegEXE;
    }
    
    public void convertor(String videoInputPath, String videoOutputPath) throws Exception {
//        ffmpeg -i input.mp4 -y output.avi
        List<String> command = new ArrayList<>();
        command.add(ffmpegEXE);
        
        command.add("-i");
        command.add(videoInputPath);
        command.add("-y");
        command.add(videoOutputPath);
        
        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 static void main(String[] args) {
        FFMpegTest ffmpeg = new FFMpegTest("D:\\ffmpeg\\bin\\ffmpeg.exe");
        try {
            ffmpeg.convertor("C:\\鬼.mp4", "C:\\北京北京.avi");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 

四、小程序上传视频后调用视频处理工具联调

 技术分享图片

 五、保存视频信息到数据库

技术分享图片

技术分享图片

 

六、截图(视频封面)保存到数据库中

1、后端接口的开发

    @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 {  //Alt + shirt + R
        
        if (StringUtils.isBlank(videoId) || StringUtils.isBlank(userId)) {
            return IMoocJSONResult.errorMsg("视频主键id和用户id不能为空...");
        }
        
        //文件保存的空间
        String fileSpace = "D:/imooc_videos_dev";
        //保存到数据库的相对路径
        String uploadPathDB = "/" + userId + "/video" ;
        FileOutputStream fileOutputStream = null;
        InputStream inputStream = null;
        
        
        String finalCoverPath = "";
        try {
            if(file != null ) {
                
                
                String fileName = file.getOriginalFilename();
                if(StringUtils.isNoneBlank(fileName)) {
                    //文件上传的最终路径
                    finalCoverPath = fileSpace + 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);
                    
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(fileOutputStream != null) {
                fileOutputStream.flush();
                fileOutputStream.close();
            }
        }
        
        videoService.updateVideo(videoId, uploadPathDB);

        
        return IMoocJSONResult.ok();
    
    
    }

 

2、前端js的开发

 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: ‘Loading...‘,
      })


      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) {

            var videoId = data.data;
            
            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"
                  });


                } else {
                  wx.showToast({
                    title: ‘上传失败!~~‘,
                    icon: "success"
                  })
                }

              }
            });
            wx.navigateBack({
              delta: 1,
            })
          } else {
            wx.showToast({
              title: ‘上传失败!~~‘,
              icon: "success"
            })
          } 

        }
      })
    }

 

在用手机端进行联调时,上传封面功能并不能实现,这是微信小程序的一个小坑。需要用ffmpeg去截视频某一帧的图才行。

 

七、使用ffmpeg生成截图

技术分享图片

生成截图工具类

package com.imooc.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:06");
                
        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("D:\\ffmpeg\\bin\\ffmpeg.exe");
        try {
            videoInfo.getCover("c:\\北京北京.avi","c:\\北京.jpg");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

在controller补充对视频的截图

    @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="String", paramType="form"),
        @ApiImplicitParam(name="videoWidth", value="视频宽度", required=true, 
                dataType="String", paramType="form"),
        @ApiImplicitParam(name="videoHeight", value="视频高度", required=true, 
                dataType="String", paramType="form"),
        @ApiImplicitParam(name="desc", value="视频描述", required=false, 
                dataType="String", paramType="form")
    })
    @PostMapping(value="/upload", headers="content-type=multipart/form-data")
    public IMoocJSONResult upload(String userId, 
            String bgmId, double videoSeconds, 
            int videoWidth, int videoHeight,
            String desc,
            @ApiParam(value="短视频", required=true)
            MultipartFile file) throws Exception {  //Alt + shirt + R
        
        if (StringUtils.isBlank(userId)) {
            return IMoocJSONResult.errorMsg("用户id不能为空...");
        }
        
        //文件保存的空间
        String fileSpace = "D:/imooc_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();
                
                String fileNamePrefix = fileName.split("\\.")[0];
                
                if(StringUtils.isNoneBlank(fileName)) {
                    //文件上传的最终路径
                    finalVideoPath = fileSpace + 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);
                    
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(fileOutputStream != null) {
                fileOutputStream.flush();
                fileOutputStream.close();
            }
        }
        
        //判断bgmid是否为空,如果不为空,
        //那就查询bgm的信息,并且合并视频,生产新的视频
        if (StringUtils.isNotBlank(bgmId)) {
            Bgm bgm = bgmService.queryBgmById(bgmId);
            String mp3InputPath = FILE_SPACE + bgm.getPath();
            
            MergeVideoMp3 tool = new MergeVideoMp3(FFMPEG_EXE);
            String videoInputPath = finalVideoPath;
            
            String videoOutputName = UUID.randomUUID().toString() + ".mp4";
            uploadPathDB = "/" + userId + "/video" + "/" + videoOutputName;
            finalVideoPath = FILE_SPACE + uploadPathDB;
            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);
//        System.out.println("desc:"+desc);
        
        return IMoocJSONResult.ok(videoId);
    
    
    }

 

小程序短视频项目———ffmpeg

标签:users   tst   create   edr   arraylist   gms   over   stat   相对路径   

原文地址:https://www.cnblogs.com/bozzzhdz/p/9743739.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!