zoukankan      html  css  js  c++  java
  • Java—视频处理

      原始视频通常需要经过编码处理,生成m3u8和ts文件方可基于HLS协议播放视频。通常用户上传原始视频,系统 自动处理成标准格式,系统对用户上传的视频自动编码、转换,最终生成m3u8文件和ts文件,

    处理流程如下:

      1、用户上传视频成功

      2、系统对上传成功的视频自动开始编码处理

      3、用户查看视频处理结果,没有处理成功的视频用户可在管理界面再次触发处理

      4、视频处理完成将视频地址及处理结果保存到数据库

    VideoUtil

    package com.xuecheng.framework.utils;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 此文件作为视频文件处理父类,提供:
     * 1、查看视频时长
     * 2、校验两个视频的时长是否相等
     *
     */
    public class VideoUtil {
    
        String ffmpeg_path = "D:\Program Files\ffmpeg-20180227-fa0c9d6-win64-static\bin\ffmpeg.exe";//ffmpeg的安装位置
    
        public VideoUtil(String ffmpeg_path){
            this.ffmpeg_path = ffmpeg_path;
        }
    
    
        //检查视频时间是否一致
        public Boolean check_video_time(String source,String target) {
            String source_time = get_video_time(source);
            //取出时分秒
            source_time = source_time.substring(0,source_time.lastIndexOf("."));
            String target_time = get_video_time(target);
            //取出时分秒
            target_time = target_time.substring(0,target_time.lastIndexOf("."));
            if(source_time == null || target_time == null){
                return false;
            }
            if(source_time.equals(target_time)){
                return true;
            }
            return false;
        }
    
        //获取视频时间(时:分:秒:毫秒)
        public String get_video_time(String video_path) {
            /*
            ffmpeg -i  lucene.mp4
             */
            List<String> commend = new ArrayList<String>();
            commend.add(ffmpeg_path);
            commend.add("-i");
            commend.add(video_path);
            try {
                ProcessBuilder builder = new ProcessBuilder();
                builder.command(commend);
                //将标准输入流和错误输入流合并,通过标准输入流程读取信息
                builder.redirectErrorStream(true);
                Process p = builder.start();
                String outstring = waitFor(p);
                System.out.println(outstring);
                int start = outstring.trim().indexOf("Duration: ");
                if(start>=0){
                    int end = outstring.trim().indexOf(", start:");
                    if(end>=0){
                        String time = outstring.substring(start+10,end);
                        if(time!=null && !time.equals("")){
                            return time.trim();
                        }
                    }
                }
    
            } catch (Exception ex) {
    
                ex.printStackTrace();
    
            }
            return null;
        }
    
         public String waitFor(Process p) {
            InputStream in = null;
            InputStream error = null;
            String result = "error";
            int exitValue = -1;
            StringBuffer outputString = new StringBuffer();
            try {
                in = p.getInputStream();
                error = p.getErrorStream();
                boolean finished = false;
                int maxRetry = 600;//每次休眠1秒,最长执行时间10分种
                int retry = 0;
                while (!finished) {
                    if (retry > maxRetry) {
                        return "error";
                    }
                    try {
                        while (in.available() > 0) {
                            Character c = new Character((char) in.read());
                            outputString.append(c);
                            System.out.print(c);
                        }
                        while (error.available() > 0) {
                            Character c = new Character((char) in.read());
                            outputString.append(c);
                            System.out.print(c);
                        }
                        //进程未结束时调用exitValue将抛出异常
                        exitValue = p.exitValue();
                        finished = true;
    
                    } catch (IllegalThreadStateException e) {
                        Thread.currentThread().sleep(1000);//休眠1秒
                        retry++;
                    }
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        System.out.println(e.getMessage());
                    }
                }
            }
           return outputString.toString();
    
        }
    
    
        public static void main(String[] args) throws IOException {
            String ffmpeg_path = "D:\Program Files\ffmpeg-20180227-fa0c9d6-win64-static\bin\ffmpeg.exe";//ffmpeg的安装位置
            VideoUtil videoUtil = new VideoUtil(ffmpeg_path);
            String video_time = videoUtil.get_video_time("E:\ffmpeg_test\1.avi");
            System.out.println(video_time);
        }
    }

    Mp4VideoUtil

    package com.xuecheng.framework.utils;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by admin on 2018/3/6.
     */
    public class Mp4VideoUtil extends VideoUtil {
    
        String ffmpeg_path = "D:\Program Files\ffmpeg-20180227-fa0c9d6-win64-static\bin\ffmpeg.exe";//ffmpeg的安装位置
        String video_path = "D:\BaiduNetdiskDownload\test1.avi";
        String mp4_name = "test1.mp4";
        String mp4folder_path = "D:/BaiduNetdiskDownload/Movies/test1/";
        public Mp4VideoUtil(String ffmpeg_path, String video_path, String mp4_name, String mp4folder_path){
            super(ffmpeg_path);
            this.ffmpeg_path = ffmpeg_path;
            this.video_path = video_path;
            this.mp4_name = mp4_name;
            this.mp4folder_path = mp4folder_path;
        }
        //清除已生成的mp4
        private void clear_mp4(String mp4_path){
            //删除原来已经生成的m3u8及ts文件
            File mp4File = new File(mp4_path);
            if(mp4File.exists() && mp4File.isFile()){
                mp4File.delete();
            }
        }
        /**
         * 视频编码,生成mp4文件
         * @return 成功返回success,失败返回控制台日志
         */
        public String generateMp4(){
            //清除已生成的mp4
            clear_mp4(mp4folder_path+mp4_name);
            /*
            ffmpeg.exe -i  lucene.avi -c:v libx264 -s 1280x720 -pix_fmt yuv420p -b:a 63k -b:v 753k -r 18 .lucene.mp4
             */
            List<String> commend = new ArrayList<String>();
            //commend.add("D:\Program Files\ffmpeg-20180227-fa0c9d6-win64-static\bin\ffmpeg.exe");
            commend.add(ffmpeg_path);
            commend.add("-i");
    //        commend.add("D:\BaiduNetdiskDownload\test1.avi");
            commend.add(video_path);
            commend.add("-c:v");
            commend.add("libx264");
            commend.add("-y");//覆盖输出文件
            commend.add("-s");
            commend.add("1280x720");
            commend.add("-pix_fmt");
            commend.add("yuv420p");
            commend.add("-b:a");
            commend.add("63k");
            commend.add("-b:v");
            commend.add("753k");
            commend.add("-r");
            commend.add("18");
            commend.add(mp4folder_path  + mp4_name );
            String outstring = null;
            try {
                ProcessBuilder builder = new ProcessBuilder();
                builder.command(commend);
                //将标准输入流和错误输入流合并,通过标准输入流程读取信息
                builder.redirectErrorStream(true);
                Process p = builder.start();
                outstring = waitFor(p);
    
            } catch (Exception ex) {
    
                ex.printStackTrace();
    
            }
            Boolean check_video_time = this.check_video_time(video_path, mp4folder_path + mp4_name);
            if(!check_video_time){
                return outstring;
            }else{
                return "success";
            }
        }
    
        public static void main(String[] args) throws IOException {
            String ffmpeg_path = "D:\Program Files\ffmpeg-20180227-fa0c9d6-win64-static\bin\ffmpeg.exe";//ffmpeg的安装位置
            String video_path = "E:\ffmpeg_test\1.avi";
            String mp4_name = "809694a6a974c35e3a36f36850837d7c.mp4";
            String mp4_path = "F:/develop/upload/8/0/809694a6a974c35e3a36f36850837d7c/";
            Mp4VideoUtil videoUtil = new Mp4VideoUtil(ffmpeg_path,video_path,mp4_name,mp4_path);
            String s = videoUtil.generateMp4();
            System.out.println(s);
        }
    }

    HlsVideoUtil

    package com.xuecheng.framework.utils;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 此文件用于视频文件处理,步骤如下:
     * 1、生成mp4
     * 2、生成m3u8
     *
     */
    public class HlsVideoUtil extends  VideoUtil {
    
        String ffmpeg_path = "D:\Program Files\ffmpeg-20180227-fa0c9d6-win64-static\bin\ffmpeg.exe";//ffmpeg的安装位置
        String video_path = "D:\BaiduNetdiskDownload\test1.avi";
        String m3u8_name = "test1.m3u8";
        String m3u8folder_path = "D:/BaiduNetdiskDownload/Movies/test1/";
        public HlsVideoUtil(String ffmpeg_path, String video_path, String m3u8_name,String m3u8folder_path){
            super(ffmpeg_path);
            this.ffmpeg_path = ffmpeg_path;
            this.video_path = video_path;
            this.m3u8_name = m3u8_name;
            this.m3u8folder_path = m3u8folder_path;
        }
    
        private void clear_m3u8(String m3u8_path){
            //删除原来已经生成的m3u8及ts文件
            File m3u8dir = new File(m3u8_path);
            if(!m3u8dir.exists()){
                m3u8dir.mkdirs();
            }
           /* if(m3u8dir.exists()&&m3u8_path.indexOf("/hls/")>=0){//在hls目录方可删除,以免错误删除
                String[] children = m3u8dir.list();
                //删除目录中的文件
                for (int i = 0; i < children.length; i++) {
                    File file = new File(m3u8_path, children[i]);
                    file.delete();
                }
            }else{
                m3u8dir.mkdirs();
            }*/
        }
    
        /**
         * 生成m3u8文件
         * @return 成功则返回success,失败返回控制台日志
         */
        public String generateM3u8(){
            //清理m3u8文件目录
            clear_m3u8(m3u8folder_path);
     /*
            ffmpeg -i  lucene.mp4   -hls_time 10 -hls_list_size 0   -hls_segment_filename ./hls/lucene_%05d.ts ./hls/lucene.m3u8
             */
    //        String m3u8_name = video_name.substring(0, video_name.lastIndexOf("."))+".m3u8";
            List<String> commend = new ArrayList<String>();
            commend.add(ffmpeg_path);
            commend.add("-i");
            commend.add(video_path);
            commend.add("-hls_time");
            commend.add("10");
            commend.add("-hls_list_size");
            commend.add("0");
            commend.add("-hls_segment_filename");
    //        commend.add("D:/BaiduNetdiskDownload/Movies/test1/test1_%05d.ts");
            commend.add(m3u8folder_path  + m3u8_name.substring(0,m3u8_name.lastIndexOf(".")) + "_%05d.ts");
    //        commend.add("D:/BaiduNetdiskDownload/Movies/test1/test1.m3u8");
            commend.add(m3u8folder_path  + m3u8_name );
            String outstring = null;
            try {
                ProcessBuilder builder = new ProcessBuilder();
                builder.command(commend);
                //将标准输入流和错误输入流合并,通过标准输入流程读取信息
                builder.redirectErrorStream(true);
                Process p = builder.start();
                outstring = waitFor(p);
    
            } catch (Exception ex) {
    
                ex.printStackTrace();
    
            }
            //通过查看视频时长判断是否成功
            Boolean check_video_time = check_video_time(video_path, m3u8folder_path + m3u8_name);
            if(!check_video_time){
                return outstring;
            }
            //通过查看m3u8列表判断是否成功
            List<String> ts_list = get_ts_list();
            if(ts_list == null){
                return outstring;
            }
            return "success";
    
    
        }
    
    
    
        /**
         * 检查视频处理是否完成
         * @return ts列表
         */
        public List<String> get_ts_list() {
    //        String m3u8_name = video_name.substring(0, video_name.lastIndexOf("."))+".m3u8";
            List<String> fileList = new ArrayList<String>();
            List<String> tsList = new ArrayList<String>();
            String m3u8file_path =m3u8folder_path + m3u8_name;
            BufferedReader br = null;
            String str = null;
            String bottomline = "";
            try {
                br = new BufferedReader(new FileReader(m3u8file_path));
                while ((str = br.readLine()) != null) {
                    bottomline = str;
                    if(bottomline.endsWith(".ts")){
                        tsList.add(bottomline);
                    }
                    //System.out.println(str);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(br!=null){
                    try {
                        br.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            if (bottomline.contains("#EXT-X-ENDLIST")) {
    //            fileList.add(hls_relativepath+m3u8_name);
                fileList.addAll(tsList);
                return fileList;
            }
            return null;
    
        }
    
    
    
    
        public static void main(String[] args) throws IOException {
            String ffmpeg_path = "D:\Program Files\ffmpeg-20180227-fa0c9d6-win64-static\bin\ffmpeg.exe";//ffmpeg的安装位置
            String video_path = "E:\ffmpeg_test\1.mp4";
            String m3u8_name = "1.m3u8";
            String m3u8_path = "E:\ffmpeg_test\1\";
            HlsVideoUtil videoUtil = new HlsVideoUtil(ffmpeg_path,video_path,m3u8_name,m3u8_path);
            String s = videoUtil.generateM3u8();
            System.out.println(s);
            System.out.println(videoUtil.get_ts_list());
        }
    }

    MediaProcessTask

    package com.xuecheng.manage_media_processor.mq;
    
    import com.alibaba.fastjson.JSON;
    import com.xuecheng.framework.domain.media.MediaFile;
    import com.xuecheng.framework.domain.media.MediaFileProcess_m3u8;
    import com.xuecheng.framework.utils.HlsVideoUtil;
    import com.xuecheng.framework.utils.Mp4VideoUtil;
    import com.xuecheng.manage_media_processor.dao.MediaFileMapper;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    import java.util.Map;
    
    /**
     * Created by Administrator on 2020/6/7 0007.
     */
    @Component
    public class MediaProcessTask {
        @Value("${xc-service-manage-media.ffmpeg-path}")
        String ffmpeg_path;
    
        //上传文件根目录
        @Value("${xc-service-manage-media.video-location}")
        String serverPath;
        @Autowired
        private MediaFileMapper mediaFileMapper;
    
        //接收视频处理消息进行视频处理
        @RabbitListener(queues = "${xc-service-manage-media.mq.queue-media-video-processor}")
        public void receiveMediaProcessTask(String msg ){
            //1.解析消息内容,得到mediaId
            Map map = JSON.parseObject(msg, Map.class);
            String mediaId = (String) map.get("mediaId");
            //2.拿到mediaId从数据库中查询文件信息
            MediaFile mediaFile = mediaFileMapper.findByFileId(mediaId);
            if(null == mediaFile){
                return;
            }
            //文件类型
            String fileType = mediaFile.getFileType();
            if(!fileType.equals("avi")){
                mediaFile.setProcessStatus("303004");//无需处理
                mediaFileMapper.save(mediaFile);
                return ;
            }else{
                //需要处理
                mediaFile.setProcessStatus("303001");//处理中
                mediaFileMapper.save(mediaFile);
            }
            //3.使用工具类将avi文件生成mp4
            //String ffmpeg_path, String video_path, String mp4_name, String mp4folder_path
            //要处理的视频文件的路径
            String video_path = serverPath + mediaFile.getFilePath() + mediaFile.getFileName();
            //生成的mp4的文件名称
            String mp4_name = mediaFile.getFileId() + ".mp4";
            //生成的mp4所在的路径
            String mp4folder_path = serverPath + mediaFile.getFilePath();
            Mp4VideoUtil mp4VideoUtil = new Mp4VideoUtil(ffmpeg_path,video_path,mp4_name,mp4folder_path);
            //进行处理
            String result = mp4VideoUtil.generateMp4();
            if(result == null || !result.equals("success")){
                //处理失败
                mediaFile.setProcessStatus("303003");
                //定义mediaFileProcess_m3u8
                MediaFileProcess_m3u8 mediaFileProcess_m3u8 = new MediaFileProcess_m3u8();
                //记录失败原因
                mediaFileProcess_m3u8.setErrormsg(result);
                mediaFile.setMediaFileProcess_m3u8(mediaFileProcess_m3u8);
                mediaFileMapper.save(mediaFile);
                return ;
            }
            //4.将mp4生成m3u8和ts文件
            //String ffmpeg_path, String video_path, String m3u8_name,String m3u8folder_path
            //mp4视频文件路径
            String mp4_video_path = serverPath + mediaFile.getFilePath() + mp4_name;
            //m3u8_name文件名称
            String m3u8_name = mediaFile.getFileId() +".m3u8";
            //m3u8文件所在目录
            String m3u8folder_path = serverPath + mediaFile.getFilePath() + "hls/";
            HlsVideoUtil hlsVideoUtil = new HlsVideoUtil(ffmpeg_path,mp4_video_path,m3u8_name,m3u8folder_path);
            //生成m3u8和ts文件
            String tsResult = hlsVideoUtil.generateM3u8();
            if(tsResult == null || !tsResult.equals("success")){
                //处理失败
                mediaFile.setProcessStatus("303003");
                //定义mediaFileProcess_m3u8
                MediaFileProcess_m3u8 mediaFileProcess_m3u8 = new MediaFileProcess_m3u8();
                //记录失败原因
                mediaFileProcess_m3u8.setErrormsg(result);
                mediaFile.setMediaFileProcess_m3u8(mediaFileProcess_m3u8);
                mediaFileMapper.save(mediaFile);
                return ;
            }
            //处理成功
            //获取ts文件列表
            List<String> ts_list = hlsVideoUtil.get_ts_list();
    
            mediaFile.setProcessStatus("303002");
            //定义mediaFileProcess_m3u8
            MediaFileProcess_m3u8 mediaFileProcess_m3u8 = new MediaFileProcess_m3u8();
            mediaFileProcess_m3u8.setTslist(ts_list);
            mediaFile.setMediaFileProcess_m3u8(mediaFileProcess_m3u8);
    
            //保存fileUrl(此url就是视频播放的相对路径)
            String fileUrl =mediaFile.getFilePath() + "hls/"+m3u8_name;
            mediaFile.setFileUrl(fileUrl);
            mediaFileMapper.save(mediaFile);
        }
    }
  • 相关阅读:
    “sockaddr”: “struct”类型重定义的错误的解决办法《转》
    2019年车险
    tinylib
    命令行利用ffmpeg实现rtmp推流《转》
    Inno setup 判断系统32位还是64位
    vs2015编译OBS-Studio21.1.12
    啃OBS源码-界面汉字
    百年孤独人物关系1
    windows命令行查看文件MD5
    python 玩爬虫安装了一大堆第三方库
  • 原文地址:https://www.cnblogs.com/bao-bei/p/13059667.html
Copyright © 2011-2022 走看看