【Java实战篇】Day5.在线教育网课平台

文章目录

  • 需求: 视频处理
  • 1、知识背景
    • 1.1 文件格式与编码格式
    • 1.2 FFmpeg
    • 1.3 视频处理工具类
  • 2、分布式任务处理
    • 2.1 分布式任务调度
    • 2.2 XXL-JOB
    • 2.3 搭建XXL-Job
    • 2.4 分片广播

需求: 视频处理

视频上传成功需要对视频的格式进行转码处理,比如:avi转成mp

1、知识背景

1.1 文件格式与编码格式

视频文件的内容主要包括视频和音频,其文件格式是按照一 定的编码格式去编码,并且按照该文件所规定的封装格式将视频、音频、字幕等信息封装在一起,播放器会根据它们的封装格式去提取出编码,然后由播放器解码,最终播放音视频。

  • .mp4、.avi、.rmvb等 这些视频文件的不同扩展名, 称为文件格式
  • 编码格式: 通过音视频的压缩技术,将视频格式转换成另一种视频格式,通过视频编码实现流媒体的传输。比如:一个.avi的视频文件原来的编码是a,通过编码后编码格式变为b,音频原来为c,通过编码后变为d

音视频编码格式种类繁多, 目前最常用的编码标准是视频H.264,音频AAC。

1.2 FFmpeg

下载地址:
https://www.ffmpeg.org/download.html#build-windows

下载后解压ffmpeg.zip, 在.exe文件的目录下打开cmd窗口, 运行 ffmpeg -v
【Java实战篇】Day5.在线教育网课平台_第1张图片
以上即安装成功

//对1.avi文件进行转码:
//先把avi转mp4
D:\soft\ffmpeg\ffmpeg.exe -i 1.avi 1.mp4
//转mp3
ffmpeg -i 1.avi 1.mp3
//转gif
ffmpeg -i 1.avi 1.gif

1.3 视频处理工具类

要通过ffmpeg对视频转码,得用Java程序去启动ffmpeg,使用java.lang.ProcessBuilder去完成

//这里以启动QQ为例
ProcessBuilder builder = new ProcessBuilder();
builder.command("C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQScLauncher.exe");
//将标准输入流和错误输入流合并,通过标准输入流程读取信息
builder.redirectErrorStream(true);
Process p = builder.start();

对视频的转码, 直接使用工具类:

Java
public static void main(String[] args) throws IOException {
    //ffmpeg的路径
    String ffmpeg_path = "D:\\soft\\ffmpeg\\ffmpeg.exe";//ffmpeg的安装位置
    //源avi视频的路径
    String video_path = "D:\\develop\\bigfile_test\\nacos01.avi";
    //转换后mp4文件的名称
    String mp4_name = "nacos01.mp4";
    //转换后mp4文件的路径
    String mp4_path = "D:\\develop\\bigfile_test\\nacos01.mp4";
    //创建工具类对象
    Mp4VideoUtil videoUtil = new Mp4VideoUtil(ffmpeg_path,video_path,mp4_name,mp4_path);
    //开始视频转换,成功将返回success
    //videoUtil工具类的generateMp4方法封装了对ffmpeg的启动以及转码所用到的语句
    String s = videoUtil.generateMp4();
    System.out.println(s);
}

generateMp4方法源代码如下:

public String generateMp4(){
        //清除已生成的mp4
//        clear_mp4(mp4folder_path+mp4_name);
        clear_mp4(mp4folder_path);
        /*
        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 );
        commend.add(mp4folder_path  );
        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);
        Boolean check_video_time = this.check_video_time(video_path, mp4folder_path);
        if(!check_video_time){
            return outstring;
        }else{
            return "success";
        }
    }
 

2、分布式任务处理

2.1 分布式任务调度

想高效的去处理一批任务,有以下两种思路:

  • 多线程:充分利用单机资源
  • 分布式加多线程:充分利用多台计算机,每台计算机使用多线程处理

关于任务调度,思考以下场景:

  • 每隔24小时执行数据备份任务
  • 12306网站会根据车次不同,设置几个时间点分批次放票
  • 某财务系统需要在每天上午10点前结算前一天的账单数据,统计汇总
  • 商品成功发货后,需要向客户发送短信提醒

以上场景的实现思路有:

思路一:线程休眠

public static void main(String[] args) {    
    //任务执行间隔时间
    final long timeInterval = 1000;
    Runnable runnable = new Runnable() {
        public void run() {
            while (true) {
                //TODO:something
                try {
                    Thread.sleep(timeInterval);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    Thread thread = new Thread(runnable);
    thread.start();
}

思路2:Timer

Jdk也提供了相关支持,如Timer、ScheduledExecutor

public static void main(String[] args){  
    Timer timer = new Timer();  
    timer.schedule(new TimerTask(){
        @Override  
        public void run() {  
           //TODO:something
        }  
    }, 1000, 2000);  //1秒后开始调度,每2秒执行一次
}

每个Timer对应一个线程,因此可以同时启动多个Timer并行执行多个任务,同一个Timer中的任务是串行执行

思路3:ScheduledExecutor

基于线程池设计的 ScheduledExecutor,每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰

public static void main(String [] agrs){
    ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
    service.scheduleAtFixedRate(
            new Runnable() {
                @Override
                public void run() {
                    //TODO:something
                    System.out.println("todo something");
                }
            }, 1,
            2, TimeUnit.SECONDS);
}

以上三种能完成简单的任务,如给定开始时间与重复间隔,重复执行某任务,但比较复杂的实现不了,如:设置每月第一天凌晨1点执行任务、复杂调度任务的管理、任务间传递数据等等

任务的调度,即指系统为了完成特定业务,基于给定时间点,给定时间间隔或者给定执行次数,去自动执行任务

【Java实战篇】Day5.在线教育网课平台_第2张图片
而分布式任务调度,即多台计算机共同去完成任务调度。从而可以:

  • 突破单机多线程的瓶颈,并行任务调度
  • 高可用
  • 弹性扩容

此外,需要注意任务管理与监测,以及防止任务被重复执行。

2.2 XXL-JOB

XXL-JOB是一个分布式任务调度平台,主要有调度中心和执行器。官网:https://www.xuxueli.com/xxl-job/
【Java实战篇】Day5.在线教育网课平台_第3张图片

调度中心和执行器之间的工作流程:

【Java实战篇】Day5.在线教育网课平台_第4张图片

  • 任务执行器根据配置的调度中心的地址,自动注册到调度中心
  • 当达到任务的触发条件时,调度中心下发任务给任务执行器
  • 执行器基于线程池执行任务,并把执行结果放入内存队列中、把执行日志写入日志文件中
  • 执行器消费内存队列中的执行结果,主动上报给调度中心
  • 当用户在调度中心查看任务日志,调度中心请求任务执行器,任务执行器读取任务日志文件并返回日志详情

2.3 搭建XXL-Job

调度中心部分

  • 下载源码解压并用IDEA打开项目
GitHub:https://github.com/xuxueli/xxl-job
码云:https://gitee.com/xuxueli0323/xxl-job
eg: https://github.com/xuxueli/xxl-job/releases/tag/2.3.1
  • 项目代码结构介绍
    【Java实战篇】Day5.在线教育网课平台_第5张图片
xxl-job-admin:调度中心
xxl-job-core:公共依赖
xxl-job-executor-samples:执行器Sample示例(选择合适的版本执行器,可直接使用)
    :xxl-job-executor-sample-springboot:Springboot版本,通过Springboot管理执行器,推荐这种方式;
    :xxl-job-executor-sample-frameless:无框架版本;
doc :文档资料,包含数据库脚本

  • 执行doc文件中的SQL脚本,创建数据库表
    【Java实战篇】Day5.在线教育网课平台_第6张图片

  • 启动调度中心

虚拟机执行:sh /data/soft/restart.sh自动启动xxl-job调度中心
访问:http://localhost:8088/xxl-job-admin/
账号和密码:admin/123456

也可直接在IDEA中启动xxl-job-admin模块

【Java实战篇】Day5.在线教育网课平台_第7张图片

执行器部分

  • 进入调度中心,添加执行器
    【Java实战篇】Day5.在线教育网课平台_第8张图片
  • 填写执行器信息,appname是前边在nacos中配置xxl信息时指定的执行器的应用名
    【Java实战篇】Day5.在线教育网课平台_第9张图片
  • 在需要跑定时任务的模块加入依赖,在项目的父工程已约定了版本2.3.1
<dependency>
    <groupId>com.xuxueligroupId>
    <artifactId>xxl-job-coreartifactId>
dependency>

  • 在nacos下对应服务的xxx-service-dev.yaml下配置xxl-job
xxl:
  job:
    admin: 
      # 调度中心地址
      addresses: http://localhost:8088/xxl-job-admin
    executor:
      # 创建执行器时的appname
      appname: media-process-service
      address: 
      ip: 
      # port是执行器启动的端口,如果本地启动多个执行器注意端口不能重复
      port: 9999
      logpath: /data/applogs/xxl-job/jobhandler
      logretentiondays: 30
    accessToken: default_token

  • 将xxl-job配置类拷贝到相应的工程目录下
    【Java实战篇】Day5.在线教育网课平台_第10张图片

执行任务

  • 在xxxservice包下新建jobhandler存放任务类
/**
 * @description 测试执行器
 */
 @Component
 @Slf4j
public class SampleJob {

 /**
  * 1、简单任务示例(Bean模式)
  */
 @XxlJob("testJob")
 public void testJob() throws Exception {
  //这里写调度任务的实现代码
  log.info("开始执行.....");

 }

}

  • 在调度中心选择执行器后,点击添加任务,进入任务管理
    【Java实战篇】Day5.在线教育网课平台_第11张图片
  • 填写任务信息
    【Java实战篇】Day5.在线教育网课平台_第12张图片

调度类型:

- 固定速度:指按固定的间隔定时调度。
- Cron:通过Cron表达式实现更丰富的定时调度策略。

cron表达式的格式为:{秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}

举例:

30 10 1 * * ?  每天11030秒触发
0/30 * * * * ?30秒触发一次
* 0/10 * * * ?10分钟触发一次

【Java实战篇】Day5.在线教育网课平台_第13张图片

运行模式

- BEAN:bean模式在项目工程中编写执行器的任务代码
- GLUE:GLUE是将任务代码编写在调度中心

JobHandler即任务方法名,填写任务方法上边@XxlJob注解中的名称

  • 信息填写完成后点击启动
    【Java实战篇】Day5.在线教育网课平台_第14张图片
  • 最后,可停止任务、手动执行一次任务、清理日志
    【Java实战篇】Day5.在线教育网课平台_第15张图片
    【Java实战篇】Day5.在线教育网课平台_第16张图片

2.4 分片广播

你可能感兴趣的:(Spring,java,ffmpeg,音视频)