externalLibrariesEnabled = getExternalLibraries();
96 | if (externalLibrariesEnabled.contains("tesseract") || externalLibrariesEnabled.contains("x265") || externalLibrariesEnabled.contains("snappy") || externalLibrariesEnabled.contains("openh264")) {
97 | // libc++_shared.so included only when tesseract or x265 is enabled
98 | System.loadLibrary("c++_shared");
99 | }
100 | System.loadLibrary("cpufeatures");
101 | System.loadLibrary("avutil");
102 | System.loadLibrary("swscale");
103 | System.loadLibrary("swresample");
104 | System.loadLibrary("avcodec");
105 | System.loadLibrary("avformat");
106 | System.loadLibrary("avfilter");
107 | System.loadLibrary("avdevice");
108 | }
109 |
110 | /* ALL MOBILE-FFMPEG LIBRARIES LOADED AT STARTUP */
111 | Abi.class.getName();
112 | FFmpeg.class.getName();
113 |
114 | /*
115 | * NEON supported arm-v7a library has a different name
116 | */
117 | boolean nativeLibraryLoaded = false;
118 | if (AbiDetect.ARM_V7A.equals(AbiDetect.getNativeAbi())) {
119 | if (AbiDetect.isNativeLTSBuild()) {
120 |
121 | /*
122 | * IF CPU SUPPORTS ARM-V7A-NEON THE TRY TO LOAD IT FIRST. IF NOT LOAD DEFAULT ARM-V7A
123 | */
124 |
125 | try {
126 | System.loadLibrary("mobileffmpeg_armv7a_neon");
127 | nativeLibraryLoaded = true;
128 | AbiDetect.setArmV7aNeonLoaded(true);
129 | } catch (final UnsatisfiedLinkError e) {
130 | Log.i(Config.TAG, "NEON supported armeabi-v7a library not found. Loading default armeabi-v7a library.", e);
131 | }
132 | } else {
133 | AbiDetect.setArmV7aNeonLoaded(true);
134 | }
135 | }
136 |
137 | if (!nativeLibraryLoaded) {
138 | System.loadLibrary("mobileffmpeg");
139 | }
140 |
141 | Log.i(Config.TAG, String.format("Loaded mobile-ffmpeg-%s-%s-%s-%s.", getPackageName(), AbiDetect.getAbi(), getVersion(), getBuildDate()));
142 |
143 | /* NATIVE LOG LEVEL IS RECEIVED ONLY ON STARTUP */
144 | activeLogLevel = Level.from(getNativeLogLevel());
145 |
146 | lastReceivedStatistics = new Statistics();
147 |
148 | enableRedirection();
149 |
150 | lastCreatedPipeIndex = 0;
151 | }
152 |
153 | /**
154 | * Default constructor hidden.
155 | */
156 | private Config() {
157 | }
158 |
159 | /**
160 | * Enables log and statistics redirection.
161 | *
When redirection is not enabled FFmpeg/FFprobe logs are printed to stderr. By enabling
162 | * redirection, they are routed to Logcat and can be routed further to a callback function.
163 | *
Statistics redirection behaviour is similar. Statistics are not printed at all if
164 | * redirection is not enabled. If it is enabled then it is possible to define a statistics
165 | * callback function but if you don't, they are not printed anywhere and only saved as
166 | * lastReceivedStatistics
data which can be polled with
167 | * {@link #getLastReceivedStatistics()}.
168 | *
Note that redirection is enabled by default. If you do not want to use its functionality
169 | * please use {@link #disableRedirection()} to disable it.
170 | */
171 | public static void enableRedirection() {
172 | enableNativeRedirection();
173 | }
174 |
175 | /**
176 | *
Disables log and statistics redirection.
177 | */
178 | public static void disableRedirection() {
179 | disableNativeRedirection();
180 | }
181 |
182 | /**
183 | * Returns log level.
184 | *
185 | * @return log level
186 | */
187 | public static Level getLogLevel() {
188 | return activeLogLevel;
189 | }
190 |
191 | /**
192 | * Sets log level.
193 | *
194 | * @param level log level
195 | */
196 | public static void setLogLevel(final Level level) {
197 | if (level != null) {
198 | activeLogLevel = level;
199 | setNativeLogLevel(level.getValue());
200 | }
201 | }
202 |
203 | /**
204 | *
Sets a callback function to redirect FFmpeg/FFprobe logs.
205 | *
206 | * @param newLogCallback new log callback function or NULL to disable a previously defined callback
207 | */
208 | public static void enableLogCallback(final LogCallback newLogCallback) {
209 | logCallbackFunction = newLogCallback;
210 | }
211 |
212 | /**
213 | *
Sets a callback function to redirect FFmpeg statistics.
214 | *
215 | * @param statisticsCallback new statistics callback function or NULL to disable a previously defined callback
216 | */
217 | public static void enableStatisticsCallback(final StatisticsCallback statisticsCallback) {
218 | statisticsCallbackFunction = statisticsCallback;
219 | }
220 |
221 | /**
222 | *
Log redirection method called by JNI/native part.
223 | *
224 | * @param levelValue log level as defined in {@link Level}
225 | * @param logMessage redirected log message
226 | */
227 | private static void log(final int levelValue, final byte[] logMessage) {
228 | final Level level = Level.from(levelValue);
229 | final String text = new String(logMessage);
230 |
231 | // AV_LOG_STDERR logs are always redirected
232 | if ((activeLogLevel == Level.AV_LOG_QUIET && levelValue != Level.AV_LOG_STDERR.getValue()) || levelValue > activeLogLevel.getValue()) {
233 | // LOG NEITHER PRINTED NOR FORWARDED
234 | return;
235 | }
236 |
237 | if (logCallbackFunction != null) {
238 | try {
239 | logCallbackFunction.apply(new LogMessage(level, text));
240 | } catch (final Exception e) {
241 | Log.e(Config.TAG, "Exception thrown inside LogCallback block", e);
242 | }
243 | } else {
244 | switch (level) {
245 | case AV_LOG_QUIET: {
246 | // PRINT NO OUTPUT
247 | }
248 | break;
249 | case AV_LOG_TRACE:
250 | case AV_LOG_DEBUG: {
251 | Log.d(TAG, text);
252 | }
253 | break;
254 | case AV_LOG_STDERR:
255 | case AV_LOG_VERBOSE: {
256 | Log.v(TAG, text);
257 | }
258 | break;
259 | case AV_LOG_INFO: {
260 | Log.i(TAG, text);
261 | }
262 | break;
263 | case AV_LOG_WARNING: {
264 | Log.w(TAG, text);
265 | }
266 | break;
267 | case AV_LOG_ERROR:
268 | case AV_LOG_FATAL:
269 | case AV_LOG_PANIC: {
270 | Log.e(TAG, text);
271 | }
272 | break;
273 | default: {
274 | Log.v(TAG, text);
275 | }
276 | break;
277 | }
278 | }
279 | }
280 |
281 | /**
282 | *
Statistics redirection method called by JNI/native part.
283 | *
284 | * @param videoFrameNumber last processed frame number for videos
285 | * @param videoFps frames processed per second for videos
286 | * @param videoQuality quality of the video stream
287 | * @param size size in bytes
288 | * @param time processed duration in milliseconds
289 | * @param bitrate output bit rate in kbits/s
290 | * @param speed processing speed = processed duration / operation duration
291 | */
292 | private static void statistics(final int videoFrameNumber, final float videoFps,
293 | final float videoQuality, final long size, final int time,
294 | final double bitrate, final double speed) {
295 | final Statistics newStatistics = new Statistics(videoFrameNumber, videoFps, videoQuality, size, time, bitrate, speed);
296 | lastReceivedStatistics.update(newStatistics);
297 |
298 | if (statisticsCallbackFunction != null) {
299 | try {
300 | statisticsCallbackFunction.apply(lastReceivedStatistics);
301 | } catch (final Exception e) {
302 | Log.e(Config.TAG, "Exception thrown inside StatisticsCallback block", e);
303 | }
304 | }
305 | }
306 |
307 | /**
308 | *
Returns the last received statistics data.
309 | *
310 | * @return last received statistics data
311 | */
312 | public static Statistics getLastReceivedStatistics() {
313 | return lastReceivedStatistics;
314 | }
315 |
316 | /**
317 | *
Resets last received statistics. It is recommended to call it before starting a new execution.
318 | */
319 | public static void resetStatistics() {
320 | lastReceivedStatistics = new Statistics();
321 | }
322 |
323 | /**
324 | *
Sets and overrides fontconfig
configuration directory.
325 | *
326 | * @param path directory which contains fontconfig configuration (fonts.conf)
327 | * @return zero on success, non-zero on error
328 | */
329 | public static int setFontconfigConfigurationPath(final String path) {
330 | return setNativeEnvironmentVariable("FONTCONFIG_PATH", path);
331 | }
332 |
333 | /**
334 | *
Registers fonts inside the given path, so they are available to use in FFmpeg filters.
335 | *
336 | *
Note that you need to build MobileFFmpeg
with fontconfig
337 | * enabled or use a prebuilt package with fontconfig
inside to use this feature.
338 | *
339 | * @param context application context to access application data
340 | * @param fontDirectoryPath directory which contains fonts (.ttf and .otf files)
341 | * @param fontNameMapping custom font name mappings, useful to access your fonts with more friendly names
342 | */
343 | public static void setFontDirectory(final Context context, final String fontDirectoryPath, final Map fontNameMapping) {
344 | final File cacheDir = context.getCacheDir();
345 | int validFontNameMappingCount = 0;
346 |
347 | final File tempConfigurationDirectory = new File(cacheDir, ".mobileffmpeg");
348 | if (!tempConfigurationDirectory.exists()) {
349 | boolean tempFontConfDirectoryCreated = tempConfigurationDirectory.mkdirs();
350 | Log.d(TAG, String.format("Created temporary font conf directory: %s.", tempFontConfDirectoryCreated));
351 | }
352 |
353 | final File fontConfiguration = new File(tempConfigurationDirectory, "fonts.conf");
354 | if (fontConfiguration.exists()) {
355 | boolean fontConfigurationDeleted = fontConfiguration.delete();
356 | Log.d(TAG, String.format("Deleted old temporary font configuration: %s.", fontConfigurationDeleted));
357 | }
358 |
359 | /* PROCESS MAPPINGS FIRST */
360 | final StringBuilder fontNameMappingBlock = new StringBuilder("");
361 | if (fontNameMapping != null && (fontNameMapping.size() > 0)) {
362 | fontNameMapping.entrySet();
363 | for (Map.Entry mapping : fontNameMapping.entrySet()) {
364 | String fontName = mapping.getKey();
365 | String mappedFontName = mapping.getValue();
366 |
367 | if ((fontName != null) && (mappedFontName != null) && (fontName.trim().length() > 0) && (mappedFontName.trim().length() > 0)) {
368 | fontNameMappingBlock.append(" \n");
369 | fontNameMappingBlock.append(" \n");
370 | fontNameMappingBlock.append(String.format(" %s\n", fontName));
371 | fontNameMappingBlock.append(" \n");
372 | fontNameMappingBlock.append(" \n");
373 | fontNameMappingBlock.append(String.format(" %s\n", mappedFontName));
374 | fontNameMappingBlock.append(" \n");
375 | fontNameMappingBlock.append(" \n");
376 |
377 | validFontNameMappingCount++;
378 | }
379 | }
380 | }
381 |
382 | final String fontConfig = "\n" +
383 | "\n" +
384 | "\n" +
385 | " .\n" +
386 | " " + fontDirectoryPath + "\n" +
387 | fontNameMappingBlock +
388 | "";
389 |
390 | final AtomicReference reference = new AtomicReference<>();
391 | try {
392 | final FileOutputStream outputStream = new FileOutputStream(fontConfiguration);
393 | reference.set(outputStream);
394 |
395 | outputStream.write(fontConfig.getBytes());
396 | outputStream.flush();
397 |
398 | Log.d(TAG, String.format("Saved new temporary font configuration with %d font name mappings.", validFontNameMappingCount));
399 |
400 | setFontconfigConfigurationPath(tempConfigurationDirectory.getAbsolutePath());
401 |
402 | Log.d(TAG, String.format("Font directory %s registered successfully.", fontDirectoryPath));
403 |
404 | } catch (final IOException e) {
405 | Log.e(TAG, String.format("Failed to set font directory: %s.", fontDirectoryPath), e);
406 | } finally {
407 | if (reference.get() != null) {
408 | try {
409 | reference.get().close();
410 | } catch (IOException e) {
411 | // DO NOT PRINT THIS ERROR
412 | }
413 | }
414 | }
415 | }
416 |
417 | /**
418 | * Returns package name.
419 | *
420 | * @return guessed package name according to supported external libraries
421 | * @since 3.0
422 | */
423 | public static String getPackageName() {
424 | return Packages.getPackageName();
425 | }
426 |
427 | /**
428 | *
Returns supported external libraries.
429 | *
430 | * @return list of supported external libraries
431 | * @since 3.0
432 | */
433 | public static List getExternalLibraries() {
434 | return Packages.getExternalLibraries();
435 | }
436 |
437 | /**
438 | * Creates a new named pipe to use in FFmpeg
operations.
439 | *
440 | *
Please note that creator is responsible of closing created pipes.
441 | *
442 | * @param context application context
443 | * @return the full path of named pipe
444 | */
445 | public static String registerNewFFmpegPipe(final Context context) {
446 |
447 | // PIPES ARE CREATED UNDER THE CACHE DIRECTORY
448 | final File cacheDir = context.getCacheDir();
449 |
450 | final String newFFmpegPipePath = cacheDir + File.separator + MOBILE_FFMPEG_PIPE_PREFIX + (++lastCreatedPipeIndex);
451 |
452 | // FIRST CLOSE OLD PIPES WITH THE SAME NAME
453 | closeFFmpegPipe(newFFmpegPipePath);
454 |
455 | int rc = registerNewNativeFFmpegPipe(newFFmpegPipePath);
456 | if (rc == 0) {
457 | return newFFmpegPipePath;
458 | } else {
459 | Log.e(TAG, String.format("Failed to register new FFmpeg pipe %s. Operation failed with rc=%d.", newFFmpegPipePath, rc));
460 | return null;
461 | }
462 | }
463 |
464 | /**
465 | *
Closes a previously created FFmpeg
pipe.
466 | *
467 | * @param ffmpegPipePath full path of ffmpeg pipe
468 | */
469 | public static void closeFFmpegPipe(final String ffmpegPipePath) {
470 | File file = new File(ffmpegPipePath);
471 | if (file.exists()) {
472 | file.delete();
473 | }
474 | }
475 |
476 | /**
477 | * Returns the list of camera ids supported.
478 | *
479 | * @param context application context
480 | * @return the list of camera ids supported or an empty list if no supported camera is found
481 | */
482 | public static List getSupportedCameraIds(final Context context) {
483 | final List detectedCameraIdList = new ArrayList<>();
484 |
485 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
486 | detectedCameraIdList.addAll(CameraSupport.extractSupportedCameraIds(context));
487 | }
488 |
489 | return detectedCameraIdList;
490 | }
491 |
492 | /**
493 | * Returns FFmpeg version bundled within the library.
494 | *
495 | * @return FFmpeg version
496 | */
497 | public static String getFFmpegVersion() {
498 | return getNativeFFmpegVersion();
499 | }
500 |
501 | /**
502 | *
Returns MobileFFmpeg library version.
503 | *
504 | * @return MobileFFmpeg version
505 | */
506 | public static String getVersion() {
507 | if (AbiDetect.isNativeLTSBuild()) {
508 | return String.format("%s-lts", getNativeVersion());
509 | } else {
510 | return getNativeVersion();
511 | }
512 | }
513 |
514 | /**
515 | *
Returns whether MobileFFmpeg release is a long term release or not.
516 | *
517 | * @return YES or NO
518 | */
519 | public static boolean isLTSBuild() {
520 | return AbiDetect.isNativeLTSBuild();
521 | }
522 |
523 | /**
524 | *
Returns MobileFFmpeg library build date.
525 | *
526 | * @return MobileFFmpeg library build date
527 | */
528 | public static String getBuildDate() {
529 | return getNativeBuildDate();
530 | }
531 |
532 | /**
533 | *
Returns return code of last executed command.
534 | *
535 | * @return return code of last executed command
536 | * @since 3.0
537 | */
538 | public static int getLastReturnCode() {
539 | return lastReturnCode;
540 | }
541 |
542 | /**
543 | *
Returns log output of last executed single FFmpeg/FFprobe command.
544 | *
545 | *
This method does not support executing multiple concurrent commands. If you execute
546 | * multiple commands at the same time, this method will return output from all executions.
547 | *
548 | *
Please note that disabling redirection using {@link Config#disableRedirection()} method
549 | * also disables this functionality.
550 | *
551 | * @return output of the last executed command
552 | * @since 3.0
553 | */
554 | public static String getLastCommandOutput() {
555 | String nativeLastCommandOutput = getNativeLastCommandOutput();
556 | if (nativeLastCommandOutput != null) {
557 |
558 | // REPLACING CH(13) WITH CH(10)
559 | nativeLastCommandOutput = nativeLastCommandOutput.replace('\r', '\n');
560 | }
561 | return nativeLastCommandOutput;
562 | }
563 |
564 | /**
565 | *
Prints the output of the last executed FFmpeg/FFprobe command to the Logcat at the
566 | * specified priority.
567 | *
568 | *
This method does not support executing multiple concurrent commands. If you execute
569 | * multiple commands at the same time, this method will print output from all executions.
570 | *
571 | * @param logPriority one of {@link Log#VERBOSE}, {@link Log#DEBUG}, {@link Log#INFO},
572 | * {@link Log#WARN}, {@link Log#ERROR}, {@link Log#ASSERT}
573 | * @since 4.3
574 | */
575 | public static void printLastCommandOutput(int logPriority) {
576 | final int LOGGER_ENTRY_MAX_LEN = 4 * 1000;
577 |
578 | String buffer = getLastCommandOutput();
579 | do {
580 | if (buffer.length() <= LOGGER_ENTRY_MAX_LEN) {
581 | Log.println(logPriority, Config.TAG, buffer);
582 | buffer = "";
583 | } else {
584 | final int index = buffer.substring(0, LOGGER_ENTRY_MAX_LEN).lastIndexOf('\n');
585 | if (index < 0) {
586 | Log.println(logPriority, Config.TAG, buffer.substring(0, LOGGER_ENTRY_MAX_LEN));
587 | buffer = buffer.substring(LOGGER_ENTRY_MAX_LEN);
588 | } else {
589 | Log.println(logPriority, Config.TAG, buffer.substring(0, index));
590 | buffer = buffer.substring(index);
591 | }
592 | }
593 | } while (buffer.length() > 0);
594 | }
595 |
596 | /**
597 | * Updates return code value for the last executed command.
598 | *
599 | * @param newLastReturnCode new last return code value
600 | */
601 | public static void setLastReturnCode(int newLastReturnCode) {
602 | lastReturnCode = newLastReturnCode;
603 | }
604 |
605 | /**
606 | *
Enables native redirection. Necessary for log and statistics callback functions.
607 | */
608 | private static native void enableNativeRedirection();
609 |
610 | /**
611 | *
Disables native redirection
612 | */
613 | private static native void disableNativeRedirection();
614 |
615 | /**
616 | * Sets native log level
617 | *
618 | * @param level log level
619 | */
620 | private static native void setNativeLogLevel(int level);
621 |
622 | /**
623 | * Returns native log level.
624 | *
625 | * @return log level
626 | */
627 | private static native int getNativeLogLevel();
628 |
629 | /**
630 | *
Returns FFmpeg version bundled within the library natively.
631 | *
632 | * @return FFmpeg version
633 | */
634 | native static String getNativeFFmpegVersion();
635 |
636 | /**
637 | *
Returns MobileFFmpeg library version natively.
638 | *
639 | * @return MobileFFmpeg version
640 | */
641 | native static String getNativeVersion();
642 |
643 | /**
644 | *
Synchronously executes FFmpeg natively with arguments provided.
645 | *
646 | * @param arguments FFmpeg command options/arguments as string array
647 | * @return zero on successful execution, 255 on user cancel and non-zero on error
648 | */
649 | public native static int nativeFFmpegExecute(final String[] arguments);
650 |
651 | /**
652 | *
Cancels an ongoing FFmpeg operation natively. This function does not wait for termination
653 | * to complete and returns immediately.
654 | */
655 | public native static void nativeFFmpegCancel();
656 |
657 | /**
658 | *
Synchronously executes FFprobe natively with arguments provided.
659 | *
660 | * @param arguments FFprobe command options/arguments as string array
661 | * @return zero on successful execution, 255 on user cancel and non-zero on error
662 | */
663 | public native static int nativeFFprobeExecute(final String[] arguments);
664 |
665 | /**
666 | *
Creates natively a new named pipe to use in FFmpeg
operations.
667 | *
668 | *
Please note that creator is responsible of closing created pipes.
669 | *
670 | * @param ffmpegPipePath full path of ffmpeg pipe
671 | * @return zero on successful creation, non-zero on error
672 | */
673 | public native static int registerNewNativeFFmpegPipe(final String ffmpegPipePath);
674 |
675 | /**
676 | *
Returns MobileFFmpeg library build date natively.
677 | *
678 | * @return MobileFFmpeg library build date
679 | */
680 | public native static String getNativeBuildDate();
681 |
682 | /**
683 | *
Sets an environment variable natively.
684 | *
685 | * @param variableName environment variable name
686 | * @param variableValue environment variable value
687 | * @return zero on success, non-zero on error
688 | */
689 | public native static int setNativeEnvironmentVariable(final String variableName, final String variableValue);
690 |
691 | /**
692 | *
Returns log output of the last executed single command natively.
693 | *
694 | * @return output of the last executed single command
695 | */
696 | native static String getNativeLastCommandOutput();
697 |
698 | }
699 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/Abi.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Taner Sener
3 | *
4 | * This file is part of MobileFFmpeg.
5 | *
6 | * MobileFFmpeg is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * MobileFFmpeg is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with MobileFFmpeg. If not, see .
18 | */
19 |
20 | package com.mobile.ffmpeg;
21 |
22 | /**
23 | *
Helper enumeration type for Android ABIs; includes only supported ABIs.
24 | *
25 | */
26 | public enum Abi {
27 |
28 | /**
29 | * Represents armeabi-v7a ABI with NEON support
30 | */
31 | ABI_ARMV7A_NEON("armeabi-v7a-neon"),
32 |
33 | /**
34 | * Represents armeabi-v7a ABI
35 | */
36 | ABI_ARMV7A("armeabi-v7a"),
37 |
38 | /**
39 | * Represents armeabi ABI
40 | */
41 | ABI_ARM("armeabi"),
42 |
43 | /**
44 | * Represents x86 ABI
45 | */
46 | ABI_X86("x86"),
47 |
48 | /**
49 | * Represents x86_64 ABI
50 | */
51 | ABI_X86_64("x86_64"),
52 |
53 | /**
54 | * Represents arm64-v8a ABI
55 | */
56 | ABI_ARM64_V8A("arm64-v8a"),
57 |
58 | /**
59 | * Represents not supported ABIs
60 | */
61 | ABI_UNKNOWN("unknown");
62 |
63 | private String name;
64 |
65 | /**
66 | *
Returns enumeration defined by ABI name.
67 | *
68 | * @param abiName ABI name
69 | * @return enumeration defined by ABI name
70 | */
71 | public static Abi from(final String abiName) {
72 | if (abiName == null) {
73 | return ABI_UNKNOWN;
74 | } else if (abiName.equals(ABI_ARM.getName())) {
75 | return ABI_ARM;
76 | } else if (abiName.equals(ABI_ARMV7A.getName())) {
77 | return ABI_ARMV7A;
78 | } else if (abiName.equals(ABI_ARMV7A_NEON.getName())) {
79 | return ABI_ARMV7A_NEON;
80 | } else if (abiName.equals(ABI_ARM64_V8A.getName())) {
81 | return ABI_ARM64_V8A;
82 | } else if (abiName.equals(ABI_X86.getName())) {
83 | return ABI_X86;
84 | } else if (abiName.equals(ABI_X86_64.getName())) {
85 | return ABI_X86_64;
86 | } else {
87 | return ABI_UNKNOWN;
88 | }
89 | }
90 |
91 | /**
92 | * Returns ABI name as defined in Android NDK documentation.
93 | *
94 | * @return ABI name
95 | */
96 | public String getName() {
97 | return name;
98 | }
99 |
100 | /**
101 | * Creates new enum.
102 | *
103 | * @param abiName ABI name
104 | */
105 | Abi(final String abiName) {
106 | this.name = abiName;
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/CameraSupport.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 Taner Sener
3 | *
4 | * This file is part of MobileFFmpeg.
5 | *
6 | * MobileFFmpeg is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * MobileFFmpeg is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with MobileFFmpeg. If not, see .
18 | */
19 |
20 | package com.mobile.ffmpeg;
21 |
22 | import android.content.Context;
23 | import android.hardware.camera2.CameraAccessException;
24 | import android.hardware.camera2.CameraCharacteristics;
25 | import android.hardware.camera2.CameraManager;
26 | import android.hardware.camera2.CameraMetadata;
27 | import android.os.Build;
28 | import android.util.Log;
29 |
30 | import java.util.ArrayList;
31 | import java.util.List;
32 |
33 | import static android.content.Context.CAMERA_SERVICE;
34 | import static com.arthenica.mobileffmpeg.Config.TAG;
35 |
36 | public class CameraSupport {
37 |
38 | /**
39 | *
Compatibility method for extracting supported camera ids.
40 | *
41 | * @param context application context
42 | * @return returns the list of supported camera ids
43 | */
44 | public static List extractSupportedCameraIds(final Context context) {
45 | final List detectedCameraIdList = new ArrayList<>();
46 |
47 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
48 | try {
49 | final CameraManager manager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
50 | if (manager != null) {
51 | final String[] cameraIdList = manager.getCameraIdList();
52 |
53 | for (String cameraId : cameraIdList) {
54 | final CameraCharacteristics chars = manager.getCameraCharacteristics(cameraId);
55 | final Integer cameraSupport = chars.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
56 |
57 | if (cameraSupport != null && cameraSupport == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
58 | Log.d(TAG, "Detected camera with id " + cameraId + " has LEGACY hardware level which is not supported by Android Camera2 NDK API.");
59 | } else if (cameraSupport != null) {
60 | detectedCameraIdList.add(cameraId);
61 | }
62 | }
63 | }
64 | } catch (final CameraAccessException e) {
65 | Log.w(TAG, "Detecting camera ids failed.", e);
66 | }
67 | }
68 |
69 | return detectedCameraIdList;
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/FFmpeg.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Taner Sener
3 | *
4 | * This file is part of MobileFFmpeg.
5 | *
6 | * MobileFFmpeg is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * MobileFFmpeg is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with MobileFFmpeg. If not, see .
18 | */
19 |
20 | package com.mobile.ffmpeg;
21 |
22 | import com.arthenica.mobileffmpeg.AbiDetect;
23 | import com.arthenica.mobileffmpeg.Config;
24 |
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | public class FFmpeg {
29 |
30 | static {
31 | AbiDetect.class.getName();
32 | Config.class.getName();
33 | }
34 |
35 | /**
36 | * Default constructor hidden.
37 | */
38 | private FFmpeg() {
39 | }
40 |
41 | /**
42 | * Synchronously executes FFmpeg with arguments provided.
43 | *
44 | * @param arguments FFmpeg command options/arguments as string array
45 | * @return zero on successful execution, 255 on user cancel and non-zero on error
46 | */
47 | public static int execute(final String[] arguments) {
48 | final int lastReturnCode = Config.nativeFFmpegExecute(arguments);
49 |
50 | Config.setLastReturnCode(lastReturnCode);
51 |
52 | return lastReturnCode;
53 | }
54 |
55 | /**
56 | *
Synchronously executes FFmpeg command provided. Command is split into arguments using
57 | * provided delimiter character.
58 | *
59 | * @param command FFmpeg command
60 | * @param delimiter delimiter used to split arguments
61 | * @return zero on successful execution, 255 on user cancel and non-zero on error
62 | * @since 3.0
63 | * @deprecated argument splitting mechanism used in this method is pretty simple and prone to
64 | * errors. Consider using a more advanced method like {@link #execute(String)} or
65 | * {@link #execute(String[])}
66 | */
67 | public static int execute(final String command, final String delimiter) {
68 | return execute((command == null) ? new String[]{""} : command.split((delimiter == null) ? " " : delimiter));
69 | }
70 |
71 | /**
72 | *
Synchronously executes FFmpeg command provided. Space character is used to split command
73 | * into arguments. You can use single and double quote characters to specify arguments inside
74 | * your command.
75 | *
76 | * @param command FFmpeg command
77 | * @return zero on successful execution, 255 on user cancel and non-zero on error
78 | */
79 | public static int execute(final String command) {
80 | return execute(parseArguments(command));
81 | }
82 |
83 | /**
84 | *
Cancels an ongoing operation. This function does not wait for termination to complete and
85 | * returns immediately.
86 | */
87 | public static void cancel() {
88 | Config.nativeFFmpegCancel();
89 | }
90 |
91 | /**
92 | *
Parses the given command into arguments.
93 | *
94 | * @param command string command
95 | * @return array of arguments
96 | */
97 | static String[] parseArguments(final String command) {
98 | final List argumentList = new ArrayList<>();
99 | StringBuilder currentArgument = new StringBuilder();
100 |
101 | boolean singleQuoteStarted = false;
102 | boolean doubleQuoteStarted = false;
103 |
104 | for (int i = 0; i < command.length(); i++) {
105 | final Character previousChar;
106 | if (i > 0) {
107 | previousChar = command.charAt(i - 1);
108 | } else {
109 | previousChar = null;
110 | }
111 | final char currentChar = command.charAt(i);
112 |
113 | if (currentChar == ' ') {
114 | if (singleQuoteStarted || doubleQuoteStarted) {
115 | currentArgument.append(currentChar);
116 | } else if (currentArgument.length() > 0) {
117 | argumentList.add(currentArgument.toString());
118 | currentArgument = new StringBuilder();
119 | }
120 | } else if (currentChar == '\'' && (previousChar == null || previousChar != '\\')) {
121 | if (singleQuoteStarted) {
122 | singleQuoteStarted = false;
123 | } else if (doubleQuoteStarted) {
124 | currentArgument.append(currentChar);
125 | } else {
126 | singleQuoteStarted = true;
127 | }
128 | } else if (currentChar == '\"' && (previousChar == null || previousChar != '\\')) {
129 | if (doubleQuoteStarted) {
130 | doubleQuoteStarted = false;
131 | } else if (singleQuoteStarted) {
132 | currentArgument.append(currentChar);
133 | } else {
134 | doubleQuoteStarted = true;
135 | }
136 | } else {
137 | currentArgument.append(currentChar);
138 | }
139 | }
140 |
141 | if (currentArgument.length() > 0) {
142 | argumentList.add(currentArgument.toString());
143 | }
144 |
145 | return argumentList.toArray(new String[0]);
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/Level.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Taner Sener
3 | *
4 | * This file is part of MobileFFmpeg.
5 | *
6 | * MobileFFmpeg is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * MobileFFmpeg is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with MobileFFmpeg. If not, see .
18 | */
19 |
20 | package com.mobile.ffmpeg;
21 |
22 | public enum Level {
23 |
24 | /**
25 | * This log level is defined by MobileFFmpeg. It is used to specify logs printed to stderr by
26 | * ffmpeg. Logs that has this level are not filtered and always redirected.
27 | *
28 | * @since 4.3.1
29 | */
30 | AV_LOG_STDERR(-16),
31 |
32 | /**
33 | * Print no output.
34 | */
35 | AV_LOG_QUIET(-8),
36 |
37 | /**
38 | * Something went really wrong and we will crash now.
39 | */
40 | AV_LOG_PANIC(0),
41 |
42 | /**
43 | * Something went wrong and recovery is not possible.
44 | * For example, no header was found for a format which depends
45 | * on headers or an illegal combination of parameters is used.
46 | */
47 | AV_LOG_FATAL(8),
48 |
49 | /**
50 | * Something went wrong and cannot losslessly be recovered.
51 | * However, not all future data is affected.
52 | */
53 | AV_LOG_ERROR(16),
54 |
55 | /**
56 | * Something somehow does not look correct. This may or may not
57 | * lead to problems. An example would be the use of '-vstrict -2'.
58 | */
59 | AV_LOG_WARNING(24),
60 |
61 | /**
62 | * Standard information.
63 | */
64 | AV_LOG_INFO(32),
65 |
66 | /**
67 | * Detailed information.
68 | */
69 | AV_LOG_VERBOSE(40),
70 |
71 | /**
72 | * Stuff which is only useful for libav* developers.
73 | */
74 | AV_LOG_DEBUG(48),
75 |
76 | /**
77 | * Extremely verbose debugging, useful for libav* development.
78 | */
79 | AV_LOG_TRACE(56);
80 |
81 | private int value;
82 |
83 | /**
84 | * Returns enumeration defined by value.
85 | *
86 | * @param value level value
87 | * @return enumeration defined by value
88 | */
89 | public static Level from(final int value) {
90 | if (value == AV_LOG_STDERR.getValue()) {
91 | return AV_LOG_STDERR;
92 | } else if (value == AV_LOG_QUIET.getValue()) {
93 | return AV_LOG_QUIET;
94 | } else if (value == AV_LOG_PANIC.getValue()) {
95 | return AV_LOG_PANIC;
96 | } else if (value == AV_LOG_FATAL.getValue()) {
97 | return AV_LOG_FATAL;
98 | } else if (value == AV_LOG_ERROR.getValue()) {
99 | return AV_LOG_ERROR;
100 | } else if (value == AV_LOG_WARNING.getValue()) {
101 | return AV_LOG_WARNING;
102 | } else if (value == AV_LOG_INFO.getValue()) {
103 | return AV_LOG_INFO;
104 | } else if (value == AV_LOG_VERBOSE.getValue()) {
105 | return AV_LOG_VERBOSE;
106 | } else if (value == AV_LOG_DEBUG.getValue()) {
107 | return AV_LOG_DEBUG;
108 | } else {
109 | return AV_LOG_TRACE;
110 | }
111 | }
112 |
113 | /**
114 | * Returns level value.
115 | *
116 | * @return level value
117 | */
118 | public int getValue() {
119 | return value;
120 | }
121 |
122 | /**
123 | * Creates new enum.
124 | *
125 | * @param value level value
126 | */
127 | Level(final int value) {
128 | this.value = value;
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/LogCallback.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Taner Sener
3 | *
4 | * This file is part of MobileFFmpeg.
5 | *
6 | * MobileFFmpeg is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * MobileFFmpeg is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with MobileFFmpeg. If not, see .
18 | */
19 |
20 | package com.mobile.ffmpeg;
21 |
22 | @FunctionalInterface
23 | public interface LogCallback {
24 |
25 | void apply(final LogMessage message);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/LogMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Taner Sener
3 | *
4 | * This file is part of MobileFFmpeg.
5 | *
6 | * MobileFFmpeg is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * MobileFFmpeg is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with MobileFFmpeg. If not, see .
18 | */
19 |
20 | package com.mobile.ffmpeg;
21 |
22 | public class LogMessage {
23 |
24 | private final Level level;
25 | private final String text;
26 |
27 | public LogMessage(final Level level, final String text) {
28 | this.level = level;
29 | this.text = text;
30 | }
31 |
32 | public Level getLevel() {
33 | return level;
34 | }
35 |
36 | public String getText() {
37 | return text;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/Packages.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Taner Sener
3 | *
4 | * This file is part of MobileFFmpeg.
5 | *
6 | * MobileFFmpeg is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * MobileFFmpeg is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with MobileFFmpeg. If not, see .
18 | */
19 |
20 | package com.mobile.ffmpeg;
21 |
22 | import com.arthenica.mobileffmpeg.AbiDetect;
23 |
24 | import java.util.ArrayList;
25 | import java.util.Collections;
26 | import java.util.List;
27 |
28 | public class Packages {
29 |
30 | private static final List supportedExternalLibraries;
31 |
32 | static {
33 | supportedExternalLibraries = new ArrayList<>();
34 | supportedExternalLibraries.add("fontconfig");
35 | supportedExternalLibraries.add("freetype");
36 | supportedExternalLibraries.add("fribidi");
37 | supportedExternalLibraries.add("gmp");
38 | supportedExternalLibraries.add("gnutls");
39 | supportedExternalLibraries.add("kvazaar");
40 | supportedExternalLibraries.add("mp3lame");
41 | supportedExternalLibraries.add("libaom");
42 | supportedExternalLibraries.add("libass");
43 | supportedExternalLibraries.add("iconv");
44 | supportedExternalLibraries.add("libilbc");
45 | supportedExternalLibraries.add("libtheora");
46 | supportedExternalLibraries.add("libvidstab");
47 | supportedExternalLibraries.add("libvorbis");
48 | supportedExternalLibraries.add("libvpx");
49 | supportedExternalLibraries.add("libwebp");
50 | supportedExternalLibraries.add("libxml2");
51 | supportedExternalLibraries.add("opencore-amr");
52 | supportedExternalLibraries.add("openh264");
53 | supportedExternalLibraries.add("opus");
54 | supportedExternalLibraries.add("sdl2");
55 | supportedExternalLibraries.add("shine");
56 | supportedExternalLibraries.add("snappy");
57 | supportedExternalLibraries.add("soxr");
58 | supportedExternalLibraries.add("speex");
59 | supportedExternalLibraries.add("tesseract");
60 | supportedExternalLibraries.add("twolame");
61 | supportedExternalLibraries.add("wavpack");
62 | supportedExternalLibraries.add("x264");
63 | supportedExternalLibraries.add("x265");
64 | supportedExternalLibraries.add("xvid");
65 | }
66 |
67 | /**
68 | * Returns enabled external libraries by FFmpeg.
69 | *
70 | * @return enabled external libraries
71 | */
72 | public static List getExternalLibraries() {
73 | final String buildConfiguration = AbiDetect.getNativeBuildConf();
74 |
75 | final List enabledLibraryList = new ArrayList<>();
76 | for (String supportedExternalLibrary : supportedExternalLibraries) {
77 | if (buildConfiguration.contains("enable-" + supportedExternalLibrary) ||
78 | buildConfiguration.contains("enable-lib" + supportedExternalLibrary)) {
79 | enabledLibraryList.add(supportedExternalLibrary);
80 | }
81 | }
82 |
83 | Collections.sort(enabledLibraryList);
84 |
85 | return enabledLibraryList;
86 | }
87 |
88 | /**
89 | * Returns MobileFFmpeg binary package name.
90 | *
91 | * @return guessed MobileFFmpeg binary package name
92 | */
93 | public static String getPackageName() {
94 | final List externalLibraryList = getExternalLibraries();
95 | final boolean speex = externalLibraryList.contains("speex");
96 | final boolean fribidi = externalLibraryList.contains("fribidi");
97 | final boolean gnutls = externalLibraryList.contains("gnutls");
98 | final boolean xvid = externalLibraryList.contains("xvid");
99 |
100 | boolean minGpl = false;
101 | boolean https = false;
102 | boolean httpsGpl = false;
103 | boolean audio = false;
104 | boolean video = false;
105 | boolean full = false;
106 | boolean fullGpl = false;
107 |
108 | if (speex && fribidi) {
109 | if (xvid) {
110 | fullGpl = true;
111 | } else {
112 | full = true;
113 | }
114 | } else if (speex) {
115 | audio = true;
116 | } else if (fribidi) {
117 | video = true;
118 | } else if (xvid) {
119 | if (gnutls) {
120 | httpsGpl = true;
121 | } else {
122 | minGpl = true;
123 | }
124 | } else {
125 | if (gnutls) {
126 | https = true;
127 | }
128 | }
129 |
130 | if (fullGpl) {
131 | if (externalLibraryList.contains("fontconfig") &&
132 | externalLibraryList.contains("freetype") &&
133 | externalLibraryList.contains("fribidi") &&
134 | externalLibraryList.contains("gmp") &&
135 | externalLibraryList.contains("gnutls") &&
136 | externalLibraryList.contains("kvazaar") &&
137 | externalLibraryList.contains("mp3lame") &&
138 | externalLibraryList.contains("libaom") &&
139 | externalLibraryList.contains("libass") &&
140 | externalLibraryList.contains("iconv") &&
141 | externalLibraryList.contains("libilbc") &&
142 | externalLibraryList.contains("libtheora") &&
143 | externalLibraryList.contains("libvidstab") &&
144 | externalLibraryList.contains("libvorbis") &&
145 | externalLibraryList.contains("libvpx") &&
146 | externalLibraryList.contains("libwebp") &&
147 | externalLibraryList.contains("libxml2") &&
148 | externalLibraryList.contains("opencore-amr") &&
149 | externalLibraryList.contains("opus") &&
150 | externalLibraryList.contains("shine") &&
151 | externalLibraryList.contains("snappy") &&
152 | externalLibraryList.contains("soxr") &&
153 | externalLibraryList.contains("speex") &&
154 | externalLibraryList.contains("twolame") &&
155 | externalLibraryList.contains("wavpack") &&
156 | externalLibraryList.contains("x264") &&
157 | externalLibraryList.contains("x265") &&
158 | externalLibraryList.contains("xvid")) {
159 | return "full-gpl";
160 | } else {
161 | return "custom";
162 | }
163 | }
164 |
165 | if (full) {
166 | if (externalLibraryList.contains("fontconfig") &&
167 | externalLibraryList.contains("freetype") &&
168 | externalLibraryList.contains("fribidi") &&
169 | externalLibraryList.contains("gmp") &&
170 | externalLibraryList.contains("gnutls") &&
171 | externalLibraryList.contains("kvazaar") &&
172 | externalLibraryList.contains("mp3lame") &&
173 | externalLibraryList.contains("libaom") &&
174 | externalLibraryList.contains("libass") &&
175 | externalLibraryList.contains("iconv") &&
176 | externalLibraryList.contains("libilbc") &&
177 | externalLibraryList.contains("libtheora") &&
178 | externalLibraryList.contains("libvorbis") &&
179 | externalLibraryList.contains("libvpx") &&
180 | externalLibraryList.contains("libwebp") &&
181 | externalLibraryList.contains("libxml2") &&
182 | externalLibraryList.contains("opencore-amr") &&
183 | externalLibraryList.contains("opus") &&
184 | externalLibraryList.contains("shine") &&
185 | externalLibraryList.contains("snappy") &&
186 | externalLibraryList.contains("soxr") &&
187 | externalLibraryList.contains("speex") &&
188 | externalLibraryList.contains("twolame") &&
189 | externalLibraryList.contains("wavpack")) {
190 | return "full";
191 | } else {
192 | return "custom";
193 | }
194 | }
195 |
196 | if (video) {
197 | if (externalLibraryList.contains("fontconfig") &&
198 | externalLibraryList.contains("freetype") &&
199 | externalLibraryList.contains("fribidi") &&
200 | externalLibraryList.contains("kvazaar") &&
201 | externalLibraryList.contains("libaom") &&
202 | externalLibraryList.contains("libass") &&
203 | externalLibraryList.contains("iconv") &&
204 | externalLibraryList.contains("libtheora") &&
205 | externalLibraryList.contains("libvpx") &&
206 | externalLibraryList.contains("libwebp") &&
207 | externalLibraryList.contains("snappy")) {
208 | return "video";
209 | } else {
210 | return "custom";
211 | }
212 | }
213 |
214 | if (audio) {
215 | if (externalLibraryList.contains("mp3lame") &&
216 | externalLibraryList.contains("libilbc") &&
217 | externalLibraryList.contains("libvorbis") &&
218 | externalLibraryList.contains("opencore-amr") &&
219 | externalLibraryList.contains("opus") &&
220 | externalLibraryList.contains("shine") &&
221 | externalLibraryList.contains("soxr") &&
222 | externalLibraryList.contains("speex") &&
223 | externalLibraryList.contains("twolame") &&
224 | externalLibraryList.contains("wavpack")) {
225 | return "audio";
226 | } else {
227 | return "custom";
228 | }
229 | }
230 |
231 | if (httpsGpl) {
232 | if (externalLibraryList.contains("gmp") &&
233 | externalLibraryList.contains("gnutls") &&
234 | externalLibraryList.contains("libvidstab") &&
235 | externalLibraryList.contains("x264") &&
236 | externalLibraryList.contains("x265") &&
237 | externalLibraryList.contains("xvid")) {
238 | return "https-gpl";
239 | } else {
240 | return "custom";
241 | }
242 | }
243 |
244 | if (https) {
245 | if (externalLibraryList.contains("gmp") &&
246 | externalLibraryList.contains("gnutls")) {
247 | return "https";
248 | } else {
249 | return "custom";
250 | }
251 | }
252 |
253 | if (minGpl) {
254 | if (externalLibraryList.contains("libvidstab") &&
255 | externalLibraryList.contains("x264") &&
256 | externalLibraryList.contains("x265") &&
257 | externalLibraryList.contains("xvid")) {
258 | return "min-gpl";
259 | } else {
260 | return "custom";
261 | }
262 | }
263 |
264 | if (externalLibraryList.size() == 0) {
265 | return "min";
266 | } else {
267 | return "custom";
268 | }
269 | }
270 |
271 | }
272 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/Statistics.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Taner Sener
3 | *
4 | * This file is part of MobileFFmpeg.
5 | *
6 | * MobileFFmpeg is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * MobileFFmpeg is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with MobileFFmpeg. If not, see .
18 | */
19 |
20 | package com.mobile.ffmpeg;
21 |
22 | public class Statistics {
23 |
24 | private int videoFrameNumber;
25 | private float videoFps;
26 | private float videoQuality;
27 | private long size;
28 | private int time;
29 | private double bitrate;
30 | private double speed;
31 |
32 | public Statistics() {
33 | videoFrameNumber = 0;
34 | videoFps = 0;
35 | videoQuality = 0;
36 | size = 0;
37 | time = 0;
38 | bitrate = 0;
39 | speed = 0;
40 | }
41 |
42 | public Statistics(int videoFrameNumber, float videoFps, float videoQuality, long size, int time, double bitrate, double speed) {
43 | this.videoFrameNumber = videoFrameNumber;
44 | this.videoFps = videoFps;
45 | this.videoQuality = videoQuality;
46 | this.size = size;
47 | this.time = time;
48 | this.bitrate = bitrate;
49 | this.speed = speed;
50 | }
51 |
52 | public void update(final Statistics newStatistics) {
53 | if (newStatistics != null) {
54 | if (newStatistics.getVideoFrameNumber() > 0) {
55 | this.videoFrameNumber = newStatistics.getVideoFrameNumber();
56 | }
57 | if (newStatistics.getVideoFps() > 0){
58 | this.videoFps = newStatistics.getVideoFps();
59 | }
60 |
61 | if (newStatistics.getVideoQuality() > 0){
62 | this.videoQuality = newStatistics.getVideoQuality();
63 | }
64 |
65 | if (newStatistics.getSize() > 0){
66 | this.size = newStatistics.getSize();
67 | }
68 |
69 | if (newStatistics.getTime() > 0){
70 | this.time = newStatistics.getTime();
71 | }
72 |
73 | if (newStatistics.getBitrate() > 0){
74 | this.bitrate = newStatistics.getBitrate();
75 | }
76 |
77 | if (newStatistics.getSpeed() > 0){
78 | this.speed = newStatistics.getSpeed();
79 | }
80 | }
81 | }
82 |
83 | public int getVideoFrameNumber() {
84 | return videoFrameNumber;
85 | }
86 |
87 | public void setVideoFrameNumber(int videoFrameNumber) {
88 | this.videoFrameNumber = videoFrameNumber;
89 | }
90 |
91 | public float getVideoFps() {
92 | return videoFps;
93 | }
94 |
95 | public void setVideoFps(float videoFps) {
96 | this.videoFps = videoFps;
97 | }
98 |
99 | public float getVideoQuality() {
100 | return videoQuality;
101 | }
102 |
103 | public void setVideoQuality(float videoQuality) {
104 | this.videoQuality = videoQuality;
105 | }
106 |
107 | public long getSize() {
108 | return size;
109 | }
110 |
111 | public void setSize(long size) {
112 | this.size = size;
113 | }
114 |
115 | public int getTime() {
116 | return time;
117 | }
118 |
119 | public void setTime(int time) {
120 | this.time = time;
121 | }
122 |
123 | public double getBitrate() {
124 | return bitrate;
125 | }
126 |
127 | public void setBitrate(double bitrate) {
128 | this.bitrate = bitrate;
129 | }
130 |
131 | public double getSpeed() {
132 | return speed;
133 | }
134 |
135 | public void setSpeed(double speed) {
136 | this.speed = speed;
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/StatisticsCallback.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Taner Sener
3 | *
4 | * This file is part of MobileFFmpeg.
5 | *
6 | * MobileFFmpeg is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * MobileFFmpeg is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with MobileFFmpeg. If not, see .
18 | */
19 |
20 | package com.mobile.ffmpeg;
21 |
22 | public interface StatisticsCallback {
23 |
24 | void apply(final Statistics statistics);
25 |
26 | void onCancel();
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/util/FFmpegAsyncUtils.java:
--------------------------------------------------------------------------------
1 | package com.mobile.ffmpeg.util;
2 |
3 | import android.os.AsyncTask;
4 |
5 | import com.arthenica.mobileffmpeg.Config;
6 | import com.mobile.ffmpeg.FFmpeg;
7 | import com.mobile.ffmpeg.Statistics;
8 | import com.mobile.ffmpeg.StatisticsCallback;
9 |
10 | public class FFmpegAsyncUtils extends AsyncTask implements StatisticsCallback {
11 |
12 | private FFmpegExecuteCallback mCallback;
13 |
14 | public FFmpegAsyncUtils setCallback(FFmpegExecuteCallback mCallback) {
15 | this.mCallback = mCallback;
16 | return this;
17 | }
18 |
19 | @Override
20 | protected void onPreExecute() {
21 | super.onPreExecute();
22 | if (null != mCallback) {
23 | mCallback.onFFmpegStart();
24 | }
25 | Config.resetStatistics();
26 | Config.enableStatisticsCallback(this);
27 | }
28 |
29 | @Override
30 | protected Integer doInBackground(String[]... strings) {
31 | if (isCancelled()) {
32 | return Config.RETURN_CODE_CANCEL;
33 | }
34 | return FFmpeg.execute(strings[0]);
35 | }
36 |
37 | @Override
38 | public void apply(Statistics statistics) {
39 | if (null != statistics) {
40 | publishProgress(statistics.getTime());
41 | }
42 | }
43 |
44 | @Override
45 | protected void onProgressUpdate(Integer... values) {
46 | super.onProgressUpdate(values);
47 | if (isCancelled() || null == mCallback) {
48 | return;
49 | }
50 | mCallback.onFFmpegProgress(values[0]);
51 | }
52 |
53 | @Override
54 | protected void onPostExecute(Integer integer) {
55 | super.onPostExecute(integer);
56 | if (null == mCallback) {
57 | return;
58 | }
59 | if (integer == Config.RETURN_CODE_SUCCESS) {
60 | mCallback.onFFmpegSucceed(Config.getLastCommandOutput());
61 | } else {
62 | mCallback.onFFmpegFailed(Config.getLastCommandOutput());
63 | }
64 | }
65 |
66 | @Override
67 | public void onCancel() {
68 | cancel(true);
69 | FFmpeg.cancel();
70 | if (null != mCallback) {
71 | mCallback.onFFmpegCancel();
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/util/FFmpegAsyncUtils2.java:
--------------------------------------------------------------------------------
1 | package com.mobile.ffmpeg.util;
2 |
3 | import android.os.AsyncTask;
4 |
5 | import com.arthenica.mobileffmpeg.Config;
6 | import com.mobile.ffmpeg.FFmpeg;
7 | import com.mobile.ffmpeg.Statistics;
8 | import com.mobile.ffmpeg.StatisticsCallback;
9 |
10 | public class FFmpegAsyncUtils2 extends AsyncTask implements StatisticsCallback {
11 |
12 | private FFmpegExecuteCallback mCallback;
13 |
14 | public FFmpegAsyncUtils2 setCallback(FFmpegExecuteCallback mCallback) {
15 | this.mCallback = mCallback;
16 | return this;
17 | }
18 |
19 | @Override
20 | protected void onPreExecute() {
21 | super.onPreExecute();
22 | if (null != mCallback) {
23 | mCallback.onFFmpegStart();
24 | }
25 | Config.resetStatistics();
26 | Config.enableStatisticsCallback(this);
27 | }
28 |
29 | @Override
30 | protected Integer doInBackground(String... strings) {
31 | if (isCancelled()) {
32 | return Config.RETURN_CODE_CANCEL;
33 | }
34 | return FFmpeg.execute(strings[0]);
35 | }
36 |
37 | @Override
38 | public void apply(Statistics statistics) {
39 | if (null != statistics) {
40 | publishProgress(statistics.getTime());
41 | }
42 | }
43 |
44 | @Override
45 | protected void onProgressUpdate(Integer... values) {
46 | super.onProgressUpdate(values);
47 | if (isCancelled() || null == mCallback) {
48 | return;
49 | }
50 | mCallback.onFFmpegProgress(values[0]);
51 | }
52 |
53 | @Override
54 | protected void onPostExecute(Integer integer) {
55 | super.onPostExecute(integer);
56 | if (null == mCallback) {
57 | return;
58 | }
59 | if (integer == Config.RETURN_CODE_SUCCESS) {
60 | mCallback.onFFmpegSucceed(Config.getLastCommandOutput());
61 | } else {
62 | mCallback.onFFmpegFailed(Config.getLastCommandOutput());
63 | }
64 | }
65 |
66 | @Override
67 | public void onCancel() {
68 | cancel(true);
69 | FFmpeg.cancel();
70 | if (null != mCallback) {
71 | mCallback.onFFmpegCancel();
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/java/com/mobile/ffmpeg/util/FFmpegExecuteCallback.java:
--------------------------------------------------------------------------------
1 | package com.mobile.ffmpeg.util;
2 |
3 | public interface FFmpegExecuteCallback {
4 | void onFFmpegStart();
5 |
6 | void onFFmpegSucceed(String executeOutput);
7 |
8 | void onFFmpegFailed(String executeOutput);
9 |
10 | void onFFmpegProgress(Integer progress);
11 |
12 | void onFFmpegCancel();
13 | }
14 |
--------------------------------------------------------------------------------
/ffmpeg/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ffmpeg
3 |
4 |
--------------------------------------------------------------------------------
/ffmpeg/src/test/java/com/mobile/ffmpeg/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.mobile.ffmpeg
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yangfeng1994/FFmpeg-Android/bc9aa26e9ab21c7349c81e24c5a60c9b5913b579/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Mar 28 16:26:48 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':ffmpeg'
2 | rootProject.name='android-ffmpeg'
3 |
--------------------------------------------------------------------------------