├── .gitignore
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── org
│ └── mountcloud
│ └── ffmepg
│ ├── annotation
│ ├── FFAnnotation.java
│ ├── FFCmd.java
│ └── FFCmdBean.java
│ ├── excption
│ ├── FFMpegOperationConvertExcption.java
│ └── FFMpegOperationNotFoundExcption.java
│ ├── operation
│ ├── FFOperationBase.java
│ └── ffmpeg
│ │ ├── FFMpegOperationBase.java
│ │ └── vidoe
│ │ ├── FFMpegVideoFormatM3u8.java
│ │ ├── FFMpegVideoInfo.java
│ │ └── FFMpegVideoScreenShot.java
│ ├── result
│ ├── FFResult.java
│ └── defaultResult
│ │ ├── FFDefaultResult.java
│ │ └── FFVideoInfoResult.java
│ ├── task
│ ├── bean
│ │ ├── FFTask.java
│ │ ├── FFTaskProgress.java
│ │ ├── FFTaskStateEnum.java
│ │ ├── FFVideoTask.java
│ │ ├── read
│ │ │ ├── FFTaskReadState.java
│ │ │ ├── FFTaskReadThread.java
│ │ │ └── FFTaskReadType.java
│ │ └── tasks
│ │ │ ├── FFMepgVideoFormatM3u8Task.java
│ │ │ ├── FFMepgVideoInfoTask.java
│ │ │ └── FFMpegVideoScreenShotTask.java
│ ├── context
│ │ └── FFTaskContext.java
│ └── threads
│ │ ├── FFThread.java
│ │ └── FFThreadManager.java
│ └── util
│ ├── FFAnnotationUtil.java
│ ├── FFBigDecimalUtil.java
│ ├── FFTerminalCreater.java
│ ├── FFVideoUtil.java
│ ├── OSUtils.java
│ ├── ObjectUtil.java
│ ├── StringUtil.java
│ └── UUIDUtil.java
└── test
└── java
└── org
└── mountcloud
└── ffmpeg
└── TestTask.java
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | bin/*
3 | !.mvn/wrapper/maven-wrapper.jar
4 | .swp
5 | .DS_Store
6 | ### STS ###
7 | .apt_generated
8 | .classpath
9 | .factorypath
10 | .project
11 | .settings
12 | .springBeans
13 | bootstrap.yml
14 |
15 | ### IntelliJ IDEA ###
16 | .idea
17 | *.iws
18 | *.iml
19 | *.ipr
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # USE 使用
2 |
3 |
4 | org.mountcloud
5 | ffmpeg-operate
6 | 1.2
7 |
8 |
9 | # English
10 |
11 | ## Description
12 | The prerequisite for this project is that FFMPEG is installed in the environment and FFMPEG commands can be used in the console. This project is very convenient for java to use FFMPEG function.
13 |
14 | There are 3 built-in video operations in the project, 1: video format is changed to M3U8 (FFMpegVideoFormatM3u8), 2: view video attribute (FFMpegVideoInfo), 3: video screenshot (FFMpegVideoScreenShot). It can also be extended by inheriting FFMpegOperationBase.
15 |
16 | ## Features
17 | 1: You can get the execution percentage progress of the task.
18 |
19 | 2: Very high scalability.
20 |
21 | 3: Multi-threaded mode of operation.
22 |
23 | 4: Tasks can be performed synchronously or asynchronously.
24 |
25 | # 中文
26 |
27 | ## 描述
28 |
29 | 这个项目使用的前提条件是环境中安装了FFMPEG,并且可以在控制台中使用FFMPEG命令。本项目极大方便了java使用FFMPEG功能。
30 |
31 | 项目中内置了3个对视频的操作,1:视频格式转为M3U8(FFMpegVideoFormatM3u8),2:查看视频属性(FFMpegVideoInfo),3:视频截图(FFMpegVideoScreenShot)。还可以通过继承FFMpegOperationBase来进行扩展。
32 |
33 | ## 特点
34 |
35 | 1:可以获取任务的执行百分比进度。
36 |
37 | 2:非常高的可扩展性。
38 |
39 | 3:多线程方式进行操作。
40 |
41 | 4:可同步或异步执行。
42 |
43 |
44 | # Demo 用例
45 |
46 |
47 | @Test
48 | public void convertM3u8() {
49 |
50 | //create result bean
51 | FFVideoInfoResult result = new FFVideoInfoResult();
52 |
53 | //find video info
54 | FFMpegVideoInfo ffMpegVideoInfo = new FFMpegVideoInfo();
55 | ffMpegVideoInfo.setVideoUrl("D:\\cma_15307640036trzll1p.mp4");
56 | FFMepgVideoInfoTask videoInfoTask = new FFMepgVideoInfoTask(result,ffMpegVideoInfo);
57 |
58 | FFTaskContext.getContext().submit(videoInfoTask,null);
59 |
60 | String bitrate = "5286k";
61 |
62 | //create to m3u8 operation
63 | FFMpegVideoFormatM3u8 m3u8Operation = new FFMpegVideoFormatM3u8();
64 | m3u8Operation.setVideoFileName("D:\\cma_15307640036trzll1p.mp4");
65 | m3u8Operation.setBitrate(bitrate);
66 | m3u8Operation.setTimes(5);
67 | m3u8Operation.setM3u8File("D:\\cma_15307640036trzll1p\\cma_15307640036trzll1p.m3u8");
68 | m3u8Operation.setTsFiles("D:\\cma_15307640036trzll1p\\cma_15307640036trzll1p%5d.ts");
69 |
70 | //to m3u8 task
71 | FFMepgVideoFormatM3u8Task task = new FFMepgVideoFormatM3u8Task(m3u8Operation);
72 |
73 | //add task
74 | FFTaskContext.getContext().addTask(task);
75 |
76 | while(!task.getProgress().getState().equals(FFTaskStateEnum.COMPLETE)){
77 | try {
78 | Thread.sleep(2000);
79 | } catch (InterruptedException e) {
80 | }
81 | }
82 |
83 | System.out.println("COMPLETE");
84 |
85 | }
86 |
87 | ## note 笔记
88 | 1: FFTaskContext.getContext().addTask(task) is an asynchronous task, FFTaskContext.getContext().submit(taks) is a synchronous task.
89 |
90 | 1:FFTaskContext.getContext().addTask(task) 为异步任务,FFTaskContext.getContext().submit(taks)为同步任务
91 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | 4.0.0
6 |
7 | org.mountcloud
8 | ffmpeg-operate
9 | 1.2
10 |
11 | A FFmpeg Java Operate
12 |
13 |
14 | jar
15 |
16 |
17 |
18 |
19 | The Apache Software License, Version 2.0
20 | http://www.apache.org/licenses/LICENSE-2.0.txt
21 |
22 |
23 |
24 |
25 | ${project.groupId}:${project.artifactId}
26 |
27 | https://github.com/MountCloud/ffmpeg-operate
28 |
29 |
30 |
31 |
32 |
33 | zhanghaishan
34 | moutcloud@outlook.com
35 |
36 |
37 |
38 |
39 |
40 | scm:git:git@github.com:MountCloud/ffmpeg-operate.git
41 | scm:git:git@github.com:MountCloud/ffmpeg-operate.git
42 | git@github.com:MountCloud/ffmpeg-operate.git
43 |
44 |
45 |
46 | UTF-8
47 | UTF-8
48 | 1.8
49 | 1.8
50 |
51 |
52 |
53 |
54 |
55 | junit
56 | junit
57 | 4.12
58 |
59 | test
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | release
68 |
69 |
70 |
71 |
72 | org.apache.maven.plugins
73 | maven-source-plugin
74 | 2.2.1
75 |
76 |
77 | package
78 |
79 | jar-no-fork
80 |
81 |
82 |
83 |
84 |
85 |
86 | org.apache.maven.plugins
87 | maven-javadoc-plugin
88 | 2.9.1
89 |
90 |
91 | package
92 |
93 | jar
94 |
95 |
96 |
97 |
98 |
99 |
100 | org.apache.maven.plugins
101 | maven-gpg-plugin
102 | 1.5
103 |
104 |
105 | verify
106 |
107 | sign
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | mountoss
117 | https://oss.sonatype.org/content/repositories/snapshots/
118 |
119 |
120 | mountoss
121 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | org.apache.maven.plugins
132 | maven-compiler-plugin
133 |
134 | 1.8
135 | 1.8
136 |
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/annotation/FFAnnotation.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.annotation;
2 |
3 | /**
4 | * ffmpeg的注解,用于注解属性
5 | * com.ugirls.ffmepg.annotation
6 | * 2018/6/6.
7 | *
8 | * @author zhanghaishan
9 | * @version V1.0
10 | */
11 | public class FFAnnotation{
12 |
13 | /**
14 | * 注解的key
15 | */
16 | private String key;
17 |
18 | /**
19 | * 注解的值
20 | */
21 | private String value;
22 |
23 | public String getKey() {
24 | return key;
25 | }
26 |
27 | public void setKey(String key) {
28 | this.key = key;
29 | }
30 |
31 | public String getValue() {
32 | return value;
33 | }
34 |
35 | public void setValue(String value) {
36 | this.value = value;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/annotation/FFCmd.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * 命令注解,用于注解类
7 | * com.ugirls.ffmepg.annotation
8 | * 2018/6/6.
9 | *
10 | * @author zhanghaishan
11 | * @version V1.0
12 | */
13 | @Target({ElementType.FIELD,ElementType.TYPE})
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Documented
16 | public @interface FFCmd {
17 |
18 | /**
19 | * 命令的key
20 | * @return 命令Key
21 | */
22 | public String key() default "";
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/annotation/FFCmdBean.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.annotation;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * 命令的父类
7 | * com.ugirls.ffmepg.annotation
8 | * 2018/6/6.
9 | *
10 | * @author zhanghaishan
11 | * @version V1.0
12 | */
13 | public class FFCmdBean {
14 |
15 | private FFAnnotation cmdName;
16 |
17 | private List cmdParameter;
18 |
19 | public FFAnnotation getCmdName() {
20 | return cmdName;
21 | }
22 |
23 | public void setCmdName(FFAnnotation cmdName) {
24 | this.cmdName = cmdName;
25 | }
26 |
27 | public List getCmdParameter() {
28 | return cmdParameter;
29 | }
30 |
31 | public void setCmdParameter(List cmdParameter) {
32 | this.cmdParameter = cmdParameter;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/excption/FFMpegOperationConvertExcption.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.excption;
2 |
3 | /**
4 | * 操作转换异常
5 | * org.mountcloud.ffmepg.excption
6 | * 2018/11/29.
7 | *
8 | * @author zhanghaishan
9 | * @version V1.0
10 | */
11 | public class FFMpegOperationConvertExcption extends RuntimeException{
12 |
13 | public FFMpegOperationConvertExcption(String ex){
14 | super(ex);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/excption/FFMpegOperationNotFoundExcption.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.excption;
2 |
3 | /**
4 | * 未找到异常
5 | * org.mountcloud.ffmepg.excption
6 | * 2018/11/29.
7 | *
8 | * @author zhanghaishan
9 | * @version V1.0
10 | */
11 | public class FFMpegOperationNotFoundExcption extends RuntimeException {
12 | public FFMpegOperationNotFoundExcption(String ex){
13 | super(ex);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/operation/FFOperationBase.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.operation;
2 |
3 |
4 | import org.mountcloud.ffmepg.annotation.FFAnnotation;
5 | import org.mountcloud.ffmepg.annotation.FFCmdBean;
6 | import org.mountcloud.ffmepg.excption.FFMpegOperationConvertExcption;
7 | import org.mountcloud.ffmepg.util.FFAnnotationUtil;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | /**
13 | * TODO:
14 | * com.ugirls.ffmepg.operation
15 | * 2018/6/6.
16 | *
17 | * @author zhanghaishan
18 | * @version V1.0
19 | */
20 | public abstract class FFOperationBase {
21 |
22 | private String stringvalue = null;
23 | private String command = null;
24 | private List commandParams = new ArrayList<>();
25 |
26 | /**
27 | * 返回命令
28 | * @return 命令
29 | */
30 | public String getCommand(){
31 | if(command == null){
32 | command = toString();
33 | }
34 | return command;
35 | }
36 |
37 | /**
38 | * 返回命令参数
39 | * @return 参数
40 | */
41 | public List getCommandParams(){
42 | if(commandParams.size()==0){
43 | toString();
44 | }
45 | return commandParams;
46 | }
47 |
48 |
49 | /**
50 | * 直接转成命令
51 | * @return 命令
52 | */
53 | @Override
54 | public String toString() {
55 |
56 | String str = null;
57 | FFAnnotationUtil ffAnnotationUtil = new FFAnnotationUtil();
58 | try {
59 | FFCmdBean cmdBean = ffAnnotationUtil.getClassAnnocation(this);
60 | String execname = command = cmdBean.getCmdName().getKey();
61 | List list = cmdBean.getCmdParameter();
62 |
63 | str = execname;
64 |
65 | for(int i=0;i0&&aValue!=null){
71 | str = str +" "+aKey;
72 | commandParams.add(aKey);
73 | }
74 |
75 | if(aValue!=null&&aValue.length()>0){
76 | str = str +" "+aValue;
77 | commandParams.add(aValue);
78 | }
79 | }
80 |
81 | } catch (IllegalAccessException e) {
82 | str = null;
83 | }
84 | if(str==null){
85 | throw new FFMpegOperationConvertExcption("FFMpegOperation To String Is Null!");
86 | }
87 |
88 | stringvalue = str;
89 |
90 | return stringvalue;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/operation/ffmpeg/FFMpegOperationBase.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.operation.ffmpeg;
2 |
3 | import org.mountcloud.ffmepg.annotation.FFCmd;
4 | import org.mountcloud.ffmepg.operation.FFOperationBase;
5 |
6 | /**
7 | * TODO: ffmepg命令处理抽象父类
8 | * com.ugirls.ffmepg.operation.ffmpeg
9 | * 2018/6/6.
10 | *
11 | * @author zhanghaishan
12 | * @version V1.0
13 | */
14 | @FFCmd(key = "ffmpeg")
15 | public abstract class FFMpegOperationBase extends FFOperationBase {
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/operation/ffmpeg/vidoe/FFMpegVideoFormatM3u8.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.operation.ffmpeg.vidoe;
2 |
3 |
4 | import org.mountcloud.ffmepg.annotation.FFCmd;
5 | import org.mountcloud.ffmepg.operation.ffmpeg.FFMpegOperationBase;
6 |
7 | /**
8 | * 视频转码操作 com.ugirls.ffmepg.operation.ffmpeg.vidoe 2018/6/6.
9 | *
10 | * @author zhanghaishan
11 | * @version V1.0
12 | */
13 | public class FFMpegVideoFormatM3u8 extends FFMpegOperationBase {
14 |
15 | /**
16 | * type
17 | */
18 | @FFCmd(key = "-re")
19 | private String type = "";
20 |
21 | /**
22 | * 视频文件
23 | */
24 | @FFCmd(key = "-i")
25 | private String videoFileName;
26 |
27 | /**
28 | * vcodec
29 | */
30 | @FFCmd(key = "-vcodec")
31 | private String vcodec = "libx264";
32 |
33 | /**
34 | * acodec
35 | */
36 | @FFCmd(key = "-acodec")
37 | private String acodec = "copy";
38 |
39 | /**
40 | * 分辨率大小 1366x768
41 | */
42 | @FFCmd(key = "-s")
43 | private String size;
44 |
45 | /**
46 | * 比特率
47 | */
48 | @FFCmd(key = "-b:v")
49 | private String bitrate;
50 |
51 | @FFCmd(key = "-force_key_frames")
52 | private String forceKeyFrames;
53 |
54 | @FFCmd(key = "-f")
55 | private String formate = "segment";
56 |
57 | @FFCmd(key = "-segment_list_type")
58 | private String listType = "m3u8";
59 |
60 | @FFCmd(key = "-segment_list_size")
61 | private String listSize = "0";
62 |
63 | @FFCmd(key = "-segment_time")
64 | private String time;
65 |
66 | @FFCmd(key = "-segment_time_delta")
67 | private String timeDelta = "0.1";
68 |
69 | @FFCmd(key = "-segment_list")
70 | private String m3u8File;
71 |
72 | @FFCmd
73 | private String tsFiles;
74 |
75 | public void setTimes(Integer time) {
76 | //this.forceKeyFrames = "\"expr:gte(t,n_forced*" + time + ")\"";
77 | this.time = String.valueOf(Double.parseDouble(time.toString()));
78 | }
79 |
80 | public String getType() {
81 | return type;
82 | }
83 |
84 | public void setType(String type) {
85 | this.type = type;
86 | }
87 |
88 | public String getVideoFileName() {
89 | return videoFileName;
90 | }
91 |
92 | public void setVideoFileName(String videoFileName) {
93 | this.videoFileName = videoFileName;
94 | }
95 |
96 | public String getVcodec() {
97 | return vcodec;
98 | }
99 |
100 | public void setVcodec(String vcodec) {
101 | this.vcodec = vcodec;
102 | }
103 |
104 | public String getAcodec() {
105 | return acodec;
106 | }
107 |
108 | public void setAcodec(String acodec) {
109 | this.acodec = acodec;
110 | }
111 |
112 | public String getSize() {
113 | return size;
114 | }
115 |
116 | public void setSize(String size) {
117 | this.size = size;
118 | }
119 |
120 | public String getBitrate() {
121 | return bitrate;
122 | }
123 |
124 | public void setBitrate(String bitrate) {
125 | this.bitrate = bitrate;
126 | }
127 |
128 | public String getForceKeyFrames() {
129 | return forceKeyFrames;
130 | }
131 |
132 | public void setForceKeyFrames(String forceKeyFrames) {
133 | this.forceKeyFrames = forceKeyFrames;
134 | }
135 |
136 | public String getFormate() {
137 | return formate;
138 | }
139 |
140 | public void setFormate(String formate) {
141 | this.formate = formate;
142 | }
143 |
144 | public String getListType() {
145 | return listType;
146 | }
147 |
148 | public void setListType(String listType) {
149 | this.listType = listType;
150 | }
151 |
152 | public String getListSize() {
153 | return listSize;
154 | }
155 |
156 | public void setListSize(String listSize) {
157 | this.listSize = listSize;
158 | }
159 |
160 | public String getTime() {
161 | return time;
162 | }
163 |
164 | public void setTime(String time) {
165 | this.time = time;
166 | }
167 |
168 | public String getTimeDelta() {
169 | return timeDelta;
170 | }
171 |
172 | public void setTimeDelta(String timeDelta) {
173 | this.timeDelta = timeDelta;
174 | }
175 |
176 | public String getM3u8File() {
177 | return m3u8File;
178 | }
179 |
180 | public void setM3u8File(String m3u8File) {
181 | this.m3u8File = m3u8File;
182 | }
183 |
184 | public String getTsFiles() {
185 | return tsFiles;
186 | }
187 |
188 | public void setTsFiles(String tsFiles) {
189 | this.tsFiles = tsFiles;
190 | }
191 | }
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/operation/ffmpeg/vidoe/FFMpegVideoInfo.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.operation.ffmpeg.vidoe;
2 |
3 | import org.mountcloud.ffmepg.annotation.FFCmd;
4 | import org.mountcloud.ffmepg.operation.ffmpeg.FFMpegOperationBase;
5 |
6 | /**
7 | * FFmpeg操作父类
8 | * com.ugirls.ffmepg.operation.ffmpeg.vidoe
9 | * 2018/6/11.
10 | *
11 | * @author zhanghaishan
12 | * @version V1.0
13 | */
14 | public class FFMpegVideoInfo extends FFMpegOperationBase {
15 |
16 | @FFCmd(key = "-i")
17 | private String videoUrl;
18 |
19 | public String getVideoUrl() {
20 | return videoUrl;
21 | }
22 |
23 | public void setVideoUrl(String videoUrl) {
24 | this.videoUrl = videoUrl;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/operation/ffmpeg/vidoe/FFMpegVideoScreenShot.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.operation.ffmpeg.vidoe;
2 |
3 |
4 | import org.mountcloud.ffmepg.annotation.FFCmd;
5 | import org.mountcloud.ffmepg.operation.ffmpeg.FFMpegOperationBase;
6 |
7 | /**
8 | * 视频截图操作
9 | * com.ugirls.ffmepg.operation.ffmpeg.vidoe
10 | * 2018/6/6.
11 | *
12 | * @author zhanghaishan
13 | * @version V1.0
14 | */
15 | public class FFMpegVideoScreenShot extends FFMpegOperationBase {
16 |
17 | /**
18 | * 视频截图操作
19 | * @param video 视频地址
20 | * @param startTime 截图开始时间
21 | * @param vframes 帧数
22 | * @param image 输出文件路径
23 | */
24 | public FFMpegVideoScreenShot(String video,String startTime, String vframes, String image) {
25 | this.video = video;
26 | this.startTime = startTime;
27 | this.vframes = vframes;
28 | this.image = image;
29 | }
30 |
31 | /**
32 | * 输入的视频文件
33 | */
34 | @FFCmd(key = "-i")
35 | private String video;
36 |
37 | /**
38 | * 输出的图片是否覆盖形式生成,如果为空则不添加该key
39 | */
40 | @FFCmd(key = "-y")
41 | private String isOverWrite = "";
42 |
43 | /**
44 | * 图片输出的格式 默认 image2
45 | */
46 | @FFCmd(key = "-f")
47 | private String imageFormat = "image2";
48 |
49 | /**
50 | * 开始时间秒
51 | */
52 | @FFCmd(key = "-ss")
53 | private String startTime;
54 |
55 | /**
56 | * 时间
57 | */
58 | @FFCmd(key = "-t")
59 | private String time;
60 |
61 | /**
62 | * 帧数
63 | */
64 | @FFCmd(key = "-vframes")
65 | private String vframes;
66 |
67 | /**
68 | * 截图的分辨率大小 例如:1020x960
69 | */
70 | @FFCmd(key = "-s")
71 | private String size;
72 |
73 | /**
74 | * 输出文件
75 | */
76 | @FFCmd
77 | private String image;
78 |
79 | public String getVideo() {
80 | return video;
81 | }
82 |
83 | public void setVideo(String video) {
84 | this.video = video;
85 | }
86 |
87 | public String getIsOverWrite() {
88 | return isOverWrite;
89 | }
90 |
91 | public void setIsOverWrite(String isOverWrite) {
92 | this.isOverWrite = isOverWrite;
93 | }
94 |
95 | public String getImageFormat() {
96 | return imageFormat;
97 | }
98 |
99 | public void setImageFormat(String imageFormat) {
100 | this.imageFormat = imageFormat;
101 | }
102 |
103 | public String getTime() {
104 | return time;
105 | }
106 |
107 | public void setTime(String time) {
108 | this.time = time;
109 | }
110 |
111 | public String getVframes() {
112 | return vframes;
113 | }
114 |
115 | public void setVframes(String vframes) {
116 | this.vframes = vframes;
117 | }
118 |
119 | public String getSize() {
120 | return size;
121 | }
122 |
123 | public void setSize(String size) {
124 | this.size = size;
125 | }
126 |
127 | public String getImage() {
128 | return image;
129 | }
130 |
131 | public void setImage(String image) {
132 | this.image = image;
133 | }
134 |
135 | public String getStartTime() {
136 | return startTime;
137 | }
138 |
139 | public void setStartTime(String startTime) {
140 | this.startTime = startTime;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/result/FFResult.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.result;
2 |
3 | /**
4 | * FFMpeg结果
5 | * com.ugirls.ffmepg.result
6 | * 2018/6/7.
7 | *
8 | * @author zhanghaishan
9 | * @version V1.0
10 | */
11 | public abstract class FFResult {
12 |
13 | /**
14 | * 结果的字符串
15 | */
16 | private String resultString;
17 |
18 | /**
19 | * 异常字符串
20 | */
21 | private String error;
22 |
23 | public FFResult(String resultStr){
24 | this.resultString = resultStr;
25 | }
26 |
27 | public String getResultString() {
28 | return resultString;
29 | }
30 |
31 | public void setResultString(String resultString) {
32 | this.resultString = resultString;
33 | }
34 |
35 | public String getError() {
36 | return error;
37 | }
38 |
39 | public void setError(String error) {
40 | this.error = error;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/result/defaultResult/FFDefaultResult.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.result.defaultResult;
2 |
3 | import org.mountcloud.ffmepg.result.FFResult;
4 |
5 | /**
6 | * FFMpeg 默认的结果
7 | * com.ugirls.ffmepg.result
8 | * 2018/6/7.
9 | *
10 | * @author zhanghaishan
11 | * @version V1.0
12 | */
13 | public class FFDefaultResult extends FFResult {
14 | public FFDefaultResult(String resultStr) {
15 | super(resultStr);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/result/defaultResult/FFVideoInfoResult.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.result.defaultResult;
2 |
3 | /**
4 | * 视频信息结果
5 | * com.ugirls.ffmepg.result.defaultResult
6 | * 2018/6/12.
7 | *
8 | * @author zhanghaishan
9 | * @version V1.0
10 | */
11 | public class FFVideoInfoResult extends FFDefaultResult{
12 |
13 |
14 | /**
15 | * 秒数
16 | */
17 | private Integer timeLengthSec;
18 |
19 | /**
20 | * 时长
21 | */
22 | private String timeLength;
23 |
24 | /**
25 | * 开始时间
26 | */
27 | private String startTime;
28 |
29 | /**
30 | * 比特率
31 | */
32 | private String bitrate;
33 |
34 |
35 | /**
36 | * 宽度
37 | */
38 | private String width;
39 |
40 | /**
41 | * 高度
42 | */
43 | private String height;
44 |
45 | /**
46 | * fps
47 | */
48 | private String fps;
49 |
50 | /**
51 | * tbr
52 | */
53 | private String tbr;
54 |
55 | /**
56 | * tbn
57 | */
58 | private String tbn;
59 |
60 | /**
61 | * tbc
62 | */
63 | private String tbc;
64 |
65 | public FFVideoInfoResult() {
66 | super("");
67 | }
68 |
69 | public FFVideoInfoResult(String resultStr) {
70 | super(resultStr);
71 | }
72 |
73 | public Integer getTimeLengthSec() {
74 | return timeLengthSec;
75 | }
76 |
77 | public void setTimeLengthSec(Integer timeLengthSec) {
78 | this.timeLengthSec = timeLengthSec;
79 | }
80 |
81 | public String getTimeLength() {
82 | return timeLength;
83 | }
84 |
85 | public void setTimeLength(String timeLength) {
86 | this.timeLength = timeLength;
87 | }
88 |
89 | public String getStartTime() {
90 | return startTime;
91 | }
92 |
93 | public void setStartTime(String startTime) {
94 | this.startTime = startTime;
95 | }
96 |
97 | public String getBitrate() {
98 | return bitrate;
99 | }
100 |
101 | public void setBitrate(String bitrate) {
102 | this.bitrate = bitrate;
103 | }
104 |
105 | public String getWidth() {
106 | return width;
107 | }
108 |
109 | public void setWidth(String width) {
110 | this.width = width;
111 | }
112 |
113 | public String getHeight() {
114 | return height;
115 | }
116 |
117 | public void setHeight(String height) {
118 | this.height = height;
119 | }
120 |
121 | public String getFps() {
122 | return fps;
123 | }
124 |
125 | public void setFps(String fps) {
126 | this.fps = fps;
127 | }
128 |
129 | public String getTbr() {
130 | return tbr;
131 | }
132 |
133 | public void setTbr(String tbr) {
134 | this.tbr = tbr;
135 | }
136 |
137 | public String getTbn() {
138 | return tbn;
139 | }
140 |
141 | public void setTbn(String tbn) {
142 | this.tbn = tbn;
143 | }
144 |
145 | public String getTbc() {
146 | return tbc;
147 | }
148 |
149 | public void setTbc(String tbc) {
150 | this.tbc = tbc;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/bean/FFTask.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.bean;
2 |
3 | import org.mountcloud.ffmepg.operation.FFOperationBase;
4 | import org.mountcloud.ffmepg.task.bean.read.FFTaskReadState;
5 | import org.mountcloud.ffmepg.task.bean.read.FFTaskReadThread;
6 | import org.mountcloud.ffmepg.task.bean.read.FFTaskReadType;
7 | import org.mountcloud.ffmepg.task.context.FFTaskContext;
8 | import org.mountcloud.ffmepg.task.threads.FFThread;
9 | import org.mountcloud.ffmepg.util.FFTerminalCreater;
10 | import org.mountcloud.ffmepg.util.UUIDUtil;
11 |
12 | import java.io.IOException;
13 | import java.util.*;
14 |
15 | /**
16 | * 任务父类
17 | * com.ugirls.ffmepg.task
18 | * 2018/6/11.
19 | *
20 | * @author zhanghaishan
21 | * @version V1.0
22 | */
23 | public abstract class FFTask implements FFThread {
24 |
25 | /**
26 | * 任务id
27 | */
28 | private String taskId;
29 |
30 | /**
31 | * 执行结果的全部内容
32 | */
33 | protected StringBuffer result = new StringBuffer("");
34 |
35 | /**
36 | * 内容操作
37 | */
38 | protected T operationBase;
39 |
40 | /**
41 | * 任务进度
42 | */
43 | private FFTaskProgress progress;
44 |
45 | /**
46 | * 任务命令行
47 | */
48 | protected FFTerminalCreater.FFTerminal terminal = null;
49 |
50 | /**
51 | * 任务创建时间
52 | */
53 | private Date createTime;
54 |
55 | /**
56 | * 读取任务的执行是否完成
57 | */
58 | private Map readState = new HashMap<>();
59 |
60 | /**
61 | * 读取线程
62 | */
63 | protected List ffTaskReadThreadList = new ArrayList<>();
64 |
65 | @Override
66 | public void run() {
67 |
68 | //执行开始前回调
69 | callExecStart();
70 |
71 | //任务开始
72 | progress.setState(FFTaskStateEnum.START);
73 |
74 | //执行的命令
75 | String cmd = operationBase.toString();
76 |
77 | //任务执行状态
78 | boolean state = true;
79 |
80 | try {
81 | terminal = FFTerminalCreater.getCreater().getTerminal(cmd);
82 | //初始化读取线程
83 | initReadThread();
84 |
85 | //等待执行完毕
86 | while (!this.checkReadIsEnd()){
87 | Thread.sleep(500);
88 | }
89 |
90 | //执行完毕则获取执行状态
91 | state = this.checkReadState();
92 |
93 | } catch (IOException e) {
94 | state =false;
95 | e.printStackTrace();
96 | } catch (InterruptedException e) {
97 | state =false;
98 | e.printStackTrace();
99 | }
100 |
101 | //设置状态
102 | if(state){
103 | progress.setState(FFTaskStateEnum.COMPLETE);
104 | } else {
105 | progress.setState(FFTaskStateEnum.FAILED);
106 | }
107 | progress.setProgress(100);
108 | FFTaskContext.getContext().removeTask(this.getTaskId());
109 | //执行结束回调
110 | callExecEnd();
111 | }
112 |
113 | /**
114 | * 判断是否在读取中
115 | * @return false 读取中,true 读取完成
116 | */
117 | private boolean checkReadIsEnd(){
118 | for(FFTaskReadState state : readState.values()){
119 | if(!state.isEnd()){
120 | return false;
121 | }
122 | }
123 | return true;
124 | }
125 |
126 | /**
127 | * 判断读取状态
128 | * @return false 读取报错,true 读取成功
129 | */
130 | private boolean checkReadState(){
131 | for(FFTaskReadState state : readState.values()){
132 | if(!state.getState()){
133 | return false;
134 | }
135 | }
136 | return true;
137 | }
138 |
139 | /**
140 | * 初始化读取线程
141 | */
142 | private void initReadThread(){
143 |
144 | //创建读取线程,读取error和in
145 | FFTaskReadThread ffTaskReadErrorThread = new FFTaskReadThread(this, FFTaskReadType.ERROR_IN);
146 | FFTaskReadThread ffTaskReadThread = new FFTaskReadThread(this, FFTaskReadType.IN);
147 | readState.put(ffTaskReadErrorThread.getReadType(),new FFTaskReadState());
148 | readState.put(ffTaskReadThread.getReadType(),new FFTaskReadState());
149 |
150 | //加入线程数组,如果以后需要可以扩展
151 | ffTaskReadThreadList.add(ffTaskReadErrorThread);
152 | ffTaskReadThreadList.add(ffTaskReadThread);
153 |
154 | //开启这两个读取线程,此处不优雅,如果有更好的方案请告诉我
155 | new Thread(ffTaskReadErrorThread).start();
156 | new Thread(ffTaskReadThread).start();
157 | }
158 |
159 |
160 | /**
161 | * 传入一行结果
162 | * @param line 一行日志
163 | */
164 | public synchronized void putResultLine(String line){
165 | result.append(line);
166 | callRsultLine(line);
167 | }
168 |
169 |
170 | /**
171 | * 执行开始
172 | */
173 | public abstract void callExecStart();
174 |
175 | /**
176 | * 正确结果行
177 | * @param line 一行结果
178 | */
179 | public abstract void callRsultLine(String line);
180 |
181 | /**
182 | * 执行结束
183 | */
184 | public abstract void callExecEnd();
185 |
186 |
187 | /**
188 | * 任务构造
189 | * @param operation 操作
190 | */
191 | public FFTask(T operation){
192 | this.operationBase = operation;
193 | this.taskId = UUIDUtil.getUUIDSimpl();
194 | this.createTime = new Date();
195 | this.progress = new FFTaskProgress();
196 | }
197 |
198 | public FFTask(){
199 | this.progress = new FFTaskProgress();
200 | }
201 |
202 | public String getTaskId() {
203 | return taskId;
204 | }
205 |
206 | public FFTaskProgress getProgress() {
207 | return progress;
208 | }
209 |
210 | public void setProgress(FFTaskProgress progress) {
211 | this.progress = progress;
212 | }
213 |
214 | public FFTerminalCreater.FFTerminal getTerminal(){
215 | return terminal;
216 | }
217 |
218 | public FFTaskReadState getReadState(FFTaskReadType ffTaskReadType){
219 | return this.readState.get(ffTaskReadType);
220 | }
221 |
222 | }
223 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/bean/FFTaskProgress.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.bean;
2 |
3 | /**
4 | * 任务状态
5 | * com.ugirls.ffmepg.task
6 | * 2018/6/11.
7 | *
8 | * @author zhanghaishan
9 | * @version V1.0
10 | */
11 | public class FFTaskProgress {
12 |
13 | public FFTaskProgress(){
14 | this.progress = 0;
15 | this.state = FFTaskStateEnum.QUEUE;
16 | }
17 |
18 | private int progress;
19 |
20 | private FFTaskStateEnum state;
21 |
22 | public FFTaskStateEnum getState() {
23 | return state;
24 | }
25 |
26 | public void setState(FFTaskStateEnum state) {
27 | this.state = state;
28 | }
29 |
30 | public int getProgress() {
31 | return progress;
32 | }
33 |
34 | public void setProgress(int progress) {
35 | this.progress = progress;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/bean/FFTaskStateEnum.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.bean;
2 |
3 | /**
4 | * 任务状态枚举
5 | * com.ugirls.ffmepg.task.bean
6 | * 2018/6/11.
7 | *
8 | * @author zhanghaishan
9 | * @version V1.0
10 | */
11 | public enum FFTaskStateEnum {
12 |
13 | /**
14 | * 队列
15 | */
16 | QUEUE(2),
17 | /**
18 | * 进行中
19 | */
20 | START(1),
21 | /**
22 | * 已完成
23 | */
24 | COMPLETE(0),
25 | /**
26 | * 失败
27 | */
28 | FAILED(-1);
29 |
30 | private Integer val = null;
31 |
32 | FFTaskStateEnum(int i) {
33 | this.val = i;
34 | }
35 |
36 | /**
37 | * 获取枚举
38 | * @param i 值
39 | * @return 枚举
40 | */
41 | public static FFTaskStateEnum getEnum(int i){
42 | switch (i){
43 | case 2:
44 | return QUEUE;
45 | case 1:
46 | return START;
47 | case 0:
48 | return COMPLETE;
49 | }
50 | return FAILED;
51 | }
52 |
53 | /**
54 | * 返回值
55 | * @return 值
56 | */
57 | public int getValue(){
58 | return val;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/bean/FFVideoTask.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.bean;
2 |
3 |
4 | import org.mountcloud.ffmepg.operation.FFOperationBase;
5 | import org.mountcloud.ffmepg.util.FFVideoUtil;
6 | import org.mountcloud.ffmepg.util.StringUtil;
7 |
8 | import java.util.regex.Matcher;
9 | import java.util.regex.Pattern;
10 |
11 | /**
12 | * 视频操作任务父类
13 | * com.ugirls.ffmepg.task.bean
14 | * 2018/6/11.
15 | *
16 | * @author zhanghaishan
17 | * @version V1.0
18 | */
19 | public abstract class FFVideoTask extends FFTask{
20 |
21 | /**
22 | * 秒数
23 | */
24 | private Integer timeLengthSec;
25 |
26 | /**
27 | * 时长
28 | */
29 | private String timeLength;
30 |
31 | /**
32 | * 开始时间
33 | */
34 | private String startTime;
35 |
36 | /**
37 | * 比特率
38 | */
39 | private String bitrate;
40 |
41 | /**
42 | * 宽度
43 | */
44 | private String width;
45 |
46 | /**
47 | * 高度
48 | */
49 | private String height;
50 |
51 | /**
52 | * fps
53 | */
54 | private String fps;
55 |
56 | /**
57 | * tbr
58 | */
59 | private String tbr;
60 |
61 | /**
62 | * tbn
63 | */
64 | private String tbn;
65 |
66 | /**
67 | * tbc
68 | */
69 | private String tbc;
70 |
71 | /**
72 | * 正则
73 | */
74 | private String regexDuration = "Duration: (.*?), start: (.*?), bitrate: (\\d*)";
75 |
76 |
77 | /**
78 | * 尺寸
79 | */
80 | private String sizeDuration = "Stream (.*?): Video: (.*?) \\d*x\\d*";
81 |
82 | /**
83 | * 正则模式
84 | */
85 | private Pattern pattern = Pattern.compile(regexDuration);
86 |
87 | /**
88 | * 正则模式
89 | */
90 | private Pattern sizePattern = Pattern.compile(sizeDuration);
91 |
92 |
93 | public FFVideoTask(T operation){
94 | super(operation);
95 | }
96 |
97 | /**
98 | * 设置结果
99 | * @param line 一行结果
100 | */
101 | @Override
102 | public void callRsultLine(String line) {
103 |
104 | //获取视频时长信息
105 | //Duration: 00:03:38.80, start: 1.427433, bitrate: 0 kb/s
106 | Matcher m = pattern.matcher(line.trim());
107 | if (m.find()) {
108 | timeLength = m.group(1);
109 | if(timeLength!=null){
110 | timeLengthSec = FFVideoUtil.getTimelen(timeLength);
111 | }
112 | startTime = m.group(2);
113 | bitrate = m.group(3);
114 | }
115 |
116 | /**
117 | * 获取视频尺寸
118 | */
119 | //Stream #0:0: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p, 1024x576 [SAR 1:1 DAR 16:9], 20 fps, 20 tbr, 90k tbn, 40 tbc
120 | Matcher sizem = sizePattern.matcher(line.trim());
121 | if(sizem.find()){
122 | findSize(line);
123 | }
124 |
125 |
126 | callBackResultLine(line);
127 | }
128 |
129 | /**
130 | * 子类需要返回的
131 | * @param line 一行结果
132 | */
133 | public abstract void callBackResultLine(String line);
134 |
135 | public String getTimeLength() {
136 | return timeLength;
137 | }
138 |
139 | public void setTimeLength(String timeLength) {
140 | this.timeLength = timeLength;
141 | }
142 |
143 | public String getStartTime() {
144 | return startTime;
145 | }
146 |
147 | public void setStartTime(String startTime) {
148 | this.startTime = startTime;
149 | }
150 |
151 | public String getBitrate() {
152 | return bitrate;
153 | }
154 |
155 | public void setBitrate(String bitrate) {
156 | this.bitrate = bitrate;
157 | }
158 |
159 | public Integer getTimeLengthSec() {
160 | return timeLengthSec;
161 | }
162 |
163 | public void setTimeLengthSec(Integer timeLengthSec) {
164 | this.timeLengthSec = timeLengthSec;
165 | }
166 |
167 | //格式:"00:00:10.68"
168 | protected int getTimelen(String timelen){
169 | int min=0;
170 | String strs[] = timelen.split(":");
171 | if (strs[0].compareTo("0") > 0) {
172 | min+=Integer.valueOf(strs[0])*60*60;//秒
173 | }
174 | if(strs[1].compareTo("0")>0){
175 | min+=Integer.valueOf(strs[1])*60;
176 | }
177 | if(strs[2].compareTo("0")>0){
178 | min+=Math.round(Float.valueOf(strs[2]));
179 | }
180 | return min;
181 | }
182 |
183 | /**
184 | * 获取长度的信息
185 | * @param line
186 | */
187 | private void findSize(String line){
188 |
189 | String sizeRegs = ", \\d*x\\d*";
190 | String sizeResul = StringUtil.findStringsByRegsOne(sizeRegs,line);
191 | sizeResul = sizeResul.replace(", ","");
192 | String[] size = sizeResul.split("x");
193 | String w = size[0];
194 | String h = size[1];
195 | setWidth(w);
196 | setHeight(h);
197 |
198 | String fpsRegs = "\\d* fps";
199 | String fpsResul = StringUtil.findStringsByRegsOne(fpsRegs,line);
200 | if(fpsResul!=null){
201 | fpsResul = fpsResul.replace(" fps","");
202 | setFps(fpsResul);
203 | }
204 |
205 | String tbrRegs = "\\d* tbr";
206 | String tbrResul = StringUtil.findStringsByRegsOne(tbrRegs,line);
207 | if(tbrResul!=null){
208 | tbrResul = tbrResul.replace(" tbr","");
209 | setTbr(tbrResul);
210 | }
211 |
212 | String tbnRegs = "[0-9a-z]* tbn";
213 | String tbnResul = StringUtil.findStringsByRegsOne(tbnRegs,line);
214 | if(tbnResul!=null){
215 | tbnResul = tbnResul.replace(" tbn","");
216 | setTbn(tbnResul);
217 | }
218 |
219 | String tbcRegs = "\\d* tbc";
220 | String tbcResul = StringUtil.findStringsByRegsOne(tbcRegs,line);
221 | if(tbcResul!=null){
222 | tbcResul = tbcResul.replace(" tbc","");
223 | setTbc(tbcResul);
224 | }
225 |
226 | }
227 |
228 | public String getWidth() {
229 | return width;
230 | }
231 |
232 | public void setWidth(String width) {
233 | this.width = width;
234 | }
235 |
236 | public String getHeight() {
237 | return height;
238 | }
239 |
240 | public void setHeight(String height) {
241 | this.height = height;
242 | }
243 |
244 | public String getFps() {
245 | return fps;
246 | }
247 |
248 | public void setFps(String fps) {
249 | this.fps = fps;
250 | }
251 |
252 | public String getTbr() {
253 | return tbr;
254 | }
255 |
256 | public void setTbr(String tbr) {
257 | this.tbr = tbr;
258 | }
259 |
260 | public String getTbn() {
261 | return tbn;
262 | }
263 |
264 | public void setTbn(String tbn) {
265 | this.tbn = tbn;
266 | }
267 |
268 | public String getTbc() {
269 | return tbc;
270 | }
271 |
272 | public void setTbc(String tbc) {
273 | this.tbc = tbc;
274 | }
275 | }
276 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/bean/read/FFTaskReadState.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.bean.read;
2 |
3 | /**
4 | * 任务读取状态
5 | * com.ugirls.ffmepg.task.bean.read
6 | * 2020/6/16.
7 | *
8 | * @author zhanghaishan
9 | * @version V1.0
10 | */
11 | public class FFTaskReadState {
12 |
13 | /**
14 | * 状态,true是成功,false是失败
15 | */
16 | private Boolean state = false;
17 |
18 | /**
19 | * 是否结束,true是结束,false是进行中
20 | */
21 | private Boolean end = false;
22 |
23 | public Boolean getState() {
24 | return state;
25 | }
26 |
27 | public void setState(Boolean state) {
28 | this.state = state;
29 | }
30 |
31 | public Boolean isEnd() {
32 | return end;
33 | }
34 |
35 | public void setEnd(Boolean end) {
36 | this.end = end;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/bean/read/FFTaskReadThread.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.bean.read;
2 |
3 | import org.mountcloud.ffmepg.task.bean.FFTask;
4 | import org.mountcloud.ffmepg.task.threads.FFThread;
5 |
6 | import java.io.IOException;
7 |
8 | /**
9 | * 任务读取异常线程
10 | * com.ugirls.ffmepg.task.bean.read
11 | * 2020/6/16.
12 | *
13 | * @author zhanghaishan
14 | * @version V1.0
15 | */
16 | public class FFTaskReadThread implements FFThread {
17 |
18 | /**
19 | * 任务
20 | */
21 | private FFTask> ffTask;
22 |
23 | /**
24 | * 读取类型
25 | */
26 | private FFTaskReadType readType;
27 |
28 | /**
29 | * 构造一个读取线程
30 | * @param ffTask 任务
31 | * @param readType 读取类型
32 | */
33 | public FFTaskReadThread(FFTask> ffTask,FFTaskReadType readType){
34 | this.ffTask = ffTask;
35 | this.readType = readType;
36 | }
37 |
38 | @Override
39 | public void run() {
40 | //结果
41 | String str = null;
42 | boolean state = false;
43 | try {
44 | if(readType.equals(FFTaskReadType.ERROR_IN)){
45 | while ((str=ffTask.getTerminal().readErrorLine())!=null){
46 | ffTask.putResultLine(str);
47 | }
48 | }else{
49 | while ((str=ffTask.getTerminal().readLine())!=null){
50 | ffTask.putResultLine(str);
51 | }
52 | }
53 | state = true;
54 | }catch (IOException e){
55 | state = false;
56 | e.printStackTrace();
57 | }
58 | //结束了
59 | FFTaskReadState readState = ffTask.getReadState(this.getReadType());
60 | readState.setEnd(true);
61 | readState.setState(state);
62 | }
63 |
64 | public FFTaskReadType getReadType(){
65 | return this.readType;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/bean/read/FFTaskReadType.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.bean.read;
2 |
3 | /**
4 | * 任务读取异常线程
5 | * com.ugirls.ffmepg.task.bean.read
6 | * 2020/6/16.
7 | *
8 | * @author zhanghaishan
9 | * @version V1.0
10 | */
11 | public enum FFTaskReadType{
12 | ERROR_IN,//读取异常流
13 | IN//读取流
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/bean/tasks/FFMepgVideoFormatM3u8Task.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.bean.tasks;
2 |
3 | import org.mountcloud.ffmepg.operation.ffmpeg.vidoe.FFMpegVideoFormatM3u8;
4 | import org.mountcloud.ffmepg.task.bean.FFVideoTask;
5 | import org.mountcloud.ffmepg.util.FFBigDecimalUtil;
6 | import org.mountcloud.ffmepg.util.FFVideoUtil;
7 |
8 | import java.util.regex.Matcher;
9 | import java.util.regex.Pattern;
10 |
11 | /**
12 | * 视频转m3u8任务
13 | * com.ugirls.ffmepg.task.bean.tasks
14 | * 2018/6/11.
15 | *
16 | * @author zhanghaishan
17 | * @version V1.0
18 | */
19 | public class FFMepgVideoFormatM3u8Task extends FFVideoTask {
20 |
21 | /**
22 | * 进度正则查询
23 | */
24 | private String frameRegexDuration = "frame=([\\s,\\d]*) fps=(.*?) q=(.*?) size=([\\s\\S]*) time=(.*?) bitrate=([\\s\\S]*) speed=(.*?)x";
25 |
26 | /**
27 | * 正则模式
28 | */
29 | private Pattern framePattern = Pattern.compile(frameRegexDuration);
30 |
31 | @Override
32 | public void callExecStart() {
33 | }
34 |
35 | @Override
36 | public void callExecEnd() {
37 | }
38 |
39 | /**
40 | * 任务构造
41 | * @param format 操作
42 | */
43 | public FFMepgVideoFormatM3u8Task(FFMpegVideoFormatM3u8 format){
44 | super(format);
45 | }
46 |
47 | /**
48 | * 回调
49 | * @param line 一行结果
50 | */
51 | @Override
52 | public void callBackResultLine(String line) {
53 |
54 | if(super.getTimeLengthSec()!=null){
55 | //获取视频信息
56 | Matcher m = framePattern.matcher(line);
57 | if(m.find()){
58 | try {
59 | String execTimeStr = m.group(5);
60 | int execTimeInt = FFVideoUtil.getTimelen(execTimeStr);
61 | double devnum = FFBigDecimalUtil.div(execTimeInt,super.getTimeLengthSec(),5);
62 | double progressDouble = FFBigDecimalUtil.mul(devnum,100);
63 | super.getProgress().setProgress((int) progressDouble);
64 | } catch (IllegalAccessException e) {
65 | e.printStackTrace();
66 | }
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/bean/tasks/FFMepgVideoInfoTask.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.bean.tasks;
2 |
3 |
4 | import org.mountcloud.ffmepg.operation.ffmpeg.vidoe.FFMpegVideoInfo;
5 | import org.mountcloud.ffmepg.result.defaultResult.FFVideoInfoResult;
6 | import org.mountcloud.ffmepg.task.bean.FFVideoTask;
7 |
8 | /**
9 | * 视频信息查询任务
10 | * com.ugirls.ffmepg.task.bean.tasks
11 | * 2018/6/12.
12 | *
13 | * @author zhanghaishan
14 | * @version V1.0
15 | */
16 | public class FFMepgVideoInfoTask extends FFVideoTask {
17 |
18 | private FFVideoInfoResult data;
19 |
20 | public FFMepgVideoInfoTask(FFMpegVideoInfo operation) {
21 | super(operation);
22 | }
23 |
24 | public FFMepgVideoInfoTask(FFVideoInfoResult result,FFMpegVideoInfo operation) {
25 | super(operation);
26 | this.data = result;
27 | }
28 |
29 | @Override
30 | public void callExecStart() {
31 |
32 | }
33 |
34 | @Override
35 | public void callBackResultLine(String line) {
36 |
37 | }
38 |
39 | @Override
40 | public void callExecEnd() {
41 | if(data==null){
42 | //返回结果
43 | data = new FFVideoInfoResult(result.toString());
44 | }
45 |
46 | //结果
47 | data.setTimeLengthSec(getTimeLengthSec());
48 | data.setTimeLength(getTimeLength());
49 | data.setStartTime(getStartTime());
50 | data.setBitrate(getBitrate());
51 | data.setWidth(getWidth());
52 | data.setHeight(getHeight());
53 | data.setFps(getFps());
54 | data.setTbr(getTbr());
55 | data.setTbn(getTbn());
56 | data.setTbc(getTbc());
57 | }
58 |
59 | public FFVideoInfoResult getData() {
60 | return data;
61 | }
62 |
63 | public void setData(FFVideoInfoResult data) {
64 | this.data = data;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/bean/tasks/FFMpegVideoScreenShotTask.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.bean.tasks;
2 |
3 | import org.mountcloud.ffmepg.operation.ffmpeg.vidoe.FFMpegVideoScreenShot;
4 | import org.mountcloud.ffmepg.task.bean.FFVideoTask;
5 |
6 | /**
7 | * 视频截图任务
8 | * com.ugirls.ffmepg.task.bean.tasks
9 | * 2018/6/12.
10 | *
11 | * @author zhanghaishan
12 | * @version V1.0
13 | */
14 | public class FFMpegVideoScreenShotTask extends FFVideoTask {
15 |
16 | public FFMpegVideoScreenShotTask(FFMpegVideoScreenShot operation) {
17 | super(operation);
18 | }
19 |
20 | @Override
21 | public void callBackResultLine(String line) {
22 |
23 | }
24 |
25 | @Override
26 | public void callExecStart() {
27 |
28 | }
29 |
30 | @Override
31 | public void callExecEnd() {
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/context/FFTaskContext.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.context;
2 |
3 | import org.mountcloud.ffmepg.task.bean.FFTask;
4 | import org.mountcloud.ffmepg.task.threads.FFThreadManager;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 | import java.util.concurrent.locks.Lock;
9 | import java.util.concurrent.locks.ReentrantLock;
10 |
11 | /**
12 | * 任务上下文
13 | * com.ugirls.ffmepg.task
14 | * 2018/6/11.
15 | *
16 | * @author zhanghaishan
17 | * @version V1.0
18 | */
19 | public class FFTaskContext {
20 |
21 | /**
22 | * 任务列表锁
23 | */
24 | private Lock lock = new ReentrantLock();
25 |
26 | /**
27 | * 上下文单例
28 | */
29 | private static FFTaskContext context;
30 |
31 | /**
32 | * 任务线程池
33 | */
34 | private FFThreadManager.ThreadPool ffThreadPool;
35 |
36 | /**
37 | * 任务列表
38 | */
39 | private Map taskMap = new HashMap();
40 |
41 | /**
42 | * 添加一个任务
43 | * @param task 任务
44 | */
45 | public void addTask(FFTask task){
46 | try{
47 | lock.lock();
48 | taskMap.put(task.getTaskId(),task);
49 | }finally {
50 | lock.unlock();
51 | }
52 | ffThreadPool.execute(task);
53 | }
54 |
55 | /**
56 | * 提交一个任务
57 | * @param task 提交任务
58 | */
59 | public void submit(FFTask task){
60 | try{
61 | lock.lock();
62 | taskMap.put(task.getTaskId(),task);
63 | }finally {
64 | lock.unlock();
65 | }
66 |
67 | try {
68 | ffThreadPool.submit(task);
69 | } catch (Exception e) {
70 | e.printStackTrace();
71 | }
72 | }
73 | /**
74 | * 提交一个任务
75 | * @param task 提交任务
76 | * @param bean 数据
77 | * @param 数据
78 | * @return 执行结果
79 | */
80 | public T submit(FFTask task,T bean){
81 | T data = null;
82 |
83 | try{
84 | lock.lock();
85 | taskMap.put(task.getTaskId(),task);
86 | }finally {
87 | lock.unlock();
88 | }
89 |
90 | try {
91 | data = ffThreadPool.submit(task,bean);
92 | } catch (Exception e) {
93 | e.printStackTrace();
94 | }
95 | return data;
96 | }
97 |
98 | /**
99 | * 任务ID
100 | * @param taskId 任务id
101 | */
102 | public void removeTask(String taskId){
103 | try{
104 | lock.lock();
105 | taskMap.remove(taskId);
106 | }finally {
107 | lock.unlock();
108 | }
109 | }
110 |
111 | /**
112 | * 提供上下文
113 | * @return 上下文
114 | */
115 | public static FFTaskContext getContext(){
116 | if(context == null){
117 | context = new FFTaskContext();
118 | }
119 | return context;
120 | }
121 |
122 | /**
123 | * 私密的上下文
124 | */
125 | private FFTaskContext(){
126 | ffThreadPool = FFThreadManager.getInstance();
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/threads/FFThread.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.threads;
2 |
3 | /**
4 | * TODO: 线程对象
5 | * com.ugirls.ffmepg.task.threads
6 | * 2018/6/11.
7 | *
8 | * @author zhanghaishan
9 | * @version V1.0
10 | */
11 | public interface FFThread extends Runnable {
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/task/threads/FFThreadManager.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.task.threads;
2 |
3 | import java.util.concurrent.*;
4 |
5 | /**
6 | * 任务的线程池
7 | * com.ugirls.ffmepg.task.threads
8 | * 2018/6/11.
9 | *
10 | * @author zhanghaishan
11 | * @version V1.0
12 | */
13 | public class FFThreadManager {
14 |
15 | public static ThreadPool instance;
16 |
17 | // 获取单例的线程池对象
18 | public static ThreadPool getInstance() {
19 | if (instance == null) {
20 | synchronized (FFThreadManager.class) {
21 | if (instance == null) {
22 | int cpuNum = Runtime.getRuntime().availableProcessors();// 获取处理器数量
23 | int threadNum = cpuNum * 2 + 1;// 根据cpu数量,计算出合理的线程并发数
24 | instance = new ThreadPool(threadNum-1, threadNum, Integer.MAX_VALUE);//默认是双核的cpu 每个核心走一个线程 一个等待线程
25 | }
26 | }
27 | }
28 | return instance;
29 | }
30 |
31 | public static class ThreadPool {
32 | private ThreadPoolExecutor mExecutor;
33 | private int corePoolSize;
34 | private int maximumPoolSize;
35 | private long keepAliveTime;
36 |
37 | private ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime) {
38 | this.corePoolSize = corePoolSize;
39 | this.maximumPoolSize = maximumPoolSize;
40 | this.keepAliveTime = keepAliveTime;
41 |
42 | mExecutor = new ThreadPoolExecutor(corePoolSize,// 核心线程数
43 | maximumPoolSize, // 最大线程数
44 | keepAliveTime, // 闲置线程存活时间
45 | TimeUnit.MILLISECONDS,// 时间单位
46 | new LinkedBlockingDeque(Integer.MAX_VALUE),// 线程队列
47 | Executors.defaultThreadFactory(),// 线程工厂
48 | new ThreadPoolExecutor.AbortPolicy() {// 队列已满,而且当前线程数已经超过最大线程数时的异常处理策略
49 | @Override
50 | public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
51 | super.rejectedExecution(r, e);
52 | }
53 | }
54 | );
55 | }
56 |
57 | public void execute(Runnable runnable) {
58 | if (runnable == null) {
59 | return;
60 | }
61 | mExecutor.execute(runnable);
62 | }
63 |
64 | /**
65 | * 提交一个可返回值的线程
66 | * @param runnable 线程
67 | * @param bean 结果类
68 | * @param 类型
69 | * @return 返回结果
70 | * @throws ExecutionException 提交异常
71 | * @throws InterruptedException 提交异常
72 | */
73 | public T submit(Runnable runnable,T bean) throws ExecutionException, InterruptedException {
74 | if (runnable == null) {
75 | return null;
76 | }
77 | Future future = mExecutor.submit(runnable,bean);
78 | return future.get();
79 | }
80 |
81 | /**
82 | * 提交一个可返回值的线程
83 | * @param runnable 线程
84 | */
85 | public void submit(Runnable runnable){
86 | if (runnable == null) {
87 | return;
88 | }
89 | mExecutor.submit(runnable);
90 | }
91 |
92 |
93 | // 从线程队列中移除对象
94 | public void cancel(Runnable runnable) {
95 | if (mExecutor != null) {
96 | mExecutor.getQueue().remove(runnable);
97 | }
98 | }
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/util/FFAnnotationUtil.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.util;
2 |
3 |
4 | import org.mountcloud.ffmepg.annotation.FFAnnotation;
5 | import org.mountcloud.ffmepg.annotation.FFCmd;
6 | import org.mountcloud.ffmepg.annotation.FFCmdBean;
7 | import org.mountcloud.ffmepg.excption.FFMpegOperationNotFoundExcption;
8 | import org.mountcloud.ffmepg.operation.FFOperationBase;
9 |
10 | import java.lang.reflect.Field;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | /**
15 | * 注解工具
16 | * com.ugirls.ffmepg.util
17 | * 2018/6/6.
18 | *
19 | * @author zhanghaishan
20 | * @version V1.0
21 | */
22 | public class FFAnnotationUtil {
23 |
24 | /**
25 | * 提取一个操作中的注解
26 | * @param bean 操作
27 | * @param 操作的类型
28 | * @return 返回操作中的所有注解
29 | * @throws IllegalAccessException 异常
30 | */
31 | public FFCmdBean getClassAnnocation(T bean) throws IllegalAccessException {
32 | FFCmdBean ffCmdBean = new FFCmdBean();
33 |
34 | Class> beanClass = bean.getClass();
35 |
36 | //获取类的注解
37 | FFCmd classFFCmd = getClassFFCmd(beanClass);
38 | FFAnnotation classFFAnnotation = getFFOperation(classFFCmd,null,bean);
39 |
40 | if(classFFAnnotation==null){
41 | throw new FFMpegOperationNotFoundExcption(beanClass.getName()+" not found FFCmd.");
42 | }
43 |
44 | //获取属性注解
45 | List fields = new ArrayList();
46 |
47 | ObjectUtil objectUtil = new ObjectUtil();
48 | //获取全部属性
49 | objectUtil.getFields(beanClass,fields,null);
50 |
51 | if(fields==null||fields.size()==0){
52 | throw new FFMpegOperationNotFoundExcption(beanClass.getName()+" fields length is 0");
53 | }
54 |
55 | List ffAnnotations = new ArrayList();
56 |
57 | for(int i=0;i type
80 | * @return FFcmd
81 | */
82 | private FFCmd getClassFFCmd(Class cls){
83 | FFCmd ffCmd = cls.getAnnotation(FFCmd.class);
84 | if(ffCmd==null){
85 | Class> superCls = cls.getSuperclass();
86 | if(superCls.equals(Object.class)){
87 | return null;
88 | }else{
89 | return getClassFFCmd(superCls);
90 | }
91 | }
92 | return ffCmd;
93 | }
94 |
95 | /**
96 | * 从一组Annotation中提取FFCmd
97 | * @param ffCmd 注解
98 | * @return FFAnnotation
99 | */
100 | private FFAnnotation getFFOperation(FFCmd ffCmd, Field field,T bean) throws IllegalAccessException {
101 | FFAnnotation ffAnnotation = null;
102 | //如果没有注解的返回空
103 | if(ffCmd==null){
104 | return ffAnnotation;
105 | }
106 |
107 | //获取key值
108 | String key = ffCmd.key();
109 |
110 | ffAnnotation = new FFAnnotation();
111 |
112 | if(field==null){
113 | ffAnnotation.setKey(key);
114 | return ffAnnotation;
115 | }
116 | //设置访问最高权限可访问private属性
117 | field.setAccessible(true);
118 |
119 | ffAnnotation.setKey(key);
120 | Object value = field.get(bean);
121 | if(value!=null){
122 | String valueStr = value.toString();
123 | ffAnnotation.setValue(valueStr);
124 | }
125 |
126 | return ffAnnotation;
127 | }
128 |
129 | }
130 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/util/FFBigDecimalUtil.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.util;
2 |
3 | import java.math.BigDecimal;
4 |
5 | /**
6 | * BigDecimal计算工具
7 | * @author zhanghaishan
8 | * @version V1.0
9 | * com.ugirls.statisticalservice.util
10 | * 2018/1/16.
11 | */
12 | public class FFBigDecimalUtil {
13 |
14 | //------------------------------------------------------------------------------------
15 | /**
16 | * 提供精确加法计算的add方法
17 | * @param value1 被加数
18 | * @param value2 加数
19 | * @return 两个参数的和
20 | */
21 | public static double add(double value1,double value2){
22 | BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
23 | BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
24 | return b1.add(b2).doubleValue();
25 | }
26 |
27 | /**
28 | * 提供精确减法运算的sub方法
29 | * @param value1 被减数
30 | * @param value2 减数
31 | * @return 两个参数的差
32 | */
33 | public static double sub(double value1,double value2){
34 | BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
35 | BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
36 | return b1.subtract(b2).doubleValue();
37 | }
38 |
39 | /**
40 | * 提供精确乘法运算的mul方法
41 | * @param value1 被乘数
42 | * @param value2 乘数
43 | * @return 两个参数的积
44 | */
45 | public static double mul(double value1,double value2){
46 | BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
47 | BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
48 | return b1.multiply(b2).doubleValue();
49 | }
50 |
51 | /**
52 | * 提供精确的除法运算方法div
53 | * @param value1 被除数
54 | * @param value2 除数
55 | * @param scale 精确范围
56 | * @return 两个参数的商
57 | * @throws IllegalAccessException 异常
58 | */
59 | public static double div(double value1,double value2,int scale) throws IllegalAccessException{
60 | //如果精确范围小于0,抛出异常信息
61 | if(scale<0){
62 | throw new IllegalAccessException("精确度不能小于0");
63 | }
64 | BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
65 | BigDecimal b2 = new BigDecimal(Double.valueOf(value2));
66 | BigDecimal devVal = b1.divide(b2, scale,BigDecimal.ROUND_HALF_UP);
67 | return devVal.doubleValue();
68 | }
69 |
70 |
71 | //-----------------------------------------------------------------------------------------------
72 |
73 |
74 | /**
75 | * 多个求和
76 | * @param decimals 多个值
77 | * @return 结果
78 | */
79 | public static BigDecimal addDecimals(BigDecimal ...decimals){
80 | BigDecimal val = new BigDecimal(0);
81 | for(BigDecimal dc:decimals){
82 | val = addDecimal(val,dc);
83 | }
84 | return val;
85 | }
86 |
87 | /**
88 | * 提供精确加法计算的add方法
89 | * @param value1 被加数
90 | * @param value2 加数
91 | * @return 两个参数的和
92 | */
93 | public static BigDecimal addDecimal(BigDecimal value1,BigDecimal value2){
94 | if(value1==null&&value2==null){
95 | return new BigDecimal(0);
96 | }
97 | if(value1==null){
98 | return value2;
99 | }
100 | if(value2==null){
101 | return value1;
102 | }
103 | return value1.add(value2);
104 | }
105 |
106 | /**
107 | * 提供精确减法运算的sub方法
108 | * @param value1 被减数
109 | * @param value2 减数
110 | * @return 两个参数的差
111 | */
112 | public static BigDecimal subDecimal(BigDecimal value1,BigDecimal value2){
113 | return value1.subtract(value2);
114 | }
115 |
116 | /**
117 | * 提供精确乘法运算的mul方法
118 | * @param value1 被乘数
119 | * @param value2 乘数
120 | * @return 两个参数的积
121 | */
122 | public static BigDecimal mulDecimal(BigDecimal value1,BigDecimal value2){
123 | return value1.multiply(value2);
124 | }
125 |
126 | /**
127 | * 提供精确的除法运算方法div
128 | * @param value1 被除数
129 | * @param value2 除数
130 | * @param scale 精确范围
131 | * @return 两个参数的商
132 | * @throws IllegalAccessException 异常
133 | */
134 | public static BigDecimal divDecimal(BigDecimal value1,BigDecimal value2,int scale) throws IllegalAccessException{
135 | //如果精确范围小于0,抛出异常信息
136 | if(scale<0){
137 | throw new IllegalAccessException("精确度不能小于0");
138 | }
139 | return value1.divide(value2, scale);
140 | }
141 |
142 | /**
143 | * 整数相加
144 | * @param i1 值1
145 | * @param i2 值2
146 | * @return 相加结果
147 | */
148 | public static Integer addInteger(Integer i1,Integer i2){
149 | if(i1==null&&i2==null){
150 | return 0;
151 | }
152 | if(i1==null){
153 | return i2;
154 | }
155 | if(i2==null){
156 | return i1;
157 | }
158 | return i1+i2;
159 | }
160 |
161 | /**
162 | * 返回浮点型累加数量
163 | * @param values 多个相加的值
164 | * @return 结果
165 | */
166 | public static Float addAllFloat(Float ...values){
167 | BigDecimal od = new BigDecimal(0.0);
168 | for(int i=0;i params) throws IOException {
68 | String[] tempParams = new String[params.size()];
69 | for(int i=0;i 0) {
22 | min+=Integer.valueOf(strs[0])*60*60;//秒
23 | }
24 | if(strs[1].compareTo("0")>0){
25 | min+=Integer.valueOf(strs[1])*60;
26 | }
27 | if(strs[2].compareTo("0")>0){
28 | min+=Math.round(Float.valueOf(strs[2]));
29 | }
30 | return min;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/util/OSUtils.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.util;
2 |
3 | public class OSUtils {
4 |
5 | public enum OSType {
6 | OS_TYPE_LINUX, OS_TYPE_WIN, OS_TYPE_SOLARIS, OS_TYPE_MAC, OS_TYPE_FREEBSD, OS_TYPE_OTHER
7 | }
8 |
9 | static private OSType getOSType() {
10 | String osName = System.getProperty("os.name");
11 | if (osName.startsWith("Windows")) {
12 | return OSType.OS_TYPE_WIN;
13 | } else if (osName.contains("SunOS") || osName.contains("Solaris")) {
14 | return OSType.OS_TYPE_SOLARIS;
15 | } else if (osName.contains("Mac")) {
16 | return OSType.OS_TYPE_MAC;
17 | } else if (osName.contains("FreeBSD")) {
18 | return OSType.OS_TYPE_FREEBSD;
19 | } else if (osName.startsWith("Linux")) {
20 | return OSType.OS_TYPE_LINUX;
21 | } else {
22 | // Some other form of Unix
23 | return OSType.OS_TYPE_OTHER;
24 | }
25 | }
26 |
27 | public static final OSType osType = getOSType();
28 | // Helper static vars for each platform
29 | public static final boolean WINDOWS = (osType == OSType.OS_TYPE_WIN);
30 | public static final boolean SOLARIS = (osType == OSType.OS_TYPE_SOLARIS);
31 | public static final boolean MAC = (osType == OSType.OS_TYPE_MAC);
32 | public static final boolean FREEBSD = (osType == OSType.OS_TYPE_FREEBSD);
33 | public static final boolean LINUX = (osType == OSType.OS_TYPE_LINUX);
34 | public static final boolean OTHER = (osType == OSType.OS_TYPE_OTHER);
35 |
36 | public static void main(String[] args) {
37 | System.out.println(OSUtils.WINDOWS);
38 | System.out.println(OSUtils.LINUX);
39 | System.out.println(OSUtils.MAC);
40 | System.out.println("OSUtils.main()");
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/util/ObjectUtil.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.util;
2 |
3 | import java.beans.PropertyDescriptor;
4 | import java.lang.reflect.Field;
5 | import java.lang.reflect.Method;
6 | import java.util.ArrayList;
7 | import java.util.Arrays;
8 | import java.util.Date;
9 | import java.util.List;
10 |
11 | /**
12 | * Object对象工具
13 | * @author zhanghaishan
14 | * @version V1.0
15 | * 2017/12/18.
16 | */
17 | public class ObjectUtil {
18 |
19 | /**
20 | * 获取所有函数
21 | * @param t 类
22 | * @param methods 方法
23 | * @param index 深度
24 | */
25 | public void getMethods(Class t, List methods, Integer index){
26 |
27 | methods.addAll(Arrays.asList(t.getMethods()));
28 |
29 | if(index!=null){
30 | index = index -1;
31 | if(index<=0){
32 | return;
33 | }
34 | }
35 |
36 | Class t1 = t.getSuperclass();
37 | if (t1.getSimpleName().equals("Object")) {
38 | return;
39 | }
40 | getMethods(t1, methods,index);
41 | }
42 |
43 | /**
44 | * 获取所有属性
45 | * @param t 类
46 | * @param fields 属性
47 | * @param index 深度
48 | */
49 | public void getFields(Class t, List fields, Integer index) {
50 |
51 | fields.addAll(Arrays.asList(t.getDeclaredFields()));
52 |
53 | if(index!=null){
54 | index = index -1;
55 | if(index<=0){
56 | return;
57 | }
58 | }
59 |
60 | Class t1 = t.getSuperclass();
61 | if (t1.getSimpleName().equals("Object")) {
62 | return;
63 | }
64 | getFields(t1, fields,index);
65 | }
66 |
67 | /**
68 | * 将空属性附上默认值
69 | * @param obj 对象
70 | * @param notSet 不设置为空的属性
71 | */
72 | public void setNullFields(T obj, List notSet){
73 | if(obj==null){
74 | return;
75 | }
76 | Class entityClass = obj.getClass();
77 |
78 | List entityFields = new ArrayList();
79 | getFields(entityClass, entityFields,null);
80 |
81 | for(Field field:entityFields){
82 | if(field.getName().equals("serialVersionUID")){
83 | continue;
84 | }
85 |
86 | if(notSet!=null&¬Set.contains(field.getName())){
87 | continue;
88 | }
89 |
90 | try{
91 | PropertyDescriptor pd = new PropertyDescriptor(field.getName(), entityClass);
92 | Method get = pd.getReadMethod();
93 | Object getValue = get.invoke(obj);
94 |
95 | if(getValue==null){
96 |
97 | Method set = pd.getWriteMethod();
98 |
99 | Class fieldClass = field.getType();
100 | if(fieldClass.equals(String.class)){
101 | set.invoke(obj,new String(""));
102 | }
103 |
104 | if(fieldClass.equals(Integer.class)){
105 | set.invoke(obj,new Integer(0));
106 | }
107 |
108 | if(fieldClass.equals(Double.class)){
109 | set.invoke(obj,new Double(0));
110 | }
111 |
112 | if(fieldClass.equals(Float.class)){
113 | set.invoke(obj,new Float(0));
114 | }
115 |
116 | if(fieldClass.equals(Date.class)){
117 | set.invoke(obj,new Date());
118 | }
119 | }
120 |
121 | }catch (Exception e){
122 | e.printStackTrace();;
123 | }
124 |
125 | }
126 |
127 | }
128 |
129 | /**
130 | * 给空属性附上默认值
131 | * @param objs 对象集合
132 | * @param notSet 不设置空的属性
133 | */
134 | public void setNullFields(List objs,List notSet){
135 | if(objs!=null){
136 | for(int i=0;i map){
107 | if(map!=null){
108 | Set keys = map.keySet();
109 | for(String key : keys){
110 | String val = map.get(key);
111 | str = str.replaceAll(key,val);
112 | }
113 | }
114 | return str;
115 | }
116 |
117 | /**
118 | * 提取字符串里的数字
119 | * @param str 字符串
120 | * @return 数字
121 | */
122 | public static String findNumber(String str){
123 | String regEx="[^0-9]";
124 | String newStr = findString(str,regEx);
125 | return newStr;
126 | }
127 |
128 | /**
129 | * 根据正则提取字符串
130 | * @param str 字符串
131 | * @param regEx 正则
132 | * @return 结果
133 | */
134 | public static String findString(String str,String regEx){
135 | if(str==null){
136 | return null;
137 | }
138 | Pattern p = Pattern.compile(regEx);
139 | Matcher m = p.matcher(str);
140 | String newStr = m.replaceAll("").trim();
141 | return newStr;
142 | }
143 |
144 | /**
145 | * 根据需要复制的字符串长度进行复制拼接字符串
146 | * @param str 字符串
147 | * @param cloneNum 需要拼接的次数
148 | * @return 结果
149 | */
150 | public static String cloneAndAppend(String str,int cloneNum){
151 | String newStr = str;
152 | for(int i=0;i findStringsByRegs(String regex, String str){
165 | List strs = new ArrayList<>();
166 | Pattern r = Pattern.compile(regex);
167 | Matcher ma = r.matcher(str);
168 | while (ma.find()){
169 | String findStr = ma.group(0);
170 | if(findStr!=null&&findStr.length()>0){
171 | strs.add(findStr);
172 | }
173 | }
174 | return strs;
175 | }
176 |
177 | /**
178 | * 查询字符串
179 | * @param regex 正则
180 | * @param str 字符串
181 | * @return 结果
182 | */
183 | public static String findStringsByRegsOne(String regex, String str){
184 | List strs = findStringsByRegs(regex,str);
185 | String result = strs.size()==0? null : strs.get(0);
186 | return result;
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/main/java/org/mountcloud/ffmepg/util/UUIDUtil.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmepg.util;
2 |
3 | import java.util.UUID;
4 |
5 | /**
6 | * UUID工具
7 | * @author zhanghaishan
8 | * @version V1.0
9 | * com.ugirls.util
10 | * 2017/12/28.
11 | */
12 | public class UUIDUtil {
13 |
14 | /**
15 | * 返回一个全UUID
16 | * @return 完全UUID
17 | */
18 | public static String getUUID(){
19 | return UUID.randomUUID().toString();
20 | }
21 |
22 | /**
23 | * 返回一个没有减号的UUID
24 | * @return 精简后的UUID
25 | */
26 | public static String getUUIDSimpl(){
27 | UUID uuid = UUID.randomUUID();
28 | return uuid.toString().replaceAll("\\-", "");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/java/org/mountcloud/ffmpeg/TestTask.java:
--------------------------------------------------------------------------------
1 | package org.mountcloud.ffmpeg;
2 |
3 | import org.junit.Test;
4 | import org.mountcloud.ffmepg.operation.ffmpeg.vidoe.FFMpegVideoFormatM3u8;
5 | import org.mountcloud.ffmepg.operation.ffmpeg.vidoe.FFMpegVideoInfo;
6 | import org.mountcloud.ffmepg.result.defaultResult.FFVideoInfoResult;
7 | import org.mountcloud.ffmepg.task.bean.FFTaskStateEnum;
8 | import org.mountcloud.ffmepg.task.bean.tasks.FFMepgVideoFormatM3u8Task;
9 | import org.mountcloud.ffmepg.task.bean.tasks.FFMepgVideoInfoTask;
10 | import org.mountcloud.ffmepg.task.context.FFTaskContext;
11 |
12 | public class TestTask {
13 |
14 | @Test
15 | public void testM3u8(){
16 | FFMpegVideoFormatM3u8 m3u8Operation = new FFMpegVideoFormatM3u8();
17 | m3u8Operation.setVideoFileName("D:\\test\\test.mp4");
18 | m3u8Operation.setBitrate("2048k");
19 | m3u8Operation.setTimes(5);
20 | m3u8Operation.setM3u8File("D:\\test\\m3u8\\test.m3u8");
21 | m3u8Operation.setTsFiles("D:\\test\\m3u8\\test%5d.ts");
22 |
23 | System.out.println(m3u8Operation.toString());
24 |
25 | FFMepgVideoFormatM3u8Task task = new FFMepgVideoFormatM3u8Task(m3u8Operation);
26 |
27 | FFTaskContext.getContext().addTask(task);
28 |
29 | while (!task.getProgress().getState().equals(FFTaskStateEnum.COMPLETE)){
30 | System.out.println(task.getProgress().getProgress());
31 | try {
32 | Thread.sleep(1000);
33 | } catch (InterruptedException e) {
34 | e.printStackTrace();
35 | }
36 | }
37 | }
38 |
39 |
40 | @Test
41 | public void testInfo(){
42 | FFVideoInfoResult result = new FFVideoInfoResult();
43 |
44 | FFMpegVideoInfo ffMpegVideoInfo = new FFMpegVideoInfo();
45 | ffMpegVideoInfo.setVideoUrl("D:\\test\\test.mp4");
46 | FFMepgVideoInfoTask videoInfoTask = new FFMepgVideoInfoTask(result,ffMpegVideoInfo);
47 |
48 | FFTaskContext.getContext().submit(videoInfoTask,null);
49 |
50 | System.out.println(result.getTimeLengthSec());
51 | System.out.println(result.getTimeLength());
52 | System.out.println(result.getStartTime());
53 | System.out.println(result.getBitrate());
54 | System.out.println(result.getWidth());
55 | System.out.println(result.getHeight());
56 | System.out.println(result.getFps());
57 | System.out.println(result.getTbr());
58 | System.out.println(result.getTbn());
59 | System.out.println(result.getTbc());
60 | }
61 | }
62 |
--------------------------------------------------------------------------------