基于java的微信小程序的实现(六)用户视频上传的前后端开发

1.用户上传视频功能需求分析

用户在登录之后可以在个人信息页面点击上传视频按钮,会让用户在本地选择一段视频进行上传,视频不能过长,选择好后,用户会跳转到选择背景音乐的界面,可以选择为该视频加上一段背景音乐,并且可以对该视频做相关描述,然后点击上传视频按钮,完成视频上传。

2.上传功能演示

在这里插入图片描述

3.编写查询背景音乐列表接口

1.需求分析

用户在上传视频之前需要查询后台所有的bgm,并显示出来,该接口需要将数据库中所有的bgm查询到,并返回给前端

2.代码实现

dao层

public interface BgmDao extends JpaRepository<Bgm,String> {
}

service层

/**
     * 查询全部的bgm并返回
     * @return
     */
    @Override
    public List<Bgm> findAllBgm() {
        return bgmDao.findAll();
    }

controller层

    @Autowired
    private BgmService bgmService;


    @ApiOperation(value = "查询BGM列表", notes = "查询bgm列表的接口")
    @PostMapping("/bgmList")
    public LexJSONResult bgmList(){
        //查询全部都bgm列表
        List<Bgm> allBgm = bgmService.findAllBgm();
        return LexJSONResult.ok(allBgm);
    }

4.FfmPeg技术的引入

1.简介

​ FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。

2.应用场景

使用该技术主要是为了处理音频与视频的结合,以及生成视频封面

3.相关操作

FfmPeg主要是通过cmd命令对文件进行相关操作的

 ffmpeg.exe -i test.mp4  -i bgm.mp3 -t 3 -y new.mp4

该命令的含义为将test.mp4和bgm.mp3合成为一个新的mp4文件,且长度为3s,使用该命令就可以将我们的音频和视频进行合成的处理了

ffmpeg.exe -ss 00:00:02 -y -i lex.mp4 -vframes 1 lex.jpg

改命令表示把lex.mp4这个视频的第二秒的内容进行一个截图,并保存为lex.jpg,使用该命令就可以生成视频的封面图

5.封装FfmPeg相关的工具类

首先我们如果想要使用FfmPeg对视频进行相关操作就一定要用到cmd命令,所以我们需要使用java中相关的类实现对cmd命令的操作


/**
 * 该类为对音频视频进行合成处理的工具类
 */
public class FFMPeg {

    private String ffmpegEXE;

    public FFMPeg(String ffmpegEXE) {
        this.ffmpegEXE = ffmpegEXE;
    }

    public void convert(String in,String mp3,Integer seconds,String out) throws IOException {
        //ffmpeg.exe -i test.mp4  -i bgm.mp3 -t 3 -y new.mp4
        //把一段命令通过空格的方式分割,并存入list
        List<String> cmd=new ArrayList<String>();
        cmd.add(ffmpegEXE);
        cmd.add("-i");

        cmd.add(in);
        cmd.add("-i");

        cmd.add(mp3);
        cmd.add("-t");

        cmd.add(String.valueOf(seconds));
        cmd.add("-y");
        cmd.add(out);

        //该类为java中操作cmd命令的一个类,参数中需要传入一个list列表
        ProcessBuilder processBuilder =new ProcessBuilder(cmd);
        Process process = processBuilder.start();
        //下面的操作是对FFMPeg中错误流的处理,如果不做该处理,最后合成的视频会不完整且无法播放
        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 class FFMPegCover {

    private String ffmpegEXE;

    public FFMPegCover(String ffmpegEXE) {
        this.ffmpegEXE = ffmpegEXE;
    }

    public void convert(String in,String out) throws IOException {
        //ffmpeg.exe -ss 00:00:01 -y -i lex.mp4 -vframes 1 lex.jpg
        List<String> cmd=new ArrayList<String>();
        cmd.add(ffmpegEXE);
        cmd.add("-ss");
        cmd.add("00:00:01");

        cmd.add("-y");
        cmd.add("-i");

        cmd.add(in);
        cmd.add("-vframes");

        cmd.add("1");
        cmd.add(out);


        for (String s:cmd
             ) {
            System.out.print(s);
        }

        ProcessBuilder processBuilder =new ProcessBuilder(cmd);
        Process process = processBuilder.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) {
        FFMPegCover ffmPegCover = new FFMPegCover("F:\\ffmpeg\\bin\\ffmpeg.exe");
        try {
            ffmPegCover.convert("F:\\ffmpeg\\bin\\lex.mp4","F:\\ffmpeg\\bin\\lex.jpg");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    }

6.编写视频上传的接口

1.需求分析

需要前端传递的参数有用户的id,bgm的id视频的长度,视频的宽度,视频的时长,上传文件的二进制文件 ,和上传头像的步骤相似,不过在传入参数时需要注意不要传递对象,否则会出现文件无法识别的的错误报415异常

2.代码实现

controller层代码

 @Autowired
    private BgmService bgmService;
    @Autowired
    private VideosService videosService;
    //该变量为ffmpeg所在的路径
    private final String FFMPEGEXE="F:\\ffmpeg\\bin\\ffmpeg.exe";
    //用户资源文件的目录
    private final  String  FILESPACE="F:/file";
    //默认每页显示数据数
    private final Integer SIZE=4;

    /**
     *
     * @param id
     * @param bgmId
     * @param videoSeconds
     * @param videoWidth
     * @param videoHeight
     * @param desc
     * @param file
     * @return
     * @throws IOException
     */
    @ApiOperation(value = "用户视频上传", notes = "用户视频上传的接口")
    @PostMapping(value = "/uploadVideo",headers = "content-type=multipart/form-data")
    public LexJSONResult upload(@RequestParam("id") String id,
                                String bgmId,
                                @RequestParam("videoSeconds") Integer videoSeconds,
                                @RequestParam("videoWidth") int videoWidth,
                                @RequestParam("videoHeight") int videoHeight,
                                String desc,
                                @ApiParam(value = "短视频",required = true) MultipartFile file) throws IOException {
        if (StringUtils.isEmpty(id)){
            return LexJSONResult.errorMsg("id不能为空");
        }
        //文件保存的命名空间
        FileOutputStream fileOutputStream=null;
        InputStream inputStream=null;
        //定义视频存放的相对路径
        String upLoadPathDb="/"+id+"/video";
        //定义视频封面存放的相路径
        String coverPathDb="/"+id+"/video";
        String coverName="/"+UUID.randomUUID().toString()+".jpg";
        try {
            if (file!=null){
                String filename = file.getOriginalFilename();
                if (!StringUtils.isEmpty(filename)){
                    String finalPath=FILESPACE+upLoadPathDb+"/"+filename;
                    upLoadPathDb=upLoadPathDb+"/"+filename;
                    File f=new File(finalPath);
                    if (f.getParentFile()!=null || !f.getParentFile().isDirectory()){
                        f.getParentFile().mkdirs();
                    }
                    fileOutputStream=new FileOutputStream(f);
                    inputStream=file.getInputStream();
                    IOUtils.copy(inputStream,fileOutputStream);
                    if (!StringUtils.isEmpty(bgmId)){
                        //判断bgmid是否为空,如果不为空,说明用户选择了bgm,根据该bgmid对bgm进行查询
                        Bgm bgm = bgmService.findOne(bgmId);
                        //获取bgm的相对路径,并和命名空间拼接获得该bgm的绝对路径
                        String bgmPath = FILESPACE+ bgm.getPath();
                        //创建ffmpeg工具类,并传入ffmpeg.exe所在的路径
                        FFMPeg ffmPeg =new FFMPeg(FFMPEGEXE);
                        //该路径为视频合成后需要存放的相对路径
                        upLoadPathDb="/"+id+"/video"+"/"+UUID.randomUUID()+".mp4";
                        //使用uuid生成新得mp4视频名称并且和路径拼接,作为绝对路径传入ffmpeg的convert方法中
                        String videoOutPath=FILESPACE+upLoadPathDb;
                        //分别传入用户上传视频的绝对路径bgm的路径,视频的秒数,合成后视频的路径
                        ffmPeg.convert(finalPath,bgmPath,videoSeconds,videoOutPath);
                    }
                    FFMPegCover ffmPegCover =new FFMPegCover(FFMPEGEXE);
                    ffmPegCover.convert(FILESPACE+upLoadPathDb,FILESPACE+coverPathDb+coverName);
                    //TODO 保存视频到数据库
                    Videos videos =new Videos();
                    videos.setUserId(id);
                    videos.setAudioId(bgmId);
                    videos.setVideoDesc(desc);
                    videos.setStatus(1);
                    videos.setVideoSeconds((float)videoSeconds);
                    videos.setVideoHeight(videoHeight);
                    videos.setVideoWidth(videoWidth);
                    videos.setVideoPath(upLoadPathDb);
                    videos.setCreateTime(new Date());
                    videos.setLikeCounts(0l);
                    videos.setCoverPath(coverPathDb+coverName);
                    videosService.save(videos);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (fileOutputStream!=null){
                fileOutputStream.flush();
                fileOutputStream.close();
            }
        }
        return LexJSONResult.ok(upLoadPathDb);
    }

service层代码

 /**
     * 通过id查询bgm
     * @param bgmId
     * @return
     */
    @Override
    public Bgm findOne(String bgmId) {
        return bgmDao.findOne(bgmId);
    }
    
     /**
     * 保存视频到数据库
     * @param videos
     */
    @Override
    @Transactional
    public void save(Videos videos) {
        videos.setId(IdUtils.getId());
        videosDao.save(videos);
    }

3.注意事项当页面报415时候的解决方案

因为刚开始写上传接口时候为了方便,我将上面的一些字段都封装到了一个Videos对象中,接口中的入参为对象,之后就一直报415,所以当有文件上传时不要传入对象

7.小程序端上传页面功能实现

1.需求分析

用户在个人信息页面点击上传视频按钮后会调用微信小程序的api让用户在本机选择一段视频,要控制长度在30s以内且不能小于1s,选择完成后会跳转到下一个选择背景音乐的页面。

2.代码实现

  uploadVideo:function(){
    var me =this;
    //微信小程序提供的api,用于选择视频
    wx.chooseVideo({
      sourceType: ['album', 'camera'],
      success(res) {
        console.log(res)
        //对视频的长度进行判断,如果小于1s则会提醒用户
        if (duration<1){
          wx.showToast({
            title: '你的视频太短了',
            icon:'none'
          })
          return;
        }else{
          //如果验证通过
          //获得该视频的时间长度
          var duration =res.duration;
          //获得视频的高度
          var height= res.height;
          //获得视频的尺寸
          var size =res.size;
          //获得视频的临时路径
          var tempFilePath =res.tempFilePath;
          //获得视频的宽度
          var width =res.width;
          //跳转到选择背景音乐的界面,并将所获得的参数传递过去
          wx.navigateTo({
            url: '../chooseBgm/chooseBgm?duration=' + duration+
              '&height=' + height+
              '&size=' + size +
              '&tempFilePath=' + tempFilePath +
              '&width=' + width 
          })
        }
      }
    })
  }

8.选择bgm页面以及上传功能的实现

1.需求分析

当用户选择完视频后会跳转到该页面来,当该页面在加载的时候应该调用查询全部bgm的接口,并将数据显示在该页面上,用户可以选择自己喜欢的bgm,并且写入视频的相关描述,点击上传按钮,我们要获取到用户所选的bgmid以及所写入的视频内容,并将这些作为参数,去调用后台的上传视频的接口

2.代码实现

const app = getApp()

Page({
    data: {
     
    bgmList:{},
    serverUrl:app.serverUrl,
    videoParams:{}

    },
    onLoad:function(params){
      var me=this;
      var serverUrl=app.serverUrl;
      //获取到上个页面传入的参数,并保存在videoParams
      me.setData({
        videoParams:params
      })
      //调用查询全部bgm的接口
      wx.request({
        url: serverUrl + '/bgmList',
        method:'POST',
        header: {
          'content-type': 'application/json'
        },
        success:function(res){
          //将返回值赋值给bgmList,在页面上遍历出来
          me.setData({
            bgmList:res.data.data
          })
          console.log(res.data)
        }
      })
    },
    //上传方法
  upload:function(e){
    var me =this;
    //获取视频的时长
    var duration=me.data.videoParams.duration;
    //获取视频的高度
    var height= me.data.videoParams.height;
    //获取上个页面返回的该视频的临时路径
    var tempFilePath = me.data.videoParams.tempFilePath;
    //获取该视频的宽度
    var width =me.data.videoParams.width;
    //获取用户所选择的bgmId
    var bgmId= e.detail.value.bgmId;
    //获取用户所输入的内容
    var desc = e.detail.value.desc;
    var serverUrl=app.serverUrl;

    // var user=app.userInfo;
    var user = app.getGlobalUserInfo("userInfo");
    wx.showLoading({
      title: '上传中',
    })
    //上传时候同样需要进行身份认证
    wx.uploadFile({
      url: serverUrl + '/video/uploadVideo', 
      filePath: tempFilePath,
      name: 'file',
      header: {
        'content-type': 'application/json',
        'userId': user.id,
        'userToken': user.token
      },
      //在uploadFile中如果要传多个数据可以使用formData
      formData:{
        id:user.id,
        videoSeconds: duration,
        videoHeight: height,
   
        videoWidth: width,
        bgmId: bgmId,
        desc: desc

      },
      success(res) {
        console.log(res.data)
        // const data = JSON.parse(res.data);
        wx.hideLoading();
        wx.showToast({
          title: '上传成功',
        })

     
      wx.redirectTo({
        url: '../mine/mine',
      })
      }
    })
    console.log(bgmId,desc)
  }

   
})

猜你喜欢

转载自blog.csdn.net/qq_36258498/article/details/84642274
今日推荐