视频的上传,转码与展示的过程

本文是记录自己学习过程的,不适合直接拿来用的

业务需求及场景

后台基于spring boot 的微服务框架,页面是vue
用户可以选择一个视频上传的管理页面,新增时,用户可以选择上传封面图片或者不选择上传封面图片(此时要根据视频的格式决定是从视频中截图或者展示默认图片)

页面效果先不展示了,涉及的信息比较多

这里贴的是视频转码功能部分,我从网上找的代码又根据自己的需要又改的,很佩服写这段代码的人
真的很厉害(侵删)

/**
 * @author wuad
 */
public class Contants {

    /**
     * 本地测试
     */
    public static final String ffmpegpath = "D:/ffmpeg-20180723-d134b8d-win64-static/bin/ffmpeg.exe";		// ffmpeg工具安装位置
    public static final String targetfolder = "C:/linshiVideo/"; // 转码后视频保存的目录
    public static final String imageRealPath = "C:/linshiVideo/"; // 截图的存放目录
}
/**
 * @author wuad
 */
@RestController
@RequestMapping(value = "/video/transition/")
public class ConverVideoTest {

    //web调用
    @GetMapping(value = "/run/{yuanPATH}")
    public Result ffmpeg(@PathVariable("yuanPATH") String yuanPATH) {
        try {
            //web传入的源视频
            String filePath = yuanPATH;
            System.out.println("ConverVideoTest说:传入工具类的源视频地址为:"+filePath);
            //传入path
            ConverVideoUtils zout = new ConverVideoUtils(filePath);
            //设置转换的格式
            String targetExtension = ".mp4";

            boolean isDelSourseFile = true;
            //开始调用转换方法,删除源文件。
            boolean beginConver = zout.beginConver(targetExtension,isDelSourseFile);
            System.out.println("beginConver:" + beginConver);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return Res.makeOKRsp("视频转码成功");
    }

}

/**
 * @author wuad
 */
public class ConverVideoUtils {
    private String sourceVideoPath;							//源视频路径
    private String filerealname;				 			//文件名不包括后缀名
    private String filename; 								//包括后缀名
    private String ffmpegpath = Contants.ffmpegpath;		 // ffmpeg.exe的目录
    private String imageRealPath = Contants.imageRealPath;  // 视频截图的目录



    //重构构造方法,传入源视频
    public ConverVideoUtils(String path) {
        sourceVideoPath = path;
    }

    //set和get方法传递path
    public String getPATH() {
        return sourceVideoPath;
    }

    public void setPATH(String path) {
        sourceVideoPath = path;
    }

    /**
     * 转换视频格式
     * @param  targetExtension 目标视频后缀名 .xxx
     * @param  isDelSourseFile 转换完成后是否删除源文件
     * @return
     */
    public boolean beginConver(String targetExtension, boolean isDelSourseFile) {
        File fi = new File(sourceVideoPath);
        //获取视频名+后缀名
        filename = fi.getName();//视频转码后,路径加这个反馈给前台显示出视频和封面图片

        //获取不带后缀的文件名-后面加.toLowerCase()小写(filerealname:视频名称)
        filerealname = filename.substring(0, filename.lastIndexOf("."));

        System.out.println("----接收到文件("+filerealname+")需要转换-------");

        //执行转码机制
        if (process(targetExtension,isDelSourseFile)) {

            System.out.println("视频转码结束,开始截图================= ");

            //视频转码完成,调用截图功能
            if (processImg(sourceVideoPath)) {
                System.out.println("截图成功! ");
            } else {
                System.out.println("截图失败! ");
            }


			File file1 = new File(sourceVideoPath);
	         if (file1.exists()){
	        	 System.out.println("删除原文件-可用:"+sourceVideoPath);
	             file1.delete();
	          }


            sourceVideoPath = null;
            return true;
        } else {
            sourceVideoPath = null;
            return false;
        }
    }



    /**
     * 视频截图功能
     * @param sourceVideoPath 需要被截图的视频路径(包含文件名和后缀名)
     * @return
     */
    public boolean processImg(String sourceVideoPath) {

        //先确保保存截图的文件夹存在
        File TempFile = new File(imageRealPath);
        if (TempFile.exists()) {
            if (TempFile.isDirectory()) {
                System.out.println("该文件夹存在。");
            }else {
                System.out.println("同名的文件存在,不能创建文件夹。");
            }
        }else {
            System.out.println("文件夹不存在,创建该文件夹。");
            TempFile.mkdir();
        }

        File fi = new File(sourceVideoPath);
        filename = fi.getName();			//获取视频文件的名称。
        filerealname = filename.substring(0, filename.lastIndexOf("."));	//获取视频名+不加后缀名 后面加.toLowerCase()转为小写

        List<String> commend = new ArrayList<String>();
        //第一帧: 00:00:01
        //截图命令:time ffmpeg -ss 00:00:01 -i test1.flv -f image2 -y test1.jpg

        commend.add(ffmpegpath);			//指定ffmpeg工具的路径
        commend.add("-ss");
        commend.add("00:00:10");			//1是代表第1秒的时候截图
        commend.add("-i");
        commend.add(sourceVideoPath);		//截图的视频路径
        commend.add("-f");
        commend.add("image2");
        commend.add("-y");
        commend.add(imageRealPath + filerealname +".jpg");		//生成截图xxx.jpg

        //打印截图命令
        StringBuffer test = new StringBuffer();
        for (int i = 0; i < commend.size(); i++) {
            test.append(commend.get(i) + " ");
        }
        System.out.println("截图命令:"+test);
        System.out.println("截图名称:"+ filerealname +".jpg");

        //转码后完成截图功能-还是得用线程来解决
        try {
			/*ProcessBuilder builder = new ProcessBuilder();
			builder.command(commend);
			Process p =builder.start();*/
            //调用线程处理命令
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commend);
            Process p = builder.start();

            //获取进程的标准输入流
            final InputStream is1 = p.getInputStream();
            //获取进程的错误流
            final InputStream is2 = p.getErrorStream();
            //启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
            new Thread() {
                public void run() {
                    BufferedReader br = new BufferedReader(
                            new InputStreamReader(is1));
                    try {
                        String lineB = null;
                        while ((lineB = br.readLine()) != null) {
                            if (lineB != null){
                                //System.out.println(lineB);    //必须取走线程信息避免堵塞
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    //关闭流
                    finally{
                        try {
                            is1.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                }
            }.start();
            new Thread() {
                public void run() {
                    BufferedReader br2 = new BufferedReader(
                            new InputStreamReader(is2));
                    try {
                        String lineC = null;
                        while ((lineC = br2.readLine()) != null) {
                            if (lineC != null)   {
                                //System.out.println(lineC);   //必须取走线程信息避免堵塞
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    //关闭流
                    finally{
                        try {
                            is2.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                }
            }.start();
            // 等Mencoder进程转换结束,再调用ffmepg进程非常重要!!!
            p.waitFor();
            System.out.println("截图进程结束");
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }



    /**
     * 实际转换视频格式的方法
     * @param targetExtension 目标视频后缀名
     * @param isDelSourseFile 转换完成后是否删除源文件
     * @return
     */
    private boolean process(String targetExtension, boolean isDelSourseFile) {

        //先判断视频的类型-返回状态码
        int type = checkContentType();
        boolean status = false;

        // 根据状态码处理
        if (type == 0) {
            System.out.println("ffmpeg可以转换,统一转为mp4文件");
            // 可以指定转换为什么格式的视频
            status = processVideoFormat(sourceVideoPath,targetExtension,isDelSourseFile);
        }
        return status;   //执行完成返回布尔类型true
    }

    /**
     * 检查文件类型,判断ffmpeg能否转换
     * @return
     */
    private int checkContentType() {

        //取得视频后缀-
        String type = sourceVideoPath.substring(sourceVideoPath.lastIndexOf(".") + 1, sourceVideoPath.length()).toLowerCase();
        System.out.println("源视频类型为:"+type);

        // 如果是ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
        if (type.equals("avi")) {
            return 0;
        } else if (type.equals("mpg")) {
            return 0;
        } else if (type.equals("wmv")) {
            return 0;
        } else if (type.equals("3gp")) {
            return 0;
        } else if (type.equals("mov")) {
            return 0;
        } else if (type.equals("mp4")) {
            return 0;
        } else if (type.equals("asf")) {
            return 0;
        } else if (type.equals("asx")) {
            return 0;
        } else if (type.equals("flv")) {
            return 0;
        }else if (type.equals("mkv")) {
            return 0;
        }
        System.out.println("上传视频格式异常");
        return 9;
    }


    /**
     * 转换为指定格式
     * ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
     * @param oldfilepath
     * @param targetExtension 目标格式后缀名 .xxx
     * @param isDelSourceFile 转换完成后是否删除源文件
     * @return
     */
    private boolean processVideoFormat(String oldfilepath, String targetExtension, boolean isDelSourceFile) {

        System.out.println("这里调用了ffmpeg.exe工具");
        System.out.println("----开始转文件(" + sourceVideoPath + ")-------------------------- ");

        List<String> commend = new ArrayList<String>();

        commend.add(ffmpegpath);		 //ffmpeg.exe工具地址
        commend.add("-i");
        commend.add(oldfilepath);			//源视频路径

        commend.add("-vcodec");
        commend.add("h263");  //
        commend.add("-ab");		//新增4条
        commend.add("128");      //高品质:128 低品质:64
        commend.add("-acodec");
        commend.add("mp3");      //音频编码器:原libmp3lame
        commend.add("-ac");
        commend.add("2");       //原1
        commend.add("-ar");
        commend.add("22050");   //音频采样率22.05kHz
        commend.add("-r");
        commend.add("29.97");  //高品质:29.97 低品质:15
        commend.add("-c:v");
        commend.add("libx264");	//视频编码器:视频是h.264编码格式
        commend.add("-strict");
        commend.add("-2");
        commend.add(targetfolder + filerealname + targetExtension);  // //转码后的路径+名称,是指定后缀的视频

        //打印命令
        StringBuffer test = new StringBuffer();
        for (int i = 0; i < commend.size(); i++) {
            test.append(commend.get(i) + " ");
        }
        System.out.println("ffmpeg输入的命令:"+test);

        try {
            //多线程处理加快速度-解决rmvb数据丢失builder名称要相同
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commend);
            Process p = builder.start();   //多线程处理加快速度-解决数据丢失

            final InputStream is1 = p.getInputStream();
            final InputStream is2 = p.getErrorStream();
            new Thread() {
                public void run() {
                    BufferedReader br = new BufferedReader(
                            new InputStreamReader(is1));
                    try {
                        String lineB = null;
                        while ((lineB = br.readLine()) != null) {
                            if (lineB != null)
                                System.out.println(lineB);    //打印mencoder转换过程代码
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
            new Thread() {
                public void run() {
                    BufferedReader br2 = new BufferedReader(
                            new InputStreamReader(is2));
                    try {
                        String lineC = null;
                        while ((lineC = br2.readLine()) != null) {
                            if (lineC != null)
                                System.out.println(lineC);    //打印mencoder转换过程代码
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }.start();

            p.waitFor();		//进程等待机制,必须要有,否则不生成mp4!!!
            System.out.println("生成mp4视频为:"+imageRealPath + filerealname + ".mp4");
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

这是controller 的


    /**
     * 添加视频信息
     * @param file
     * @return
     */
    @PostMapping(value = "/save")
    public Result save(Video video, @RequestParam("file") MultipartFile[]file){
//        logger.error("[file]" + file.length);
        try{
            if(video != null){
                // 根据视频名称查询,重复的视频名称数据不能添加
                List<Video> list = videoService.fingListByVideoName(video.getVideoName());
                if(list != null && list.size() > 0) {
                    return Res.makeErrRsp("视频名称,请勿命名重复");
                }else{
                    if(file != null){
                        //上传视频
                        JSONObject rData = videoService.fileUpload(file);
                        // 获取上传视频后的路径
                        String data = rData.get("data").toString();
                        JSONObject rr = JSONObject.parseObject(data);

                        // 获取基本信息,厂商id,视屏名称,视频上传后的路径
                        video.setVideoPath(rr.getString("path"));

                        // 视频名称
                        video.setUploadVideoName(rr.getString("fileName"));
//                        // 用户上传的图片名称
                        video.setCoverPicture(rr.getString("coverPictureName"));
                        // 视频中截取的图片
                        video.setJietu(rr.getString("jieTu"));

                        video.setId(UUID.randomUUID().toString().replace("-",""));
                        videoService.insert(video);

                    }else if (video != null && file == null){
                        logger.error("[添加文件信息失败]");
                        return Res.makeErrRsp("添加失败,未上传文件");
                    }else if(video == null && file != null){
                        logger.error("[添加文件信息失败]");
                        return Res.makeErrRsp("添加失败,参数为空");
                    }
                }
            }
        } catch (Exception e){
            logger.error("[添加文件信息失败]",e);
            return Res.makeErrRsp("添加文件信息失败");
        }
        return Res.makeOKRsp(video);
    }

这是实现类,这个写的比较乱,自己写的很乱,有涉及到很多变量名称的修改和存储

 /**
     * 视频上传
     * @param file
     * @return
     */
    @Override
    public JSONObject fileUpload(MultipartFile [] file) {
        JSONObject rData = new JSONObject();
        try {
            // 视频上传用拼接路径 :/new/video/
            String suffixPath =  File.separator + "new" + File.separator + "video"+ File.separator ;
            String coverPictureName = "";
            String fileName = "";
            if (file != null && file.length == 1) {

                // 获取视频后缀
                String suffix = file[0].getOriginalFilename().substring(file[0].getOriginalFilename().lastIndexOf("."));
                if (".jpg".equals(suffix.toLowerCase()) || ".png".equals(suffix.toLowerCase()) || ".jpeg".equals(suffix.toLowerCase()))  {
                    // 获取图片名称和后缀格式
                    String pictureName = file[0].getOriginalFilename().substring(0,file[0].getOriginalFilename().lastIndexOf(".")).replaceAll(" ", "");

                    //  图片名称拼接
                    coverPictureName = pictureName + "-" + System.currentTimeMillis() + suffix;
                    byte[] bytesPicture = file[0].getBytes();
                    // 上传路径正式环境
                    Path pathPicture = Paths.get( uploadFilesPath + suffixPath + File.separator+ coverPictureName);
                    // 图片写入指定路径
                    Files.write(pathPicture,bytesPicture);
                } else {

                    // 获取视频名称
                    String uploadFileName = file[0].getOriginalFilename().substring(0,file[0].getOriginalFilename().lastIndexOf(".")).replaceAll(" ", "");
//                    // 获取视频后缀
//                    String houzhui = suffix;
                    System.out.println("需要上传的视频为:" + uploadFileName + suffix);
//                     判断视频格式是否是MP4,否,则调用转码方法,转码方法也能将视频上传

                        // 视频名称拼接
                        fileName = uploadFileName + "-" + System.currentTimeMillis() + suffix;

                        byte[] bytes = file[0].getBytes();
                        // 上传路径
                        Path path = Paths.get( uploadFilesPath  + suffixPath  + fileName);

                        //视频写入指定路径
                        Files.write(path, bytes);
                        //
                    if(!suffix.equals(".mp4")){
                        coverPictureName = fileName.replace(suffix, ".jpg");
                    }

                }
            } else if(file != null && file.length == 2)  {
                // 获取视频名称和后缀
                String uploadFileName = file[0].getOriginalFilename().substring(0,file[0].getOriginalFilename().lastIndexOf(".")).replaceAll(" ", "");
                String suffix = file[0].getOriginalFilename().substring(file[0].getOriginalFilename().lastIndexOf("."));
                String houzhui = suffix;
                System.out.println("视频后缀为:" + suffix);

                    // 视频名称拼接
                    fileName = uploadFileName + "-" + System.currentTimeMillis() + suffix;
                    byte[] bytes = file[0].getBytes();
                    Path path = Paths.get( uploadFilesPath  + suffixPath  + fileName);
                    //视频写入指定路径
                    Files.write(path, bytes);
                    
            // 获取图片名称和后缀格式
                String pictureName = file[1].getOriginalFilename().substring(0,file[1].getOriginalFilename().lastIndexOf(".")).replaceAll(" ", "");
                String suffixpicture = file[1].getOriginalFilename().substring(file[1].getOriginalFilename().lastIndexOf("."));
                //  图片名称拼接
                coverPictureName = pictureName + "-" + System.currentTimeMillis() + suffixpicture;
                byte[] bytesPicture = file[1].getBytes();
                Path pathPicture = Paths.get( uploadFilesPath +suffixPath + File.separator+ coverPictureName);
                // 图片写入指定路径
                Files.write(pathPicture,bytesPicture);
            }
            // 将后缀修改后即为视频截图
            String jieTu = fileName.replace(fileName.substring(fileName.indexOf(".")+1,fileName.length()),"jpg");
            JSONObject rr = new JSONObject();

            rr.put("zhuanmaqianfileName",fileName);
            rr.put("jieTu",jieTu);
            rr.put("coverPictureName",coverPictureName);
            rr.put("fileName",fileName);
            rData.put("state","0");
            rData.put("msg","文件上传成功");
            rData.put("data",rr);

        } catch (Exception e) {
            rData.put("state","1");
            rData.put("msg","文件上传失败:" + e);
            return rData;
        }
        return rData;
    }
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
FFmpeg是一个开源的跨平台音视频处理工具,可以用于转码、剪辑、合并、分割等多种音视频处理操作。下面是使用FFmpeg进行视频转码的一般步骤: 1. 下载和安装FFmpeg:你可以从FFmpeg官方网站(https://ffmpeg.org/)下载适合你操作系统的版本,并按照官方提供的安装指南进行安装。 2. 打开命令行终端:在Windows系统中,你可以使用cmd或PowerShell;在Linux或Mac系统中,你可以使用终端。 3. 转码命令:使用以下命令进行视频转码: ``` ffmpeg -i input.mp4 output.mp4 ``` 其中,`input.mp4`是你要转码的原始视频文件名,`output.mp4`是转码后生成的目标视频文件名。你可以根据需要修改文件名和路径。 4. 转码参数:你可以根据需要添加一些参数来控制转码过程,例如: - 调整视频分辨率:使用`-s`参数,如`-s 1280x720`表示将视频分辨率调整为1280x720。 - 调整视频比特率:使用`-b:v`参数,如`-b:v 2M`表示将视频比特率调整为2Mbps。 - 调整音频比特率:使用`-b:a`参数,如`-b:a 128k`表示将音频比特率调整为128kbps。 - 转换视频格式:使用`-c:v`参数,如`-c:v libx264`表示将视频编码格式转换为H.264。 5. 执行转码:在命令行中输入转码命令后,按下回车键执行转码操作。你可以在命令行中看到转码的进度和输出信息。 6. 等待转码完成:转码时间根据原始视频的大小和你的电脑性能而定,等待转码完成后,你就可以在指定的输出路径中找到转码后的视频文件了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值