Skip to content

Commit 70d4e6c

Browse files
authored
Merge pull request #37 from Tencent/feature/vap_java_tool
vaptool java
2 parents 841f465 + 0b40b94 commit 70d4e6c

344 files changed

Lines changed: 1394 additions & 285 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Android/PlayerProj/animplayer/publish.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ ext {
2323
// library artifact(单个module一般就填写library name)
2424
artifact = 'animplayer'
2525
libraryName = 'animplayer'
26-
libraryVersion = '2.0.9'
26+
libraryVersion = '2.0.10'
2727
libraryDescription = ''
2828
// bintrayName 是你在网页Repository页面能看到的名称
2929
bintrayName = 'vap'

Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimConfigManager.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,21 @@ class AnimConfigManager(val player: AnimPlayer) {
3636
* 解析配置
3737
* @return true 解析成功 false 解析失败
3838
*/
39-
fun parseConfig(fileContainer: FileContainer, defaultVideoMode: Int, defaultFps: Int): Int {
39+
fun parseConfig(fileContainer: FileContainer, enableVersion1: Boolean, defaultVideoMode: Int, defaultFps: Int): Int {
4040
try {
4141
isParsingConfig = true
4242
// 解析vapc
4343
val time = SystemClock.elapsedRealtime()
4444
val result = parse(fileContainer, defaultVideoMode, defaultFps)
45-
ALog.i(TAG, "parseConfig cost=${SystemClock.elapsedRealtime() - time}ms")
45+
ALog.i(TAG, "parseConfig cost=${SystemClock.elapsedRealtime() - time}ms enableVersion1=$enableVersion1 result=$result")
4646
if (!result) {
4747
isParsingConfig = false
4848
return Constant.REPORT_ERROR_TYPE_PARSE_CONFIG
4949
}
50+
if (config?.isDefaultConfig == true && !enableVersion1) {
51+
isParsingConfig = false
52+
return Constant.REPORT_ERROR_TYPE_PARSE_CONFIG
53+
}
5054
// 插件解析配置
5155
val resultCode = config?.let {
5256
player.pluginManager.onConfigCreate(it)

Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimPlayer.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class AnimPlayer(val animView: AnimView) {
4242
}
4343
var supportMaskBoolean : Boolean = false
4444
var maskEdgeBlurBoolean : Boolean = false
45+
// 是否兼容老版本 默认不兼容
46+
var enableVersion1 : Boolean = false
4547
// 视频模式
4648
var videoMode: Int = Constant.VIDEO_MODE_SPLIT_HORIZONTAL
4749
var isDetachedFromWindow = false
@@ -79,7 +81,7 @@ class AnimPlayer(val animView: AnimView) {
7981
}
8082
// 在线程中解析配置
8183
decoder?.renderThread?.handler?.post {
82-
val result = configManager.parseConfig(fileContainer, videoMode, fps)
84+
val result = configManager.parseConfig(fileContainer, enableVersion1, videoMode, fps)
8385
if (result != Constant.OK) {
8486
decoder?.onFailed(result, Constant.getErrorMsg(result))
8587
isStartRunning = false

Android/PlayerProj/animplayer/src/main/java/com/tencent/qgame/animplayer/AnimView.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@ open class AnimView @JvmOverloads constructor(context: Context, attrs: Attribute
188188
player?.updateMaskConfig(maskConfig)
189189
}
190190

191+
192+
@Deprecated("Compatible older version mp4, default false")
193+
fun enableVersion1(enable: Boolean) {
194+
player?.enableVersion1 = enable
195+
}
196+
191197
// 兼容老版本视频模式
192198
@Deprecated("Compatible older version mp4")
193199
fun setVideoMode(mode: Int) {

Android/PlayerProj/animtool/src/main/java/com/tencent/qgame/playerproj/animtool/AnimTool.java

Lines changed: 106 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@
1515
*/
1616
package com.tencent.qgame.playerproj.animtool;
1717

18+
import com.tencent.qgame.playerproj.animtool.vapx.FrameSet;
19+
import com.tencent.qgame.playerproj.animtool.vapx.GetMaskFrame;
20+
import com.tencent.qgame.playerproj.animtool.vapx.SrcSet;
21+
1822
import javax.imageio.ImageIO;
1923
import java.awt.image.BufferedImage;
20-
import java.io.BufferedReader;
2124
import java.io.BufferedWriter;
2225
import java.io.File;
2326
import java.io.FileWriter;
2427
import java.io.IOException;
25-
import java.io.InputStreamReader;
26-
import java.util.concurrent.TimeUnit;
2728

2829
public class AnimTool {
2930

@@ -32,7 +33,8 @@ public class AnimTool {
3233
public static final String OUTPUT_DIR = "output"+ File.separator;
3334
public static final String FRAME_IMAGE_DIR = "frames"+ File.separator;
3435
public static final String VIDEO_FILE = "video.mp4";
35-
public static final String TEM_VIDEO_FILE = "tmp_video.mp4";
36+
public static final String TEMP_VIDEO_FILE = "tmp_video.mp4";
37+
public static final String TEMP_VIDEO_AUDIO_FILE = "tmp_video_audio.mp4";
3638
public static final String VAPC_BIN_FILE = "vapc.bin";
3739
public static final String VAPC_JSON_FILE = "vapc.json";
3840

@@ -42,6 +44,7 @@ public class AnimTool {
4244
private volatile int finishThreadCount = 0;
4345
private long time;
4446
private GetAlphaFrame getAlphaFrame = new GetAlphaFrame();
47+
private GetMaskFrame getMaskFrame = new GetMaskFrame();
4548
private IToolListener toolListener;
4649

4750
public void setToolListener(IToolListener toolListener) {
@@ -57,7 +60,7 @@ public void create(final CommonArg commonArg, final boolean needVideo) throws Ex
5760
createAllFrameImage(commonArg, new Runnable() {
5861
@Override
5962
public void run() {
60-
if (needVideo) {
63+
if (finalCheck(commonArg) && needVideo) {
6164
// 最终生成视频文件
6265
createVideo(commonArg);
6366
}
@@ -71,7 +74,23 @@ public void run() {
7174
* @return
7275
*/
7376
private boolean checkCommonArg(CommonArg commonArg) throws Exception {
74-
return CommonArgTool.autoFillAndCheck(commonArg);
77+
return CommonArgTool.autoFillAndCheck(commonArg, toolListener);
78+
}
79+
80+
private boolean finalCheck(CommonArg commonArg) {
81+
if (commonArg.isVapx) {
82+
if (commonArg.srcSet.srcs.isEmpty()) {
83+
TLog.i(TAG, "vapx error: src is empty");
84+
return false;
85+
}
86+
for (SrcSet.Src src : commonArg.srcSet.srcs) {
87+
if (src.w <=0 || src.h <= 0) {
88+
TLog.i(TAG, "vapx error: src.id=" + src.srcId + ",src.w=" + src.w + ",src.h=" + src.h);
89+
return false;
90+
}
91+
}
92+
}
93+
return true;
7594
}
7695

7796
private void createAllFrameImage(final CommonArg commonArg, final Runnable finishRunnable) throws Exception{
@@ -107,6 +126,11 @@ private void createAllFrameImage(final CommonArg commonArg, final Runnable finis
107126
@Override
108127
public void run() {
109128
for(int i = threadIndexSet[k][0]; i<threadIndexSet[k][1]; i++) {
129+
try {
130+
createFrame(commonArg, i);
131+
} catch (Exception e) {
132+
e.printStackTrace();
133+
}
110134
synchronized (AnimTool.class) {
111135
totalP++;
112136
float progress = totalP * 1.0f / commonArg.totalFrame;
@@ -116,11 +140,6 @@ public void run() {
116140
TLog.i(TAG, "progress " + progress);
117141
}
118142
}
119-
try {
120-
createFrame(commonArg, i);
121-
} catch (Exception e) {
122-
e.printStackTrace();
123-
}
124143
}
125144
synchronized (AnimTool.class) {
126145
finishThreadCount++;
@@ -141,18 +160,21 @@ public void run() {
141160
}
142161

143162
private void createFrame(CommonArg commonArg, int frameIndex) throws Exception {
144-
int w = commonArg.videoW;
145-
int h = commonArg.videoH;
146163
File inputFile = new File(commonArg.inputPath + String.format("%03d", frameIndex)+".png");
147-
GetAlphaFrame.AlphaFrameOut videoFrame = getAlphaFrame.createFrame(commonArg.orin, w, h,
148-
commonArg.gap, commonArg.wFill, commonArg.hFill, inputFile);
164+
GetAlphaFrame.AlphaFrameOut videoFrame = getAlphaFrame.createFrame(commonArg, inputFile);
165+
if (commonArg.isVapx) {
166+
FrameSet.FrameObj frameObj = getMaskFrame.getFrameObj(frameIndex, commonArg, videoFrame.argb);
167+
if (frameObj != null) {
168+
commonArg.frameSet.frameObjs.add(frameObj);
169+
}
170+
}
149171
if (videoFrame == null) {
150172
TLog.i(TAG, "frameIndex="+frameIndex +" is empty");
151173
return;
152174
}
153175
// 最后保存图片
154-
BufferedImage outBuf = new BufferedImage(videoFrame.outW, videoFrame.outH, BufferedImage.TYPE_INT_ARGB);
155-
outBuf.setRGB(0,0, videoFrame.outW, videoFrame.outH, videoFrame.argb, 0, videoFrame.outW);
176+
BufferedImage outBuf = new BufferedImage(commonArg.outputW, commonArg.outputH, BufferedImage.TYPE_INT_ARGB);
177+
outBuf.setRGB(0,0, commonArg.outputW, commonArg.outputH, videoFrame.argb, 0, commonArg.outputW);
156178

157179
File outputFile = new File(commonArg.frameOutputPath + String.format("%03d", frameIndex) +".png");
158180
ImageIO.write(outBuf, "PNG", outputFile);
@@ -180,17 +202,30 @@ private void createVideo(CommonArg commonArg){
180202
TLog.i(TAG, "createMp4 fail");
181203
return;
182204
}
205+
String tempVideoName = TEMP_VIDEO_FILE;
206+
if (commonArg.needAudio) {
207+
result = mergeAudio2Mp4(commonArg, tempVideoName);
208+
if (!result) {
209+
TLog.i(TAG, "mergeAudio2Mp4 fail");
210+
return;
211+
}
212+
tempVideoName = TEMP_VIDEO_AUDIO_FILE;
213+
}
214+
183215
String input = commonArg.outputPath + VAPC_JSON_FILE;
184216
// 由json变为bin文件
185217
String vapcBinPath = mp4BoxTool(input, commonArg.outputPath);
186218
// 将bin文件合并到mp4里
187-
result = mergeBin2Mp4(commonArg, vapcBinPath, commonArg.outputPath);
219+
result = mergeBin2Mp4(commonArg, vapcBinPath, tempVideoName, commonArg.outputPath);
188220
if (!result) {
189221
TLog.i(TAG, "mergeBin2Mp4 fail");
190222
return;
191223
}
192224
// 删除临时视频文件
193-
new File(commonArg.outputPath + TEM_VIDEO_FILE).delete();
225+
new File(commonArg.outputPath + TEMP_VIDEO_FILE).delete();
226+
if (commonArg.needAudio) {
227+
new File(commonArg.outputPath + TEMP_VIDEO_AUDIO_FILE).delete();
228+
}
194229
new File(commonArg.outputPath + VAPC_BIN_FILE).delete();
195230
// 计算文件md5
196231
String md5 = new Md5Util().getFileMD5(new File(commonArg.outputPath + VIDEO_FILE), commonArg.outputPath);
@@ -205,36 +240,34 @@ private void createVideo(CommonArg commonArg){
205240
* @param commonArg
206241
*/
207242
private void createVapcJson(CommonArg commonArg) {
208-
String json = "{\"info\":{\"v\":$(v),\"f\":$(f),\"w\":$(w),\"h\":$(h),\"videoW\":$(videoW),\"videoH\":$(videoH),\"orien\":0,\"fps\":$(fps),\"isVapx\":0,\"aFrame\":$(aFrame),\"rgbFrame\":$(rgbFrame)}}";
209-
json = json.replace("$(v)", String.valueOf(commonArg.version));
210-
json = json.replace("$(f)", String.valueOf(commonArg.totalFrame));
211-
json = json.replace("$(w)", String.valueOf(commonArg.videoW));
212-
json = json.replace("$(h)", String.valueOf(commonArg.videoH));
213-
json = json.replace("$(fps)", String.valueOf(commonArg.fps));
214-
int realW = 0;
215-
int realH = 0;
216-
int cx, cy;
217-
String aFrame = "[0,0,"+commonArg.videoW+","+commonArg.videoH+"]";
218-
String rgbFrame = "[0,0,0,0]";
219-
if (commonArg.orin == CommonArg.ORIN_H) { // 水平对齐
220-
realW = 2 * commonArg.videoW + commonArg.gap;
221-
realH = commonArg.videoH;
222-
cx = commonArg.videoW + commonArg.gap;
223-
cy = 0;
224-
} else { // 上下对齐
225-
realW = commonArg.videoW;
226-
realH = 2 * commonArg.videoH + commonArg.gap;
227-
cx = 0;
228-
cy = commonArg.videoH + commonArg.gap;
243+
244+
String json = "\"info\":{" +
245+
"\"v\":" + commonArg.version + "," +
246+
"\"f\":" + commonArg.totalFrame + "," +
247+
"\"w\":" + commonArg.rgbPoint.w + "," +
248+
"\"h\":" + commonArg.rgbPoint.h + "," +
249+
"\"fps\":" + commonArg.fps + "," +
250+
"\"videoW\":" + commonArg.outputW + "," +
251+
"\"videoH\":" + commonArg.outputH + "," +
252+
"\"aFrame\":" + commonArg.alphaPoint.toString() + "," +
253+
"\"rgbFrame\":" + commonArg.rgbPoint.toString() + "," +
254+
"\"isVapx\":" + (commonArg.isVapx ? 1 : 0) + "," +
255+
"\"orien\":" + 0 +
256+
"}";
257+
TLog.i(TAG, "{" + json + "}");
258+
259+
StringBuilder sb = new StringBuilder();
260+
sb.append("{");
261+
sb.append(json);
262+
if (commonArg.isVapx) {
263+
sb.append(",");
264+
sb.append(commonArg.srcSet.toString());
265+
sb.append(",");
266+
sb.append(commonArg.frameSet.toString());
229267
}
230-
rgbFrame = "["+cx+","+cy+","+commonArg.videoW+","+commonArg.videoH+"]";
231-
232-
realW += commonArg.wFill;
233-
realH += commonArg.hFill;
234-
json = json.replace("$(videoW)", String.valueOf(realW));
235-
json = json.replace("$(videoH)", String.valueOf(realH));
236-
json = json.replace("$(aFrame)", aFrame);
237-
json = json.replace("$(rgbFrame)", rgbFrame);
268+
sb.append("}");
269+
json = sb.toString();
270+
238271
try {
239272
BufferedWriter writer = new BufferedWriter(new FileWriter(commonArg.outputPath + VAPC_JSON_FILE));
240273
writer.write(json);
@@ -244,8 +277,6 @@ private void createVapcJson(CommonArg commonArg) {
244277
e.printStackTrace();
245278
throw new RuntimeException();
246279
}
247-
TLog.i(TAG,json);
248-
249280
}
250281

251282

@@ -254,8 +285,6 @@ private void createVapcJson(CommonArg commonArg) {
254285

255286
/**
256287
* 创建mp4
257-
* @param commonArg
258-
* @throws Exception
259288
*/
260289
private boolean createMp4(CommonArg commonArg, String videoPath, String frameImagePath) throws Exception {
261290
String[] cmd = null;
@@ -269,17 +298,18 @@ private boolean createMp4(CommonArg commonArg, String videoPath, String frameIma
269298
"-level", "4.0",
270299
"-tag:v", "hvc1",
271300
"-bufsize", "2000k",
272-
"-y", videoPath + TEM_VIDEO_FILE};
301+
"-y", videoPath + TEMP_VIDEO_FILE};
273302
} else {
274303
cmd = new String[]{commonArg.ffmpegCmd, "-r", String.valueOf(commonArg.fps),
275304
"-i", frameImagePath + "%03d.png",
276305
"-pix_fmt", "yuv420p",
277306
"-vcodec", "libx264",
278307
"-b:v", "3000k",
279-
"-profile:v", "baseline",
280-
"-level", "3.0",
308+
"-profile:v", "main",
309+
"-level", "4.0",
281310
"-bf", "0",
282-
"-y", videoPath + TEM_VIDEO_FILE};
311+
"-bufsize", "3000k",
312+
"-y", videoPath + TEMP_VIDEO_FILE};
283313
}
284314

285315
TLog.i(TAG, "run createMp4");
@@ -288,13 +318,28 @@ private boolean createMp4(CommonArg commonArg, String videoPath, String frameIma
288318
return result == 0;
289319
}
290320

321+
/**
322+
* 合并音频文件
323+
*/
324+
private boolean mergeAudio2Mp4(CommonArg commonArg, String tempVideoFile) throws Exception {
325+
String[] cmd = new String[] {commonArg.ffmpegCmd,
326+
"-i", commonArg.audioPath,
327+
"-i", commonArg.outputPath + tempVideoFile,
328+
"-c:v", "copy",
329+
"-c:a", "aac",
330+
"-y", commonArg.outputPath + TEMP_VIDEO_AUDIO_FILE};
331+
TLog.i(TAG, "run mergeAudio2Mp4");
332+
int result = ProcessUtil.run(cmd);
333+
TLog.i(TAG, "mergeAudio2Mp4 result=" + (result == 0? "success" : "fail"));
334+
return result == 0;
335+
}
336+
337+
291338
/**
292339
* 合并vapc.bin到mp4里
293-
* @param inputFile
294-
* @throws Exception
295340
*/
296-
private boolean mergeBin2Mp4(CommonArg commonArg, String inputFile, String videoPath) throws Exception{
297-
String[] cmd = new String[] {commonArg.mp4editCmd, "--insert", ":"+inputFile+":1", videoPath + TEM_VIDEO_FILE, videoPath + VIDEO_FILE};
341+
private boolean mergeBin2Mp4(CommonArg commonArg, String inputFile, String tempVideoFile, String videoPath) throws Exception{
342+
String[] cmd = new String[] {commonArg.mp4editCmd, "--insert", ":"+inputFile+":1", videoPath + tempVideoFile, videoPath + VIDEO_FILE};
298343
TLog.i(TAG, "run mergeBin2Mp4");
299344
int result = ProcessUtil.run(cmd);
300345
TLog.i(TAG, "mergeBin2Mp4 result=" + (result == 0? "success" : "fail"));
@@ -313,6 +358,7 @@ private String mp4BoxTool(String inputFile, String outputPath) throws Exception
313358

314359
public interface IToolListener {
315360
void onProgress(float progress);
361+
void onWarning(String msg);
316362
void onError();
317363
void onComplete();
318364
}

0 commit comments

Comments
 (0)