();
1242 |
1243 | cmd.add(mFfmpegBin);
1244 | cmd.add("-y");
1245 | cmd.add("-i");
1246 |
1247 | cmd.add(new File(in.path).getCanonicalPath());
1248 |
1249 | InfoParser ip = new InfoParser(in);
1250 | execFFMPEG(cmd,ip, null);
1251 |
1252 | try{Thread.sleep(200);}
1253 | catch (Exception e){}
1254 |
1255 |
1256 | return in;
1257 |
1258 | }
1259 |
1260 | private class InfoParser implements ShellCallback {
1261 |
1262 | private Clip mMedia;
1263 | private int retValue;
1264 |
1265 | public InfoParser (Clip media)
1266 | {
1267 | mMedia = media;
1268 | }
1269 |
1270 | @Override
1271 | public void shellOut(String shellLine) {
1272 | if (shellLine.contains("Duration:"))
1273 | {
1274 |
1275 | // Duration: 00:01:01.75, start: 0.000000, bitrate: 8184 kb/s
1276 |
1277 | String[] timecode = shellLine.split(",")[0].split(":");
1278 |
1279 |
1280 | double duration = 0;
1281 |
1282 | duration = Double.parseDouble(timecode[1].trim())*60*60; //hours
1283 | duration += Double.parseDouble(timecode[2].trim())*60; //minutes
1284 | duration += Double.parseDouble(timecode[3].trim()); //seconds
1285 |
1286 | mMedia.duration = duration;
1287 |
1288 |
1289 | }
1290 |
1291 | // Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080, 16939 kb/s, 30.02 fps, 30 tbr, 90k tbn, 180k tbc
1292 | else if (shellLine.contains(": Video:"))
1293 | {
1294 | String[] line = shellLine.split(":");
1295 | String[] videoInfo = line[3].split(",");
1296 |
1297 | mMedia.videoCodec = videoInfo[0];
1298 | }
1299 |
1300 | //Stream #0:1(eng): Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, s16, 121 kb/s
1301 | else if (shellLine.contains(": Audio:"))
1302 | {
1303 | String[] line = shellLine.split(":");
1304 | String[] audioInfo = line[3].split(",");
1305 |
1306 | mMedia.audioCodec = audioInfo[0];
1307 |
1308 | }
1309 |
1310 |
1311 | //
1312 | //Stream #0.0(und): Video: h264 (Baseline), yuv420p, 1280x720, 8052 kb/s, 29.97 fps, 90k tbr, 90k tbn, 180k tbc
1313 | //Stream #0.1(und): Audio: mp2, 22050 Hz, 2 channels, s16, 127 kb/s
1314 |
1315 | }
1316 |
1317 | @Override
1318 | public void processComplete(int exitValue) {
1319 | retValue = exitValue;
1320 |
1321 | }
1322 | }
1323 |
1324 | private class StreamGobbler extends Thread
1325 | {
1326 | InputStream is;
1327 | String type;
1328 | ShellCallback sc;
1329 |
1330 | StreamGobbler(InputStream is, String type, ShellCallback sc)
1331 | {
1332 | this.is = is;
1333 | this.type = type;
1334 | this.sc = sc;
1335 | }
1336 |
1337 | public void run()
1338 | {
1339 | try
1340 | {
1341 | InputStreamReader isr = new InputStreamReader(is);
1342 | BufferedReader br = new BufferedReader(isr);
1343 | String line=null;
1344 | while ( (line = br.readLine()) != null)
1345 | if (sc != null)
1346 | sc.shellOut(line);
1347 |
1348 | } catch (IOException ioe)
1349 | {
1350 | // Log.e(TAG,"error reading shell slog",ioe);
1351 | ioe.printStackTrace();
1352 | }
1353 | }
1354 | }
1355 |
1356 | public static Bitmap getVideoFrame(String videoPath,long frameTime) throws Exception {
1357 | MediaMetadataRetriever retriever = new MediaMetadataRetriever();
1358 |
1359 | try {
1360 | retriever.setDataSource(videoPath);
1361 | return retriever.getFrameAtTime(frameTime, MediaMetadataRetriever.OPTION_CLOSEST);
1362 |
1363 | } finally {
1364 | try {
1365 | retriever.release();
1366 | } catch (RuntimeException ex) {
1367 | }
1368 | }
1369 | }
1370 | }
1371 |
1372 | /*
1373 | * Main options:
1374 | -L show license
1375 | -h show help
1376 | -? show help
1377 | -help show help
1378 | --help show help
1379 | -version show version
1380 | -formats show available formats
1381 | -codecs show available codecs
1382 | -bsfs show available bit stream filters
1383 | -protocols show available protocols
1384 | -filters show available filters
1385 | -pix_fmts show available pixel formats
1386 | -sample_fmts show available audio sample formats
1387 | -loglevel loglevel set libav* logging level
1388 | -v loglevel set libav* logging level
1389 | -debug flags set debug flags
1390 | -report generate a report
1391 | -f fmt force format
1392 | -i filename input file name
1393 | -y overwrite output files
1394 | -n do not overwrite output files
1395 | -c codec codec name
1396 | -codec codec codec name
1397 | -pre preset preset name
1398 | -t duration record or transcode "duration" seconds of audio/video
1399 | -fs limit_size set the limit file size in bytes
1400 | -ss time_off set the start time offset
1401 | -itsoffset time_off set the input ts offset
1402 | -itsscale scale set the input ts scale
1403 | -timestamp time set the recording timestamp ('now' to set the current time)
1404 | -metadata string=string add metadata
1405 | -dframes number set the number of data frames to record
1406 | -timelimit limit set max runtime in seconds
1407 | -target type specify target file type ("vcd", "svcd", "dvd", "dv", "dv50", "pal-vcd", "ntsc-svcd", ...)
1408 | -xerror exit on error
1409 | -frames number set the number of frames to record
1410 | -tag fourcc/tag force codec tag/fourcc
1411 | -filter filter_list set stream filterchain
1412 | -stats print progress report during encoding
1413 | -attach filename add an attachment to the output file
1414 | -dump_attachment filename extract an attachment into a file
1415 | -bsf bitstream_filters A comma-separated list of bitstream filters
1416 | -dcodec codec force data codec ('copy' to copy stream)
1417 |
1418 | Advanced options:
1419 | -map file.stream[:syncfile.syncstream] set input stream mapping
1420 | -map_channel file.stream.channel[:syncfile.syncstream] map an audio channel from one stream to another
1421 | -map_meta_data outfile[,metadata]:infile[,metadata] DEPRECATED set meta data information of outfile from infile
1422 | -map_metadata outfile[,metadata]:infile[,metadata] set metadata information of outfile from infile
1423 | -map_chapters input_file_index set chapters mapping
1424 | -benchmark add timings for benchmarking
1425 | -dump dump each input packet
1426 | -hex when dumping packets, also dump the payload
1427 | -re read input at native frame rate
1428 | -loop_input deprecated, use -loop
1429 | -loop_output deprecated, use -loop
1430 | -vsync video sync method
1431 | -async audio sync method
1432 | -adrift_threshold threshold audio drift threshold
1433 | -copyts copy timestamps
1434 | -copytb source copy input stream time base when stream copying
1435 | -shortest finish encoding within shortest input
1436 | -dts_delta_threshold threshold timestamp discontinuity delta threshold
1437 | -copyinkf copy initial non-keyframes
1438 | -q q use fixed quality scale (VBR)
1439 | -qscale q use fixed quality scale (VBR)
1440 | -streamid streamIndex:value set the value of an outfile streamid
1441 | -muxdelay seconds set the maximum demux-decode delay
1442 | -muxpreload seconds set the initial demux-decode delay
1443 | -fpre filename set options from indicated preset file
1444 |
1445 | Video options:
1446 | -vframes number set the number of video frames to record
1447 | -r rate set frame rate (Hz value, fraction or abbreviation)
1448 | -s size set frame size (WxH or abbreviation)
1449 | -aspect aspect set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)
1450 | -bits_per_raw_sample number set the number of bits per raw sample
1451 | -croptop size Removed, use the crop filter instead
1452 | -cropbottom size Removed, use the crop filter instead
1453 | -cropleft size Removed, use the crop filter instead
1454 | -cropright size Removed, use the crop filter instead
1455 | -padtop size Removed, use the pad filter instead
1456 | -padbottom size Removed, use the pad filter instead
1457 | -padleft size Removed, use the pad filter instead
1458 | -padright size Removed, use the pad filter instead
1459 | -padcolor color Removed, use the pad filter instead
1460 | -vn disable video
1461 | -vcodec codec force video codec ('copy' to copy stream)
1462 | -sameq use same quantizer as source (implies VBR)
1463 | -same_quant use same quantizer as source (implies VBR)
1464 | -pass n select the pass number (1 or 2)
1465 | -passlogfile prefix select two pass log file name prefix
1466 | -vf filter list video filters
1467 | -b bitrate video bitrate (please use -b:v)
1468 | -dn disable data
1469 |
1470 | Advanced Video options:
1471 | -pix_fmt format set pixel format
1472 | -intra use only intra frames
1473 | -vdt n discard threshold
1474 | -rc_override override rate control override for specific intervals
1475 | -deinterlace deinterlace pictures
1476 | -psnr calculate PSNR of compressed frames
1477 | -vstats dump video coding statistics to file
1478 | -vstats_file file dump video coding statistics to file
1479 | -intra_matrix matrix specify intra matrix coeffs
1480 | -inter_matrix matrix specify inter matrix coeffs
1481 | -top top=1/bottom=0/auto=-1 field first
1482 | -dc precision intra_dc_precision
1483 | -vtag fourcc/tag force video tag/fourcc
1484 | -qphist show QP histogram
1485 | -force_fps force the selected framerate, disable the best supported framerate selection
1486 | -force_key_frames timestamps force key frames at specified timestamps
1487 | -vbsf video bitstream_filters deprecated
1488 | -vpre preset set the video options to the indicated preset
1489 |
1490 | Audio options:
1491 | -aframes number set the number of audio frames to record
1492 | -aq quality set audio quality (codec-specific)
1493 | -ar rate set audio sampling rate (in Hz)
1494 | -ac channels set number of audio channels
1495 | -an disable audio
1496 | -acodec codec force audio codec ('copy' to copy stream)
1497 | -vol volume change audio volume (256=normal)
1498 | -rmvol volume rematrix volume (as factor)
1499 |
1500 | */
1501 |
1502 | /*
1503 | * //./ffmpeg -y -i test.mp4 -vframes 999999 -vf 'redact=blurbox.txt [out] [d], [d]nullsink' -acodec copy outputa.mp4
1504 |
1505 | //ffmpeg -v 10 -y -i /sdcard/org.witness.sscvideoproto/videocapture1042744151.mp4 -vcodec libx264
1506 | //-b 3000k -s 720x480 -r 30 -acodec copy -f mp4 -vf 'redact=/data/data/org.witness.sscvideoproto/redact_unsort.txt'
1507 | ///sdcard/org.witness.sscvideoproto/new.mp4
1508 |
1509 | //"-vf" , "redact=" + Environment.getExternalStorageDirectory().getPath() + "/" + PACKAGENAME + "/redact_unsort.txt",
1510 |
1511 |
1512 | // Need to make sure this will create a legitimate mp4 file
1513 | //"-acodec", "ac3", "-ac", "1", "-ar", "16000", "-ab", "32k",
1514 |
1515 |
1516 | String[] ffmpegCommand = {"/data/data/"+PACKAGENAME+"/ffmpeg", "-v", "10", "-y", "-i", recordingFile.getPath(),
1517 | "-vcodec", "libx264", "-b", "3000k", "-vpre", "baseline", "-s", "720x480", "-r", "30",
1518 | //"-vf", "drawbox=10:20:200:60:red@0.5",
1519 | "-vf" , "\"movie="+ overlayImage.getPath() +" [logo];[in][logo] overlay=0:0 [out]\"",
1520 | "-acodec", "copy",
1521 | "-f", "mp4", savePath.getPath()+"/output.mp4"};
1522 |
1523 |
1524 |
1525 |
1526 | //ffmpeg -i source-video.avi -s 480x320 -vcodec mpeg4 -acodec aac -ac 1 -ar 16000 -r 13 -ab 32000 -aspect 3:2 output-video.mp4/
1527 |
1528 |
1529 | */
1530 |
1531 |
1532 | /* concat doesn't seem to work
1533 | cmd.add("-i");
1534 |
1535 | StringBuffer concat = new StringBuffer();
1536 |
1537 | for (int i = 0; i < videos.size(); i++)
1538 | {
1539 | if (i > 0)
1540 | concat.append("|");
1541 |
1542 | concat.append(out.path + '.' + i + ".wav");
1543 |
1544 | }
1545 |
1546 | cmd.add("concat:\"" + concat.toString() + "\"");
1547 | */
1548 |
1549 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/ShellUtils.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
2 | /* See LICENSE for licensing information */
3 | package org.ffmpeg.android;
4 |
5 | import java.io.BufferedReader;
6 | import java.io.File;
7 | import java.io.IOException;
8 | import java.io.InputStreamReader;
9 | import java.io.OutputStreamWriter;
10 | import java.util.StringTokenizer;
11 |
12 |
13 | import android.util.Log;
14 |
15 | public class ShellUtils {
16 |
17 | //various console cmds
18 | public final static String SHELL_CMD_CHMOD = "chmod";
19 | public final static String SHELL_CMD_KILL = "kill -9";
20 | public final static String SHELL_CMD_RM = "rm";
21 | public final static String SHELL_CMD_PS = "ps";
22 | public final static String SHELL_CMD_PIDOF = "pidof";
23 |
24 | public final static String CHMOD_EXE_VALUE = "700";
25 |
26 | public static boolean isRootPossible()
27 | {
28 |
29 | StringBuilder log = new StringBuilder();
30 |
31 | try {
32 |
33 | // Check if Superuser.apk exists
34 | File fileSU = new File("/system/app/Superuser.apk");
35 | if (fileSU.exists())
36 | return true;
37 |
38 | fileSU = new File("/system/bin/su");
39 | if (fileSU.exists())
40 | return true;
41 |
42 | //Check for 'su' binary
43 | String[] cmd = {"which su"};
44 | int exitCode = ShellUtils.doShellCommand(null,cmd, new ShellCallback ()
45 | {
46 |
47 | @Override
48 | public void shellOut(String msg) {
49 |
50 | //System.out.print(msg);
51 |
52 | }
53 |
54 | @Override
55 | public void processComplete(int exitValue) {
56 | // TODO Auto-generated method stub
57 |
58 | }
59 |
60 | }, false, true).exitValue();
61 |
62 | if (exitCode == 0) {
63 | logMessage("Can acquire root permissions");
64 | return true;
65 |
66 | }
67 |
68 | } catch (IOException e) {
69 | //this means that there is no root to be had (normally) so we won't log anything
70 | logException("Error checking for root access",e);
71 |
72 | }
73 | catch (Exception e) {
74 | logException("Error checking for root access",e);
75 | //this means that there is no root to be had (normally)
76 | }
77 |
78 | logMessage("Could not acquire root permissions");
79 |
80 |
81 | return false;
82 | }
83 |
84 |
85 | public static int findProcessId(String command)
86 | {
87 | int procId = -1;
88 |
89 | try
90 | {
91 | procId = findProcessIdWithPidOf(command);
92 |
93 | if (procId == -1)
94 | procId = findProcessIdWithPS(command);
95 | }
96 | catch (Exception e)
97 | {
98 | try
99 | {
100 | procId = findProcessIdWithPS(command);
101 | }
102 | catch (Exception e2)
103 | {
104 | logException("Unable to get proc id for: " + command,e2);
105 | }
106 | }
107 |
108 | return procId;
109 | }
110 |
111 | //use 'pidof' command
112 | public static int findProcessIdWithPidOf(String command) throws Exception
113 | {
114 |
115 | int procId = -1;
116 |
117 | Runtime r = Runtime.getRuntime();
118 |
119 | Process procPs = null;
120 |
121 | String baseName = new File(command).getName();
122 | //fix contributed my mikos on 2010.12.10
123 | procPs = r.exec(new String[] {SHELL_CMD_PIDOF, baseName});
124 | //procPs = r.exec(SHELL_CMD_PIDOF);
125 |
126 | BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
127 | String line = null;
128 |
129 | while ((line = reader.readLine())!=null)
130 | {
131 |
132 | try
133 | {
134 | //this line should just be the process id
135 | procId = Integer.parseInt(line.trim());
136 | break;
137 | }
138 | catch (NumberFormatException e)
139 | {
140 | logException("unable to parse process pid: " + line,e);
141 | }
142 | }
143 |
144 |
145 | return procId;
146 |
147 | }
148 |
149 | //use 'ps' command
150 | public static int findProcessIdWithPS(String command) throws Exception
151 | {
152 |
153 | int procId = -1;
154 |
155 | Runtime r = Runtime.getRuntime();
156 |
157 | Process procPs = null;
158 |
159 | procPs = r.exec(SHELL_CMD_PS);
160 |
161 | BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream()));
162 | String line = null;
163 |
164 | while ((line = reader.readLine())!=null)
165 | {
166 | if (line.indexOf(' ' + command)!=-1)
167 | {
168 |
169 | StringTokenizer st = new StringTokenizer(line," ");
170 | st.nextToken(); //proc owner
171 |
172 | procId = Integer.parseInt(st.nextToken().trim());
173 |
174 | break;
175 | }
176 | }
177 |
178 |
179 |
180 | return procId;
181 |
182 | }
183 |
184 | public static int doShellCommand(String[] cmds, ShellCallback sc, boolean runAsRoot, boolean waitFor) throws Exception
185 | {
186 | return doShellCommand (null, cmds, sc, runAsRoot, waitFor).exitValue();
187 |
188 | }
189 |
190 | public static Process doShellCommand(Process proc, String[] cmds, ShellCallback sc, boolean runAsRoot, boolean waitFor) throws Exception
191 | {
192 |
193 |
194 | if (proc == null)
195 | {
196 | if (runAsRoot)
197 | proc = Runtime.getRuntime().exec("su");
198 | else
199 | proc = Runtime.getRuntime().exec("sh");
200 | }
201 |
202 | OutputStreamWriter out = new OutputStreamWriter(proc.getOutputStream());
203 |
204 | for (int i = 0; i < cmds.length; i++)
205 | {
206 | logMessage("executing shell cmd: " + cmds[i] + "; runAsRoot=" + runAsRoot + ";waitFor=" + waitFor);
207 |
208 | out.write(cmds[i]);
209 | out.write("\n");
210 | }
211 |
212 | out.flush();
213 | out.write("exit\n");
214 | out.flush();
215 |
216 | if (waitFor)
217 | {
218 |
219 | final char buf[] = new char[20];
220 |
221 | // Consume the "stdout"
222 | InputStreamReader reader = new InputStreamReader(proc.getInputStream());
223 | int read=0;
224 | while ((read=reader.read(buf)) != -1) {
225 | if (sc != null) sc.shellOut(new String(buf));
226 | }
227 |
228 | // Consume the "stderr"
229 | reader = new InputStreamReader(proc.getErrorStream());
230 | read=0;
231 | while ((read=reader.read(buf)) != -1) {
232 | if (sc != null) sc.shellOut(new String(buf));
233 | }
234 |
235 | proc.waitFor();
236 |
237 | }
238 |
239 | sc.processComplete(proc.exitValue());
240 |
241 | return proc;
242 |
243 | }
244 |
245 | public static void logMessage (String msg)
246 | {
247 |
248 | }
249 |
250 | public static void logException (String msg, Exception e)
251 | {
252 |
253 | }
254 |
255 | public interface ShellCallback
256 | {
257 | public void shellOut (String shellLine);
258 |
259 | public void processComplete (int exitValue);
260 | }
261 | }
262 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/filters/CropVideoFilter.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.filters;
2 |
3 | public class CropVideoFilter extends VideoFilter {
4 |
5 | private String mOutWidth;
6 | private String mOutHeight;
7 | private String mX;
8 | private String mY;
9 |
10 | public CropVideoFilter (String width, String height, String x, String y)
11 | {
12 | mOutWidth = width;
13 | mOutHeight = height;
14 | mX = x;
15 | mY = y;
16 | }
17 |
18 | @Override
19 | public String getFilterString() {
20 |
21 | StringBuffer result = new StringBuffer();
22 |
23 | result.append("crop=");
24 |
25 | if (mOutWidth != null)
26 | result.append(mOutWidth).append(":");
27 |
28 | if (mOutHeight != null)
29 | result.append(mOutHeight).append(":");
30 |
31 | if (mX != null)
32 | result.append(mX).append(":");
33 |
34 | if (mY != null)
35 | result.append(mY).append(":");
36 |
37 | result.deleteCharAt(result.length()-1); //remove the last semicolon!
38 |
39 | return result.toString();
40 | }
41 |
42 | }
43 |
44 | /*
45 | Crop the input video to out_w:out_h:x:y:keep_aspect
46 |
47 | The keep_aspect parameter is optional, if specified and set to a non-zero value will force the output display aspect ratio to be the same of the input, by changing the output sample aspect ratio.
48 |
49 | The out_w, out_h, x, y parameters are expressions containing the following constants:
50 |
51 | ‘x, y’
52 | the computed values for x and y. They are evaluated for each new frame.
53 |
54 | ‘in_w, in_h’
55 | the input width and height
56 |
57 | ‘iw, ih’
58 | same as in_w and in_h
59 |
60 | ‘out_w, out_h’
61 | the output (cropped) width and height
62 |
63 | ‘ow, oh’
64 | same as out_w and out_h
65 |
66 | ‘a’
67 | same as iw / ih
68 |
69 | ‘sar’
70 | input sample aspect ratio
71 |
72 | ‘dar’
73 | input display aspect ratio, it is the same as (iw / ih) * sar
74 |
75 | ‘hsub, vsub’
76 | horizontal and vertical chroma subsample values. For example for the pixel format "yuv422p" hsub is 2 and vsub is 1.
77 |
78 | ‘n’
79 | the number of input frame, starting from 0
80 |
81 | ‘pos’
82 | the position in the file of the input frame, NAN if unknown
83 |
84 | ‘t’
85 | timestamp expressed in seconds, NAN if the input timestamp is unknown
86 |
87 | The out_w and out_h parameters specify the expressions for the width and height of the output (cropped) video. They are evaluated just at the configuration of the filter.
88 |
89 | The default value of out_w is "in_w", and the default value of out_h is "in_h".
90 |
91 | The expression for out_w may depend on the value of out_h, and the expression for out_h may depend on out_w, but they cannot depend on x and y, as x and y are evaluated after out_w and out_h.
92 |
93 | The x and y parameters specify the expressions for the position of the top-left corner of the output (non-cropped) area. They are evaluated for each frame. If the evaluated value is not valid, it is approximated to the nearest valid value.
94 |
95 | The default value of x is "(in_w-out_w)/2", and the default value for y is "(in_h-out_h)/2", which set the cropped area at the center of the input image.
96 |
97 | The expression for x may depend on y, and the expression for y may depend on x.
98 |
99 | Follow some examples:
100 |
101 |
102 | # crop the central input area with size 100x100
103 | crop=100:100
104 |
105 | # crop the central input area with size 2/3 of the input video
106 | "crop=2/3*in_w:2/3*in_h"
107 |
108 | # crop the input video central square
109 | crop=in_h
110 |
111 | # delimit the rectangle with the top-left corner placed at position
112 | # 100:100 and the right-bottom corner corresponding to the right-bottom
113 | # corner of the input image.
114 | crop=in_w-100:in_h-100:100:100
115 |
116 | # crop 10 pixels from the left and right borders, and 20 pixels from
117 | # the top and bottom borders
118 | "crop=in_w-2*10:in_h-2*20"
119 |
120 | # keep only the bottom right quarter of the input image
121 | "crop=in_w/2:in_h/2:in_w/2:in_h/2"
122 |
123 | # crop height for getting Greek harmony
124 | "crop=in_w:1/PHI*in_w"
125 |
126 | # trembling effect
127 | "crop=in_w/2:in_h/2:(in_w-out_w)/2+((in_w-out_w)/2)*sin(n/10):(in_h-out_h)/2 +((in_h-out_h)/2)*sin(n/7)"
128 |
129 | # erratic camera effect depending on timestamp
130 | "crop=in_w/2:in_h/2:(in_w-out_w)/2+((in_w-out_w)/2)*sin(t*10):(in_h-out_h)/2 +((in_h-out_h)/2)*sin(t*13)"
131 |
132 | # set x depending on the value of y
133 | "crop=in_w/2:in_h/2:y:10+10*sin(n/10)"
134 | */
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/filters/DrawBoxVideoFilter.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.filters;
2 |
3 | import java.io.File;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 |
7 | import android.content.Context;
8 | import android.graphics.Bitmap;
9 | import android.graphics.Bitmap.Config;
10 | import android.graphics.Canvas;
11 | import android.graphics.Color;
12 | import android.graphics.Paint;
13 |
14 | public class DrawBoxVideoFilter extends OverlayVideoFilter {
15 |
16 | public int x;
17 | public int y;
18 | public int width;
19 | public int height;
20 | public String color;
21 |
22 | public DrawBoxVideoFilter (int x, int y, int width, int height, int alpha, String color, File tmpDir) throws Exception
23 | {
24 | this.x = x;
25 | this.y = y;
26 | this.width = width;
27 | this.height = height;
28 | this.color = color;
29 |
30 | if( alpha < 0 || alpha > 255 ) {
31 | throw new IllegalArgumentException("Alpha must be an integer betweeen 0 and 255");
32 | }
33 | Paint paint = new Paint();
34 | paint.setAlpha(alpha);
35 |
36 |
37 | Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
38 | bitmap.eraseColor(Color.parseColor(color));
39 |
40 | Bitmap temp_box = Bitmap.createBitmap(width, height, Config.ARGB_8888);
41 | Canvas canvas = new Canvas(temp_box);
42 | canvas.drawBitmap(bitmap, 0, 0, paint);
43 |
44 | File outputFile;
45 | outputFile = File.createTempFile("box_"+width+height+color, ".png", tmpDir);
46 | FileOutputStream os = new FileOutputStream(outputFile);
47 | temp_box.compress(Bitmap.CompressFormat.PNG, 100, os);
48 | overlayFile = outputFile;
49 | xParam = Integer.toString(x);
50 | yParam = Integer.toString(y);
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/filters/DrawTextVideoFilter.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.filters;
2 |
3 | import java.io.File;
4 |
5 | public class DrawTextVideoFilter extends VideoFilter {
6 |
7 | private String mX;
8 | private String mY;
9 | private String mText;
10 | private String mFontColor;
11 | private int mFontSize;
12 | private File mFileFont;
13 | private int mBox;
14 | private String mBoxColor;
15 |
16 | public final static String X_CENTERED = "(w-text_w)/2";
17 | public final static String Y_CENTERED = "(h-text_h-line_h)/2";
18 |
19 | public final static String X_LEFT = "0";
20 | public final static String Y_BOTTOM = "(h-text_h-line_h)";
21 |
22 | public DrawTextVideoFilter (String text)
23 | {
24 | mX = X_CENTERED;
25 | mY = Y_CENTERED;
26 |
27 | mText = text;
28 | mFontColor = "white";
29 | mFontSize = 36;
30 | mFileFont = new File("/system/fonts/Roboto-Regular.ttf");
31 | if (!mFileFont.exists())
32 | mFileFont = new File("/system/fonts/DroidSerif-Regular.ttf");
33 |
34 | mBox = 1;
35 | mBoxColor = "black@0.5";//0x00000000@1
36 |
37 | }
38 |
39 | public DrawTextVideoFilter (String text, String x, String y, String fontColor, int fontSize, File fontFile, boolean showBox, String boxColor, String boxOpacity)
40 | {
41 | mX = x;
42 | mY = y;
43 |
44 | mText = text;
45 | mFontColor = fontColor;
46 | mFontSize = fontSize;
47 |
48 | mFileFont = fontFile;
49 |
50 | mBox = showBox? 1 : 0;
51 | mBoxColor = boxColor + '@' + boxOpacity;
52 |
53 | }
54 |
55 | @Override
56 | public String getFilterString() {
57 |
58 | StringBuffer result = new StringBuffer ();
59 | result.append("drawtext=");
60 | result.append("fontfile='").append(mFileFont.getAbsolutePath()).append("':");
61 | result.append("text='").append(mText).append("':");
62 | result.append("x=").append(mX).append(":");
63 | result.append("y=").append(mY).append(":");
64 | result.append("fontcolor=").append(mFontColor).append(":");
65 | result.append("fontsize=").append(mFontSize).append(":");
66 | result.append("box=").append(mBox).append(":");
67 | result.append("boxcolor=").append(mBoxColor);
68 |
69 | return result.toString();
70 | }
71 |
72 | }
73 |
74 | /*
75 | * //mdout.videoFilter = "drawtext=fontfile=/system/fonts/DroidSans.ttf: text='this is awesome':x=(w-text_w)/2:y=H-60 :fontcolor=white :box=1:boxcolor=0x00000000@1";
76 |
77 | File fontFile = new File("/system/fonts/Roboto-Regular.ttf");
78 | if (!fontFile.exists())
79 | fontFile = new File("/system/fonts/DroidSans.ttf");
80 |
81 | mdout.videoFilter = "drawtext=fontfile='" + fontFile.getAbsolutePath() + "':text='this is awesome':x=(main_w-text_w)/2:y=50:fontsize=24:fontcolor=white";
82 | */
83 |
84 | /**
85 |
86 |
87 | /system/fonts
88 |
89 | AndroidClock.ttf
90 | AndroidClock_Highlight.ttf
91 | AndroidClock_Solid.ttf
92 | AndroidEmoji.ttf
93 | AnjaliNewLipi-light.ttf
94 | Clockopia.ttf
95 | DroidNaskh-Regular-SystemUI.ttf
96 | DroidNaskh-Regular.ttf
97 | DroidSans-Bold.ttf
98 | DroidSans.ttf
99 | DroidSansArmenian.ttf
100 | DroidSansDevanagari-Regular.ttf
101 | DroidSansEthiopic-Regular.ttf
102 | DroidSansFallback.ttf
103 | DroidSansGeorgian.ttf
104 | DroidSansHebrew-Bold.ttf
105 | DroidSansHebrew-Regular.ttf
106 | DroidSansMono.ttf
107 | DroidSansTamil-Bold.ttf
108 | DroidSansTamil-Regular.ttf
109 | DroidSansThai.ttf
110 | DroidSerif-Bold.ttf
111 | DroidSerif-BoldItalic.ttf
112 | DroidSerif-Italic.ttf
113 | DroidSerif-Regular.ttf
114 | Lohit-Bengali.ttf
115 | Lohit-Kannada.ttf
116 | Lohit-Telugu.ttf
117 | MTLmr3m.ttf
118 | Roboto-Bold.ttf
119 | Roboto-BoldItalic.ttf
120 | Roboto-Italic.ttf
121 | Roboto-Light.ttf
122 | Roboto-LightItalic.ttf
123 | Roboto-Regular.ttf
124 | RobotoCondensed-Bold.ttf
125 | RobotoCondensed-BoldItalic.ttf
126 | RobotoCondensed-Italic.ttf
127 | RobotoCondensed-Regular.ttf
128 | */
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/filters/FadeVideoFilter.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.filters;
2 |
3 | public class FadeVideoFilter extends VideoFilter {
4 |
5 | private String mAction; //in our out
6 | private int mStart;
7 | private int mLength;
8 |
9 | public FadeVideoFilter (String action, int start, int length)
10 | {
11 | mAction = action;
12 | mStart = start;
13 | mLength = length;
14 | }
15 |
16 | @Override
17 | public String getFilterString() {
18 |
19 | StringBuffer result = new StringBuffer ();
20 | result.append("fade=");
21 | result.append(mAction).append(':').append(mStart).append(':').append(mLength);
22 |
23 | return result.toString();
24 | }
25 |
26 | }
27 |
28 | ///fade=in:0:25, fade=out:975:25
29 |
30 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/filters/OverlayVideoFilter.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.filters;
2 |
3 | import java.io.File;
4 |
5 | /**
6 | * @class overlay overlay one image or video on top of another
7 | *
8 | * @desc x is the x coordinate of the overlayed video on the main video,
9 | * y is the y coordinate. The parameters are expressions containing
10 | * the following parameters:
11 | *
12 | * main_w, main_h
13 | * main input width and height
14 | *
15 | * W, H
16 | * same as main_w and main_h
17 | *
18 | * overlay_w, overlay_h
19 | * overlay input width and height
20 | *
21 | * w, h
22 | * same as overlay_w and overlay_h
23 | *
24 | * @examples
25 | * draw the overlay at 10 pixels from the bottom right
26 | * corner of the main video.
27 | * main_w-overlay_w-10
28 | * main_h-overlay_h-10
29 | * draw the overlay in the bottom left corner of the input
30 | * 10
31 | * main_h-overlay_h-10 [out]
32 | *
33 | */
34 | public class OverlayVideoFilter extends VideoFilter {
35 |
36 | public File overlayFile;
37 | public String xParam, yParam;
38 |
39 | public OverlayVideoFilter() {
40 |
41 | }
42 |
43 | public OverlayVideoFilter (File fileMovieOverlay, int x, int y)
44 | {
45 | this.overlayFile = fileMovieOverlay;
46 | this.xParam = Integer.toString(x);
47 | this.yParam = Integer.toString(y);
48 | }
49 |
50 | public OverlayVideoFilter (File fileMovieOverlay, String xExpression, String yExpression)
51 | {
52 | this.overlayFile = fileMovieOverlay;
53 | this.xParam = xExpression;
54 | this.yParam = yExpression;
55 | }
56 |
57 | public String getFilterString ()
58 | {
59 | if (overlayFile != null)
60 | return "movie="
61 | + overlayFile.getAbsolutePath()
62 | + " [logo];[in][logo] "
63 | + "overlay=" + xParam + ":" + yParam
64 | + " [out]";
65 | else
66 | return "";
67 |
68 | }
69 | }
70 |
71 | //"\"movie="+ overlayImage.getPath() +" [logo];[in][logo] overlay=0:0 [out]\"",
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/filters/RedactVideoFilter.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.filters;
2 |
3 | import java.io.File;
4 |
5 | public class RedactVideoFilter extends VideoFilter {
6 |
7 | private File fileRedactList;
8 |
9 | public RedactVideoFilter (File fileRedactList)
10 | {
11 | this.fileRedactList = fileRedactList;
12 | }
13 |
14 | public String getFilterString ()
15 | {
16 | if (fileRedactList != null)
17 | return "redact=" + fileRedactList.getAbsolutePath();
18 | else
19 | return "";
20 |
21 | }
22 | }
23 |
24 | //redact=blurbox.txt [out] [d], [d]nullsink
25 | //"redact=" + Environment.getExternalStorageDirectory().getPath() + "/" + PACKAGENAME + "/redact_unsort.txt",
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/filters/TransposeVideoFilter.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.filters;
2 |
3 | /*
4 | * works for video and images
5 | * 0 = 90CounterCLockwise and Vertical Flip (default)
6 | 1 = 90Clockwise
7 | 2 = 90CounterClockwise
8 | 3 = 90Clockwise and Vertical Flip
9 | */
10 | public class TransposeVideoFilter extends VideoFilter {
11 |
12 | private int mTranspose = -1;
13 |
14 | public final static int NINETY_COUNTER_CLOCKWISE_AND_VERTICAL_FLIP = 0;
15 | public final static int NINETY_CLOCKWISE = 1;
16 | public final static int NINETY_COUNTER_CLOCKWISE = 2;
17 | public final static int NINETY_CLOCKWISE_AND_VERTICAL_FLIP = 3;
18 |
19 | public TransposeVideoFilter (int transpose)
20 | {
21 | mTranspose = transpose;
22 | }
23 |
24 | @Override
25 | public String getFilterString() {
26 |
27 | return "transpose=" + mTranspose;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/filters/VideoFilter.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.filters;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Iterator;
5 |
6 | public abstract class VideoFilter {
7 |
8 | public abstract String getFilterString ();
9 |
10 | public static String format (ArrayList listFilters)
11 | {
12 | StringBuffer result = new StringBuffer();
13 |
14 | Iterator it = listFilters.iterator();
15 | VideoFilter vf;
16 |
17 | while (it.hasNext())
18 | {
19 | vf = it.next();
20 | result.append(vf.getFilterString());
21 |
22 | if (it.hasNext())
23 | result.append(",");
24 | }
25 | return result.toString();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/test/ConcatTest.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.test;
2 |
3 |
4 | import java.io.File;
5 | import java.util.ArrayList;
6 | import java.util.Locale;
7 |
8 | import net.sourceforge.sox.SoxController;
9 |
10 | import org.ffmpeg.android.Clip;
11 | import org.ffmpeg.android.FfmpegController;
12 | import org.ffmpeg.android.ShellUtils;
13 |
14 | public class ConcatTest {
15 |
16 | public static void test (String videoRoot, String fileTmpPath, String fileOut, double fadeLen) throws Exception
17 | {
18 | File fileTmp = new File(fileTmpPath);
19 | File fileAppRoot = new File("");
20 | File fileVideoRoot = new File(videoRoot);
21 |
22 | FfmpegController fc = new FfmpegController(null, fileTmp);
23 | SoxController sxCon = new SoxController(null, fileAppRoot, null);
24 |
25 | ArrayList listVideos = new ArrayList();
26 |
27 | String[] fileList = fileVideoRoot.list();
28 | for (String fileVideo : fileList)
29 | {
30 | if (fileVideo.endsWith("mp4"))
31 | {
32 | Clip clip = new Clip();
33 | clip.path = new File(fileVideoRoot,fileVideo).getCanonicalPath();
34 |
35 | fc.getInfo(clip);
36 |
37 | clip.duration = clip.duration-fadeLen;
38 | listVideos.add(clip);
39 |
40 |
41 | }
42 | }
43 |
44 | Clip clipOut = new Clip ();
45 | clipOut.path = new File(fileOut).getCanonicalPath();
46 |
47 | fc.concatAndTrimFilesMP4Stream(listVideos, clipOut, false, false, new ShellUtils.ShellCallback() {
48 |
49 | @Override
50 | public void shellOut(String shellLine) {
51 |
52 | System.out.println("fc>" + shellLine);
53 | }
54 |
55 | @Override
56 | public void processComplete(int exitValue) {
57 |
58 | if (exitValue < 0)
59 | System.err.println("concat non-zero exit: " + exitValue);
60 | }
61 | });
62 |
63 |
64 |
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/test/ConvertTest.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.test;
2 |
3 | public class ConvertTest {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/test/CrossfadeTest.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.test;
2 |
3 | import java.io.File;
4 | import java.io.FileNotFoundException;
5 | import java.util.ArrayList;
6 | import java.util.Locale;
7 |
8 | import net.sourceforge.sox.CrossfadeCat;
9 | import net.sourceforge.sox.SoxController;
10 |
11 | import org.ffmpeg.android.Clip;
12 | import org.ffmpeg.android.FfmpegController;
13 | import org.ffmpeg.android.ShellUtils;
14 |
15 | public class CrossfadeTest {
16 |
17 |
18 | public static void test (String videoRoot, String fileTmpPath, String clipOutPath, double fadeLen) throws Exception
19 | {
20 | File fileTmp = new File(fileTmpPath);
21 | File fileAppRoot = new File("");
22 | File fileVideoRoot = new File(videoRoot);
23 |
24 | String fadeType = "l";
25 | int sampleRate = 22050;
26 | int channels = 1;
27 |
28 | FfmpegController ffmpegc = new FfmpegController (null, fileTmp);
29 |
30 | Clip clipOut = new Clip();
31 | clipOut.path = clipOutPath;
32 | clipOut.audioCodec="aac";
33 | clipOut.audioBitrate=56;
34 |
35 |
36 | ArrayList listVideos = new ArrayList();
37 |
38 | String[] fileList = fileVideoRoot.list();
39 | for (String fileVideo : fileList)
40 | {
41 | if (fileVideo.endsWith("mp4"))
42 | {
43 | Clip clip = new Clip();
44 | clip.path = new File(fileVideoRoot,fileVideo).getCanonicalPath();
45 | //clip.startTime = "00:00:03";
46 | //clip.duration = "00:00:02";
47 |
48 | ffmpegc.getInfo(clip);
49 |
50 | //System.out.println("clip " + fileVideo + " duration=" + clip.duration);
51 |
52 | listVideos.add(clip);
53 |
54 | }
55 | }
56 |
57 | //now add 1 second cross fade to each audio file and cat them together
58 | SoxController sxCon = new SoxController(null, fileAppRoot, new ShellUtils.ShellCallback() {
59 |
60 | @Override
61 | public void shellOut(String shellLine) {
62 |
63 | // System.out.println("sxCon> " + shellLine);
64 |
65 | }
66 |
67 | @Override
68 | public void processComplete(int exitValue) {
69 |
70 |
71 | if (exitValue != 0)
72 | {
73 | System.err.println("sxCon> EXIT=" + exitValue);
74 |
75 | RuntimeException re = new RuntimeException("non-zero exit: " + exitValue);
76 | re.printStackTrace();
77 | throw re;
78 | }
79 |
80 | }
81 | });
82 |
83 | ArrayList alAudio = new ArrayList();
84 |
85 | //convert each input file to a WAV so we can use Sox to process
86 | int wavIdx = 0;
87 |
88 | for (Clip mediaIn : listVideos)
89 | {
90 | if (new File(mediaIn.path).exists())
91 | {
92 |
93 | if (mediaIn.audioCodec == null)
94 | {
95 | //there is no audio track so let's generate silence
96 |
97 |
98 | }
99 | else
100 | {
101 | Clip audioOut = ffmpegc.convertToWaveAudio(mediaIn, new File(fileTmp, wavIdx+".wav").getCanonicalPath(),sampleRate,channels, new ShellUtils.ShellCallback() {
102 |
103 | @Override
104 | public void shellOut(String shellLine) {
105 |
106 | // System.out.println("convertToWav> " + shellLine);
107 |
108 | }
109 |
110 | @Override
111 | public void processComplete(int exitValue) {
112 |
113 | if (exitValue != 0)
114 | {
115 |
116 | System.err.println("convertToWav> EXIT=" + exitValue);
117 |
118 | RuntimeException re = new RuntimeException("non-zero exit: " + exitValue);
119 | re.printStackTrace();
120 | throw re;
121 | }
122 | }
123 | });
124 |
125 | alAudio.add(audioOut);
126 |
127 | /*
128 | float duration = (float) sxCon.getLength(new File(audioOut.path).getCanonicalPath());
129 |
130 | if (mediaIn.duration == null)
131 | {
132 | mediaIn.duration = String.format(Locale.US, "%f", duration);
133 | }*/
134 | ffmpegc.getInfo(mediaIn);
135 |
136 |
137 | wavIdx++;
138 | }
139 | }
140 | else
141 | {
142 | throw new FileNotFoundException(mediaIn.path);
143 | }
144 | }
145 |
146 | if (alAudio.size() > 0)
147 | {
148 | String fileOut = alAudio.get(0).path;
149 |
150 | System.out.println("mix length=" + sxCon.getLength(fileOut));
151 |
152 | for (int i = 1; i < alAudio.size(); i++)
153 | {
154 |
155 | File fileAdd = new File(alAudio.get(i).path);
156 |
157 | CrossfadeCat xCat = new CrossfadeCat(sxCon, fileOut, fileAdd.getCanonicalPath(), fadeLen, fileOut);
158 | xCat.start();
159 |
160 | fileAdd.deleteOnExit();
161 |
162 | System.out.println("mix length=" + sxCon.getLength(fileOut));
163 |
164 | }
165 |
166 |
167 | //1 second fade in and fade out, t = triangle or linear
168 | //String fadeLenStr = sxCon.formatTimePeriod(fadeLen);
169 |
170 |
171 |
172 | String fadeFileOut = sxCon.fadeAudio(fileOut, fadeType, fadeLen, sxCon.getLength(fileOut)-fadeLen, fadeLen);
173 |
174 | //now export the final file to our requested output format mOut.mimeType = AppConstants.MimeTypes.MP4_AUDIO;
175 |
176 | Clip mdFinalIn = new Clip();
177 | mdFinalIn.path = fadeFileOut;
178 |
179 |
180 | System.out.println ("final duration: " + sxCon.getLength(fadeFileOut));
181 |
182 | Clip exportOut = ffmpegc.convertTo3GPAudio(mdFinalIn, clipOut, new ShellUtils.ShellCallback() {
183 |
184 | @Override
185 | public void shellOut(String shellLine) {
186 |
187 | //System.out.println("convertTo3gp> " + shellLine);
188 | }
189 |
190 | @Override
191 | public void processComplete(int exitValue) {
192 |
193 | if (exitValue < 0)
194 | {
195 | RuntimeException re = new RuntimeException("non-zero exit: " + exitValue);
196 | re.printStackTrace();
197 | throw re;
198 | }
199 | }
200 | });
201 | }
202 | }
203 |
204 | }
205 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/test/FilterTest.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.test;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.ArrayList;
6 |
7 | import org.ffmpeg.android.filters.CropVideoFilter;
8 | import org.ffmpeg.android.filters.DrawBoxVideoFilter;
9 | import org.ffmpeg.android.filters.DrawTextVideoFilter;
10 | import org.ffmpeg.android.filters.FadeVideoFilter;
11 | import org.ffmpeg.android.filters.TransposeVideoFilter;
12 | import org.ffmpeg.android.filters.VideoFilter;
13 |
14 | import android.app.Activity;
15 | import android.content.Context;
16 |
17 | public class FilterTest {
18 |
19 |
20 | public static void test (String title, String textColor, File fileFont, String boxColor, String opacity) throws Exception
21 | {
22 | ArrayList listFilters = new ArrayList();
23 |
24 | File fileDir = new File("tmp");
25 | fileDir.mkdir();
26 |
27 | int height = 480;
28 | int width = 720;
29 | int lowerThird = height / 3;
30 | DrawBoxVideoFilter vf = new DrawBoxVideoFilter(0,height-lowerThird,width,lowerThird,100,"blue",fileDir);
31 |
32 | DrawTextVideoFilter vfTitle =
33 | new DrawTextVideoFilter(title,
34 | DrawTextVideoFilter.X_CENTERED,DrawTextVideoFilter.Y_CENTERED,
35 | textColor,
36 | 38,
37 | fileFont,
38 | true,
39 | boxColor,
40 | opacity);
41 |
42 | float fps = 29.97f;
43 | int fadeTime = (int)(fps*3);
44 | //fades in first 3 seconds
45 | FadeVideoFilter vfFadeIn = new FadeVideoFilter("in",0,fadeTime);
46 |
47 | //fades out last 50 frames
48 | int totalFrames = (int)(14.37*29.97);
49 | FadeVideoFilter vfFadeOut = new FadeVideoFilter("out",totalFrames-fadeTime,fadeTime);
50 |
51 | //crops video in 100 pixels on each side
52 | CropVideoFilter vfCrop = new CropVideoFilter("in_w-100","in_h-100","100","100");
53 |
54 | //rotates video 90 degress clockwise
55 | TransposeVideoFilter vfTranspose = new TransposeVideoFilter(TransposeVideoFilter.NINETY_CLOCKWISE);
56 |
57 | listFilters.add(vfTranspose);
58 | listFilters.add(vfCrop);
59 | listFilters.add(vfTitle);
60 | listFilters.add(vfFadeIn);
61 | listFilters.add(vfFadeOut);
62 |
63 |
64 |
65 | fileDir.deleteOnExit();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/test/MixTest.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.test;
2 |
3 | import java.io.File;
4 |
5 | import org.ffmpeg.android.Clip;
6 | import org.ffmpeg.android.FfmpegController;
7 | import org.ffmpeg.android.ShellUtils;
8 |
9 | public class MixTest {
10 |
11 | public static void test (String fileTmpPath, String videoClipPath, String audioClipPath, Clip clipOut) throws Exception
12 | {
13 | File fileTmp = new File(fileTmpPath);
14 | File fileAppRoot = new File("");
15 |
16 | FfmpegController fc = new FfmpegController(null, fileTmp);
17 |
18 | Clip clipVideo = new Clip(videoClipPath);
19 | //fc.getInfo(clipVideo);
20 |
21 | Clip clipAudio = new Clip(audioClipPath);
22 | //fc.getInfo(clipAudio);
23 |
24 | fc.combineAudioAndVideo(clipVideo, clipAudio, clipOut, new ShellUtils.ShellCallback() {
25 |
26 | @Override
27 | public void shellOut(String shellLine) {
28 | // System.out.println("MIX> " + shellLine);
29 | }
30 |
31 | @Override
32 | public void processComplete(int exitValue) {
33 |
34 | if (exitValue != 0)
35 | System.err.println("concat non-zero exit: " + exitValue);
36 | }
37 | });
38 |
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/org/ffmpeg/android/test/Tests.java:
--------------------------------------------------------------------------------
1 | package org.ffmpeg.android.test;
2 |
3 | import java.io.File;
4 |
5 | import org.ffmpeg.android.Clip;
6 |
7 | public class Tests {
8 |
9 | /**
10 | * @param args
11 | */
12 | public static void main(String[] args) throws Exception {
13 |
14 |
15 |
16 | String[] testpaths = {
17 | // "/home/n8fr8/Desktop/smcampmovie",
18 | // "/home/n8fr8/Desktop/smcampmovie2",
19 | "/home/n8fr8/Desktop/sm3"
20 |
21 | };
22 |
23 | int idx = -1;
24 |
25 | double fadeLen = 1;
26 |
27 | for (String testpath : testpaths)
28 | {
29 | idx++;
30 |
31 | System.out.println ("************************************");
32 | System.out.println ("CONCAT TEST: " + testpath);
33 |
34 | File fileVideoOutput = new File("/tmp/test" + idx + ".mp4");
35 | fileVideoOutput.delete();
36 |
37 | ConcatTest.test(testpath, "/tmp", fileVideoOutput.getCanonicalPath(), fadeLen);
38 |
39 | if (!fileVideoOutput.exists())
40 | {
41 | System.out.println("FAIL!! > output file did not get created: " + fileVideoOutput.getCanonicalPath());
42 | continue;
43 | }
44 | else
45 | System.out.println("SUCCESS!! > " + fileVideoOutput.getCanonicalPath());
46 |
47 | System.out.println ("************************************");
48 | System.out.println ("CROSSFADE TEST: " + testpath);
49 |
50 | File fileAudioOutput = new File("/tmp/test" + idx + ".3gp");
51 | fileAudioOutput.delete();
52 | CrossfadeTest.test(testpath, "/tmp", fileAudioOutput.getCanonicalPath(),fadeLen);
53 | if (!fileAudioOutput.exists())
54 | {
55 | System.out.println("FAIL!! > output file did not get created: " + fileAudioOutput.getCanonicalPath());
56 | continue;
57 | }
58 | else
59 | System.out.println("SUCCESS!! > " + fileAudioOutput.getCanonicalPath());
60 |
61 | System.out.println ("************************************");
62 | System.out.println ("MIX TEST: " + testpath);
63 |
64 | File fileMix = new File("/tmp/test" + idx + "mix.mp4");
65 | fileMix.delete();
66 | Clip clipMixOut = new Clip(fileMix.getCanonicalPath());
67 | MixTest.test("/tmp", fileVideoOutput.getCanonicalPath(), fileAudioOutput.getCanonicalPath(), clipMixOut);
68 | if (!fileMix.exists())
69 | System.out.println("FAIL!! > output file did not get created: " + fileMix.getCanonicalPath());
70 | else
71 | System.out.println("SUCCESS!! > " + fileMix.getCanonicalPath());
72 |
73 |
74 | }
75 |
76 | System.out.println("**********************");
77 | System.out.println("*******FIN**********");
78 |
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------