Compare commits

..

651 Commits

Author SHA1 Message Date
Taner Sener ae769f8cfd connect ffplay to sdl for android 2020-07-17 19:06:32 +01:00
Taner Sener 1da0c9d8d7 implement ffplay for android 2020-02-09 22:38:08 +00:00
Taner Sener 1883d97999 fix ios/tvos sdl flags 2020-01-30 22:03:15 +00:00
Taner Sener 46b538107b update release dates 2020-01-26 12:19:05 +00:00
Taner Sener fd11dd5004 apply workaround for aarch64 architectures, fixes #328 2020-01-25 10:06:22 +00:00
Taner Sener 9da84b3edb fix concurrent writer registration, fixes #324 2020-01-22 23:18:19 +00:00
Taner Sener 639dbb3ccb update clean.sh script 2020-01-19 11:16:43 +00:00
Hannes Achleitner d8b1754272 cleanup Android project 2020-01-16 20:49:23 +00:00
Taner Sener 73e2cc557f update wiki images 2020-01-16 19:41:51 +00:00
Taner Sener b70229b9e7 fix cancel operation 2020-01-14 19:53:54 +00:00
Taner Sener 47a9b728d7 update project main page 2020-01-14 00:16:17 +00:00
Taner Sener 32f25905cb update test-application versions 2020-01-13 23:37:03 +00:00
Taner Sener 35c26b390c freeze v4.3.1 2020-01-13 00:35:05 +00:00
Taner Sener b9549a04e7 fix duplicate symbol errors for fftools 2020-01-12 20:54:57 +00:00
Taner Sener c6840985e6 update copyright headers for android 2020-01-12 20:54:57 +00:00
Taner Sener 8e671be23d fix ffprobe optional parameter parsing errors. 2020-01-12 20:08:05 +00:00
Taner Sener 807051ce3c create scripts to build universal packages. 2020-01-12 20:06:22 +00:00
Taner Sener c38ebd52b6 update ios/tvos test applications 2020-01-12 20:05:13 +00:00
Taner Sener 37ba9a95c1 fix ios/tvos depreciation warnings 2020-01-12 10:11:13 +00:00
Taner Sener 99ae2531a4 fix ios tvos compilation for libvpx 2020-01-12 09:10:55 +00:00
Taner Sener 60accc6233 fix ffprobe android lts linking errors 2020-01-10 01:07:06 +00:00
Taner Sener 35fd709066 use new x264 version v20191125-stable 2020-01-09 23:01:48 +00:00
Taner Sener 57ebc9a177 fix libvpx ios compilation errors 2020-01-09 22:07:22 +00:00
Taner Sener dcb1935b57 fix wavpack ios compilation errors 2020-01-09 18:14:44 +00:00
Taner Sener 815b122cef use new ffmpeg version v4.3-dev-1944-g94cdf82d53 2020-01-09 01:18:19 +00:00
Taner Sener f3a279348d use new wavpack version v5.2.0 2020-01-09 01:06:30 +00:00
Taner Sener 920aa583b9 use new xvidcore version v1.3.7 2020-01-09 01:04:41 +00:00
Taner Sener 1e7a4bb3f2 use new libwebp version v1.1.0 2020-01-09 01:04:07 +00:00
Taner Sener e92ba21784 use new libjpeg-turbo version v2.0.4 2020-01-09 01:00:18 +00:00
Taner Sener 0d47a43829 use new libvpx version v1.8.2 2020-01-09 00:52:30 +00:00
Taner Sener 77d4f80ba6 use new libaom version v1.0.0-errata1-avif-110-gceb377078 2020-01-08 23:50:00 +00:00
Taner Sener ab0ecc624d use system libiconv on ios/tvos, fixes #230 2020-01-08 23:35:02 +00:00
Taner Sener 7d9747789b implement ffprobe, fixes #286 2020-01-08 23:27:35 +00:00
Taner Sener dfdadf656b use system libiconv on ios/tvos 2020-01-08 16:15:39 +00:00
Taner Sener ef03a31d23 update helper methods to reflect concurrent execution support changes, fixes #182 2020-01-03 12:41:19 +00:00
Taner Sener 8041678c13 Merge branch 'concurrent' into development 2020-01-03 00:38:13 +00:00
Taner Sener 283ebe29a4 fix report option and issue #302 2020-01-03 00:11:51 +00:00
Taner Sener bdbabb5a18 prevent libogg auto detection, fixes #307 2019-12-28 11:18:13 +03:00
Taner Sener 4e078bb9e8 support concurrent execution 2019-12-19 23:47:38 +00:00
Taner Sener 240def7581 fix x265 build errors 2019-12-19 19:38:16 +00:00
Taner Sener cc1a5bd4b2 update gradle version 2019-12-15 11:50:52 +00:00
Taner Sener 6ae6627d97 update library version 2019-12-15 11:30:52 +00:00
Taner Sener b151e6ab81 synchronise mobile-ffmpeg source code 2019-12-15 01:21:27 +00:00
Taner Sener e3c0e4d2e7 use new ffmpeg version v4.3-dev-1687 2019-12-14 23:38:18 +00:00
Taner Sener 9dec4e0353 update ignored files for new versions 2019-12-14 20:39:02 +00:00
Taner Sener 062ca46069 use new xvidcore version 1.3.6 2019-12-14 19:08:02 +00:00
Taner Sener 267e8236f5 use new gnutls version 3.6.11.1 2019-12-14 19:04:52 +00:00
Taner Sener 4f3380c7fe use new tiff version 4.1 2019-12-14 19:02:49 +00:00
Taner Sener 7692c42c64 use new fribidi version 1.0.8 2019-12-14 18:58:53 +00:00
Taner Sener 71a1289c32 fix tvos pod name 2019-11-25 20:27:49 +00:00
Javernaut 911a8f5478 [Android Demo] Cleaning Fragment classes 2019-11-21 18:35:31 +00:00
Javernaut 54fe0bd773 [Android Demo] Simplifying the layout for the main screen 2019-11-21 18:35:31 +00:00
Javernaut 7c99fcdeac [Android Demo] Removing custom header for the screen and using a standard ActionBar provided by the app theme 2019-11-21 18:35:31 +00:00
Javernaut 47c590c2b1 [Android Demo] Migrating the demo app to AndroidX 2019-11-21 18:35:31 +00:00
Javernaut 3e307bb4d6 [Android Demo] Removing worthless instrumentation tests from the demo app 2019-11-21 18:35:31 +00:00
Alexander Berezhnoi feece0ea50 Android library module improvement (#269)
* [Android Demo] Updating the Android Gradle Plugin to 3.5.2

* [Android Demo] Updating Gradle distribution to 6.0

* [Android Demo] Removing redundant dependencies in the library module

* [Android Demo] Removing worthless instrumentation test file from library module

* [Android Demo] Updating testing dependency in library module

* [Android Demo] Removing redundant resources from the library module

* Improving the android.sh, so it builds only necessary parts of the only library module

* Improving the android.sh. Cleaning only android library module when calling gradlew.

* [Android Demo] Updating Gradle dist to 6.0.1
2019-11-19 12:20:19 +00:00
Taner Sener 540e180e53 merge master README 2019-11-16 16:36:00 +00:00
Taner Sener 38398cb128 use new libxml2 version 2.9.10 2019-11-02 12:59:38 +00:00
Taner Sener a416890244 use new x265 version 3.2.1 2019-11-02 12:55:05 +00:00
Taner Sener 9bf06a9bc2 improve getNativeLastCommandOutput checks 2019-10-28 09:13:21 +00:00
Taner Sener f7957bf2d9 update project page 2019-10-27 15:46:51 +00:00
Taner Sener 6a41bfd4e1 generate ios documentation 2019-10-27 15:20:29 +00:00
Taner Sener 2a96951d7d Merge branch 'master' into development 2019-10-27 15:14:12 +00:00
Taner Sener 448b5c61bb use new versions in ios test applications 2019-10-27 14:21:11 +00:00
Taner Sener 4217621f6f update issue template fields and paypal link 2019-10-27 12:59:56 +00:00
Taner Sener 9db209d406 release v4.3 2019-10-27 12:53:06 +00:00
Taner Sener 8a478f6dbe do not use deprecated api methods in test applications 2019-10-27 11:39:16 +00:00
Taner Sener cdc9dde9db fix getMediaInformation errors 2019-10-27 09:53:10 +00:00
Taner Sener ba768fe9e4 fix AsyncExecuteTask compatibility errors 2019-10-27 09:46:25 +00:00
Taner Sener 3993234a23 fix getNativeLastCommandOutput errors 2019-10-26 20:57:04 +01:00
Taner Sener aafc9587fc freeze v4.3 2019-10-26 15:27:31 +01:00
Taner Sener f6ea03addf prevent multiple executions, fixes #259 2019-10-26 14:17:32 +01:00
Taner Sener 0bead05ef8 add a few tests for issue #255 2019-10-26 12:44:05 +01:00
Taner Sener e00eadb4ff catch exceptions thrown by LogCallback and StatisticsCallback blocks, fixes #255 2019-10-26 12:30:00 +01:00
Taner Sener 220b4cead6 use new x264 version v20191024-2245-stable 2019-10-25 00:52:42 +01:00
Taner Sener 699485e0c5 use new ffmpeg version v4.3-dev-1181 2019-10-25 00:49:51 +01:00
Taner Sener 39f80127af use new libaom version v1.0.0-2567 2019-10-25 00:43:28 +01:00
Taner Sener 524d90aafe use new x265 version 3.2 2019-10-24 15:50:28 +01:00
Taner Sener aed8772010 use new twolame version 0.4.0 2019-10-24 00:17:20 +01:00
Taner Sener 663bd9e10a use new gnutls version 3.6.10 2019-10-23 23:47:24 +01:00
Taner Sener 6747a96694 use new fribidi version 1.0.7 2019-10-23 23:22:13 +01:00
Taner Sener a1a3c196cc use new fontconfig version 2.13.92 2019-10-23 20:46:08 +01:00
Taner Sener 0920ad0684 use new expat version 2.2.9 2019-10-23 19:41:27 +01:00
Taner Sener 1f32a2a47c support ios 13 2019-10-21 00:03:41 +01:00
Taner Sener cd5a43332a enable crc and crypto extensions for arm64e cpus 2019-09-17 23:08:32 +03:00
Taner Sener e6006621aa enable asm for gnutls on arm64 and arm64e architectures 2019-09-17 23:08:32 +03:00
Taner Sener 5ea232e853 fix libogg include errors 2019-09-16 17:01:49 +03:00
Taner Sener 8c5bb2d462 fix libogg include errors 2019-09-16 16:25:41 +03:00
Taner Sener c78f7b8822 fix gnutls asm errors 2019-09-16 13:41:06 +03:00
Taner Sener 0dbcdd373f use new x265 version 3.1.2 2019-09-16 11:42:23 +03:00
Taner Sener 1d828d300f use new libvpx version 1.8.1 2019-09-15 22:15:20 +03:00
Taner Sener c9c34dd4d0 use new gnutls version 3.6.9 2019-09-15 21:53:34 +03:00
Taner Sener ce920a56af use new libogg version 1.3.4 2019-09-15 21:32:20 +03:00
Taner Sener 231de3e7b4 use new libjpeg-turbo version 2.0.3 2019-09-15 21:23:42 +03:00
Taner Sener bbff12fb32 use new expat version 2.2.8 2019-09-15 21:14:30 +03:00
Taner Sener 14fbeca989 add backers section in readme.md 2019-09-10 12:14:31 +03:00
Taner Sener 3f24d91c9f add backers section in readme.md 2019-09-10 12:11:47 +03:00
Taner Sener c85017fe15 record only video using android_camera on site README 2019-09-06 22:16:48 +03:00
Taner Sener dc614948f9 record only video using android_camera on site README 2019-09-06 22:15:22 +03:00
Taner Sener 59ee330875 record only video using android_camera 2019-09-06 22:01:39 +03:00
Taner Sener 9444911b5d record only video using android_camera 2019-09-06 21:58:51 +03:00
Taner Sener 3d5dff0883 add ios min package screenshot 2019-08-30 15:02:47 +03:00
Taner Sener 5ec5470590 use printLastCommandOutput in android examples 2019-08-29 21:14:00 +03:00
Taner Sener 80cbbd6d5d add printLastCommandOutput api method on android 2019-08-29 21:06:48 +03:00
Taner Sener 39e55f48ee fix test errors 2019-08-28 18:07:59 +03:00
Taner Sener 2d2278b111 use av_malloc/av_free functions to allocate memory 2019-08-28 14:24:00 +03:00
Taner Sener 2e595085ef use new ffmpeg version v4.3-dev-300-gf8ad2ddd7a 2019-08-28 13:54:56 +03:00
Taner Sener 86ed56ecae build the last command output inside the log callback function, fixes #211 2019-08-28 13:32:09 +03:00
Taner Sener f97dccb5f9 remove unused Android Manifest attributes, fixes #206. 2019-08-06 23:59:57 +03:00
Taner Sener fc0d13f5a5 update test-app versions 2019-08-06 23:46:57 +03:00
Taner Sener cfa7948c10 update FUNDING.yml 2019-07-24 12:00:28 +03:00
Taner Sener d1b5ef3643 Update FUNDING.yml 2019-07-24 11:58:38 +03:00
Taner Sener 1815af56e8 use full package in README examples 2019-07-20 09:22:46 +03:00
Taner Sener a16c573b31 use full package in examples 2019-07-20 09:21:03 +03:00
Taner Sener ff54a727f1 update ffmpeg build scripts 2019-07-20 00:49:33 +03:00
Taner Sener 40f74f9cd5 update travis configuration 2019-07-18 10:39:56 +03:00
Taner Sener d34e86fda5 test new travis fixes 2019-07-18 10:13:01 +03:00
Taner Sener fa4d818a38 test travis fixes 2019-07-18 10:08:25 +03:00
Taner Sener 179cc3c029 support single quotes and double quotes in command strings, fixes #190 2019-07-16 21:14:20 +03:00
Taner Sener 293e51301a support single quotes and double quotes in command strings 2019-07-16 21:14:19 +03:00
Taner Sener fde19f7bff Update FUNDING.yml
add open collective link
2019-07-16 21:14:19 +03:00
Taner Sener d6d6b14214 Merge pull request #175 from tanersener/development
update README
2019-07-16 21:14:18 +03:00
Taner Sener 46b331059a build ffmpeg without -mdynamic-no-pic on ios/tvos, fixes #187 2019-07-16 15:25:17 +03:00
Taner Sener c285041333 include sysv hash table in both android release variants, enhances #184 2019-07-14 11:09:03 +03:00
Taner Sener d20cbfc03c use new x265 version 3.1.1 2019-07-11 16:32:01 +03:00
Taner Sener 2bc8e925e4 use new openh264 version 2.0.0 2019-07-11 15:05:44 +03:00
Taner Sener 7e2c8039fa use new kvazaar version 1.3.0 2019-07-11 12:38:41 +03:00
Taner Sener a212506d2c Update FUNDING.yml
add open collective link
2019-07-09 18:03:40 +03:00
Taner Sener 40e2e0e279 remove patreon link 2019-07-08 15:02:22 +03:00
Taner Sener aeac5d17f4 remove patreon link 2019-07-08 15:01:25 +03:00
Taner Sener c08b377287 display sponsor button 2019-07-08 14:43:15 +03:00
Taner Sener 214f2e0902 display sponsor button 2019-07-08 14:41:39 +03:00
Taner Sener 7910ba20be remove development builds link 2019-07-07 20:53:14 +03:00
Taner Sener 2c13b1ac8d remove development builds link 2019-07-07 20:47:26 +03:00
Taner Sener 8e221e9380 add patreon link 2019-07-07 19:48:38 +03:00
Taner Sener fffac3e9cd add patreon link 2019-07-07 19:47:48 +03:00
Taner Sener 1637b94a2a version bump 2019-07-05 19:56:15 +03:00
Taner Sener 13e87d6dc5 use underscore instead of hyphen in android library names 2019-07-05 15:35:10 +03:00
Taner Sener 819ccf4294 Merge pull request #175 from tanersener/development
update README
2019-07-04 15:09:48 +03:00
Taner Sener b2a957471b update README 2019-07-04 15:09:16 +03:00
Taner Sener a3610893d7 Merge pull request #174 from tanersener/development
update project website
2019-07-04 15:02:55 +03:00
Taner Sener cfd54d23f4 update project website 2019-07-04 15:02:12 +03:00
Taner Sener 2e80a5552c Merge pull request #173 from tanersener/development
merge v4.2.2
2019-07-04 14:44:46 +03:00
Taner Sener 40f0c6d093 update android.sh help text 2019-07-04 14:43:35 +03:00
Taner Sener d8db2adf7f update README 2019-07-04 14:31:46 +03:00
Taner Sener d3aca61ce6 add pods test application for tvos 2019-07-03 23:13:37 +03:00
Taner Sener aef439d4d4 update test applications 2019-07-03 16:39:28 +03:00
Taner Sener ae5cdad4e5 re-generate android javadoc documentation 2019-07-03 13:22:54 +03:00
Taner Sener c80e11cfc4 disable asm for libtheora on android lts releases 2019-07-03 13:15:44 +03:00
Taner Sener 879a78601c fix snappy linking errors on android 2019-07-03 03:35:47 +03:00
Taner Sener d0b26d7c59 freeze v4.2.2 2019-07-02 18:33:21 +03:00
Taner Sener 7f1a6b1c01 fix build errors 2019-07-02 17:32:42 +03:00
Taner Sener 0011be58d0 use new libaom version 1.0.0-2018-g5bceb59e7 2019-07-02 15:02:24 +03:00
Taner Sener e5ba73c90f use new x264 version snapshot-20190701 2019-07-02 14:48:01 +03:00
Taner Sener bc1d17b7ba use new ffmpeg version 4.2-dev-1824-g231d0c819f 2019-07-02 14:42:55 +03:00
Taner Sener 2f5b4751d5 use new gnutls version 3.6.8 2019-07-02 14:37:24 +03:00
Taner Sener fe05bb766e use new nettle version 3.5.1 2019-07-02 13:02:03 +03:00
Taner Sener b1f7f22970 use new freetype version 2.10.1 2019-07-02 09:35:52 +03:00
Taner Sener ed1a3edb6e use new expat version 2.2.7 2019-07-02 09:28:15 +03:00
Taner Sener 4aecd528eb update top level build scripts 2019-06-30 00:01:35 +03:00
Taner Sener fe8e3f6605 include external library license files in universal library release packages, fixes #169 2019-06-29 16:28:16 +03:00
Taner Sener d1ccc2e219 add iOS modulemap for mobileffmpeg.framework, fixes #166 2019-06-29 02:31:18 +03:00
Taner Sener bfafe4cd84 update README 2019-06-25 17:45:11 +03:00
Taner Sener c67e2b0aaa enable travis builds on master and development branches fixes #160 2019-06-25 17:40:45 +03:00
Taner Sener 61ebdd4532 merge travis build configuration 2019-06-25 17:22:26 +03:00
Taner Sener 605c43511f Merge branch 'development' into travis-test 2019-06-25 17:20:40 +03:00
Taner Sener 29a4866fff enable travis android jobs 2019-06-25 14:39:44 +03:00
Taner Sener 25dc08be0e implement --no-output-redirection hidden flag 2019-06-25 13:10:41 +03:00
Taner Sener 6c1117baf8 test travis ios lts build fix #11 2019-06-25 10:02:44 +03:00
Taner Sener 247a0c3f6a test travis ios lts build fix #10 2019-06-25 09:30:09 +03:00
Taner Sener aa2370c665 test travis ios lts build fix #9 2019-06-25 09:24:43 +03:00
Taner Sener c4504de8d0 test travis ios lts build fix #8 2019-06-25 09:10:54 +03:00
Taner Sener 61d9e890ec test travis ios lts build fix #7 2019-06-25 08:40:34 +03:00
Taner Sener a878c0ec84 test travis ios lts build fix #6 2019-06-25 08:35:47 +03:00
Taner Sener 979d9a0b18 test travis ios lts build fix #5 2019-06-25 08:14:51 +03:00
Taner Sener 056da3a64f test travis ios lts build fix #4 2019-06-25 07:47:11 +03:00
Taner Sener 1ffc0632cf test travis ios lts build fix #3 2019-06-25 07:40:49 +03:00
Taner Sener 877c8fdfd9 test travis ios lts build fix #2 2019-06-25 07:21:08 +03:00
Taner Sener 20b54df76c test travis ios lts build fix 2019-06-25 07:17:44 +03:00
Taner Sener 1191d09d45 enable all android, ios and tvos jobs for travis 2019-06-24 23:37:54 +03:00
Taner Sener 78bc0ef275 add travis ios test job 2019-06-24 23:07:45 +03:00
Taner Sener a3c922e11b add all travis android jobs 2019-06-24 23:00:21 +03:00
Taner Sener d63649a67a enable travis job matrixes 2019-06-24 21:46:26 +03:00
Taner Sener ddd1ba8468 add travis license and cache sections 2019-06-24 20:59:24 +03:00
Taner Sener 6326504628 implement hidden --no-link-time-optimization flag for android 2019-06-24 17:44:42 +03:00
Taner Sener 308b269710 add travis platform dependency 2019-06-24 15:48:58 +03:00
Taner Sener e2bcbe18d2 Add travis confguration 2019-06-24 15:38:37 +03:00
Taner Sener 981741de0b implement hidden --no-workspace-cleanup- flag for ffmpeg builds 2019-06-24 14:58:07 +03:00
Taner Sener b9ca079fd7 log --reconf and --rebuild flags, fixes #159 2019-06-24 14:21:36 +03:00
Taner Sener 39920243ea include development builds link in README 2019-06-23 13:50:50 +03:00
Taner Sener 8f288e3971 upgrade gradle wrapper to 5.4.1 2019-06-23 12:06:35 +03:00
Taner Sener dea2d51783 fix android lint issues 2019-06-23 11:44:04 +03:00
Taner Sener 6fdf6e4dec fix gradle warnings 2019-06-23 10:41:24 +03:00
Taner Sener 137e3aa1c3 update gradle bintray plugin 2019-06-23 10:06:22 +03:00
Taner Sener eb7649e666 update version as 4.2.2 2019-06-22 22:08:16 +03:00
Taner Sener 56b4e1eeb1 use new libaom version 1.0.0-1974-g32185d165 2019-06-22 22:02:35 +03:00
Taner Sener fe6f1299ae use new x264 version snapshot-20190621 2019-06-22 21:31:41 +03:00
Taner Sener 17cc87793a use new ffmpeg version 4.2-dev-1735-gebcf4d354f 2019-06-19 12:24:43 +03:00
Taner Sener 6a0ea618dc use the different cocoapods packages for tvos and ios 2019-06-19 11:23:05 +03:00
Taner Sener 205a3016ef remove allowBackup flag from androidmanifest.xml file, fixes #154 2019-06-18 13:30:07 +03:00
Taner Sener 3a1e7507d5 use new opus version 1.3.1 2019-06-15 09:23:51 +03:00
Taner Sener adac5c4a7d use new libpng version 1.6.37 2019-06-15 00:00:20 +03:00
Taner Sener 51b232670a use new libiconv version 1.16 2019-06-14 23:58:25 +03:00
Taner Sener 0e2357f761 use new fontconfig version 2.13.91 2019-06-14 23:44:13 +03:00
Taner Sener bcb22f9e63 clean script updated 2019-06-14 19:13:22 +03:00
Taner Sener 3a252b5059 use ffmpeg 4.2-dev-1720-gc9c1711f49 2019-06-14 18:57:28 +03:00
Taner Sener 7d24edd1b2 support openh264, fixed #152 2019-06-14 16:56:48 +03:00
Taner Sener e4b43d6584 add gif samples for tvos platform 2019-06-11 15:40:13 +03:00
Taner Sener cfb9d40f0b update README 2019-06-11 13:00:14 +03:00
Taner Sener 4092ada348 add tvos test-applications 2019-06-11 00:15:54 +03:00
Taner Sener ec6a7c40ac auto-disable 32-bit architectures on IOS 11 and 12, fixes #149 2019-06-11 00:15:54 +03:00
Taner Sener b7785d5bf2 support tvos, fixed #151 2019-06-11 00:15:53 +03:00
Taner Sener 0eea0a3246 getSupportedCameraIds api method introduced on android, fixes #145 2019-05-29 12:00:18 +03:00
Taner Sener f16edb5779 fix version strings in Info.plist file, fixes #141
(cherry picked from commit 88f2d7d728)
2019-05-21 16:18:30 +03:00
Taner Sener 88f2d7d728 fix version strings in Info.plist file 2019-05-21 16:13:10 +03:00
Taner Sener 413a4cb5a6 disable libgif auto-detection for libwebp on ios 2019-05-13 19:32:00 +03:00
Taner Sener ff3d2f94fa remove android:label property from AndroidManifest.xml 2019-05-04 09:09:45 +03:00
Taner Sener 48b909445c include proguard configuration in aar archive, fix #128 2019-04-27 23:11:26 +03:00
Taner Sener 6369bf54a8 fix libvpx build errors on android lts 2019-04-27 10:49:02 +03:00
Taner Sener cb5285a749 add async execution utility class for Android 2019-04-27 08:45:51 +03:00
Taner Sener a91f51bdcc support api level 16 on android by implementing missing functions in android_lts_support library 2019-04-27 00:25:02 +03:00
Taner Sener c103dc0f16 explicitly specify LOCAL_ARM_NEON flag on Android.lts.mk 2019-04-26 13:05:32 +03:00
Taner Sener 2a8317e3fe trigger arm-v7a-neon check when armeabi-v7a is loaded, fix #126 2019-04-26 12:53:31 +03:00
Taner Sener ef004c8d03 Revert "use api level 18 for android lts releases"
This reverts commit a019c44f56.
2019-04-24 15:23:50 +03:00
Taner Sener 0da03186ac add release notes links in version history table 2019-04-22 12:32:36 +03:00
Taner Sener c1422648aa reverse version history table order 2019-04-22 12:26:48 +03:00
Taner Sener 19852f9193 update versions section in README 2019-04-22 12:21:43 +03:00
Taner Sener c50917ab27 exclude unwider libraries during linking for android 2019-04-21 14:46:11 +03:00
Taner Sener 328e93680c update test-app kvazaar command 2019-04-21 14:45:22 +03:00
Taner Sener 3e647a4bbf remove api level 21 specific features 2019-04-21 11:06:31 +03:00
Taner Sener 5ed1871c6d use an lts specific build.gradle file for lts releases 2019-04-21 10:14:38 +03:00
Taner Sener 846b986f1c add setNativeEnvironmentVariable method for android 2019-04-20 17:00:18 +03:00
Taner Sener a019c44f56 use api level 18 for android lts releases 2019-04-20 13:41:46 +03:00
Taner Sener d4e87a8f2a add side data to stream information, fix #123 2019-04-18 19:22:50 +03:00
Taner Sener 56ccd1f2de fix metadata creation for stream information on ios, fix #122 2019-04-18 18:52:52 +03:00
Taner Sener f6d8703027 fix data stream parsing errors on ios 2019-04-18 17:44:09 +03:00
Taner Sener 579c435442 fix data stream parsing errors on android 2019-04-18 17:30:58 +03:00
Taner Sener cd9c858d93 add generic stream test cases for media information parsing 2019-04-18 16:40:41 +03:00
Taner Sener c6be30edca add metadata test cases for media information parsing 2019-04-18 15:44:46 +03:00
Taner Sener 02916b6ce4 add new test cases for media information parsing 2019-04-18 15:06:54 +03:00
Taner Sener e32e5fc13c update test-app Podfile.lock 2019-04-18 14:31:19 +03:00
Taner Sener 6b94aeea2d add ANDROID_HOME validation 2019-04-07 15:23:21 +03:00
Taner Sener 48774bf01a improve getMediaInformation, fix #113 2019-04-07 11:19:57 +03:00
Taner Sener d91065b3b6 fix ld: symbol(s) not found for architecture x86_64 errors 2019-04-06 10:05:53 +03:00
Taner Sener b3702699e2 fix ld: symbol(s) not found for architecture x86_64 errors 2019-04-05 18:38:19 +03:00
Taner Sener 44043868b8 fix paths in clean script 2019-04-03 19:31:44 +03:00
Taner Sener 2e26282b4a Merge pull request #112 from tanersener/development
merge the latest documentation updates
2019-04-03 19:24:50 +03:00
Taner Sener 4988ab9cc6 update README 2019-04-03 19:22:15 +03:00
Taner Sener 83503c1fdb disable gitter 2019-04-03 19:19:50 +03:00
Taner Sener 69b5c6e8a5 fix gradle warnings 2019-04-03 19:15:22 +03:00
Taner Sener 50acbeb4c8 remove unused declarations from app build.gradle 2019-04-03 19:07:55 +03:00
Taner Sener aa87ece761 version bump in ios autotools 2019-04-03 18:59:53 +03:00
Taner Sener ccd068b11b Merge pull request #110 from tanersener/development
merge v4.2.1 to master
2019-04-02 21:22:58 +03:00
Taner Sener dd35c6131a release v4.2.1 2019-04-02 21:18:43 +03:00
Taner Sener e0d7b9cad6 update ios test applications with v4.2.1 packages 2019-04-02 20:46:12 +03:00
Taner Sener 8b3692267f fix podspec errors 2019-04-02 19:59:25 +03:00
Taner Sener ac4893216c use v4.2.1 release in android test-application 2019-04-02 18:54:54 +03:00
Taner Sener 23b701a556 fix android release script for http-gpl package 2019-04-02 18:04:30 +03:00
Taner Sener 69b2fa6e03 set android target sdk version to 28 in release scripts 2019-04-02 13:04:51 +03:00
Taner Sener c2870db53c add libc++_shared library dependency to x265 2019-04-02 09:56:33 +03:00
Taner Sener cccd72d96a set android target sdk version to 28 2019-04-02 09:56:33 +03:00
Taner Sener 5472992f83 upgrade gradle plugin version to 3.3.2 2019-04-02 09:56:33 +03:00
Taner Sener 0107986bdf move android release build files under tools/release/android 2019-04-02 09:56:32 +03:00
Taner Sener a3887fda89 prepare v4.2.1 2019-04-02 09:56:31 +03:00
Taner Sener e76ae61e2b autoreconf fontconfig 2019-04-01 09:56:48 +03:00
Taner Sener b4a75138e2 autoreconf libuuid 2019-04-01 09:48:53 +03:00
Taner Sener 5b3db7db41 disable realtime only for libvpx 2019-03-31 11:19:35 +03:00
Taner Sener b5f7531dff replace printf calls with av_log, fixes #104 2019-03-29 21:57:14 +03:00
Taner Sener 3a2ebf15f0 update mobile-ffmpeg library using ffmpeg/fftools 2019-03-29 21:45:30 +03:00
Taner Sener 0f61b7e0bf use new x264 version snapshot-20190328-2245-stable 2019-03-29 20:04:55 +03:00
Taner Sener 2456c963e6 use new ffmpeg version v4.2-dev-1156-g9dece050ef 2019-03-29 19:22:14 +03:00
Taner Sener d124a16627 use new libaom version v1.0.0-1544-g5bdd95475 2019-03-29 18:03:01 +03:00
Taner Sener 1434d0c300 use new libwebp version v1.0.2 2019-03-29 17:32:10 +03:00
Taner Sener 5fc5c86749 use new libjpeg turbo version v2.0.2 2019-03-29 16:16:58 +03:00
Taner Sener 2e969093e8 use new leptonica version v1.78.0 2019-03-29 16:09:36 +03:00
Taner Sener f7526b861e use new freetype version v2.10.0 2019-03-29 15:58:03 +03:00
Taner Sener 71ec510992 fix xcode 10 compatibility issues, fixes issues #60 and #106 2019-03-29 14:49:58 +03:00
Taner Sener 738b93cb42 use 12.1 as IOS_MIN_VERSION 2019-03-26 17:33:12 +03:00
Taner Sener dd695b64f0 print build options during compilation 2019-03-25 20:22:37 +03:00
Taner Sener 882e3303c7 Revert "import predefined cpufeatures module in android ndk-build" 2019-03-25 19:10:48 +03:00
Taner Sener 2a68ce3a5b print build date on library initialization 2019-03-25 00:49:54 +03:00
Taner Sener c0b471b312 fix cpu-features linking error for libvpx on android platform as mentioned in #102 2019-03-24 23:25:50 +03:00
Taner Sener 31e3b2b836 add info severity to system information in build log 2019-03-24 21:12:27 +03:00
Taner Sener 8f94235dc0 print BUILD_VERSION during compilation 2019-03-24 20:32:16 +03:00
Taner Sener 0b1ceb031f update default android.mk for android builds 2019-03-24 17:55:17 +03:00
Taner Sener 7a2cea646b remove config.h includes from library headers, fix #100 2019-03-22 12:30:32 +03:00
Taner Sener b18006fceb import predefined cpufeatures module in android ndk-build 2019-03-04 18:25:32 +03:00
Taner Sener 16c335981e remove c++_shared dependency for ffmpeg on android, fixes #92 2019-03-04 16:53:40 +03:00
Taner Sener 2db0de4d8e remove app icons from android library, fix #88 2019-02-23 14:19:17 +03:00
Taner Sener 38fd55e605 upgrade gradle wrapper to v5.2.1, fixes #87 2019-02-20 12:56:39 +03:00
Taner Sener 801377f739 register active JVM with av_jni_set_java_vm(), fix #83 2019-02-14 20:55:39 +03:00
Taner Sener 143347c530 enable signing and proguard for android test-app release builds, fix #82 2019-02-14 15:34:27 +03:00
Taner Sener cdf1532e1d fix ffmpeg arm64 build errors 2019-02-09 11:19:11 +03:00
Taner Sener e99bec4622 add log guards for nslog statements in ios library 2019-02-09 10:07:31 +03:00
Taner Sener fcb298b91a fix doxygen errors 2019-02-08 23:59:59 +03:00
Taner Sener cd58ea32c1 update javadoc 2019-02-08 23:30:07 +03:00
Taner Sener 850da3004d fix android javadoc errors 2019-02-08 23:17:00 +03:00
Taner Sener 73285ef20a use new ffmpeg version v4.2-dev-768-g7f8bfbee36 2019-02-08 22:56:44 +03:00
Taner Sener 027d9ac753 use new libaom version v1.0.0-1318 2019-02-08 22:50:55 +03:00
Taner Sener e27ab37249 use new x265 version v3.0 2019-02-08 22:42:10 +03:00
Taner Sener 92248f3f33 add a new async command task for android 2019-02-08 17:18:30 +03:00
Taner Sener b3d0c650fb implement pipe support and add a pipe tab inside test-applications. 2019-02-08 12:05:03 +03:00
Taner Sener 19fc09e378 update libvpx version to 1.8.0 2019-02-05 16:40:45 +03:00
Taner Sener cbb059aa1f add clean script to delete binary files 2019-02-02 18:51:30 +03:00
Taner Sener debd06db88 downgrade sdl to v2.0.8 2019-01-31 20:38:25 +03:00
Taner Sener c2b2226e16 do not use -DDEBUG when debug flag is present, fix #74 for ios. 2019-01-31 15:34:54 +03:00
Taner Sener 299f176e45 do not --enable-lto for ffmpeg when debug flag is present, fix #74 for android. 2019-01-29 18:32:23 +03:00
Taner Sener 06811386a3 do not --enable-lto for ffmpeg when debug flag is present, fix #74 for android. 2019-01-29 18:27:34 +03:00
Taner Sener 8650308bfb use new ffmpeg version v4.2-dev-702-gd8ebfd1bdf 2019-01-27 12:26:34 +03:00
Taner Sener 3005a673cd use new libxml2 version 2.9.9 2019-01-27 12:19:45 +03:00
Taner Sener 3a91363d1d fix android scripts for ndk r19, #72 2019-01-27 09:29:44 +03:00
Taner Sener 2fc9e360ad Update am__api_version in libilbc/configure 2019-01-22 17:54:33 +03:00
Taner Sener d6b935dac5 Merge pull request #71 from RexProg/master
Update configure
2019-01-22 17:48:03 +03:00
RexProg 42c1732886 Update configure 2019-01-22 17:32:59 +03:30
Taner Sener 4ffd9b31f2 include documentation_url in full and full-gpl podspec files. 2019-01-18 00:40:59 +03:00
Taner Sener c92b236b5c update podspec file to enable cocoapods.org page generation 2019-01-17 23:54:54 +03:00
Taner Sener e8d60ac392 Merge pull request #69 from tanersener/development
remove <br/> from last rows
2019-01-08 14:26:52 +03:00
Taner Sener 4a2d1221e3 remove <br/> from last rows 2019-01-08 13:52:05 +03:00
Taner Sener 15b4f67060 Merge pull request #68 from tanersener/dev-v4.2
merge v4.2 updates
2019-01-08 13:49:10 +03:00
Taner Sener 7e8b90a2fb update strip-frameworks.sh references 2019-01-08 13:37:05 +03:00
Taner Sener 852d148727 update asset paths in docs 2019-01-08 13:25:28 +03:00
Taner Sener 5f9813877f disable lto for IOS 2019-01-02 20:20:39 +03:00
Taner Sener 77ba8681ff Merge pull request #64 from tanersener/dev-v4.2
apply minor documentation updates from dev-v4.2 branch
2018-12-31 14:35:17 +03:00
Taner Sener c5aeb63278 apply minor documentation updates 2018-12-31 14:30:10 +03:00
Taner Sener 85bab613bf Merge pull request #63 from tanersener/dev-v4.2
merge v4.2 to master
2018-12-30 15:15:40 +03:00
Taner Sener 64e4f81ff6 update README 2018-12-30 15:13:53 +03:00
Taner Sener 85aa254fb0 update README 2018-12-30 13:45:32 +03:00
Taner Sener 76b6e82993 use latest released version on ios test-app 2018-12-29 11:33:43 +03:00
Taner Sener 8c756b8033 use latest released version in android test-app 2018-12-29 09:46:25 +03:00
Taner Sener 1c6963374c update test application build numbers 2018-12-28 21:53:34 +03:00
Taner Sener 3a18694799 clean release directories in ios release scripts 2018-12-28 20:40:21 +03:00
Taner Sener edb7c6bce2 fix x265 ios bitcode errors 2018-12-28 18:31:42 +03:00
Taner Sener a7de983214 update ios podspec dependencies 2018-12-28 14:00:33 +03:00
Taner Sener 11b0155110 assembly disabled for x264 on IOS i386 and x86_64 2018-12-28 13:51:48 +03:00
Taner Sener 16a55ccd0e fix ios package detection 2018-12-27 16:17:57 +03:00
Taner Sener 92c81bedaa fix android package detection 2018-12-27 16:10:38 +03:00
Taner Sener 73d05ee3a2 use v4.2.LTS in android test-app 2018-12-27 15:43:00 +03:00
Taner Sener 836d1450db use deployment target 9.3 for ios lts releases 2018-12-27 13:56:50 +03:00
Taner Sener b6b29cc2c2 update api documentation 2018-12-27 12:17:39 +03:00
Taner Sener c306df44af fix tesseract source code 2018-12-27 10:47:36 +03:00
Taner Sener d1ac2b37b6 rollback to tesseract v3.05.02 2018-12-27 10:45:06 +03:00
Taner Sener c4f30fb621 update tesseract .pc versions 2018-12-27 10:16:20 +03:00
Taner Sener d88571e30f fix android release scripts 2018-12-27 00:38:40 +03:00
Taner Sener 95c4b2eb75 move isNativeLTSBuild method inside AbiDetect class 2018-12-26 22:14:16 +03:00
Taner Sener 5555f759c0 fix android init log for non-lts releases 2018-12-26 22:14:16 +03:00
Taner Sener 9c87ef0546 use the same value for compile sdk version and target sdk version 2018-12-26 22:14:16 +03:00
Taner Sener 69cee669d4 move ios isLTSBuild method inside ArchDetect class 2018-12-26 21:38:12 +03:00
Taner Sener 056be3480d perform darwin os checks earlier in ios.sh 2018-12-26 20:22:36 +03:00
Taner Sener c8a1f43446 update release scripts 2018-12-26 19:21:14 +03:00
Taner Sener 7b8c0e528a change build dependencies for android arm-v7a-neon architecture. 2018-12-26 01:05:47 +03:00
Taner Sener a1bed50fa7 use new ffmpeg version v4.2-dev-480-g70c86deb8e 2018-12-25 23:39:14 +03:00
Taner Sener 3e98adc541 add lts flag to cflags 2018-12-25 22:59:36 +03:00
Taner Sener c47e6e7a70 enable lts version for android 2018-12-25 15:58:55 +03:00
Taner Sener afd7cc625a use new sdl version v2.0.9 2018-12-25 13:39:02 +03:00
Taner Sener f5a5ec85b8 use new tesseract version v4.0.0 2018-12-25 13:34:34 +03:00
Taner Sener 733566386b use new leptonica version v1.77.0 2018-12-25 13:21:13 +03:00
Taner Sener 08b07197f2 use new libpng version v1.6.36 2018-12-25 13:12:22 +03:00
Taner Sener 0602d3ed42 use new libaom version v1.0.0-1053-g440e6d412 2018-12-25 12:59:46 +03:00
Taner Sener 17a21867e0 use new x264 version snapshot-20181224-2245-stable 2018-12-25 12:41:42 +03:00
Taner Sener 5e3ed008fd enable asm for libvpx on ios arm64e 2018-12-25 12:06:37 +03:00
Taner Sener d5f6327634 fix libaom build on ios arm64e 2018-12-25 11:35:34 +03:00
Taner Sener e71f879506 use sdk version as ios min version 2018-12-24 22:14:20 +03:00
Taner Sener 9d1a7f9893 create ios framework for each external library 2018-12-24 19:11:12 +03:00
Taner Sener fb87f6fb93 fix ios --lts build errors 2018-12-23 12:34:02 +03:00
Taner Sener 84f64466c6 fix wrong paths for ios libwebp build 2018-12-23 09:39:33 +03:00
Taner Sener c29766c11d update test apps with new binaries 2018-12-22 23:16:38 +03:00
Taner Sener 9ddb8e716a drop shared libraries support for ios, fix #59 2018-12-22 21:49:31 +03:00
Taner Sener 938ccf28b2 add CFBundleSupportedPlatforms key to the info.plist file, fix #58 2018-12-22 21:32:37 +03:00
Taner Sener 8351675692 add new ios test-app for universal binaries 2018-12-21 20:31:35 +03:00
Taner Sener 66d0e2a43d rename default ios test-app as pods-with-tooltip 2018-12-21 13:35:44 +03:00
Taner Sener 1ef044c87f add a new ios test-app with manual frameworks 2018-12-21 12:20:16 +03:00
Taner Sener fd57251531 update ios test-app info.plist 2018-12-21 09:42:51 +03:00
Taner Sener a145bb6e06 update size optimization flags 2018-12-19 20:13:44 +03:00
Taner Sener 1a33b54893 do not warn about not supported optimization arguments on ios 2018-12-19 18:36:57 +03:00
Taner Sener b77614be2e fix default ios releases 2018-12-19 15:34:16 +03:00
Taner Sener 3dcff03844 add guards for ios sdk v12.1 specific constants 2018-12-19 15:32:10 +03:00
Taner Sener 7294c21d85 set ffmpeg debug option by top level build script 2018-12-19 14:54:25 +03:00
Taner Sener 2c579d33cb patch gas-preprocessor.pl against regex warnings 2018-12-19 14:47:43 +03:00
Taner Sener 703242e65c fix debug and size optimization flags 2018-12-19 13:51:06 +03:00
Taner Sener 45ff661719 disable armv7 and armv7s for main build, armv7s for lts 2018-12-19 12:31:20 +03:00
Taner Sener ffc9f609f0 android cpu abi implemented 2018-12-19 10:31:22 +03:00
Taner Sener 30a90c1318 support ios arm64e architecture 2018-12-19 09:28:15 +03:00
Taner Sener 13ac2cdc70 set next release number 2018-12-19 09:26:45 +03:00
Taner Sener d8a902a405 Log active sdk version for IOS 2018-12-18 23:28:55 +03:00
Taner Sener 3a52290297 Reorganize Info.plist entries 2018-12-18 21:44:19 +03:00
Taner Sener 3390f7e076 Remove unused gnutls specific IOS_MIN_VERSION variable 2018-12-18 21:37:52 +03:00
Taner Sener 3bd8087fb2 add strip-frameworks.sh script to shared universal library, fixes #55 2018-12-18 21:01:15 +03:00
Taner Sener 776a14dd0b add ios-frameworks wiki assets 2018-12-18 18:12:39 +03:00
Taner Sener 5a2397f39c apply issue #18 patch in ios test application 2018-12-17 20:47:38 +03:00
Taner Sener 5d6b1341b2 add patch script for issue #18 2018-12-17 19:51:45 +03:00
Taner Sener 4ef0f24b1d Merge branch 'master' into dev-v3.x 2018-12-16 22:22:48 +03:00
Taner Sener af2d21458d disable unused devices for ffmpeg IOS build 2018-12-16 22:20:14 +03:00
Taner Sener 5bf6afe0bf disable assembly for xvidcore on IOS x86-64 2018-12-16 22:20:14 +03:00
Taner Sener ca562561e7 fix test errors 2018-12-16 22:20:14 +03:00
Taner Sener e20a27f60d disable unusable devices from ffmpeg android build 2018-12-16 11:53:50 +03:00
Taner Sener 23fecea67f decrease size of ios binaries 2018-12-14 15:11:15 +03:00
Taner Sener 4b1feed331 decrease size of android libraries 2018-12-12 19:17:00 +03:00
Taner Sener 6d5ffc8da0 update versions section as releases 2018-12-12 01:20:02 +03:00
Taner Sener 1cc5d7067c Merge pull request #52 from tanersener/dev-v3.x
fix github page errors
2018-12-12 00:34:27 +03:00
Taner Sener 6c799e4a2e fix github page errors 2018-12-12 00:32:43 +03:00
Taner Sener 28a61a4699 Set theme jekyll-theme-minimal 2018-12-11 22:44:18 +03:00
Taner Sener 99f08588e1 Set theme jekyll-theme-modernist 2018-12-11 22:41:28 +03:00
Taner Sener cd871f5ff8 Merge pull request #51 from tanersener/dev-v3.x
merge v3.1 to master
2018-12-11 00:37:40 +03:00
Taner Sener d634b5d11b Merge branch 'master' into dev-v3.x 2018-12-11 00:36:51 +03:00
Taner Sener d05b37571a merge v3.1 to master 2018-12-11 00:30:11 +03:00
Taner Sener 9408c5d40c merge branch 'master' into dev-v3.x 2018-12-11 00:24:31 +03:00
Taner Sener 64c1cf6e1e use v3.1 in ios test-app 2018-12-11 00:07:35 +03:00
Taner Sener 8521c29ac8 apply post-release updates 2018-12-10 21:29:04 +03:00
Taner Sener 327d65307e use v3.1 in android test-app 2018-12-10 19:22:32 +03:00
Taner Sener 10567f8c90 release v3.1 2018-12-10 09:47:26 +03:00
Taner Sener 8fb5cf4527 use longer android versionCode 2018-12-09 23:43:45 +03:00
Taner Sener 502ff33107 use new toolchain name for android 2018-12-09 22:48:00 +03:00
Taner Sener a0e9b21515 use new nettle version: v3.4.1 2018-12-09 18:09:16 +03:00
Taner Sener 54ab8353a2 use new x264 version: snapshot-20181208-2245-stable 2018-12-09 18:03:07 +03:00
Taner Sener 9c6e4c7f6f use new libwebp version: v1.0.1 2018-12-09 18:01:43 +03:00
Taner Sener 696081f580 use new tiff version: v4.0.10 2018-12-09 12:59:36 +03:00
Taner Sener 86e1f752e8 use new libjpeg-turbo version: v2.0.1 2018-12-09 12:55:52 +03:00
Taner Sener 4d83b4c396 use new libaom version: v1.0.0-1014-gbf0a6f9d1 2018-12-09 12:49:34 +03:00
Taner Sener 200a2c8289 use new ffmpeg version: n4.1-10-g59e30c05d7 2018-12-09 12:38:35 +03:00
Taner Sener f1f35f7e2c remove not supported set_toolchain_gcc_paths function from build scripts, as part of fix #48 2018-12-09 12:04:32 +03:00
Taner Sener 7b0b8a68d8 Process callback data inside @autoreleasepool block, fix #47 2018-12-09 09:48:57 +03:00
Taner Sener 9aa8afbaa5 Process log level earlier, fix #50 2018-12-09 09:39:48 +03:00
Taner Sener 4d5e759953 use gradle wrapper for android test-app 2018-12-09 00:48:31 +03:00
Taner Sener 12d2cc1665 fix android libvorbis build errors 2018-12-08 23:44:00 +03:00
Taner Sener ad74fbba8d Use gradle wrapper for Android. 2018-12-08 21:05:52 +03:00
Taner Sener 15a107a0fd Upgrade gradle wrapper version. 2018-12-08 20:56:19 +03:00
Taner Sener 5b392e4a85 Use new version of Android gradle plugin. 2018-12-08 20:41:24 +03:00
Taner Sener d719a02d14 disable sdl2 auto-detection in ffmpeg build scripts. 2018-12-08 11:27:04 +03:00
Taner Sener 6ac802ce81 video4linux2 enabled again, #48 fixed with option 2. 2018-12-07 21:24:39 +03:00
Taner Sener f6843481e4 Disable v4l2 and fix #48. 2018-12-07 09:42:07 +03:00
Taner Sener e259e4a437 android ndk version is printed during library compilation. 2018-12-06 21:00:02 +03:00
Taner Sener 0897c655b1 Disabled fontconfig test bz106632.c due to deprecated system() calls 2018-11-18 09:15:58 +03:00
Taner Sener 3a14b142f7 README updated: Versions section revised as Releases 2018-11-12 19:18:12 +03:00
Taner Sener bb1399ad83 test-app: amr conversion command updated 2018-10-28 15:40:09 +03:00
Taner Sener 84d8a153c2 Stream information typo fixed 2018-10-26 17:00:32 +03:00
Taner Sener 91ee58ca4b delimiter validation added in execute() 2018-10-26 14:35:20 +03:00
Taner Sener 334987736a documentation update 2018-10-26 14:11:46 +03:00
Taner Sener 8d3d809482 Merged v3.0 2018-10-25 21:38:54 +03:00
Taner Sener fbf8757bc9 Unused source files removed 2018-10-25 21:20:58 +03:00
Taner Sener eb5810a2b3 ios test-app using v3.0 2018-10-25 20:41:20 +03:00
Taner Sener 05dee70dcc documentation update 2018-10-25 18:00:49 +03:00
Taner Sener 9fde72ac48 fixed: gpl package detection 2018-10-25 13:43:43 +03:00
Taner Sener f9912c462c android test-app versions updated 2018-10-25 13:10:53 +03:00
Taner Sener fdfef17c51 README update: package table updated 2018-10-25 01:24:08 +03:00
Taner Sener 5f86552238 README, testing html table 2018-10-25 01:09:50 +03:00
Taner Sener b4287287eb README packages table updated 2018-10-25 00:21:37 +03:00
Taner Sener 5cc967fb92 preparing release 2018-10-24 23:37:48 +03:00
Taner Sener 56df2b1018 doc updated 2018-10-24 21:43:36 +03:00
Taner Sener 5403567631 test-app updated: manual tests added for chromaprint and libwebp 2018-10-24 20:56:00 +03:00
Taner Sener 82e08a56b9 ios update: optional videotoolbox support handled in autools files 2018-10-24 10:15:39 +03:00
Taner Sener e6ff6f2951 version update: ffmpeg v4.1-dev-1517-gc2ac3b8e6a 2018-10-24 09:35:50 +03:00
Taner Sener 1b855d5762 version update: libaom v1.0.0-820-g4c118dc5 2018-10-24 01:58:57 +03:00
Taner Sener 6db573c9b3 version update: opus v1.3 2018-10-24 01:48:29 +03:00
Taner Sener 3831dcfeb8 updated:project logo 2018-10-24 01:29:50 +03:00
Taner Sener 010a11aa78 updated: media file used for https testing 2018-10-24 01:19:20 +03:00
Taner Sener 9c4092acd5 updated: using delimiter in test apps 2018-10-24 00:45:03 +03:00
Taner Sener aa99132930 updated: size optimization disabled on debug builds 2018-10-24 00:38:33 +03:00
Taner Sener 9dfae4be30 updated: cpu architectures on ios 2018-10-24 00:37:56 +03:00
Taner Sener 7f9ebf9988 new api: package detection and external library methods implemented on ios 2018-10-24 00:10:05 +03:00
Taner Sener 36f5dd2ece new api: getLastXXX methods implemented on ios 2018-10-23 19:38:14 +03:00
Taner Sener 133c0c42eb new api: executeWithDelimiter method added for ios 2018-10-23 19:37:42 +03:00
Taner Sener 48645800ec new api: getMediaInformation for ios 2018-10-23 19:26:57 +03:00
Taner Sener 998d3bfa37 updated: new test case for start time 2018-10-22 22:15:47 +03:00
Taner Sener 60d1ed9f90 updated: rounding mode for start time 2018-10-22 13:46:07 +03:00
Taner Sener 209131b92f fixed: index method handling substring length 2018-10-21 22:27:46 +03:00
Taner Sener 1a88f77684 fixed: getMediaInformation method return type fixed on android 2018-10-20 00:28:43 +03:00
Taner Sener a4fadfce40 fixed: last command output filtered based on log severity 2018-10-19 23:28:18 +03:00
Taner Sener a737b02e88 MediaInformationTests completed 2018-10-19 22:02:49 +03:00
Taner Sener 235fe08dc4 MediaInformation classes added. 2018-10-19 11:02:22 +03:00
Taner Sener 893dcf8582 FFmpegTest class added 2018-10-18 08:33:36 +03:00
Taner Sener 2e20471922 custom package name defined on android platform. 2018-10-17 23:39:45 +03:00
Taner Sener baf251e659 fixed: log level is effective for system commands 2018-10-17 22:50:35 +03:00
Taner Sener 1a9ac6dbb0 new api feature: system execute method implemented on android 2018-10-17 21:25:20 +03:00
Taner Sener 317d01c3e6 new native api: getBuildConf method added for android 2018-10-17 20:16:29 +03:00
Taner Sener cd8a8e2145 new api: getExternalLibraries on android 2018-10-17 18:04:46 +03:00
Taner Sener fa8d119669 new api: last return code and last command output on android 2018-10-17 18:03:37 +03:00
Taner Sener 9c5cf7d825 fixed: PIC for cmake based libraries on android platform 2018-10-17 12:22:44 +03:00
Taner Sener 554bbe3fbf android test app permissions updated 2018-10-17 09:28:33 +03:00
Taner Sener 2f2f779d12 android test app updated with twolame test 2018-10-17 08:15:35 +03:00
Taner Sener fe7ea3a975 reverting ffmpeg back to v4.1-dev-1368-gd3bda871f0 2018-10-16 23:07:45 +03:00
Taner Sener ed755140b3 updated: libaom version inside .pc file 2018-10-16 21:23:16 +03:00
Taner Sener b03c484fd3 ios test app updated with new codecs 2018-10-16 20:41:47 +03:00
Taner Sener b665a4ee34 avfoundation enabled for ios 2018-10-16 19:43:19 +03:00
Taner Sener f43eaa7a08 speed option implemented 2018-10-16 19:09:27 +03:00
Taner Sener 55b28d48e6 videotoolbox enabled for ios 2018-10-16 18:41:34 +03:00
Taner Sener cdd2d54f4c Updated package information 2018-10-16 18:02:39 +03:00
Taner Sener fbe3dd4806 version update: libaom-v1.0.0-773-g07f8a18bb 2018-10-16 00:47:17 +03:00
Taner Sener 76ec9d59cf version update: x264-20181015 2018-10-16 00:43:23 +03:00
Taner Sener d2a3df33b6 Public web page updated 2018-10-16 00:41:55 +03:00
Taner Sener 5bffc5ed9d README updated 2018-10-15 22:51:15 +03:00
Taner Sener 95f6fdd9e4 logo name updated 2018-10-15 22:27:51 +03:00
Taner Sener 1a9a47c65b platform specific ffmpeg outputs enabled. 2018-10-15 22:14:57 +03:00
Taner Sener 1d3c0e7f60 ffmpeg n4.1-dev-1457-ge1e6a31216 2018-10-15 21:59:10 +03:00
Taner Sener a307a10c32 updated: ios target host 2018-10-15 20:33:38 +03:00
Taner Sener 78e986bf20 bitcode removed from cxxflags for ios i386 and x86-64 architectures 2018-10-15 20:30:40 +03:00
Taner Sener e702bef31f new external library: tesseract 2018-10-15 04:16:26 +03:00
Taner Sener 006a001fd0 new external library: sdl 2018-10-14 14:14:01 +03:00
Taner Sener 7d29088799 new external library: twolame 2018-10-14 13:36:33 +03:00
Taner Sener dfddf18b52 new major version 2018-10-14 12:22:34 +03:00
Taner Sener 1336eab42f updated: ios release package information 2018-10-14 12:18:44 +03:00
Taner Sener e01989639d fixed: ios x265 v2.9 build errors 2018-10-14 11:41:09 +03:00
Taner Sener 1b041324b4 fixed; android x265 v2.9 linking errors 2018-10-14 10:10:08 +03:00
Taner Sener df3faba968 using x265 v2.9 2018-10-13 23:15:33 +03:00
Taner Sener 85c4fe3308 Update issue templates 2018-10-05 19:52:14 +03:00
Taner Sener 1b3b2c3c2f android native version bump 2018-09-29 18:17:13 +03:00
Taner Sener d9d31985df android test-app version bump 2018-09-29 18:09:12 +03:00
Taner Sener 322877b3c3 versions in fontconfig build scripts updated. 2018-09-29 18:08:49 +03:00
Taner Sener 9d414b9790 Reverted "using ffmpeg n4.1-dev-1349-g179ed2d2e0 version"
This reverts commit 318efe8a5d.
2018-09-29 18:02:18 +03:00
Taner Sener 270fc3f1ad ignored files updated for fontconfig 2018-09-29 14:09:29 +03:00
Taner Sener d2ef2da94b fontconfig patch applied for https://gitlab.freedesktop.org/fontconfig/fontconfig/issues/109 2018-09-29 13:28:41 +03:00
Taner Sener f92c5288b9 fontconfig v2.13.1 2018-09-29 12:17:28 +03:00
Taner Sener 248a6cba7a update release version 2018-09-29 12:17:27 +03:00
Taner Sener 318efe8a5d using ffmpeg n4.1-dev-1349-g179ed2d2e0 version 2018-09-29 11:18:26 +03:00
Taner Sener ea9abafaa7 preparing next minor release 2018-09-29 10:41:21 +03:00
Taner Sener 9ede8768f5 README, misleading Xcode support information corrected 2018-09-29 09:44:05 +03:00
Taner Sener 1fcf112ed0 Minor changes for Xcode 7.3.1 compatibility, fixes #28 2018-09-29 09:31:30 +03:00
Taner Sener ace472d20c Using custom Xcode for building. 2018-09-27 12:34:39 +03:00
Taner Sener 36fa6b0028 New keys added in IOS framework Info.plist file 2018-09-26 13:41:18 +03:00
Taner Sener 841a44e2c8 IOS static universal binary generation merged from dev-v2.x. 2018-09-25 14:27:35 +03:00
Taner Sener 29ca9e37e7 Fixed IOS dynamic framework generation, issue #27 2018-09-25 13:55:19 +03:00
Taner Sener f0a65465e9 README updated. 2018-09-22 23:08:42 +03:00
Taner Sener 4808e4c686 ios static universal libraries fixed. 2018-09-22 22:17:34 +03:00
Taner Sener 41f55f415e Updated README. 2018-09-20 19:48:00 +03:00
Taner Sener 3716c4623b Removed MinimumOSVersion from ios Info.plist 2018-09-19 15:35:45 +03:00
Taner Sener 7ccf16f130 libvpx minimum ios version set to 7.0 in order to build library on IOS 12. 2018-09-19 14:45:32 +03:00
Taner Sener 2cc3a9b0db Building static ios libraries enabled. 2018-09-19 13:48:44 +03:00
Taner Sener 21c071bebe API documentation update. 2018-09-16 20:27:52 +03:00
Taner Sener caa4ac1f9b Using latest released versions. 2018-09-16 20:21:04 +03:00
Taner Sener f438e94c58 Updated documentation 2018-09-16 20:16:20 +03:00
Taner Sener 48b0933d16 Merged v2.1.1 2018-09-16 19:54:53 +03:00
Taner Sener 09caf1e997 Android test application uses the latest published version. 2018-09-16 19:32:50 +03:00
Taner Sener b3109cf276 Preparing v2.1.1 patch for android. 2018-09-16 17:22:23 +03:00
Taner Sener 4bd20725a8 Fixed armeabi-v7a-neon ABI for issue #24 2018-09-16 15:57:31 +03:00
Taner Sener 0a127d4370 armeabi-v7a ABI load log fixed. 2018-09-16 13:59:11 +03:00
Taner Sener ba7afe784d Redirection documentation updated. 2018-09-11 12:12:02 +03:00
Taner Sener e73224d560 Updated setFontDirectory usage example 2018-09-11 07:35:12 +03:00
Taner Sener 4d544fa7ca @rpath paths fixed for frameworks in ios.sh. 2018-09-07 22:23:14 +03:00
Taner Sener d500463706 Universal binary creation fixed. 2018-09-07 20:51:53 +03:00
Taner Sener a3b95188fb Updating version to v2.2 2018-09-07 16:05:51 +03:00
Taner Sener 5a7bd1ab52 IOS API documentation regenerated. 2018-09-07 16:02:48 +03:00
Taner Sener 7d27ab7be5 Merging documentation updates from master. 2018-09-07 15:42:24 +03:00
Taner Sener 6cc35a6dc9 Project web site updated. 2018-09-07 15:25:04 +03:00
Taner Sener 2ee604de1d Project web site updated. 2018-09-07 15:23:44 +03:00
Taner Sener 6af39b5234 Merged v2.1.1 to master. 2018-09-07 15:12:49 +03:00
Taner Sener 7681389a9c Updated IOS test-app to v2.1.1. 2018-09-07 14:05:49 +03:00
Taner Sener e85b08e7c2 preparing IOS v2.1.1 patch, fixes #22. 2018-09-07 12:56:37 +03:00
Taner Sener d298c9ac3b burning subtitles for ios arm architectures fixed. 2018-09-07 09:52:47 +03:00
Taner Sener e0e415f808 Merge branch 'dev-v2.x' 2018-09-05 23:10:26 +03:00
Taner Sener 5ffc79e879 Using new test-app gifs. 2018-09-05 23:02:58 +03:00
Taner Sener 2f08be1ff9 Android test-app icons updated. 2018-09-05 22:55:31 +03:00
Taner Sener 6f5262748f Using EasyTipView from cocoapods. 2018-09-05 22:41:20 +03:00
Taner Sener e2a4766c61 MinimumOSVersion defined in Info.plist for IOS. 2018-09-05 18:01:20 +03:00
Taner Sener 63e87d04ef Public site updated. 2018-09-05 15:58:54 +03:00
Taner Sener fe73ca4697 android test-app dependencies updated. 2018-09-05 14:55:39 +03:00
Taner Sener 68026adb2c README updated. 2018-09-05 13:27:58 +03:00
Taner Sener ede6a05766 video-gpl package removed, currently it has the same libraries with min-gpl. 2018-09-05 10:42:48 +03:00
Taner Sener ba6c218b21 new android release packages fixed. 2018-09-05 09:49:30 +03:00
Taner Sener 1d5b3f7603 ios release script updated. 2018-09-05 03:36:27 +03:00
Taner Sener b33891eba9 android native versions updated 2018-09-05 03:27:53 +03:00
Taner Sener f7cbe9c006 Release packages updated. 2018-09-05 02:09:28 +03:00
Taner Sener 84b740d514 Updating documentation. 2018-09-05 00:45:37 +03:00
Taner Sener 703459c2cf ios test-app icons updated. 2018-09-04 22:37:31 +03:00
Taner Sener 04d2709eb4 -d, --debug option added. 2018-09-04 22:37:31 +03:00
Taner Sener 05d2422bd5 video codec explicitly specified. 2018-09-04 21:56:55 +03:00
Taner Sener f57a3c6c05 paths fixed for subtitle tab. 2018-09-04 21:56:13 +03:00
Taner Sener 5392566ed6 x265 assembly disabled for android x86. 2018-09-04 21:25:47 +03:00
Taner Sener 58cff5c8fb android icons updated. 2018-09-04 21:25:04 +03:00
Taner Sener 2f854d843a hiding keyboard when buttons are clicked @ ios test-app command tab. 2018-09-01 22:10:46 +03:00
Taner Sener 6d02e9b0dc missing arm cpus added for ios cpu detection. 2018-09-01 22:02:58 +03:00
Taner Sener 156f51cacf ios test-app launch screen modified. 2018-09-01 21:39:42 +03:00
Taner Sener de7c992bd7 ARC enabled for ios. Fixes #16 2018-09-01 20:02:41 +03:00
Taner Sener 9ca086452c ios x265 compilation updated. 2018-09-01 19:12:26 +03:00
Taner Sener b96ac2b4b3 unnecessary log lines removed from gas-preprocessor download phase. 2018-09-01 15:38:38 +03:00
Taner Sener 05cc4f9998 Android icons updated. 2018-09-01 14:12:43 +03:00
Taner Sener 870c674e0c assembly disabled for android arm due to relocation errors. 2018-09-01 13:49:12 +03:00
Taner Sener 166404fecc SIGSEGV fixed for android x86_64 architecture. 2018-09-01 10:52:21 +03:00
Taner Sener 633238b79f README logo link updated. 2018-08-30 20:21:21 +03:00
Taner Sener b6ac3d143d README updated. 2018-08-30 20:15:18 +03:00
Taner Sener e5581f60ce android test app icon registered. 2018-08-30 19:31:26 +03:00
Taner Sener 1ad6a02bf7 ios test app icon registered. 2018-08-30 19:30:45 +03:00
Taner Sener 47d8c54da3 assembly disabled for gmp. 2018-08-30 17:41:50 +03:00
Taner Sener e1870ecde9 Using newer x264 snapshot. 2018-08-30 16:42:53 +03:00
Taner Sener 761aa55a46 Using newer libaom snapshot. 2018-08-30 16:38:46 +03:00
Taner Sener 1e67fdb1e9 Using expat v2.2.6. 2018-08-30 16:35:25 +03:00
Taner Sener da48d1edb8 README updated. 2018-08-30 16:01:28 +03:00
Taner Sener a7c009704e Test applications updated. 2018-08-14 00:11:42 +03:00
Taner Sener c144aa3058 (!received_sigterm) validation added inside ifilter_send_eof() to complete operation cancellation. 2018-08-13 23:41:42 +03:00
Taner Sener c1584b8080 Using new features in IOS test-app. Closes issues #14 and #15. 2018-08-13 10:36:30 +03:00
Taner Sener dd6341359d Bug fixes for IOS api. 2018-08-13 08:20:13 +03:00
Taner Sener 107b5f1efd Uncaught exception handler added for IOS test-app. 2018-08-13 08:15:48 +03:00
Taner Sener 529893fd84 Updated statistics forwarding rules. 2018-08-13 08:13:58 +03:00
Taner Sener 6aee1343f0 IOS API redesigned. 2018-08-12 21:48:52 +03:00
Taner Sener c0d231337e Package refactoring for RunCallback class. 2018-08-11 07:49:43 +03:00
Taner Sener 77d8e86859 Using newer gradle plugin version. 2018-08-11 02:09:57 +03:00
Taner Sener a578211c67 Android API redesigned. 2018-08-11 02:06:12 +03:00
Taner Sener ef1bbd1c78 New versions for x264 and libaom. 2018-08-09 18:27:14 +03:00
Taner Sener 502df26547 errors fixed in ios test-app vidstab tab. 2018-08-09 18:18:41 +03:00
Taner Sener fa2d24e136 Android test application updated. 2018-08-09 17:55:01 +03:00
Taner Sener 0eb3f23dde Better tooltip registration for android test-app. 2018-08-07 23:47:55 +03:00
Taner Sener 5b999a40c4 Log callback function string allocation improved. 2018-08-07 23:45:02 +03:00
Taner Sener 22bddcf207 Android test-app updated. 2018-08-07 22:52:33 +03:00
Taner Sener 49e7f5e312 info popups added for command and vid.stab tabs. 2018-08-07 09:10:16 +03:00
Taner Sener ecb97b6b9a snappy ios link options updated. 2018-08-07 01:55:04 +03:00
Taner Sener 043138e413 libjpeg-turbo ios build script updated with cmake. 2018-08-07 01:32:42 +03:00
Taner Sener 8cb63decf4 assembly disabled in gmp for android arm-v7a and arm-v7a-neon due to linking errors. 2018-08-07 00:01:44 +03:00
Taner Sener c81ee56ab4 Android log redirection errors fixed. 2018-08-06 23:52:30 +03:00
Taner Sener 0a0f008aca Updated libjpeg-turbo to v2.0.0. 2018-08-05 19:34:23 +03:00
Taner Sener 328e37db0f Updated libpng to v1.6.35. 2018-08-05 19:04:39 +03:00
Taner Sener 4f36ac31fc Updated fribidi to v1.0.5. 2018-08-05 18:56:53 +03:00
Taner Sener d0bc612062 Updated freetype to v2.9.1. 2018-08-05 18:56:53 +03:00
Taner Sener 701860d5ed Android x265 build errors fixed. 2018-08-05 18:50:42 +03:00
Taner Sener 172af56b15 asm enabled for ios i386 and x86_64 architectures 2018-08-05 16:50:55 +03:00
Taner Sener c4c5d60632 ios test-app subtitle resource path updated. 2018-08-05 13:15:19 +03:00
Taner Sener 9bea827e39 sed name collision fixed. 2018-08-05 13:14:07 +03:00
Taner Sener 71e7856102 android x265 build errors updated. 2018-08-05 12:59:53 +03:00
Taner Sener bc05d66b5b Defined platform dependent sed inline edit command. 2018-08-05 12:56:50 +03:00
Taner Sener a39d47f71a Android chromaprint build errors fixed. 2018-08-05 11:46:11 +03:00
Taner Sener 10b024082a Moving subtitle file to correct Android resource path. 2018-08-05 11:45:44 +03:00
Taner Sener d109a8d3d8 IOS test-app video positions updated. 2018-08-05 10:17:38 +03:00
Taner Sener 6c49e64b66 IOS build errors fixed. 2018-08-05 01:58:09 +03:00
Taner Sener b076562170 Using newer libaom snaphot. 2018-08-05 00:29:07 +03:00
Taner Sener 149adaed4a Using newer x264 snapshot version. 2018-08-05 00:29:07 +03:00
Taner Sener 4529ec7ba1 Removing frei0r from build scripts. 2018-08-04 15:07:15 +03:00
Taner Sener 25d576abdb Audio, subtitle and vid.stab tabs added to IOS test-app. 2018-08-04 14:37:49 +03:00
Taner Sener e2ff9c62a6 Updated video tab design for IOS test-app. 2018-08-03 23:42:47 +03:00
Taner Sener 5cdec4ed43 Less logs for android log internals. 2018-08-02 21:19:12 +03:00
Taner Sener c039a72e01 IOS test-app slideshow tab updated as video tab. 2018-08-02 21:06:37 +03:00
Taner Sener 4d544be832 IOS test-app command tab updated. 2018-08-02 19:10:31 +03:00
Taner Sener 66267ef7f0 Better os detection. 2018-08-02 18:15:54 +03:00
Taner Sener f1c0224aac null check added before calling JNIEnv->GetStringUTFChars. Fixed #9. 2018-08-02 18:01:20 +03:00
Taner Sener da6a51af70 IOS lipo path is extracted from xcrun. Fixes #12. 2018-08-02 17:53:15 +03:00
Taner Sener 4c1cd17ba2 Build fix for arm-v7a-neon architecture. 2018-08-02 17:46:09 +03:00
Taner Sener c1789def81 android/ios APIs revised; fixed #13. 2018-08-02 17:42:00 +03:00
Taner Sener c9449c894e New tabs added to ios test application. 2018-07-26 15:35:30 +03:00
Taner Sener 87d1a546ae chromaprint, x265 support 2018-07-21 19:59:03 +03:00
Taner Sener 4a221b2845 ffmpeg v4.0.2 2018-07-19 19:50:20 +03:00
Taner Sener 492626cc32 libaom v2018.07.18-snapshot 2018-07-19 17:06:44 +03:00
Taner Sener 5010b2c8d4 gnutls v3.5.19 2018-07-19 17:03:39 +03:00
Taner Sener 7c8743ba07 Creating slideshow.mp4 under documents folder for IOS test application. 2018-07-19 13:33:56 +03:00
Taner Sener c829f6660f android versions updated. 2018-07-13 20:03:30 +03:00
Taner Sener c612d2eb15 Fixed issue #8 for v2.x 2018-07-12 16:50:18 +03:00
Taner Sener 0933a77265 README updated 2018-07-12 16:45:38 +03:00
Taner Sener 4bc585fb50 bintray download badges added, features updated. 2018-07-12 15:48:51 +03:00
The Gitter Badger 9995378117 Add a Gitter chat badge to README.md (#7)
* Add Gitter badge

* Changed position of badge
2018-07-12 11:15:33 +03:00
Taner Sener 094c96a0fe Merge branch 'gitter-badger-gitter-badge' 2018-07-12 11:12:39 +03:00
The Gitter Badger d3ee5ab33f Add Gitter badge 2018-07-12 11:09:12 +03:00
Taner Sener 60b3483a70 v2.0 merged to master. 2018-07-01 18:47:54 +03:00
Taner Sener d96b96d12f README updated 2018-07-01 18:25:22 +03:00
Taner Sener 60ecdc66c8 ios-release branch merged. 2018-06-26 23:50:26 +03:00
Taner Sener 9812d6d294 android-release branch merged. 2018-06-23 11:20:39 +03:00
Taner Sener 1b6e71d157 dev-v1.x branch merged. 2018-06-18 11:01:16 +03:00
19025 changed files with 3000508 additions and 904050 deletions
+3
View File
@@ -0,0 +1,3 @@
open_collective: mobile-ffmpeg
patreon: tanersener
custom: ['https://buymeacoff.ee/tanersener','https://paypal.me/teodosiyminchev']
+33
View File
@@ -0,0 +1,33 @@
---
name: Issue Template
about: Create an issue to help us improve
---
**Description**
Description of what the issue is about.
**Expected behavior**
What you expected to happen.
**Current behavior**
What happened.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Logs**
Post logs here or paste them to [Ghostbin](https://ghostbin.co) and insert the link here.
**Environment**
- Platform: [e.g. Android/IOS]
- Architecture: [arm-v7a, arm-v7a-neon, arm64-v8a, x86, x86_64, armv7, armv7s, arm64, i386, x86_64]
- Version (if applicable) [e.g. v1.2]
- Source branch (if applicable) [e.g. master, dev-v2.x]
- Xcode version (if applicable) [e.g. 7.3.1, 9.0.1]
- Cocoapods version (if applicable) [e.g. 1.2.1]
- Android Studio version (if applicable) [e.g. 3.1]
- Android NDK version (if applicable) [e.g. 16b, 17c]
**Other**
Add any other context about the problem here.
+136
View File
@@ -0,0 +1,136 @@
branches:
only:
- master
- development
sudo: false
git:
quiet: true
addons:
apt:
packages:
- autoconf
- automake
- libtool
- pkg-config
- curl
- git
- cmake
- gcc
- gperf
- texinfo
- yasm
- nasm
- bison
- autogen
- patch
homebrew:
packages:
- nasm
update: true
matrix:
include:
- name: "Android Main Build"
language: android
dist : trusty
android:
components:
- tools
- platform-tools
- build-tools-28.0.3
- android-24
- extra-google-google_play_services
- extra-google-m2repository
- extra-android-m2repository
install:
- echo y | sdkmanager "ndk-bundle"
- echo y | sdkmanager "cmake;3.10.2.4988404"
- echo y | sdkmanager "lldb;3.1"
before_install:
- touch $HOME/.android/repositories.cfg
before_script:
- export ANDROID_NDK_ROOT=$ANDROID_HOME/ndk-bundle
- rm -f ./build.log
after_success:
- grep -e INFO ./build.log | grep build
after_failure:
- tail -30 ./build.log
- tail -30 ./src/ffmpeg/ffbuild/config.log
script:
- bash ./android.sh --no-output-redirection
- name: "Android LTS Build"
language: android
dist : trusty
android:
components:
- tools
- platform-tools
- build-tools-28.0.3
- android-16
- android-21
- extra-google-google_play_services
- extra-google-m2repository
- extra-android-m2repository
install:
- echo y | sdkmanager "ndk-bundle"
- echo y | sdkmanager "cmake;3.10.2.4988404"
- echo y | sdkmanager "lldb;3.1"
before_install:
- touch $HOME/.android/repositories.cfg
before_script:
- export ANDROID_NDK_ROOT=$ANDROID_HOME/ndk-bundle
- rm -f ./build.log
after_success:
- grep -e INFO ./build.log | grep build
after_failure:
- tail -30 ./build.log
- tail -30 ./src/ffmpeg/ffbuild/config.log
script:
- bash ./android.sh --lts --no-output-redirection
- name: "iOS Main Build"
language: objective-c
osx_image: xcode10.2
before_script:
- rm -f ./build.log
after_success:
- grep -e INFO ./build.log | grep build
after_failure:
- tail -30 ./build.log
- tail -30 ./src/ffmpeg/ffbuild/config.log
script:
- bash ./ios.sh --no-output-redirection
- name: "iOS LTS Build"
language: objective-c
osx_image: xcode7.3
before_script:
- rm -f ./build.log
after_success:
- grep -e INFO ./build.log | grep build
after_failure:
- tail -30 ./build.log
- tail -30 ./src/ffmpeg/ffbuild/config.log
script:
- bash ./ios.sh --lts --no-output-redirection
- name: "tvOS Main Build"
language: objective-c
osx_image: xcode10.2
before_script:
- rm -f ./build.log
after_success:
- grep -e INFO ./build.log | grep build
after_failure:
- tail -30 ./build.log
- tail -30 ./src/ffmpeg/ffbuild/config.log
script:
- bash ./tvos.sh --no-output-redirection
- name: "tvOS LTS Build"
language: objective-c
osx_image: xcode7.3
before_script:
- rm -f ./build.log
after_success:
- grep -e INFO ./build.log | grep build
after_failure:
- tail -30 ./build.log
- tail -30 ./src/ffmpeg/ffbuild/config.log
script:
- bash ./tvos.sh --lts --no-output-redirection
+490 -95
View File
@@ -1,165 +1,560 @@
# MobileFFmpeg
Source code and scripts to build FFmpeg for Android and IOS platforms
# MobileFFmpeg [![Financial Contributors on Open Collective](https://opencollective.com/mobile-ffmpeg/all/badge.svg?label=financial+contributors)](https://opencollective.com/mobile-ffmpeg) ![GitHub release](https://img.shields.io/badge/release-v4.3.1-blue.svg) ![Bintray](https://img.shields.io/badge/bintray-v4.3.1-blue.svg) ![CocoaPods](https://img.shields.io/badge/pod-v4.3.1-blue.svg) [![Build Status](https://travis-ci.org/tanersener/mobile-ffmpeg.svg?branch=master)](https://travis-ci.org/tanersener/mobile-ffmpeg)
FFmpeg for Android, iOS and tvOS
<img src="https://github.com/tanersener/mobile-ffmpeg/blob/master/docs/assets/mobile-ffmpeg-logo-v7.png" width="320">
### 1. Features
- Builds both Android and IOS
- Supports
- FFmpeg `v3.4.x` and `v4.0.x` releases
- 21 external libraries.
- Includes both `FFmpeg` and `FFprobe`
- Use binaries available at `Github`/`JCenter`/`CocoaPods` or build your own version with external libraries you need
- Supports
- Android, iOS and tvOS
- FFmpeg `v3.4.x`, `v4.0.x`, `v4.1`, `v4.2` and `v4.3-dev` releases
- 28 external libraries
`fontconfig`, `freetype`, `fribidi`, `gmp`, `gnutls`, `kvazaar`, `lame`, `libass`, `libiconv`, `libilbc`, `libtheora`, `libvorbis`, `libvpx`, `libwebp`, `libxml2`, `opencore-amr`, `opus`, `shine`, `snappy`, `speex`, `wavpack`
`chromaprint`, `fontconfig`, `freetype`, `fribidi`, `gmp`, `gnutls`, `kvazaar`, `lame`, `libaom`, `libass`, `libiconv`, `libilbc`, `libtheora`, `libvorbis`, `libvpx`, `libwebp`, `libxml2`, `opencore-amr`, `openh264`, `opus`, `sdl`, `shine`, `snappy`, `soxr`, `speex`, `tesseract`, `twolame`, `wavpack`
- 2 external libraries with GPL license
- 4 external libraries with GPL license
`x264`, `xvidcore`
`vid.stab`, `x264`, `x265`, `xvidcore`
- Exposes FFmpeg capabilities both directly from FFmpeg libraries and through MobileFFmpeg wrapper library
- Creates shared libraries (.so for Android, .dylib for IOS)
- Includes cross-compile instructions for 32 open-source libraries
- Concurrent execution
- Exposes both FFmpeg library and MobileFFmpeg wrapper library capabilities
- Includes cross-compile instructions for 44 open-source libraries
`expat`, `ffmpeg`, `fontconfig`, `freetype`, `fribidi`, `giflib`, `gmp`, `gnutls`, `kvazaar`, `lame`, `libass`, `libiconv`, `libilbc`, `libjpeg`, `libogg`, `libpng`, `libtheora`, `libuuid`, `libvorbis`, `libvpx`, `libwebp`, `libxml2`, `nettle`, `opencore-amr`, `opus`, `shine`, `snappy`, `speex`, `tiff`, `wavpack`, `x264`, `xvidcore`
- Prebuilt binaries under `JCenter` and `CocoaPods`
`chromaprint`, `expat`, `ffmpeg`, `fontconfig`, `freetype`, `fribidi`, `giflib`, `gmp`, `gnutls`, `kvazaar`, `lame`, `leptonica`, `libaom`, `libass`, `libiconv`, `libilbc`, `libjpeg`, `libjpeg-turbo`, `libogg`, `libpng`, `libsndfile`, `libtheora`, `libuuid`, `libvorbis`, `libvpx`, `libwebp`, `libxml2`, `nettle`, `opencore-amr`, `openh264`, `opus`, `sdl`, `shine`, `snappy`, `soxr`, `speex`, `tesseract`, `tiff`, `twolame`, `vid.stab`, `wavpack`, `x264`, `x265`, `xvidcore`
- Licensed under LGPL 3.0, can be customized to support GPL v3.0
#### 1.1 Android
- Supports `arm-v7a`, `arm-v7a-neon`, `arm64-v8a`, `x86` and `x86_64` architectures
- Builds `arm-v7a`, `arm-v7a-neon`, `arm64-v8a`, `x86` and `x86_64` architectures
- Supports `zlib` and `MediaCodec` system libraries
- Camera access on [supported devices](https://developer.android.com/ndk/guides/stable_apis#camera)
- Builds shared native libraries (.so)
- Creates Android archive with .aar extension
#### 1.2 IOS
- Supports `armv7`, `armv7s`, `arm64`, `i386` and `x86_64` architectures
- Builds with `-fembed-bitcode` flag
- Creates IOS dynamic universal (fat) library
- Creates IOS dynamic framework for IOS 8 or later
- Supports `API Level 16+`
#### 1.2 iOS
- Builds `armv7`, `armv7s`, `arm64`, `arm64e`, `i386` and `x86_64` architectures
- Supports `bzip2`, `zlib`, `iconv` system libraries and `AudioToolbox`, `CoreImage`, `VideoToolbox`, `AVFoundation` system frameworks
- Objective-C API
- Camera access
- `ARC` enabled library
- Built with `-fembed-bitcode` flag
- Creates static framework and static universal (fat) library (.a)
- Supports `iOS SDK 9.3` or later
#### 1.3 tvOS
- Builds `arm64` and `x86_64` architectures
- Supports `bzip2`, `zlib`, `iconv` system libraries and `AudioToolbox`, `CoreImage`, `VideoToolbox` system frameworks
- Objective-C API
- `ARC` enabled library
- Built with `-fembed-bitcode` flag
- Creates static framework and static universal (fat) library (.a)
- Supports `tvOS SDK 9.2` or later
### 2. Using
Prebuilt libraries are available under [Github](https://github.com/tanersener/mobile-ffmpeg/releases), [JCenter](https://bintray.com/bintray/jcenter) and [CocoaPods](https://cocoapods.org)
Published binaries are available at [Github](https://github.com/tanersener/mobile-ffmpeg/releases), [JCenter](https://bintray.com/bintray/jcenter) and [CocoaPods](https://cocoapods.org).
There are six different prebuilt packages. Below you can see which external libraries are enabled in each of them.
There are eight different `mobile-ffmpeg` packages. Below you can see which system libraries and external libraries are enabled in each of them.
| | min | min-gpl | https | https-gpl | full | full-gpl |
| :----: | :----: | :----: | :----: | :----: | :----: | :----: |
| external <br/> libraries <br/> enabled | - | x264 <br/> xvidcore | gnutls | gnutls <br/> x264 <br/> xvidcore | fontconfig <br/> freetype <br/> fribidi <br/> gmp <br/> gnutls <br/> kvazaar <br/> lame <br/> libass <br/> libiconv <br/> libilbc <br/> libtheora <br/> libvorbis <br/> libvpx <br/> libwebp <br/> libxml2 <br/> opencore-amr <br/> opus <br/> shine <br/> snappy <br/> speex <br/> wavpack | fontconfig <br/> freetype <br/> fribidi <br/> gmp <br/> gnutls <br/> kvazaar <br/> lame <br/> libass <br/> libiconv <br/> libilbc <br/> libtheora <br/> libvorbis <br/> libvpx <br/> libwebp <br/> libxml2 <br/> opencore-amr <br/> opus <br/> shine <br/> snappy <br/> speex <br/> wavpack <br/> x264 <br/> xvidcore |
Please remember that some parts of `FFmpeg` are licensed under the `GPL` and only `GPL` licensed `mobile-ffmpeg` packages include them.
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center">min</th>
<th align="center">min-gpl</th>
<th align="center">https</th>
<th align="center">https-gpl</th>
<th align="center">audio</th>
<th align="center">video</th>
<th align="center">full</th>
<th align="center">full-gpl</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center"><sup>external libraries</sup></td>
<td align="center">-</td>
<td align="center"><sup>vid.stab</sup><br><sup>x264</sup><br><sup>x265</sup><br><sup>xvidcore</sup></td>
<td align="center"><sup>gmp</sup><br><sup>gnutls</sup></td>
<td align="center"><sup>gmp</sup><br><sup>gnutls</sup><br><sup>vid.stab</sup><br><sup>x264</sup><br><sup>x265</sup><br><sup>xvidcore</sup></td>
<td align="center"><sup>lame</sup><br><sup>libilbc</sup><br><sup>libvorbis</sup><br><sup>opencore-amr</sup><br><sup>opus</sup><br><sup>shine</sup><br><sup>soxr</sup><br><sup>speex</sup><br><sup>twolame</sup><br><sup>wavpack</sup></td>
<td align="center"><sup>fontconfig</sup><br><sup>freetype</sup><br><sup>fribidi</sup><br><sup>kvazaar</sup><br><sup>libaom</sup><br><sup>libass</sup><br><sup>libiconv</sup><br><sup>libtheora</sup><br><sup>libvpx</sup><br><sup>libwebp</sup><br><sup>snappy</sup></td>
<td align="center"><sup>fontconfig</sup><br><sup>freetype</sup><br><sup>fribidi</sup><br><sup>gmp</sup><br><sup>gnutls</sup><br><sup>kvazaar</sup><br><sup>lame</sup><br><sup>libaom</sup><br><sup>libass</sup><br><sup>libiconv</sup><br><sup>libilbc</sup><br><sup>libtheora</sup><br><sup>libvorbis</sup><br><sup>libvpx</sup><br><sup>libwebp</sup><br><sup>libxml2</sup><br><sup>opencore-amr</sup><br><sup>opus</sup><br><sup>shine</sup><br><sup>snappy</sup><br><sup>soxr</sup><br><sup>speex</sup><br><sup>twolame</sup><br><sup>wavpack</sup></td>
<td align="center"><sup>fontconfig</sup><br><sup>freetype</sup><br><sup>fribidi</sup><br><sup>gmp</sup><br><sup>gnutls</sup><br><sup>kvazaar</sup><br><sup>lame</sup><br><sup>libaom</sup><br><sup>libass</sup><br><sup>libiconv</sup><br><sup>libilbc</sup><br><sup>libtheora</sup><br><sup>libvorbis</sup><br><sup>libvpx</sup><br><sup>libwebp</sup><br><sup>libxml2</sup><br><sup>opencore-amr</sup><br><sup>opus</sup><br><sup>shine</sup><br><sup>snappy</sup><br><sup>soxr</sup><br><sup>speex</sup><br><sup>twolame</sup><br><sup>vid.stab</sup><br><sup>wavpack</sup><br><sup>x264</sup><br><sup>x265</sup><br><sup>xvidcore</sup></td>
</tr>
<tr>
<td align="center"><sup>android system libraries</sup></td>
<td align="center" colspan=8><sup>zlib</sup><br><sup>MediaCodec</sup></td>
</tr>
<tr>
<td align="center"><sup>ios system libraries</sup></td>
<td align="center" colspan=8><sup>zlib</sup><br><sup>AudioToolbox</sup><br><sup>AVFoundation</sup><br><sup>CoreImage</sup><br><sup>iconv</sup><br><sup>VideoToolbox</sup><br><sup>bzip2</sup></td>
</tr>
<tr>
<td align="center"><sup>tvos system libraries</sup></td>
<td align="center" colspan=8><sup>zlib</sup><br><sup>AudioToolbox</sup><br><sup>CoreImage</sup><br><sup>iconv</sup><br><sup>VideoToolbox</sup><br><sup>bzip2</sup></td>
</tr>
</tbody>
</table>
- `libilbc`, `opus`, `snappy`, `x264` and `xvidcore` are supported since `v1.1`
- `libaom` and `soxr` are supported since `v2.0`
- `chromaprint`, `vid.stab` and `x265` are supported since `v2.1`
- `sdl`, `tesseract`, `twolame` external libraries; `zlib`, `MediaCodec` Android system libraries; `bzip2`, `zlib` iOS system libraries and `AudioToolbox`, `CoreImage`, `VideoToolbox`, `AVFoundation` iOS system frameworks are supported since `v3.0`
- Since `v4.2`, `chromaprint`, `sdl` and `tesseract` libraries are not included in binary releases. You can still build them and include in your releases
- `AVFoundation` is not available on `tvOS`, `VideoToolbox` is not available on `tvOS` LTS releases
- Since `v4.3.1`, `iOS` and `tvOS` releases started to use `iconv` system library instead of `iconv` external library
#### 2.1 Android
1. Add MobileFFmpeg dependency from `jcenter()`
1. Add MobileFFmpeg dependency to your `build.gradle` in `mobile-ffmpeg-<package name>` format
```
dependencies {`
implementation 'com.arthenica:mobile-ffmpeg-full-gpl:1.1'
dependencies {
implementation 'com.arthenica:mobile-ffmpeg-full:4.3.1'
}
```
2. Use the following source code to execute commands.
2. Execute FFmpeg commands.
```
import com.arthenica.mobileffmpeg.Config;
import com.arthenica.mobileffmpeg.FFmpeg;
int rc = FFmpeg.execute("-i", "file1.mp4", "-c:v", "libxvid", "file1.avi");
Log.i(Log.TAG, String.format("Command execution %s.", (rc == 0?"completed successfully":"failed with rc=" + rc));
```
#### 2.2 IOS
1. Add MobileFFmpeg pod to your `Podfile`
```
pod 'mobile-ffmpeg-full-gpl', '~> 1.1'
```
2. Create and execute commands using the following `Objective-C` example.
```
#import <mobileffmpeg/mobileffmpeg.h>
NSString* command = @"-i file1.mp4 -c:v libxvid file1.avi";
NSArray* commandArray = [command componentsSeparatedByString:@" "];
char **arguments = (char **)malloc(sizeof(char*) * ([commandArray count]));
for (int i=0; i < [commandArray count]; i++) {
NSString *argument = [commandArray objectAtIndex:i];
arguments[i] = (char *) [argument UTF8String];
int rc = FFmpeg.execute("-i file1.mp4 -c:v mpeg4 file2.mp4");
if (rc == RETURN_CODE_SUCCESS) {
Log.i(Config.TAG, "Command execution completed successfully.");
} else if (rc == RETURN_CODE_CANCEL) {
Log.i(Config.TAG, "Command execution cancelled by user.");
} else {
Log.i(Config.TAG, String.format("Command execution failed with rc=%d and the output below.", rc));
Config.printLastCommandOutput(Log.INFO);
}
int result = mobileffmpeg_execute((int) [commandArray count], arguments);
NSLog(@"Process exited with rc %d\n", result);
free(arguments);
```
#### 2.3 Test Application
3. Execute FFprobe commands.
```
import com.arthenica.mobileffmpeg.Config;
import com.arthenica.mobileffmpeg.FFprobe;
int rc = FFprobe.execute("-i file1.mp4");
if (rc == RETURN_CODE_SUCCESS) {
Log.i(Config.TAG, "Command execution completed successfully.");
} else {
Log.i(Config.TAG, String.format("Command execution failed with rc=%d and the output below.", rc));
Config.printLastCommandOutput(Log.INFO);
}
```
4. Check execution output later.
```
int rc = Config.getLastReturnCode();
if (rc == RETURN_CODE_SUCCESS) {
Log.i(Config.TAG, "Command execution completed successfully.");
} else if (rc == RETURN_CODE_CANCEL) {
Log.i(Config.TAG, "Command execution cancelled by user.");
} else {
Log.i(Config.TAG, String.format("Command execution failed with rc=%d and the output below.", rc));
Config.printLastCommandOutput(Log.INFO);
}
```
5. Stop an ongoing FFmpeg operation.
```
FFmpeg.cancel();
```
6. Get media information for a file.
```
MediaInformation info = FFprobe.getMediaInformation("<file path or uri>");
```
7. Record video using Android camera.
```
FFmpeg.execute("-f android_camera -i 0:0 -r 30 -pixel_format bgr0 -t 00:00:05 <record file path>");
```
8. List enabled external libraries.
```
List<String> externalLibraries = Config.getExternalLibraries();
```
9. Enable log callback.
```
Config.enableLogCallback(new LogCallback() {
public void apply(LogMessage message) {
Log.d(Config.TAG, message.getText());
}
});
```
10. Enable statistics callback.
```
Config.enableStatisticsCallback(new StatisticsCallback() {
public void apply(Statistics newStatistics) {
Log.d(Config.TAG, String.format("frame: %d, time: %d", newStatistics.getVideoFrameNumber(), newStatistics.getTime()));
}
});
```
11. Set log level.
```
Config.setLogLevel(Level.AV_LOG_FATAL);
```
12. Register custom fonts directory.
```
Config.setFontDirectory(this, "<folder with fonts>", Collections.EMPTY_MAP);
```
#### 2.2 iOS / tvOS
1. Add MobileFFmpeg dependency to your `Podfile` in `mobile-ffmpeg-<package name>` format
- iOS
```
pod 'mobile-ffmpeg-full', '~> 4.3.1'
```
- tvOS
```
pod 'mobile-ffmpeg-tvos-full', '~> 4.3.1'
```
2. Execute FFmpeg commands.
```
#import <mobileffmpeg/MobileFFmpegConfig.h>
#import <mobileffmpeg/MobileFFmpeg.h>
int rc = [MobileFFmpeg execute: @"-i file1.mp4 -c:v mpeg4 file2.mp4"];
if (rc == RETURN_CODE_SUCCESS) {
NSLog(@"Command execution completed successfully.\n");
} else if (rc == RETURN_CODE_CANCEL) {
NSLog(@"Command execution cancelled by user.\n");
} else {
NSLog(@"Command execution failed with rc=%d and output=%@.\n", rc, [MobileFFmpegConfig getLastCommandOutput]);
}
```
3. Execute FFprobe commands.
```
#import <mobileffmpeg/MobileFFmpegConfig.h>
#import <mobileffmpeg/MobileFFprobe.h>
int rc = [MobileFFprobe execute: @"-i file1.mp4"];
if (rc == RETURN_CODE_SUCCESS) {
NSLog(@"Command execution completed successfully.\n");
} else if (rc == RETURN_CODE_CANCEL) {
NSLog(@"Command execution cancelled by user.\n");
} else {
NSLog(@"Command execution failed with rc=%d and output=%@.\n", rc, [MobileFFmpegConfig getLastCommandOutput]);
}
```
4. Check execution output later.
```
int rc = [MobileFFmpegConfig getLastReturnCode];
NSString *output = [MobileFFmpegConfig getLastCommandOutput];
if (rc == RETURN_CODE_SUCCESS) {
NSLog(@"Command execution completed successfully.\n");
} else if (rc == RETURN_CODE_CANCEL) {
NSLog(@"Command execution cancelled by user.\n");
} else {
NSLog(@"Command execution failed with rc=%d and output=%@.\n", rc, output);
}
```
5. Stop an ongoing FFmpeg operation.
```
[MobileFFmpeg cancel];
```
6. Get media information for a file.
```
MediaInformation *mediaInformation = [MobileFFprobe getMediaInformation:@"<file path or uri>"];
```
7. Record video and audio using iOS camera. This operation is not supported on `tvOS` since `AVFoundation` is not available on `tvOS`.
```
[MobileFFmpeg execute: @"-f avfoundation -r 30 -video_size 1280x720 -pixel_format bgr0 -i 0:0 -vcodec h264_videotoolbox -vsync 2 -f h264 -t 00:00:05 %@", recordFilePath];
```
8. List enabled external libraries.
```
NSArray *externalLibraries = [MobileFFmpegConfig getExternalLibraries];
```
9. Enable log callback.
```
[MobileFFmpegConfig setLogDelegate:self];
- (void)logCallback: (int)level :(NSString*)message {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@", message);
});
}
```
10. Enable statistics callback.
```
[MobileFFmpegConfig setStatisticsDelegate:self];
- (void)statisticsCallback:(Statistics *)newStatistics {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"frame: %d, time: %d\n", newStatistics.getVideoFrameNumber, newStatistics.getTime);
});
}
```
11. Set log level.
```
[MobileFFmpegConfig setLogLevel:AV_LOG_FATAL];
```
12. Register custom fonts directory.
```
[MobileFFmpegConfig setFontDirectory:@"<folder with fonts>" with:nil];
```
#### 2.3 Manual Installation
##### 2.3.1 Android
You can import `MobileFFmpeg` aar packages in `Android Studio` using the `File` -> `New` -> `New Module` -> `Import .JAR/.AAR Package` menu.
##### 2.3.2 iOS / tvOS
iOS and tvOS frameworks can be installed manually using the [Importing Frameworks](https://github.com/tanersener/mobile-ffmpeg/wiki/Importing-Frameworks) guide.
If you want to use universal binaries please refer to [Using Universal Binaries](https://github.com/tanersener/mobile-ffmpeg/wiki/Using-Universal-Binaries) guide.
#### 2.4 Test Application
You can see how MobileFFmpeg is used inside an application by running test applications provided.
There is an Android test application under the `android/test-app` folder and an IOS test application under the
`ios/test-app` folder. Both applications are identical and supports command execution and video encoding.
There is an `Android` test application under the `android/test-app` folder, an `iOS` test application under the
`ios/test-app` folder and a `tvOS` test application under the `tvos/test-app` folder.
All applications are identical and supports command execution, video encoding, accessing https, encoding audio,
burning subtitles, video stabilization and pipe operations.
<img src="https://github.com/tanersener/mobile-ffmpeg/blob/master/docs/assets/android_test_app.gif" width="240">
### 3. Versions
- `MobileFFmpeg v1.x` is the current stable, includes `FFmpeg v3.4.2`
`MobileFFmpeg` version number is aligned with `FFmpeg` since version `4.2`.
- `MobileFFmpeg v2.x` is the next stable, includes `FFmpeg v4.0.1`
In previous versions, `MobileFFmpeg` version of a release and `FFmpeg` version included in that release was different.
The following table lists `FFmpeg` versions used in `MobileFFmpeg` releases.
- `dev` part in `FFmpeg` version number indicates that `FFmpeg` source is pulled from the `FFmpeg` `master` branch.
Exact version number is obtained using `git describe --tags`.
### 4. Building
#### 4.1 Prerequisites
| MobileFFmpeg Version | FFmpeg Version | Release Date |
| :----: | :----: |:----: |
| [4.3.1](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v4.3.1) | 4.3-dev-1944 | Jan 25, 2020 |
| [4.3.1.LTS](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v4.3.1.LTS) | 4.3-dev-1944 | Jan 25, 2020 |
| [4.3](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v4.3) | 4.3-dev-1181 | Oct 27, 2019 |
| [4.2.2](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v4.2.2) | 4.2-dev-1824 | July 3, 2019 |
| [4.2.2.LTS](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v4.2.2.LTS) | 4.2-dev-1824 | July 3, 2019 |
| [4.2.1](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v4.2.1) | 4.2-dev-1156 | Apr 2, 2019 |
| [4.2](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v4.2) | 4.2-dev-480 | Jan 3, 2019 |
| [4.2.LTS](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v4.2.LTS) | 4.2-dev-480 | Jan 3, 2019 |
| [3.1](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v3.1) | 4.1-10 | Dec 11, 2018 |
| [3.0](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v3.0) | 4.1-dev-1517 | Oct 25, 2018 |
| [2.2](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v2.2) | 4.0.3 | Nov 10, 2018 |
| [2.1.1](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v2.1.1) | 4.0.2 | Sep 19, 2018 |
| [2.1](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v2.1) | 4.0.2 | Sep 5, 2018 |
| [2.0](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v2.0) | 4.0.1 | Jun 30, 2018 |
| [1.2](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v1.2) | 3.4.4 | Aug 30, 2018|
| [1.1](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v1.1) | 3.4.2 | Jun 18, 2018 |
| [1.0](https://github.com/tanersener/mobile-ffmpeg/releases/tag/v1.0) | 3.4.2 | Jun 6, 2018 |
### 4. LTS Releases
Starting from `v4.2`, `MobileFFmpeg` binaries are published in two different variants: `Main Release` and `LTS Release`.
- Main releases include complete functionality of the library and support the latest SDK/API features.
- LTS releases are customized to support a wider range of devices. They are built using older API/SDK versions, so some features are not available on them.
This table shows the differences between two variants.
| | Main Release | LTS Release |
| :----: | :----: | :----: |
| Android API Level | 24 | 16 |
| Android Camera Access | Yes | - |
| Android Architectures | arm-v7a-neon<br/>arm64-v8a<br/>x86<br/>x86-64 | arm-v7a<br/>arm-v7a-neon<br/>arm64-v8a<br/>x86<br/>x86-64 |
| Xcode Support | 10.1 | 7.3.1 |
| iOS SDK | 12.1 | 9.3 |
| iOS Architectures | arm64<br/>arm64e<br/>x86-64 | armv7<br/>arm64<br/>i386<br/>x86-64 |
| tvOS SDK | 10.2 | 9.2 |
| tvOS Architectures | arm64<br/>x86-64 | arm64<br/>x86-64 |
### 5. Building
Build scripts from `master` and `development` branches are tested periodically. See the latest status from the table below.
| branch | status |
| :---: | :---: |
| master | [![Build Status](https://travis-ci.org/tanersener/mobile-ffmpeg.svg?branch=master)](https://travis-ci.org/tanersener/mobile-ffmpeg) |
| development | [![Build Status](https://travis-ci.org/tanersener/mobile-ffmpeg.svg?branch=development)](https://travis-ci.org/tanersener/mobile-ffmpeg) |
#### 5.1 Prerequisites
1. Use your package manager (apt, yum, dnf, brew, etc.) to install the following packages.
```
autoconf automake libtool pkg-config curl cmake gcc gperf texinfo yasm nasm
autoconf automake libtool pkg-config curl cmake gcc gperf texinfo yasm nasm bison autogen patch git
```
Some of these packages are not mandatory for the default build.
Please visit [Android Prerequisites](https://github.com/tanersener/mobile-ffmpeg/wiki/Android-Prerequisites) and
[IOS Prerequisites](https://github.com/tanersener/mobile-ffmpeg/wiki/IOS-Prerequisites) for the details.
Please visit [Android Prerequisites](https://github.com/tanersener/mobile-ffmpeg/wiki/Android-Prerequisites),
[iOS Prerequisites](https://github.com/tanersener/mobile-ffmpeg/wiki/iOS-Prerequisites) and
[tvOS Prerequisites](https://github.com/tanersener/mobile-ffmpeg/wiki/tvOS-Prerequisites) for the details.
2. Android builds require these additional packages.
- **Android SDK 5.0 Lollipop (API Level 21)** or later
- **Android NDK r16b** or later with LLDB and CMake
- **gradle 4.4** or later
- **Android SDK 4.1 Jelly Bean (API Level 16)** or later
- **Android NDK r20** or later with LLDB and CMake
3. IOS builds need these extra packages and tools.
- **IOS SDK 7.0.x** or later
- **Xcode 8.x** or later
3. iOS builds need these extra packages and tools.
- **Xcode 7.3.1** or later
- **iOS SDK 9.3** or later
- **Command Line Tools**
- **lipo** utility
#### 4.2 Build Scripts
Use `android.sh` and `ios.sh` to build MobileFFmpeg for each platform.
After a successful build, compiled FFmpeg and MobileFFmpeg libraries can be found under `prebuilt` directory.
4. tvOS builds need these extra packages and tools.
- **Xcode 7.3.1** or later
- **tvOS SDK 9.2** or later
- **Command Line Tools**
Both `android.sh` and `ios.sh` can be customized to override default settings,
[android.sh](https://github.com/tanersener/mobile-ffmpeg/wiki/android.sh) and
[ios.sh](https://github.com/tanersener/mobile-ffmpeg/wiki/ios.sh) wiki pages include all available build options.
##### 4.2.1 Android
#### 5.2 Build Scripts
Use `android.sh`, `ios.sh` and `tvos.sh` to build MobileFFmpeg for each platform.
All three scripts support additional options and
can be customized to enable/disable specific external libraries and/or architectures. Please refer to wiki pages of
[android.sh](https://github.com/tanersener/mobile-ffmpeg/wiki/android.sh),
[ios.sh](https://github.com/tanersener/mobile-ffmpeg/wiki/ios.sh) and
[tvos.sh](https://github.com/tanersener/mobile-ffmpeg/wiki/tvos.sh) to see all available build options.
##### 5.2.1 Android
```
export ANDROID_HOME=<Android SDK Path>
export ANDROID_NDK_ROOT=<Android NDK Path>
./android.sh
```
##### 4.2.2 IOS
<img src="https://github.com/tanersener/mobile-ffmpeg/blob/master/docs/assets/android_custom.gif" width="600">
##### 5.2.2 iOS
```
./ios.sh
./ios.sh
```
#### 4.3 GPL Support
Since`v1.1`, it is possible to enable to GPL licensed libraries `x264` and `xvidcore` from the top level build scripts.
Their source code is not included in the repository and downloaded when enabled.
<img src="https://github.com/tanersener/mobile-ffmpeg/blob/master/docs/assets/ios_custom.gif" width="600">
#### 4.4 External Libraries
`build` directory includes build scripts for external libraries. There are two scripts for each library, one for Android
and one for IOS. They include all options/flags used to cross-compile the libraries. `ASM` is enabled by most of them,
exceptions are listed under the [ASM Support](https://github.com/tanersener/mobile-ffmpeg/wiki/ASM-Support) page.
##### 5.2.3 tvOS
```
./tvos.sh
```
### 5. Documentation
<img src="https://github.com/tanersener/mobile-ffmpeg/blob/master/docs/assets/tvos_custom.gif" width="600">
##### 5.2.4 Building LTS Binaries
Use `--lts` option to build lts binaries for each platform.
#### 5.3 Build Output
All libraries created by the top level build scripts (`android.sh`, `ios.sh` and `tvos.sh`) can be found under
the `prebuilt` directory.
- `Android` archive (.aar file) is located under the `android-aar` folder
- `iOS` frameworks are located under the `ios-framework`folder
- `iOS` universal binaries are located under the `ios-universal`folder
- `tvOS` frameworks are located under the `tvos-framework`folder
- `tvOS` universal binaries are located under the `tvos-universal`folder
#### 5.4 GPL Support
It is possible to enable GPL licensed libraries `x264`, `xvidcore` since `v1.1` and `vid.stab`, `x265` since `v2.1`
from the top level build scripts. Their source code is not included in the repository and downloaded when enabled.
#### 5.5 External Libraries
`build` directory includes build scripts of all external libraries. Two scripts exist for each external library,
one for `Android` and one for `iOS / tvOS`. Each of these two scripts contains options/flags used to cross-compile the
library on the specified mobile platform.
CPU optimizations (`ASM`) are enabled for most of the external libraries. Details and exceptions can be found under the
[ASM Support](https://github.com/tanersener/mobile-ffmpeg/wiki/ASM-Support) wiki page.
### 6. Documentation
A more detailed documentation is available at [Wiki](https://github.com/tanersener/mobile-ffmpeg/wiki).
### 6. License
### 7. Contributors
#### 7.1 Code Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/tanersener/mobile-ffmpeg/graphs/contributors"><img src="https://opencollective.com/mobile-ffmpeg/contributors.svg?width=890&button=false" /></a>
#### 7.2 Financial Contributors
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/mobile-ffmpeg/contribute)]
##### 7.2.1 Individuals
<a href="https://opencollective.com/mobile-ffmpeg"><img src="https://opencollective.com/mobile-ffmpeg/individuals.svg?width=890"></a>
##### 7.2.2 Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/mobile-ffmpeg/contribute)]
<a href="https://opencollective.com/mobile-ffmpeg/organization/0/website"><img src="https://opencollective.com/mobile-ffmpeg/organization/0/avatar.svg"></a>
<a href="https://opencollective.com/mobile-ffmpeg/organization/1/website"><img src="https://opencollective.com/mobile-ffmpeg/organization/1/avatar.svg"></a>
<a href="https://opencollective.com/mobile-ffmpeg/organization/2/website"><img src="https://opencollective.com/mobile-ffmpeg/organization/2/avatar.svg"></a>
<a href="https://opencollective.com/mobile-ffmpeg/organization/3/website"><img src="https://opencollective.com/mobile-ffmpeg/organization/3/avatar.svg"></a>
<a href="https://opencollective.com/mobile-ffmpeg/organization/4/website"><img src="https://opencollective.com/mobile-ffmpeg/organization/4/avatar.svg"></a>
<a href="https://opencollective.com/mobile-ffmpeg/organization/5/website"><img src="https://opencollective.com/mobile-ffmpeg/organization/5/avatar.svg"></a>
<a href="https://opencollective.com/mobile-ffmpeg/organization/6/website"><img src="https://opencollective.com/mobile-ffmpeg/organization/6/avatar.svg"></a>
<a href="https://opencollective.com/mobile-ffmpeg/organization/7/website"><img src="https://opencollective.com/mobile-ffmpeg/organization/7/avatar.svg"></a>
<a href="https://opencollective.com/mobile-ffmpeg/organization/8/website"><img src="https://opencollective.com/mobile-ffmpeg/organization/8/avatar.svg"></a>
<a href="https://opencollective.com/mobile-ffmpeg/organization/9/website"><img src="https://opencollective.com/mobile-ffmpeg/organization/9/avatar.svg"></a>
### 8. License
This project is licensed under the LGPL v3.0. However, if source code is built using optional `--enable-gpl` flag or
prebuilt binaries with `-gpl` postfix are used then MobileFFmpeg is subject to the GPL v3.0 license.
Source code of FFmpeg and external libraries is included in compliance with their individual licenses.
`strip-frameworks.sh` script included and distributed is published under the Apache License version 2.0.
`openh264` source code included in this repository is licensed under the 2-clause BSD License but this license does
not cover the `MPEG LA` licensing fees. If you build `mobile-ffmpeg` with `openh264` and distribute that library, then
you are subject to pay `MPEG LA` licensing fees. Refer to [OpenH264 FAQ](https://www.openh264.org/faq.html) page for
the details. Please note that `mobile-ffmpeg` does not publish a binary with `openh264` inside.
Digital assets used in test applications are published in the public domain.
`strip-frameworks.sh` script included and distributed (until v4.x) is published under the [Apache License version 2.0](https://www.apache.org/licenses/LICENSE-2.0).
In test applications; embedded fonts are licensed under the [SIL Open Font License](https://opensource.org/licenses/OFL-1.1), other digital assets are published in the public domain.
Please visit [License](https://github.com/tanersener/mobile-ffmpeg/wiki/License) page for the details.
### 7. Contributing
### 9. Contributing
If you have any recommendations or ideas to improve it, please feel free to submit issues or pull requests. Any help is appreciated.
### 8. See Also
### 10. See Also
- [libav gas-preprocessor](https://github.com/libav/gas-preprocessor/raw/master/gas-preprocessor.pl)
- [FFmpeg API Documentation](https://ffmpeg.org/doxygen/3.4/index.html)
- [FFmpeg API Documentation](https://ffmpeg.org/doxygen/4.0/index.html)
- [FFmpeg Wiki](https://trac.ffmpeg.org/wiki/WikiStart)
- [FFmpeg License and Legal Considerations](https://ffmpeg.org/legal.html)
- [FFmpeg External Library Licenses](https://www.ffmpeg.org/doxygen/4.0/md_LICENSE.html)
+336 -66
View File
@@ -28,34 +28,45 @@ LIBRARY_WAVPACK=16
LIBRARY_KVAZAAR=17
LIBRARY_X264=18
LIBRARY_XVIDCORE=19
LIBRARY_LIBILBC=20
LIBRARY_OPUS=21
LIBRARY_SNAPPY=22
LIBRARY_SOXR=23
LIBRARY_LIBAOM=24
LIBRARY_GIFLIB=25
LIBRARY_JPEG=26
LIBRARY_LIBOGG=27
LIBRARY_LIBPNG=28
LIBRARY_LIBUUID=29
LIBRARY_NETTLE=30
LIBRARY_TIFF=31
LIBRARY_EXPAT=32
LIBRARY_ZLIB=33
LIBRARY_MEDIA_CODEC=34
LIBRARY_X265=20
LIBRARY_LIBVIDSTAB=21
LIBRARY_LIBILBC=22
LIBRARY_OPUS=23
LIBRARY_SNAPPY=24
LIBRARY_SOXR=25
LIBRARY_LIBAOM=26
LIBRARY_CHROMAPRINT=27
LIBRARY_TWOLAME=28
LIBRARY_SDL=29
LIBRARY_TESSERACT=30
LIBRARY_OPENH264=31
LIBRARY_GIFLIB=32
LIBRARY_JPEG=33
LIBRARY_LIBOGG=34
LIBRARY_LIBPNG=35
LIBRARY_LIBUUID=36
LIBRARY_NETTLE=37
LIBRARY_TIFF=38
LIBRARY_EXPAT=39
LIBRARY_SNDFILE=40
LIBRARY_LEPTONICA=41
LIBRARY_ZLIB=42
LIBRARY_MEDIA_CODEC=43
# ENABLE ARCH
ENABLED_ARCHITECTURES=(1 1 1 1 1)
# ENABLE LIBRARIES
ENABLED_LIBRARIES=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
ENABLED_LIBRARIES=(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
export BASEDIR=$(pwd)
export MOBILE_FFMPEG_TMPDIR="${BASEDIR}/.tmp"
# USING API LEVEL 21 / Android 5.0 (LOLLIPOP)
export API=21
# USING API LEVEL 24 / Android 7.0 (NOUGAT)
export API=24
RECONF_LIBRARIES=()
REBUILD_LIBRARIES=()
get_mobile_ffmpeg_version() {
local MOBILE_FFMPEG_VERSION=$(grep '#define MOBILE_FFMPEG_VERSION' ${BASEDIR}/android/app/src/main/cpp/mobileffmpeg.h | grep -Eo '\".*\"' | sed -e 's/\"//g')
@@ -71,14 +82,18 @@ without any external libraries enabled. Options can be used to disable ABIs and/
Please note that GPL libraries (external libraries with GPL license) need --enable-gpl flag to be set explicitly. \
When compilation ends an Android Archive (AAR) file is created with enabled platforms inside.\n"
echo -e "Usage: ./"$COMMAND" [OPTION]...\n"
echo -e "Usage: ./"$COMMAND" [OPTION]...\n"
echo -e "Specify environment variables as VARIABLE=VALUE to override default build options.\n"
echo -e "Options:"
echo -e " -h, --help\t\t\tdisplay this help and exit"
echo -e " -V, --version\t\t\tdisplay version information and exit\n"
echo -e " -v, --version\t\t\tdisplay version information and exit"
echo -e " -d, --debug\t\t\tbuild with debug information"
echo -e " -s, --speed\t\t\toptimize for speed instead of size"
echo -e " -l, --lts\t\t\tbuild lts packages to support API 16+ devices"
echo -e " -f, --force\t\t\tignore warnings\n"
echo -e "Licensing options:"
@@ -95,8 +110,9 @@ When compilation ends an Android Archive (AAR) file is created with enabled plat
echo -e "Libraries:"
echo -e " --full\t\t\tenables all external libraries"
echo -e " --enable-android-media-codec\tbuild with built-in Android MediaCodec [no]"
echo -e " --enable-android-zlib\t\tbuild with built-in zlib [no]"
echo -e " --enable-android-media-codec\tbuild with built-in Android MediaCodec support[no]"
echo -e " --enable-android-zlib\t\tbuild with built-in zlib support[no]"
echo -e " --enable-chromaprint\t\tbuild with chromaprint [no]"
echo -e " --enable-fontconfig\t\tbuild with fontconfig [no]"
echo -e " --enable-freetype\t\tbuild with freetype [no]"
echo -e " --enable-fribidi\t\tbuild with fribidi [no]"
@@ -114,16 +130,22 @@ When compilation ends an Android Archive (AAR) file is created with enabled plat
echo -e " --enable-libwebp\t\tbuild with libwebp [no]"
echo -e " --enable-libxml2\t\tbuild with libxml2 [no]"
echo -e " --enable-opencore-amr\t\tbuild with opencore-amr [no]"
echo -e " --enable-openh264\t\tbuild with openh264 [no]"
echo -e " --enable-opus\t\t\tbuild with opus [no]"
echo -e " --enable-sdl\t\t\tbuild with sdl [no]"
echo -e " --enable-shine\t\tbuild with shine [no]"
echo -e " --enable-snappy\t\tbuild with snappy [no]"
echo -e " --enable-soxr\t\t\tbuild with soxr [no]"
echo -e " --enable-speex\t\tbuild with speex [no]"
echo -e " --enable-tesseract\t\tbuild with tesseract [no]"
echo -e " --enable-twolame\t\tbuild with twolame [no]"
echo -e " --enable-wavpack\t\tbuild with wavpack [no]\n"
echo -e "GPL libraries:"
echo -e " --enable-libvidstab\t\tbuild with libvidstab [no]"
echo -e " --enable-x264\t\t\tbuild with x264 [no]"
echo -e " --enable-x265\t\t\tbuild with x265 [no]"
echo -e " --enable-xvidcore\t\tbuild with xvidcore [no]\n"
echo -e "Advanced options:"
@@ -136,7 +158,7 @@ display_version() {
COMMAND=`echo $0 | sed -e 's/\.\///g'`
echo -e "\
$COMMAND $(get_mobile_ffmpeg_version)\n\
$COMMAND v$(get_mobile_ffmpeg_version)\n\
Copyright (c) 2018 Taner Sener\n\
License LGPLv3.0: GNU LGPL version 3 or later\n\
<https://www.gnu.org/licenses/lgpl-3.0.en.html>\n\
@@ -145,16 +167,81 @@ GNU Lesser General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version."
}
reconf_library() {
RECONF_VARIABLE=$(echo "RECONF_$1" | sed "s/\-/\_/g")
skip_library() {
SKIP_VARIABLE=$(echo "SKIP_$1" | sed "s/\-/\_/g")
export ${RECONF_VARIABLE}=1
export ${SKIP_VARIABLE}=1
}
no_output_redirection() {
export NO_OUTPUT_REDIRECTION=1
}
no_workspace_cleanup_library() {
NO_WORKSPACE_CLEANUP_VARIABLE=$(echo "NO_WORKSPACE_CLEANUP_$1" | sed "s/\-/\_/g")
export ${NO_WORKSPACE_CLEANUP_VARIABLE}=1
}
no_link_time_optimization() {
export NO_LINK_TIME_OPTIMIZATION=1
}
enable_debug() {
export MOBILE_FFMPEG_DEBUG="-g"
BUILD_TYPE_ID+="debug "
}
optimize_for_speed() {
export MOBILE_FFMPEG_OPTIMIZED_FOR_SPEED="1"
}
enable_lts_build() {
export MOBILE_FFMPEG_LTS_BUILD="1"
# USING API LEVEL 16 / Android 4.1 (JELLY BEAN)
export API=16
}
reconf_library() {
local RECONF_VARIABLE=$(echo "RECONF_$1" | sed "s/\-/\_/g")
local library_supported=0
for library in {1..42}
do
library_name=$(get_library_name $((library - 1)))
if [[ $1 != "ffmpeg" ]] && [[ ${library_name} == $1 ]]; then
export ${RECONF_VARIABLE}=1
RECONF_LIBRARIES+=($1)
library_supported=1
fi
done
if [[ ${library_supported} -eq 0 ]]; then
echo -e "INFO: --reconf flag detected for library $1 is not supported.\n" 1>>${BASEDIR}/build.log 2>&1
fi
}
rebuild_library() {
REBUILD_VARIABLE=$(echo "REBUILD_$1" | sed "s/\-/\_/g")
local REBUILD_VARIABLE=$(echo "REBUILD_$1" | sed "s/\-/\_/g")
local library_supported=0
export ${REBUILD_VARIABLE}=1
for library in {1..42}
do
library_name=$(get_library_name $((library - 1)))
if [[ $1 != "ffmpeg" ]] && [[ ${library_name} == $1 ]]; then
export ${REBUILD_VARIABLE}=1
REBUILD_LIBRARIES+=($1)
library_supported=1
fi
done
if [[ ${library_supported} -eq 0 ]]; then
echo -e "INFO: --rebuild flag detected for library $1 is not supported.\n" 1>>${BASEDIR}/build.log 2>&1
fi
}
enable_library() {
@@ -169,6 +256,9 @@ set_library() {
android-zlib)
ENABLED_LIBRARIES[LIBRARY_ZLIB]=$2
;;
chromaprint)
ENABLED_LIBRARIES[LIBRARY_CHROMAPRINT]=$2
;;
fontconfig)
ENABLED_LIBRARIES[LIBRARY_FONTCONFIG]=$2
ENABLED_LIBRARIES[LIBRARY_LIBUUID]=$2
@@ -228,6 +318,9 @@ set_library() {
ENABLED_LIBRARIES[LIBRARY_LIBOGG]=$2
set_library "libvorbis" $2
;;
libvidstab)
ENABLED_LIBRARIES[LIBRARY_LIBVIDSTAB]=$2
;;
libvorbis)
ENABLED_LIBRARIES[LIBRARY_LIBVORBIS]=$2
ENABLED_LIBRARIES[LIBRARY_LIBOGG]=$2
@@ -249,9 +342,15 @@ set_library() {
opencore-amr)
ENABLED_LIBRARIES[LIBRARY_OPENCOREAMR]=$2
;;
openh264)
ENABLED_LIBRARIES[LIBRARY_OPENH264]=$2
;;
opus)
ENABLED_LIBRARIES[LIBRARY_OPUS]=$2
;;
sdl)
ENABLED_LIBRARIES[LIBRARY_SDL]=$2
;;
shine)
ENABLED_LIBRARIES[LIBRARY_SHINE]=$2
;;
@@ -265,25 +364,42 @@ set_library() {
speex)
ENABLED_LIBRARIES[LIBRARY_SPEEX]=$2
;;
tesseract)
ENABLED_LIBRARIES[LIBRARY_TESSERACT]=$2
ENABLED_LIBRARIES[LIBRARY_LEPTONICA]=$2
ENABLED_LIBRARIES[LIBRARY_LIBWEBP]=$2
ENABLED_LIBRARIES[LIBRARY_GIFLIB]=$2
ENABLED_LIBRARIES[LIBRARY_JPEG]=$2
ENABLED_LIBRARIES[LIBRARY_ZLIB]=$2
set_library "tiff" $2
set_library "libpng" $2
;;
twolame)
ENABLED_LIBRARIES[LIBRARY_TWOLAME]=$2
ENABLED_LIBRARIES[LIBRARY_SNDFILE]=$2
;;
wavpack)
ENABLED_LIBRARIES[LIBRARY_WAVPACK]=$2
;;
x264)
ENABLED_LIBRARIES[LIBRARY_X264]=$2
;;
x265)
ENABLED_LIBRARIES[LIBRARY_X265]=$2
;;
xvidcore)
ENABLED_LIBRARIES[LIBRARY_XVIDCORE]=$2
;;
tiff)
ENABLED_LIBRARIES[LIBRARY_TIFF]=$2
ENABLED_LIBRARIES[LIBRARY_JPEG]=$2
expat | giflib | jpeg | leptonica | libogg | libpng | libsndfile | libuuid)
# THESE LIBRARIES ARE NOT ENABLED DIRECTLY
;;
nettle)
ENABLED_LIBRARIES[LIBRARY_NETTLE]=$2
set_library "gmp" $2
;;
giflib | jpeg | libogg | libpng | libuuid | expat)
# THESE LIBRARIES ARE NOT ENABLED DIRECTLY
tiff)
ENABLED_LIBRARIES[LIBRARY_TIFF]=$2
ENABLED_LIBRARIES[LIBRARY_JPEG]=$2
;;
*)
print_unknown_library $1
@@ -361,7 +477,7 @@ print_enabled_libraries() {
let enabled=0;
# FIRST BUILT-IN LIBRARIES
for library in {33..34}
for library in {42..43}
do
if [[ ${ENABLED_LIBRARIES[$library]} -eq 1 ]]; then
if [[ ${enabled} -ge 1 ]]; then
@@ -373,7 +489,7 @@ print_enabled_libraries() {
done
# THEN EXTERNAL LIBRARIES
for library in {0..24}
for library in {0..31}
do
if [[ ${ENABLED_LIBRARIES[$library]} -eq 1 ]]; then
if [[ ${enabled} -ge 1 ]]; then
@@ -391,7 +507,63 @@ print_enabled_libraries() {
fi
}
print_reconfigure_requested_libraries() {
local counter=0;
for RECONF_LIBRARY in "${RECONF_LIBRARIES[@]}"
do
if [[ ${counter} -eq 0 ]]; then
echo -n "Reconfigure: "
else
echo -n ", "
fi
echo -n ${RECONF_LIBRARY}
counter=$((${counter} + 1));
done
if [[ ${counter} -gt 0 ]]; then
echo ""
fi
}
print_rebuild_requested_libraries() {
local counter=0;
for REBUILD_LIBRARY in "${REBUILD_LIBRARIES[@]}"
do
if [[ ${counter} -eq 0 ]]; then
echo -n "Rebuild: "
else
echo -n ", "
fi
echo -n ${REBUILD_LIBRARY}
counter=$((${counter} + 1));
done
if [[ ${counter} -gt 0 ]]; then
echo ""
fi
}
build_application_mk() {
if [[ ! -z ${MOBILE_FFMPEG_LTS_BUILD} ]]; then
local LTS_BUILD_FLAG="-DMOBILE_FFMPEG_LTS "
fi
if [[ ${ENABLED_LIBRARIES[$LIBRARY_X265]} -eq 1 ]] || [[ ${ENABLED_LIBRARIES[$LIBRARY_TESSERACT]} -eq 1 ]] || [[ ${ENABLED_LIBRARIES[$LIBRARY_OPENH264]} -eq 1 ]] || [[ ${ENABLED_LIBRARIES[$LIBRARY_SNAPPY]} -eq 1 ]]; then
local APP_STL="c++_shared"
else
local APP_STL="none"
${SED_INLINE} 's/c++_shared //g' ${BASEDIR}/android/jni/Android.mk 1>>${BASEDIR}/build.log 2>&1
fi
local BUILD_DATE="-DMOBILE_FFMPEG_BUILD_DATE=$(date +%Y%m%d 2>>${BASEDIR}/build.log)"
rm -f ${BASEDIR}/android/jni/Application.mk
cat > "${BASEDIR}/android/jni/Application.mk" << EOF
@@ -399,32 +571,73 @@ APP_OPTIM := release
APP_ABI := ${ANDROID_ARCHITECTURES}
APP_STL := c++_shared
APP_STL := ${APP_STL}
APP_PLATFORM := android-21
APP_PLATFORM := android-${API}
APP_CFLAGS := -O3 -DANDROID -Wall -Wno-deprecated-declarations -Wno-pointer-sign -Wno-switch -Wno-unused-result -Wno-unused-variable
APP_CFLAGS := -O3 -DANDROID ${LTS_BUILD_FLAG}${BUILD_DATE} -Wall -Wno-deprecated-declarations -Wno-pointer-sign -Wno-switch -Wno-unused-result -Wno-unused-variable
APP_LDFLAGS := -Wl,--hash-style=both
EOF
}
# ENABLE COMMON FUNCTIONS
. ${BASEDIR}/build/android-common.sh
DETECTED_NDK_VERSION=$(grep -Eo Revision.* ${ANDROID_NDK_ROOT}/source.properties | sed 's/Revision//g;s/=//g;s/ //g')
echo -e "\nINFO: Using Android NDK v${DETECTED_NDK_VERSION} provided at ${ANDROID_NDK_ROOT}\n" 1>>${BASEDIR}/build.log 2>&1
echo -e "INFO: Build options: $@\n" 1>>${BASEDIR}/build.log 2>&1
# CLEAR OLD NATIVE LIBS
rm -rf ${BASEDIR}/android/libs 1>>${BASEDIR}/build.log 2>&1
rm -rf ${BASEDIR}/android/obj 1>>${BASEDIR}/build.log 2>&1
GPL_ENABLED="no"
DISPLAY_HELP=""
BUILD_LTS=""
BUILD_TYPE_ID=""
BUILD_VERSION=$(git describe --tags 2>>${BASEDIR}/build.log)
while [ ! $# -eq 0 ]
do
case $1 in
-h | --help)
display_help
exit 0
DISPLAY_HELP="1"
;;
-V | --version)
-v | --version)
display_version
exit 0
;;
--skip-*)
SKIP_LIBRARY=`echo $1 | sed -e 's/^--[A-Za-z]*-//g'`
skip_library ${SKIP_LIBRARY}
;;
--no-output-redirection)
no_output_redirection
;;
--no-workspace-cleanup-*)
NO_WORKSPACE_CLEANUP_LIBRARY=`echo $1 | sed -e 's/^--[A-Za-z]*-[A-Za-z]*-[A-Za-z]*-//g'`
no_workspace_cleanup_library ${NO_WORKSPACE_CLEANUP_LIBRARY}
;;
--no-link-time-optimization)
no_link_time_optimization
;;
-d | --debug)
enable_debug
;;
-s | --speed)
optimize_for_speed
;;
-l | --lts)
BUILD_LTS="1"
;;
-f | --force)
BUILD_FORCE="1"
;;
--reconf-*)
CONF_LIBRARY=`echo $1 | sed -e 's/^--[A-Za-z]*-//g'`
@@ -436,9 +649,9 @@ do
rebuild_library ${BUILD_LIBRARY}
;;
--full)
for library in {0..34}
for library in {0..43}
do
if [[ $library -ne 18 ]] && [[ $library -ne 19 ]]; then
if [[ $library -ne 18 ]] && [[ $library -ne 19 ]] && [[ $library -ne 20 ]] && [[ $library -ne 21 ]]; then
enable_library $(get_library_name $library)
fi
done
@@ -463,59 +676,100 @@ do
shift
done;
# DETECT BUILD TYPE
rm -f ${BASEDIR}/android/jni/Android.mk 1>>${BASEDIR}/build.log 2>&1
rm -f ${BASEDIR}/android/app/build.gradle 1>>${BASEDIR}/build.log 2>&1
if [[ ! -z ${BUILD_LTS} ]]; then
enable_lts_build
BUILD_TYPE_ID+="LTS "
cp ${BASEDIR}/tools/ndk/Android.lts.mk ${BASEDIR}/android/jni/Android.mk 1>>${BASEDIR}/build.log 2>&1
cp ${BASEDIR}/tools/release/android/build.lts.gradle ${BASEDIR}/android/app/build.gradle 1>>${BASEDIR}/build.log 2>&1
else
cp ${BASEDIR}/tools/ndk/Android.mk ${BASEDIR}/android/jni/Android.mk 1>>${BASEDIR}/build.log 2>&1
cp ${BASEDIR}/tools/release/android/build.gradle ${BASEDIR}/android/app/build.gradle 1>>${BASEDIR}/build.log 2>&1
if [[ -z ${BUILD_FORCE} ]] && [[ ${ENABLED_ARCHITECTURES[${ARCH_ARM_V7A}]} -eq 1 ]]; then
echo -e "INFO: Disabled arm-v7a architecture which is not included in Main releases.\n" 1>>${BASEDIR}/build.log 2>&1
disable_arch "arm-v7a"
fi
fi
if [[ ! -z ${DISPLAY_HELP} ]]; then
display_help
exit 0
fi
if [[ -z ${ANDROID_NDK_ROOT} ]]; then
echo "ANDROID_NDK_ROOT not defined"
exit 1
fi
echo -e "Building mobile-ffmpeg for Android\n"
echo -e -n "INFO: Building mobile-ffmpeg for Android: " >>${BASEDIR}/build.log
echo -e `date` >>${BASEDIR}/build.log
if [[ -z ${ANDROID_HOME} ]]; then
echo "ANDROID_HOME not defined"
exit 1
fi
if [[ ${ENABLED_ARCHITECTURES[0]} -eq 0 ]] && [[ ${ENABLED_ARCHITECTURES[1]} -eq 1 ]]; then
ENABLED_ARCHITECTURES[0]=1
echo -e "\nBuilding mobile-ffmpeg ${BUILD_TYPE_ID}library for Android\n"
echo -e -n "INFO: Building mobile-ffmpeg ${BUILD_VERSION} ${BUILD_TYPE_ID}library for Android: " 1>>${BASEDIR}/build.log 2>&1
echo -e `date` 1>>${BASEDIR}/build.log 2>&1
# PERFORM THIS CHECK ONLY ON LTS
if [[ ! -z ${MOBILE_FFMPEG_LTS_BUILD} ]] && [[ ${ENABLED_ARCHITECTURES[0]} -eq 0 ]] && [[ ${ENABLED_ARCHITECTURES[1]} -eq 1 ]]; then
ENABLED_ARCHITECTURES[ARCH_ARM_V7A]=1
echo -e "(*) arm-v7a architecture enabled since arm-v7a-neon will be built\n"
echo -e "(*) arm-v7a architecture enabled since arm-v7a-neon will be built\n" 2>>${BASEDIR}/build.log 1>>${BASEDIR}/build.log
echo -e "(*) arm-v7a architecture enabled since arm-v7a-neon will be built\n" 1>>${BASEDIR}/build.log 2>&1
fi
print_enabled_architectures
print_enabled_libraries
print_reconfigure_requested_libraries
print_rebuild_requested_libraries
# CHECKING GPL LIBRARIES
for gpl_library in {18..19}
for gpl_library in {18..21}
do
if [[ ${ENABLED_LIBRARIES[$gpl_library]} -eq 1 ]]; then
library_name=$(get_library_name ${gpl_library})
if [ ${GPL_ENABLED} != "yes" ]; then
echo -e "\n(*) Invalid configuration detected. GPL library ${library_name} enabled without --enable-gpl flag.\n"
echo -e "\n(*) Invalid configuration detected. GPL library ${library_name} enabled without --enable-gpl flag.\n" >> ${BASEDIR}/build.log
echo -e "\n(*) Invalid configuration detected. GPL library ${library_name} enabled without --enable-gpl flag.\n" 1>>${BASEDIR}/build.log 2>&1
exit 1
else
DOWNLOAD_RESULT=$(download_gpl_library_source ${library_name})
if [[ ${DOWNLOAD_RESULT} -ne 0 ]]; then
echo -e "\n(*) Failed to download GPL library ${library_name} source. Please check build.log file for details. If the problem persists refer to offline building instructions.\n"
echo -e "\n(*) Failed to download GPL library ${library_name} source.\n" >> ${BASEDIR}/build.log
echo -e "\n(*) Failed to download GPL library ${library_name} source.\n" 1>>${BASEDIR}/build.log 2>&1
exit 1
fi
fi
fi
done
# SAVE API VALUE
export ORIGINAL_API=${API};
for run_arch in {0..4}
do
if [[ ${ENABLED_ARCHITECTURES[$run_arch]} -eq 1 ]]; then
if [[ ( ${run_arch} -eq ${ARCH_ARM64_V8A} || ${run_arch} -eq ${ARCH_X86_64} ) && ${API} < 21 ]] ; then
# 64 bit ABIs supported after API 21
export API=21
else
export API=${ORIGINAL_API}
fi
export ARCH=$(get_arch_name $run_arch)
export TOOLCHAIN=$(get_toolchain)
export TOOLCHAIN_ARCH=$(get_toolchain_arch)
create_toolchain || exit 1
. ${BASEDIR}/build/main-android.sh "${ENABLED_LIBRARIES[@]}" || exit 1
# CLEAR FLAGS
for library in {1..35}
for library in {1..44}
do
library_name=$(get_library_name $((library - 1)))
unset $(echo "OK_${library_name}" | sed "s/\-/\_/g")
@@ -524,11 +778,14 @@ do
fi
done
rm -f ${BASEDIR}/android/build/.neon
export API=${ORIGINAL_API}
# DEFINE ANDROID ARCHITECTURES
rm -f ${BASEDIR}/android/build/.neon 1>>${BASEDIR}/build.log 2>&1
ANDROID_ARCHITECTURES=""
if [[ ${ENABLED_ARCHITECTURES[1]} -eq 1 ]]; then
ANDROID_ARCHITECTURES+="$(get_android_arch 0) "
mkdir -p ${BASEDIR}/android/build
mkdir -p ${BASEDIR}/android/build 1>>${BASEDIR}/build.log 2>&1
cat > "${BASEDIR}/android/build/.neon" << EOF
EOF
elif [[ ${ENABLED_ARCHITECTURES[0]} -eq 1 ]]; then
@@ -544,6 +801,14 @@ if [[ ${ENABLED_ARCHITECTURES[4]} -eq 1 ]]; then
ANDROID_ARCHITECTURES+="$(get_android_arch 4) "
fi
# DEFINE BUILD FFPLAY FLAG
rm -f ${BASEDIR}/android/build/.ffplay 1>>${BASEDIR}/build.log 2>&1
if [[ ${ENABLED_LIBRARIES[LIBRARY_SDL]} -eq 1 ]]; then
mkdir -p ${BASEDIR}/android/build 1>>${BASEDIR}/build.log 2>&1
cat > "${BASEDIR}/android/build/.ffplay" << EOF
EOF
fi
if [[ ! -z ${ANDROID_ARCHITECTURES} ]]; then
echo -n -e "\nmobile-ffmpeg: "
@@ -553,13 +818,13 @@ if [[ ! -z ${ANDROID_ARCHITECTURES} ]]; then
MOBILE_FFMPEG_AAR=${BASEDIR}/prebuilt/android-aar/mobile-ffmpeg
# BUILDING ANDROID ARCHIVE LIBRARY
rm -rf ${BASEDIR}/android/libs
rm -rf ${BASEDIR}/android/libs 1>>${BASEDIR}/build.log 2>&1
mkdir -p ${MOBILE_FFMPEG_AAR}
mkdir -p ${MOBILE_FFMPEG_AAR} 1>>${BASEDIR}/build.log 2>&1
cd ${BASEDIR}/android
cd ${BASEDIR}/android 1>>${BASEDIR}/build.log 2>&1
${ANDROID_NDK_ROOT}/ndk-build -B 2>>${BASEDIR}/build.log 1>>${BASEDIR}/build.log
${ANDROID_NDK_ROOT}/ndk-build -B 1>>${BASEDIR}/build.log 2>&1
if [ $? -eq 0 ]; then
echo "ok"
@@ -570,16 +835,21 @@ if [[ ! -z ${ANDROID_ARCHITECTURES} ]]; then
echo -e -n "\n\nCreating Android archive under prebuilt/android-aar: "
gradle clean build 2>>${BASEDIR}/build.log 1>>${BASEDIR}/build.log
./gradlew app:clean app:assembleRelease app:testReleaseUnitTest 1>>${BASEDIR}/build.log 2>&1
if [ $? -ne 0 ]; then
echo -e "failed\n"
exit 1
fi
cp ${BASEDIR}/android/app/build/outputs/aar/mobile-ffmpeg-*.aar ${MOBILE_FFMPEG_AAR}/mobile-ffmpeg.aar || exit 1
cp ${BASEDIR}/android/app/build/outputs/aar/mobile-ffmpeg-release.aar ${MOBILE_FFMPEG_AAR}/mobile-ffmpeg.aar 1>>${BASEDIR}/build.log 2>&1
echo -e "Created mobile-ffmpeg Android archive successfully.\n" >> ${BASEDIR}/build.log
if [ $? -ne 0 ]; then
echo -e "failed\n"
exit 1
fi
echo -e "Created mobile-ffmpeg Android archive successfully.\n" 1>>${BASEDIR}/build.log 2>&1
echo -e "ok\n"
fi
+6 -8
View File
@@ -1,12 +1,10 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
local.properties
.DS_Store
/build
/captures
build
captures
.externalNativeBuild
/.idea/
/obj/
/libs/
.idea
obj
libs
-2
View File
@@ -1,2 +0,0 @@
/build
/local.properties
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = "MobileFFmpeg Android API"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 2.0
PROJECT_NUMBER = 4.3.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
+11 -23
View File
@@ -1,15 +1,17 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
compileSdkVersion 29
defaultConfig {
minSdkVersion 21
targetSdkVersion 27
versionCode 20
versionName "2.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
minSdkVersion 24
targetSdkVersion 29
versionCode 240431
versionName "4.3.1"
project.archivesBaseName = "mobile-ffmpeg"
consumerProguardFiles 'proguard-rules.pro'
}
buildTypes {
release {
minifyEnabled false
@@ -23,12 +25,8 @@ android {
}
}
libraryVariants.all { variant ->
variant.outputs.all { output ->
if (outputFile != null && outputFileName.endsWith('.aar')) {
outputFileName = "${archivesBaseName}-${android.defaultConfig.versionName}.aar"
}
}
testOptions {
unitTests.returnDefaultValues = true
}
}
@@ -39,16 +37,6 @@ task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
}
afterEvaluate {
javadoc.classpath += files(android.libraryVariants.collect { variant ->
variant.javaCompile.classpath.files
})
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
testImplementation "androidx.test.ext:junit:1.1.1"
}
+8 -13
View File
@@ -5,17 +5,12 @@
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-keep class com.arthenica.mobileffmpeg.Config {
native <methods>;
void log(int, byte[]);
void statistics(int, float, float, long , int, double, double);
}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keep class com.arthenica.mobileffmpeg.AbiDetect {
native <methods>;
}
@@ -1,45 +0,0 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.arthenica.mobileffmpeg", appContext.getPackageName());
}
}
-7
View File
@@ -1,11 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.arthenica.mobileffmpeg">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"/>
</manifest>
+2
View File
@@ -0,0 +1,2 @@
/android_lts_support.o
/libandroidltssupport.a
-91
View File
@@ -1,91 +0,0 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu-features.h"
#include "abidetect.h"
/** Full name of the Java class that owns native functions in this file. */
const char *abiDetectClassName = "com/arthenica/mobileffmpeg/AbiDetect";
/** Prototypes of native functions defined by this file. */
JNINativeMethod abiDetectMethods[] = {
{"getAbi", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_AbiDetect_getAbi}
};
/**
* Called when 'abidetect' native library is loaded.
*
* \param vm pointer to the running virtual machine
* \param reserved reserved
* \return JNI version needed by 'abidetect' library
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
LOGE("OnLoad failed to GetEnv for class %s.", abiDetectClassName);
return JNI_FALSE;
}
jclass abiDetectClass = (*env)->FindClass(env, abiDetectClassName);
if (abiDetectClass == NULL) {
LOGE("OnLoad failed to FindClass %s.", abiDetectClassName);
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, abiDetectClass, abiDetectMethods, 1) < 0) {
LOGE("OnLoad failed to RegisterNatives for class %s.", abiDetectClassName);
return JNI_FALSE;
}
return JNI_VERSION_1_6;
}
/**
* Returns running ABI name.
*
* \param env pointer to native method interface
* \param object reference to the class on which this method is invoked
* \return running ABI name as UTF string
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_AbiDetect_getAbi(JNIEnv *env, jclass object) {
AndroidCpuFamily family = android_getCpuFamily();
if (family == ANDROID_CPU_FAMILY_ARM) {
uint64_t features = android_getCpuFeatures();
if (features & ANDROID_CPU_ARM_FEATURE_ARMv7) {
if (features & ANDROID_CPU_ARM_FEATURE_NEON) {
return (*env)->NewStringUTF(env, ABI_ARMV7A_NEON);
} else {
return (*env)->NewStringUTF(env, ABI_ARMV7A);
}
} else {
return (*env)->NewStringUTF(env, ABI_ARM);
}
} else if (family == ANDROID_CPU_FAMILY_ARM64) {
return (*env)->NewStringUTF(env, ABI_ARM64_V8A);
} else if (family == ANDROID_CPU_FAMILY_X86) {
return (*env)->NewStringUTF(env, ABI_X86);
} else if (family == ANDROID_CPU_FAMILY_X86_64) {
return (*env)->NewStringUTF(env, ABI_X86_64);
} else {
return (*env)->NewStringUTF(env, ABI_UNKNOWN);
}
}
-54
View File
@@ -1,54 +0,0 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOBILEFFMPEG_ABIDETECT_H
#define MOBILEFFMPEG_ABIDETECT_H
#include <jni.h>
#include "log.h"
/** Represents armeabi-v7a ABI with NEON support. */
#define ABI_ARMV7A_NEON "armeabi-v7a-neon"
/** Represents armeabi-v7a ABI. */
#define ABI_ARMV7A "armeabi-v7a"
/** Represents armeabi ABI. */
#define ABI_ARM "armeabi"
/** Represents x86 ABI. */
#define ABI_X86 "x86"
/** Represents x86_64 ABI. */
#define ABI_X86_64 "x86_64"
/** Represents arm64-v8a ABI. */
#define ABI_ARM64_V8A "arm64-v8a"
/** Represents not supported ABIs. */
#define ABI_UNKNOWN "unknown"
/*
* Class: com_arthenica_mobileffmpeg_AbiDetect
* Method: getAbi
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_AbiDetect_getAbi(JNIEnv *, jclass);
#endif /* MOBILEFFMPEG_ABIDETECT_H */
@@ -0,0 +1,69 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <math.h>
#include <errno.h>
#include <malloc.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
#if __ANDROID_API__ < 17
int posix_memalign(void** memptr, size_t alignment, size_t size) {
if ((alignment & (alignment - 1)) != 0 || alignment == 0) {
return EINVAL;
}
if (alignment % sizeof(void*) != 0) {
return EINVAL;
}
*memptr = memalign(alignment, size);
if (*memptr == NULL) {
return errno;
}
return 0;
}
#endif /* __ANDROID_API__ < 17 */
double log2(double x) {
return (log(x) / M_LN2);
}
float log2f(float x) {
return (float) log2((double) x);
}
#ifdef __cplusplus
}; /* end of extern "C" */
#endif
File diff suppressed because it is too large Load Diff
-670
View File
@@ -1,670 +0,0 @@
/*
* Various utilities for command line tools
* copyright (c) 2003 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* CHANGES 03.2018 Taner Sener
* --------------------------------------------------------
* - Include guards renamed
* - log.h included
* - Unused headers removed
*/
#ifndef MOBILEFFMPEG_CMDUTILS_H
#define MOBILEFFMPEG_CMDUTILS_H
#include <stdint.h>
#include "config.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "log.h"
#ifdef _WIN32
#undef main /* We don't want SDL to override our main() */
#endif
/**
* program name, defined by the program for show_version().
*/
extern const char program_name[];
/**
* program birth year, defined by the program for show_banner()
*/
extern const int program_birth_year;
extern AVCodecContext *avcodec_opts[AVMEDIA_TYPE_NB];
extern AVFormatContext *avformat_opts;
extern AVDictionary *sws_dict;
extern AVDictionary *swr_opts;
extern AVDictionary *format_opts, *codec_opts, *resample_opts;
extern int hide_banner;
/**
* Register a program-specific cleanup routine.
*/
void register_exit(void (*cb)(int ret));
/**
* Wraps exit with a program-specific cleanup routine.
*/
void exit_program(int ret) av_noreturn;
/**
* Initialize dynamic library loading
*/
void init_dynload(void);
/**
* Initialize the cmdutils option system, in particular
* allocate the *_opts contexts.
*/
void init_opts(void);
/**
* Uninitialize the cmdutils option system, in particular
* free the *_opts contexts and their contents.
*/
void uninit_opts(void);
/**
* Trivial log callback.
* Only suitable for opt_help and similar since it lacks prefix handling.
*/
void log_callback_help(void* ptr, int level, const char* fmt, va_list vl);
/**
* Override the cpuflags.
*/
int opt_cpuflags(void *optctx, const char *opt, const char *arg);
/**
* Fallback for options that are not explicitly handled, these will be
* parsed through AVOptions.
*/
int opt_default(void *optctx, const char *opt, const char *arg);
/**
* Set the libav* libraries log level.
*/
int opt_loglevel(void *optctx, const char *opt, const char *arg);
int opt_report(const char *opt);
int opt_max_alloc(void *optctx, const char *opt, const char *arg);
int opt_codec_debug(void *optctx, const char *opt, const char *arg);
#if CONFIG_OPENCL
int opt_opencl(void *optctx, const char *opt, const char *arg);
int opt_opencl_bench(void *optctx, const char *opt, const char *arg);
#endif
/**
* Limit the execution time.
*/
int opt_timelimit(void *optctx, const char *opt, const char *arg);
/**
* Parse a string and return its corresponding value as a double.
* Exit from the application if the string cannot be correctly
* parsed or the corresponding value is invalid.
*
* @param context the context of the value to be set (e.g. the
* corresponding command line option name)
* @param numstr the string to be parsed
* @param type the type (OPT_INT64 or OPT_FLOAT) as which the
* string should be parsed
* @param min the minimum valid accepted value
* @param max the maximum valid accepted value
*/
double parse_number_or_die(const char *context, const char *numstr, int type,
double min, double max);
/**
* Parse a string specifying a time and return its corresponding
* value as a number of microseconds. Exit from the application if
* the string cannot be correctly parsed.
*
* @param context the context of the value to be set (e.g. the
* corresponding command line option name)
* @param timestr the string to be parsed
* @param is_duration a flag which tells how to interpret timestr, if
* not zero timestr is interpreted as a duration, otherwise as a
* date
*
* @see av_parse_time()
*/
int64_t parse_time_or_die(const char *context, const char *timestr,
int is_duration);
typedef struct SpecifierOpt {
char *specifier; /**< stream/chapter/program/... specifier */
union {
uint8_t *str;
int i;
int64_t i64;
float f;
double dbl;
} u;
} SpecifierOpt;
typedef struct OptionDef {
const char *name;
int flags;
#define HAS_ARG 0x0001
#define OPT_BOOL 0x0002
#define OPT_EXPERT 0x0004
#define OPT_STRING 0x0008
#define OPT_VIDEO 0x0010
#define OPT_AUDIO 0x0020
#define OPT_INT 0x0080
#define OPT_FLOAT 0x0100
#define OPT_SUBTITLE 0x0200
#define OPT_INT64 0x0400
#define OPT_EXIT 0x0800
#define OPT_DATA 0x1000
#define OPT_PERFILE 0x2000 /* the option is per-file (currently ffmpeg-only).
implied by OPT_OFFSET or OPT_SPEC */
#define OPT_OFFSET 0x4000 /* option is specified as an offset in a passed optctx */
#define OPT_SPEC 0x8000 /* option is to be stored in an array of SpecifierOpt.
Implies OPT_OFFSET. Next element after the offset is
an int containing element count in the array. */
#define OPT_TIME 0x10000
#define OPT_DOUBLE 0x20000
#define OPT_INPUT 0x40000
#define OPT_OUTPUT 0x80000
union {
void *dst_ptr;
int (*func_arg)(void *, const char *, const char *);
size_t off;
} u;
const char *help;
const char *argname;
} OptionDef;
/**
* Print help for all options matching specified flags.
*
* @param options a list of options
* @param msg title of this group. Only printed if at least one option matches.
* @param req_flags print only options which have all those flags set.
* @param rej_flags don't print options which have any of those flags set.
* @param alt_flags print only options that have at least one of those flags set
*/
void show_help_options(const OptionDef *options, const char *msg, int req_flags,
int rej_flags, int alt_flags);
#if CONFIG_OPENCL
#define CMDUTILS_COMMON_OPTIONS_OPENCL \
{ "opencl_bench", OPT_EXIT, {.func_arg = opt_opencl_bench}, \
"run benchmark on all OpenCL devices and show results" }, \
{ "opencl_options", HAS_ARG, {.func_arg = opt_opencl}, \
"set OpenCL environment options" }, \
#else
#define CMDUTILS_COMMON_OPTIONS_OPENCL
#endif
#if CONFIG_AVDEVICE
#define CMDUTILS_COMMON_OPTIONS_AVDEVICE \
{ "sources" , OPT_EXIT | HAS_ARG, { .func_arg = show_sources }, \
"list sources of the input device", "device" }, \
{ "sinks" , OPT_EXIT | HAS_ARG, { .func_arg = show_sinks }, \
"list sinks of the output device", "device" }, \
#else
#define CMDUTILS_COMMON_OPTIONS_AVDEVICE
#endif
#define CMDUTILS_COMMON_OPTIONS \
{ "L", OPT_EXIT, { .func_arg = show_license }, "show license" }, \
{ "h", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
{ "?", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
{ "help", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
{ "-help", OPT_EXIT, { .func_arg = show_help }, "show help", "topic" }, \
{ "version", OPT_EXIT, { .func_arg = show_version }, "show version" }, \
{ "buildconf", OPT_EXIT, { .func_arg = show_buildconf }, "show build configuration" }, \
{ "formats", OPT_EXIT, { .func_arg = show_formats }, "show available formats" }, \
{ "muxers", OPT_EXIT, { .func_arg = show_muxers }, "show available muxers" }, \
{ "demuxers", OPT_EXIT, { .func_arg = show_demuxers }, "show available demuxers" }, \
{ "devices", OPT_EXIT, { .func_arg = show_devices }, "show available devices" }, \
{ "codecs", OPT_EXIT, { .func_arg = show_codecs }, "show available codecs" }, \
{ "decoders", OPT_EXIT, { .func_arg = show_decoders }, "show available decoders" }, \
{ "encoders", OPT_EXIT, { .func_arg = show_encoders }, "show available encoders" }, \
{ "bsfs", OPT_EXIT, { .func_arg = show_bsfs }, "show available bit stream filters" }, \
{ "protocols", OPT_EXIT, { .func_arg = show_protocols }, "show available protocols" }, \
{ "filters", OPT_EXIT, { .func_arg = show_filters }, "show available filters" }, \
{ "pix_fmts", OPT_EXIT, { .func_arg = show_pix_fmts }, "show available pixel formats" }, \
{ "layouts", OPT_EXIT, { .func_arg = show_layouts }, "show standard channel layouts" }, \
{ "sample_fmts", OPT_EXIT, { .func_arg = show_sample_fmts }, "show available audio sample formats" }, \
{ "colors", OPT_EXIT, { .func_arg = show_colors }, "show available color names" }, \
{ "loglevel", HAS_ARG, { .func_arg = opt_loglevel }, "set logging level", "loglevel" }, \
{ "v", HAS_ARG, { .func_arg = opt_loglevel }, "set logging level", "loglevel" }, \
{ "report", 0, { (void*)opt_report }, "generate a report" }, \
{ "max_alloc", HAS_ARG, { .func_arg = opt_max_alloc }, "set maximum size of a single allocated block", "bytes" }, \
{ "cpuflags", HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags }, "force specific cpu flags", "flags" }, \
{ "hide_banner", OPT_BOOL | OPT_EXPERT, {&hide_banner}, "do not show program banner", "hide_banner" }, \
CMDUTILS_COMMON_OPTIONS_OPENCL \
CMDUTILS_COMMON_OPTIONS_AVDEVICE \
/**
* Show help for all options with given flags in class and all its
* children.
*/
void show_help_children(const AVClass *class, int flags);
/**
* Per-fftool specific help handler. Implemented in each
* fftool, called by show_help().
*/
void show_help_default(const char *opt, const char *arg);
/**
* Generic -h handler common to all fftools.
*/
int show_help(void *optctx, const char *opt, const char *arg);
/**
* Parse the command line arguments.
*
* @param optctx an opaque options context
* @param argc number of command line arguments
* @param argv values of command line arguments
* @param options Array with the definitions required to interpret every
* option of the form: -option_name [argument]
* @param parse_arg_function Name of the function called to process every
* argument without a leading option name flag. NULL if such arguments do
* not have to be processed.
*/
void parse_options(void *optctx, int argc, char **argv, const OptionDef *options,
void (* parse_arg_function)(void *optctx, const char*));
/**
* Parse one given option.
*
* @return on success 1 if arg was consumed, 0 otherwise; negative number on error
*/
int parse_option(void *optctx, const char *opt, const char *arg,
const OptionDef *options);
/**
* An option extracted from the commandline.
* Cannot use AVDictionary because of options like -map which can be
* used multiple times.
*/
typedef struct Option {
const OptionDef *opt;
const char *key;
const char *val;
} Option;
typedef struct OptionGroupDef {
/**< group name */
const char *name;
/**
* Option to be used as group separator. Can be NULL for groups which
* are terminated by a non-option argument (e.g. ffmpeg output files)
*/
const char *sep;
/**
* Option flags that must be set on each option that is
* applied to this group
*/
int flags;
} OptionGroupDef;
typedef struct OptionGroup {
const OptionGroupDef *group_def;
const char *arg;
Option *opts;
int nb_opts;
AVDictionary *codec_opts;
AVDictionary *format_opts;
AVDictionary *resample_opts;
AVDictionary *sws_dict;
AVDictionary *swr_opts;
} OptionGroup;
/**
* A list of option groups that all have the same group type
* (e.g. input files or output files)
*/
typedef struct OptionGroupList {
const OptionGroupDef *group_def;
OptionGroup *groups;
int nb_groups;
} OptionGroupList;
typedef struct OptionParseContext {
OptionGroup global_opts;
OptionGroupList *groups;
int nb_groups;
/* parsing state */
OptionGroup cur_group;
} OptionParseContext;
/**
* Parse an options group and write results into optctx.
*
* @param optctx an app-specific options context. NULL for global options group
*/
int parse_optgroup(void *optctx, OptionGroup *g);
/**
* Split the commandline into an intermediate form convenient for further
* processing.
*
* The commandline is assumed to be composed of options which either belong to a
* group (those with OPT_SPEC, OPT_OFFSET or OPT_PERFILE) or are global
* (everything else).
*
* A group (defined by an OptionGroupDef struct) is a sequence of options
* terminated by either a group separator option (e.g. -i) or a parameter that
* is not an option (doesn't start with -). A group without a separator option
* must always be first in the supplied groups list.
*
* All options within the same group are stored in one OptionGroup struct in an
* OptionGroupList, all groups with the same group definition are stored in one
* OptionGroupList in OptionParseContext.groups. The order of group lists is the
* same as the order of group definitions.
*/
int split_commandline(OptionParseContext *octx, int argc, char *argv[],
const OptionDef *options,
const OptionGroupDef *groups, int nb_groups);
/**
* Free all allocated memory in an OptionParseContext.
*/
void uninit_parse_context(OptionParseContext *octx);
/**
* Find the '-loglevel' option in the command line args and apply it.
*/
void parse_loglevel(int argc, char **argv, const OptionDef *options);
/**
* Return index of option opt in argv or 0 if not found.
*/
int locate_option(int argc, char **argv, const OptionDef *options,
const char *optname);
/**
* Check if the given stream matches a stream specifier.
*
* @param s Corresponding format context.
* @param st Stream from s to be checked.
* @param spec A stream specifier of the [v|a|s|d]:[\<stream index\>] form.
*
* @return 1 if the stream matches, 0 if it doesn't, <0 on error
*/
int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec);
/**
* Filter out options for given codec.
*
* Create a new options dictionary containing only the options from
* opts which apply to the codec with ID codec_id.
*
* @param opts dictionary to place options in
* @param codec_id ID of the codec that should be filtered for
* @param s Corresponding format context.
* @param st A stream from s for which the options should be filtered.
* @param codec The particular codec for which the options should be filtered.
* If null, the default one is looked up according to the codec id.
* @return a pointer to the created dictionary
*/
AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
AVFormatContext *s, AVStream *st, AVCodec *codec);
/**
* Setup AVCodecContext options for avformat_find_stream_info().
*
* Create an array of dictionaries, one dictionary for each stream
* contained in s.
* Each dictionary will contain the options from codec_opts which can
* be applied to the corresponding stream codec context.
*
* @return pointer to the created array of dictionaries, NULL if it
* cannot be created
*/
AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
AVDictionary *codec_opts);
/**
* Print an error message to stderr, indicating filename and a human
* readable description of the error code err.
*
* If strerror_r() is not available the use of this function in a
* multithreaded application may be unsafe.
*
* @see av_strerror()
*/
void print_error(const char *filename, int err);
/**
* Print the program banner to stderr. The banner contents depend on the
* current version of the repository and of the libav* libraries used by
* the program.
*/
void show_banner(int argc, char **argv, const OptionDef *options);
/**
* Print the version of the program to stdout. The version message
* depends on the current versions of the repository and of the libav*
* libraries.
* This option processing function does not utilize the arguments.
*/
int show_version(void *optctx, const char *opt, const char *arg);
/**
* Print the build configuration of the program to stdout. The contents
* depend on the definition of FFMPEG_CONFIGURATION.
* This option processing function does not utilize the arguments.
*/
int show_buildconf(void *optctx, const char *opt, const char *arg);
/**
* Print the license of the program to stdout. The license depends on
* the license of the libraries compiled into the program.
* This option processing function does not utilize the arguments.
*/
int show_license(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the formats supported by the
* program (including devices).
* This option processing function does not utilize the arguments.
*/
int show_formats(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the muxers supported by the
* program (including devices).
* This option processing function does not utilize the arguments.
*/
int show_muxers(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the demuxer supported by the
* program (including devices).
* This option processing function does not utilize the arguments.
*/
int show_demuxers(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the devices supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_devices(void *optctx, const char *opt, const char *arg);
#if CONFIG_AVDEVICE
/**
* Print a listing containing autodetected sinks of the output device.
* Device name with options may be passed as an argument to limit results.
*/
int show_sinks(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing autodetected sources of the input device.
* Device name with options may be passed as an argument to limit results.
*/
int show_sources(void *optctx, const char *opt, const char *arg);
#endif
/**
* Print a listing containing all the codecs supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_codecs(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the decoders supported by the
* program.
*/
int show_decoders(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the encoders supported by the
* program.
*/
int show_encoders(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the filters supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_filters(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the bit stream filters supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_bsfs(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the protocols supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_protocols(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the pixel formats supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_pix_fmts(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the standard channel layouts supported by
* the program.
* This option processing function does not utilize the arguments.
*/
int show_layouts(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the sample formats supported by the
* program.
*/
int show_sample_fmts(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the color names and values recognized
* by the program.
*/
int show_colors(void *optctx, const char *opt, const char *arg);
/**
* Return a positive value if a line read from standard input
* starts with [yY], otherwise return 0.
*/
int read_yesno(void);
/**
* Get a file corresponding to a preset file.
*
* If is_path is non-zero, look for the file in the path preset_name.
* Otherwise search for a file named arg.ffpreset in the directories
* $FFMPEG_DATADIR (if set), $HOME/.ffmpeg, and in the datadir defined
* at configuration time or in a "ffpresets" folder along the executable
* on win32, in that order. If no such file is found and
* codec_name is defined, then search for a file named
* codec_name-preset_name.avpreset in the above-mentioned directories.
*
* @param filename buffer where the name of the found filename is written
* @param filename_size size in bytes of the filename buffer
* @param preset_name name of the preset to search
* @param is_path tell if preset_name is a filename path
* @param codec_name name of the codec for which to look for the
* preset, may be NULL
*/
FILE *get_preset_file(char *filename, size_t filename_size,
const char *preset_name, int is_path, const char *codec_name);
/**
* Realloc array to hold new_size elements of elem_size.
* Calls exit() on failure.
*
* @param array array to reallocate
* @param elem_size size in bytes of each element
* @param size new element count will be written here
* @param new_size number of elements to place in reallocated array
* @return reallocated array
*/
void *grow_array(void *array, int elem_size, int *size, int new_size);
#define media_type_string av_get_media_type_string
#define GROW_ARRAY(array, nb_elems)\
array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1)
#define GET_PIX_FMT_NAME(pix_fmt)\
const char *name = av_get_pix_fmt_name(pix_fmt);
#define GET_SAMPLE_FMT_NAME(sample_fmt)\
const char *name = av_get_sample_fmt_name(sample_fmt)
#define GET_SAMPLE_RATE_NAME(rate)\
char name[16];\
snprintf(name, sizeof(name), "%d", rate);
#define GET_CH_LAYOUT_NAME(ch_layout)\
char name[16];\
snprintf(name, sizeof(name), "0x%"PRIx64, ch_layout);
#define GET_CH_LAYOUT_DESC(ch_layout)\
char name[128];\
av_get_channel_layout_string(name, sizeof(name), 0, ch_layout);
double get_rotation(AVStream *st);
#endif /* MOBILEFFMPEG_CMDUTILS_H */
-29
View File
@@ -1,29 +0,0 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOBILEFFMPEG_EXCEPTION_H
#define MOBILEFFMPEG_EXCEPTION_H
#include <stdio.h>
#include <setjmp.h>
/** Holds information to implement exception handling. */
jmp_buf ex_buf__;
#endif // MOBILEFFMPEG_EXCEPTION_H
File diff suppressed because it is too large Load Diff
-719
View File
@@ -1,719 +0,0 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* CHANGES 03.2018 Taner Sener
* --------------------------------------------------------
* - Include guards renamed
* - log.h included
* - mid_pred copied from libavcodec/mathops.h
* - ff_dlog copied from libavutil/internal.h
* - SWS_BILINEAR and SWS_BITEXACT definitions copied from libswscale/swscale.h
*/
#ifndef MOBILEFFMPEG_FFMPEG_H
#define MOBILEFFMPEG_FFMPEG_H
#include "config.h"
#include <stdint.h>
#include <stdio.h>
#include <signal.h>
#include "log.h"
#if HAVE_PTHREADS
#include <pthread.h>
#endif
#include "cmdutils.h"
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavutil/avutil.h"
#include "libavutil/dict.h"
#include "libavutil/eval.h"
#include "libavutil/fifo.h"
#include "libavutil/hwcontext.h"
#include "libavutil/pixfmt.h"
#include "libavutil/rational.h"
#include "libavutil/threadmessage.h"
#include "libswresample/swresample.h"
/* median of 3 */
#ifndef mid_pred
#define mid_pred mid_pred
static inline av_const int mid_pred(int a, int b, int c)
{
if(a>b){
if(c>b){
if(c>a) b=a;
else b=c;
}
}else{
if(b>c){
if(c>a) b=c;
else b=a;
}
}
return b;
}
#endif
#define SWS_BILINEAR 2
#define SWS_BITEXACT 0x80000
#ifdef DEBUG
# define ff_dlog(ctx, ...) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__)
#else
# define ff_dlog(ctx, ...) do { if (0) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0)
#endif
#define VSYNC_AUTO -1
#define VSYNC_PASSTHROUGH 0
#define VSYNC_CFR 1
#define VSYNC_VFR 2
#define VSYNC_VSCFR 0xfe
#define VSYNC_DROP 0xff
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
enum HWAccelID {
HWACCEL_NONE = 0,
HWACCEL_AUTO,
HWACCEL_VDPAU,
HWACCEL_DXVA2,
HWACCEL_VDA,
HWACCEL_VIDEOTOOLBOX,
HWACCEL_QSV,
HWACCEL_VAAPI,
HWACCEL_CUVID,
HWACCEL_D3D11VA,
};
typedef struct HWAccel {
const char *name;
int (*init)(AVCodecContext *s);
enum HWAccelID id;
enum AVPixelFormat pix_fmt;
enum AVHWDeviceType device_type;
} HWAccel;
typedef struct HWDevice {
char *name;
enum AVHWDeviceType type;
AVBufferRef *device_ref;
} HWDevice;
/* select an input stream for an output stream */
typedef struct StreamMap {
int disabled; /* 1 is this mapping is disabled by a negative map */
int file_index;
int stream_index;
int sync_file_index;
int sync_stream_index;
char *linklabel; /* name of an output link, for mapping lavfi outputs */
} StreamMap;
typedef struct {
int file_idx, stream_idx, channel_idx; // input
int ofile_idx, ostream_idx; // output
} AudioChannelMap;
typedef struct OptionsContext {
OptionGroup *g;
/* input/output options */
int64_t start_time;
int64_t start_time_eof;
int seek_timestamp;
const char *format;
SpecifierOpt *codec_names;
int nb_codec_names;
SpecifierOpt *audio_channels;
int nb_audio_channels;
SpecifierOpt *audio_sample_rate;
int nb_audio_sample_rate;
SpecifierOpt *frame_rates;
int nb_frame_rates;
SpecifierOpt *frame_sizes;
int nb_frame_sizes;
SpecifierOpt *frame_pix_fmts;
int nb_frame_pix_fmts;
/* input options */
int64_t input_ts_offset;
int loop;
int rate_emu;
int accurate_seek;
int thread_queue_size;
SpecifierOpt *ts_scale;
int nb_ts_scale;
SpecifierOpt *dump_attachment;
int nb_dump_attachment;
SpecifierOpt *hwaccels;
int nb_hwaccels;
SpecifierOpt *hwaccel_devices;
int nb_hwaccel_devices;
SpecifierOpt *hwaccel_output_formats;
int nb_hwaccel_output_formats;
SpecifierOpt *autorotate;
int nb_autorotate;
/* output options */
StreamMap *stream_maps;
int nb_stream_maps;
AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */
int nb_audio_channel_maps; /* number of (valid) -map_channel settings */
int metadata_global_manual;
int metadata_streams_manual;
int metadata_chapters_manual;
const char **attachments;
int nb_attachments;
int chapters_input_file;
int64_t recording_time;
int64_t stop_time;
uint64_t limit_filesize;
float mux_preload;
float mux_max_delay;
int shortest;
int video_disable;
int audio_disable;
int subtitle_disable;
int data_disable;
/* indexed by output file stream index */
int *streamid_map;
int nb_streamid_map;
SpecifierOpt *metadata;
int nb_metadata;
SpecifierOpt *max_frames;
int nb_max_frames;
SpecifierOpt *bitstream_filters;
int nb_bitstream_filters;
SpecifierOpt *codec_tags;
int nb_codec_tags;
SpecifierOpt *sample_fmts;
int nb_sample_fmts;
SpecifierOpt *qscale;
int nb_qscale;
SpecifierOpt *forced_key_frames;
int nb_forced_key_frames;
SpecifierOpt *force_fps;
int nb_force_fps;
SpecifierOpt *frame_aspect_ratios;
int nb_frame_aspect_ratios;
SpecifierOpt *rc_overrides;
int nb_rc_overrides;
SpecifierOpt *intra_matrices;
int nb_intra_matrices;
SpecifierOpt *inter_matrices;
int nb_inter_matrices;
SpecifierOpt *chroma_intra_matrices;
int nb_chroma_intra_matrices;
SpecifierOpt *top_field_first;
int nb_top_field_first;
SpecifierOpt *metadata_map;
int nb_metadata_map;
SpecifierOpt *presets;
int nb_presets;
SpecifierOpt *copy_initial_nonkeyframes;
int nb_copy_initial_nonkeyframes;
SpecifierOpt *copy_prior_start;
int nb_copy_prior_start;
SpecifierOpt *filters;
int nb_filters;
SpecifierOpt *filter_scripts;
int nb_filter_scripts;
SpecifierOpt *reinit_filters;
int nb_reinit_filters;
SpecifierOpt *fix_sub_duration;
int nb_fix_sub_duration;
SpecifierOpt *canvas_sizes;
int nb_canvas_sizes;
SpecifierOpt *pass;
int nb_pass;
SpecifierOpt *passlogfiles;
int nb_passlogfiles;
SpecifierOpt *max_muxing_queue_size;
int nb_max_muxing_queue_size;
SpecifierOpt *guess_layout_max;
int nb_guess_layout_max;
SpecifierOpt *apad;
int nb_apad;
SpecifierOpt *discard;
int nb_discard;
SpecifierOpt *disposition;
int nb_disposition;
SpecifierOpt *program;
int nb_program;
SpecifierOpt *time_bases;
int nb_time_bases;
SpecifierOpt *enc_time_bases;
int nb_enc_time_bases;
} OptionsContext;
typedef struct InputFilter {
AVFilterContext *filter;
struct InputStream *ist;
struct FilterGraph *graph;
uint8_t *name;
enum AVMediaType type; // AVMEDIA_TYPE_SUBTITLE for sub2video
AVFifoBuffer *frame_queue;
// parameters configured for this input
int format;
int width, height;
AVRational sample_aspect_ratio;
int sample_rate;
int channels;
uint64_t channel_layout;
AVBufferRef *hw_frames_ctx;
int eof;
} InputFilter;
typedef struct OutputFilter {
AVFilterContext *filter;
struct OutputStream *ost;
struct FilterGraph *graph;
uint8_t *name;
/* temporary storage until stream maps are processed */
AVFilterInOut *out_tmp;
enum AVMediaType type;
/* desired output stream properties */
int width, height;
AVRational frame_rate;
int format;
int sample_rate;
uint64_t channel_layout;
// those are only set if no format is specified and the encoder gives us multiple options
int *formats;
uint64_t *channel_layouts;
int *sample_rates;
} OutputFilter;
typedef struct FilterGraph {
int index;
const char *graph_desc;
AVFilterGraph *graph;
int reconfiguration;
InputFilter **inputs;
int nb_inputs;
OutputFilter **outputs;
int nb_outputs;
} FilterGraph;
typedef struct InputStream {
int file_index;
AVStream *st;
int discard; /* true if stream data should be discarded */
int user_set_discard;
int decoding_needed; /* non zero if the packets must be decoded in 'raw_fifo', see DECODING_FOR_* */
#define DECODING_FOR_OST 1
#define DECODING_FOR_FILTER 2
AVCodecContext *dec_ctx;
AVCodec *dec;
AVFrame *decoded_frame;
AVFrame *filter_frame; /* a ref of decoded_frame, to be sent to filters */
int64_t start; /* time when read started */
/* predicted dts of the next packet read for this stream or (when there are
* several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
int64_t next_dts;
int64_t dts; ///< dts of the last packet read for this stream (in AV_TIME_BASE units)
int64_t next_pts; ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)
int64_t pts; ///< current pts of the decoded frame (in AV_TIME_BASE units)
int wrap_correction_done;
int64_t filter_in_rescale_delta_last;
int64_t min_pts; /* pts with the smallest value in a current stream */
int64_t max_pts; /* pts with the higher value in a current stream */
// when forcing constant input framerate through -r,
// this contains the pts that will be given to the next decoded frame
int64_t cfr_next_pts;
int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */
double ts_scale;
int saw_first_ts;
AVDictionary *decoder_opts;
AVRational framerate; /* framerate forced with -r */
int top_field_first;
int guess_layout_max;
int autorotate;
int fix_sub_duration;
struct { /* previous decoded subtitle and related variables */
int got_output;
int ret;
AVSubtitle subtitle;
} prev_sub;
struct sub2video {
int64_t last_pts;
int64_t end_pts;
AVFifoBuffer *sub_queue; ///< queue of AVSubtitle* before filter init
AVFrame *frame;
int w, h;
} sub2video;
int dr1;
/* decoded data from this stream goes into all those filters
* currently video and audio only */
InputFilter **filters;
int nb_filters;
int reinit_filters;
/* hwaccel options */
enum HWAccelID hwaccel_id;
char *hwaccel_device;
enum AVPixelFormat hwaccel_output_format;
/* hwaccel context */
enum HWAccelID active_hwaccel_id;
void *hwaccel_ctx;
void (*hwaccel_uninit)(AVCodecContext *s);
int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags);
int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame);
enum AVPixelFormat hwaccel_pix_fmt;
enum AVPixelFormat hwaccel_retrieved_pix_fmt;
AVBufferRef *hw_frames_ctx;
/* stats */
// combined size of all the packets read
uint64_t data_size;
/* number of packets successfully read for this stream */
uint64_t nb_packets;
// number of frames/samples retrieved from the decoder
uint64_t frames_decoded;
uint64_t samples_decoded;
int64_t *dts_buffer;
int nb_dts_buffer;
int got_output;
} InputStream;
typedef struct InputFile {
AVFormatContext *ctx;
int eof_reached; /* true if eof reached */
int eagain; /* true if last read attempt returned EAGAIN */
int ist_index; /* index of first stream in input_streams */
int loop; /* set number of times input stream should be looped */
int64_t duration; /* actual duration of the longest stream in a file
at the moment when looping happens */
AVRational time_base; /* time base of the duration */
int64_t input_ts_offset;
int64_t ts_offset;
int64_t last_ts;
int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
int seek_timestamp;
int64_t recording_time;
int nb_streams; /* number of stream that ffmpeg is aware of; may be different
from ctx.nb_streams if new streams appear during av_read_frame() */
int nb_streams_warn; /* number of streams that the user was warned of */
int rate_emu;
int accurate_seek;
#if HAVE_PTHREADS
AVThreadMessageQueue *in_thread_queue;
pthread_t thread; /* thread reading from this file */
int non_blocking; /* reading packets from the thread should not block */
int joined; /* the thread has been joined */
int thread_queue_size; /* maximum number of queued packets */
#endif
} InputFile;
enum forced_keyframes_const {
FKF_N,
FKF_N_FORCED,
FKF_PREV_FORCED_N,
FKF_PREV_FORCED_T,
FKF_T,
FKF_NB
};
#define ABORT_ON_FLAG_EMPTY_OUTPUT (1 << 0)
extern const char *const forced_keyframes_const_names[];
typedef enum {
ENCODER_FINISHED = 1,
MUXER_FINISHED = 2,
} OSTFinished ;
typedef struct OutputStream {
int file_index; /* file index */
int index; /* stream index in the output file */
int source_index; /* InputStream index */
AVStream *st; /* stream in the output file */
int encoding_needed; /* true if encoding needed for this stream */
int frame_number;
/* input pts and corresponding output pts
for A/V sync */
struct InputStream *sync_ist; /* input stream to sync against */
int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number
/* pts of the first frame encoded for this stream, used for limiting
* recording time */
int64_t first_pts;
/* dts of the last packet sent to the muxer */
int64_t last_mux_dts;
// the timebase of the packets sent to the muxer
AVRational mux_timebase;
AVRational enc_timebase;
int nb_bitstream_filters;
AVBSFContext **bsf_ctx;
AVCodecContext *enc_ctx;
AVCodecParameters *ref_par; /* associated input codec parameters with encoders options applied */
AVCodec *enc;
int64_t max_frames;
AVFrame *filtered_frame;
AVFrame *last_frame;
int last_dropped;
int last_nb0_frames[3];
void *hwaccel_ctx;
/* video only */
AVRational frame_rate;
int is_cfr;
int force_fps;
int top_field_first;
int rotate_overridden;
double rotate_override_value;
AVRational frame_aspect_ratio;
/* forced key frames */
int64_t *forced_kf_pts;
int forced_kf_count;
int forced_kf_index;
char *forced_keyframes;
AVExpr *forced_keyframes_pexpr;
double forced_keyframes_expr_const_values[FKF_NB];
/* audio only */
int *audio_channels_map; /* list of the channels id to pick from the source stream */
int audio_channels_mapped; /* number of channels in audio_channels_map */
char *logfile_prefix;
FILE *logfile;
OutputFilter *filter;
char *avfilter;
char *filters; ///< filtergraph associated to the -filter option
char *filters_script; ///< filtergraph script associated to the -filter_script option
AVDictionary *encoder_opts;
AVDictionary *sws_dict;
AVDictionary *swr_opts;
AVDictionary *resample_opts;
char *apad;
OSTFinished finished; /* no more packets should be written for this stream */
int unavailable; /* true if the steram is unavailable (possibly temporarily) */
int stream_copy;
// init_output_stream() has been called for this stream
// The encoder and the bitstream filters have been initialized and the stream
// parameters are set in the AVStream.
int initialized;
int inputs_done;
const char *attachment_filename;
int copy_initial_nonkeyframes;
int copy_prior_start;
char *disposition;
int keep_pix_fmt;
AVCodecParserContext *parser;
AVCodecContext *parser_avctx;
/* stats */
// combined size of all the packets written
uint64_t data_size;
// number of packets send to the muxer
uint64_t packets_written;
// number of frames/samples sent to the encoder
uint64_t frames_encoded;
uint64_t samples_encoded;
/* packet quality factor */
int quality;
int max_muxing_queue_size;
/* the packets are buffered here until the muxer is ready to be initialized */
AVFifoBuffer *muxing_queue;
/* packet picture type */
int pict_type;
/* frame encode sum of squared error values */
int64_t error[4];
} OutputStream;
typedef struct OutputFile {
AVFormatContext *ctx;
AVDictionary *opts;
int ost_index; /* index of the first stream in output_streams */
int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units
int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units
uint64_t limit_filesize; /* filesize limit expressed in bytes */
int shortest;
int header_written;
} OutputFile;
extern InputStream **input_streams;
extern int nb_input_streams;
extern InputFile **input_files;
extern int nb_input_files;
extern OutputStream **output_streams;
extern int nb_output_streams;
extern OutputFile **output_files;
extern int nb_output_files;
extern FilterGraph **filtergraphs;
extern int nb_filtergraphs;
extern char *vstats_filename;
extern char *sdp_filename;
extern float audio_drift_threshold;
extern float dts_delta_threshold;
extern float dts_error_threshold;
extern int audio_volume;
extern int audio_sync_method;
extern int video_sync_method;
extern float frame_drop_threshold;
extern int do_benchmark;
extern int do_benchmark_all;
extern int do_deinterlace;
extern int do_hex_dump;
extern int do_pkt_dump;
extern int copy_ts;
extern int start_at_zero;
extern int copy_tb;
extern int debug_ts;
extern int exit_on_error;
extern int abort_on_flags;
extern int print_stats;
extern int qp_hist;
extern int stdin_interaction;
extern int frame_bits_per_raw_sample;
extern AVIOContext *progress_avio;
extern float max_error_rate;
extern char *videotoolbox_pixfmt;
extern int filter_nbthreads;
extern int filter_complex_nbthreads;
extern int vstats_version;
extern const AVIOInterruptCB int_cb;
extern const OptionDef options[];
extern const HWAccel hwaccels[];
extern int hwaccel_lax_profile_check;
extern AVBufferRef *hw_device_ctx;
#if CONFIG_QSV
extern char *qsv_device;
#endif
extern HWDevice *filter_hw_device;
void term_init(void);
void term_exit(void);
void reset_options(OptionsContext *o, int is_input);
void show_usage(void);
void opt_output_file(void *optctx, const char *filename);
void remove_avoptions(AVDictionary **a, AVDictionary *b);
void assert_avoptions(AVDictionary *m);
int guess_input_channel_layout(InputStream *ist);
enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *avctx, AVCodec *codec, enum AVPixelFormat target);
void choose_sample_fmt(AVStream *st, AVCodec *codec);
int configure_filtergraph(FilterGraph *fg);
int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out);
void check_filter_outputs(void);
int ist_in_filtergraph(FilterGraph *fg, InputStream *ist);
int filtergraph_is_simple(FilterGraph *fg);
int init_simple_filtergraph(InputStream *ist, OutputStream *ost);
int init_complex_filtergraph(FilterGraph *fg);
void sub2video_update(InputStream *ist, AVSubtitle *sub);
int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame);
int ffmpeg_parse_options(int argc, char **argv);
int vda_init(AVCodecContext *s);
int videotoolbox_init(AVCodecContext *s);
int qsv_init(AVCodecContext *s);
int cuvid_init(AVCodecContext *s);
HWDevice *hw_device_get_by_name(const char *name);
int hw_device_init_from_string(const char *arg, HWDevice **dev);
void hw_device_free_all(void);
int hw_device_setup_for_decode(InputStream *ist);
int hw_device_setup_for_encode(OutputStream *ost);
int hwaccel_decode_init(AVCodecContext *avctx);
#endif /* MOBILEFFMPEG_FFMPEG_H */
File diff suppressed because it is too large Load Diff
-385
View File
@@ -1,385 +0,0 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include "libavutil/avstring.h"
#include "ffmpeg.h"
static int nb_hw_devices;
static HWDevice **hw_devices;
static HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)
{
HWDevice *found = NULL;
int i;
for (i = 0; i < nb_hw_devices; i++) {
if (hw_devices[i]->type == type) {
if (found)
return NULL;
found = hw_devices[i];
}
}
return found;
}
HWDevice *hw_device_get_by_name(const char *name)
{
int i;
for (i = 0; i < nb_hw_devices; i++) {
if (!strcmp(hw_devices[i]->name, name))
return hw_devices[i];
}
return NULL;
}
static HWDevice *hw_device_add(void)
{
int err;
err = av_reallocp_array(&hw_devices, nb_hw_devices + 1,
sizeof(*hw_devices));
if (err) {
nb_hw_devices = 0;
return NULL;
}
hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice));
if (!hw_devices[nb_hw_devices])
return NULL;
return hw_devices[nb_hw_devices++];
}
int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
{
// "type=name:device,key=value,key2=value2"
// "type:device,key=value,key2=value2"
// -> av_hwdevice_ctx_create()
// "type=name@name"
// "type@name"
// -> av_hwdevice_ctx_create_derived()
AVDictionary *options = NULL;
char *type_name = NULL, *name = NULL, *device = NULL;
enum AVHWDeviceType type;
HWDevice *dev, *src;
AVBufferRef *device_ref = NULL;
int err;
const char *errmsg, *p, *q;
size_t k;
k = strcspn(arg, ":=@");
p = arg + k;
type_name = av_strndup(arg, k);
if (!type_name) {
err = AVERROR(ENOMEM);
goto fail;
}
type = av_hwdevice_find_type_by_name(type_name);
if (type == AV_HWDEVICE_TYPE_NONE) {
errmsg = "unknown device type";
goto invalid;
}
if (*p == '=') {
k = strcspn(p + 1, ":@");
name = av_strndup(p + 1, k);
if (!name) {
err = AVERROR(ENOMEM);
goto fail;
}
if (hw_device_get_by_name(name)) {
errmsg = "named device already exists";
goto invalid;
}
p += 1 + k;
} else {
// Give the device an automatic name of the form "type%d".
// We arbitrarily limit at 1000 anonymous devices of the same
// type - there is probably something else very wrong if you
// get to this limit.
size_t index_pos;
int index, index_limit = 1000;
index_pos = strlen(type_name);
name = av_malloc(index_pos + 4);
if (!name) {
err = AVERROR(ENOMEM);
goto fail;
}
for (index = 0; index < index_limit; index++) {
snprintf(name, index_pos + 4, "%s%d", type_name, index);
if (!hw_device_get_by_name(name))
break;
}
if (index >= index_limit) {
errmsg = "too many devices";
goto invalid;
}
}
if (!*p) {
// New device with no parameters.
err = av_hwdevice_ctx_create(&device_ref, type,
NULL, NULL, 0);
if (err < 0)
goto fail;
} else if (*p == ':') {
// New device with some parameters.
++p;
q = strchr(p, ',');
if (q) {
device = av_strndup(p, q - p);
if (!device) {
err = AVERROR(ENOMEM);
goto fail;
}
err = av_dict_parse_string(&options, q + 1, "=", ",", 0);
if (err < 0) {
errmsg = "failed to parse options";
goto invalid;
}
}
err = av_hwdevice_ctx_create(&device_ref, type,
device ? device : p, options, 0);
if (err < 0)
goto fail;
} else if (*p == '@') {
// Derive from existing device.
src = hw_device_get_by_name(p + 1);
if (!src) {
errmsg = "invalid source device name";
goto invalid;
}
err = av_hwdevice_ctx_create_derived(&device_ref, type,
src->device_ref, 0);
if (err < 0)
goto fail;
} else {
errmsg = "parse error";
goto invalid;
}
dev = hw_device_add();
if (!dev) {
err = AVERROR(ENOMEM);
goto fail;
}
dev->name = name;
dev->type = type;
dev->device_ref = device_ref;
if (dev_out)
*dev_out = dev;
name = NULL;
err = 0;
done:
av_freep(&type_name);
av_freep(&name);
av_freep(&device);
av_dict_free(&options);
return err;
invalid:
av_log(NULL, AV_LOG_ERROR,
"Invalid device specification \"%s\": %s\n", arg, errmsg);
err = AVERROR(EINVAL);
goto done;
fail:
av_log(NULL, AV_LOG_ERROR,
"Device creation failed: %d.\n", err);
av_buffer_unref(&device_ref);
goto done;
}
void hw_device_free_all(void)
{
int i;
for (i = 0; i < nb_hw_devices; i++) {
av_freep(&hw_devices[i]->name);
av_buffer_unref(&hw_devices[i]->device_ref);
av_freep(&hw_devices[i]);
}
av_freep(&hw_devices);
nb_hw_devices = 0;
}
static enum AVHWDeviceType hw_device_match_type_by_hwaccel(enum HWAccelID hwaccel_id)
{
int i;
if (hwaccel_id == HWACCEL_NONE)
return AV_HWDEVICE_TYPE_NONE;
for (i = 0; hwaccels[i].name; i++) {
if (hwaccels[i].id == hwaccel_id)
return hwaccels[i].device_type;
}
return AV_HWDEVICE_TYPE_NONE;
}
static enum AVHWDeviceType hw_device_match_type_in_name(const char *codec_name)
{
const char *type_name;
enum AVHWDeviceType type;
for (type = av_hwdevice_iterate_types(AV_HWDEVICE_TYPE_NONE);
type != AV_HWDEVICE_TYPE_NONE;
type = av_hwdevice_iterate_types(type)) {
type_name = av_hwdevice_get_type_name(type);
if (strstr(codec_name, type_name))
return type;
}
return AV_HWDEVICE_TYPE_NONE;
}
int hw_device_setup_for_decode(InputStream *ist)
{
enum AVHWDeviceType type;
HWDevice *dev;
int err;
if (ist->hwaccel_device) {
dev = hw_device_get_by_name(ist->hwaccel_device);
if (!dev) {
char *tmp;
type = hw_device_match_type_by_hwaccel(ist->hwaccel_id);
if (type == AV_HWDEVICE_TYPE_NONE) {
// No match - this isn't necessarily invalid, though,
// because an explicit device might not be needed or
// the hwaccel setup could be handled elsewhere.
return 0;
}
tmp = av_asprintf("%s:%s", av_hwdevice_get_type_name(type),
ist->hwaccel_device);
if (!tmp)
return AVERROR(ENOMEM);
err = hw_device_init_from_string(tmp, &dev);
av_free(tmp);
if (err < 0)
return err;
}
} else {
if (ist->hwaccel_id != HWACCEL_NONE)
type = hw_device_match_type_by_hwaccel(ist->hwaccel_id);
else
type = hw_device_match_type_in_name(ist->dec->name);
if (type != AV_HWDEVICE_TYPE_NONE) {
dev = hw_device_get_by_type(type);
if (!dev) {
hw_device_init_from_string(av_hwdevice_get_type_name(type),
&dev);
}
} else {
// No device required.
return 0;
}
}
if (!dev) {
av_log(ist->dec_ctx, AV_LOG_WARNING, "No device available "
"for decoder (device type %s for codec %s).\n",
av_hwdevice_get_type_name(type), ist->dec->name);
return 0;
}
ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
if (!ist->dec_ctx->hw_device_ctx)
return AVERROR(ENOMEM);
return 0;
}
int hw_device_setup_for_encode(OutputStream *ost)
{
enum AVHWDeviceType type;
HWDevice *dev;
type = hw_device_match_type_in_name(ost->enc->name);
if (type != AV_HWDEVICE_TYPE_NONE) {
dev = hw_device_get_by_type(type);
if (!dev) {
av_log(ost->enc_ctx, AV_LOG_WARNING, "No device available "
"for encoder (device type %s for codec %s).\n",
av_hwdevice_get_type_name(type), ost->enc->name);
return 0;
}
ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
if (!ost->enc_ctx->hw_device_ctx)
return AVERROR(ENOMEM);
return 0;
} else {
// No device required.
return 0;
}
}
static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
{
InputStream *ist = avctx->opaque;
AVFrame *output = NULL;
enum AVPixelFormat output_format = ist->hwaccel_output_format;
int err;
if (input->format == output_format) {
// Nothing to do.
return 0;
}
output = av_frame_alloc();
if (!output)
return AVERROR(ENOMEM);
output->format = output_format;
err = av_hwframe_transfer_data(output, input, 0);
if (err < 0) {
av_log(avctx, AV_LOG_ERROR, "Failed to transfer data to "
"output frame: %d.\n", err);
goto fail;
}
err = av_frame_copy_props(output, input);
if (err < 0) {
av_frame_unref(output);
goto fail;
}
av_frame_unref(input);
av_frame_move_ref(input, output);
av_frame_free(&output);
return 0;
fail:
av_frame_free(&output);
return err;
}
int hwaccel_decode_init(AVCodecContext *avctx)
{
InputStream *ist = avctx->opaque;
ist->hwaccel_retrieve_data = &hwaccel_retrieve_data;
return 0;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+636
View File
@@ -0,0 +1,636 @@
/*
* Various utilities for command line tools
* copyright (c) 2003 Fabrice Bellard
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* CHANGES 01.2020
* - ffprobe support changes
* - AV_LOG_STDERR introduced
*
* CHANGES 12.2019
* - Concurrent execution support
*
* CHANGES 03.2019
* --------------------------------------------------------
* - config.h include removed
*
* CHANGES 08.2018
* --------------------------------------------------------
* - fftools_ prefix added to file name and include guards
*
* CHANGES 07.2018
* --------------------------------------------------------
* - Include guards renamed
* - Unused headers removed
*/
#ifndef FFTOOLS_CMDUTILS_H
#define FFTOOLS_CMDUTILS_H
#include <stdint.h>
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#ifdef _WIN32
#undef main /* We don't want SDL to override our main() */
#endif
/**
* Defines logs printed to stderr by ffmpeg. They are not filtered and always redirected.
*/
#define AV_LOG_STDERR -16
/**
* program name, defined by the program for show_version().
*/
extern __thread char *program_name;
/**
* program birth year, defined by the program for show_banner()
*/
extern __thread int program_birth_year;
extern __thread AVCodecContext *avcodec_opts[AVMEDIA_TYPE_NB];
extern __thread AVFormatContext *avformat_opts;
extern __thread AVDictionary *sws_dict;
extern __thread AVDictionary *swr_opts;
extern __thread AVDictionary *format_opts, *codec_opts, *resample_opts;
extern __thread int hide_banner;
extern __thread int find_stream_info;
extern __thread int filter_nbthreads;
/**
* Register a program-specific cleanup routine.
*/
void register_exit(void (*cb)(int ret));
/**
* Wraps exit with a program-specific cleanup routine.
*/
void exit_program(int ret) av_noreturn;
/**
* Initialize dynamic library loading
*/
void init_dynload(void);
/**
* Initialize the cmdutils option system, in particular
* allocate the *_opts contexts.
*/
void init_opts(void);
/**
* Uninitialize the cmdutils option system, in particular
* free the *_opts contexts and their contents.
*/
void uninit_opts(void);
/**
* Trivial log callback.
* Only suitable for opt_help and similar since it lacks prefix handling.
*/
void log_callback_help(void* ptr, int level, const char* fmt, va_list vl);
/**
* Override the cpuflags.
*/
int opt_cpuflags(void *optctx, const char *opt, const char *arg);
/**
* Fallback for options that are not explicitly handled, these will be
* parsed through AVOptions.
*/
int opt_default(void *optctx, const char *opt, const char *arg);
/**
* Set the libav* libraries log level.
*/
int opt_loglevel(void *optctx, const char *opt, const char *arg);
int opt_report(void *optctx, const char *opt, const char *arg);
int opt_max_alloc(void *optctx, const char *opt, const char *arg);
int opt_codec_debug(void *optctx, const char *opt, const char *arg);
/**
* Limit the execution time.
*/
int opt_timelimit(void *optctx, const char *opt, const char *arg);
/**
* Parse a string and return its corresponding value as a double.
* Exit from the application if the string cannot be correctly
* parsed or the corresponding value is invalid.
*
* @param context the context of the value to be set (e.g. the
* corresponding command line option name)
* @param numstr the string to be parsed
* @param type the type (OPT_INT64 or OPT_FLOAT) as which the
* string should be parsed
* @param min the minimum valid accepted value
* @param max the maximum valid accepted value
*/
double parse_number_or_die(const char *context, const char *numstr, int type,
double min, double max);
/**
* Parse a string specifying a time and return its corresponding
* value as a number of microseconds. Exit from the application if
* the string cannot be correctly parsed.
*
* @param context the context of the value to be set (e.g. the
* corresponding command line option name)
* @param timestr the string to be parsed
* @param is_duration a flag which tells how to interpret timestr, if
* not zero timestr is interpreted as a duration, otherwise as a
* date
*
* @see av_parse_time()
*/
int64_t parse_time_or_die(const char *context, const char *timestr,
int is_duration);
typedef struct SpecifierOpt {
char *specifier; /**< stream/chapter/program/... specifier */
union {
uint8_t *str;
int i;
int64_t i64;
uint64_t ui64;
float f;
double dbl;
} u;
} SpecifierOpt;
typedef struct OptionDef {
const char *name;
int flags;
#define HAS_ARG 0x0001
#define OPT_BOOL 0x0002
#define OPT_EXPERT 0x0004
#define OPT_STRING 0x0008
#define OPT_VIDEO 0x0010
#define OPT_AUDIO 0x0020
#define OPT_INT 0x0080
#define OPT_FLOAT 0x0100
#define OPT_SUBTITLE 0x0200
#define OPT_INT64 0x0400
#define OPT_EXIT 0x0800
#define OPT_DATA 0x1000
#define OPT_PERFILE 0x2000 /* the option is per-file (currently ffmpeg-only).
implied by OPT_OFFSET or OPT_SPEC */
#define OPT_OFFSET 0x4000 /* option is specified as an offset in a passed optctx */
#define OPT_SPEC 0x8000 /* option is to be stored in an array of SpecifierOpt.
Implies OPT_OFFSET. Next element after the offset is
an int containing element count in the array. */
#define OPT_TIME 0x10000
#define OPT_DOUBLE 0x20000
#define OPT_INPUT 0x40000
#define OPT_OUTPUT 0x80000
union {
void *dst_ptr;
int (*func_arg)(void *, const char *, const char *);
size_t off;
} u;
const char *help;
const char *argname;
} OptionDef;
/**
* Print help for all options matching specified flags.
*
* @param options a list of options
* @param msg title of this group. Only printed if at least one option matches.
* @param req_flags print only options which have all those flags set.
* @param rej_flags don't print options which have any of those flags set.
* @param alt_flags print only options that have at least one of those flags set
*/
void show_help_options(const OptionDef *options, const char *msg, int req_flags,
int rej_flags, int alt_flags);
/**
* Show help for all options with given flags in class and all its
* children.
*/
void show_help_children(const AVClass *class, int flags);
/**
* Per-fftool specific help handlers. Implemented in each
* fftool, called by show_help().
*/
void show_help_default_ffmpeg(const char *opt, const char *arg);
void show_help_default_ffprobe(const char *opt, const char *arg);
/**
* Generic -h handler common to all fftools.
*/
int show_help(void *optctx, const char *opt, const char *arg);
/**
* Parse the command line arguments.
*
* @param optctx an opaque options context
* @param argc number of command line arguments
* @param argv values of command line arguments
* @param options Array with the definitions required to interpret every
* option of the form: -option_name [argument]
* @param parse_arg_function Name of the function called to process every
* argument without a leading option name flag. NULL if such arguments do
* not have to be processed.
*/
void parse_options(void *optctx, int argc, char **argv, const OptionDef *options,
void (* parse_arg_function)(void *optctx, const char*));
/**
* Parse one given option.
*
* @return on success 1 if arg was consumed, 0 otherwise; negative number on error
*/
int parse_option(void *optctx, const char *opt, const char *arg,
const OptionDef *options);
/**
* An option extracted from the commandline.
* Cannot use AVDictionary because of options like -map which can be
* used multiple times.
*/
typedef struct Option {
const OptionDef *opt;
const char *key;
const char *val;
} Option;
typedef struct OptionGroupDef {
/**< group name */
const char *name;
/**
* Option to be used as group separator. Can be NULL for groups which
* are terminated by a non-option argument (e.g. ffmpeg output files)
*/
const char *sep;
/**
* Option flags that must be set on each option that is
* applied to this group
*/
int flags;
} OptionGroupDef;
typedef struct OptionGroup {
const OptionGroupDef *group_def;
const char *arg;
Option *opts;
int nb_opts;
AVDictionary *codec_opts;
AVDictionary *format_opts;
AVDictionary *resample_opts;
AVDictionary *sws_dict;
AVDictionary *swr_opts;
} OptionGroup;
/**
* A list of option groups that all have the same group type
* (e.g. input files or output files)
*/
typedef struct OptionGroupList {
const OptionGroupDef *group_def;
OptionGroup *groups;
int nb_groups;
} OptionGroupList;
typedef struct OptionParseContext {
OptionGroup global_opts;
OptionGroupList *groups;
int nb_groups;
/* parsing state */
OptionGroup cur_group;
} OptionParseContext;
/**
* Parse an options group and write results into optctx.
*
* @param optctx an app-specific options context. NULL for global options group
*/
int parse_optgroup(void *optctx, OptionGroup *g);
/**
* Split the commandline into an intermediate form convenient for further
* processing.
*
* The commandline is assumed to be composed of options which either belong to a
* group (those with OPT_SPEC, OPT_OFFSET or OPT_PERFILE) or are global
* (everything else).
*
* A group (defined by an OptionGroupDef struct) is a sequence of options
* terminated by either a group separator option (e.g. -i) or a parameter that
* is not an option (doesn't start with -). A group without a separator option
* must always be first in the supplied groups list.
*
* All options within the same group are stored in one OptionGroup struct in an
* OptionGroupList, all groups with the same group definition are stored in one
* OptionGroupList in OptionParseContext.groups. The order of group lists is the
* same as the order of group definitions.
*/
int split_commandline(OptionParseContext *octx, int argc, char *argv[],
const OptionDef *options,
const OptionGroupDef *groups, int nb_groups);
/**
* Free all allocated memory in an OptionParseContext.
*/
void uninit_parse_context(OptionParseContext *octx);
/**
* Find the '-loglevel' option in the command line args and apply it.
*/
void parse_loglevel(int argc, char **argv, const OptionDef *options);
/**
* Return index of option opt in argv or 0 if not found.
*/
int locate_option(int argc, char **argv, const OptionDef *options,
const char *optname);
/**
* Check if the given stream matches a stream specifier.
*
* @param s Corresponding format context.
* @param st Stream from s to be checked.
* @param spec A stream specifier of the [v|a|s|d]:[\<stream index\>] form.
*
* @return 1 if the stream matches, 0 if it doesn't, <0 on error
*/
int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec);
/**
* Filter out options for given codec.
*
* Create a new options dictionary containing only the options from
* opts which apply to the codec with ID codec_id.
*
* @param opts dictionary to place options in
* @param codec_id ID of the codec that should be filtered for
* @param s Corresponding format context.
* @param st A stream from s for which the options should be filtered.
* @param codec The particular codec for which the options should be filtered.
* If null, the default one is looked up according to the codec id.
* @return a pointer to the created dictionary
*/
AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
AVFormatContext *s, AVStream *st, AVCodec *codec);
/**
* Setup AVCodecContext options for avformat_find_stream_info().
*
* Create an array of dictionaries, one dictionary for each stream
* contained in s.
* Each dictionary will contain the options from codec_opts which can
* be applied to the corresponding stream codec context.
*
* @return pointer to the created array of dictionaries, NULL if it
* cannot be created
*/
AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
AVDictionary *codec_opts);
/**
* Print an error message to stderr, indicating filename and a human
* readable description of the error code err.
*
* If strerror_r() is not available the use of this function in a
* multithreaded application may be unsafe.
*
* @see av_strerror()
*/
void print_error(const char *filename, int err);
/**
* Print the program banner to stderr. The banner contents depend on the
* current version of the repository and of the libav* libraries used by
* the program.
*/
void show_banner(int argc, char **argv, const OptionDef *options);
/**
* Print the version of the program to stdout. The version message
* depends on the current versions of the repository and of the libav*
* libraries.
* This option processing function does not utilize the arguments.
*/
int show_version(void *optctx, const char *opt, const char *arg);
/**
* Print the build configuration of the program to stdout. The contents
* depend on the definition of FFMPEG_CONFIGURATION.
* This option processing function does not utilize the arguments.
*/
int show_buildconf(void *optctx, const char *opt, const char *arg);
/**
* Print the license of the program to stdout. The license depends on
* the license of the libraries compiled into the program.
* This option processing function does not utilize the arguments.
*/
int show_license(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the formats supported by the
* program (including devices).
* This option processing function does not utilize the arguments.
*/
int show_formats(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the muxers supported by the
* program (including devices).
* This option processing function does not utilize the arguments.
*/
int show_muxers(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the demuxer supported by the
* program (including devices).
* This option processing function does not utilize the arguments.
*/
int show_demuxers(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the devices supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_devices(void *optctx, const char *opt, const char *arg);
#if CONFIG_AVDEVICE
/**
* Print a listing containing autodetected sinks of the output device.
* Device name with options may be passed as an argument to limit results.
*/
int show_sinks(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing autodetected sources of the input device.
* Device name with options may be passed as an argument to limit results.
*/
int show_sources(void *optctx, const char *opt, const char *arg);
#endif
/**
* Print a listing containing all the codecs supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_codecs(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the decoders supported by the
* program.
*/
int show_decoders(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the encoders supported by the
* program.
*/
int show_encoders(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the filters supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_filters(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the bit stream filters supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_bsfs(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the protocols supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_protocols(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the pixel formats supported by the
* program.
* This option processing function does not utilize the arguments.
*/
int show_pix_fmts(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the standard channel layouts supported by
* the program.
* This option processing function does not utilize the arguments.
*/
int show_layouts(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the sample formats supported by the
* program.
*/
int show_sample_fmts(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the color names and values recognized
* by the program.
*/
int show_colors(void *optctx, const char *opt, const char *arg);
/**
* Return a positive value if a line read from standard input
* starts with [yY], otherwise return 0.
*/
int read_yesno(void);
/**
* Get a file corresponding to a preset file.
*
* If is_path is non-zero, look for the file in the path preset_name.
* Otherwise search for a file named arg.ffpreset in the directories
* $FFMPEG_DATADIR (if set), $HOME/.ffmpeg, and in the datadir defined
* at configuration time or in a "ffpresets" folder along the executable
* on win32, in that order. If no such file is found and
* codec_name is defined, then search for a file named
* codec_name-preset_name.avpreset in the above-mentioned directories.
*
* @param filename buffer where the name of the found filename is written
* @param filename_size size in bytes of the filename buffer
* @param preset_name name of the preset to search
* @param is_path tell if preset_name is a filename path
* @param codec_name name of the codec for which to look for the
* preset, may be NULL
*/
FILE *get_preset_file(char *filename, size_t filename_size,
const char *preset_name, int is_path, const char *codec_name);
/**
* Realloc array to hold new_size elements of elem_size.
* Calls exit() on failure.
*
* @param array array to reallocate
* @param elem_size size in bytes of each element
* @param size new element count will be written here
* @param new_size number of elements to place in reallocated array
* @return reallocated array
*/
void *grow_array(void *array, int elem_size, int *size, int new_size);
#define media_type_string av_get_media_type_string
#define GROW_ARRAY(array, nb_elems)\
array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1)
#define GET_PIX_FMT_NAME(pix_fmt)\
const char *name = av_get_pix_fmt_name(pix_fmt);
#define GET_CODEC_NAME(id)\
const char *name = avcodec_descriptor_get(id)->name;
#define GET_SAMPLE_FMT_NAME(sample_fmt)\
const char *name = av_get_sample_fmt_name(sample_fmt)
#define GET_SAMPLE_RATE_NAME(rate)\
char name[16];\
snprintf(name, sizeof(name), "%d", rate);
#define GET_CH_LAYOUT_NAME(ch_layout)\
char name[16];\
snprintf(name, sizeof(name), "0x%"PRIx64, ch_layout);
#define GET_CH_LAYOUT_DESC(ch_layout)\
char name[128];\
av_get_channel_layout_string(name, sizeof(name), 0, ch_layout);
double get_rotation(AVStream *st);
#endif /* FFTOOLS_CMDUTILS_H */
File diff suppressed because it is too large Load Diff
+760
View File
@@ -0,0 +1,760 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* CHANGES 01.2020
* - ffprobe support changes
*
* CHANGES 12.2019
* - Concurrent execution support
*
* CHANGES 03.2019
* --------------------------------------------------------
* - config.h include removed
*
* CHANGES 08.2018
* --------------------------------------------------------
* - fftools_ prefix added to file name and include guards
* - set_report_callback() method declared
* - cancel_operation() method declared
*
* CHANGES 07.2018
* --------------------------------------------------------
* - Include guards renamed
*/
#ifndef FFTOOLS_FFMPEG_H
#define FFTOOLS_FFMPEG_H
#include <stdint.h>
#include <stdio.h>
#include <signal.h>
#include "fftools_cmdutils.h"
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavutil/avutil.h"
#include "libavutil/dict.h"
#include "libavutil/eval.h"
#include "libavutil/fifo.h"
#include "libavutil/hwcontext.h"
#include "libavutil/pixfmt.h"
#include "libavutil/rational.h"
#include "libavutil/thread.h"
#include "libavutil/threadmessage.h"
#include "libswresample/swresample.h"
#define VSYNC_AUTO -1
#define VSYNC_PASSTHROUGH 0
#define VSYNC_CFR 1
#define VSYNC_VFR 2
#define VSYNC_VSCFR 0xfe
#define VSYNC_DROP 0xff
#define MAX_STREAMS 1024 /* arbitrary sanity check value */
enum HWAccelID {
HWACCEL_NONE = 0,
HWACCEL_AUTO,
HWACCEL_GENERIC,
HWACCEL_VIDEOTOOLBOX,
HWACCEL_QSV,
HWACCEL_CUVID,
};
typedef struct HWAccel {
const char *name;
int (*init)(AVCodecContext *s);
enum HWAccelID id;
enum AVPixelFormat pix_fmt;
} HWAccel;
typedef struct HWDevice {
const char *name;
enum AVHWDeviceType type;
AVBufferRef *device_ref;
} HWDevice;
/* select an input stream for an output stream */
typedef struct StreamMap {
int disabled; /* 1 is this mapping is disabled by a negative map */
int file_index;
int stream_index;
int sync_file_index;
int sync_stream_index;
char *linklabel; /* name of an output link, for mapping lavfi outputs */
} StreamMap;
typedef struct {
int file_idx, stream_idx, channel_idx; // input
int ofile_idx, ostream_idx; // output
} AudioChannelMap;
typedef struct OptionsContext {
OptionGroup *g;
/* input/output options */
int64_t start_time;
int64_t start_time_eof;
int seek_timestamp;
const char *format;
SpecifierOpt *codec_names;
int nb_codec_names;
SpecifierOpt *audio_channels;
int nb_audio_channels;
SpecifierOpt *audio_sample_rate;
int nb_audio_sample_rate;
SpecifierOpt *frame_rates;
int nb_frame_rates;
SpecifierOpt *frame_sizes;
int nb_frame_sizes;
SpecifierOpt *frame_pix_fmts;
int nb_frame_pix_fmts;
/* input options */
int64_t input_ts_offset;
int loop;
int rate_emu;
int accurate_seek;
int thread_queue_size;
SpecifierOpt *ts_scale;
int nb_ts_scale;
SpecifierOpt *dump_attachment;
int nb_dump_attachment;
SpecifierOpt *hwaccels;
int nb_hwaccels;
SpecifierOpt *hwaccel_devices;
int nb_hwaccel_devices;
SpecifierOpt *hwaccel_output_formats;
int nb_hwaccel_output_formats;
SpecifierOpt *autorotate;
int nb_autorotate;
/* output options */
StreamMap *stream_maps;
int nb_stream_maps;
AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */
int nb_audio_channel_maps; /* number of (valid) -map_channel settings */
int metadata_global_manual;
int metadata_streams_manual;
int metadata_chapters_manual;
const char **attachments;
int nb_attachments;
int chapters_input_file;
int64_t recording_time;
int64_t stop_time;
uint64_t limit_filesize;
float mux_preload;
float mux_max_delay;
int shortest;
int bitexact;
int video_disable;
int audio_disable;
int subtitle_disable;
int data_disable;
/* indexed by output file stream index */
int *streamid_map;
int nb_streamid_map;
SpecifierOpt *metadata;
int nb_metadata;
SpecifierOpt *max_frames;
int nb_max_frames;
SpecifierOpt *bitstream_filters;
int nb_bitstream_filters;
SpecifierOpt *codec_tags;
int nb_codec_tags;
SpecifierOpt *sample_fmts;
int nb_sample_fmts;
SpecifierOpt *qscale;
int nb_qscale;
SpecifierOpt *forced_key_frames;
int nb_forced_key_frames;
SpecifierOpt *force_fps;
int nb_force_fps;
SpecifierOpt *frame_aspect_ratios;
int nb_frame_aspect_ratios;
SpecifierOpt *rc_overrides;
int nb_rc_overrides;
SpecifierOpt *intra_matrices;
int nb_intra_matrices;
SpecifierOpt *inter_matrices;
int nb_inter_matrices;
SpecifierOpt *chroma_intra_matrices;
int nb_chroma_intra_matrices;
SpecifierOpt *top_field_first;
int nb_top_field_first;
SpecifierOpt *metadata_map;
int nb_metadata_map;
SpecifierOpt *presets;
int nb_presets;
SpecifierOpt *copy_initial_nonkeyframes;
int nb_copy_initial_nonkeyframes;
SpecifierOpt *copy_prior_start;
int nb_copy_prior_start;
SpecifierOpt *filters;
int nb_filters;
SpecifierOpt *filter_scripts;
int nb_filter_scripts;
SpecifierOpt *reinit_filters;
int nb_reinit_filters;
SpecifierOpt *fix_sub_duration;
int nb_fix_sub_duration;
SpecifierOpt *canvas_sizes;
int nb_canvas_sizes;
SpecifierOpt *pass;
int nb_pass;
SpecifierOpt *passlogfiles;
int nb_passlogfiles;
SpecifierOpt *max_muxing_queue_size;
int nb_max_muxing_queue_size;
SpecifierOpt *guess_layout_max;
int nb_guess_layout_max;
SpecifierOpt *apad;
int nb_apad;
SpecifierOpt *discard;
int nb_discard;
SpecifierOpt *disposition;
int nb_disposition;
SpecifierOpt *program;
int nb_program;
SpecifierOpt *time_bases;
int nb_time_bases;
SpecifierOpt *enc_time_bases;
int nb_enc_time_bases;
} OptionsContext;
typedef struct InputFilter {
AVFilterContext *filter;
struct InputStream *ist;
struct FilterGraph *graph;
uint8_t *name;
enum AVMediaType type; // AVMEDIA_TYPE_SUBTITLE for sub2video
AVFifoBuffer *frame_queue;
// parameters configured for this input
int format;
int width, height;
AVRational sample_aspect_ratio;
int sample_rate;
int channels;
uint64_t channel_layout;
AVBufferRef *hw_frames_ctx;
int eof;
} InputFilter;
typedef struct OutputFilter {
AVFilterContext *filter;
struct OutputStream *ost;
struct FilterGraph *graph;
uint8_t *name;
/* temporary storage until stream maps are processed */
AVFilterInOut *out_tmp;
enum AVMediaType type;
/* desired output stream properties */
int width, height;
AVRational frame_rate;
int format;
int sample_rate;
uint64_t channel_layout;
// those are only set if no format is specified and the encoder gives us multiple options
int *formats;
uint64_t *channel_layouts;
int *sample_rates;
} OutputFilter;
typedef struct FilterGraph {
int index;
const char *graph_desc;
AVFilterGraph *graph;
int reconfiguration;
InputFilter **inputs;
int nb_inputs;
OutputFilter **outputs;
int nb_outputs;
} FilterGraph;
typedef struct InputStream {
int file_index;
AVStream *st;
int discard; /* true if stream data should be discarded */
int user_set_discard;
int decoding_needed; /* non zero if the packets must be decoded in 'raw_fifo', see DECODING_FOR_* */
#define DECODING_FOR_OST 1
#define DECODING_FOR_FILTER 2
AVCodecContext *dec_ctx;
AVCodec *dec;
AVFrame *decoded_frame;
AVFrame *filter_frame; /* a ref of decoded_frame, to be sent to filters */
int64_t start; /* time when read started */
/* predicted dts of the next packet read for this stream or (when there are
* several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
int64_t next_dts;
int64_t dts; ///< dts of the last packet read for this stream (in AV_TIME_BASE units)
int64_t next_pts; ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)
int64_t pts; ///< current pts of the decoded frame (in AV_TIME_BASE units)
int wrap_correction_done;
int64_t filter_in_rescale_delta_last;
int64_t min_pts; /* pts with the smallest value in a current stream */
int64_t max_pts; /* pts with the higher value in a current stream */
// when forcing constant input framerate through -r,
// this contains the pts that will be given to the next decoded frame
int64_t cfr_next_pts;
int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */
double ts_scale;
int saw_first_ts;
AVDictionary *decoder_opts;
AVRational framerate; /* framerate forced with -r */
int top_field_first;
int guess_layout_max;
int autorotate;
int fix_sub_duration;
struct { /* previous decoded subtitle and related variables */
int got_output;
int ret;
AVSubtitle subtitle;
} prev_sub;
struct sub2video {
int64_t last_pts;
int64_t end_pts;
AVFifoBuffer *sub_queue; ///< queue of AVSubtitle* before filter init
AVFrame *frame;
int w, h;
} sub2video;
int dr1;
/* decoded data from this stream goes into all those filters
* currently video and audio only */
InputFilter **filters;
int nb_filters;
int reinit_filters;
/* hwaccel options */
enum HWAccelID hwaccel_id;
enum AVHWDeviceType hwaccel_device_type;
char *hwaccel_device;
enum AVPixelFormat hwaccel_output_format;
/* hwaccel context */
void *hwaccel_ctx;
void (*hwaccel_uninit)(AVCodecContext *s);
int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags);
int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame);
enum AVPixelFormat hwaccel_pix_fmt;
enum AVPixelFormat hwaccel_retrieved_pix_fmt;
AVBufferRef *hw_frames_ctx;
/* stats */
// combined size of all the packets read
uint64_t data_size;
/* number of packets successfully read for this stream */
uint64_t nb_packets;
// number of frames/samples retrieved from the decoder
uint64_t frames_decoded;
uint64_t samples_decoded;
int64_t *dts_buffer;
int nb_dts_buffer;
int got_output;
} InputStream;
typedef struct InputFile {
AVFormatContext *ctx;
int eof_reached; /* true if eof reached */
int eagain; /* true if last read attempt returned EAGAIN */
int ist_index; /* index of first stream in input_streams */
int loop; /* set number of times input stream should be looped */
int64_t duration; /* actual duration of the longest stream in a file
at the moment when looping happens */
AVRational time_base; /* time base of the duration */
int64_t input_ts_offset;
int64_t ts_offset;
int64_t last_ts;
int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
int seek_timestamp;
int64_t recording_time;
int nb_streams; /* number of stream that ffmpeg is aware of; may be different
from ctx.nb_streams if new streams appear during av_read_frame() */
int nb_streams_warn; /* number of streams that the user was warned of */
int rate_emu;
int accurate_seek;
#if HAVE_THREADS
AVThreadMessageQueue *in_thread_queue;
pthread_t thread; /* thread reading from this file */
int non_blocking; /* reading packets from the thread should not block */
int joined; /* the thread has been joined */
int thread_queue_size; /* maximum number of queued packets */
#endif
} InputFile;
enum forced_keyframes_const {
FKF_N,
FKF_N_FORCED,
FKF_PREV_FORCED_N,
FKF_PREV_FORCED_T,
FKF_T,
FKF_NB
};
#define ABORT_ON_FLAG_EMPTY_OUTPUT (1 << 0)
extern const char *const forced_keyframes_const_names[];
typedef enum {
ENCODER_FINISHED = 1,
MUXER_FINISHED = 2,
} OSTFinished ;
typedef struct OutputStream {
int file_index; /* file index */
int index; /* stream index in the output file */
int source_index; /* InputStream index */
AVStream *st; /* stream in the output file */
int encoding_needed; /* true if encoding needed for this stream */
int frame_number;
/* input pts and corresponding output pts
for A/V sync */
struct InputStream *sync_ist; /* input stream to sync against */
int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number
/* pts of the first frame encoded for this stream, used for limiting
* recording time */
int64_t first_pts;
/* dts of the last packet sent to the muxer */
int64_t last_mux_dts;
// the timebase of the packets sent to the muxer
AVRational mux_timebase;
AVRational enc_timebase;
int nb_bitstream_filters;
AVBSFContext **bsf_ctx;
AVCodecContext *enc_ctx;
AVCodecParameters *ref_par; /* associated input codec parameters with encoders options applied */
AVCodec *enc;
int64_t max_frames;
AVFrame *filtered_frame;
AVFrame *last_frame;
int last_dropped;
int last_nb0_frames[3];
void *hwaccel_ctx;
/* video only */
AVRational frame_rate;
int is_cfr;
int force_fps;
int top_field_first;
int rotate_overridden;
double rotate_override_value;
AVRational frame_aspect_ratio;
/* forced key frames */
int64_t forced_kf_ref_pts;
int64_t *forced_kf_pts;
int forced_kf_count;
int forced_kf_index;
char *forced_keyframes;
AVExpr *forced_keyframes_pexpr;
double forced_keyframes_expr_const_values[FKF_NB];
/* audio only */
int *audio_channels_map; /* list of the channels id to pick from the source stream */
int audio_channels_mapped; /* number of channels in audio_channels_map */
char *logfile_prefix;
FILE *logfile;
OutputFilter *filter;
char *avfilter;
char *filters; ///< filtergraph associated to the -filter option
char *filters_script; ///< filtergraph script associated to the -filter_script option
AVDictionary *encoder_opts;
AVDictionary *sws_dict;
AVDictionary *swr_opts;
AVDictionary *resample_opts;
char *apad;
OSTFinished finished; /* no more packets should be written for this stream */
int unavailable; /* true if the steram is unavailable (possibly temporarily) */
int stream_copy;
// init_output_stream() has been called for this stream
// The encoder and the bitstream filters have been initialized and the stream
// parameters are set in the AVStream.
int initialized;
int inputs_done;
const char *attachment_filename;
int copy_initial_nonkeyframes;
int copy_prior_start;
char *disposition;
int keep_pix_fmt;
/* stats */
// combined size of all the packets written
uint64_t data_size;
// number of packets send to the muxer
uint64_t packets_written;
// number of frames/samples sent to the encoder
uint64_t frames_encoded;
uint64_t samples_encoded;
/* packet quality factor */
int quality;
int max_muxing_queue_size;
/* the packets are buffered here until the muxer is ready to be initialized */
AVFifoBuffer *muxing_queue;
/* packet picture type */
int pict_type;
/* frame encode sum of squared error values */
int64_t error[4];
} OutputStream;
typedef struct OutputFile {
AVFormatContext *ctx;
AVDictionary *opts;
int ost_index; /* index of the first stream in output_streams */
int64_t recording_time; ///< desired length of the resulting file in microseconds == AV_TIME_BASE units
int64_t start_time; ///< start time in microseconds == AV_TIME_BASE units
uint64_t limit_filesize; /* filesize limit expressed in bytes */
int shortest;
int header_written;
} OutputFile;
extern __thread InputStream **input_streams;
extern __thread int nb_input_streams;
extern __thread InputFile **input_files;
extern __thread int nb_input_files;
extern __thread OutputStream **output_streams;
extern __thread int nb_output_streams;
extern __thread OutputFile **output_files;
extern __thread int nb_output_files;
extern __thread FilterGraph **filtergraphs;
extern __thread int nb_filtergraphs;
extern __thread char *vstats_filename;
extern __thread char *sdp_filename;
extern __thread float audio_drift_threshold;
extern __thread float dts_delta_threshold;
extern __thread float dts_error_threshold;
extern __thread int audio_volume;
extern __thread int audio_sync_method;
extern __thread int video_sync_method;
extern __thread float frame_drop_threshold;
extern __thread int do_benchmark;
extern __thread int do_benchmark_all;
extern __thread int do_deinterlace;
extern __thread int do_hex_dump;
extern __thread int do_pkt_dump;
extern __thread int copy_ts;
extern __thread int start_at_zero;
extern __thread int copy_tb;
extern __thread int debug_ts;
extern __thread int exit_on_error;
extern __thread int abort_on_flags;
extern __thread int print_stats;
extern __thread int qp_hist;
extern __thread int stdin_interaction;
extern __thread int frame_bits_per_raw_sample;
extern __thread AVIOContext *progress_avio;
extern __thread float max_error_rate;
extern __thread char *videotoolbox_pixfmt;
extern __thread int filter_complex_nbthreads;
extern __thread int vstats_version;
extern __thread const AVIOInterruptCB int_cb;
extern const HWAccel hwaccels[];
extern __thread AVBufferRef *hw_device_ctx;
#if CONFIG_QSV
extern __thread char *qsv_device;
#endif
extern __thread HWDevice *filter_hw_device;
void term_init(void);
void term_exit(void);
void reset_options(OptionsContext *o, int is_input);
void show_usage(void);
void opt_output_file(void *optctx, const char *filename);
void remove_avoptions(AVDictionary **a, AVDictionary *b);
void assert_avoptions(AVDictionary *m);
int guess_input_channel_layout(InputStream *ist);
enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *avctx, AVCodec *codec, enum AVPixelFormat target);
void choose_sample_fmt(AVStream *st, AVCodec *codec);
int configure_filtergraph(FilterGraph *fg);
int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out);
void check_filter_outputs(void);
int ist_in_filtergraph(FilterGraph *fg, InputStream *ist);
int filtergraph_is_simple(FilterGraph *fg);
int init_simple_filtergraph(InputStream *ist, OutputStream *ost);
int init_complex_filtergraph(FilterGraph *fg);
void sub2video_update(InputStream *ist, AVSubtitle *sub);
int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame);
int ffmpeg_parse_options(int argc, char **argv);
int videotoolbox_init(AVCodecContext *s);
int qsv_init(AVCodecContext *s);
int cuvid_init(AVCodecContext *s);
HWDevice *hw_device_get_by_name(const char *name);
int hw_device_init_from_string(const char *arg, HWDevice **dev);
void hw_device_free_all(void);
int hw_device_setup_for_decode(InputStream *ist);
int hw_device_setup_for_encode(OutputStream *ost);
int hwaccel_decode_init(AVCodecContext *avctx);
void set_report_callback(void (*callback)(int, float, float, int64_t, int, double, double));
void cancel_operation();
int opt_map(void *optctx, const char *opt, const char *arg);
int opt_map_channel(void *optctx, const char *opt, const char *arg);
int opt_recording_timestamp(void *optctx, const char *opt, const char *arg);
int opt_data_frames(void *optctx, const char *opt, const char *arg);
int opt_progress(void *optctx, const char *opt, const char *arg);
int opt_target(void *optctx, const char *opt, const char *arg);
int opt_vsync(void *optctx, const char *opt, const char *arg);
int opt_abort_on(void *optctx, const char *opt, const char *arg);
int opt_qscale(void *optctx, const char *opt, const char *arg);
int opt_profile(void *optctx, const char *opt, const char *arg);
int opt_filter_complex(void *optctx, const char *opt, const char *arg);
int opt_filter_complex_script(void *optctx, const char *opt, const char *arg);
int opt_attach(void *optctx, const char *opt, const char *arg);
int opt_video_frames(void *optctx, const char *opt, const char *arg);
int opt_video_codec(void *optctx, const char *opt, const char *arg);
int opt_sameq(void *optctx, const char *opt, const char *arg);
int opt_timecode(void *optctx, const char *opt, const char *arg);
int opt_vstats_file(void *optctx, const char *opt, const char *arg);
int opt_vstats(void *optctx, const char *opt, const char *arg);
int opt_video_frames(void *optctx, const char *opt, const char *arg);
int opt_old2new(void *optctx, const char *opt, const char *arg);
int opt_streamid(void *optctx, const char *opt, const char *arg);
int opt_bitrate(void *optctx, const char *opt, const char *arg);
int show_hwaccels(void *optctx, const char *opt, const char *arg);
int opt_video_filters(void *optctx, const char *opt, const char *arg);
int opt_audio_frames(void *optctx, const char *opt, const char *arg);
int opt_audio_qscale(void *optctx, const char *opt, const char *arg);
int opt_audio_codec(void *optctx, const char *opt, const char *arg);
int opt_channel_layout(void *optctx, const char *opt, const char *arg);
int opt_preset(void *optctx, const char *opt, const char *arg);
int opt_audio_filters(void *optctx, const char *opt, const char *arg);
int opt_subtitle_codec(void *optctx, const char *opt, const char *arg);
int opt_video_channel(void *optctx, const char *opt, const char *arg);
int opt_video_standard(void *optctx, const char *opt, const char *arg);
int opt_sdp_file(void *optctx, const char *opt, const char *arg);
int opt_data_codec(void *optctx, const char *opt, const char *arg);
int opt_init_hw_device(void *optctx, const char *opt, const char *arg);
int opt_filter_hw_device(void *optctx, const char *opt, const char *arg);
void add_input_streams(OptionsContext *o, AVFormatContext *ic);
void assert_file_overwrite(const char *filename);
void dump_attachment(AVStream *st, const char *filename);
uint8_t *get_line(AVIOContext *s);
void uninit_options(OptionsContext *o);
void init_options(OptionsContext *o);
AVDictionary *strip_specifiers(AVDictionary *dict);
void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec);
int fftools_copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o);
AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder);
AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st);
int open_input_file(OptionsContext *o, const char *filename);
int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s);
int choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost);
OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index);
void parse_matrix_coeffs(uint16_t *dest, const char *str);
uint8_t *fftools_read_file(const char *filename);
char *get_ost_filters(OptionsContext *o, AVFormatContext *oc, OutputStream *ost);
void check_streamcopy_filters(OptionsContext *o, AVFormatContext *oc, const OutputStream *ost, enum AVMediaType type);
OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
OutputStream *new_unknown_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc, int source_index);
int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata);
void init_output_filter(OutputFilter *ofilter, OptionsContext *o, AVFormatContext *oc);
int init_complex_filters(void);
int open_output_file(OptionsContext *o, const char *filename);
int opt_default_new(OptionsContext *o, const char *opt, const char *arg);
int open_files(OptionGroupList *l, const char *inout, int (*open_file)(OptionsContext*, const char*));
#endif /* FFTOOLS_FFMPEG_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,491 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* CHANGES 12.2019
* - Concurrent execution support
*
* CHANGES 08.2018
* --------------------------------------------------------
* - fftools_ prefix added to file name and parent header
*/
#include <string.h>
#include "libavutil/avstring.h"
#include "fftools_ffmpeg.h"
__thread int nb_hw_devices;
__thread HWDevice **hw_devices;
static HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)
{
HWDevice *found = NULL;
int i;
for (i = 0; i < nb_hw_devices; i++) {
if (hw_devices[i]->type == type) {
if (found)
return NULL;
found = hw_devices[i];
}
}
return found;
}
HWDevice *hw_device_get_by_name(const char *name)
{
int i;
for (i = 0; i < nb_hw_devices; i++) {
if (!strcmp(hw_devices[i]->name, name))
return hw_devices[i];
}
return NULL;
}
static HWDevice *hw_device_add(void)
{
int err;
err = av_reallocp_array(&hw_devices, nb_hw_devices + 1,
sizeof(*hw_devices));
if (err) {
nb_hw_devices = 0;
return NULL;
}
hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice));
if (!hw_devices[nb_hw_devices])
return NULL;
return hw_devices[nb_hw_devices++];
}
static char *hw_device_default_name(enum AVHWDeviceType type)
{
// Make an automatic name of the form "type%d". We arbitrarily
// limit at 1000 anonymous devices of the same type - there is
// probably something else very wrong if you get to this limit.
const char *type_name = av_hwdevice_get_type_name(type);
char *name;
size_t index_pos;
int index, index_limit = 1000;
index_pos = strlen(type_name);
name = av_malloc(index_pos + 4);
if (!name)
return NULL;
for (index = 0; index < index_limit; index++) {
snprintf(name, index_pos + 4, "%s%d", type_name, index);
if (!hw_device_get_by_name(name))
break;
}
if (index >= index_limit) {
av_freep(&name);
return NULL;
}
return name;
}
int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
{
// "type=name:device,key=value,key2=value2"
// "type:device,key=value,key2=value2"
// -> av_hwdevice_ctx_create()
// "type=name@name"
// "type@name"
// -> av_hwdevice_ctx_create_derived()
AVDictionary *options = NULL;
const char *type_name = NULL, *name = NULL, *device = NULL;
enum AVHWDeviceType type;
HWDevice *dev, *src;
AVBufferRef *device_ref = NULL;
int err;
const char *errmsg, *p, *q;
size_t k;
k = strcspn(arg, ":=@");
p = arg + k;
type_name = av_strndup(arg, k);
if (!type_name) {
err = AVERROR(ENOMEM);
goto fail;
}
type = av_hwdevice_find_type_by_name(type_name);
if (type == AV_HWDEVICE_TYPE_NONE) {
errmsg = "unknown device type";
goto invalid;
}
if (*p == '=') {
k = strcspn(p + 1, ":@");
name = av_strndup(p + 1, k);
if (!name) {
err = AVERROR(ENOMEM);
goto fail;
}
if (hw_device_get_by_name(name)) {
errmsg = "named device already exists";
goto invalid;
}
p += 1 + k;
} else {
name = hw_device_default_name(type);
if (!name) {
err = AVERROR(ENOMEM);
goto fail;
}
}
if (!*p) {
// New device with no parameters.
err = av_hwdevice_ctx_create(&device_ref, type,
NULL, NULL, 0);
if (err < 0)
goto fail;
} else if (*p == ':') {
// New device with some parameters.
++p;
q = strchr(p, ',');
if (q) {
if (q - p > 0) {
device = av_strndup(p, q - p);
if (!device) {
err = AVERROR(ENOMEM);
goto fail;
}
}
err = av_dict_parse_string(&options, q + 1, "=", ",", 0);
if (err < 0) {
errmsg = "failed to parse options";
goto invalid;
}
}
err = av_hwdevice_ctx_create(&device_ref, type,
q ? device : p[0] ? p : NULL,
options, 0);
if (err < 0)
goto fail;
} else if (*p == '@') {
// Derive from existing device.
src = hw_device_get_by_name(p + 1);
if (!src) {
errmsg = "invalid source device name";
goto invalid;
}
err = av_hwdevice_ctx_create_derived(&device_ref, type,
src->device_ref, 0);
if (err < 0)
goto fail;
} else {
errmsg = "parse error";
goto invalid;
}
dev = hw_device_add();
if (!dev) {
err = AVERROR(ENOMEM);
goto fail;
}
dev->name = name;
dev->type = type;
dev->device_ref = device_ref;
if (dev_out)
*dev_out = dev;
name = NULL;
err = 0;
done:
av_freep(&type_name);
av_freep(&name);
av_freep(&device);
av_dict_free(&options);
return err;
invalid:
av_log(NULL, AV_LOG_ERROR,
"Invalid device specification \"%s\": %s\n", arg, errmsg);
err = AVERROR(EINVAL);
goto done;
fail:
av_log(NULL, AV_LOG_ERROR,
"Device creation failed: %d.\n", err);
av_buffer_unref(&device_ref);
goto done;
}
static int hw_device_init_from_type(enum AVHWDeviceType type,
const char *device,
HWDevice **dev_out)
{
AVBufferRef *device_ref = NULL;
HWDevice *dev;
char *name;
int err;
name = hw_device_default_name(type);
if (!name) {
err = AVERROR(ENOMEM);
goto fail;
}
err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
if (err < 0) {
av_log(NULL, AV_LOG_ERROR,
"Device creation failed: %d.\n", err);
goto fail;
}
dev = hw_device_add();
if (!dev) {
err = AVERROR(ENOMEM);
goto fail;
}
dev->name = name;
dev->type = type;
dev->device_ref = device_ref;
if (dev_out)
*dev_out = dev;
return 0;
fail:
av_freep(&name);
av_buffer_unref(&device_ref);
return err;
}
void hw_device_free_all(void)
{
int i;
for (i = 0; i < nb_hw_devices; i++) {
av_freep(&hw_devices[i]->name);
av_buffer_unref(&hw_devices[i]->device_ref);
av_freep(&hw_devices[i]);
}
av_freep(&hw_devices);
nb_hw_devices = 0;
}
static HWDevice *hw_device_match_by_codec(const AVCodec *codec)
{
const AVCodecHWConfig *config;
HWDevice *dev;
int i;
for (i = 0;; i++) {
config = avcodec_get_hw_config(codec, i);
if (!config)
return NULL;
if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
continue;
dev = hw_device_get_by_type(config->device_type);
if (dev)
return dev;
}
}
int hw_device_setup_for_decode(InputStream *ist)
{
const AVCodecHWConfig *config;
enum AVHWDeviceType type;
HWDevice *dev = NULL;
int err, auto_device = 0;
if (ist->hwaccel_device) {
dev = hw_device_get_by_name(ist->hwaccel_device);
if (!dev) {
if (ist->hwaccel_id == HWACCEL_AUTO) {
auto_device = 1;
} else if (ist->hwaccel_id == HWACCEL_GENERIC) {
type = ist->hwaccel_device_type;
err = hw_device_init_from_type(type, ist->hwaccel_device,
&dev);
} else {
// This will be dealt with by API-specific initialisation
// (using hwaccel_device), so nothing further needed here.
return 0;
}
} else {
if (ist->hwaccel_id == HWACCEL_AUTO) {
ist->hwaccel_device_type = dev->type;
} else if (ist->hwaccel_device_type != dev->type) {
av_log(ist->dec_ctx, AV_LOG_ERROR, "Invalid hwaccel device "
"specified for decoder: device %s of type %s is not "
"usable with hwaccel %s.\n", dev->name,
av_hwdevice_get_type_name(dev->type),
av_hwdevice_get_type_name(ist->hwaccel_device_type));
return AVERROR(EINVAL);
}
}
} else {
if (ist->hwaccel_id == HWACCEL_AUTO) {
auto_device = 1;
} else if (ist->hwaccel_id == HWACCEL_GENERIC) {
type = ist->hwaccel_device_type;
dev = hw_device_get_by_type(type);
if (!dev)
err = hw_device_init_from_type(type, NULL, &dev);
} else {
dev = hw_device_match_by_codec(ist->dec);
if (!dev) {
// No device for this codec, but not using generic hwaccel
// and therefore may well not need one - ignore.
return 0;
}
}
}
if (auto_device) {
int i;
if (!avcodec_get_hw_config(ist->dec, 0)) {
// Decoder does not support any hardware devices.
return 0;
}
for (i = 0; !dev; i++) {
config = avcodec_get_hw_config(ist->dec, i);
if (!config)
break;
type = config->device_type;
dev = hw_device_get_by_type(type);
if (dev) {
av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
"hwaccel type %s with existing device %s.\n",
av_hwdevice_get_type_name(type), dev->name);
}
}
for (i = 0; !dev; i++) {
config = avcodec_get_hw_config(ist->dec, i);
if (!config)
break;
type = config->device_type;
// Try to make a new device of this type.
err = hw_device_init_from_type(type, ist->hwaccel_device,
&dev);
if (err < 0) {
// Can't make a device of this type.
continue;
}
if (ist->hwaccel_device) {
av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
"hwaccel type %s with new device created "
"from %s.\n", av_hwdevice_get_type_name(type),
ist->hwaccel_device);
} else {
av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
"hwaccel type %s with new default device.\n",
av_hwdevice_get_type_name(type));
}
}
if (dev) {
ist->hwaccel_device_type = type;
} else {
av_log(ist->dec_ctx, AV_LOG_INFO, "Auto hwaccel "
"disabled: no device found.\n");
ist->hwaccel_id = HWACCEL_NONE;
return 0;
}
}
if (!dev) {
av_log(ist->dec_ctx, AV_LOG_ERROR, "No device available "
"for decoder: device type %s needed for codec %s.\n",
av_hwdevice_get_type_name(type), ist->dec->name);
return err;
}
ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
if (!ist->dec_ctx->hw_device_ctx)
return AVERROR(ENOMEM);
return 0;
}
int hw_device_setup_for_encode(OutputStream *ost)
{
HWDevice *dev;
dev = hw_device_match_by_codec(ost->enc);
if (dev) {
ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
if (!ost->enc_ctx->hw_device_ctx)
return AVERROR(ENOMEM);
return 0;
} else {
// No device required, or no device available.
return 0;
}
}
static int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame *input)
{
InputStream *ist = avctx->opaque;
AVFrame *output = NULL;
enum AVPixelFormat output_format = ist->hwaccel_output_format;
int err;
if (input->format == output_format) {
// Nothing to do.
return 0;
}
output = av_frame_alloc();
if (!output)
return AVERROR(ENOMEM);
output->format = output_format;
err = av_hwframe_transfer_data(output, input, 0);
if (err < 0) {
av_log(avctx, AV_LOG_ERROR, "Failed to transfer data to "
"output frame: %d.\n", err);
goto fail;
}
err = av_frame_copy_props(output, input);
if (err < 0) {
av_frame_unref(output);
goto fail;
}
av_frame_unref(input);
av_frame_move_ref(input, output);
av_frame_free(&output);
return 0;
fail:
av_frame_free(&output);
return err;
}
int hwaccel_decode_init(AVCodecContext *avctx)
{
InputStream *ist = avctx->opaque;
ist->hwaccel_retrieve_data = &hwaccel_retrieve_data;
return 0;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-175
View File
@@ -1,175 +0,0 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include "log.h"
/** Global reference to the virtual machine running */
static JavaVM *globalVm;
/** Global reference of Log class in Java side */
static jclass logClass;
/** Global reference of forward log method in Java side */
static jmethodID logMethod;
/** file descriptor of the pipe created */
static int pipeFd[2];
/** log collector thread variable */
static pthread_t logThread;
/** Holds whether log collector thread is enabled or not */
static int logThreadEnabled = 1;
/** Full name of the Java class that owns native functions in this file. */
const char *logClassName = "com/arthenica/mobileffmpeg/Log";
/** Prototypes of native functions defined by this file. */
JNINativeMethod logMethods[] = {
{"startNativeCollector", "()I", (void*) Java_com_arthenica_mobileffmpeg_Log_startNativeCollector},
{"stopNativeCollector", "()I", (void*) Java_com_arthenica_mobileffmpeg_Log_stopNativeCollector}
};
/**
* Called when 'ffmpeglog' native library is loaded.
*
* \param vm pointer to the running virtual machine
* \param reserved reserved
* \return JNI version needed by 'ffmpeglog' library
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
LOGE("OnLoad failed to GetEnv for class %s.", logClassName);
return JNI_FALSE;
}
(*env)->GetJavaVM(env, &globalVm);
jclass clazz = (*env)->FindClass(env, logClassName);
if (clazz == NULL) {
LOGE("OnLoad failed to FindClass %s.", logClassName);
return JNI_FALSE;
}
logMethod = (*env)->GetStaticMethodID(env, clazz, "log", "([B)V");
if (logMethod == NULL) {
LOGE("OnLoad thread failed to GetMethodID for %s.", "log");
(*globalVm)->DetachCurrentThread(globalVm);
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, clazz, logMethods, 2) < 0) {
LOGE("OnLoad failed to RegisterNatives for class %s.", logClassName);
return JNI_FALSE;
}
logClass = (jclass) ((*env)->NewGlobalRef(env, clazz));
return JNI_VERSION_1_6;
}
/**
* Native log collector main thread function.
*/
static void *logThreadFunction() {
int readSize;
char buffer[512];
JNIEnv *env;
jint getEnvRc = (*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
if (getEnvRc != JNI_OK) {
if (getEnvRc != JNI_EDETACHED) {
LOGE("Log thread failed to GetEnv for class %s with rc %d.", logClassName, getEnvRc);
return JNI_FALSE;
}
if ((*globalVm)->AttachCurrentThread(globalVm, &env, NULL) != 0) {
LOGE("Log thread failed to AttachCurrentThread for class %s.", logClassName);
return JNI_FALSE;
}
}
LOGI("Native log thread started.");
while(logThreadEnabled && ((readSize = (int)read(pipeFd[0], buffer, sizeof(buffer) - 1)) > 0)) {
if (readSize > 0) {
if (buffer[readSize - 1] == '\n') {
readSize--;
}
buffer[readSize] = 0; /* add null-terminator */
jbyteArray byteArray = (jbyteArray) (*env)->NewByteArray(env, readSize);
(*env)->SetByteArrayRegion(env, byteArray, 0, readSize, (jbyte *)buffer);
(*env)->CallStaticVoidMethod(env, logClass, logMethod, byteArray);
(*env)->DeleteLocalRef(env, byteArray);
}
}
(*globalVm)->DetachCurrentThread(globalVm);
LOGI("Native log thread stopped.");
return 0;
}
/**
* Starts native log collector. Native log collector creates a pipe and redirects stdout and stderr to it. Then starts
* a thread, reads data written to this pipe and forwards it to the Java side.
*
* \param env pointer to native method interface
* \param object reference to the object on which this method is invoked
* \return zero on success, non-zero if an error occurs
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Log_startNativeCollector(JNIEnv *env, jobject object) {
/* make stdout line-buffered and stderr unbuffered */
setvbuf(stdout, 0, _IOLBF, 0);
setvbuf(stderr, 0, _IONBF, 0);
/* create the pipe and redirect stdout and stderr */
pipe(pipeFd);
dup2(pipeFd[1], 1);
dup2(pipeFd[1], 2);
/* spawn the logging thread */
int rc = pthread_create(&logThread, 0, logThreadFunction, 0);
if (rc != 0) {
LOGE("Failed to create native log thread (rc=%d).", rc);
return rc;
}
return 0;
}
/**
* Initiates a stop request for native log collector thread. Please note that when this function returns collector
* thread might be still alive.
*
* \param env pointer to native method interface
* \param object reference to the object on which this method is invoked
* \return zero on success, non-zero if an error occurs
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Log_stopNativeCollector(JNIEnv *env, jobject object) {
logThreadEnabled = 0;
LOGI("Stopping native log thread\n");
return 0;
}
-61
View File
@@ -1,61 +0,0 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOBILEFFMPEG_LOG_H
#define MOBILEFFMPEG_LOG_H
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <jni.h>
#include <android/log.h>
/** Defines tag used for Android logging. */
#define LIB_NAME "mobile-ffmpeg"
/** Verbose Android logging macro. */
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LIB_NAME, __VA_ARGS__)
/** Debug Android logging macro. */
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LIB_NAME, __VA_ARGS__)
/** Info Android logging macro. */
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LIB_NAME, __VA_ARGS__)
/** Warn Android logging macro. */
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LIB_NAME, __VA_ARGS__)
/** Error Android logging macro. */
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LIB_NAME, __VA_ARGS__)
/*
* Class: com_arthenica_mobileffmpeg_Log
* Method: startNativeCollector
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Log_startNativeCollector(JNIEnv *, jobject);
/*
* Class: com_arthenica_mobileffmpeg_Log
* Method: stopNativeCollector
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Log_stopNativeCollector(JNIEnv *, jobject);
#endif /* MOBILEFFMPEG_LOG_H */
+777 -43
View File
@@ -17,80 +17,734 @@
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* CHANGES 08.2019
* --------------------------------------------------------
* - lastCommandOutput methods introduced
* - AV_LOG_STDERR introduced
*
* CHANGES 04.2019
* --------------------------------------------------------
* - setNativeEnvironmentVariable method added
*
* CHANGES 02.2019
* --------------------------------------------------------
* - JavaVM registered via av_jni_set_java_vm()
* - registerNewNativeFFmpegPipe() method added
*
* CHANGES 10.2018
* --------------------------------------------------------
* - getBuildConf method added
*
* CHANGES 09.2018
* --------------------------------------------------------
* - Merged with mobileffmpeg_config
*
* CHANGES 08.2018
* --------------------------------------------------------
* - Copied methods with avutil_log_ prefix from libavutil/log.c
*/
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include "libavcodec/jni.h"
#include "libavutil/bprint.h"
#include "fftools_ffmpeg.h"
#include "mobileffmpeg.h"
#include "mobileffprobe.h"
/** Forward declaration for function defined in ffmpeg.c */
int execute(int argc, char **argv);
/** Callback data structure */
struct CallbackData {
int type; // 1 (log callback) or 2 (statistics callback)
/** Full name of the Java class that owns native functions in this file. */
const char *ffmpegClassName = "com/arthenica/mobileffmpeg/FFmpeg";
int logLevel; // log level
char *logData; // log data
/** Prototypes of native functions defined by this file. */
JNINativeMethod ffmpegMethods[] = {
{"getFFmpegVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_FFmpeg_getFFmpegVersion},
{"getVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_FFmpeg_getVersion},
{"execute", "([Ljava/lang/String;)I", (void*) Java_com_arthenica_mobileffmpeg_FFmpeg_execute}
int statisticsFrameNumber; // statistics frame number
float statisticsFps; // statistics fps
float statisticsQuality; // statistics quality
int64_t statisticsSize; // statistics size
int statisticsTime; // statistics time
double statisticsBitrate; // statistics bitrate
double statisticsSpeed; // statistics speed
struct CallbackData *next;
};
/** Redirection control variables */
pthread_mutex_t lockMutex;
pthread_mutex_t monitorMutex;
pthread_cond_t monitorCondition;
/** Last command output variables */
pthread_mutex_t logMutex;
static char *lastCommandOutput;
pthread_t callbackThread;
int redirectionEnabled;
struct CallbackData *callbackDataHead;
struct CallbackData *callbackDataTail;
/** Global reference to the virtual machine running */
static JavaVM *globalVm;
/** Global reference of Config class in Java */
static jclass configClass;
/** Global reference of log redirection method in Java */
static jmethodID logMethod;
/** Global reference of statistics redirection method in Java */
static jmethodID statisticsMethod;
/** Global reference of String class in Java */
static jclass stringClass;
/** Global reference of String constructor in Java */
static jmethodID stringConstructor;
/** Full name of the Config class */
const char *configClassName = "com/arthenica/mobileffmpeg/Config";
/** Full name of String class */
const char *stringClassName = "java/lang/String";
/** Prototypes of native functions defined by Config class. */
JNINativeMethod configMethods[] = {
{"enableNativeRedirection", "()V", (void*) Java_com_arthenica_mobileffmpeg_Config_enableNativeRedirection},
{"disableNativeRedirection", "()V", (void*) Java_com_arthenica_mobileffmpeg_Config_disableNativeRedirection},
{"setNativeLogLevel", "(I)V", (void*) Java_com_arthenica_mobileffmpeg_Config_setNativeLogLevel},
{"getNativeLogLevel", "()I", (void*) Java_com_arthenica_mobileffmpeg_Config_getNativeLogLevel},
{"getNativeFFmpegVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_Config_getNativeFFmpegVersion},
{"getNativeVersion", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_Config_getNativeVersion},
{"nativeFFmpegExecute", "([Ljava/lang/String;)I", (void*) Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegExecute},
{"nativeFFmpegCancel", "()V", (void*) Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegCancel},
{"nativeFFprobeExecute", "([Ljava/lang/String;)I", (void*) Java_com_arthenica_mobileffmpeg_Config_nativeFFprobeExecute},
{"registerNewNativeFFmpegPipe", "(Ljava/lang/String;)I", (void*) Java_com_arthenica_mobileffmpeg_Config_registerNewNativeFFmpegPipe},
{"getNativeBuildDate", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_Config_getNativeBuildDate},
{"setNativeEnvironmentVariable", "(Ljava/lang/String;Ljava/lang/String;)I", (void*) Java_com_arthenica_mobileffmpeg_Config_setNativeEnvironmentVariable}
};
/** Forward declaration for function defined in fftools_ffmpeg.c */
int ffmpeg_execute(int argc, char **argv);
/** DEFINES LINE SIZE USED FOR LOGGING */
#define LOG_LINE_SIZE 1024
static const char *avutil_log_get_level_str(int level) {
switch (level) {
case AV_LOG_STDERR:
return "stderr";
case AV_LOG_QUIET:
return "quiet";
case AV_LOG_DEBUG:
return "debug";
case AV_LOG_VERBOSE:
return "verbose";
case AV_LOG_INFO:
return "info";
case AV_LOG_WARNING:
return "warning";
case AV_LOG_ERROR:
return "error";
case AV_LOG_FATAL:
return "fatal";
case AV_LOG_PANIC:
return "panic";
default:
return "";
}
}
static void avutil_log_format_line(void *avcl, int level, const char *fmt, va_list vl, AVBPrint part[4], int *print_prefix) {
int flags = av_log_get_flags();
AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
av_bprint_init(part+0, 0, 1);
av_bprint_init(part+1, 0, 1);
av_bprint_init(part+2, 0, 1);
av_bprint_init(part+3, 0, 65536);
if (*print_prefix && avc) {
if (avc->parent_log_context_offset) {
AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) +
avc->parent_log_context_offset);
if (parent && *parent) {
av_bprintf(part+0, "[%s @ %p] ",
(*parent)->item_name(parent), parent);
}
}
av_bprintf(part+1, "[%s @ %p] ",
avc->item_name(avcl), avcl);
}
if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
av_bprintf(part+2, "[%s] ", avutil_log_get_level_str(level));
av_vbprintf(part+3, fmt, vl);
if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
*print_prefix = lastc == '\n' || lastc == '\r';
}
}
static void avutil_log_sanitize(uint8_t *line) {
while(*line){
if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
*line='?';
line++;
}
}
void mutexInit() {
pthread_mutexattr_t attributes;
pthread_mutexattr_init(&attributes);
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&lockMutex, &attributes);
pthread_mutexattr_destroy(&attributes);
}
void monitorInit() {
pthread_mutexattr_t attributes;
pthread_mutexattr_init(&attributes);
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_condattr_t cattributes;
pthread_condattr_init(&cattributes);
pthread_condattr_setpshared(&cattributes, PTHREAD_PROCESS_PRIVATE);
pthread_mutex_init(&monitorMutex, &attributes);
pthread_mutexattr_destroy(&attributes);
pthread_cond_init(&monitorCondition, &cattributes);
pthread_condattr_destroy(&cattributes);
}
void logInit() {
pthread_mutexattr_t attributes;
pthread_mutexattr_init(&attributes);
pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&logMutex, &attributes);
pthread_mutexattr_destroy(&attributes);
lastCommandOutput = NULL;
}
void mutexUnInit() {
pthread_mutex_destroy(&lockMutex);
}
void monitorUnInit() {
pthread_mutex_destroy(&monitorMutex);
pthread_cond_destroy(&monitorCondition);
}
void logUnInit() {
pthread_mutex_destroy(&logMutex);
}
void mutexLock() {
pthread_mutex_lock(&lockMutex);
}
void lastCommandOutputLock() {
pthread_mutex_lock(&logMutex);
}
void mutexUnlock() {
pthread_mutex_unlock(&lockMutex);
}
void lastCommandOutputUnlock() {
pthread_mutex_unlock(&logMutex);
}
void clearLastCommandOutput() {
lastCommandOutputLock();
if (lastCommandOutput != NULL) {
av_free(lastCommandOutput);
lastCommandOutput = NULL;
}
lastCommandOutputUnlock();
}
void appendLastCommandOutput(const char *logMessage) {
size_t length = 0;
char *tempLastCommandOutput = NULL;
size_t logMessageLength = strlen(logMessage);
if (logMessageLength <= 0) {
return;
}
lastCommandOutputLock();
if (lastCommandOutput == NULL) {
length = logMessageLength + 1;
lastCommandOutput = (char*)av_malloc(length);
memcpy(lastCommandOutput, logMessage, length);
} else {
size_t length1 = strlen(lastCommandOutput);
length = length1 + logMessageLength + 1;
char *newLastCommandOutput = (char*)av_malloc(length);
memcpy(newLastCommandOutput, lastCommandOutput, length1);
memcpy(newLastCommandOutput + length1, logMessage, logMessageLength + 1);
tempLastCommandOutput = lastCommandOutput;
lastCommandOutput = newLastCommandOutput;
}
lastCommandOutputUnlock();
if (tempLastCommandOutput != NULL) {
av_free(tempLastCommandOutput);
}
}
void monitorWait(int milliSeconds) {
struct timeval tp;
struct timespec ts;
int rc;
rc = gettimeofday(&tp, NULL);
if (rc) {
return;
}
ts.tv_sec = tp.tv_sec;
ts.tv_nsec = tp.tv_usec * 1000;
ts.tv_sec += milliSeconds / 1000;
ts.tv_nsec += (milliSeconds % 1000)*1000000;
pthread_mutex_lock(&monitorMutex);
pthread_cond_timedwait(&monitorCondition, &monitorMutex, &ts);
pthread_mutex_unlock(&monitorMutex);
}
void monitorNotify() {
pthread_mutex_lock(&monitorMutex);
pthread_cond_signal(&monitorCondition);
pthread_mutex_unlock(&monitorMutex);
}
/**
* Adds log data to the end of callback data list.
*
* @param level log level
* @param data log data
*/
void logCallbackDataAdd(int level, const char *data) {
// CREATE DATA STRUCT FIRST
struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData));
newData->type = 1;
newData->logLevel = level;
size_t dataSize = strlen(data) + 1;
newData->logData = (char*)av_malloc(dataSize);
memcpy(newData->logData, data, dataSize);
newData->next = NULL;
mutexLock();
// INSERT IT TO THE END OF QUEUE
if (callbackDataTail == NULL) {
callbackDataTail = newData;
if (callbackDataHead != NULL) {
LOGE("Dangling callback data head detected. This can cause memory leak.");
} else {
callbackDataHead = newData;
}
} else {
struct CallbackData *oldTail = callbackDataTail;
oldTail->next = newData;
callbackDataTail = newData;
}
mutexUnlock();
monitorNotify();
}
/**
* Adds statistics data to the end of callback data list.
*/
void statisticsCallbackDataAdd(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
// CREATE DATA STRUCT FIRST
struct CallbackData *newData = (struct CallbackData*)av_malloc(sizeof(struct CallbackData));
newData->type = 2;
newData->statisticsFrameNumber = frameNumber;
newData->statisticsFps = fps;
newData->statisticsQuality = quality;
newData->statisticsSize = size;
newData->statisticsTime = time;
newData->statisticsBitrate = bitrate;
newData->statisticsSpeed = speed;
newData->next = NULL;
mutexLock();
// INSERT IT TO THE END OF QUEUE
if (callbackDataTail == NULL) {
callbackDataTail = newData;
if (callbackDataHead != NULL) {
LOGE("Dangling callback data head detected. This can cause memory leak.");
} else {
callbackDataHead = newData;
}
} else {
struct CallbackData *oldTail = callbackDataTail;
oldTail->next = newData;
callbackDataTail = newData;
}
mutexUnlock();
monitorNotify();
}
/**
* Removes head of callback data list.
*/
struct CallbackData *callbackDataRemove() {
struct CallbackData *currentData;
mutexLock();
if (callbackDataHead == NULL) {
currentData = NULL;
} else {
currentData = callbackDataHead;
struct CallbackData *nextHead = currentData->next;
if (nextHead == NULL) {
if (callbackDataHead != callbackDataTail) {
LOGE("Head and tail callback data pointers do not match for single callback data element. This can cause memory leak.");
} else {
callbackDataTail = NULL;
}
callbackDataHead = NULL;
} else {
callbackDataHead = nextHead;
}
}
mutexUnlock();
return currentData;
}
/**
* Callback function for FFmpeg logs.
*
* @param ptr pointer to AVClass struct
* @param level log level
* @param format format string
* @param vargs arguments
*/
void mobileffmpeg_log_callback_function(void *ptr, int level, const char* format, va_list vargs) {
char line[LOG_LINE_SIZE];
AVBPrint part[4];
int print_prefix = 1;
if (level >= 0) {
level &= 0xff;
}
int activeLogLevel = av_log_get_level();
// AV_LOG_STDERR logs are always redirected
if ((activeLogLevel == AV_LOG_QUIET && level != AV_LOG_STDERR) || (level > activeLogLevel)) {
return;
}
avutil_log_format_line(ptr, level, format, vargs, part, &print_prefix);
avutil_log_sanitize(part[0].str);
avutil_log_sanitize(part[1].str);
avutil_log_sanitize(part[2].str);
avutil_log_sanitize(part[3].str);
snprintf(line, sizeof(line), "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
logCallbackDataAdd(level, line);
appendLastCommandOutput(line);
av_bprint_finalize(part, NULL);
av_bprint_finalize(part+1, NULL);
av_bprint_finalize(part+2, NULL);
av_bprint_finalize(part+3, NULL);
}
/**
* Callback function for FFmpeg statistics.
*
* @param frameNumber last processed frame number
* @param fps frames processed per second
* @param quality quality of the output stream (video only)
* @param size size in bytes
* @param time processed output duration
* @param bitrate output bit rate in kbits/s
* @param speed processing speed = processed duration / operation duration
*/
void mobileffmpeg_statistics_callback_function(int frameNumber, float fps, float quality, int64_t size, int time, double bitrate, double speed) {
statisticsCallbackDataAdd(frameNumber, fps, quality, size, time, bitrate, speed);
}
/**
* Forwards callback messages to Java classes.
*/
void *callbackThreadFunction() {
JNIEnv *env;
jint getEnvRc = (*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
if (getEnvRc != JNI_OK) {
if (getEnvRc != JNI_EDETACHED) {
LOGE("Callback thread failed to GetEnv for class %s with rc %d.\n", configClassName, getEnvRc);
return NULL;
}
if ((*globalVm)->AttachCurrentThread(globalVm, &env, NULL) != 0) {
LOGE("Callback thread failed to AttachCurrentThread for class %s.\n", configClassName);
return NULL;
}
}
LOGD("Callback thread started.\n");
while(redirectionEnabled) {
struct CallbackData *callbackData = callbackDataRemove();
if (callbackData != NULL) {
if (callbackData->type == 1) {
// LOG CALLBACK
size_t size = strlen(callbackData->logData);
jbyteArray byteArray = (jbyteArray) (*env)->NewByteArray(env, size);
(*env)->SetByteArrayRegion(env, byteArray, 0, size, (jbyte *)callbackData->logData);
(*env)->CallStaticVoidMethod(env, configClass, logMethod, callbackData->logLevel, byteArray);
(*env)->DeleteLocalRef(env, byteArray);
// CLEAN LOG DATA
av_free(callbackData->logData);
} else {
// STATISTICS CALLBACK
(*env)->CallStaticVoidMethod(env, configClass, statisticsMethod,
callbackData->statisticsFrameNumber, callbackData->statisticsFps,
callbackData->statisticsQuality, callbackData->statisticsSize,
callbackData->statisticsTime, callbackData->statisticsBitrate,
callbackData->statisticsSpeed);
}
// CLEAN STRUCT
callbackData->next = NULL;
av_free(callbackData);
} else {
monitorWait(100);
}
}
(*globalVm)->DetachCurrentThread(globalVm);
LOGD("Callback thread stopped.\n");
return NULL;
}
/**
* Called when 'mobileffmpeg' native library is loaded.
*
* \param vm pointer to the running virtual machine
* \param reserved reserved
* \return JNI version needed by 'mobileffmpeg' library
* @param vm pointer to the running virtual machine
* @param reserved reserved
* @return JNI version needed by 'mobileffmpeg' library
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if ((*vm)->GetEnv(vm, (void**)(&env), JNI_VERSION_1_6) != JNI_OK) {
LOGE("OnLoad failed to GetEnv for class %s.", ffmpegClassName);
LOGE("OnLoad failed to GetEnv for class %s.\n", configClassName);
return JNI_FALSE;
}
jclass ffmpegClass = (*env)->FindClass(env, ffmpegClassName);
if (ffmpegClass == NULL) {
LOGE("OnLoad failed to FindClass %s.", ffmpegClassName);
jclass localConfigClass = (*env)->FindClass(env, configClassName);
if (localConfigClass == NULL) {
LOGE("OnLoad failed to FindClass %s.\n", configClassName);
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, ffmpegClass, ffmpegMethods, 3) < 0) {
LOGE("OnLoad failed to RegisterNatives for class %s.", ffmpegClassName);
if ((*env)->RegisterNatives(env, localConfigClass, configMethods, 12) < 0) {
LOGE("OnLoad failed to RegisterNatives for class %s.\n", configClassName);
return JNI_FALSE;
}
jclass localStringClass = (*env)->FindClass(env, stringClassName);
if (localStringClass == NULL) {
LOGE("OnLoad failed to FindClass %s.\n", stringClassName);
return JNI_FALSE;
}
(*env)->GetJavaVM(env, &globalVm);
logMethod = (*env)->GetStaticMethodID(env, localConfigClass, "log", "(I[B)V");
if (logMethod == NULL) {
LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "log");
(*globalVm)->DetachCurrentThread(globalVm);
return JNI_FALSE;
}
statisticsMethod = (*env)->GetStaticMethodID(env, localConfigClass, "statistics", "(IFFJIDD)V");
if (logMethod == NULL) {
LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "statistics");
(*globalVm)->DetachCurrentThread(globalVm);
return JNI_FALSE;
}
stringConstructor = (*env)->GetMethodID(env, localStringClass, "<init>", "([BLjava/lang/String;)V");
if (stringConstructor == NULL) {
LOGE("OnLoad thread failed to GetMethodID for %s.\n", "<init>");
(*globalVm)->DetachCurrentThread(globalVm);
return JNI_FALSE;
}
av_jni_set_java_vm(vm, NULL);
configClass = (jclass) ((*env)->NewGlobalRef(env, localConfigClass));
stringClass = (jclass) ((*env)->NewGlobalRef(env, localStringClass));
redirectionEnabled = 0;
callbackDataHead = NULL;
callbackDataTail = NULL;
mutexInit();
monitorInit();
logInit();
return JNI_VERSION_1_6;
}
/**
* Returns FFmpeg version bundled within the library.
* Sets log level.
*
* \param env pointer to native method interface
* \param object reference to the class on which this method is invoked
* \return FFmpeg version string
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @param level log level
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_FFmpeg_getFFmpegVersion(JNIEnv *env, jclass object) {
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_setNativeLogLevel(JNIEnv *env, jclass object, jint level) {
av_log_set_level(level);
}
/**
* Returns current log level.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeLogLevel(JNIEnv *env, jclass object) {
return av_log_get_level();
}
/**
* Enables log and statistics redirection.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
*/
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_enableNativeRedirection(JNIEnv *env, jclass object) {
mutexLock();
if (redirectionEnabled != 0) {
mutexUnlock();
return;
}
redirectionEnabled = 1;
mutexUnlock();
int rc = pthread_create(&callbackThread, 0, callbackThreadFunction, 0);
if (rc != 0) {
LOGE("Failed to create callback thread (rc=%d).\n", rc);
return;
}
av_log_set_callback(mobileffmpeg_log_callback_function);
set_report_callback(mobileffmpeg_statistics_callback_function);
}
/**
* Disables log and statistics redirection.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
*/
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_disableNativeRedirection(JNIEnv *env, jclass object) {
mutexLock();
if (redirectionEnabled != 1) {
mutexUnlock();
return;
}
redirectionEnabled = 0;
mutexUnlock();
av_log_set_callback(av_log_default_callback);
set_report_callback(NULL);
monitorNotify();
}
/**
* Returns FFmpeg version bundled within the library natively.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @return FFmpeg version string
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeFFmpegVersion(JNIEnv *env, jclass object) {
return (*env)->NewStringUTF(env, FFMPEG_VERSION);
}
/**
* Returns MobileFFmpeg library version.
* Returns MobileFFmpeg library version natively.
*
* \param env pointer to native method interface
* \param object reference to the class on which this method is invoked
* \return MobileFFmpeg version string
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @return MobileFFmpeg version string
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_FFmpeg_getVersion(JNIEnv *env, jclass object) {
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeVersion(JNIEnv *env, jclass object) {
return (*env)->NewStringUTF(env, MOBILE_FFMPEG_VERSION);
}
/**
* Synchronously executes FFmpeg command with arguments provided.
* Synchronously executes FFmpeg natively with arguments provided.
*
* \param env pointer to native method interface
* \param object reference to the class on which this method is invoked
* \param stringArray reference to the object holding FFmpeg command arguments
* \return zero on successful execution, non-zero on error
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @param stringArray reference to the object holding FFmpeg command arguments
* @return zero on successful execution, non-zero on error
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_FFmpeg_execute(JNIEnv *env, jclass object, jobjectArray stringArray) {
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegExecute(JNIEnv *env, jclass object, jobjectArray stringArray) {
jstring *tempArray = NULL;
int argumentCount = 1;
char **argv = NULL;
@@ -99,27 +753,32 @@ JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_FFmpeg_execute(JNIEnv *en
int programArgumentCount = (*env)->GetArrayLength(env, stringArray);
argumentCount = programArgumentCount + 1;
tempArray = (jstring *) malloc(sizeof(jstring) * programArgumentCount);
tempArray = (jstring *) av_malloc(sizeof(jstring) * programArgumentCount);
}
/* PRESERVING USAGE FORMAT
/* PRESERVE USAGE FORMAT
*
* ffmpeg <arguments>
*/
argv = (char **)malloc(sizeof(char*) * (argumentCount));
argv[0] = (char *)malloc(sizeof(char) * (strlen(LIB_NAME) + 1));
argv = (char **)av_malloc(sizeof(char*) * (argumentCount));
argv[0] = (char *)av_malloc(sizeof(char) * (strlen(LIB_NAME) + 1));
strcpy(argv[0], LIB_NAME);
// PREPARE
if (stringArray != NULL) {
for (int i = 0; i < (argumentCount - 1); i++) {
tempArray[i] = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
argv[i + 1] = (char *) (*env)->GetStringUTFChars(env, tempArray[i], 0);
if (tempArray[i] != NULL) {
argv[i + 1] = (char *) (*env)->GetStringUTFChars(env, tempArray[i], 0);
}
}
}
// LAST COMMAND OUTPUT SHOULD BE CLEARED BEFORE STARTING A NEW EXECUTION
clearLastCommandOutput();
// RUN
int retCode = execute(argumentCount, argv);
int retCode = ffmpeg_execute(argumentCount, argv);
// CLEANUP
if (tempArray != NULL) {
@@ -127,10 +786,85 @@ JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_FFmpeg_execute(JNIEnv *en
(*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]);
}
free(tempArray);
av_free(tempArray);
}
free(argv[0]);
free(argv);
av_free(argv[0]);
av_free(argv);
return retCode;
}
/**
* Cancels an ongoing FFmpeg operation natively.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
*/
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegCancel(JNIEnv *env, jclass object) {
cancel_operation();
}
/**
* Creates natively a new named pipe to use in FFmpeg operations.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @param ffmpegPipePath full path of ffmpeg pipe
* @return zero on successful creation, non-zero on error
*/
JNIEXPORT int JNICALL Java_com_arthenica_mobileffmpeg_Config_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath) {
const char *ffmpegPipePathString = (*env)->GetStringUTFChars(env, ffmpegPipePath, 0);
return mkfifo(ffmpegPipePathString, S_IRWXU | S_IRWXG | S_IROTH);
}
/**
* Returns MobileFFmpeg library build date natively.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @return MobileFFmpeg library build date
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeBuildDate(JNIEnv *env, jclass object) {
char buildDate[10];
sprintf(buildDate, "%d", MOBILE_FFMPEG_BUILD_DATE);
return (*env)->NewStringUTF(env, buildDate);
}
/**
* Sets an environment variable natively
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @param variableName environment variable name
* @param variableValue environment variable value
* @return zero on success, non-zero on error
*/
JNIEXPORT int JNICALL Java_com_arthenica_mobileffmpeg_Config_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue) {
const char *variableNameString = (*env)->GetStringUTFChars(env, variableName, 0);
const char *variableValueString = (*env)->GetStringUTFChars(env, variableValue, 0);
return setenv(variableNameString, variableValueString, 1);
}
/**
* Returns log output of the last executed command natively.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @return output of the last executed command
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeLastCommandOutput(JNIEnv *env, jclass object) {
if (lastCommandOutput != NULL) {
int size = strlen(lastCommandOutput);
if (size > 0) {
jbyteArray byteArray = (*env)->NewByteArray(env, size);
(*env)->SetByteArrayRegion(env, byteArray, 0, size, lastCommandOutput);
jstring charsetName = (*env)->NewStringUTF(env, "UTF-8");
return (jstring) (*env)->NewObject(env, stringClass, stringConstructor, byteArray, charsetName);
}
}
return (*env)->NewStringUTF(env, "");
}
+96 -16
View File
@@ -17,38 +17,118 @@
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOBILEFFMPEG_H
#define MOBILEFFMPEG_H
#ifndef MOBILE_FFMPEG_H
#define MOBILE_FFMPEG_H
#include <string.h>
#include <stdlib.h>
#include <jni.h>
#include <android/log.h>
#include "libavutil/log.h"
#include "libavutil/ffversion.h"
#include "log.h"
/** Library version string */
#define MOBILE_FFMPEG_VERSION "2.0"
#define MOBILE_FFMPEG_VERSION "4.3.1"
/** Defines tag used for Android logging. */
#define LIB_NAME "mobile-ffmpeg"
/** Verbose Android logging macro. */
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LIB_NAME, __VA_ARGS__)
/** Debug Android logging macro. */
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LIB_NAME, __VA_ARGS__)
/** Info Android logging macro. */
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LIB_NAME, __VA_ARGS__)
/** Warn Android logging macro. */
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LIB_NAME, __VA_ARGS__)
/** Error Android logging macro. */
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LIB_NAME, __VA_ARGS__)
/*
* Class: com_arthenica_mobileffmpeg_FFmpeg
* Method: getFFmpegVersion
* Class: com_arthenica_mobileffmpeg_Config
* Method: enableNativeRedirection
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_enableNativeRedirection(JNIEnv *, jclass);
/*
* Class: com_arthenica_mobileffmpeg_Config
* Method: disableNativeRedirection
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_disableNativeRedirection(JNIEnv *, jclass);
/*
* Class: com_arthenica_mobileffmpeg_Config
* Method: setNativeLogLevel
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_setNativeLogLevel(JNIEnv *, jclass, jint);
/*
* Class: com_arthenica_mobileffmpeg_Config
* Method: getNativeLogLevel
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeLogLevel(JNIEnv *, jclass);
/*
* Class: com_arthenica_mobileffmpeg_Config
* Method: getNativeFFmpegVersion
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_FFmpeg_getFFmpegVersion(JNIEnv *, jclass);
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeFFmpegVersion(JNIEnv *, jclass);
/*
* Class: com_arthenica_mobileffmpeg_FFmpeg
* Method: getVersion
* Class: com_arthenica_mobileffmpeg_Config
* Method: getNativeVersion
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_FFmpeg_getVersion(JNIEnv *, jclass);
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeVersion(JNIEnv *, jclass);
/*
* Class: com_arthenica_mobileffmpeg_FFmpeg
* Method: execute
* Class: com_arthenica_mobileffmpeg_Config
* Method: nativeFFmpegExecute
* Signature: ([Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_FFmpeg_execute(JNIEnv *, jclass, jobjectArray);
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegExecute(JNIEnv *, jclass, jobjectArray);
#endif /* MOBILEFFMPEG_H */
/*
* Class: com_arthenica_mobileffmpeg_Config
* Method: nativeFFmpegCancel
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFmpegCancel(JNIEnv *, jclass);
/*
* Class: com_arthenica_mobileffmpeg_Config
* Method: registerNewNativeFFmpegPipe
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT int JNICALL Java_com_arthenica_mobileffmpeg_Config_registerNewNativeFFmpegPipe(JNIEnv *env, jclass object, jstring ffmpegPipePath);
/*
* Class: com_arthenica_mobileffmpeg_Config
* Method: getNativeBuildDate
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeBuildDate(JNIEnv *env, jclass object);
/**
* Class: com_arthenica_mobileffmpeg_Config
* Method: setNativeEnvironmentVariable
* Signature: (Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT int JNICALL Java_com_arthenica_mobileffmpeg_Config_setNativeEnvironmentVariable(JNIEnv *env, jclass object, jstring variableName, jstring variableValue);
/*
* Class: com_arthenica_mobileffmpeg_Config
* Method: getNativeLastCommandOutput
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_Config_getNativeLastCommandOutput(JNIEnv *env, jclass object);
#endif /* MOBILE_FFMPEG_H */
@@ -0,0 +1,144 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu-features.h"
#include "fftools_ffmpeg.h"
#include "mobileffmpeg_abidetect.h"
/** Full name of the Java class that owns native functions in this file. */
const char *abiDetectClassName = "com/arthenica/mobileffmpeg/AbiDetect";
/** Prototypes of native functions defined by this file. */
JNINativeMethod abiDetectMethods[] = {
{"getNativeAbi", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_AbiDetect_getNativeAbi},
{"getNativeCpuAbi", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_AbiDetect_getNativeCpuAbi},
{"isNativeLTSBuild", "()Z", (void*) Java_com_arthenica_mobileffmpeg_AbiDetect_isNativeLTSBuild},
{"getNativeBuildConf", "()Ljava/lang/String;", (void*) Java_com_arthenica_mobileffmpeg_AbiDetect_getNativeBuildConf}
};
/**
* Called when 'abidetect' native library is loaded.
*
* @param vm pointer to the running virtual machine
* @param reserved reserved
* @return JNI version needed by 'abidetect' library
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
LOGE("OnLoad failed to GetEnv for class %s.\n", abiDetectClassName);
return JNI_FALSE;
}
jclass abiDetectClass = (*env)->FindClass(env, abiDetectClassName);
if (abiDetectClass == NULL) {
LOGE("OnLoad failed to FindClass %s.\n", abiDetectClassName);
return JNI_FALSE;
}
if ((*env)->RegisterNatives(env, abiDetectClass, abiDetectMethods, 4) < 0) {
LOGE("OnLoad failed to RegisterNatives for class %s.\n", abiDetectClassName);
return JNI_FALSE;
}
return JNI_VERSION_1_6;
}
/**
* Returns loaded ABI name.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @return loaded ABI name as UTF string
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_AbiDetect_getNativeAbi(JNIEnv *env, jclass object) {
#ifdef MOBILE_FFMPEG_ARM_V7A
return (*env)->NewStringUTF(env, "arm-v7a");
#elif MOBILE_FFMPEG_ARM64_V8A
return (*env)->NewStringUTF(env, "arm64-v8a");
#elif MOBILE_FFMPEG_X86
return (*env)->NewStringUTF(env, "x86");
#elif MOBILE_FFMPEG_X86_64
return (*env)->NewStringUTF(env, "x86_64");
#else
return (*env)->NewStringUTF(env, "unknown");
#endif
}
/**
* Returns ABI name of the running cpu.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @return ABI name of the running cpu as UTF string
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_AbiDetect_getNativeCpuAbi(JNIEnv *env, jclass object) {
AndroidCpuFamily family = android_getCpuFamily();
if (family == ANDROID_CPU_FAMILY_ARM) {
uint64_t features = android_getCpuFeatures();
if (features & ANDROID_CPU_ARM_FEATURE_ARMv7) {
if (features & ANDROID_CPU_ARM_FEATURE_NEON) {
return (*env)->NewStringUTF(env, ABI_ARMV7A_NEON);
} else {
return (*env)->NewStringUTF(env, ABI_ARMV7A);
}
} else {
return (*env)->NewStringUTF(env, ABI_ARM);
}
} else if (family == ANDROID_CPU_FAMILY_ARM64) {
return (*env)->NewStringUTF(env, ABI_ARM64_V8A);
} else if (family == ANDROID_CPU_FAMILY_X86) {
return (*env)->NewStringUTF(env, ABI_X86);
} else if (family == ANDROID_CPU_FAMILY_X86_64) {
return (*env)->NewStringUTF(env, ABI_X86_64);
} else {
return (*env)->NewStringUTF(env, ABI_UNKNOWN);
}
}
/**
* Returns whether MobileFFmpeg release is a long term release or not.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @return YES or NO
*/
JNIEXPORT jboolean JNICALL Java_com_arthenica_mobileffmpeg_AbiDetect_isNativeLTSBuild(JNIEnv *env, jclass object) {
#if defined(MOBILE_FFMPEG_LTS)
return JNI_TRUE;
#else
return JNI_FALSE;
#endif
}
/**
* Returns build configuration for FFmpeg.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @return build configuration string
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_AbiDetect_getNativeBuildConf(JNIEnv *env, jclass object) {
return (*env)->NewStringUTF(env, FFMPEG_CONFIGURATION);
}
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOBILE_FFMPEG_ABIDETECT_H
#define MOBILE_FFMPEG_ABIDETECT_H
#include <jni.h>
#include "mobileffmpeg.h"
/** Represents armeabi-v7a ABI with NEON support. */
#define ABI_ARMV7A_NEON "armeabi-v7a-neon"
/** Represents armeabi-v7a ABI. */
#define ABI_ARMV7A "armeabi-v7a"
/** Represents armeabi ABI. */
#define ABI_ARM "armeabi"
/** Represents x86 ABI. */
#define ABI_X86 "x86"
/** Represents x86_64 ABI. */
#define ABI_X86_64 "x86_64"
/** Represents arm64-v8a ABI. */
#define ABI_ARM64_V8A "arm64-v8a"
/** Represents not supported ABIs. */
#define ABI_UNKNOWN "unknown"
/*
* Class: com_arthenica_mobileffmpeg_AbiDetect
* Method: getNativeAbi
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_AbiDetect_getNativeAbi(JNIEnv *, jclass);
/*
* Class: com_arthenica_mobileffmpeg_AbiDetect
* Method: getNativeCpuAbi
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_AbiDetect_getNativeCpuAbi(JNIEnv *, jclass);
/**
* Class: com_arthenica_mobileffmpeg_AbiDetect
* Method: isNativeLTSBuild
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_arthenica_mobileffmpeg_AbiDetect_isNativeLTSBuild(JNIEnv *, jclass);
/*
* Class: com_arthenica_mobileffmpeg_AbiDetect
* Method: getNativeBuildConf
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_arthenica_mobileffmpeg_AbiDetect_getNativeBuildConf(JNIEnv *, jclass);
#endif /* MOBILE_FFMPEG_ABIDETECT_H */
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <setjmp.h>
/** Holds information to implement exception handling. */
__thread jmp_buf ex_buf__;
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOBILE_FFMPEG_EXCEPTION_H
#define MOBILE_FFMPEG_EXCEPTION_H
#include <stdio.h>
#include <setjmp.h>
/** Holds information to implement exception handling. */
extern __thread jmp_buf ex_buf__;
#endif // MOBILE_FFMPEG_EXCEPTION_H
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include <jni.h>
#include "libavcodec/jni.h"
/** Forward declaration for function defined in fftools_ffplay.c */
int ffplay_execute(int argc, char **argv);
/** Forward declaration for functions defined in SDl_android.c */
void set_mobile_ffmpeg_ffplay_execute(int (*ffplay_execute_function)(int argc, char **argv));
jint SDL_Android_Initialize(JavaVM* vm, void* reserved);
/**
* Initializes SDL for FFplay. It must be called before other SDL functions.
*/
JNIEXPORT void JNICALL Java_com_arthenica_mobileffmpeg_FFplay_nativeSDLInit(JNIEnv *env, jclass object) {
set_mobile_ffmpeg_ffplay_execute(ffplay_execute);
JavaVM *globalVm = av_jni_get_java_vm(NULL);
if (globalVm) {
SDL_Android_Initialize(globalVm, NULL);
}
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOBILE_FFPLAY_H
#define MOBILE_FFPLAY_H
#include <jni.h>
/*
* Class: com_arthenica_mobileffmpeg_Config
* Method: nativeFFplayExecute
* Signature: ([Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFplayExecute(JNIEnv *, jclass, jobjectArray);
#endif /* MOBILE_FFPLAY_H */
+91
View File
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include "libavcodec/jni.h"
#include "libavutil/bprint.h"
#include "mobileffmpeg.h"
/** Forward declaration for function defined in fftools_ffprobe.c */
int ffprobe_execute(int argc, char **argv);
/** Forward declaration for function defined in mobileffmpeg.c */
void clearLastCommandOutput();
/**
* Synchronously executes FFprobe natively with arguments provided.
*
* @param env pointer to native method interface
* @param object reference to the class on which this method is invoked
* @param stringArray reference to the object holding FFprobe command arguments
* @return zero on successful execution, non-zero on error
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFprobeExecute(JNIEnv *env, jclass object, jobjectArray stringArray) {
jstring *tempArray = NULL;
int argumentCount = 1;
char **argv = NULL;
if (stringArray != NULL) {
int programArgumentCount = (*env)->GetArrayLength(env, stringArray);
argumentCount = programArgumentCount + 1;
tempArray = (jstring *) av_malloc(sizeof(jstring) * programArgumentCount);
}
/* PRESERVE USAGE FORMAT
*
* ffprobe <arguments>
*/
argv = (char **)av_malloc(sizeof(char*) * (argumentCount));
argv[0] = (char *)av_malloc(sizeof(char) * (strlen(LIB_NAME) + 1));
strcpy(argv[0], LIB_NAME);
// PREPARE
if (stringArray != NULL) {
for (int i = 0; i < (argumentCount - 1); i++) {
tempArray[i] = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i);
if (tempArray[i] != NULL) {
argv[i + 1] = (char *) (*env)->GetStringUTFChars(env, tempArray[i], 0);
}
}
}
// LAST COMMAND OUTPUT SHOULD BE CLEARED BEFORE STARTING A NEW EXECUTION
clearLastCommandOutput();
// RUN
int retCode = ffprobe_execute(argumentCount, argv);
// CLEANUP
if (tempArray != NULL) {
for (int i = 0; i < (argumentCount - 1); i++) {
(*env)->ReleaseStringUTFChars(env, tempArray[i], argv[i + 1]);
}
av_free(tempArray);
}
av_free(argv[0]);
av_free(argv);
return retCode;
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MOBILE_FFPROBE_H
#define MOBILE_FFPROBE_H
#include <jni.h>
/*
* Class: com_arthenica_mobileffmpeg_Config
* Method: nativeFFprobeExecute
* Signature: ([Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_arthenica_mobileffmpeg_Config_nativeFFprobeExecute(JNIEnv *, jclass, jobjectArray);
#endif /* MOBILE_FFPROBE_H */
@@ -19,6 +19,8 @@
package com.arthenica.mobileffmpeg;
import android.os.Build;
/**
* <p>This class is used to detect running ABI name using Android's <code>cpufeatures</code>
* library.
@@ -29,20 +31,74 @@ package com.arthenica.mobileffmpeg;
public class AbiDetect {
static {
System.loadLibrary("abidetect");
armV7aNeonLoaded = false;
/* LOAD NOT-LOADED LIBRARIES ON API < 21 */
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
System.loadLibrary("cpufeatures");
}
System.loadLibrary("mobileffmpeg_abidetect");
/* ALL LIBRARIES LOADED AT STARTUP */
Config.class.getName();
FFmpeg.class.getName();
}
static final String ARM_V7A = "arm-v7a";
static final String ARM_V7A_NEON = "arm-v7a-neon";
private static boolean armV7aNeonLoaded;
/**
* Default constructor hidden.
*/
private AbiDetect() {
}
static void setArmV7aNeonLoaded(final boolean armV7aNeonLoaded) {
AbiDetect.armV7aNeonLoaded = armV7aNeonLoaded;
}
/**
* <p>Returns running ABI name.
* <p>Returns loaded ABI name.
*
* @return running ABI name
* @return loaded ABI name
*/
public native static String getAbi();
public static String getAbi() {
if (armV7aNeonLoaded) {
return ARM_V7A_NEON;
} else {
return getNativeAbi();
}
}
/**
* <p>Returns loaded ABI name.
*
* @return loaded ABI name
*/
public native static String getNativeAbi();
/**
* <p>Returns ABI name of the running cpu.
*
* @return ABI name of the running cpu
*/
public native static String getNativeCpuAbi();
/**
* <p>Returns whether MobileFFmpeg release is a long term release or not.
*
* @return YES or NO
*/
native static boolean isNativeLTSBuild();
/**
* <p>Returns build configuration for <code>FFmpeg</code>.
*
* @return build configuration string
*/
native static String getNativeBuildConf();
}
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2019 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.os.Build;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import static android.content.Context.CAMERA_SERVICE;
import static com.arthenica.mobileffmpeg.Config.TAG;
class CameraSupport {
/**
* <p>Compatibility method for extracting supported camera ids.
*
* @param context application context
* @return returns the list of supported camera ids
*/
static List<String> extractSupportedCameraIds(final Context context) {
final List<String> detectedCameraIdList = new ArrayList<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
try {
final CameraManager manager = (CameraManager) context.getSystemService(CAMERA_SERVICE);
if (manager != null) {
final String[] cameraIdList = manager.getCameraIdList();
for (String cameraId : cameraIdList) {
final CameraCharacteristics chars = manager.getCameraCharacteristics(cameraId);
final Integer cameraSupport = chars.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (cameraSupport != null && cameraSupport == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
Log.d(TAG, "Detected camera with id " + cameraId + " has LEGACY hardware level which is not supported by Android Camera2 NDK API.");
} else if (cameraSupport != null) {
detectedCameraIdList.add(cameraId);
}
}
}
} catch (final CameraAccessException e) {
Log.w(TAG, "Detecting camera ids failed.", e);
}
}
return detectedCameraIdList;
}
}
@@ -0,0 +1,692 @@
/*
* Copyright (c) 2018-2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
/**
* <p>This class is used to configure MobileFFmpeg library utilities/tools.
*
* <p>1. {@link LogCallback}: This class redirects FFmpeg/FFprobe output to Logcat by default. As
* an alternative, it is possible not to print messages to Logcat and pass them to a
* {@link LogCallback} function. This function can decide whether to print these logs, show them
* inside another container or ignore them.
*
* <p>2. {@link #setLogLevel(Level)}/{@link #getLogLevel()}: Use this methods to set/get
* FFmpeg/FFprobe log severity.
*
* <p>3. {@link StatisticsCallback}: It is possible to receive statistics about an ongoing
* operation by defining a {@link StatisticsCallback} function or by calling
* {@link #getLastReceivedStatistics()} method.
*
* <p>4. Font configuration: It is possible to register custom fonts with
* {@link #setFontconfigConfigurationPath(String)} and
* {@link #setFontDirectory(Context, String, Map)} methods.
*
* @author Taner Sener
* @since v2.1
*/
public class Config {
public static final int RETURN_CODE_SUCCESS = 0;
public static final int RETURN_CODE_CANCEL = 255;
private static int lastReturnCode = 0;
/**
* Defines tag used for logging.
*/
public static final String TAG = "mobile-ffmpeg";
public static final String MOBILE_FFMPEG_PIPE_PREFIX = "mf_pipe_";
private static LogCallback logCallbackFunction;
private static Level activeLogLevel;
private static StatisticsCallback statisticsCallbackFunction;
private static Statistics lastReceivedStatistics;
private static int lastCreatedPipeIndex;
static {
Log.i(Config.TAG, "Loading mobile-ffmpeg.");
/* LOAD NOT-LOADED LIBRARIES ON API < 21 */
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
final List<String> externalLibrariesEnabled = getExternalLibraries();
if (externalLibrariesEnabled.contains("tesseract") || externalLibrariesEnabled.contains("x265") || externalLibrariesEnabled.contains("snappy") || externalLibrariesEnabled.contains("openh264")) {
// libc++_shared.so included only when tesseract or x265 is enabled
System.loadLibrary("c++_shared");
}
System.loadLibrary("cpufeatures");
System.loadLibrary("avutil");
System.loadLibrary("swscale");
System.loadLibrary("swresample");
System.loadLibrary("avcodec");
System.loadLibrary("avformat");
System.loadLibrary("avfilter");
System.loadLibrary("avdevice");
}
/* ALL MOBILE-FFMPEG LIBRARIES LOADED AT STARTUP */
Abi.class.getName();
FFmpeg.class.getName();
FFprobe.class.getName();
FFplay.class.getName();
/*
* NEON supported arm-v7a library has a different name
*/
boolean nativeLibraryLoaded = false;
if (AbiDetect.ARM_V7A.equals(AbiDetect.getNativeAbi())) {
if (AbiDetect.isNativeLTSBuild()) {
/*
* IF CPU SUPPORTS ARM-V7A-NEON THE TRY TO LOAD IT FIRST. IF NOT LOAD DEFAULT ARM-V7A
*/
try {
System.loadLibrary("mobileffmpeg_armv7a_neon");
nativeLibraryLoaded = true;
AbiDetect.setArmV7aNeonLoaded(true);
} catch (final UnsatisfiedLinkError e) {
Log.i(Config.TAG, "NEON supported armeabi-v7a library not found. Loading default armeabi-v7a library.", e);
}
} else {
AbiDetect.setArmV7aNeonLoaded(true);
}
}
if (!nativeLibraryLoaded) {
System.loadLibrary("mobileffmpeg");
}
Log.i(Config.TAG, String.format("Loaded mobile-ffmpeg-%s-%s-%s-%s.", getPackageName(), AbiDetect.getAbi(), getVersion(), getBuildDate()));
/* NATIVE LOG LEVEL IS RECEIVED ONLY ON STARTUP */
activeLogLevel = Level.from(getNativeLogLevel());
lastReceivedStatistics = new Statistics();
enableRedirection();
lastCreatedPipeIndex = 0;
}
/**
* Default constructor hidden.
*/
private Config() {
}
/**
* <p>Enables log and statistics redirection.
* <p>When redirection is not enabled FFmpeg/FFprobe logs are printed to stderr. By enabling
* redirection, they are routed to Logcat and can be routed further to a callback function.
* <p>Statistics redirection behaviour is similar. Statistics are not printed at all if
* redirection is not enabled. If it is enabled then it is possible to define a statistics
* callback function but if you don't, they are not printed anywhere and only saved as
* <code>lastReceivedStatistics</code> data which can be polled with
* {@link #getLastReceivedStatistics()}.
* <p>Note that redirection is enabled by default. If you do not want to use its functionality
* please use {@link #disableRedirection()} to disable it.
*/
public static void enableRedirection() {
enableNativeRedirection();
}
/**
* <p>Disables log and statistics redirection.
*/
public static void disableRedirection() {
disableNativeRedirection();
}
/**
* Returns log level.
*
* @return log level
*/
public static Level getLogLevel() {
return activeLogLevel;
}
/**
* Sets log level.
*
* @param level log level
*/
public static void setLogLevel(final Level level) {
if (level != null) {
activeLogLevel = level;
setNativeLogLevel(level.getValue());
}
}
/**
* <p>Sets a callback function to redirect FFmpeg/FFprobe logs.
*
* @param newLogCallback new log callback function or NULL to disable a previously defined callback
*/
public static void enableLogCallback(final LogCallback newLogCallback) {
logCallbackFunction = newLogCallback;
}
/**
* <p>Sets a callback function to redirect FFmpeg statistics.
*
* @param statisticsCallback new statistics callback function or NULL to disable a previously defined callback
*/
public static void enableStatisticsCallback(final StatisticsCallback statisticsCallback) {
statisticsCallbackFunction = statisticsCallback;
}
/**
* <p>Log redirection method called by JNI/native part.
*
* @param levelValue log level as defined in {@link Level}
* @param logMessage redirected log message
*/
private static void log(final int levelValue, final byte[] logMessage) {
final Level level = Level.from(levelValue);
final String text = new String(logMessage);
// AV_LOG_STDERR logs are always redirected
if ((activeLogLevel == Level.AV_LOG_QUIET && levelValue != Level.AV_LOG_STDERR.getValue()) || levelValue > activeLogLevel.getValue()) {
// LOG NEITHER PRINTED NOR FORWARDED
return;
}
if (logCallbackFunction != null) {
try {
logCallbackFunction.apply(new LogMessage(level, text));
} catch (final Exception e) {
Log.e(Config.TAG, "Exception thrown inside LogCallback block", e);
}
} else {
switch (level) {
case AV_LOG_QUIET: {
// PRINT NO OUTPUT
}
break;
case AV_LOG_TRACE:
case AV_LOG_DEBUG: {
android.util.Log.d(TAG, text);
}
break;
case AV_LOG_STDERR:
case AV_LOG_VERBOSE: {
android.util.Log.v(TAG, text);
}
break;
case AV_LOG_INFO: {
android.util.Log.i(TAG, text);
}
break;
case AV_LOG_WARNING: {
android.util.Log.w(TAG, text);
}
break;
case AV_LOG_ERROR:
case AV_LOG_FATAL:
case AV_LOG_PANIC: {
android.util.Log.e(TAG, text);
}
break;
default: {
android.util.Log.v(TAG, text);
}
break;
}
}
}
/**
* <p>Statistics redirection method called by JNI/native part.
*
* @param videoFrameNumber last processed frame number for videos
* @param videoFps frames processed per second for videos
* @param videoQuality quality of the video stream
* @param size size in bytes
* @param time processed duration in milliseconds
* @param bitrate output bit rate in kbits/s
* @param speed processing speed = processed duration / operation duration
*/
private static void statistics(final int videoFrameNumber, final float videoFps,
final float videoQuality, final long size, final int time,
final double bitrate, final double speed) {
final Statistics newStatistics = new Statistics(videoFrameNumber, videoFps, videoQuality, size, time, bitrate, speed);
lastReceivedStatistics.update(newStatistics);
if (statisticsCallbackFunction != null) {
try {
statisticsCallbackFunction.apply(lastReceivedStatistics);
} catch (final Exception e) {
Log.e(Config.TAG, "Exception thrown inside StatisticsCallback block", e);
}
}
}
/**
* <p>Returns the last received statistics data.
*
* @return last received statistics data
*/
public static Statistics getLastReceivedStatistics() {
return lastReceivedStatistics;
}
/**
* <p>Resets last received statistics. It is recommended to call it before starting a new execution.
*/
public static void resetStatistics() {
lastReceivedStatistics = new Statistics();
}
/**
* <p>Sets and overrides <code>fontconfig</code> configuration directory.
*
* @param path directory which contains fontconfig configuration (fonts.conf)
* @return zero on success, non-zero on error
*/
public static int setFontconfigConfigurationPath(final String path) {
return setNativeEnvironmentVariable("FONTCONFIG_PATH", path);
}
/**
* <p>Registers fonts inside the given path, so they are available to use in FFmpeg filters.
*
* <p>Note that you need to build <code>MobileFFmpeg</code> with <code>fontconfig</code>
* enabled or use a prebuilt package with <code>fontconfig</code> inside to use this feature.
*
* @param context application context to access application data
* @param fontDirectoryPath directory which contains fonts (.ttf and .otf files)
* @param fontNameMapping custom font name mappings, useful to access your fonts with more friendly names
*/
public static void setFontDirectory(final Context context, final String fontDirectoryPath, final Map<String, String> fontNameMapping) {
final File cacheDir = context.getCacheDir();
int validFontNameMappingCount = 0;
final File tempConfigurationDirectory = new File(cacheDir, ".mobileffmpeg");
if (!tempConfigurationDirectory.exists()) {
boolean tempFontConfDirectoryCreated = tempConfigurationDirectory.mkdirs();
Log.d(TAG, String.format("Created temporary font conf directory: %s.", tempFontConfDirectoryCreated));
}
final File fontConfiguration = new File(tempConfigurationDirectory, "fonts.conf");
if (fontConfiguration.exists()) {
boolean fontConfigurationDeleted = fontConfiguration.delete();
Log.d(TAG, String.format("Deleted old temporary font configuration: %s.", fontConfigurationDeleted));
}
/* PROCESS MAPPINGS FIRST */
final StringBuilder fontNameMappingBlock = new StringBuilder("");
if (fontNameMapping != null && (fontNameMapping.size() > 0)) {
fontNameMapping.entrySet();
for (Map.Entry<String, String> mapping : fontNameMapping.entrySet()) {
String fontName = mapping.getKey();
String mappedFontName = mapping.getValue();
if ((fontName != null) && (mappedFontName != null) && (fontName.trim().length() > 0) && (mappedFontName.trim().length() > 0)) {
fontNameMappingBlock.append(" <match target=\"pattern\">\n");
fontNameMappingBlock.append(" <test qual=\"any\" name=\"family\">\n");
fontNameMappingBlock.append(String.format(" <string>%s</string>\n", fontName));
fontNameMappingBlock.append(" </test>\n");
fontNameMappingBlock.append(" <edit name=\"family\" mode=\"assign\" binding=\"same\">\n");
fontNameMappingBlock.append(String.format(" <string>%s</string>\n", mappedFontName));
fontNameMappingBlock.append(" </edit>\n");
fontNameMappingBlock.append(" </match>\n");
validFontNameMappingCount++;
}
}
}
final String fontConfig = "<?xml version=\"1.0\"?>\n" +
"<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">\n" +
"<fontconfig>\n" +
" <dir>.</dir>\n" +
" <dir>" + fontDirectoryPath + "</dir>\n" +
fontNameMappingBlock +
"</fontconfig>";
final AtomicReference<FileOutputStream> reference = new AtomicReference<>();
try {
final FileOutputStream outputStream = new FileOutputStream(fontConfiguration);
reference.set(outputStream);
outputStream.write(fontConfig.getBytes());
outputStream.flush();
Log.d(TAG, String.format("Saved new temporary font configuration with %d font name mappings.", validFontNameMappingCount));
setFontconfigConfigurationPath(tempConfigurationDirectory.getAbsolutePath());
Log.d(TAG, String.format("Font directory %s registered successfully.", fontDirectoryPath));
} catch (final IOException e) {
Log.e(TAG, String.format("Failed to set font directory: %s.", fontDirectoryPath), e);
} finally {
if (reference.get() != null) {
try {
reference.get().close();
} catch (IOException e) {
// DO NOT PRINT THIS ERROR
}
}
}
}
/**
* <p>Returns package name.
*
* @return guessed package name according to supported external libraries
* @since 3.0
*/
public static String getPackageName() {
return Packages.getPackageName();
}
/**
* <p>Returns supported external libraries.
*
* @return list of supported external libraries
* @since 3.0
*/
public static List<String> getExternalLibraries() {
return Packages.getExternalLibraries();
}
/**
* <p>Creates a new named pipe to use in <code>FFmpeg</code> operations.
*
* <p>Please note that creator is responsible of closing created pipes.
*
* @param context application context
* @return the full path of named pipe
*/
public static String registerNewFFmpegPipe(final Context context) {
// PIPES ARE CREATED UNDER THE CACHE DIRECTORY
final File cacheDir = context.getCacheDir();
final String newFFmpegPipePath = cacheDir + File.separator + MOBILE_FFMPEG_PIPE_PREFIX + (++lastCreatedPipeIndex);
// FIRST CLOSE OLD PIPES WITH THE SAME NAME
closeFFmpegPipe(newFFmpegPipePath);
int rc = registerNewNativeFFmpegPipe(newFFmpegPipePath);
if (rc == 0) {
return newFFmpegPipePath;
} else {
Log.e(TAG, String.format("Failed to register new FFmpeg pipe %s. Operation failed with rc=%d.", newFFmpegPipePath, rc));
return null;
}
}
/**
* <p>Closes a previously created <code>FFmpeg</code> pipe.
*
* @param ffmpegPipePath full path of ffmpeg pipe
*/
public static void closeFFmpegPipe(final String ffmpegPipePath) {
File file = new File(ffmpegPipePath);
if (file.exists()) {
file.delete();
}
}
/**
* Returns the list of camera ids supported.
*
* @param context application context
* @return the list of camera ids supported or an empty list if no supported camera is found
*/
public static List<String> getSupportedCameraIds(final Context context) {
final List<String> detectedCameraIdList = new ArrayList<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
detectedCameraIdList.addAll(CameraSupport.extractSupportedCameraIds(context));
}
return detectedCameraIdList;
}
/**
* <p>Returns FFmpeg version bundled within the library.
*
* @return FFmpeg version
*/
public static String getFFmpegVersion() {
return getNativeFFmpegVersion();
}
/**
* <p>Returns MobileFFmpeg library version.
*
* @return MobileFFmpeg version
*/
public static String getVersion() {
if (AbiDetect.isNativeLTSBuild()) {
return String.format("%s-lts", getNativeVersion());
} else {
return getNativeVersion();
}
}
/**
* <p>Returns whether MobileFFmpeg release is a long term release or not.
*
* @return YES or NO
*/
public static boolean isLTSBuild() {
return AbiDetect.isNativeLTSBuild();
}
/**
* <p>Returns MobileFFmpeg library build date.
*
* @return MobileFFmpeg library build date
*/
public static String getBuildDate() {
return getNativeBuildDate();
}
/**
* <p>Returns return code of last executed command.
*
* @return return code of last executed command
* @since 3.0
*/
public static int getLastReturnCode() {
return lastReturnCode;
}
/**
* <p>Returns log output of last executed single FFmpeg/FFprobe command.
*
* <p>This method does not support executing multiple concurrent commands. If you execute
* multiple commands at the same time, this method will return output from all executions.
*
* <p>Please note that disabling redirection using {@link Config#disableRedirection()} method
* also disables this functionality.
*
* @return output of the last executed command
* @since 3.0
*/
public static String getLastCommandOutput() {
String nativeLastCommandOutput = getNativeLastCommandOutput();
if (nativeLastCommandOutput != null) {
// REPLACING CH(13) WITH CH(10)
nativeLastCommandOutput = nativeLastCommandOutput.replace('\r', '\n');
}
return nativeLastCommandOutput;
}
/**
* <p>Prints the output of the last executed FFmpeg/FFprobe command to the Logcat at the
* specified priority.
*
* <p>This method does not support executing multiple concurrent commands. If you execute
* multiple commands at the same time, this method will print output from all executions.
*
* @param logPriority one of {@link Log#VERBOSE}, {@link Log#DEBUG}, {@link Log#INFO},
* {@link Log#WARN}, {@link Log#ERROR}, {@link Log#ASSERT}
* @since 4.3
*/
public static void printLastCommandOutput(int logPriority) {
final int LOGGER_ENTRY_MAX_LEN = 4 * 1000;
String buffer = getLastCommandOutput();
do {
if (buffer.length() <= LOGGER_ENTRY_MAX_LEN) {
Log.println(logPriority, Config.TAG, buffer);
buffer = "";
} else {
final int index = buffer.substring(0, LOGGER_ENTRY_MAX_LEN).lastIndexOf('\n');
if (index < 0) {
Log.println(logPriority, Config.TAG, buffer.substring(0, LOGGER_ENTRY_MAX_LEN));
buffer = buffer.substring(LOGGER_ENTRY_MAX_LEN);
} else {
Log.println(logPriority, Config.TAG, buffer.substring(0, index));
buffer = buffer.substring(index);
}
}
} while (buffer.length() > 0);
}
/**
* Updates return code value for the last executed command.
*
* @param newLastReturnCode new last return code value
*/
static void setLastReturnCode(int newLastReturnCode) {
lastReturnCode = newLastReturnCode;
}
/**
* <p>Enables native redirection. Necessary for log and statistics callback functions.
*/
private native static void enableNativeRedirection();
/**
* <p>Disables native redirection
*/
private native static void disableNativeRedirection();
/**
* Sets native log level
*
* @param level log level
*/
private native static void setNativeLogLevel(int level);
/**
* Returns native log level.
*
* @return log level
*/
private native static int getNativeLogLevel();
/**
* <p>Returns FFmpeg version bundled within the library natively.
*
* @return FFmpeg version
*/
native static String getNativeFFmpegVersion();
/**
* <p>Returns MobileFFmpeg library version natively.
*
* @return MobileFFmpeg version
*/
native static String getNativeVersion();
/**
* <p>Synchronously executes FFmpeg natively with arguments provided.
*
* @param arguments FFmpeg command options/arguments as string array
* @return zero on successful execution, 255 on user cancel and non-zero on error
*/
native static int nativeFFmpegExecute(final String[] arguments);
/**
* <p>Cancels an ongoing FFmpeg operation natively. This function does not wait for termination
* to complete and returns immediately.
*/
native static void nativeFFmpegCancel();
/**
* <p>Synchronously executes FFprobe natively with arguments provided.
*
* @param arguments FFprobe command options/arguments as string array
* @return zero on successful execution, 255 on user cancel and non-zero on error
*/
native static int nativeFFprobeExecute(final String[] arguments);
/**
* <p>Creates natively a new named pipe to use in <code>FFmpeg</code> operations.
*
* <p>Please note that creator is responsible of closing created pipes.
*
* @param ffmpegPipePath full path of ffmpeg pipe
* @return zero on successful creation, non-zero on error
*/
native static int registerNewNativeFFmpegPipe(final String ffmpegPipePath);
/**
* <p>Returns MobileFFmpeg library build date natively.
*
* @return MobileFFmpeg library build date
*/
native static String getNativeBuildDate();
/**
* <p>Sets an environment variable natively.
*
* @param variableName environment variable name
* @param variableValue environment variable value
* @return zero on success, non-zero on error
*/
public native static int setNativeEnvironmentVariable(final String variableName, final String variableValue);
/**
* <p>Returns log output of the last executed single command natively.
*
* @return output of the last executed single command
*/
native static String getNativeLastCommandOutput();
}
@@ -19,15 +19,16 @@
package com.arthenica.mobileffmpeg;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Main class for FFmpeg operations. Provides {@link #execute(String...)} method to execute
* FFmpeg commands.
* <pre>
* int rc = FFmpeg.execute("-i", "file1.mp4", "-c:v", "libxvid", "file1.avi");
* Log.i(Log.TAG, String.format("Command execution %s.", (rc == 0?"completed successfully":"failed with rc=" + rc));
* int rc = FFmpeg.execute("-i file1.mp4 -c:v libxvid file1.avi");
* Log.i(Config.TAG, String.format("Command execution %s.", (rc == 0?"completed successfully":"failed with rc=" + rc));
* </pre>
* <p>Note that it is recommended to call {@link #shutdown()} method before terminating your
* Android app.
*
* @author Taner Sener
* @since v1.0
@@ -35,33 +36,8 @@ package com.arthenica.mobileffmpeg;
public class FFmpeg {
static {
final Abi abi = Abi.from(AbiDetect.getAbi());
String abiName = abi.getName();
Log.enableCollectingStdOutErr();
android.util.Log.i(Log.TAG, "Loading mobile-ffmpeg.");
/*
* NEON supported arm-v7a library has a different name
*/
boolean nativeLibraryLoaded = false;
if (abi == Abi.ABI_ARMV7A_NEON) {
try {
System.loadLibrary("mobileffmpeg-armv7a-neon");
android.util.Log.i(Log.TAG, String.format("Loaded mobile-ffmpeg-%s-%s.", abiName, getVersion()));
nativeLibraryLoaded = true;
} catch (UnsatisfiedLinkError e) {
android.util.Log.i(Log.TAG, "NEON supported armeabi-v7a library not found. Loading default armeabi-v7a library.", e);
abiName = Abi.ABI_ARMV7A.getName();
}
}
if (!nativeLibraryLoaded) {
System.loadLibrary("mobileffmpeg");
android.util.Log.i(Log.TAG, String.format("Loaded mobile-ffmpeg-%s-%s.", abiName, getVersion()));
}
AbiDetect.class.getName();
Config.class.getName();
}
/**
@@ -70,41 +46,111 @@ public class FFmpeg {
private FFmpeg() {
}
/**
* <p>Returns FFmpeg version bundled within the library.
*
* @return FFmpeg version
*/
public native static String getFFmpegVersion();
/**
* <p>Returns MobileFFmpeg library version.
*
* @return MobileFFmpeg version
*/
public native static String getVersion();
/**
* <p>Synchronously executes FFmpeg with arguments provided.
*
* @param arguments FFmpeg command options/arguments
* @return zero on successful execution, non-zero on error
* @param arguments FFmpeg command options/arguments as string array
* @return zero on successful execution, 255 on user cancel and non-zero on error
*/
public native static int execute(final String ... arguments);
public static int execute(final String[] arguments) {
final int lastReturnCode = Config.nativeFFmpegExecute(arguments);
/**
* <p>Shuts down library capabilities.
*/
public static void shutdown() {
Log.disableCollectingStdOutErr();
Config.setLastReturnCode(lastReturnCode);
return lastReturnCode;
}
/**
* <p>Overrides default {@link Object#finalize()} method.
* <p>Synchronously executes FFmpeg command provided. Command is split into arguments using
* provided delimiter character.
*
* @param command FFmpeg command
* @param delimiter delimiter used to split arguments
* @return zero on successful execution, 255 on user cancel and non-zero on error
* @since 3.0
* @deprecated argument splitting mechanism used in this method is pretty simple and prone to
* errors. Consider using a more advanced method like {@link #execute(String)} or
* {@link #execute(String[])}
*/
@Override
protected void finalize() {
shutdown();
public static int execute(final String command, final String delimiter) {
return execute((command == null) ? new String[]{""} : command.split((delimiter == null) ? " " : delimiter));
}
/**
* <p>Synchronously executes FFmpeg command provided. Space character is used to split command
* into arguments. You can use single and double quote characters to specify arguments inside
* your command.
*
* @param command FFmpeg command
* @return zero on successful execution, 255 on user cancel and non-zero on error
*/
public static int execute(final String command) {
return execute(parseArguments(command));
}
/**
* <p>Cancels an ongoing operation. This function does not wait for termination to complete and
* returns immediately.
*/
public static void cancel() {
Config.nativeFFmpegCancel();
}
/**
* <p>Parses the given command into arguments.
*
* @param command string command
* @return array of arguments
*/
static String[] parseArguments(final String command) {
final List<String> argumentList = new ArrayList<>();
StringBuilder currentArgument = new StringBuilder();
boolean singleQuoteStarted = false;
boolean doubleQuoteStarted = false;
for (int i = 0; i < command.length(); i++) {
final Character previousChar;
if (i > 0) {
previousChar = command.charAt(i - 1);
} else {
previousChar = null;
}
final char currentChar = command.charAt(i);
if (currentChar == ' ') {
if (singleQuoteStarted || doubleQuoteStarted) {
currentArgument.append(currentChar);
} else if (currentArgument.length() > 0) {
argumentList.add(currentArgument.toString());
currentArgument = new StringBuilder();
}
} else if (currentChar == '\'' && (previousChar == null || previousChar != '\\')) {
if (singleQuoteStarted) {
singleQuoteStarted = false;
} else if (doubleQuoteStarted) {
currentArgument.append(currentChar);
} else {
singleQuoteStarted = true;
}
} else if (currentChar == '\"' && (previousChar == null || previousChar != '\\')) {
if (doubleQuoteStarted) {
doubleQuoteStarted = false;
} else if (singleQuoteStarted) {
currentArgument.append(currentChar);
} else {
doubleQuoteStarted = true;
}
} else {
currentArgument.append(currentChar);
}
}
if (currentArgument.length() > 0) {
argumentList.add(currentArgument.toString());
}
return argumentList.toArray(new String[0]);
}
}
@@ -0,0 +1,526 @@
/*
* Copyright (c) 2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import android.content.Context;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Surface;
import com.arthenica.mobileffmpeg.player.AudioHandler;
import com.arthenica.mobileffmpeg.player.ControllerHandler;
import com.arthenica.mobileffmpeg.player.PlayerManager;
import java.io.IOException;
import java.io.InputStream;
import static com.arthenica.mobileffmpeg.Config.TAG;
public class FFplay {
private static final boolean enabled;
private static boolean separateMouseAndTouch;
private static AudioHandler audioHandler;
private static ControllerHandler controllerHandler;
private static PlayerManager playerManager;
static {
/* MOUSE AND TOUCH IS THE SAME DEVICE BY DEFAULT */
separateMouseAndTouch = false;
/* FFPLAY DEPENDS ON SDL. CHECK WHETHER IT IS ENABLED OR NOT */
if (Config.getExternalLibraries().contains("sdl2")) {
init();
/* FFPLAY METHODS ARE ENABLED ONLY IF INITIALIZATION COMPLETES SUCCESSFULLY */
enabled = true;
} else {
enabled = false;
}
}
static void init() {
// ENABLE SDL FIRST
nativeSDLInit();
// COMPLETE OTHER COMPONENTS AFTER
nativePlayerInit();
nativeAudioInit();
nativeControllerInit();
}
/**
* <p>Synchronously executes FFplay with arguments provided.
*
* @param arguments FFplay command options/arguments as string array
* @return zero on successful execution, 255 on user cancel and non-zero on error
*/
public static int execute(final String[] arguments) {
if (enabled) {
return nativePlayerRun(arguments);
} else {
throw new RuntimeException("sdl not found. FFplay requires sdl to run.");
}
}
public static boolean isSeparateMouseAndTouch() {
return separateMouseAndTouch;
}
public static void setSeparateMouseAndTouch(boolean separateMouseAndTouch) {
FFplay.separateMouseAndTouch = separateMouseAndTouch;
}
public static AudioHandler getAudioHandler() {
return audioHandler;
}
public static ControllerHandler getControllerHandler() {
return controllerHandler;
}
public static PlayerManager getPlayerManager() {
return playerManager;
}
public static void setAudioHandler(final AudioHandler newAudioHandler) {
audioHandler = newAudioHandler;
}
public static void setControllerManager(final ControllerHandler newControllerHandler) {
controllerHandler = newControllerHandler;
}
public static void setPlayerManager(PlayerManager newPlayerManager) {
playerManager = newPlayerManager;
}
public static String playerNativeGetHint(final String name) {
return nativePlayerNativeGetHint(name);
}
public static void inputSetComposingText(final String text, final int newCursorPosition) {
nativeInputSetComposingText(text, newCursorPosition);
}
public static void inputGenerateScancodeForUnichar(final char c) {
nativeInputGenerateScancodeForUnichar(c);
}
public static void inputCommitText(String text, int newCursorPosition) {
nativeInputCommitText(text, newCursorPosition);
}
public static void playerNativeSetenv(final String name, final String value) {
//@TODO We already have this method under Config
nativePlayerNativeSetenv(name, value);
}
public static void playerOnDropFile(final String filename) {
nativePlayerOnDropFile(filename);
}
public static void playerNativeLowMemory() {
nativePlayerNativeLowMemory();
}
public static void playerNativeQuit() {
nativePlayerNativeQuit();
}
public static void playerNativePause() {
nativePlayerNativePause();
}
public static void playerNativeResume() {
nativePlayerNativeResume();
}
public static void playerOnKeyDown(final int keyCode) {
nativePlayerOnKeyDown(keyCode);
}
public static void playerOnKeyUp(final int keyCode) {
nativePlayerOnKeyUp(keyCode);
}
public static void playerOnKeyboardFocusLost() {
nativePlayerOnKeyboardFocusLost();
}
public static void playerOnClipboardChanged() {
nativePlayerOnClipboardChanged();
}
public static void playerOnSurfaceChanged() {
nativePlayerOnSurfaceChanged();
}
public static void playerOnSurfaceDestroyed() {
nativePlayerOnSurfaceDestroyed();
}
public static void playerOnMouse(final int button, final int action, final float x, final float y) {
nativePlayerOnMouse(button, action, x, y);
}
public static int controllerAddHaptic(final int deviceId, final String name) {
return nativeControllerAddHaptic(deviceId, name);
}
public static int controllerRemoveHaptic(final int deviceId) {
return nativeControllerRemoveHaptic(deviceId);
}
public static int controllerAddJoystick(final int deviceId, final String name, final String desc, final int isAccelerometer, final int nButtons, final int nAxes, final int nHats, final int nBalls) {
return nativeControllerAddJoystick(deviceId, name, desc, isAccelerometer, nButtons, nAxes, nHats, nBalls);
}
public static int controllerRemoveJoystick(final int deviceId) {
return nativeControllerRemoveJoystick(deviceId);
}
public static void controllerOnJoy(final int deviceId, final int axis, final float value) {
nativeControllerOnJoy(deviceId, axis, value);
}
public static void controllerOnHat(final int deviceId, final int hatId, final int x, final int y) {
nativeControllerOnHat(deviceId, hatId, x, y);
}
public static void playerOnResize(final int x, final int y, final int format, final float rate) {
nativePlayerOnResize(x, y, format, rate);
}
public static int controllerOnPadDown(final int deviceId, final int keycode) {
return nativeControllerOnPadDown(deviceId, keycode);
}
public static int controllerOnPadUp(final int deviceId, final int keycode) {
return nativeControllerOnPadUp(deviceId, keycode);
}
public static void playerOnTouch(final int touchDevId, final int pointerFingerId, final int action, final float x, final float y, final float p) {
nativePlayerOnTouch(touchDevId, pointerFingerId, action, x, y, p);
}
public static void playerOnAccel(final float x, final float y, final float z) {
nativePlayerOnAccel(x, y, z);
}
/* AUDIO FUNCTIONS CALLED BY NATIVE THREADS */
static int audioOpen(final int sampleRate, final boolean is16Bit, final boolean isStereo, final int desiredFrames) {
if (audioHandler != null) {
return audioHandler.audioOpen(sampleRate, is16Bit, isStereo, desiredFrames);
} else {
return -1;
}
}
static void audioWriteShortBuffer(final short[] buffer) {
if (audioHandler != null) {
audioHandler.audioWriteShortBuffer(buffer);
}
}
static void audioWriteByteBuffer(final byte[] buffer) {
if (audioHandler != null) {
audioHandler.audioWriteByteBuffer(buffer);
}
}
static int captureOpen(final int sampleRate, final boolean is16Bit, final boolean isStereo, final int desiredFrames) {
if (audioHandler != null) {
return audioHandler.captureOpen(sampleRate, is16Bit, isStereo, desiredFrames);
} else {
return -1;
}
}
static int captureReadShortBuffer(final short[] buffer, final boolean blocking) {
if (audioHandler != null) {
return audioHandler.captureReadShortBuffer(buffer, blocking);
} else {
return -1;
}
}
static int captureReadByteBuffer(final byte[] buffer, final boolean blocking) {
if (audioHandler != null) {
return audioHandler.captureReadByteBuffer(buffer, blocking);
} else {
return -1;
}
}
static void audioClose() {
if (audioHandler != null) {
audioHandler.audioClose();
}
}
static void captureClose() {
if (audioHandler != null) {
audioHandler.captureClose();
}
}
/* CONTROLLER FUNCTIONS CALLED BY NATIVE THREADS */
static void pollInputDevices() {
if (controllerHandler != null) {
controllerHandler.pollInputDevices();
}
}
static void pollHapticDevices() {
if (controllerHandler != null) {
controllerHandler.pollHapticDevices();
}
}
static void hapticRun(final int deviceId, final int length) {
if (controllerHandler != null) {
controllerHandler.hapticRun(deviceId, length);
}
}
/* PLAYER FUNCTIONS CALLED BY NATIVE THREADS */
static boolean setActivityTitle(final String title) {
if (playerManager != null) {
return playerManager.setActivityTitle(title);
} else {
return true;
}
}
static void setWindowStyle(final boolean fullScreen) {
if (playerManager != null) {
playerManager.setWindowStyle(fullScreen);
}
}
static void setOrientation(final int w, final int h, final boolean resizable, final String hint) {
if (playerManager != null) {
playerManager.setOrientation(w, h, resizable, hint);
}
}
static boolean isScreenKeyboardShown() {
if (playerManager != null) {
return playerManager.isScreenKeyboardShown();
} else {
return false;
}
}
static boolean sendMessage(final int command, final int param) {
if (playerManager != null) {
return playerManager.sendMessage(command, param);
} else {
return false;
}
}
static Context getContext() {
if (playerManager != null) {
return playerManager.getContext();
} else {
return null;
}
}
static boolean isAndroidTV() {
if (playerManager != null) {
return playerManager.isAndroidTV();
} else {
return false;
}
}
static DisplayMetrics getDisplayDPI() {
if (playerManager != null) {
return playerManager.getDisplayDPI();
} else {
return null;
}
}
static boolean getManifestEnvironmentVariables() {
if (playerManager != null) {
return playerManager.getManifestEnvironmentVariables();
} else {
return false;
}
}
static boolean showTextInput(final int x, final int y, final int w, final int h) {
if (playerManager != null) {
return playerManager.showTextInput(x, y, w, h);
} else {
return false;
}
}
static Surface getNativeSurface() {
if (playerManager != null) {
return playerManager.getNativeSurface();
} else {
return null;
}
}
static int[] inputGetInputDeviceIds(final int sources) {
if (playerManager != null) {
return playerManager.inputGetInputDeviceIds(sources);
} else {
return new int[0];
}
}
static boolean clipboardHasText() {
if (playerManager != null) {
return playerManager.clipboardHasText();
} else {
return false;
}
}
static String clipboardGetText() {
if (playerManager != null) {
return playerManager.clipboardGetText();
} else {
return "";
}
}
static void clipboardSetText(final String string) {
if (playerManager != null) {
playerManager.clipboardSetText(string);
}
}
static InputStream openAPKExpansionInputStream(final String fileName) throws IOException {
Log.e(TAG, "Opening APK Expansion is not supported.");
return null;
}
static int messageBoxShowMessageBox(final int flags, final String title, final String message, final int[] buttonFlags, final int[] buttonIds, final String[] buttonTexts, final int[] colors) {
if (playerManager != null) {
return playerManager.showMessageBox(flags, title, message, buttonFlags, buttonIds, buttonTexts, colors);
} else {
return -1;
}
}
/* NATIVE SDL FUNCTIONS */
/**
* <p>Initializes SDL for FFplay. It must be called before other SDL functions.
*/
native static void nativeSDLInit();
/* NATIVE PLAYER FUNCTIONS */
native static int nativePlayerInit();
/**
* <p>Synchronously executes FFplay natively with arguments provided.
*
* @param arguments FFplay command options/arguments as string array
* @return zero on successful execution, 255 on user cancel and non-zero on error
*/
native static int nativePlayerRun(final String[] arguments);
native static void nativePlayerNativeLowMemory();
native static void nativePlayerNativeQuit();
native static void nativePlayerNativePause();
native static void nativePlayerNativeResume();
native static void nativePlayerOnDropFile(final String filename);
native static void nativePlayerOnResize(final int x, final int y, final int format, final float rate);
native static void nativePlayerOnKeyDown(final int keyCode);
native static void nativePlayerOnKeyUp(final int keyCode);
native static void nativePlayerOnKeyboardFocusLost();
native static void nativePlayerOnMouse(final int button, final int action, final float x, final float y);
native static void nativePlayerOnTouch(final int touchDevId, final int pointerFingerId, final int action, final float x, final float y, final float p);
native static void nativePlayerOnAccel(final float x, final float y, final float z);
native static void nativePlayerOnClipboardChanged();
native static void nativePlayerOnSurfaceChanged();
native static void nativePlayerOnSurfaceDestroyed();
native static String nativePlayerNativeGetHint(final String name);
native static void nativePlayerNativeSetenv(final String name, final String value);
/* NATIVE AUDIO FUNCTIONS */
native static int nativeAudioInit();
/* NATIVE CONTROLLER FUNCTIONS */
native static int nativeControllerInit();
native static int nativeControllerAddJoystick(final int deviceId, final String name, final String desc, final int isAccelerometer, final int nButtons, final int nAxes, final int nHats, final int nBalls);
native static int nativeControllerRemoveJoystick(final int deviceId);
native static int nativeControllerAddHaptic(final int deviceId, final String name);
native static int nativeControllerRemoveHaptic(final int deviceId);
native static int nativeControllerOnPadDown(final int deviceId, final int keycode);
native static int nativeControllerOnPadUp(final int deviceId, final int keycode);
native static void nativeControllerOnJoy(final int deviceId, final int axis, final float value);
native static void nativeControllerOnHat(final int deviceId, final int hatId, final int x, final int y);
/* NATIVE INPUT FUNCTIONS */
native static void nativeInputCommitText(final String text, final int newCursorPosition);
native static void nativeInputGenerateScancodeForUnichar(final char c);
native static void nativeInputSetComposingText(final String text, final int newCursorPosition);
}
@@ -0,0 +1,114 @@
/*
* Copyright (c) 2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import android.util.Log;
/**
* <p>Main class for FFprobe operations. Provides {@link #execute(String...)} method to execute
* FFprobe commands.
* <pre>
* int rc = FFprobe.execute("-hide_banner -v error -show_entries format=size -of default=noprint_wrappers=1 file1.mp4");
* Log.i(Config.TAG, String.format("Command execution %s.", (rc == 0?"completed successfully":"failed with rc=" + rc));
* </pre>
*
* @author Taner Sener
* @since v4.3.1
*/
public class FFprobe {
static {
AbiDetect.class.getName();
Config.class.getName();
}
/**
* Default constructor hidden.
*/
private FFprobe() {
}
/**
* <p>Synchronously executes FFprobe with arguments provided.
*
* @param arguments FFprobe command options/arguments as string array
* @return zero on successful execution, 255 on user cancel and non-zero on error
*/
public static int execute(final String[] arguments) {
final int lastReturnCode = Config.nativeFFprobeExecute(arguments);
Config.setLastReturnCode(lastReturnCode);
return lastReturnCode;
}
/**
* <p>Synchronously executes FFprobe command provided. Space character is used to split command
* into arguments. You can use single and double quote characters to specify arguments inside
* your command.
*
* @param command FFprobe command
* @return zero on successful execution, 255 on user cancel and non-zero on error
*/
public static int execute(final String command) {
return execute(FFmpeg.parseArguments(command));
}
/**
* <p>Returns media information for given file.
*
* <p>This method does not support executing multiple concurrent operations. If you execute
* multiple operations (execute or getMediaInformation) at the same time, the response of this
* method is not predictable.
*
* @param path path or uri of media file
* @return media information
* @since 3.0
*/
public static MediaInformation getMediaInformation(final String path) {
final int rc = execute(new String[]{"-v", "info", "-hide_banner", "-i", path});
if (rc == 0) {
return MediaInformationParser.from(Config.getLastCommandOutput());
} else {
Log.i(Config.TAG, Config.getLastCommandOutput());
return null;
}
}
/**
* <p>Returns media information for given file.
*
* <p>This method does not support executing multiple concurrent operations. If you execute
* multiple operations (execute or getMediaInformation) at the same time, the response of this
* method is not predictable.
*
* @param path path or uri of media file
* @param timeout complete timeout
* @return media information
* @since 3.0
* @deprecated this method is deprecated since v4.3.1. You can still use this method but
* <code>timeout</code> parameter is not effective anymore.
*/
public static MediaInformation getMediaInformation(final String path, final Long timeout) {
return getMediaInformation(path);
}
}
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
/**
* <p>Helper enumeration type for log levels.
*
* @author Taner Sener
* @since v2.1
*/
public enum Level {
/**
* This log level is defined by MobileFFmpeg. It is used to specify logs printed to stderr by
* ffmpeg. Logs that has this level are not filtered and always redirected.
*
* @since 4.3.1
*/
AV_LOG_STDERR(-16),
/**
* Print no output.
*/
AV_LOG_QUIET(-8),
/**
* Something went really wrong and we will crash now.
*/
AV_LOG_PANIC(0),
/**
* Something went wrong and recovery is not possible.
* For example, no header was found for a format which depends
* on headers or an illegal combination of parameters is used.
*/
AV_LOG_FATAL(8),
/**
* Something went wrong and cannot losslessly be recovered.
* However, not all future data is affected.
*/
AV_LOG_ERROR(16),
/**
* Something somehow does not look correct. This may or may not
* lead to problems. An example would be the use of '-vstrict -2'.
*/
AV_LOG_WARNING(24),
/**
* Standard information.
*/
AV_LOG_INFO(32),
/**
* Detailed information.
*/
AV_LOG_VERBOSE(40),
/**
* Stuff which is only useful for libav* developers.
*/
AV_LOG_DEBUG(48),
/**
* Extremely verbose debugging, useful for libav* development.
*/
AV_LOG_TRACE(56);
private int value;
/**
* <p>Returns enumeration defined by value.
*
* @param value level value
* @return enumeration defined by value
*/
public static Level from(final int value) {
if (value == AV_LOG_STDERR.getValue()) {
return AV_LOG_STDERR;
} else if (value == AV_LOG_QUIET.getValue()) {
return AV_LOG_QUIET;
} else if (value == AV_LOG_PANIC.getValue()) {
return AV_LOG_PANIC;
} else if (value == AV_LOG_FATAL.getValue()) {
return AV_LOG_FATAL;
} else if (value == AV_LOG_ERROR.getValue()) {
return AV_LOG_ERROR;
} else if (value == AV_LOG_WARNING.getValue()) {
return AV_LOG_WARNING;
} else if (value == AV_LOG_INFO.getValue()) {
return AV_LOG_INFO;
} else if (value == AV_LOG_VERBOSE.getValue()) {
return AV_LOG_VERBOSE;
} else if (value == AV_LOG_DEBUG.getValue()) {
return AV_LOG_DEBUG;
} else {
return AV_LOG_TRACE;
}
}
/**
* Returns level value.
*
* @return level value
*/
public int getValue() {
return value;
}
/**
* Creates new enum.
*
* @param value level value
*/
Level(final int value) {
this.value = value;
}
}
@@ -1,107 +0,0 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import android.arch.core.util.Function;
/**
* <p>This class is used to process stdout and stderr logs from native libraries.
*
* <p>By default stdout and stderr is redirected to <code>/dev/null</code> in Android. This class
* redirects these streams to Logcat in order to view logs printed by FFmpeg native libraries.
*
* <p>Alternatively, it is possible not to print messages to Logcat and pass them to a callback
* function. This function can decide whether to print these logs or ignore them according to its
* own rules.
*
* @author Taner Sener
* @since v1.0
*/
public class Log {
/**
* Defines tag used for logging.
*/
public static final String TAG = "mobile-ffmpeg";
private static Function<byte[], Void> callbackFunction;
static {
System.loadLibrary("ffmpeglog");
}
/**
* Default constructor hidden.
*/
private Log() {
}
/**
* <p>Enables redirecting stdout and stderr.
*/
public static void enableCollectingStdOutErr() {
startNativeCollector();
}
/**
* <p>Disables redirecting stdout and stderr.
*/
public static void disableCollectingStdOutErr() {
stopNativeCollector();
}
/**
* <p>Sets a callback function to receive logs from FFmpeg native libraries.
*
* @param newCallbackFunction callback to receive logs
*/
public static void enableCallbackFunction(final Function<byte[], Void> newCallbackFunction) {
callbackFunction = newCallbackFunction;
}
/**
* <p>Main method called by JNI part to redirect log messages. It is not designed to be called
* manually by Java classes.
*
* @param logMessage log message
*/
public static void log(final byte[] logMessage) {
if (callbackFunction != null) {
callbackFunction.apply(logMessage);
} else {
android.util.Log.d(TAG, new String(logMessage));
}
}
/**
* <p>Starts native log collector.
*
* @return zero on success, non-zero if an error occurs
*/
public static native int startNativeCollector();
/**
* <p>Stops native log collector.
*
* @return zero on success, non-zero if an error occurs
*/
public static native int stopNativeCollector();
}
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
/**
* <p>Represents a callback function to redirect logs.
*
* @author Taner Sener
* @since v2.1
*/
@FunctionalInterface
public interface LogCallback {
void apply(final LogMessage message);
}
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
/**
* <p>Represents a redirected log message.
*
* @author Taner Sener
* @since v2.1
*/
public class LogMessage {
private final Level level;
private final String text;
public LogMessage(final Level level, final String text) {
this.level = level;
this.text = text;
}
public Level getLevel() {
return level;
}
public String getText() {
return text;
}
}
@@ -0,0 +1,225 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Media information class.
*
* @since 3.0
*/
public class MediaInformation {
/**
* Format
*/
private String format;
/**
* Path
*/
private String path;
/**
* Duration, in milliseconds
*/
private Long duration;
/**
* Start time, in milliseconds
*/
private Long startTime;
/**
* Bitrate, kb/s
*/
private Long bitrate;
/**
* Metadata map
*/
private Map<String, String> metadata;
/**
* List of streams
*/
private List<StreamInformation> streams;
/**
* Raw unparsed media information
*/
private String rawInformation;
public MediaInformation() {
this.metadata = new HashMap<>();
this.streams = new ArrayList<>();
}
/**
* Returns format.
*
* @return media format
*/
public String getFormat() {
return format;
}
/**
* Sets media format.
*
* @param format media format
*/
public void setFormat(String format) {
this.format = format;
}
/**
* Returns path.
*
* @return media path
*/
public String getPath() {
return path;
}
/**
* Sets path.
*
* @param path media path
*/
public void setPath(String path) {
this.path = path;
}
/**
* Returns duration.
*
* @return media duration in milliseconds
*/
public Long getDuration() {
return duration;
}
/**
* Sets duration.
*
* @param duration media duration in milliseconds
*/
public void setDuration(Long duration) {
this.duration = duration;
}
/**
* Returns start time.
*
* @return media start time in milliseconds
*/
public Long getStartTime() {
return startTime;
}
/**
* Sets start time.
*
* @param startTime media start time in milliseconds
*/
public void setStartTime(Long startTime) {
this.startTime = startTime;
}
/**
* Returns bitrate.
*
* @return media bitrate in kb/s
*/
public Long getBitrate() {
return bitrate;
}
/**
* Sets bitrate.
*
* @param bitrate media bitrate in kb/s
*/
public void setBitrate(Long bitrate) {
this.bitrate = bitrate;
}
/**
* Returns unparsed media information.
*
* @return unparsed media information data
*/
public String getRawInformation() {
return rawInformation;
}
/**
* Sets unparsed media information.
*
* @param rawInformation unparsed media information data
*/
public void setRawInformation(String rawInformation) {
this.rawInformation = rawInformation;
}
/**
* Adds metadata.
*
* @param key metadata key
* @param value metadata value
*/
public void addMetadata(String key, String value) {
this.metadata.put(key, value);
}
/**
* Returns all metadata entries.
*
* @return set of metadata entries
*/
public Set<Map.Entry<String, String>> getMetadataEntries() {
return this.metadata.entrySet();
}
/**
* Adds new stream.
*
* @param stream new stream information
*/
public void addStream(StreamInformation stream) {
this.streams.add(stream);
}
/**
* Returns all streams.
*
* @return list of streams
*/
public List<StreamInformation> getStreams() {
return streams;
}
}
@@ -0,0 +1,525 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import android.util.Log;
import com.arthenica.mobileffmpeg.util.Pair;
import com.arthenica.mobileffmpeg.util.Trio;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* Helper class for {@link MediaInformation}.
*
* @since 3.0
*/
public class MediaInformationParser {
public static SimpleDateFormat DURATION_FORMAT;
public static Date REFERENCE_DURATION;
static {
try {
DURATION_FORMAT = new SimpleDateFormat("kk:mm:ss", Locale.getDefault());
REFERENCE_DURATION = DURATION_FORMAT.parse("00:00:00");
} catch (final ParseException e) {
Log.i(Config.TAG, "Preparing duration reference failed.", e);
DURATION_FORMAT = null;
REFERENCE_DURATION = null;
}
}
/**
* Parses media information command output and builds a {@link MediaInformation} instance.
*
* @param rawCommandOutput media information command output
* @return parsed instance of null if a parsing error occurs
*/
public static MediaInformation from(final String rawCommandOutput) {
final MediaInformation mediaInformation = new MediaInformation();
if (rawCommandOutput != null) {
final String[] split = rawCommandOutput.split("\n");
boolean metadata = false;
boolean sidedata = false;
StreamInformation lastCreatedStream = null;
final StringBuilder rawInformation = new StringBuilder();
for (final String outputLine : split) {
if (outputLine.startsWith("[")) {
metadata = false;
sidedata = false;
continue;
}
final String trimmedLine = outputLine.trim();
if (trimmedLine.startsWith("Input")) {
metadata = false;
sidedata = false;
lastCreatedStream = null;
Pair<String, String> pair = parseInputBlock(trimmedLine);
mediaInformation.setFormat(pair.getFirst());
mediaInformation.setPath(pair.getSecond());
} else if (trimmedLine.startsWith("Duration")) {
metadata = false;
sidedata = false;
lastCreatedStream = null;
Trio<Long, Long, Long> trio = parseDurationBlock(trimmedLine);
mediaInformation.setDuration(trio.getFirst());
mediaInformation.setStartTime(trio.getSecond());
mediaInformation.setBitrate(trio.getThird());
} else if (trimmedLine.toLowerCase(Locale.ENGLISH).startsWith("metadata")) {
sidedata = false;
metadata = true;
} else if (trimmedLine.toLowerCase(Locale.ENGLISH).startsWith("side data")) {
metadata = false;
sidedata = true;
} else if (trimmedLine.startsWith("Stream mapping") || trimmedLine.startsWith("Press [q] to stop") || trimmedLine.startsWith("Output")) {
break;
} else if (trimmedLine.startsWith("Stream")) {
metadata = false;
sidedata = false;
lastCreatedStream = MediaInformationParser.parseStreamBlock(trimmedLine);
mediaInformation.addStream(lastCreatedStream);
} else if (metadata) {
Pair<String, String> pair = parseMetadataBlock(trimmedLine);
if (pair.getFirst() != null && pair.getSecond() != null) {
if (lastCreatedStream != null) {
lastCreatedStream.addMetadata(pair.getFirst(), pair.getSecond());
} else {
mediaInformation.addMetadata(pair.getFirst(), pair.getSecond());
}
}
} else if (sidedata) {
Pair<String, String> pair = parseMetadataBlock(trimmedLine);
if (pair.getFirst() != null && pair.getSecond() != null) {
if (lastCreatedStream != null) {
lastCreatedStream.addSidedata(pair.getFirst(), pair.getSecond());
}
}
}
rawInformation.append(outputLine);
rawInformation.append("\n");
}
mediaInformation.setRawInformation(rawInformation.toString());
}
return mediaInformation;
}
static Pair<String, String> parseInputBlock(final String input) {
String format = substring(input, ",", ", from", Collections.<String>emptyList());
String path = substring(input, "\'", "\'", Collections.<String>emptyList());
return new Pair<>(format, path);
}
static Trio<Long, Long, Long> parseDurationBlock(final String line) {
Long duration = parseDuration(substring(line, "Duration:", ",", Collections.singletonList("uration:")));
Long start = parseStartTime(substring(line, "start:", ",", Collections.singletonList("tart:")));
Long bitrate = toLongObject(substring(line, "bitrate:", Arrays.asList("itrate:", "kb/s")));
return new Trio<>(duration, start, bitrate);
}
static Pair<String, String> parseMetadataBlock(final String metadata) {
String key = null;
String value = null;
if (metadata != null) {
int index = metadata.indexOf(':');
if (index > -1) {
key = metadata.substring(0, index).trim();
value = metadata.substring(index + 1).trim();
}
}
return new Pair<>(key, value);
}
static StreamInformation parseStreamBlock(final String input) {
final StreamInformation streamInformation = new StreamInformation();
if (input != null) {
streamInformation.setIndex(parseStreamIndex(input));
int typeBlockStartIndex = index(input, ":", 0, 2);
if (typeBlockStartIndex > -1 && (typeBlockStartIndex < input.length())) {
String[] parts = input.substring(typeBlockStartIndex + 1).split(",");
String typePart = safeGet(parts, 0);
final String type = parseStreamType(typePart);
streamInformation.setType(type);
streamInformation.setCodec(parseStreamCodec(typePart));
streamInformation.setFullCodec(parseStreamFullCodec(typePart));
String part2 = safeGet(parts, 1);
String part3 = safeGet(parts, 2);
String part4 = safeGet(parts, 3);
String part5 = safeGet(parts, 4);
if ("video".equals(type)) {
int lastUsedPart = 1;
if (part2 != null) {
int pStart = count(part2, "(");
int pEnd = count(part2, ")");
while (pStart != pEnd) {
lastUsedPart++;
String newPart = safeGet(parts, lastUsedPart);
if (newPart == null) {
break;
}
part2 = String.format("%s,%s", part2, newPart);
pStart = count(part2, "(");
pEnd = count(part2, ")");
}
streamInformation.setFullFormat(part2.toLowerCase(Locale.getDefault()).trim());
streamInformation.setFormat(part2.replaceAll("\\(.*\\)", "").toLowerCase(Locale.getDefault()).trim());
}
lastUsedPart++;
String videoDimensionPart = safeGet(parts, lastUsedPart);
if (videoDimensionPart != null) {
String videoLayout = videoDimensionPart.toLowerCase(Locale.getDefault()).trim();
Pair<Long, Long> dimensions = parseVideoDimensions(videoLayout);
streamInformation.setWidth(dimensions.getFirst());
streamInformation.setHeight(dimensions.getSecond());
streamInformation.setSampleAspectRatio(parseVideoStreamSampleAspectRatio(videoLayout));
streamInformation.setDisplayAspectRatio(parseVideoStreamDisplayAspectRatio(videoLayout));
}
for (int i = lastUsedPart + 1; i < parts.length; i++) {
String part = parts[i].replaceAll("\\(.*\\)", "").toLowerCase(Locale.getDefault());
if (part.contains("kb/s")) {
streamInformation.setBitrate(toLongObject(part.replaceAll("kb/s", "").trim()));
} else if (part.contains("fps")) {
streamInformation.setAverageFrameRate(part.replaceAll("fps", "").trim());
} else if (part.contains("tbr")) {
streamInformation.setRealFrameRate(part.replaceAll("tbr", "").trim());
} else if (part.contains("tbn")) {
streamInformation.setTimeBase(part.replaceAll("tbn", "").trim());
} else if (part.contains("tbc")) {
streamInformation.setCodecTimeBase(part.replaceAll("tbc", "").trim());
}
}
} else if ("audio".equals(type)) {
if (part2 != null) {
streamInformation.setSampleRate(parseAudioStreamSampleRate(part2));
}
if (part3 != null) {
streamInformation.setChannelLayout(part3.toLowerCase(Locale.getDefault()).trim());
}
if (part4 != null) {
streamInformation.setSampleFormat(part4.toLowerCase(Locale.getDefault()).trim());
}
if (part5 != null) {
streamInformation.setBitrate(toLongObject(part5.toLowerCase(Locale.getDefault()).replaceAll("\\(.*\\)", "").replaceAll("kb/s", "").trim()));
}
} else if ("data".equals(type)) {
if (part2 != null) {
streamInformation.setBitrate(toLongObject(part2.toLowerCase(Locale.getDefault()).replaceAll("\\(.*\\)", "").replaceAll("kb/s", "").trim()));
}
}
}
}
return streamInformation;
}
static Pair<Long, Long> parseVideoDimensions(final String input) {
Long width = null;
Long height = null;
if (input != null) {
final String[] dimensions = input.toLowerCase(Locale.getDefault()).replaceAll("\\[.*\\]", "").trim().split("x");
width = toLongObject(safeGet(dimensions, 0));
height = toLongObject(safeGet(dimensions, 1));
}
return new Pair<>(width, height);
}
static String parseVideoStreamSampleAspectRatio(final String input) {
if (input != null) {
String[] parts = input.replaceAll("\\[", "").replaceAll("\\]", "").split(" ");
for (int i = 0; i < parts.length; i++) {
if (parts[i].toLowerCase(Locale.getDefault()).equals("sar")) {
return safeGet(parts, i + 1);
}
}
}
return null;
}
static String parseVideoStreamDisplayAspectRatio(final String input) {
if (input != null) {
String[] parts = input.replaceAll("\\[", "").replaceAll("\\]", "").split(" ");
for (int i = 0; i < parts.length; i++) {
if (parts[i].toLowerCase(Locale.getDefault()).equals("dar")) {
return safeGet(parts, i + 1);
}
}
}
return null;
}
static Long parseAudioStreamSampleRate(final String input) {
if (input != null) {
boolean khz = false;
boolean mhz = false;
String lowerCase = input.toLowerCase(Locale.getDefault());
if (lowerCase.contains("khz")) {
khz = true;
}
if (lowerCase.contains("mhz")) {
mhz = true;
}
String sampleRate = lowerCase
.replaceAll("khz", "")
.replaceAll("mhz", "")
.replaceAll("hz", "")
.trim();
if (khz) {
return 1000 * toLong(sampleRate);
} else if (mhz) {
return 1000000 * toLong(sampleRate);
} else {
return toLong(sampleRate);
}
}
return null;
}
static String parseStreamType(final String input) {
if (input != null) {
if (input.toLowerCase(Locale.getDefault()).contains("audio:")) {
return "audio";
} else if (input.toLowerCase(Locale.getDefault()).contains("video:")) {
return "video";
} else if (input.toLowerCase(Locale.getDefault()).contains("data:")) {
return "data";
}
}
return null;
}
static String parseStreamCodec(final String input) {
if (input != null) {
return input.toLowerCase(Locale.getDefault())
.replaceAll("\\(.*\\)", "")
.replaceAll("video:", "")
.replaceAll("audio:", "")
.replaceAll("data:", "")
.trim();
}
return null;
}
static String parseStreamFullCodec(final String input) {
if (input != null) {
return input.toLowerCase(Locale.getDefault())
.replaceAll("video:", "")
.replaceAll("audio:", "")
.replaceAll("data:", "")
.trim();
}
return null;
}
static Long parseStreamIndex(final String input) {
String substring = substring(input, "Stream #0:", ":", Collections.singletonList("tream #0"));
if (substring != null) {
// DISCARD PARANTHESIS
return toLongObject(substring
.replace(":", "")
.replaceAll("\\(.*\\)", ""));
}
return null;
}
static Long parseDuration(final String duration) {
if (duration == null || duration.equals("N/A")) {
return null;
}
try {
final Date calculated = DURATION_FORMAT.parse(duration);
long secondsPartInMilliseconds = calculated.getTime() - REFERENCE_DURATION.getTime();
int index = duration.indexOf('.');
if (index > -1) {
Long centiSeconds = toLong(duration.substring(index + 1));
secondsPartInMilliseconds += 10 * centiSeconds;
}
return secondsPartInMilliseconds;
} catch (final ParseException e) {
Log.d(Config.TAG, String.format("Parsing duration: %s failed.", duration), e);
return null;
}
}
static Long parseStartTime(final String startTime) {
if (startTime == null || startTime.equals("N/A")) {
return null;
}
try {
BigDecimal bigDecimal = new BigDecimal(startTime);
bigDecimal = bigDecimal.setScale(3, BigDecimal.ROUND_CEILING).multiply(new BigDecimal(1000));
return bigDecimal.longValue();
} catch (NumberFormatException e) {
Log.d(Config.TAG, String.format("Parsing startTime: %s failed.", startTime), e);
return null;
}
}
public static String substring(final String string, final String start, final String end, final List<String> ignoredTokens) {
String extractedSubstring = null;
if (string != null) {
int formatStart = string.indexOf(start);
if (formatStart > -1) {
int formatEnd = string.indexOf(end, formatStart + start.length());
if (formatEnd > -1) {
extractedSubstring = string.substring(formatStart + start.length(), formatEnd);
}
}
}
if ((ignoredTokens != null) && (extractedSubstring != null)) {
for (String token : ignoredTokens) {
extractedSubstring = extractedSubstring.replaceAll(token, "");
}
}
return (extractedSubstring == null) ? null : extractedSubstring.trim();
}
public static String substring(final String string, final String start, final List<String> ignoredTokens) {
String extractedSubstring = null;
if (string != null) {
int formatStart = string.indexOf(start);
if (formatStart > -1) {
extractedSubstring = string.substring(formatStart + 1);
}
}
if ((ignoredTokens != null) && (extractedSubstring != null)) {
for (String token : ignoredTokens) {
extractedSubstring = extractedSubstring.replaceAll(token, "");
}
}
return (extractedSubstring == null) ? null : extractedSubstring.trim();
}
public static int index(final String string, String substring, int startIndex, int n) {
int count = 1;
while (count <= n) {
startIndex = string.indexOf(substring, startIndex + substring.length());
count++;
}
return startIndex;
}
public static int count(final String string, String substring) {
int count = 0;
int index = 0;
do {
index = string.indexOf(substring, index);
if (index >= 0) {
count++;
index = index + substring.length();
}
} while (index >= 0);
return count;
}
private static <K> K safeGet(final K[] array, final int index) {
if (array == null) {
return null;
}
try {
final int size = array.length;
if (size > index) {
return array[index];
} else {
return null;
}
} catch (final ArrayIndexOutOfBoundsException e) {
return null;
}
}
private static long toLong(final String value) {
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
return 0;
}
}
static Long toLongObject(final String value) {
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
return null;
}
}
}
@@ -0,0 +1,274 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* <p>Provides helper methods to extract binary package information.
*
* @since 3.0
*/
class Packages {
private static final List<String> supportedExternalLibraries;
static {
supportedExternalLibraries = new ArrayList<>();
supportedExternalLibraries.add("fontconfig");
supportedExternalLibraries.add("freetype");
supportedExternalLibraries.add("fribidi");
supportedExternalLibraries.add("gmp");
supportedExternalLibraries.add("gnutls");
supportedExternalLibraries.add("kvazaar");
supportedExternalLibraries.add("mp3lame");
supportedExternalLibraries.add("libaom");
supportedExternalLibraries.add("libass");
supportedExternalLibraries.add("iconv");
supportedExternalLibraries.add("libilbc");
supportedExternalLibraries.add("libtheora");
supportedExternalLibraries.add("libvidstab");
supportedExternalLibraries.add("libvorbis");
supportedExternalLibraries.add("libvpx");
supportedExternalLibraries.add("libwebp");
supportedExternalLibraries.add("libxml2");
supportedExternalLibraries.add("opencore-amr");
supportedExternalLibraries.add("openh264");
supportedExternalLibraries.add("opus");
supportedExternalLibraries.add("sdl2");
supportedExternalLibraries.add("shine");
supportedExternalLibraries.add("snappy");
supportedExternalLibraries.add("soxr");
supportedExternalLibraries.add("speex");
supportedExternalLibraries.add("tesseract");
supportedExternalLibraries.add("twolame");
supportedExternalLibraries.add("wavpack");
supportedExternalLibraries.add("x264");
supportedExternalLibraries.add("x265");
supportedExternalLibraries.add("xvid");
}
/**
* Returns enabled external libraries by FFmpeg.
*
* @return enabled external libraries
*/
static List<String> getExternalLibraries() {
final String buildConfiguration = AbiDetect.getNativeBuildConf();
final List<String> enabledLibraryList = new ArrayList<>();
for (String supportedExternalLibrary : supportedExternalLibraries) {
if (buildConfiguration.contains("enable-" + supportedExternalLibrary) ||
buildConfiguration.contains("enable-lib" + supportedExternalLibrary)) {
enabledLibraryList.add(supportedExternalLibrary);
}
}
Collections.sort(enabledLibraryList);
return enabledLibraryList;
}
/**
* Returns MobileFFmpeg binary package name.
*
* @return guessed MobileFFmpeg binary package name
*/
static String getPackageName() {
final List<String> externalLibraryList = getExternalLibraries();
final boolean speex = externalLibraryList.contains("speex");
final boolean fribidi = externalLibraryList.contains("fribidi");
final boolean gnutls = externalLibraryList.contains("gnutls");
final boolean xvid = externalLibraryList.contains("xvid");
boolean minGpl = false;
boolean https = false;
boolean httpsGpl = false;
boolean audio = false;
boolean video = false;
boolean full = false;
boolean fullGpl = false;
if (speex && fribidi) {
if (xvid) {
fullGpl = true;
} else {
full = true;
}
} else if (speex) {
audio = true;
} else if (fribidi) {
video = true;
} else if (xvid) {
if (gnutls) {
httpsGpl = true;
} else {
minGpl = true;
}
} else {
if (gnutls) {
https = true;
}
}
if (fullGpl) {
if (externalLibraryList.contains("fontconfig") &&
externalLibraryList.contains("freetype") &&
externalLibraryList.contains("fribidi") &&
externalLibraryList.contains("gmp") &&
externalLibraryList.contains("gnutls") &&
externalLibraryList.contains("kvazaar") &&
externalLibraryList.contains("mp3lame") &&
externalLibraryList.contains("libaom") &&
externalLibraryList.contains("libass") &&
externalLibraryList.contains("iconv") &&
externalLibraryList.contains("libilbc") &&
externalLibraryList.contains("libtheora") &&
externalLibraryList.contains("libvidstab") &&
externalLibraryList.contains("libvorbis") &&
externalLibraryList.contains("libvpx") &&
externalLibraryList.contains("libwebp") &&
externalLibraryList.contains("libxml2") &&
externalLibraryList.contains("opencore-amr") &&
externalLibraryList.contains("opus") &&
externalLibraryList.contains("shine") &&
externalLibraryList.contains("snappy") &&
externalLibraryList.contains("soxr") &&
externalLibraryList.contains("speex") &&
externalLibraryList.contains("twolame") &&
externalLibraryList.contains("wavpack") &&
externalLibraryList.contains("x264") &&
externalLibraryList.contains("x265") &&
externalLibraryList.contains("xvid")) {
return "full-gpl";
} else {
return "custom";
}
}
if (full) {
if (externalLibraryList.contains("fontconfig") &&
externalLibraryList.contains("freetype") &&
externalLibraryList.contains("fribidi") &&
externalLibraryList.contains("gmp") &&
externalLibraryList.contains("gnutls") &&
externalLibraryList.contains("kvazaar") &&
externalLibraryList.contains("mp3lame") &&
externalLibraryList.contains("libaom") &&
externalLibraryList.contains("libass") &&
externalLibraryList.contains("iconv") &&
externalLibraryList.contains("libilbc") &&
externalLibraryList.contains("libtheora") &&
externalLibraryList.contains("libvorbis") &&
externalLibraryList.contains("libvpx") &&
externalLibraryList.contains("libwebp") &&
externalLibraryList.contains("libxml2") &&
externalLibraryList.contains("opencore-amr") &&
externalLibraryList.contains("opus") &&
externalLibraryList.contains("shine") &&
externalLibraryList.contains("snappy") &&
externalLibraryList.contains("soxr") &&
externalLibraryList.contains("speex") &&
externalLibraryList.contains("twolame") &&
externalLibraryList.contains("wavpack")) {
return "full";
} else {
return "custom";
}
}
if (video) {
if (externalLibraryList.contains("fontconfig") &&
externalLibraryList.contains("freetype") &&
externalLibraryList.contains("fribidi") &&
externalLibraryList.contains("kvazaar") &&
externalLibraryList.contains("libaom") &&
externalLibraryList.contains("libass") &&
externalLibraryList.contains("iconv") &&
externalLibraryList.contains("libtheora") &&
externalLibraryList.contains("libvpx") &&
externalLibraryList.contains("libwebp") &&
externalLibraryList.contains("snappy")) {
return "video";
} else {
return "custom";
}
}
if (audio) {
if (externalLibraryList.contains("mp3lame") &&
externalLibraryList.contains("libilbc") &&
externalLibraryList.contains("libvorbis") &&
externalLibraryList.contains("opencore-amr") &&
externalLibraryList.contains("opus") &&
externalLibraryList.contains("shine") &&
externalLibraryList.contains("soxr") &&
externalLibraryList.contains("speex") &&
externalLibraryList.contains("twolame") &&
externalLibraryList.contains("wavpack")) {
return "audio";
} else {
return "custom";
}
}
if (httpsGpl) {
if (externalLibraryList.contains("gmp") &&
externalLibraryList.contains("gnutls") &&
externalLibraryList.contains("libvidstab") &&
externalLibraryList.contains("x264") &&
externalLibraryList.contains("x265") &&
externalLibraryList.contains("xvid")) {
return "https-gpl";
} else {
return "custom";
}
}
if (https) {
if (externalLibraryList.contains("gmp") &&
externalLibraryList.contains("gnutls")) {
return "https";
} else {
return "custom";
}
}
if (minGpl) {
if (externalLibraryList.contains("libvidstab") &&
externalLibraryList.contains("x264") &&
externalLibraryList.contains("x265") &&
externalLibraryList.contains("xvid")) {
return "min-gpl";
} else {
return "custom";
}
}
if (externalLibraryList.size() == 0) {
return "min";
} else {
return "custom";
}
}
}
@@ -0,0 +1,145 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
/**
* <p>Represents statistics data.
*
* @author Taner Sener
* @since v2.1
*/
public class Statistics {
private int videoFrameNumber;
private float videoFps;
private float videoQuality;
private long size;
private int time;
private double bitrate;
private double speed;
public Statistics() {
videoFrameNumber = 0;
videoFps = 0;
videoQuality = 0;
size = 0;
time = 0;
bitrate = 0;
speed = 0;
}
public Statistics(int videoFrameNumber, float videoFps, float videoQuality, long size, int time, double bitrate, double speed) {
this.videoFrameNumber = videoFrameNumber;
this.videoFps = videoFps;
this.videoQuality = videoQuality;
this.size = size;
this.time = time;
this.bitrate = bitrate;
this.speed = speed;
}
public void update(final Statistics newStatistics) {
if (newStatistics != null) {
if (newStatistics.getVideoFrameNumber() > 0) {
this.videoFrameNumber = newStatistics.getVideoFrameNumber();
}
if (newStatistics.getVideoFps() > 0){
this.videoFps = newStatistics.getVideoFps();
}
if (newStatistics.getVideoQuality() > 0){
this.videoQuality = newStatistics.getVideoQuality();
}
if (newStatistics.getSize() > 0){
this.size = newStatistics.getSize();
}
if (newStatistics.getTime() > 0){
this.time = newStatistics.getTime();
}
if (newStatistics.getBitrate() > 0){
this.bitrate = newStatistics.getBitrate();
}
if (newStatistics.getSpeed() > 0){
this.speed = newStatistics.getSpeed();
}
}
}
public int getVideoFrameNumber() {
return videoFrameNumber;
}
public void setVideoFrameNumber(int videoFrameNumber) {
this.videoFrameNumber = videoFrameNumber;
}
public float getVideoFps() {
return videoFps;
}
public void setVideoFps(float videoFps) {
this.videoFps = videoFps;
}
public float getVideoQuality() {
return videoQuality;
}
public void setVideoQuality(float videoQuality) {
this.videoQuality = videoQuality;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
public double getBitrate() {
return bitrate;
}
public void setBitrate(double bitrate) {
this.bitrate = bitrate;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
/**
* <p>Represents a callback function to receive statistics of running operation.
*
* @author Taner Sener
* @since v2.1
*/
@FunctionalInterface
public interface StatisticsCallback {
void apply(final Statistics statistics);
}
@@ -0,0 +1,479 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Stream information class.
*
* @since 3.0
*/
public class StreamInformation {
/**
* Stream index
*/
private Long index;
private String type;
private String codec;
private String fullCodec;
private String format;
private String fullFormat;
private Long width;
private Long height;
private Long bitrate;
private Long sampleRate;
private String sampleFormat;
private String channelLayout;
/**
* SAR
*/
private String sampleAspectRatio;
/**
* DAR
*/
private String displayAspectRatio;
/**
* fps
*/
private String averageFrameRate;
/**
* tbr
*/
private String realFrameRate;
/**
* tbn
*/
private String timeBase;
/**
* tbc
*/
private String codecTimeBase;
/**
* Metadata map
*/
private final Map<String, String> metadata;
/**
* Side data map
*/
private final Map<String, String> sidedata;
public StreamInformation() {
this.metadata = new HashMap<>();
this.sidedata = new HashMap<>();
}
/**
* Returns stream index.
*
* @return stream index, starting from zero
*/
public Long getIndex() {
return index;
}
/**
* Sets stream index.
*
* @param index stream index, starting from zero
*/
public void setIndex(Long index) {
this.index = index;
}
/**
* Returns stream type.
*
* @return stream type; audio or video
*/
public String getType() {
return type;
}
/**
* Sets stream type.
*
* @param type stream type; audio or video
*/
public void setType(String type) {
this.type = type;
}
/**
* Returns stream codec.
*
* @return stream codec
*/
public String getCodec() {
return codec;
}
/**
* Sets stream codec.
*
* @param codec stream codec
*/
public void setCodec(String codec) {
this.codec = codec;
}
/**
* Returns full stream codec.
*
* @return stream codec with additional profile and mode information
*/
public String getFullCodec() {
return fullCodec;
}
/**
* Sets full stream codec.
*
* @param fullCodec stream codec with additional profile and mode information
*/
public void setFullCodec(String fullCodec) {
this.fullCodec = fullCodec;
}
/**
* Returns stream format.
*
* @return stream format
*/
public String getFormat() {
return format;
}
/**
* Sets stream format.
*
* @param format stream format
*/
public void setFormat(String format) {
this.format = format;
}
/**
* Returns full stream format.
*
* @return stream format with
*/
public String getFullFormat() {
return fullFormat;
}
/**
* Sets full stream format.
*
* @param fullFormat stream format with
*/
public void setFullFormat(String fullFormat) {
this.fullFormat = fullFormat;
}
/**
* Returns width.
*
* @return width in pixels
*/
public Long getWidth() {
return width;
}
/**
* Sets width.
*
* @param width width in pixels
*/
public void setWidth(Long width) {
this.width = width;
}
/**
* Returns height.
*
* @return height in pixels
*/
public Long getHeight() {
return height;
}
/**
* Sets height.
*
* @param height height in pixels
*/
public void setHeight(Long height) {
this.height = height;
}
/**
* Returns bitrate.
*
* @return bitrate in kb/s
*/
public Long getBitrate() {
return bitrate;
}
/**
* Sets bitrate.
*
* @param bitrate bitrate in kb/s
*/
public void setBitrate(Long bitrate) {
this.bitrate = bitrate;
}
/**
* Returns sample rate.
*
* @return sample rate in hz
*/
public Long getSampleRate() {
return sampleRate;
}
/**
* Sets sample rate.
*
* @param sampleRate sample rate in hz
*/
public void setSampleRate(Long sampleRate) {
this.sampleRate = sampleRate;
}
/**
* Returns sample format.
*
* @return sample format
*/
public String getSampleFormat() {
return sampleFormat;
}
/**
* Sets sample format.
*
* @param sampleFormat sample format
*/
public void setSampleFormat(String sampleFormat) {
this.sampleFormat = sampleFormat;
}
/**
* Returns channel layout.
*
* @return channel layout
*/
public String getChannelLayout() {
return channelLayout;
}
/**
* Sets channel layout.
*
* @param channelLayout channel layout
*/
public void setChannelLayout(String channelLayout) {
this.channelLayout = channelLayout;
}
/**
* Returns sample aspect ratio.
*
* @return sample aspect ratio
*/
public String getSampleAspectRatio() {
return sampleAspectRatio;
}
/**
* Sets sample aspect ratio.
*
* @param sampleAspectRatio sample aspect ratio
*/
public void setSampleAspectRatio(String sampleAspectRatio) {
this.sampleAspectRatio = sampleAspectRatio;
}
/**
* Returns display aspect ratio.
*
* @return display aspect ratio
*/
public String getDisplayAspectRatio() {
return displayAspectRatio;
}
/**
* Sets display aspect ratio.
*
* @param displayAspectRatio display aspect ratio
*/
public void setDisplayAspectRatio(String displayAspectRatio) {
this.displayAspectRatio = displayAspectRatio;
}
/**
* Returns display aspect ratio.
*
* @return average frame rate in fps
*/
public String getAverageFrameRate() {
return averageFrameRate;
}
/**
* Sets average frame rate.
*
* @param averageFrameRate average frame rate in fps
*/
public void setAverageFrameRate(String averageFrameRate) {
this.averageFrameRate = averageFrameRate;
}
/**
* Returns real frame rate.
*
* @return real frame rate in tbr
*/
public String getRealFrameRate() {
return realFrameRate;
}
/**
* Sets real frame rate.
*
* @param realFrameRate real frame rate in tbr
*/
public void setRealFrameRate(String realFrameRate) {
this.realFrameRate = realFrameRate;
}
/**
* Returns time base.
*
* @return time base in tbn
*/
public String getTimeBase() {
return timeBase;
}
/**
* Sets time base.
*
* @param timeBase time base in tbn
*/
public void setTimeBase(String timeBase) {
this.timeBase = timeBase;
}
/**
* Returns codec time base.
*
* @return codec time base in tbc
*/
public String getCodecTimeBase() {
return codecTimeBase;
}
/**
* Sets codec time base.
*
* @param codecTimeBase codec time base in tbc
*/
public void setCodecTimeBase(String codecTimeBase) {
this.codecTimeBase = codecTimeBase;
}
/**
* Adds metadata.
*
* @param key metadata key
* @param value metadata value
*/
public void addMetadata(String key, String value) {
this.metadata.put(key, value);
}
/**
* Retrieves metadata value associated with this key.
*
* @param key metadata key
* @return metadata value associated with this key
*/
public String getMetadata(String key) {
return this.metadata.get(key);
}
/**
* Returns all metadata entries.
*
* @return set of metadata entries
*/
public Set<Map.Entry<String, String>> getMetadataEntries() {
return this.metadata.entrySet();
}
/**
* Adds side data.
*
* @param key side data key
* @param value side data value
*/
public void addSidedata(String key, String value) {
this.sidedata.put(key, value);
}
/**
* Retrieves side data value associated with this key.
*
* @param key side data key
* @return side data value associated with this key
*/
public String getSidedata(String key) {
return this.sidedata.get(key);
}
/**
* Returns all side data entries.
*
* @return set of site data entries
*/
public Set<Map.Entry<String, String>> getSidedataEntries() {
return this.sidedata.entrySet();
}
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.player;
public interface AudioHandler {
void initialize();
int audioOpen(final int sampleRate, final boolean is16Bit, final boolean isStereo, final int desiredFrames);
void audioWriteShortBuffer(final short[] buffer);
void audioWriteByteBuffer(final byte[] buffer);
int captureOpen(final int sampleRate, final boolean is16Bit, final boolean isStereo, final int desiredFrames);
int captureReadShortBuffer(final short[] buffer, final boolean blocking);
int captureReadByteBuffer(final byte[] buffer, final boolean blocking);
void audioClose();
void captureClose();
}
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.player;
import android.content.Context;
import android.view.MotionEvent;
public interface ControllerHandler {
void initialize(final Context context);
boolean handleJoystickMotionEvent(final MotionEvent event);
void pollInputDevices();
void pollHapticDevices();
void hapticRun(final int deviceId, final int length);
boolean isDeviceSDLJoystick(final int deviceId);
}
@@ -0,0 +1,180 @@
/*
* Simple DirectMedia Layer
* Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* CHANGES 07.2020
* - SDLActivity renamed as FullScreenActivity
*/
package com.arthenica.mobileffmpeg.player;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import com.arthenica.mobileffmpeg.FFplay;
import static com.arthenica.mobileffmpeg.Config.TAG;
import static com.arthenica.mobileffmpeg.player.PlayerSession.FFPLAY_COMMAND;
import static com.arthenica.mobileffmpeg.player.PlayerSession.NativeState;
public class FullScreenActivity extends Activity {
protected PlayerSurface playerSurface;
protected ViewGroup viewLayout;
protected PlayerSession playerSession;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String ffplayCommand = intent.getStringExtra(FFPLAY_COMMAND);
if (ffplayCommand == null) {
Log.i(TAG, "FullScreenActivity created with empty ffplay command.");
} else {
Log.v(TAG, "FullScreenActivity created.");
}
playerSession = new PlayerSession(getRequestedOrientation(), this, ffplayCommand);
playerSurface = new PlayerSurface(this);
playerSurface.init(this, new GenericMotionListener(), playerSession);
viewLayout = new RelativeLayout(this);
viewLayout.addView(playerSurface);
setContentView(viewLayout);
setWindowStyle(false);
}
@Override
protected void onPause() {
Log.v(TAG, "FullScreenActivity paused.");
setNextNativeState(NativeState.PAUSED);
setResumedCalled(false);
handleNativeState();
super.onPause();
}
@Override
protected void onResume() {
Log.v(TAG, "FullScreenActivity resumed.");
setNextNativeState(NativeState.RESUMED);
setResumedCalled(true);
handleNativeState();
super.onResume();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
Log.v(TAG, String.format("FullScreenActivity window focus changed, hasFocus: %s.", hasFocus));
setHasFocus(hasFocus);
if (hasFocus) {
setNextNativeState(NativeState.RESUMED);
} else {
setNextNativeState(NativeState.PAUSED);
}
handleNativeState();
super.onWindowFocusChanged(hasFocus);
}
@Override
public void onLowMemory() {
Log.v(TAG, "FullScreenActivity is on low memory.");
FFplay.playerNativeLowMemory();
super.onLowMemory();
}
@Override
protected void onDestroy() {
Log.v(TAG, "FullScreenActivity destroyed.");
setNextNativeState(NativeState.PAUSED);
handleNativeState();
// Send a quit message to the application
FFplay.playerNativeQuit();
super.onDestroy();
}
@Override
public boolean dispatchKeyEvent(final KeyEvent event) {
int keyCode = event.getKeyCode();
// Ignore certain special keys so they're handled by Android
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
keyCode == KeyEvent.KEYCODE_CAMERA ||
keyCode == KeyEvent.KEYCODE_ZOOM_IN ||
keyCode == KeyEvent.KEYCODE_ZOOM_OUT) {
return false;
}
return super.dispatchKeyEvent(event);
}
protected void setNextNativeState(final NativeState nextNativeState) {
PlayerSession playerSession = this.playerSession;
if (playerSession != null) {
playerSession.setNextNativeState(nextNativeState);
}
}
protected void handleNativeState() {
PlayerSurface playerSurface = this.playerSurface;
if (playerSurface != null) {
playerSurface.handleNativeState();
}
}
protected void setHasFocus(final boolean hasFocus) {
PlayerSurface playerSurface = this.playerSurface;
if (playerSurface != null) {
playerSurface.setHasFocus(hasFocus);
}
}
protected void setResumedCalled(final boolean resumedCalled) {
PlayerSurface playerSurface = this.playerSurface;
if (playerSurface != null) {
playerSurface.setResumedCalled(resumedCalled);
}
}
protected void setWindowStyle(final boolean fullScreen) {
PlayerSurface playerSurface = this.playerSurface;
if (playerSurface != null) {
playerSurface.setWindowStyle(fullScreen);
}
}
public PlayerSurface getPlayerSurface() {
return playerSurface;
}
public PlayerSession getPlayerSession() {
return playerSession;
}
}
@@ -0,0 +1,191 @@
/*
* Simple DirectMedia Layer
* Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* CHANGES 07.2020
* - SDLAudioHandler renamed as GenericAudioHandler
*/
package com.arthenica.mobileffmpeg.player;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Build;
import android.util.Log;
import static com.arthenica.mobileffmpeg.Config.TAG;
public class GenericAudioHandler implements AudioHandler {
protected AudioTrack audioTrack;
protected AudioRecord audioRecord;
public void initialize() {
audioTrack = null;
audioRecord = null;
}
public int audioOpen(final int sampleRate, final boolean is16Bit, final boolean isStereo, int desiredFrames) {
int channelConfig = isStereo ? AudioFormat.CHANNEL_OUT_STEREO : AudioFormat.CHANNEL_OUT_MONO;
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
Log.v(TAG, String.format("AudioHandler audio: wanted %s %s %skHz, %d frames buffer.", isStereo ? "stereo" : "mono", is16Bit ? "16-bit" : "8-bit", sampleRate / 1000f, desiredFrames));
// Let the user pick a larger buffer if they really want -- but ye
// gods they probably shouldn't, the minimums are horrifyingly high
// latency already
desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
if (audioTrack == null) {
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
// Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
// Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
// Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
if (audioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
Log.e(TAG, "AudioHandler failed during initialization of AudioTrack.");
audioTrack = null;
return -1;
}
audioTrack.play();
}
Log.v(TAG, String.format("AudioHandler audio: got %s %s %skHz, %d frames buffer.", (audioTrack.getChannelCount() >= 2) ? "stereo" : "mono", (audioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit", audioTrack.getSampleRate() / 1000f, desiredFrames));
return 0;
}
public void audioWriteShortBuffer(final short[] buffer) {
if (audioTrack == null) {
Log.e(TAG, "AudioHandler attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length; ) {
int result = audioTrack.write(buffer, i, buffer.length - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "AudioHandler audio: error return from write(short).");
return;
}
}
}
public void audioWriteByteBuffer(final byte[] buffer) {
if (audioTrack == null) {
Log.e(TAG, "AudioHandler attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length; ) {
int result = audioTrack.write(buffer, i, buffer.length - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "AudioHandler audio: error return from write(byte).");
return;
}
}
}
public int captureOpen(final int sampleRate, final boolean is16Bit, final boolean isStereo, int desiredFrames) {
int channelConfig = isStereo ? AudioFormat.CHANNEL_IN_STEREO : AudioFormat.CHANNEL_IN_MONO;
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
Log.v(TAG, String.format("AudioHandler capture: wanted %s %s %skHz, %d frames buffer.", isStereo ? "stereo" : "mono", is16Bit ? "16-bit" : "8-bit", sampleRate / 1000f, desiredFrames));
// Let the user pick a larger buffer if they really want -- but ye
// gods they probably shouldn't, the minimums are horrifyingly high
// latency already
desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
if (audioRecord == null) {
audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate, channelConfig, audioFormat, desiredFrames * frameSize);
// see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
Log.e(TAG, "AudioHandler failed during initialization of AudioRecord.");
audioRecord.release();
audioRecord = null;
return -1;
}
audioRecord.startRecording();
}
Log.v(TAG, String.format("AudioHandler capture: got %s %s %skHz, %d frames buffer.", (audioRecord.getChannelCount() >= 2) ? "stereo" : "mono", (audioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit", audioRecord.getSampleRate() / 1000f, desiredFrames));
return 0;
}
public int captureReadShortBuffer(final short[] buffer, final boolean blocking) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return audioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
} else {
return audioRecord.read(buffer, 0, buffer.length);
}
}
public int captureReadByteBuffer(final byte[] buffer, final boolean blocking) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return audioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
} else {
return audioRecord.read(buffer, 0, buffer.length);
}
}
public void audioClose() {
if (audioTrack != null) {
audioTrack.stop();
audioTrack.release();
audioTrack = null;
}
}
public void captureClose() {
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
}
}
@@ -0,0 +1,110 @@
/*
* Simple DirectMedia Layer
* Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
package com.arthenica.mobileffmpeg.player;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
import static com.arthenica.mobileffmpeg.Config.TAG;
/**
* A Handler class for Messages from native SDL applications.
* It uses current Activities as target (e.g. for the title).
* static to prevent implicit references to enclosing object.
*/
public class GenericCommandHandler extends Handler {
public static final int COMMAND_CHANGE_TITLE = 1;
public static final int COMMAND_CHANGE_WINDOW_STYLE = 2;
public static final int COMMAND_SET_KEEP_SCREEN_ON = 5;
protected final Context context;
public GenericCommandHandler(final Context context) {
this.context = context;
}
@Override
public void handleMessage(final Message message) {
switch (message.arg1) {
case COMMAND_CHANGE_TITLE:
if (context instanceof Activity) {
((Activity) context).setTitle((String) message.obj);
} else {
Log.e(TAG, "CommandHandler error handling message, getContext() returned no Activity.");
}
break;
case COMMAND_CHANGE_WINDOW_STYLE:
if (Build.VERSION.SDK_INT < 19) {
// This version of Android doesn't support the immersive fullscreen mode
break;
}
/* This needs more testing, per bug 4096 - Enabling fullscreen on Android causes the app to toggle fullscreen mode continuously in a loop
***
if (context instanceof Activity) {
Window window = ((Activity) context).getWindow();
if (window != null) {
if ((message.obj instanceof Integer) && (((Integer) message.obj).intValue() != 0)) {
int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
window.getDecorView().setSystemUiVisibility(flags);
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
window.getDecorView().setSystemUiVisibility(flags);
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
} else {
Log.e(TAG, "error handling message, getContext() returned no Activity");
}
***/
break;
case COMMAND_SET_KEEP_SCREEN_ON: {
if (context instanceof Activity) {
Window window = ((Activity) context).getWindow();
if (window != null) {
if ((message.obj instanceof Integer) && (((Integer) message.obj).intValue() != 0)) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
}
break;
}
default:
Log.e(TAG, String.format("CommandHandler error handling message, command is %d.", message.arg1));
}
}
}
@@ -0,0 +1,81 @@
/*
* Simple DirectMedia Layer
* Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* CHANGES 07.2020
* - SDLControllerHandler renamed as GenericControllerHandler
*/
package com.arthenica.mobileffmpeg.player;
import android.content.Context;
import android.view.InputDevice;
import android.view.MotionEvent;
public class GenericControllerHandler implements ControllerHandler {
protected GenericJoystickHandler genericJoystickHandler;
protected GenericHapticHandler genericHapticHandler;
public void initialize(final Context context) {
genericJoystickHandler = new GenericJoystickHandler(this);
genericHapticHandler = new GenericHapticHandler(context);
}
/**
* Joystick glue code, just a series of stubs that redirect to the JoystickHandler instance.
*/
public boolean handleJoystickMotionEvent(final MotionEvent event) {
return genericJoystickHandler.handleMotionEvent(event);
}
public void pollInputDevices() {
genericJoystickHandler.pollInputDevices();
}
public void pollHapticDevices() {
genericHapticHandler.pollHapticDevices();
}
public void hapticRun(final int deviceId, final int length) {
genericHapticHandler.run(deviceId, length);
}
/**
* Check if a given device is considered a possible SDL joystick.
*
* @param deviceId device identifier
* @return true if device is a joystick, false otherwise
*/
public boolean isDeviceSDLJoystick(final int deviceId) {
InputDevice device = InputDevice.getDevice(deviceId);
if ((device == null) || device.isVirtual() || (deviceId < 0)) {
return false;
}
int sources = device.getSources();
return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
);
}
}
@@ -0,0 +1,148 @@
/*
* Simple DirectMedia Layer
* Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* CHANGES 07.2020
* - SDLHapticHandler renamed as GenericHapticHandler
* - SDLHaptic class renamed as Haptic
* - Haptic class refactored
*/
package com.arthenica.mobileffmpeg.player;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Vibrator;
import android.view.InputDevice;
import com.arthenica.mobileffmpeg.FFplay;
import java.util.ArrayList;
/**
* <p>Generic haptic handler for FFplay Controller.
*/
public class GenericHapticHandler {
public static class Haptic {
public final int deviceId;
public final String name;
public final Vibrator vibrator;
public Haptic(final int deviceId, final String name, final Vibrator vibrator) {
this.deviceId = deviceId;
this.name = name;
this.vibrator = vibrator;
}
}
protected final ArrayList<Haptic> hapticList;
protected final Vibrator vibratorService;
public GenericHapticHandler(final Context context) {
hapticList = new ArrayList<>();
vibratorService = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
}
@SuppressLint("MissingPermission")
public void run(final int deviceId, final int length) {
Haptic haptic = getHaptic(deviceId);
if (haptic != null) {
haptic.vibrator.vibrate(length);
}
}
public void pollHapticDevices() {
final int DEVICE_ID_VIBRATOR_SERVICE = 999999;
boolean hasVibratorService = false;
final int[] deviceIdArray = InputDevice.getDeviceIds();
// It helps processing the device ids in reverse order
// For example, in the case of the XBox 360 wireless dongle,
// so the first controller seen by SDL matches what the receiver
// considers to be the first controller
for (int i = deviceIdArray.length - 1; i > -1; i--) {
Haptic haptic = getHaptic(deviceIdArray[i]);
if (haptic == null) {
InputDevice device = InputDevice.getDevice(deviceIdArray[i]);
Vibrator vib = device.getVibrator();
if (vib.hasVibrator()) {
haptic = new Haptic(deviceIdArray[i], device.getName(), vib);
hapticList.add(haptic);
FFplay.controllerAddHaptic(haptic.deviceId, haptic.name);
}
}
}
/* Check VIBRATOR_SERVICE */
if (vibratorService != null) {
hasVibratorService = vibratorService.hasVibrator();
if (hasVibratorService) {
Haptic haptic = getHaptic(DEVICE_ID_VIBRATOR_SERVICE);
if (haptic == null) {
haptic = new Haptic(DEVICE_ID_VIBRATOR_SERVICE, "VIBRATOR_SERVICE", vibratorService);
hapticList.add(haptic);
FFplay.controllerAddHaptic(haptic.deviceId, haptic.name);
}
}
}
/* Check removed devices */
ArrayList<Integer> removedDevices = new ArrayList<>();
for (int i = 0; i < hapticList.size(); i++) {
int deviceId = hapticList.get(i).deviceId;
int j;
for (j = 0; j < deviceIdArray.length; j++) {
if (deviceId == deviceIdArray[j]) break;
}
if (deviceId == DEVICE_ID_VIBRATOR_SERVICE && hasVibratorService) {
// don't remove the vibrator if it is still present
} else if (j == deviceIdArray.length) {
removedDevices.add(deviceId);
}
}
for (int i = 0; i < removedDevices.size(); i++) {
int deviceId = removedDevices.get(i);
FFplay.controllerRemoveHaptic(deviceId);
for (int j = 0; j < hapticList.size(); j++) {
if (hapticList.get(j).deviceId == deviceId) {
hapticList.remove(j);
break;
}
}
}
}
protected Haptic getHaptic(final int deviceId) {
for (int i = 0; i < hapticList.size(); i++) {
if (hapticList.get(i).deviceId == deviceId) {
return hapticList.get(i);
}
}
return null;
}
}
@@ -0,0 +1,179 @@
/*
* Simple DirectMedia Layer
* Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* CHANGES 07.2020
* - SDLJoystickHandler renamed as GenericJoystickHandler
* - SDLJoystick class renamed as Joystick
* - Joystick class refactored
*/
package com.arthenica.mobileffmpeg.player;
import android.view.InputDevice;
import android.view.MotionEvent;
import com.arthenica.mobileffmpeg.FFplay;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* <p>Generic joystick handler for FFplay Controller.
*/
public class GenericJoystickHandler {
public static class Joystick {
public final int deviceId;
public final String name;
public final String desc;
public final ArrayList<InputDevice.MotionRange> axes;
public final ArrayList<InputDevice.MotionRange> hats;
public Joystick(final int deviceId, final String name, final String desc, final ArrayList<InputDevice.MotionRange> axes, final ArrayList<InputDevice.MotionRange> hats) {
this.deviceId = deviceId;
this.name = name;
this.desc = desc;
this.axes = axes;
this.hats = hats;
}
}
public static class RangeComparator implements Comparator<InputDevice.MotionRange> {
@Override
public int compare(final InputDevice.MotionRange arg0, final InputDevice.MotionRange arg1) {
return arg0.getAxis() - arg1.getAxis();
}
}
protected final ArrayList<Joystick> joystickList;
protected final ControllerHandler controllerHandler;
public GenericJoystickHandler(final ControllerHandler controllerHandler) {
this.joystickList = new ArrayList<>();
this.controllerHandler = controllerHandler;
}
public void pollInputDevices() {
int[] deviceIds = InputDevice.getDeviceIds();
// It helps processing the device ids in reverse order
// For example, in the case of the XBox 360 wireless dongle,
// so the first controller seen by SDL matches what the receiver
// considers to be the first controller
for (int i = deviceIds.length - 1; i > -1; i--) {
Joystick joystick = getJoystick(deviceIds[i]);
if (joystick == null) {
InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
if (controllerHandler.isDeviceSDLJoystick(deviceIds[i])) {
joystick = new Joystick(deviceIds[i], joystickDevice.getName(), getJoystickDescriptor(joystickDevice), new ArrayList<InputDevice.MotionRange>(), new ArrayList<InputDevice.MotionRange>());
List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
Collections.sort(ranges, new RangeComparator());
for (InputDevice.MotionRange range : ranges) {
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
joystick.hats.add(range);
} else {
joystick.axes.add(range);
}
}
}
joystickList.add(joystick);
FFplay.controllerAddJoystick(joystick.deviceId, joystick.name, joystick.desc, 0, -1, joystick.axes.size(), joystick.hats.size() / 2, 0);
}
}
}
/* Check removed devices */
ArrayList<Integer> removedDevices = new ArrayList<>();
for (int i = 0; i < joystickList.size(); i++) {
int deviceId = joystickList.get(i).deviceId;
int j;
for (j = 0; j < deviceIds.length; j++) {
if (deviceId == deviceIds[j]) break;
}
if (j == deviceIds.length) {
removedDevices.add(deviceId);
}
}
for (int i = 0; i < removedDevices.size(); i++) {
int deviceId = removedDevices.get(i);
FFplay.controllerRemoveJoystick(deviceId);
for (int j = 0; j < joystickList.size(); j++) {
if (joystickList.get(j).deviceId == deviceId) {
joystickList.remove(j);
break;
}
}
}
}
protected Joystick getJoystick(int deviceId) {
for (int i = 0; i < joystickList.size(); i++) {
if (joystickList.get(i).deviceId == deviceId) {
return joystickList.get(i);
}
}
return null;
}
public boolean handleMotionEvent(final MotionEvent event) {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
int actionPointerIndex = event.getActionIndex();
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_MOVE) {
Joystick joystick = getJoystick(event.getDeviceId());
if (joystick != null) {
for (int i = 0; i < joystick.axes.size(); i++) {
InputDevice.MotionRange range = joystick.axes.get(i);
/* Normalize the value to -1...1 */
float value = (event.getAxisValue(range.getAxis(), actionPointerIndex) - range.getMin()) / range.getRange() * 2.0f - 1.0f;
FFplay.controllerOnJoy(joystick.deviceId, i, value);
}
for (int i = 0; i < joystick.hats.size(); i += 2) {
int hatX = Math.round(event.getAxisValue(joystick.hats.get(i).getAxis(), actionPointerIndex));
int hatY = Math.round(event.getAxisValue(joystick.hats.get(i + 1).getAxis(), actionPointerIndex));
FFplay.controllerOnHat(joystick.deviceId, i / 2, hatX, hatY);
}
}
}
}
return true;
}
public String getJoystickDescriptor(final InputDevice joystickDevice) {
String desc = joystickDevice.getDescriptor();
if (desc != null && !desc.isEmpty()) {
return desc;
}
return joystickDevice.getName();
}
}
@@ -0,0 +1,90 @@
/*
* Simple DirectMedia Layer
* Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* CHANGES 07.2020
* - SDLGenericMotionListener renamed as GenericMotionListener
*/
package com.arthenica.mobileffmpeg.player;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
import com.arthenica.mobileffmpeg.FFplay;
/**
* <p>Generic motion listener for FFplay Player.
*/
public class GenericMotionListener implements View.OnGenericMotionListener {
@Override
public boolean onGenericMotion(final View view, final MotionEvent event) {
ControllerHandler controllerHandler = FFplay.getControllerHandler();
float x, y;
int action;
switch (event.getSource()) {
case InputDevice.SOURCE_JOYSTICK:
case InputDevice.SOURCE_GAMEPAD:
case InputDevice.SOURCE_DPAD: {
if (controllerHandler != null) {
return controllerHandler.handleJoystickMotionEvent(event);
} else {
return false;
}
}
case InputDevice.SOURCE_MOUSE: {
if (!FFplay.isSeparateMouseAndTouch()) {
break;
}
action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_SCROLL: {
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
FFplay.playerOnMouse(0, action, x, y);
return true;
}
case MotionEvent.ACTION_HOVER_MOVE: {
x = event.getX(0);
y = event.getY(0);
FFplay.playerOnMouse(0, action, x, y);
return true;
}
default: {
break;
}
}
break;
}
default: {
break;
}
}
return false;
}
}
@@ -0,0 +1,92 @@
/*
* Simple DirectMedia Layer
* Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* CHANGES 07.2020
* - SDLClipboardHandler renamed as PlayerClipboard
* - Added null checks for clipboardManager field
*/
package com.arthenica.mobileffmpeg.player;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import com.arthenica.mobileffmpeg.FFplay;
/**
* <p>Clipboard for FFplay Player.
*/
public class PlayerClipboard implements ClipboardManager.OnPrimaryClipChangedListener {
protected final Context context;
protected final ClipboardManager clipboardManager;
public PlayerClipboard(final Context context) {
this.context = context;
this.clipboardManager = (android.content.ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
if (this.clipboardManager != null) {
this.clipboardManager.addPrimaryClipChangedListener(this);
}
}
public boolean clipboardHasText() {
if (clipboardManager != null) {
final ClipData clip = clipboardManager.getPrimaryClip();
return (clip != null) && (clip.getItemCount() > 0);
}
return false;
}
public String clipboardGetText() {
CharSequence text = null;
if (clipboardManager != null) {
ClipData clip = clipboardManager.getPrimaryClip();
if (clip != null && clip.getItemCount() > 0) {
text = clip.getItemAt(0).coerceToText(context);
}
}
if (text != null) {
return text.toString();
} else {
return null;
}
}
public void clipboardSetText(final String string) {
if (clipboardManager != null) {
clipboardManager.removePrimaryClipChangedListener(this);
clipboardManager.setPrimaryClip(ClipData.newPlainText(null, string));
clipboardManager.addPrimaryClipChangedListener(this);
}
}
@Override
public void onPrimaryClipChanged() {
FFplay.playerOnClipboardChanged();
}
}
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.player;
import android.content.Context;
import android.util.DisplayMetrics;
import android.view.Surface;
public interface PlayerManager {
void initialize();
boolean setActivityTitle(final String title);
void setWindowStyle(final boolean fullScreen);
void setOrientation(final int w, final int h, final boolean resizable, final String hint);
boolean isScreenKeyboardShown();
boolean sendMessage(final int command, final int param);
Context getContext();
boolean isAndroidTV();
DisplayMetrics getDisplayDPI();
boolean getManifestEnvironmentVariables();
boolean showTextInput(final int x, final int y, final int w, final int h);
Surface getNativeSurface();
int[] inputGetInputDeviceIds(final int sources);
boolean clipboardHasText();
String clipboardGetText();
void clipboardSetText(final String string);
int showMessageBox(final int flags, final String title, final String message, final int[] buttonFlags, final int[] buttonIds, final String[] buttonTexts, final int[] colors);
}
@@ -0,0 +1,93 @@
/*
* Copyright (c) 2020 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.player;
import android.content.Context;
import android.os.AsyncTask;
import com.arthenica.mobileffmpeg.FFplay;
import com.arthenica.mobileffmpeg.util.AsyncSingleFFplayExecuteTask;
public class PlayerSession {
public static final String FFPLAY_COMMAND = "ffplayCommand";
public enum NativeState {
INIT, RESUMED, PAUSED
}
protected int requestedOrientation;
protected Context context;
protected final String command;
protected NativeState nextNativeState;
protected NativeState currentNativeState;
public PlayerSession(final int requestedOrientation, final Context context, final String command) {
this.requestedOrientation = requestedOrientation;
this.context = context;
this.command = command;
}
public NativeState getNextNativeState() {
return nextNativeState;
}
public void setNextNativeState(final NativeState nextNativeState) {
this.nextNativeState = nextNativeState;
}
public NativeState getCurrentNativeState() {
return currentNativeState;
}
public void setCurrentNativeState(final NativeState currentNativeState) {
this.currentNativeState = currentNativeState;
}
public Context getContext() {
return context;
}
public void setContext(final Context context) {
this.context = context;
}
public int getRequestedOrientation() {
return requestedOrientation;
}
public AsyncTask<String, Integer, Integer> execute() {
FFplay.setAudioHandler(new GenericAudioHandler());
FFplay.setControllerManager(new GenericControllerHandler());
AudioHandler audioHandler = FFplay.getAudioHandler();
if (audioHandler != null) {
audioHandler.initialize();
}
ControllerHandler controllerHandler = FFplay.getControllerHandler();
if (controllerHandler != null) {
controllerHandler.initialize(context);
}
AsyncSingleFFplayExecuteTask task = new AsyncSingleFFplayExecuteTask(command);
return task.execute("");
}
}
@@ -0,0 +1,683 @@
/*
* Simple DirectMedia Layer
* Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/*
* CHANGES 07.2020
* - SDLSurface renamed as PlayerSurface
*/
package com.arthenica.mobileffmpeg.player;
import android.app.Activity;
import android.app.UiModeManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.PixelFormat;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import com.arthenica.mobileffmpeg.FFplay;
import com.arthenica.mobileffmpeg.player.PlayerSession.NativeState;
import java.util.Arrays;
import static android.content.Context.UI_MODE_SERVICE;
import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
import static com.arthenica.mobileffmpeg.Config.TAG;
import static com.arthenica.mobileffmpeg.player.GenericCommandHandler.COMMAND_CHANGE_TITLE;
import static com.arthenica.mobileffmpeg.player.GenericCommandHandler.COMMAND_CHANGE_WINDOW_STYLE;
/**
* PlayerSurface. This is what we draw on, so we need to know when it's created in order to do
* anything useful.
* <p>
* Because of this, that's where we set up the SDL thread
*/
public class PlayerSurface extends SurfaceView implements SurfaceHolder.Callback,
View.OnKeyListener, View.OnTouchListener, SensorEventListener, PlayerManager {
protected Activity activity;
protected Handler commandHandler;
protected PlayerClipboard playerClipboard;
protected SensorManager sensorManager;
protected Display display;
protected float width, height;
protected PlayerSession playerSession;
protected boolean ready;
protected boolean resumedCalled;
protected boolean hasFocus;
public PlayerSurface(final Context context) {
super(context);
onCreated(context);
}
public PlayerSurface(final Context context, final AttributeSet attrs) {
super(context, attrs);
onCreated(context);
}
public PlayerSurface(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
onCreated(context);
}
public PlayerSurface(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
onCreated(context);
}
protected void onCreated(final Context context) {
Log.v(TAG, String.format("PlayerSurface created on device: %s and model: %s.", android.os.Build.DEVICE, android.os.Build.MODEL));
getHolder().addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
setOnKeyListener(this);
setOnTouchListener(this);
commandHandler = new GenericCommandHandler(context);
playerClipboard = new PlayerClipboard(context);
display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
// Some arbitrary defaults to avoid a potential division by zero
width = 1.0f;
height = 1.0f;
ready = false;
}
public void init(final Activity activity, final View.OnGenericMotionListener motionListener, final PlayerSession playerSession) {
this.activity = activity;
setOnGenericMotionListener(motionListener);
FFplay.setPlayerManager(this);
this.playerSession = playerSession;
}
public void handlePause() {
enableSensor(Sensor.TYPE_ACCELEROMETER, false);
}
public void handleResume() {
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
setOnKeyListener(this);
setOnTouchListener(this);
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
}
public Surface getNativeSurface() {
return getHolder().getSurface();
}
@Override
public void surfaceCreated(final SurfaceHolder ignored) {
}
@Override
public void surfaceDestroyed(final SurfaceHolder holder) {
// Transition to pause, if needed
setNextNativeState(NativeState.PAUSED);
handleNativeState();
ready = false;
FFplay.playerOnSurfaceDestroyed();
}
@Override
public void surfaceChanged(final SurfaceHolder holder, final int format, final int width, final int height) {
int sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565 by default
switch (format) {
case PixelFormat.A_8:
Log.v(TAG, "PlayerSurface using pixel format A_8");
break;
case PixelFormat.LA_88:
Log.v(TAG, "PlayerSurface using pixel format LA_88");
break;
case PixelFormat.L_8:
Log.v(TAG, "PlayerSurface using pixel format L_8");
break;
case PixelFormat.RGBA_4444:
Log.v(TAG, "PlayerSurface using pixel format RGBA_4444");
sdlFormat = 0x15421002; // SDL_PIXELFORMAT_RGBA4444
break;
case PixelFormat.RGBA_5551:
Log.v(TAG, "PlayerSurface using pixel format RGBA_5551");
sdlFormat = 0x15441002; // SDL_PIXELFORMAT_RGBA5551
break;
case PixelFormat.RGBA_8888:
Log.v(TAG, "PlayerSurface using pixel format RGBA_8888");
sdlFormat = 0x16462004; // SDL_PIXELFORMAT_RGBA8888
break;
case PixelFormat.RGBX_8888:
Log.v(TAG, "PlayerSurface using pixel format RGBX_8888");
sdlFormat = 0x16261804; // SDL_PIXELFORMAT_RGBX8888
break;
case PixelFormat.RGB_332:
Log.v(TAG, "PlayerSurface using pixel format RGB_332");
sdlFormat = 0x14110801; // SDL_PIXELFORMAT_RGB332
break;
case PixelFormat.RGB_565:
Log.v(TAG, "PlayerSurface using pixel format RGB_565");
sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565
break;
case PixelFormat.RGB_888:
Log.v(TAG, "PlayerSurface using pixel format RGB_888");
// Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
sdlFormat = 0x16161804; // SDL_PIXELFORMAT_RGB888
break;
default:
Log.v(TAG, String.format("PlayerSurface using pixel format unknown %d", format));
break;
}
this.width = width;
this.height = height;
FFplay.playerOnResize(width, height, sdlFormat, display.getRefreshRate());
Log.v(TAG, String.format("PlayerSurface window size: %dx%d.", width, height));
boolean skip = false;
int requestedOrientation = getRequestedOrientation();
if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
// Accept any
} else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
if (this.width > this.height) {
skip = true;
}
} else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
if (this.width < this.height) {
skip = true;
}
}
// Special Patch for Square Resolution: Black Berry Passport
if (skip) {
double min = Math.min(this.width, this.height);
double max = Math.max(this.width, this.height);
if (max / min < 1.20) {
Log.v(TAG, "PlayerSurface don't skip on such aspect-ratio. Could be a square resolution.");
skip = false;
}
}
if (skip) {
Log.v(TAG, "PlayerSurface skip .. Surface is not ready.");
ready = false;
return;
}
/* Surface is ready */
ready = true;
/* If the surface has been previously destroyed by onNativeSurfaceDestroyed, recreate it here */
FFplay.playerOnSurfaceChanged();
handleNativeState();
}
@Override
public boolean onKey(final View v, final int keyCode, final KeyEvent event) {
final ControllerHandler controllerHandler = FFplay.getControllerHandler();
// Dispatch the different events depending on where they come from
// Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
// So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
//
// Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
// SOURCE_JOYSTICK, while its key events arrive from the keyboard source
// So, retrieve the device itself and check all of its sources
if (controllerHandler != null && controllerHandler.isDeviceSDLJoystick(event.getDeviceId())) {
// Note that we process events with specific key codes here
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (FFplay.controllerOnPadDown(event.getDeviceId(), keyCode) == 0) {
return true;
}
} else if (event.getAction() == KeyEvent.ACTION_UP) {
if (FFplay.controllerOnPadUp(event.getDeviceId(), keyCode) == 0) {
return true;
}
}
}
if ((event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (isTextInputEvent(event)) {
FFplay.inputCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
}
FFplay.playerOnKeyDown(keyCode);
return true;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
FFplay.playerOnKeyUp(keyCode);
return true;
}
}
if ((event.getSource() & InputDevice.SOURCE_MOUSE) != 0) {
// on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
// they are ignored here because sending them as mouse input to SDL is messy
if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
switch (event.getAction()) {
case KeyEvent.ACTION_DOWN:
case KeyEvent.ACTION_UP:
// mark the event as handled or it will be handled by system
// handling KEYCODE_BACK by system will call onBackPressed()
return true;
}
}
}
return false;
}
@Override
public boolean onTouch(final View v, final MotionEvent event) {
final int touchDevId = event.getDeviceId();
final int pointerCount = event.getPointerCount();
int action = event.getActionMasked();
int pointerFingerId;
int mouseButton;
int i = -1;
float x, y, p;
if (event.getSource() == InputDevice.SOURCE_MOUSE && FFplay.isSeparateMouseAndTouch()) {
try {
mouseButton = (Integer) event.getClass().getMethod("getButtonState").invoke(event);
} catch (Exception e) {
mouseButton = 1; // oh well.
}
FFplay.playerOnMouse(mouseButton, action, event.getX(0), event.getY(0));
} else {
switch (action) {
case MotionEvent.ACTION_MOVE:
for (i = 0; i < pointerCount; i++) {
pointerFingerId = event.getPointerId(i);
x = event.getX(i) / width;
y = event.getY(i) / height;
p = event.getPressure(i);
if (p > 1.0f) {
// may be larger than 1.0f on some devices
// see the documentation of getPressure(i)
p = 1.0f;
}
FFplay.playerOnTouch(touchDevId, pointerFingerId, action, x, y, p);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_DOWN:
// Primary pointer up/down, the index is always zero
i = 0;
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN:
// Non primary pointer up/down
if (i == -1) {
i = event.getActionIndex();
}
pointerFingerId = event.getPointerId(i);
x = event.getX(i) / width;
y = event.getY(i) / height;
p = event.getPressure(i);
if (p > 1.0f) {
// may be larger than 1.0f on some devices
// see the documentation of getPressure(i)
p = 1.0f;
}
FFplay.playerOnTouch(touchDevId, pointerFingerId, action, x, y, p);
break;
case MotionEvent.ACTION_CANCEL:
for (i = 0; i < pointerCount; i++) {
pointerFingerId = event.getPointerId(i);
x = event.getX(i) / width;
y = event.getY(i) / height;
p = event.getPressure(i);
if (p > 1.0f) {
// may be larger than 1.0f on some devices
// see the documentation of getPressure(i)
p = 1.0f;
}
FFplay.playerOnTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p);
}
break;
default:
break;
}
}
return true;
}
@Override
public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
// TODO
}
@Override
public void onSensorChanged(final SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float x, y;
switch (display.getRotation()) {
case Surface.ROTATION_90:
x = -event.values[1];
y = event.values[0];
break;
case Surface.ROTATION_270:
x = event.values[1];
y = -event.values[0];
break;
case Surface.ROTATION_180:
x = -event.values[1];
y = -event.values[0];
break;
default:
x = event.values[0];
y = event.values[1];
break;
}
FFplay.playerOnAccel(-x / SensorManager.GRAVITY_EARTH,
y / SensorManager.GRAVITY_EARTH,
event.values[2] / SensorManager.GRAVITY_EARTH);
}
}
public void enableSensor(final int sensorType, final boolean enabled) {
// TODO: This uses getDefaultSensor - what if we have >1 accels?
if (enabled) {
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(sensorType),
SensorManager.SENSOR_DELAY_GAME, null);
} else {
sensorManager.unregisterListener(this, sensorManager.getDefaultSensor(sensorType));
}
}
int getRequestedOrientation() {
final PlayerSession playerSession = this.playerSession;
if (playerSession == null) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
} else {
return playerSession.getRequestedOrientation();
}
}
public void setNextNativeState(final NativeState nextNativeState) {
final PlayerSession playerSession = this.playerSession;
if (playerSession != null) {
playerSession.setNextNativeState(nextNativeState);
}
}
public void setCurrentNativeState(final NativeState currentNativeState) {
final PlayerSession playerSession = this.playerSession;
if (playerSession != null) {
playerSession.setCurrentNativeState(currentNativeState);
}
}
public static boolean isTextInputEvent(final KeyEvent event) {
if (event.isCtrlPressed()) {
return false;
}
return event.isPrintingKey() || event.getKeyCode() == KeyEvent.KEYCODE_SPACE;
}
public void handleNativeState() {
Log.v(TAG, String.format("PlayerSurface handling nativeState with ready: %s, hasFocus: %s, resumed: %s.", ready, hasFocus, resumedCalled));
NativeState currentNativeState = null;
NativeState nextNativeState = null;
if (playerSession != null) {
currentNativeState = playerSession.getCurrentNativeState();
nextNativeState = playerSession.getNextNativeState();
}
Log.v(TAG, String.format("PlayerSurface handling nativeState with current:%s, next: %s.", currentNativeState, nextNativeState));
if (nextNativeState == currentNativeState) {
// Already in same state, discard.
return;
}
// Try a transition to init state
if (nextNativeState == NativeState.INIT) {
setCurrentNativeState(nextNativeState);
return;
}
// Try a transition to paused state
if (nextNativeState == NativeState.PAUSED) {
FFplay.playerNativePause();
handlePause();
setCurrentNativeState(nextNativeState);
return;
}
// Try a transition to resumed state
if (nextNativeState == NativeState.RESUMED) {
play();
}
}
public void play() {
if (ready && resumedCalled) {
initialize();
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
if (playerSession != null) {
playerSession.execute();
}
FFplay.playerNativeResume();
handleResume();
setCurrentNativeState(NativeState.RESUMED);
} else {
Log.v(TAG, String.format("PlayerSurface play failed for ready:%s, hasFocus: %s, resumed: %s.", ready, hasFocus, resumedCalled));
}
}
public void setHasFocus(final boolean hasFocus) {
this.hasFocus = hasFocus;
}
public void setResumedCalled(final boolean resumedCalled) {
this.resumedCalled = resumedCalled;
}
public boolean sendCommand(final int command, final Object data) {
Message message = commandHandler.obtainMessage();
message.arg1 = command;
message.obj = data;
return commandHandler.sendMessage(message);
}
public void initialize() {
setHasFocus(true);
setNextNativeState(NativeState.INIT);
setCurrentNativeState(NativeState.INIT);
}
public boolean setActivityTitle(final String title) {
return sendCommand(COMMAND_CHANGE_TITLE, title);
}
public void setWindowStyle(final boolean fullScreen) {
sendCommand(COMMAND_CHANGE_WINDOW_STYLE, fullScreen ? 1 : 0);
}
public void setOrientation(final int w, final int h, final boolean resizable, final String hint) {
int orientation = -1;
if (hint.contains("LandscapeRight") && hint.contains("LandscapeLeft")) {
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
} else if (hint.contains("LandscapeRight")) {
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
} else if (hint.contains("LandscapeLeft")) {
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
} else if (hint.contains("Portrait") && hint.contains("PortraitUpsideDown")) {
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
} else if (hint.contains("Portrait")) {
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
} else if (hint.contains("PortraitUpsideDown")) {
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
}
/* no valid hint */
if (orientation == -1) {
if (resizable) {
/* no fixed orientation */
} else {
if (w > h) {
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
} else {
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
}
}
}
Log.v(TAG, String.format("PlayerSurface set orientation:%d, width:%d, height:%d, resizable:%s and hint:%s.", orientation, w, h, resizable, hint));
if (orientation != -1) {
activity.setRequestedOrientation(orientation);
}
}
public boolean isScreenKeyboardShown() {
return false;
}
public boolean sendMessage(final int command, final int param) {
return sendCommand(command, param);
}
public boolean isAndroidTV() {
UiModeManager uiModeManager = (UiModeManager) getContext().getSystemService(UI_MODE_SERVICE);
return (uiModeManager.getCurrentModeType() == UI_MODE_TYPE_TELEVISION);
}
public DisplayMetrics getDisplayDPI() {
return getContext().getResources().getDisplayMetrics();
}
public boolean getManifestEnvironmentVariables() {
try {
ApplicationInfo applicationInfo = getContext().getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
Bundle bundle = applicationInfo.metaData;
if (bundle == null) {
return false;
}
String prefix = "SDL_ENV.";
final int trimLength = prefix.length();
for (String key : bundle.keySet()) {
if (key.startsWith(prefix)) {
String name = key.substring(trimLength);
String value = bundle.get(key).toString();
FFplay.playerNativeSetenv(name, value);
}
}
return true;
} catch (final Exception e) {
Log.i(TAG, "PlayerSurface failed to set environment variables. " + e.toString());
}
return false;
}
public boolean showTextInput(final int x, final int y, final int w, final int h) {
return false;
}
public int[] inputGetInputDeviceIds(final int sources) {
int[] ids = InputDevice.getDeviceIds();
int[] filtered = new int[ids.length];
int used = 0;
for (int id : ids) {
InputDevice device = InputDevice.getDevice(id);
if ((device != null) && ((device.getSources() & sources) != 0)) {
filtered[used++] = device.getId();
}
}
return Arrays.copyOf(filtered, used);
}
public int showMessageBox(
final int flags,
final String title,
final String message,
final int[] buttonFlags,
final int[] buttonIds,
final String[] buttonTexts,
final int[] colors) {
Log.i(TAG, String.format("PlayerSurface was asked to showMessageBox for title: %s, message: %s and %d buttons: %s.", title, message, (buttonIds != null) ? buttonIds.length : 0, Arrays.toString(buttonTexts)));
return -1;
}
public boolean clipboardHasText() {
return playerClipboard.clipboardHasText();
}
public String clipboardGetText() {
return playerClipboard.clipboardGetText();
}
public void clipboardSetText(final String string) {
playerClipboard.clipboardSetText(string);
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2018-2019 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.util;
import android.os.AsyncTask;
import com.arthenica.mobileffmpeg.Config;
import com.arthenica.mobileffmpeg.FFmpeg;
public class AsyncSingleFFmpegExecuteTask extends AsyncTask<String, Integer, Integer> {
private final String command;
private final SingleExecuteCallback singleExecuteCallback;
public AsyncSingleFFmpegExecuteTask(final String command, final SingleExecuteCallback singleExecuteCallback) {
this.command = command;
this.singleExecuteCallback = singleExecuteCallback;
}
@Override
protected Integer doInBackground(final String... arguments) {
return FFmpeg.execute(command);
}
@Override
protected void onPostExecute(final Integer rc) {
if (singleExecuteCallback != null) {
singleExecuteCallback.apply(rc, Config.getLastCommandOutput());
}
}
}
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2019 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.util;
import android.os.AsyncTask;
import android.util.Log;
import com.arthenica.mobileffmpeg.FFplay;
import static com.arthenica.mobileffmpeg.Config.TAG;
public class AsyncSingleFFplayExecuteTask extends AsyncTask<String, Integer, Integer> {
private final String command;
public AsyncSingleFFplayExecuteTask(final String command) {
this.command = command;
}
@Override
protected Integer doInBackground(final String... ignored) {
Log.v(TAG, String.format("Running FFplay for %s.", command));
int rc = FFplay.execute(command.split(" "));
Log.v(TAG, String.format("Finished running FFplay for %s.", command));
return rc;
}
@Override
protected void onPostExecute(final Integer ignored) {
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2018-2019 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.util;
import android.os.AsyncTask;
import com.arthenica.mobileffmpeg.Config;
import com.arthenica.mobileffmpeg.FFprobe;
public class AsyncSingleFFprobeExecuteTask extends AsyncTask<String, Integer, Integer> {
private final String command;
private final SingleExecuteCallback singleExecuteCallback;
public AsyncSingleFFprobeExecuteTask(final String command, final SingleExecuteCallback singleExecuteCallback) {
this.command = command;
this.singleExecuteCallback = singleExecuteCallback;
}
@Override
protected Integer doInBackground(final String... arguments) {
return FFprobe.execute(command);
}
@Override
protected void onPostExecute(final Integer rc) {
if (singleExecuteCallback != null) {
singleExecuteCallback.apply(rc, Config.getLastCommandOutput());
}
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2018-2019 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.util;
import android.os.AsyncTask;
import com.arthenica.mobileffmpeg.FFprobe;
import com.arthenica.mobileffmpeg.MediaInformation;
public class AsyncSingleGetMediaInformationTask extends AsyncTask<String, MediaInformation, MediaInformation> {
private final String path;
private final SingleGetMediaInformationCallback singleGetMediaInformationCallback;
public AsyncSingleGetMediaInformationTask(final String path, final SingleGetMediaInformationCallback singleGetMediaInformationCallback) {
this.path = path;
this.singleGetMediaInformationCallback = singleGetMediaInformationCallback;
}
@Override
protected MediaInformation doInBackground(final String... arguments) {
return FFprobe.getMediaInformation(path);
}
@Override
protected void onPostExecute(final MediaInformation mediaInformation) {
if (singleGetMediaInformationCallback != null) {
singleGetMediaInformationCallback.apply(mediaInformation);
}
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.util;
public class Pair<A, B> {
/**
* The first element of the pair.
*/
protected A first;
/**
* The second element of the pair.
*/
protected B second;
public Pair(final A first, final B second) {
this.first = first;
this.second = second;
}
public A getFirst() {
return first;
}
public B getSecond() {
return second;
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.util;
/**
* <p>Represents a callback function to receive a single execution result.
*
* @author Taner Sener
* @since v2.1
*/
@FunctionalInterface
public interface SingleExecuteCallback {
void apply(int returnCode, String executeOutput);
}
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.util;
import com.arthenica.mobileffmpeg.MediaInformation;
/**
* <p>Represents a callback function to receive a single getMediaInformation result.
*
* @author Taner Sener
*/
@FunctionalInterface
public interface SingleGetMediaInformationCallback {
void apply(MediaInformation mediaInformation);
}
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg.util;
public class Trio<A, B, C> {
/**
* The first element of the trio.
*/
protected final A first;
/**
* The second element of the trio.
*/
protected final B second;
/**
* The third element of the trio.
*/
protected final C third;
public Trio(final A first, final B second, final C third) {
this.first = first;
this.second = second;
this.third = third;
}
public A getFirst() {
return first;
}
public B getSecond() {
return second;
}
public C getThird() {
return third;
}
}
@@ -1,34 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>
@@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

@@ -1,3 +0,0 @@
<resources>
<string name="app_name">MobileFFmpeg</string>
</resources>
@@ -1,11 +0,0 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
@@ -0,0 +1,186 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* <p>Tests for {@link Config} class.
*/
public class ConfigTest {
private static final String externalLibrariesCommandOutput = " configuration:\n" +
" --cross-prefix=i686-linux-android-\n" +
" --sysroot=/Users/taner/Library/Android/sdk/ndk-bundle/toolchains/mobile-ffmpeg-i686/sysroot\n" +
" --prefix=/Users/taner/Projects/mobile-ffmpeg/prebuilt/android-x86/ffmpeg\n" +
" --pkg-config=/usr/local/bin/pkg-config --extra-cflags='-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32 -Wno-unused-function -fstrict-aliasing -fPIC -DANDROID -D__ANDROID__ -D__ANDROID_API__=21 -O2 -I/Users/taner/Library/Android/sdk/ndk-bundle/toolchains/mobile-ffmpeg-i686/sysroot/usr/include -I/Users/taner/Library/Android/sdk/ndk-bundle/toolchains/mobile-ffmpeg-i686/sysroot/usr/local/include'\n" +
" --extra-cxxflags='-std=c++11 -fno-exceptions -fno-rtti'\n" +
" --extra-ldflags='-march=i686 -Wl,--gc-sections,--icf=safe -lc -lm -ldl -llog -lc++_shared -L/Users/taner/Library/Android/sdk/ndk-bundle/toolchains/mobile-ffmpeg-i686/i686-linux-android/lib -L/Users/taner/Library/Android/sdk/ndk-bundle/toolchains/mobile-ffmpeg-i686/sysroot/usr/lib -L/Users/taner/Library/Android/sdk/ndk-bundle/toolchains/mobile-ffmpeg-i686/lib -L/Users/taner/Library/Android/sdk/ndk-bundle/platforms/android-21/arch-x86/usr/lib'\n" +
" --enable-version3\n" +
" --arch=i686\n" +
" --cpu=i686\n" +
" --target-os=android\n" +
" --disable-neon\n" +
" --disable-asm\n" +
" --disable-inline-asm\n" +
" --enable-cross-compile\n" +
" --enable-pic\n" +
" --enable-jni\n" +
" --enable-libvorbis\n" +
" --enable-optimizations\n" +
" --enable-swscale\n" +
" --enable-shared\n" +
" --enable-v4l2-m2m\n" +
" --enable-small\n" +
" --disable-openssl\n" +
" --disable-xmm-clobber-test\n" +
" --disable-debug\n" +
" --disable-neon-clobber-test\n" +
" --disable-programs\n" +
" --disable-postproc\n" +
" --disable-doc\n" +
" --disable-htmlpages\n" +
" --disable-manpages\n" +
" --disable-podpages\n" +
" --disable-txtpages\n" +
" --disable-static\n" +
" --disable-sndio\n" +
" --disable-schannel\n" +
" --disable-securetransport\n" +
" --disable-xlib\n" +
" --disable-cuda\n" +
" --disable-cuvid\n" +
" --disable-nvenc\n" +
" --disable-vaapi\n" +
" --disable-vdpau\n" +
" --disable-videotoolbox\n" +
" --disable-audiotoolbox\n" +
" --disable-appkit\n" +
" --disable-alsa\n" +
" --disable-cuda\n" +
" --disable-cuvid\n" +
" --disable-nvenc\n" +
" --disable-vaapi\n" +
" --disable-vdpau\n" +
" --disable-zlib\n";
@Test
public void getExternalLibraries() {
final List<String> supportedExternalLibraries = new ArrayList<>();
supportedExternalLibraries.add("chromaprint");
supportedExternalLibraries.add("fontconfig");
supportedExternalLibraries.add("freetype");
supportedExternalLibraries.add("fribidi");
supportedExternalLibraries.add("gmp");
supportedExternalLibraries.add("gnutls");
supportedExternalLibraries.add("kvazaar");
supportedExternalLibraries.add("lame");
supportedExternalLibraries.add("libaom");
supportedExternalLibraries.add("libass");
supportedExternalLibraries.add("libiconv");
supportedExternalLibraries.add("libilbc");
supportedExternalLibraries.add("libtheora");
supportedExternalLibraries.add("libvidstab");
supportedExternalLibraries.add("libvorbis");
supportedExternalLibraries.add("libvpx");
supportedExternalLibraries.add("libwebp");
supportedExternalLibraries.add("libxml2");
supportedExternalLibraries.add("opencore-amr");
supportedExternalLibraries.add("opus");
supportedExternalLibraries.add("shine");
supportedExternalLibraries.add("sdl");
supportedExternalLibraries.add("snappy");
supportedExternalLibraries.add("soxr");
supportedExternalLibraries.add("speex");
supportedExternalLibraries.add("tesseract");
supportedExternalLibraries.add("twolame");
supportedExternalLibraries.add("wavpack");
supportedExternalLibraries.add("x264");
supportedExternalLibraries.add("x265");
supportedExternalLibraries.add("xvidcore");
supportedExternalLibraries.add("android-zlib");
supportedExternalLibraries.add("android-media-codec");
final List<String> enabledList = new ArrayList<>();
for (String supportedExternalLibrary : supportedExternalLibraries) {
if (externalLibrariesCommandOutput.contains("enable-" + supportedExternalLibrary) ||
externalLibrariesCommandOutput.contains("enable-lib" + supportedExternalLibrary)) {
enabledList.add(supportedExternalLibrary);
}
}
Collections.sort(enabledList);
Assert.assertNotNull(enabledList);
Assert.assertEquals(1, enabledList.size());
}
@Test
public void getPackageName() {
Assert.assertEquals("min", listToPackageName(Collections.singletonList("")));
Assert.assertEquals("min-gpl", listToPackageName(Collections.singletonList("xvidcore")));
Assert.assertEquals("full-gpl", listToPackageName(Arrays.asList("gnutls", "speex", "fribidi", "xvidcore")));
Assert.assertEquals("full", listToPackageName(Arrays.asList("fribidi", "speex")));
Assert.assertEquals("video", listToPackageName(Collections.singletonList("fribidi")));
Assert.assertEquals("audio", listToPackageName(Collections.singletonList("speex")));
Assert.assertEquals("https", listToPackageName(Collections.singletonList("gnutls")));
Assert.assertEquals("https-gpl", listToPackageName(Arrays.asList("gnutls", "xvidcore")));
}
private String listToPackageName(final List<String> externalLibraryList) {
boolean speex = externalLibraryList.contains("speex");
boolean fribidi = externalLibraryList.contains("fribidi");
boolean gnutls = externalLibraryList.contains("gnutls");
boolean xvidcore = externalLibraryList.contains("xvidcore");
if (speex && fribidi) {
if (xvidcore) {
return "full-gpl";
} else {
return "full";
}
} else if (speex) {
return "audio";
} else if (fribidi) {
return "video";
} else if (xvidcore) {
if (gnutls) {
return "https-gpl";
} else {
return "min-gpl";
}
} else {
if (gnutls) {
return "https";
} else {
return "min";
}
}
}
}
@@ -1,36 +0,0 @@
/*
* Copyright (c) 2018 Taner Sener
*
* This file is part of MobileFFmpeg.
*
* MobileFFmpeg is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MobileFFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MobileFFmpeg. If not, see <http://www.gnu.org/licenses/>.
*/
package com.arthenica.mobileffmpeg;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

Some files were not shown because too many files have changed in this diff Show More