├── .gitignore
├── .gitmodules
├── .travis.yml
├── LICENSE
├── README.md
├── build.gradle
├── example
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── ffmpegtest
│ │ ├── AppConstants.java
│ │ ├── MainActivity.java
│ │ ├── UserPreferences.java
│ │ ├── VideoActivity.java
│ │ └── adapter
│ │ ├── ItemsAdapter.java
│ │ └── VideoItem.java
│ └── res
│ ├── layout
│ ├── main_activity.xml
│ ├── main_list_item.xml
│ └── video_surfaceview.xml
│ ├── menu
│ └── main_activity.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ └── values
│ ├── constans.xml
│ └── strings.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── library-jni
└── jni
│ ├── Android-tropicssl.mk
│ ├── Android.mk
│ ├── Application.mk
│ ├── aes-protocol.c
│ ├── aes-protocol.h
│ ├── android-ndk-profiler-3.1
│ ├── android-ndk-profiler.mk
│ ├── armeabi-v7a
│ │ └── libandprof.a
│ ├── armeabi
│ │ └── libandprof.a
│ └── prof.h
│ ├── blend.c
│ ├── blend.h
│ ├── build_android.sh
│ ├── convert.cpp
│ ├── convert.h
│ ├── fetch.sh
│ ├── ffmpeg-jni.c
│ ├── helpers.c
│ ├── helpers.h
│ ├── jni-protocol.c
│ ├── jni-protocol.h
│ ├── nativetester-jni.c
│ ├── nativetester.c
│ ├── nativetester.h
│ ├── player.c
│ ├── player.h
│ ├── queue.c
│ ├── queue.h
│ └── sync.h
├── library
├── build.gradle
├── lint.xml
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── appunite
│ │ └── ffmpeg
│ │ ├── FFmpegDisplay.java
│ │ ├── FFmpegError.java
│ │ ├── FFmpegListener.java
│ │ ├── FFmpegPlayer.java
│ │ ├── FFmpegStreamInfo.java
│ │ ├── FFmpegSurfaceView.java
│ │ ├── FpsCounter.java
│ │ ├── JniReader.java
│ │ ├── NativeTester.java
│ │ ├── NotPlayingException.java
│ │ ├── SeekerView.java
│ │ └── ViewCompat.java
│ ├── jniLibs
│ └── res
│ └── values
│ ├── attrs.xml
│ └── styles.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | #Specific
2 | library-jni/libs/
3 | library-jni/obj/
4 | library-jni/jni/ffmpeg-build/
5 |
6 | #IntelliJ IDEA
7 | .idea
8 | *.iml
9 | *.ipr
10 | *.iws
11 | classes
12 | gen-external-apklibs
13 |
14 | #Gradle
15 | .gradle
16 | build
17 | local.properties
18 |
19 | #Other
20 | .DS_Store
21 | tmp
22 | *.swp
23 | *.tmp
24 | *.bak
25 | *.swp
26 | *.launch
27 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "library-jni/jni/ffmpeg"]
2 | path = library-jni/jni/ffmpeg
3 | url = git://source.ffmpeg.org/ffmpeg.git
4 | [submodule "library-jni/jni/vo-aacenc"]
5 | path = library-jni/jni/vo-aacenc
6 | url = git://git.code.sf.net/p/opencore-amr/vo-aacenc
7 | [submodule "library-jni/jni/vo-amrwbenc"]
8 | path = library-jni/jni/vo-amrwbenc
9 | url = git://git.code.sf.net/p/opencore-amr/vo-amrwbenc
10 | [submodule "library-jni/jni/x264"]
11 | path = library-jni/jni/x264
12 | url = git://git.videolan.org/x264.git
13 | [submodule "library-jni/jni/tropicssl"]
14 | path = library-jni/jni/tropicssl
15 | url = https://github.com/appunite/tropicssl.git
16 | [submodule "library-jni/jni/libass"]
17 | path = library-jni/jni/libass
18 | url = https://github.com/libass/libass.git
19 | [submodule "library-jni/jni/fribidi"]
20 | path = library-jni/jni/fribidi
21 | url = https://github.com/appunite/fribidi.git
22 | [submodule "library-jni/jni/freetype2"]
23 | path = library-jni/jni/freetype2
24 | url = git://git.sv.gnu.org/freetype/freetype2.git
25 | [submodule "library-jni/jni/libyuv"]
26 | path = library-jni/jni/libyuv
27 | url = https://chromium.googlesource.com/external/libyuv
28 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk7
3 | sudo: false
4 |
5 | env:
6 | global:
7 | - NDK_VERSION=r10e
8 |
9 | addons:
10 | apt:
11 | packages:
12 | - libgd2-xpm
13 | - ia32-libs
14 | - ia32-libs-multiarch
15 | - yasm
16 | - pkg-config
17 | - make
18 | - autoconf
19 | - libtool
20 | - make
21 | - autoconf-archive
22 | - automake
23 |
24 | cache:
25 | directories:
26 | - $HOME/.gradle/caches
27 |
28 | android:
29 | components:
30 | - build-tools-22.0.1
31 | - android-15
32 | - extra-android-m2repository
33 | licenses:
34 | - 'android-sdk-preview-license-52d11cd2'
35 | - 'android-sdk-license-.+'
36 | - 'google-gdk-license-.+'
37 |
38 | before_install:
39 | # Android NDK
40 | - if [ `uname -m` = x86_64 ]; then wget http://dl.google.com/android/ndk/android-ndk-$NDK_VERSION-linux-x86_64.bin -O ndk.bin; else wget http://dl.google.com/android/ndk/android-ndk-$NDK_VERSION-linux-x86.bin -O ndk.bin; fi
41 | - chmod a+x ndk.bin
42 | - ./ndk.bin | egrep -v ^Extracting
43 | - rm ndk.bin
44 | - export ANDROID_NDK_HOME=`pwd`/android-ndk-$NDK_VERSION
45 | - export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${ANDROID_NDK_HOME}
46 | install:
47 | - sh -c 'cd library-jni/jni/ && ./fetch.sh'
48 | - sh -c 'cd library-jni/jni && ./build_android.sh'
49 | - sh -c 'cd library-jni/jni && ndk-build'
50 | - rm -rf $ANDROID_NDK_HOME
51 | - rm -rf library-jni/jni
52 | - TERM=dumb ./gradlew build
53 |
54 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AndroidFFmpegLibrary
2 | This project aims to create **working** library providing playing video files in android via ffmpeg libraries. With some effort and NDK knowledge you can use this ffmpeg libraries build to convert video files.
3 | We rather want to use ffmpeg library without modifications to facilitate updating of ffmpeg core.
4 |
5 | 
6 |
7 | This project aim to simplify compilation of FFmpeg for android different architectures to one big apk file.
8 |
9 | I'm afraid this project is not prepared for android beginners - build it and using it requires some NDK skills.
10 |
11 | [](https://travis-ci.org/appunite/AndroidFFmpeg)
12 |
13 | ## License
14 | Copyright (C) 2012 Appunite.com
15 | Licensed under the Apache License, Verision 2.0
16 |
17 | FFmpeg, libvo-aacenc, vo-amrwbenc, libyuv and others libraries projects are distributed on theirs own license.
18 |
19 | ## Patent disclaimer
20 | We do not grant of patent rights.
21 | Some codecs use patented techniques and before use those parts of library you have to buy thrid-party patents.
22 |
23 | ## Pre-requirments
24 | on mac: you have to install xcode and command tools from xcode preferences
25 | you have to install (on mac you can use brew command from homebrew):
26 | you have to install:
27 | - autoconf
28 | - libtool
29 | - make
30 | - autoconf-archive
31 | - automake
32 | - pkg-config
33 | - git
34 |
35 | on Debian/Ubuntu - you can use apt-get
36 |
37 | on Mac - you can use tool brew from homebrew project. You have additionally install xcode.
38 |
39 | ## Bug reporting and questions
40 |
41 | **Please read instruciton very carefully**. A lot of people had trouble because they did not read this manual with attention. **If you have some problems or questions do not send me emails**. First: look on past issues on github. Than: try figure out problem with google. If you did not find solution then you can ask on github issue tracker.
42 |
43 | ## Installation
44 |
45 | ### Go to the work
46 | downloading source code
47 |
48 | git clone --recurse-submodules https://github.com/appunite/AndroidFFmpeg.git AndroidFFmpeg
49 | cd AndroidFFmpeg
50 | git submodule init
51 | git submodule sync #if you are updating source code
52 | git submodule update
53 | cd library-jni
54 | cd jni
55 |
56 | download libyuv and configure libs
57 |
58 | ./fetch.sh
59 |
60 | build external libraries
61 | Download r8e ndk: https://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86_64.tar.bz2 or
62 | ttps://dl.google.com/android/ndk/android-ndk-r8e-linux-x86_64.tar.bz2
63 | Now it should also support r10e
64 |
65 | export ANDROID_NDK_HOME=/your/path/to/android-ndk
66 | ./build_android.sh
67 |
68 | make sure that files library-jni/jni/ffmpeg-build/{armeabi,armeabi-v7a,x86}/libffmpeg.so was created, otherwise you are in truble
69 |
70 |
71 | build ndk jni library (in `library-jni` directory)
72 |
73 | export PATH="${PATH}:${ANDROID_NDK_HOME}"
74 | ndk-build
75 |
76 | make sure that files library-jni/libs/{armeabi,armeabi-v7a,x86}/libffmpeg.so was created, otherwise you are in truble
77 |
78 | build your project
79 |
80 | ./gradlew build
81 |
82 | ## More codecs
83 | If you need more codecs:
84 | - edit build_android.sh
85 | - add more codecs in ffmpeg configuration section
86 | - remove old ffmpeg-build directory by
87 |
88 | rm -r ffmpeg-build
89 |
90 | - build ffmpeg end supporting libraries
91 |
92 | ./build_android.sh
93 |
94 | During this process make sure that ffmpeg configuration goes without error.
95 |
96 | After build make sure that files FFmpegLibrary/jni/ffmpeg-build/{armeabi,armeabi-v7a,x86}/libffmpeg.so was created, otherwise you are in truble
97 |
98 | - build your ndk library
99 |
100 | ndk-build
101 |
102 | - refresh your FFmpegLibrary project in eclipse!!!!
103 | - build your FFmpegExample project
104 |
105 |
106 | ## Credits
107 | Library made by Jacek Marchwicki from Appunite.com
108 |
109 | - Thanks to Martin Böhme for writing tutorial: http://www.inb.uni-luebeck.de/~boehme/libavcodec_update.html
110 | - Thanks to Stephen Dranger for writing tutorial: http://dranger.com/ffmpeg/
111 | - Thanks to Liu Feipeng for writing blog: http://www.roman10.net/how-to-port-ffmpeg-the-program-to-androidideas-and-thoughts/
112 | - Thanks to ffmpeg team for writing cool stuff http://ffmpeg.org
113 | - Thanks to Alvaro for writing blog: http://odroid.foros-phpbb.com/t338-ffmpeg-compiled-with-android-ndk
114 | - Thanks to android-fplayer for sample code: http://code.google.com/p/android-fplayer/
115 | - Thanks to best-video-player for sample code: http://code.google.com/p/best-video-player/
116 | - Thanks to Robin Watts for his work in yuv2rgb converter http://wss.co.uk/pinknoise/yuv2rgb/
117 | - Thanks to Mohamed Naufal (https://github.com/hexene) and Martin Storsjö (https://github.com/mstorsjo) for theirs work on sample code for stagefright/openmax integration layer.
118 | - Thanks www.fourcc.org for theirs http://www.fourcc.org/yuv.php page
119 | - Thanks to Cedric Fungfor his blog bost: http://vec.io/posts/use-android-hardware-decoder-with-omxcodec-in-ndk
120 | - Thanks Google/Google chrome/Chromium teams for libyuv library https://code.google.com/p/libyuv/
121 | - Thanks to Picker Wengs for this slides about android multimedia stack http://www.slideshare.net/pickerweng/android-multimedia-framework
122 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | }
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:1.2.3'
8 | }
9 | }
10 |
11 | allprojects {
12 | repositories {
13 | jcenter()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/example/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | dependencies {
4 | compile 'com.android.support:support-v4:22.1.1'
5 | compile "javax.annotation:javax.annotation-api:1.2"
6 | compile "com.google.code.findbugs:jsr305:2.0.1"
7 |
8 | compile(project(":library"))
9 | }
10 |
11 | android {
12 | compileSdkVersion 15
13 | buildToolsVersion "22.0.1"
14 |
15 | defaultConfig {
16 | minSdkVersion 9
17 | targetSdkVersion 17
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/example/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
27 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/example/src/main/java/com/ffmpegtest/AppConstants.java:
--------------------------------------------------------------------------------
1 | package com.ffmpegtest;
2 |
3 | public class AppConstants {
4 | public static final String VIDEO_PLAY_ACTION = "com.ffmpegtest.VIDEO_PLAY_ACTION";
5 | public static final String VIDEO_PLAY_ACTION_EXTRA_URL = "url";
6 | public static final String VIDEO_PLAY_ACTION_EXTRA_ENCRYPTION_KEY = "encryption_key";
7 | }
8 |
--------------------------------------------------------------------------------
/example/src/main/java/com/ffmpegtest/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.ffmpegtest;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | import android.app.Activity;
8 | import android.content.Intent;
9 | import android.os.Bundle;
10 | import android.os.Environment;
11 | import android.support.annotation.NonNull;
12 | import android.view.LayoutInflater;
13 | import android.view.Menu;
14 | import android.view.View;
15 | import android.widget.AdapterView;
16 | import android.widget.AdapterView.OnItemClickListener;
17 | import android.widget.EditText;
18 | import android.widget.ListView;
19 |
20 | import com.ffmpegtest.adapter.ItemsAdapter;
21 | import com.ffmpegtest.adapter.VideoItem;
22 |
23 | public class MainActivity extends Activity implements OnItemClickListener {
24 |
25 | private ItemsAdapter adapter;
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | setContentView(R.layout.main_activity);
31 |
32 | final ListView listView = (ListView) findViewById(R.id.main_activity_list);
33 | final EditText editText = (EditText) findViewById(R.id.main_activity_video_url);
34 | final View button = findViewById(R.id.main_activity_play_button);
35 |
36 | final UserPreferences userPreferences = new UserPreferences(this);
37 | if (savedInstanceState == null) {
38 | editText.setText(userPreferences.getUrl());
39 | }
40 | adapter = new ItemsAdapter(LayoutInflater.from(this));
41 | adapter.swapItems(getVideoItems());
42 |
43 | listView.setAdapter(adapter);
44 | listView.setOnItemClickListener(this);
45 |
46 | button.setOnClickListener(new View.OnClickListener() {
47 | @Override
48 | public void onClick(View v) {
49 | final String url = String.valueOf(editText.getText());
50 | playVideo(url);
51 | userPreferences.setUrl(url);
52 | }
53 | });
54 | }
55 |
56 | private void playVideo(String url) {
57 | final Intent intent = new Intent(AppConstants.VIDEO_PLAY_ACTION)
58 | .putExtra(AppConstants.VIDEO_PLAY_ACTION_EXTRA_URL, url);
59 | startActivity(intent);
60 | }
61 |
62 | @NonNull
63 | private List getVideoItems() {
64 | final List items = new ArrayList();
65 | items.add(new VideoItem(
66 | items.size(),
67 | "\"localfile.mp4\" on sdcard",
68 | getSDCardFile("localfile.mp4"),
69 | null));
70 | items.add(new VideoItem(
71 | items.size(),
72 | "Apple sample",
73 | "http://devimages.apple.com.edgekey.net/resources/http-streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8",
74 | null));
75 | items.add(new VideoItem(
76 | items.size(),
77 | "Apple advenced sample",
78 | "https://devimages.apple.com.edgekey.net/resources/http-streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8",
79 | null));
80 | items.add(new VideoItem(
81 | items.size(),
82 | "IP camera",
83 | "rtsp://ip.appunite-local.net:554",
84 | null));
85 | return items;
86 | }
87 |
88 | private static String getSDCardFile(String file) {
89 | File videoFile = new File(Environment.getExternalStorageDirectory(),
90 | file);
91 | return "file://" + videoFile.getAbsolutePath();
92 | }
93 |
94 | @Override
95 | public boolean onCreateOptionsMenu(Menu menu) {
96 | getMenuInflater().inflate(R.menu.main_activity, menu);
97 | return true;
98 | }
99 |
100 | @Override
101 | public void onItemClick(AdapterView> listView, View view, int position, long id) {
102 | final VideoItem videoItem = adapter.getItem(position);
103 | final Intent intent = new Intent(AppConstants.VIDEO_PLAY_ACTION)
104 | .putExtra(AppConstants.VIDEO_PLAY_ACTION_EXTRA_URL, videoItem.video())
105 | .putExtra(AppConstants.VIDEO_PLAY_ACTION_EXTRA_ENCRYPTION_KEY, videoItem.video());
106 | startActivity(intent);
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/example/src/main/java/com/ffmpegtest/UserPreferences.java:
--------------------------------------------------------------------------------
1 | package com.ffmpegtest;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.support.annotation.Nullable;
6 |
7 | import javax.annotation.Nonnull;
8 |
9 | public class UserPreferences {
10 |
11 | public static final String USER_PREFERENCES = "USER_PREFERENCES";
12 | private static final String KEY_URL = "url";
13 | private final SharedPreferences preferences;
14 |
15 | public UserPreferences(@Nonnull Context context) {
16 | preferences = context.getSharedPreferences(USER_PREFERENCES, 0);
17 | }
18 |
19 | public void setUrl(@Nullable String url) {
20 | preferences.edit().putString(KEY_URL, url).apply();
21 | }
22 |
23 | @Nullable
24 | public String getUrl() {
25 | return preferences.getString(KEY_URL, "rtsp://ip.appunite-local.net:554");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/example/src/main/java/com/ffmpegtest/VideoActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MainActivity.java
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | package com.ffmpegtest;
20 |
21 | import java.io.File;
22 | import java.util.HashMap;
23 | import java.util.Locale;
24 |
25 | import android.annotation.TargetApi;
26 | import android.app.Activity;
27 | import android.app.AlertDialog;
28 | import android.app.AlertDialog.Builder;
29 | import android.content.DialogInterface;
30 | import android.content.Intent;
31 | import android.content.pm.ActivityInfo;
32 | import android.database.Cursor;
33 | import android.database.MatrixCursor;
34 | import android.graphics.PixelFormat;
35 | import android.net.Uri;
36 | import android.os.Build;
37 | import android.os.Bundle;
38 | import android.os.Environment;
39 | import android.provider.BaseColumns;
40 | import android.support.v4.widget.SimpleCursorAdapter;
41 | import android.view.View;
42 | import android.view.View.OnClickListener;
43 | import android.view.Window;
44 | import android.view.WindowManager;
45 | import android.widget.AdapterView;
46 | import android.widget.AdapterView.OnItemSelectedListener;
47 | import android.widget.Button;
48 | import android.widget.SeekBar;
49 | import android.widget.SeekBar.OnSeekBarChangeListener;
50 | import android.widget.Spinner;
51 |
52 | import com.appunite.ffmpeg.FFmpegDisplay;
53 | import com.appunite.ffmpeg.FFmpegError;
54 | import com.appunite.ffmpeg.FFmpegListener;
55 | import com.appunite.ffmpeg.FFmpegPlayer;
56 | import com.appunite.ffmpeg.FFmpegStreamInfo;
57 | import com.appunite.ffmpeg.FFmpegStreamInfo.CodecType;
58 | import com.appunite.ffmpeg.NotPlayingException;
59 |
60 | public class VideoActivity extends Activity implements OnClickListener,
61 | FFmpegListener, OnSeekBarChangeListener, OnItemSelectedListener {
62 |
63 | private static final String[] PROJECTION = new String[] {"title", BaseColumns._ID};
64 | private static final int PROJECTION_ID = 1;
65 |
66 | private FFmpegPlayer mMpegPlayer;
67 | protected boolean mPlay = false;
68 | private View mControlsView;
69 | private View mLoadingView;
70 | private SeekBar mSeekBar;
71 | private View mVideoView;
72 | private Button mPlayPauseButton;
73 | private boolean mTracking = false;
74 | private View mStreamsView;
75 | private Spinner mLanguageSpinner;
76 | private int mLanguageSpinnerSelectedPosition = 0;
77 | private Spinner mSubtitleSpinner;
78 | private int mSubtitleSpinnerSelectedPosition = 0;
79 | private SimpleCursorAdapter mLanguageAdapter;
80 | private SimpleCursorAdapter mSubtitleAdapter;
81 |
82 | private int mAudioStreamNo = FFmpegPlayer.UNKNOWN_STREAM;
83 | private int mSubtitleStreamNo = FFmpegPlayer.NO_STREAM;
84 | private View mScaleButton;
85 | private long mCurrentTimeUs;
86 |
87 | @Override
88 | public void onCreate(Bundle savedInstanceState) {
89 | this.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
90 | getWindow().setFormat(PixelFormat.RGBA_8888);
91 | getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DITHER);
92 |
93 | super.onCreate(savedInstanceState);
94 |
95 | this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
96 | this.getWindow().clearFlags(
97 | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
98 | this.getWindow().setBackgroundDrawable(null);
99 |
100 | this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
101 |
102 | this.setContentView(R.layout.video_surfaceview);
103 |
104 | mSeekBar = (SeekBar) this.findViewById(R.id.seek_bar);
105 | mSeekBar.setOnSeekBarChangeListener(this);
106 |
107 | mPlayPauseButton = (Button) this.findViewById(R.id.play_pause);
108 | mPlayPauseButton.setOnClickListener(this);
109 |
110 | mScaleButton = this.findViewById(R.id.scale_type);
111 | mScaleButton.setOnClickListener(this);
112 |
113 | mControlsView = this.findViewById(R.id.controls);
114 | mStreamsView = this.findViewById(R.id.streams);
115 | mLoadingView = this.findViewById(R.id.loading_view);
116 | mLanguageSpinner = (Spinner) this.findViewById(R.id.language_spinner);
117 | mSubtitleSpinner = (Spinner) this.findViewById(R.id.subtitle_spinner);
118 |
119 | mLanguageAdapter = new SimpleCursorAdapter(this,
120 | android.R.layout.simple_spinner_item, null, PROJECTION,
121 | new int[] { android.R.id.text1 }, 0);
122 | mLanguageAdapter
123 | .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
124 |
125 | mLanguageSpinner.setAdapter(mLanguageAdapter);
126 | mLanguageSpinner.setOnItemSelectedListener(this);
127 |
128 | mSubtitleAdapter = new SimpleCursorAdapter(this,
129 | android.R.layout.simple_spinner_item, null, PROJECTION,
130 | new int[] { android.R.id.text1 }, 0);
131 | mSubtitleAdapter
132 | .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
133 |
134 | mSubtitleSpinner.setAdapter(mSubtitleAdapter);
135 | mSubtitleSpinner.setOnItemSelectedListener(this);
136 |
137 | mVideoView = this.findViewById(R.id.video_view);
138 | mMpegPlayer = new FFmpegPlayer((FFmpegDisplay) mVideoView, this);
139 | mMpegPlayer.setMpegListener(this);
140 | setDataSource();
141 | }
142 |
143 | @Override
144 | protected void onPause() {
145 | super.onPause();
146 | };
147 |
148 | @Override
149 | protected void onResume() {
150 | super.onResume();
151 | }
152 |
153 | @Override
154 | protected void onDestroy() {
155 | super.onDestroy();
156 | this.mMpegPlayer.setMpegListener(null);
157 | this.mMpegPlayer.stop();
158 | stop();
159 | }
160 |
161 | private void setDataSource() {
162 | HashMap params = new HashMap();
163 |
164 | // set font for ass
165 | File assFont = new File(Environment.getExternalStorageDirectory(),
166 | "DroidSansFallback.ttf");
167 | params.put("ass_default_font_path", assFont.getAbsolutePath());
168 |
169 | Intent intent = getIntent();
170 | Uri uri = intent.getData();
171 | String url;
172 | if (uri != null) {
173 | url = uri.toString();
174 | } else {
175 | url = intent
176 | .getStringExtra(AppConstants.VIDEO_PLAY_ACTION_EXTRA_URL);
177 | if (url == null) {
178 | throw new IllegalArgumentException(String.format(
179 | "\"%s\" did not provided",
180 | AppConstants.VIDEO_PLAY_ACTION_EXTRA_URL));
181 | }
182 | if (intent
183 | .hasExtra(AppConstants.VIDEO_PLAY_ACTION_EXTRA_ENCRYPTION_KEY)) {
184 | params.put(
185 | "aeskey",
186 | intent.getStringExtra(AppConstants.VIDEO_PLAY_ACTION_EXTRA_ENCRYPTION_KEY));
187 | }
188 | }
189 |
190 | this.mPlayPauseButton
191 | .setBackgroundResource(android.R.drawable.ic_media_play);
192 | this.mPlayPauseButton.setEnabled(true);
193 | mPlay = false;
194 |
195 | mMpegPlayer.setDataSource(url, params, FFmpegPlayer.UNKNOWN_STREAM, mAudioStreamNo,
196 | mSubtitleStreamNo);
197 |
198 | }
199 |
200 | @Override
201 | public void onClick(View v) {
202 | int viewId = v.getId();
203 | switch (viewId) {
204 | case R.id.play_pause:
205 | resumePause();
206 | return;
207 | case R.id.scale_type:
208 | return;
209 | default:
210 | throw new RuntimeException();
211 | }
212 | }
213 |
214 | @Override
215 | public void onFFUpdateTime(long currentTimeUs, long videoDurationUs, boolean isFinished) {
216 | mCurrentTimeUs = currentTimeUs;
217 | if (!mTracking) {
218 | int currentTimeS = (int)(currentTimeUs / 1000 / 1000);
219 | int videoDurationS = (int)(videoDurationUs / 1000 / 1000);
220 | mSeekBar.setMax(videoDurationS);
221 | mSeekBar.setProgress(currentTimeS);
222 | }
223 |
224 | if (isFinished) {
225 | new AlertDialog.Builder(this)
226 | .setTitle(R.string.dialog_end_of_video_title)
227 | .setMessage(R.string.dialog_end_of_video_message)
228 | .setCancelable(true).show();
229 | }
230 | }
231 |
232 | @Override
233 | public void onFFDataSourceLoaded(FFmpegError err, FFmpegStreamInfo[] streams) {
234 | if (err != null) {
235 | String format = getResources().getString(
236 | R.string.main_could_not_open_stream);
237 | String message = String.format(format, err.getMessage());
238 |
239 | Builder builder = new AlertDialog.Builder(VideoActivity.this);
240 | builder.setTitle(R.string.app_name)
241 | .setMessage(message)
242 | .setOnCancelListener(
243 | new DialogInterface.OnCancelListener() {
244 |
245 | @Override
246 | public void onCancel(DialogInterface dialog) {
247 | VideoActivity.this.finish();
248 | }
249 | }).show();
250 | return;
251 | }
252 | mPlayPauseButton.setBackgroundResource(android.R.drawable.ic_media_play);
253 | mPlayPauseButton.setEnabled(true);
254 | this.mControlsView.setVisibility(View.VISIBLE);
255 | this.mStreamsView.setVisibility(View.VISIBLE);
256 | this.mLoadingView.setVisibility(View.GONE);
257 | MatrixCursor audio = new MatrixCursor(PROJECTION);
258 | MatrixCursor subtitles = new MatrixCursor(PROJECTION);
259 | subtitles.addRow(new Object[] {"None", FFmpegPlayer.NO_STREAM});
260 | for (FFmpegStreamInfo streamInfo : streams) {
261 | CodecType mediaType = streamInfo.getMediaType();
262 | Locale locale = streamInfo.getLanguage();
263 | String languageName = locale == null ? getString(
264 | R.string.unknown) : locale.getDisplayLanguage();
265 | if (FFmpegStreamInfo.CodecType.AUDIO.equals(mediaType)) {
266 | audio.addRow(new Object[] {languageName, streamInfo.getStreamNumber()});
267 | } else if (FFmpegStreamInfo.CodecType.SUBTITLE.equals(mediaType)) {
268 | subtitles.addRow(new Object[] {languageName, streamInfo.getStreamNumber()});
269 | }
270 | }
271 | mLanguageAdapter.swapCursor(audio);
272 | mSubtitleAdapter.swapCursor(subtitles);
273 | }
274 |
275 | private void displaySystemMenu(boolean visible) {
276 | if (Build.VERSION.SDK_INT >= 14) {
277 | displaySystemMenu14(visible);
278 | } else if (Build.VERSION.SDK_INT >= 11) {
279 | displaySystemMenu11(visible);
280 | }
281 | }
282 |
283 | @SuppressWarnings("deprecation")
284 | @TargetApi(11)
285 | private void displaySystemMenu11(boolean visible) {
286 | if (visible) {
287 | this.mVideoView.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
288 | } else {
289 | this.mVideoView.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
290 | }
291 | }
292 |
293 | @TargetApi(14)
294 | private void displaySystemMenu14(boolean visible) {
295 | if (visible) {
296 | this.mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
297 | } else {
298 | this.mVideoView
299 | .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
300 | }
301 | }
302 |
303 | public void resumePause() {
304 | this.mPlayPauseButton.setEnabled(false);
305 | if (mPlay) {
306 | mMpegPlayer.pause();
307 | } else {
308 | mMpegPlayer.resume();
309 | displaySystemMenu(true);
310 | }
311 | mPlay = !mPlay;
312 | }
313 |
314 | @Override
315 | public void onFFResume(NotPlayingException result) {
316 | this.mPlayPauseButton
317 | .setBackgroundResource(android.R.drawable.ic_media_pause);
318 | this.mPlayPauseButton.setEnabled(true);
319 |
320 | displaySystemMenu(false);
321 | mPlay = true;
322 | }
323 |
324 | @Override
325 | public void onFFPause(NotPlayingException err) {
326 | this.mPlayPauseButton
327 | .setBackgroundResource(android.R.drawable.ic_media_play);
328 | this.mPlayPauseButton.setEnabled(true);
329 | mPlay = false;
330 | }
331 |
332 | private void stop() {
333 | this.mControlsView.setVisibility(View.GONE);
334 | this.mStreamsView.setVisibility(View.GONE);
335 | this.mLoadingView.setVisibility(View.VISIBLE);
336 | }
337 |
338 | @Override
339 | public void onFFStop() {
340 | }
341 |
342 | @Override
343 | public void onFFSeeked(NotPlayingException result) {
344 | // if (result != null)
345 | // throw new RuntimeException(result);
346 | }
347 |
348 | @Override
349 | public void onProgressChanged(SeekBar seekBar, int progress,
350 | boolean fromUser) {
351 | if (fromUser) {
352 | long timeUs = progress * 1000 * 1000;
353 | mMpegPlayer.seek(timeUs);
354 | }
355 | }
356 |
357 | @Override
358 | public void onStartTrackingTouch(SeekBar seekBar) {
359 | mTracking = true;
360 | }
361 |
362 | @Override
363 | public void onStopTrackingTouch(SeekBar seekBar) {
364 | mTracking = false;
365 | }
366 |
367 | private void setDataSourceAndResumeState() {
368 | setDataSource();
369 | mMpegPlayer.seek(mCurrentTimeUs);
370 | mMpegPlayer.resume();
371 | }
372 |
373 | @Override
374 | public void onItemSelected(AdapterView> parentView,
375 | View selectedItemView, int position, long id) {
376 | Cursor c = (Cursor) parentView
377 | .getItemAtPosition(position);
378 | if (parentView == mLanguageSpinner) {
379 | if (mLanguageSpinnerSelectedPosition != position) {
380 | mLanguageSpinnerSelectedPosition = position;
381 | mAudioStreamNo = c.getInt(PROJECTION_ID);
382 | setDataSourceAndResumeState();
383 | }
384 | } else if (parentView == mSubtitleSpinner) {
385 | if (mSubtitleSpinnerSelectedPosition != position) {
386 | mSubtitleSpinnerSelectedPosition = position;
387 | mSubtitleStreamNo = c.getInt(PROJECTION_ID);
388 | setDataSourceAndResumeState();
389 | }
390 | } else {
391 | throw new RuntimeException();
392 | }
393 | }
394 |
395 | @Override
396 | public void onNothingSelected(AdapterView> parentView) {
397 | // if (parentView == languageSpinner) {
398 | // audioStream = null;
399 | // } else if (parentView == subtitleSpinner) {
400 | // subtitleStream = null;
401 | // } else {
402 | // throw new RuntimeException();
403 | // }
404 | // play();
405 | }
406 |
407 | }
408 |
--------------------------------------------------------------------------------
/example/src/main/java/com/ffmpegtest/adapter/ItemsAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ffmpegtest.adapter;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.BaseAdapter;
7 | import android.widget.TextView;
8 |
9 | import com.ffmpegtest.R;
10 | import com.ffmpegtest.adapter.VideoItem;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | import javax.annotation.Nonnull;
16 |
17 | public class ItemsAdapter extends BaseAdapter {
18 | @Nonnull
19 | private final LayoutInflater inflater;
20 | private List videoItems = new ArrayList();
21 |
22 | public static class ViewHolder {
23 |
24 | @Nonnull
25 | private final View view;
26 | @Nonnull
27 | private final TextView textView;
28 |
29 | public static ViewHolder fromConvertView(@Nonnull View convertView) {
30 | return (ViewHolder) convertView.getTag();
31 | }
32 |
33 | public ViewHolder(@Nonnull LayoutInflater inflater, @Nonnull ViewGroup parent) {
34 | view = inflater.inflate(R.layout.main_list_item, parent, false);
35 | textView = (TextView) view.findViewById(R.id.main_list_item_text);
36 | view.setTag(this);
37 | }
38 |
39 | @Nonnull
40 | public View getView() {
41 | return view;
42 | }
43 |
44 | public void bind(@Nonnull VideoItem videoItem) {
45 | textView.setText(videoItem.text());
46 | }
47 | }
48 |
49 | public ItemsAdapter(@Nonnull LayoutInflater inflater) {
50 | this.inflater = inflater;
51 | }
52 |
53 | @Override
54 | public int getCount() {
55 | return videoItems.size();
56 | }
57 |
58 | @Override
59 | public VideoItem getItem(int position) {
60 | return videoItems.get(position);
61 | }
62 |
63 | @Override
64 | public long getItemId(int position) {
65 | return videoItems.get(position).id();
66 | }
67 |
68 | @Override
69 | public View getView(int position, View convertView, ViewGroup parent) {
70 | final ViewHolder holder;
71 | if (convertView == null) {
72 | holder = new ViewHolder(inflater, parent);
73 | convertView = holder.getView();
74 | } else {
75 | holder = ViewHolder.fromConvertView(convertView);
76 | }
77 | holder.bind(videoItems.get(position));
78 | return convertView;
79 | }
80 |
81 | public void swapItems(@Nonnull List items) {
82 | videoItems = items;
83 | notifyDataSetChanged();
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/example/src/main/java/com/ffmpegtest/adapter/VideoItem.java:
--------------------------------------------------------------------------------
1 | package com.ffmpegtest.adapter;
2 |
3 | import android.support.annotation.Nullable;
4 |
5 | import javax.annotation.Nonnull;
6 |
7 | public class VideoItem {
8 | private final long id;
9 | @Nullable
10 | private final String text;
11 | @Nonnull
12 | private String video;
13 | @Nullable
14 | private String key;
15 |
16 | public VideoItem(long id,
17 | @Nullable String text,
18 | @Nonnull String video,
19 | @Nullable String key) {
20 | this.id = id;
21 | this.text = text;
22 | this.video = video;
23 | this.key = key;
24 | }
25 |
26 | public long id() {
27 | return id;
28 | }
29 |
30 | @Nullable
31 | public String text() {
32 | return text;
33 | }
34 |
35 | @Nonnull
36 | public String video() {
37 | return video;
38 | }
39 |
40 | @Nullable
41 | public String key() {
42 | return key;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/example/src/main/res/layout/main_activity.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
15 |
16 |
20 |
28 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/example/src/main/res/layout/main_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/example/src/main/res/layout/video_surfaceview.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
18 |
23 |
24 |
29 |
30 |
31 |
40 |
41 |
48 |
49 |
56 |
57 |
64 |
65 |
66 |
73 |
74 |
81 |
82 |
--------------------------------------------------------------------------------
/example/src/main/res/menu/main_activity.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/e8a1dd26ee293630d8cb18885b729786bac06d7c/example/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/e8a1dd26ee293630d8cb18885b729786bac06d7c/example/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/e8a1dd26ee293630d8cb18885b729786bac06d7c/example/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/e8a1dd26ee293630d8cb18885b729786bac06d7c/example/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/e8a1dd26ee293630d8cb18885b729786bac06d7c/example/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/src/main/res/values/constans.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - .3gp
5 | - .mp4
6 | - .avi
7 | - .mov
8 |
9 |
--------------------------------------------------------------------------------
/example/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hello World, FFmpegExampleActivity!
5 | FFmpegExample
6 | No videos
7 | Could not read videos directory
8 | Error!
9 | Select video file
10 | Convert Video
11 | Could not convert video
12 | Language: %s
13 | Subtitle: %s
14 | Unknown
15 | End of video
16 | End of video occure
17 | Could not open stream
18 | Hello world!
19 | Settings
20 | AndroidFFmpeg
21 | Video url
22 | Play
23 |
24 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/e8a1dd26ee293630d8cb18885b729786bac06d7c/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/library-jni/jni/Android-tropicssl.mk:
--------------------------------------------------------------------------------
1 | #the tropicssl library
2 | include $(CLEAR_VARS)
3 |
4 | LOCAL_CFLAGS := -std=gnu99
5 |
6 | SRC_FILES := \
7 | aes.c arc4.c base64.c \
8 | bignum.c certs.c debug.c \
9 | des.c dhm.c havege.c \
10 | md2.c md4.c md5.c \
11 | net.c padlock.c rsa.c \
12 | sha1.c sha2.c sha4.c \
13 | ssl_cli.c ssl_srv.c ssl_tls.c \
14 | timing.c x509parse.c xtea.c \
15 | camellia.c
16 | SRC_DIR=tropicssl/library
17 |
18 | #disable thumb
19 | LOCAL_ARM_MODE := arm
20 | LOCAL_CFLAGS := -O3
21 |
22 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/tropicssl/include/
23 | LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
24 | LOCAL_MODULE := tropicssl
25 | LOCAL_SRC_FILES := $(addprefix $(SRC_DIR)/,$(SRC_FILES))
26 |
27 | LOCAL_LDLIBS := -ldl -llog
28 |
29 | include $(BUILD_STATIC_LIBRARY)
30 |
--------------------------------------------------------------------------------
/library-jni/jni/Android.mk:
--------------------------------------------------------------------------------
1 | # Application.mk
2 | # Copyright (c) 2012 Jacek Marchwicki
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | LOCAL_PATH := $(call my-dir)
17 |
18 | include $(CLEAR_VARS)
19 |
20 | #presets - do not tuch this
21 | FEATURE_NEON:=
22 | LIBRARY_PROFILER:=
23 | MODULE_ENCRYPT:=
24 |
25 | #settings
26 |
27 | # add support for encryption
28 | MODULE_ENCRYPT:=yes
29 |
30 |
31 | #if armeabi-v7a
32 | ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
33 | # add neon optimization code (only armeabi-v7a)
34 | FEATURE_NEON:=yes
35 | else
36 |
37 | endif
38 |
39 | #if armeabi or armeabi-v7a
40 | ifeq ($(TARGET_ARCH_ABI),$(filter $(TARGET_ARCH_ABI),armeabi armeabi-v7a))
41 | # add profiler (only arm)
42 | #LIBRARY_PROFILER:=yes
43 |
44 | endif
45 |
46 |
47 |
48 |
49 | include $(CLEAR_VARS)
50 | LOCAL_MODULE := ffmpeg-prebuilt
51 | LOCAL_SRC_FILES := ffmpeg-build/$(TARGET_ARCH_ABI)/libffmpeg.so
52 | LOCAL_EXPORT_C_INCLUDES := ffmpeg-build/$(TARGET_ARCH_ABI)/include
53 | LOCAL_EXPORT_LDLIBS := ffmpeg-build/$(TARGET_ARCH_ABI)/libffmpeg.so
54 | LOCAL_PRELINK_MODULE := true
55 | include $(PREBUILT_SHARED_LIBRARY)
56 |
57 | ifdef FEATURE_NEON
58 | include $(CLEAR_VARS)
59 | LOCAL_MODULE := ffmpeg-prebuilt-neon
60 | LOCAL_SRC_FILES := ffmpeg-build/$(TARGET_ARCH_ABI)/libffmpeg-neon.so
61 | LOCAL_EXPORT_C_INCLUDES := ffmpeg-build/$(TARGET_ARCH_ABI)-neon/include
62 | LOCAL_EXPORT_LDLIBS := ffmpeg-build/$(TARGET_ARCH_ABI)/libffmpeg-neon.so
63 | LOCAL_PRELINK_MODULE := true
64 | include $(PREBUILT_SHARED_LIBRARY)
65 | endif
66 |
67 | #ffmpeg-jni library
68 | include $(CLEAR_VARS)
69 | LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
70 | LOCAL_MODULE := ffmpeg-jni
71 | LOCAL_SRC_FILES := ffmpeg-jni.c player.c queue.c helpers.c jni-protocol.c blend.c convert.cpp
72 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg-build/$(TARGET_ARCH_ABI)/include
73 | LOCAL_SHARED_LIBRARY := ffmpeg-prebuilt
74 |
75 | #if enabled profiler add it
76 | ifdef LIBRARY_PROFILER
77 | LOCAL_CFLAGS += -pg -g -DPROFILER
78 | LOCAL_STATIC_LIBRARIES += andprof
79 | LOCAL_REQUIRED_MODULES += andprof
80 | endif
81 |
82 | LOCAL_CFLAGS += -DLIBYUV
83 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/libyuv/include
84 | LOCAL_CPP_INCLUDES += $(LOCAL_PATH)/libyuv/include
85 | LOCAL_STATIC_LIBRARIES += libyuv_static
86 | LOCAL_REQUIRED_MODULES += libyuv_static
87 |
88 | ifdef MODULE_ENCRYPT
89 | LOCAL_CFLAGS += -DMODULE_ENCRYPT
90 | LOCAL_SRC_FILES += aes-protocol.c
91 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/tropicssl/include
92 | LOCAL_STATIC_LIBRARIES += tropicssl
93 | LOCAL_REQUIRED_MODULES += tropicssl
94 | endif
95 |
96 | LOCAL_LDLIBS += -landroid
97 | LOCAL_LDLIBS += -llog -ljnigraphics -lz -lm -g $(LOCAL_PATH)/ffmpeg-build/$(TARGET_ARCH_ABI)/libffmpeg.so
98 | include $(BUILD_SHARED_LIBRARY)
99 |
100 |
101 | ifdef FEATURE_NEON
102 | include $(CLEAR_VARS)
103 | LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
104 | LOCAL_MODULE := ffmpeg-jni-neon
105 | LOCAL_SRC_FILES := ffmpeg-jni.c player.c queue.c helpers.c jni-protocol.c blend.c convert.cpp
106 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg-build/$(TARGET_ARCH_ABI)/include
107 | LOCAL_SHARED_LIBRARY := ffmpeg-prebuilt-neon
108 |
109 | #if enabled profiler add it
110 | ifdef LIBRARY_PROFILER
111 | LOCAL_CFLAGS += -pg -g -DPROFILER
112 | LOCAL_STATIC_LIBRARIES += andprof
113 | LOCAL_REQUIRED_MODULES += andprof
114 | endif
115 |
116 | LOCAL_CFLAGS += -DLIBYUV
117 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/libyuv/include
118 | LOCAL_CPP_INCLUDES += $(LOCAL_PATH)/libyuv/include
119 | LOCAL_STATIC_LIBRARIES += libyuv_static
120 | LOCAL_REQUIRED_MODULES += libyuv_static
121 |
122 | ifdef MODULE_ENCRYPT
123 | LOCAL_CFLAGS += -DMODULE_ENCRYPT
124 | LOCAL_SRC_FILES += aes-protocol.c
125 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/tropicssl/include
126 | LOCAL_STATIC_LIBRARIES += tropicssl
127 | LOCAL_REQUIRED_MODULES += tropicssl
128 | endif
129 |
130 | LOCAL_LDLIBS += -landroid
131 | LOCAL_LDLIBS += -llog -ljnigraphics -lz -lm -g $(LOCAL_PATH)/ffmpeg-build/$(TARGET_ARCH_ABI)/libffmpeg-neon.so
132 | include $(BUILD_SHARED_LIBRARY)
133 | endif
134 |
135 |
136 | #nativetester-jni library
137 | include $(CLEAR_VARS)
138 |
139 | ifdef FEATURE_VFPV3
140 | LOCAL_CFLAGS += -DFEATURE_VFPV3
141 | endif
142 |
143 | ifdef FEATURE_NEON
144 | LOCAL_CFLAGS += -DFEATURE_NEON
145 | endif
146 |
147 | LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
148 | LOCAL_MODULE := nativetester-jni
149 | LOCAL_SRC_FILES := nativetester-jni.c nativetester.c
150 | LOCAL_STATIC_LIBRARIES := cpufeatures
151 | LOCAL_LDLIBS := -llog
152 | include $(BUILD_SHARED_LIBRARY)
153 |
154 |
155 | #includes
156 | ifdef MODULE_ENCRYPT
157 | include $(LOCAL_PATH)/Android-tropicssl.mk
158 | endif
159 |
160 | ifdef LIBRARY_PROFILER
161 | include $(LOCAL_PATH)/android-ndk-profiler-3.1/android-ndk-profiler.mk
162 | endif
163 |
164 | include $(call all-makefiles-under,$(LOCAL_PATH))
165 | $(call import-module,cpufeatures)
166 |
--------------------------------------------------------------------------------
/library-jni/jni/Application.mk:
--------------------------------------------------------------------------------
1 | # Application.mk
2 | # Copyright (c) 2012 Jacek Marchwicki
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | # The ARMv7 is significanly faster due to the use of the hardware FPU
17 | #APP_ABI := all
18 | APP_ABI := armeabi-v7a armeabi x86 mips
19 | APP_PLATFORM := android-10
20 | #APP_OPTIM := debug
21 |
22 | APP_STL := gnustl_static
23 |
--------------------------------------------------------------------------------
/library-jni/jni/aes-protocol.c:
--------------------------------------------------------------------------------
1 | /*
2 | * aes-protocol.c
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include "ffmpeg/libavformat/url.h"
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 |
30 | #include "aes-protocol.h"
31 |
32 | #define FALSE (0)
33 | #define TRUE (!FALSE)
34 |
35 | #include
36 | #define LOG_LEVEL 2
37 | #define LOG_TAG "aes-protocol.c"
38 | #define LOGI(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__);}
39 | #define LOGE(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);}
40 |
41 | #define RAW_KEY_SIZE 24
42 | #define BASE64_KEY_SIZE ((4 * RAW_KEY_SIZE) / 3)
43 | #define SHA256_KEY_SIZE 32
44 | #define AES_KEY_SIZE 16
45 | #define BUFFER_SIZE 512
46 |
47 | typedef struct {
48 | const AVClass *class;
49 | URLContext *hd;
50 | uint8_t *key;
51 | aes_context aes;
52 | unsigned char iv[AES_KEY_SIZE];
53 | unsigned char read_buff[BUFFER_SIZE];
54 | unsigned char decoded_buff[BUFFER_SIZE];
55 | int64_t reading_position;
56 | int64_t read_start_point;
57 | int64_t read_end_point;
58 | int64_t stream_end;
59 | } AesContext;
60 |
61 | #define OFFSET(x) offsetof(AesContext, x)
62 |
63 | static const AVOption options[] = { { "aeskey", "AES decryption key",
64 | OFFSET(key), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_DECODING_PARAM },
65 | { NULL } };
66 |
67 | static const AVClass aes_class = { .class_name = "aes", .item_name =
68 | av_default_item_name, .option = options, .version =
69 | LIBAVUTIL_VERSION_INT, };
70 |
71 | #define MAX_PRINT_LEN 2048
72 |
73 | #if LOG_LEVEL >= 10
74 | static char print_buff[MAX_PRINT_LEN * 2 + 1];
75 | #endif
76 |
77 | static void log_hex(char *log, char *data, int len) {
78 | #if LOG_LEVEL >= 10
79 | int i;
80 | if (len > MAX_PRINT_LEN) {
81 | LOGI(1,
82 | "log_hex: oversized log requested: %d, max size: %d", len, MAX_PRINT_LEN);
83 | len = MAX_PRINT_LEN;
84 | }
85 | for (i = 0; i < len; ++i)
86 | sprintf(&print_buff[i * 2], "%02X", (unsigned char) data[i]);
87 | LOGI(10, log, len, print_buff);
88 | #endif
89 | }
90 |
91 | static int aes_open(URLContext *h, const char *uri, int flags) {
92 | const char *nested_url;
93 | int ret = 0;
94 | AesContext *c = h->priv_data;
95 | LOGI(3, "aes_open: opening data");
96 |
97 | if (!av_strstart(uri, "aes+", &nested_url)
98 | && !av_strstart(uri, "aes:", &nested_url)) {
99 | av_log(h, AV_LOG_ERROR, "Unsupported url %s", uri);
100 | LOGE(1, "Unsupported url %s", uri);
101 | ret = AVERROR(EINVAL);
102 | goto err;
103 | }
104 |
105 | if (c->key == NULL) {
106 | av_log(h, AV_LOG_ERROR, "Key is not set\n");
107 | LOGE(1, "Key is not set");
108 | ret = AVERROR(EINVAL);
109 | goto err;
110 | }
111 | if (strlen(c->key) != BASE64_KEY_SIZE) {
112 | av_log(h, AV_LOG_ERROR, "Wrong size of key\n");
113 | LOGE(1, "Wrong size of key");
114 | ret = AVERROR(EINVAL);
115 | goto err;
116 | }
117 | if (flags & AVIO_FLAG_WRITE) {
118 | av_log(h, AV_LOG_ERROR, "Only decryption is supported currently\n");
119 | LOGE(1, "Only decryption is supported currently");
120 | ret = AVERROR(ENOSYS);
121 | goto err;
122 | }
123 | if ((ret = ffurl_open(&c->hd, nested_url, AVIO_FLAG_READ,
124 | &h->interrupt_callback, NULL)) < 0) {
125 | av_log(h, AV_LOG_ERROR, "Unable to open input\n");
126 | LOGE(1, "Unable to open input");
127 | goto err;
128 | }
129 | LOGI(3, "aes_open: opened data with key: %s", c->key);
130 | log_hex("aes_open: raw_key[%d]: %s", c->key, RAW_KEY_SIZE);
131 |
132 | memset(c->iv, 0, AES_KEY_SIZE);
133 | memset(c->read_buff, 0, BUFFER_SIZE);
134 | memset(c->decoded_buff, 0, BUFFER_SIZE);
135 | c->reading_position = 0;
136 | c->read_start_point = 0;
137 | c->read_end_point = 0;
138 | c->stream_end = -1;
139 |
140 | unsigned char sha256_key[SHA256_KEY_SIZE];
141 | sha2_context ctx;
142 | sha2_starts(&ctx, 0);
143 | sha2_update(&ctx, c->key, BASE64_KEY_SIZE);
144 | sha2_finish(&ctx, sha256_key);
145 | log_hex("aes_open: sha256_key[%d]: %s", sha256_key, SHA256_KEY_SIZE);
146 |
147 | unsigned char aes_key[AES_KEY_SIZE];
148 | memcpy(aes_key, sha256_key, AES_KEY_SIZE);
149 |
150 | log_hex("aes_open: aes_key[%d]: %s", aes_key, AES_KEY_SIZE);
151 |
152 | aes_setkey_dec(&c->aes, aes_key, AES_KEY_SIZE << 3);
153 |
154 | // h->is_streamed = 1; // disable seek
155 | LOGI(3, "aes_open: finished opening");
156 | err: return ret;
157 | }
158 |
159 | static int64_t aes_seek(URLContext *h, int64_t pos, int whence) {
160 | AesContext *c = h->priv_data;
161 | LOGI(3, "aes_seek: trying to seek");
162 | switch (whence) {
163 | case SEEK_SET:
164 | LOGI(3, "aes_seek: pos: %"PRId64", SEEK_SET", pos);
165 | // The offset is set to offset bytes.
166 | c->reading_position = pos;
167 | break;
168 |
169 | case SEEK_CUR:
170 | LOGI(3, "aes_seek: pos: %"PRId64", SEEK_CUR", pos);
171 | // The offset is set to its current location plus offset bytes.
172 | c->reading_position += pos;
173 | break;
174 |
175 | case AVSEEK_SIZE:
176 | // Measuring file size
177 | LOGI(3, "aes_seek: AVSEEK_SIZE");
178 | if (c->stream_end >= 0) {
179 | LOGI(3, "aes_seek: already_measured_size: %"PRId64, c->stream_end);
180 | return c->stream_end;
181 | }
182 | c->stream_end = ffurl_seek(c->hd, 0, AVSEEK_SIZE);
183 | LOGI(3, "aes_seek: measured_size: %"PRId64, c->stream_end);
184 | return c->stream_end;
185 |
186 | case SEEK_END:
187 | LOGI(3, "aes_seek: pos: %d, SEEK_END", pos);
188 | // The offset is set to the size of the file plus offset bytes.
189 | if (c->stream_end < 0) {
190 | c->stream_end = ffurl_seek(c->hd, 0, AVSEEK_SIZE);
191 | if (c->stream_end < 0) {
192 | LOGE(2,
193 | "aes_seek: could not measure size, error: %"PRId64, c->stream_end);
194 | return c->stream_end;
195 | }
196 | }
197 | LOGI(3, "aes_seek: measured_size: %"PRId64, c->stream_end);
198 | c->reading_position = c->stream_end - pos;
199 | break;
200 | default:
201 | LOGE(1, "aes_seek: unknown whence: %d", whence);
202 | return -1;
203 | }
204 | LOGI(3, "aes_seek: reading_position: %" PRId64, c->reading_position);
205 |
206 | c->read_start_point = (c->reading_position / (int64_t) BUFFER_SIZE)
207 | * (int64_t) BUFFER_SIZE;
208 | c->read_end_point = c->read_start_point;
209 | LOGI(3, "aes_seek: read_start_point: %" PRId64, c->read_start_point);
210 |
211 | int64_t ret = ffurl_seek(c->hd, c->read_start_point, whence);
212 | LOGI(3, "aes_seek: return: %"PRId64, ret);
213 | if (ret < 0) {
214 | LOGE(1,
215 | "aes_seek: seeking error: %"PRId64", trying to seek: %"PRId64", whence: %d", ret, c->read_start_point, whence);
216 | return ret;
217 | }
218 | if (ret != c->read_start_point) {
219 | LOGE(1, "aes_seek: seeking fatal error: unknown state");
220 | return -2;
221 | }
222 | return c->reading_position;
223 | }
224 |
225 | static int aes_read(URLContext *h, uint8_t *buf, int size) {
226 | AesContext *c = h->priv_data;
227 |
228 | int buf_position = 0;
229 | int buf_left = size;
230 | int end = FALSE;
231 | LOGI(3, "aes_read started");
232 |
233 | while (buf_left > 0 && !end) {
234 | LOGI(3,
235 | "aes_read loop, read_position: %"PRId64", buf_left: %d", c->reading_position, buf_left);
236 | if (c->reading_position < c->read_start_point) {
237 | LOGE(1, "aes_read reading error");
238 | return -1;
239 | }
240 |
241 | while (c->reading_position >= c->read_end_point && !end) {
242 | LOGI(3,
243 | "aes_read read loop: current read_end_point %"PRId64, c->read_end_point);
244 | int64_t position = c->read_end_point;
245 |
246 | int decode_buf_left = BUFFER_SIZE;
247 | int encrypted_buffer_size = 0;
248 | while (decode_buf_left > 0 && !end) {
249 | int n = ffurl_read(c->hd,
250 | &(c->read_buff[encrypted_buffer_size]),
251 | decode_buf_left);
252 |
253 | if (n < 0)
254 | return n;
255 |
256 | if (n == 0)
257 | end = TRUE;
258 |
259 | decode_buf_left -= n;
260 | encrypted_buffer_size += n;
261 | }
262 | c->read_start_point = c->read_end_point;
263 | c->read_end_point += encrypted_buffer_size;
264 |
265 | // Inflight magic trick - LOL
266 | *(int *) &c->iv[0] = (int) (c->read_start_point >> 9);
267 | memset(&c->iv[4], 0, sizeof(c->iv) - 4);
268 | aes_crypt_cbc(&c->aes, AES_DECRYPT, encrypted_buffer_size, c->iv,
269 | c->read_buff, c->decoded_buff);
270 | LOGI(3, "aes_read enc: position: %"PRId64, position);
271 | log_hex("aes_read enc: encoded[%d]: %s", c->read_buff,
272 | encrypted_buffer_size);
273 | log_hex("aes_read enc: decoded[%d]: %s", c->decoded_buff,
274 | encrypted_buffer_size);
275 | }
276 | int delta = c->reading_position - c->read_start_point;
277 | int copy_size = c->read_end_point - c->reading_position;
278 | if (copy_size > buf_left)
279 | copy_size = buf_left;
280 |
281 | LOGI(10, "aes_read delta: %d, copy_size: %d", delta, copy_size);
282 | memcpy(&buf[buf_position], &c->decoded_buff[delta], copy_size);
283 | c->reading_position += copy_size;
284 | buf_left -= copy_size;
285 | buf_position += copy_size;
286 | }
287 | LOGI(3, "aes_read read bytes: %d", buf_position);
288 | log_hex("eas_read wrote to buffer[%d]: %s", buf, buf_position);
289 | LOGI(3, "aes_read write success");
290 | return buf_position;
291 | }
292 |
293 | static int aes_close(URLContext *h) {
294 | AesContext *c = h->priv_data;
295 | if (c->hd)
296 | ffurl_close(c->hd);
297 | return 0;
298 | }
299 |
300 | URLProtocol aes_protocol = { .name = "aes", .url_open = aes_open, .url_read =
301 | aes_read, .url_close = aes_close, .url_seek = aes_seek,
302 | .priv_data_size = sizeof(AesContext), .priv_data_class = &aes_class,
303 | .flags = URL_PROTOCOL_FLAG_NESTED_SCHEME, };
304 |
305 | void register_aes_protocol() {
306 | ffurl_register_protocol(&aes_protocol, sizeof(aes_protocol));
307 | }
308 |
--------------------------------------------------------------------------------
/library-jni/jni/aes-protocol.h:
--------------------------------------------------------------------------------
1 | /*
2 | * aes-protocol.h
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #ifndef AES_PROTOCOL_H
20 | #define AES_PROTOCOL_H
21 |
22 | void register_aes_protocol();
23 |
24 | #endif /* H_AES_PROTOCOL */
25 |
26 |
--------------------------------------------------------------------------------
/library-jni/jni/android-ndk-profiler-3.1/android-ndk-profiler.mk:
--------------------------------------------------------------------------------
1 | TARGET_thumb_release_CFLAGS := $(filter-out -ffunction-sections,$(TARGET_thumb_release_CFLAGS))
2 | TARGET_thumb_release_CFLAGS := $(filter-out -fomit-frame-pointer,$(TARGET_thumb_release_CFLAGS))
3 | TARGET_arm_release_CFLAGS := $(filter-out -ffunction-sections,$(TARGET_arm_release_CFLAGS))
4 | TARGET_arm_release_CFLAGS := $(filter-out -fomit-frame-pointer,$(TARGET_arm_release_CFLAGS))
5 | TARGET_CFLAGS := $(filter-out -ffunction-sections,$(TARGET_CFLAGS))
6 |
7 | # include libandprof.a in the build
8 | include $(CLEAR_VARS)
9 | LOCAL_MODULE := andprof
10 | LOCAL_SRC_FILES := android-ndk-profiler-3.1/$(TARGET_ARCH_ABI)/libandprof.a
11 | include $(PREBUILT_STATIC_LIBRARY)
12 |
--------------------------------------------------------------------------------
/library-jni/jni/android-ndk-profiler-3.1/armeabi-v7a/libandprof.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/e8a1dd26ee293630d8cb18885b729786bac06d7c/library-jni/jni/android-ndk-profiler-3.1/armeabi-v7a/libandprof.a
--------------------------------------------------------------------------------
/library-jni/jni/android-ndk-profiler-3.1/armeabi/libandprof.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/e8a1dd26ee293630d8cb18885b729786bac06d7c/library-jni/jni/android-ndk-profiler-3.1/armeabi/libandprof.a
--------------------------------------------------------------------------------
/library-jni/jni/android-ndk-profiler-3.1/prof.h:
--------------------------------------------------------------------------------
1 | #ifndef prof_h_seen
2 | #define prof_h_seen
3 | #ifdef __cplusplus
4 | extern "C" {
5 | #endif
6 |
7 | void monstartup(const char *libname);
8 | void moncleanup(void);
9 |
10 | #ifdef __cplusplus
11 | }
12 | #endif
13 | #endif
14 |
--------------------------------------------------------------------------------
/library-jni/jni/blend.c:
--------------------------------------------------------------------------------
1 | /*
2 | * blend.c
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #include "blend.h"
20 | #include
21 |
22 | #define RGBA_IN(r, g, b, a, s)\
23 | {\
24 | unsigned int v = ((const uint32_t *)(s))[0];\
25 | a = (v >> 24) & 0xff;\
26 | r = (v >> 16) & 0xff;\
27 | g = (v >> 8) & 0xff;\
28 | b = v & 0xff;\
29 | }
30 |
31 | #define RGB565_IN(r, g, b, s)\
32 | {\
33 | unsigned int v = ((const uint16_t *)(s))[0];\
34 | r = (v >> 11) & 0x1f;\
35 | g = (v >> 5) & 0x3f;\
36 | b = v & 0x1f;\
37 | }
38 |
39 | #define RGB565_OUT(d, r, g, b)\
40 | {\
41 | ((uint16_t *)(d))[0] = (r << 11) | (g << 5) | b;\
42 | }
43 |
44 | #define RGBA_OUT(d, r, g, b, a)\
45 | {\
46 | ((uint32_t *)(d))[0] = (a << 24) | (r << 16) | (g << 8) | b;\
47 | }
48 |
49 | #define ALPHA_BLEND_RGB(color1, color2, alpha)\
50 | (((color1 * (0xff - alpha)) + (color2 * alpha))/0xff)
51 |
52 | #define AR(c) ( (c)>>24)
53 | #define AG(c) (((c)>>16)&0xFF)
54 | #define AB(c) (((c)>>8) &0xFF)
55 | #define AA(c) ((0xFF-c) &0xFF)
56 |
57 | void blend_ass_image(AVPicture *dest, const ASS_Image *image, int imgw,
58 | int imgh, enum PixelFormat pixel_format) {
59 | uint8_t rgba_color[] = { AR(image->color), AG(image->color), AB(
60 | image->color), AA(image->color) };
61 | uint8_t rect_r, rect_g, rect_b, rect_a;
62 | int dest_r, dest_g, dest_b, dest_a;
63 | int x, y;
64 | uint32_t *dst2;
65 | uint8_t *src, *src2;
66 | uint8_t *dst = dest->data[0];
67 |
68 | if (pixel_format != PIX_FMT_RGBA)
69 | return;
70 |
71 | dst += image->dst_y * dest->linesize[0] + image->dst_x * 4;
72 | src = image->bitmap;
73 | for (y = 0; y < image->h; y++) {
74 | dst2 = (uint32_t *) dst;
75 | src2 = src;
76 | for (x = 0; x < image->w; x++) {
77 | uint8_t image_pixel = *(src2++);
78 | uint32_t *pixel = (dst2++);
79 |
80 | rect_r = image_pixel & rgba_color[0];
81 | rect_g = image_pixel & rgba_color[1];
82 | rect_b = image_pixel & rgba_color[2];
83 | rect_a = image_pixel & rgba_color[3];
84 |
85 | RGBA_IN(dest_r, dest_g, dest_b, dest_a, pixel);
86 |
87 | // write subtitle on the image
88 | dest_r = ALPHA_BLEND_RGB(dest_r, rect_r, rect_a);
89 | dest_g = ALPHA_BLEND_RGB(dest_g, rect_g, rect_a);
90 | dest_b = ALPHA_BLEND_RGB(dest_b, rect_b, rect_a);
91 |
92 | RGBA_OUT(pixel, dest_r, dest_g, dest_b, dest_a);
93 | }
94 | dst += dest->linesize[0];
95 | src += image->stride;
96 | }
97 | }
98 |
99 | void blend_subrect_rgba(AVPicture *dest, const AVSubtitleRect *rect, int imgw,
100 | int imgh, enum PixelFormat pixel_format) {
101 | int rect_r, rect_g, rect_b, rect_a;
102 | int dest_r, dest_g, dest_b, dest_a;
103 | uint32_t *pal;
104 | uint32_t *dst2;
105 | uint8_t *src, *src2;
106 | int x, y;
107 | uint8_t *dst = dest->data[0];
108 |
109 | if (pixel_format != PIX_FMT_RGBA)
110 | return;
111 |
112 | dst += rect->y * dest->linesize[0] + rect->x * 4;
113 | src = rect->pict.data[0];
114 | pal = (uint32_t *) rect->pict.data[1];
115 |
116 | for (y = 0; y < rect->h; y++) {
117 | dst2 = (uint32_t *) dst;
118 | src2 = src;
119 | for (x = 0; x < rect->w; x++) {
120 | uint32_t *rect_pixel = &pal[*(src2++)];
121 | uint32_t *pixel = (dst2++);
122 |
123 | // read subtitle rgba8888
124 | RGBA_IN(rect_r, rect_g, rect_b, rect_a, rect_pixel);
125 |
126 | RGBA_IN(dest_r, dest_g, dest_b, dest_a, pixel);
127 |
128 | // write subtitle on the image
129 | dest_r = ALPHA_BLEND_RGB(dest_r, rect_r, rect_a);
130 | dest_g = ALPHA_BLEND_RGB(dest_g, rect_g, rect_a);
131 | dest_b = ALPHA_BLEND_RGB(dest_b, rect_b, rect_a);
132 |
133 | RGBA_OUT(pixel, dest_r, dest_g, dest_b, dest_a);
134 | }
135 | dst += dest->linesize[0];
136 | src += rect->pict.linesize[0];
137 | }
138 | }
139 |
140 |
--------------------------------------------------------------------------------
/library-jni/jni/blend.h:
--------------------------------------------------------------------------------
1 | /*
2 | * blend.h
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #ifndef BLEND_H_
20 | #define BLEND_H_
21 |
22 | #include
23 | #include
24 |
25 | void blend_ass_image(AVPicture *dest, const ASS_Image *image, int imgw,
26 | int imgh, enum PixelFormat pixel_format);
27 | void blend_subrect_rgba(AVPicture *dest, const AVSubtitleRect *rect, int imgw,
28 | int imgh, enum PixelFormat pixel_format);
29 |
30 | #endif /* BLEND_H_ */
31 |
--------------------------------------------------------------------------------
/library-jni/jni/build_android.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | #
3 | # build_android.sh
4 | # Copyright (c) 2012 Jacek Marchwicki
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | set -x
19 |
20 | if [ "$ANDROID_NDK_HOME" = "" ]; then
21 | echo ANDROID_NDK_HOME variable not set, exiting
22 | echo "Use: export ANDROID_NDK_HOME=/your/path/to/android-ndk"
23 | exit 1
24 | fi
25 |
26 | # Get the newest arm-linux-androideabi version
27 | if [ -z "$COMPILATOR_VERSION" ]; then
28 | DIRECTORIES=$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-*
29 | for i in $DIRECTORIES; do
30 | PROPOSED_NAME=${i#*$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-}
31 | if [[ $PROPOSED_NAME =~ ^[0-9\.]+$ ]] ; then
32 | echo "Available compilator version: $PROPOSED_NAME"
33 | COMPILATOR_VERSION=$PROPOSED_NAME
34 | fi
35 | done
36 | fi
37 |
38 | if [ -z "$COMPILATOR_VERSION" ]; then
39 | echo "Could not find compilator"
40 | exit 1
41 | fi
42 |
43 | if [ ! -d $ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-$COMPILATOR_VERSION ]; then
44 | echo $ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-$COMPILATOR_VERSION does not exist
45 | exit 1
46 | fi
47 | echo "Using compilator version: $COMPILATOR_VERSION"
48 |
49 | OS_ARCH=`basename $ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-$COMPILATOR_VERSION/prebuilt/*`
50 | echo "Using architecture: $OS_ARCH"
51 |
52 |
53 | function setup_paths
54 | {
55 | export PLATFORM=$ANDROID_NDK_HOME/platforms/$PLATFORM_VERSION/arch-$ARCH/
56 | if [ ! -d $PLATFORM ]; then
57 | echo $PLATFORM does not exist
58 | exit 1
59 | fi
60 | echo "Using platform: $PLATFORM"
61 | export PATH=${PATH}:$PREBUILT/bin/
62 | export CROSS_COMPILE=$PREBUILT/bin/$EABIARCH-
63 | export CFLAGS=$OPTIMIZE_CFLAGS
64 | export CPPFLAGS="$CFLAGS"
65 | export CFLAGS="$CFLAGS"
66 | export CXXFLAGS="$CFLAGS"
67 | export CXX="${CROSS_COMPILE}g++ --sysroot=$PLATFORM"
68 | export AS="${CROSS_COMPILE}gcc --sysroot=$PLATFORM"
69 | export CC="${CROSS_COMPILE}gcc --sysroot=$PLATFORM"
70 | export PKG_CONFIG="${CROSS_COMPILE}pkg-config"
71 | export LD="${CROSS_COMPILE}ld"
72 | export NM="${CROSS_COMPILE}nm"
73 | export STRIP="${CROSS_COMPILE}strip"
74 | export RANLIB="${CROSS_COMPILE}ranlib"
75 | export AR="${CROSS_COMPILE}ar"
76 | export LDFLAGS="-Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lc -lm -ldl -llog"
77 | export PKG_CONFIG_LIBDIR=$PREFIX/lib/pkgconfig/
78 | export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig/
79 |
80 | if [ ! -f "${CROSS_COMPILE}gcc" ]; then
81 | echo "Gcc does not exists in path: ${CROSS_COMPILE}gcc"
82 | exit 1;
83 | fi
84 |
85 | if [ ! -f "${PKG_CONFIG}" ]; then
86 | echo "Pkg config does not exists in path: ${PKG_CONFIG} - Probably BUG in NDK but..."
87 | set +e
88 | SYS_PKG_CONFIG=$(which pkg-config)
89 | if [ "$?" -ne 0 ]; then
90 | echo "This system does not contain system pkg-config, so we can do anything"
91 | exit 1
92 | fi
93 | set -e
94 | cat > $PKG_CONFIG << EOF
95 | #!/bin/bash
96 | pkg-config \$*
97 | EOF
98 | chmod u+x $PKG_CONFIG
99 | echo "Because we have local pkg-config we will create it in ${PKG_CONFIG} directory using ${SYS_PKG_CONFIG}"
100 | fi
101 | }
102 |
103 | function build_x264
104 | {
105 | echo "Starting build x264 for $ARCH"
106 | cd x264
107 | ./configure --prefix=$PREFIX --host=$ARCH-linux --enable-static $ADDITIONAL_CONFIGURE_FLAG
108 |
109 | make clean
110 | make -j4 install
111 | make clean
112 | cd ..
113 | echo "FINISHED x264 for $ARCH"
114 | }
115 |
116 | function build_amr
117 | {
118 | echo "Starting build amr for $ARCH"
119 | cd vo-amrwbenc
120 | ./configure \
121 | --prefix=$PREFIX \
122 | --host=$ARCH-linux \
123 | --disable-dependency-tracking \
124 | --disable-shared \
125 | --enable-static \
126 | --with-pic \
127 | $ADDITIONAL_CONFIGURE_FLAG
128 |
129 | make clean
130 | make -j4 install
131 | make clean
132 | cd ..
133 | echo "FINISHED amr for $ARCH"
134 | }
135 |
136 | function build_aac
137 | {
138 | echo "Starting build aac for $ARCH"
139 | cd vo-aacenc
140 | ./configure \
141 | --prefix=$PREFIX \
142 | --host=$ARCH-linux \
143 | --disable-dependency-tracking \
144 | --disable-shared \
145 | --enable-static \
146 | --with-pic \
147 | $ADDITIONAL_CONFIGURE_FLAG
148 |
149 | make clean
150 | make -j4 install
151 | make clean
152 | cd ..
153 | echo "FINISHED aac for $ARCH"
154 | }
155 | function build_freetype2
156 | {
157 | echo "Starting build freetype2 for $ARCH"
158 | cd freetype2
159 | ./configure \
160 | --prefix=$PREFIX \
161 | --host=$ARCH-linux \
162 | --disable-dependency-tracking \
163 | --disable-shared \
164 | --enable-static \
165 | --with-pic \
166 | $ADDITIONAL_CONFIGURE_FLAG
167 |
168 | make clean
169 | make -j4 install
170 | make clean
171 | cd ..
172 | echo "FINISHED freetype2 for $ARCH"
173 | }
174 | function build_ass
175 | {
176 | echo "Starting build ass for $ARCH"
177 | cd libass
178 | ./configure \
179 | --prefix=$PREFIX \
180 | --host=$ARCH-linux \
181 | --disable-fontconfig \
182 | --disable-dependency-tracking \
183 | --disable-shared \
184 | --enable-static \
185 | --with-pic \
186 | $ADDITIONAL_CONFIGURE_FLAG
187 |
188 | make clean
189 | make V=1 -j4 install
190 | make clean
191 | cd ..
192 | echo "FINISHED ass for $ARCH"
193 | }
194 | function build_fribidi
195 | {
196 | echo "Starting build fribidi for $ARCH"
197 | cd fribidi
198 | ./configure \
199 | --prefix=$PREFIX \
200 | --host=$ARCH-linux \
201 | --disable-bin \
202 | --disable-dependency-tracking \
203 | --disable-shared \
204 | --enable-static \
205 | --with-pic \
206 | $ADDITIONAL_CONFIGURE_FLAG
207 |
208 | make clean
209 | make -j4 install
210 | make clean
211 | cd ..
212 | echo "FINISHED fribidi for $ARCH"
213 | }
214 | function build_ffmpeg
215 | {
216 | echo "Starting build ffmpeg for $ARCH"
217 | cd ffmpeg
218 | ./configure --target-os=linux \
219 | --prefix=$PREFIX \
220 | --enable-cross-compile \
221 | --extra-libs="-lgcc" \
222 | --arch=$ARCH \
223 | --cc=$CC \
224 | --cross-prefix=$CROSS_COMPILE \
225 | --nm=$NM \
226 | --sysroot=$PLATFORM \
227 | --extra-cflags=" -O3 -fpic -DANDROID -DHAVE_SYS_UIO_H=1 -Dipv6mr_interface=ipv6mr_ifindex -fasm -Wno-psabi -fno-short-enums -fno-strict-aliasing -finline-limit=300 $OPTIMIZE_CFLAGS " \
228 | --disable-shared \
229 | --enable-static \
230 | --enable-runtime-cpudetect \
231 | --extra-ldflags="-Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lc -lm -ldl -llog -L$PREFIX/lib" \
232 | --extra-cflags="-I$PREFIX/include" \
233 | --disable-everything \
234 | --enable-pthreads \
235 | --enable-libass \
236 | --enable-libvo-aacenc \
237 | --enable-libvo-amrwbenc \
238 | --enable-hwaccel=h264_vaapi \
239 | --enable-hwaccel=h264_vaapi \
240 | --enable-hwaccel=h264_dxva2 \
241 | --enable-hwaccel=mpeg4_vaapi \
242 | --enable-demuxer=mov \
243 | --enable-demuxer=h264 \
244 | --enable-demuxer=mpegvideo \
245 | --enable-demuxer=h263 \
246 | --enable-demuxer=mpegps \
247 | --enable-demuxer=mjpeg \
248 | --enable-demuxer=rtsp \
249 | --enable-demuxer=rtp \
250 | --enable-demuxer=hls \
251 | --enable-demuxer=matroska \
252 | --enable-muxer=rtsp \
253 | --enable-muxer=mp4 \
254 | --enable-muxer=mov \
255 | --enable-muxer=mjpeg \
256 | --enable-muxer=matroska \
257 | --enable-protocol=crypto \
258 | --enable-protocol=jni \
259 | --enable-protocol=file \
260 | --enable-protocol=rtp \
261 | --enable-protocol=tcp \
262 | --enable-protocol=udp \
263 | --enable-protocol=applehttp \
264 | --enable-protocol=hls \
265 | --enable-protocol=http \
266 | --enable-decoder=xsub \
267 | --enable-decoder=jacosub \
268 | --enable-decoder=dvdsub \
269 | --enable-decoder=dvbsub \
270 | --enable-decoder=subviewer \
271 | --enable-decoder=rawvideo \
272 | --enable-encoder=rawvideo \
273 | --enable-decoder=mjpeg \
274 | --enable-encoder=mjpeg \
275 | --enable-decoder=h263 \
276 | --enable-decoder=mpeg4 \
277 | --enable-encoder=mpeg4 \
278 | --enable-decoder=h264 \
279 | --enable-encoder=h264 \
280 | --enable-decoder=aac \
281 | --enable-encoder=aac \
282 | --enable-parser=h264 \
283 | --enable-encoder=mp2 \
284 | --enable-decoder=mp2 \
285 | --enable-encoder=libvo_amrwbenc \
286 | --enable-decoder=amrwb \
287 | --enable-muxer=mp2 \
288 | --enable-bsfs \
289 | --enable-decoders \
290 | --enable-encoders \
291 | --enable-parsers \
292 | --enable-hwaccels \
293 | --enable-muxers \
294 | --enable-avformat \
295 | --enable-avcodec \
296 | --enable-avresample \
297 | --enable-zlib \
298 | --disable-doc \
299 | --disable-ffplay \
300 | --disable-ffmpeg \
301 | --disable-ffplay \
302 | --disable-ffprobe \
303 | --disable-ffserver \
304 | --disable-avfilter \
305 | --disable-avdevice \
306 | --enable-nonfree \
307 | --enable-version3 \
308 | --enable-memalign-hack \
309 | --enable-asm \
310 | $ADDITIONAL_CONFIGURE_FLAG
311 | make clean
312 | make -j4 install
313 | make clean
314 |
315 | cd ..
316 | echo "FINISHED ffmpeg for $ARCH"
317 | }
318 |
319 | function build_one {
320 | echo "Starting build one for $ARCH"
321 | cd ffmpeg
322 | ${LD} -rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -L$PREFIX/lib -soname $SONAME -shared -nostdlib -Bsymbolic --whole-archive --no-undefined -o $OUT_LIBRARY -lavcodec -lavformat -lavresample -lavutil -lswresample -lass -lfreetype -lfribidi -lswscale -lvo-aacenc -lvo-amrwbenc -lc -lm -lz -ldl -llog --dynamic-linker=/system/bin/linker -zmuldefs $PREBUILT/lib/gcc/$EABIARCH/$COMPILATOR_VERSION/libgcc.a
323 | cd ..
324 | echo "FINISHED one for $ARCH"
325 | }
326 |
327 | #arm v5
328 | EABIARCH=arm-linux-androideabi
329 | ARCH=arm
330 | CPU=armv5
331 | OPTIMIZE_CFLAGS="-marm -march=$CPU"
332 | PREFIX=$(pwd)/ffmpeg-build/armeabi
333 | OUT_LIBRARY=$PREFIX/libffmpeg.so
334 | ADDITIONAL_CONFIGURE_FLAG=
335 | SONAME=libffmpeg.so
336 | PREBUILT=$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-$COMPILATOR_VERSION/prebuilt/$OS_ARCH
337 | PLATFORM_VERSION=android-5
338 | setup_paths
339 | build_amr
340 | build_aac
341 | build_fribidi
342 | build_freetype2
343 | build_ass
344 | build_ffmpeg
345 | build_one
346 |
347 | #x86
348 | EABIARCH=i686-linux-android
349 | ARCH=x86
350 | OPTIMIZE_CFLAGS="-m32"
351 | PREFIX=$(pwd)/ffmpeg-build/x86
352 | OUT_LIBRARY=$PREFIX/libffmpeg.so
353 | ADDITIONAL_CONFIGURE_FLAG=--disable-asm
354 | SONAME=libffmpeg.so
355 | PREBUILT=$ANDROID_NDK_HOME/toolchains/x86-$COMPILATOR_VERSION/prebuilt/$OS_ARCH
356 | PLATFORM_VERSION=android-9
357 | setup_paths
358 | build_amr
359 | build_aac
360 | build_fribidi
361 | build_freetype2
362 | build_ass
363 | build_ffmpeg
364 | build_one
365 |
366 | #mips
367 | EABIARCH=mipsel-linux-android
368 | ARCH=mips
369 | OPTIMIZE_CFLAGS="-EL -march=mips32 -mips32 -mhard-float"
370 | PREFIX=$(pwd)/ffmpeg-build/mips
371 | OUT_LIBRARY=$PREFIX/libffmpeg.so
372 | ADDITIONAL_CONFIGURE_FLAG="--disable-mips32r2"
373 | SONAME=libffmpeg.so
374 | PREBUILT=$ANDROID_NDK_HOME/toolchains/mipsel-linux-android-$COMPILATOR_VERSION/prebuilt/$OS_ARCH
375 | PLATFORM_VERSION=android-9
376 | setup_paths
377 | build_amr
378 | build_aac
379 | build_fribidi
380 | build_freetype2
381 | build_ass
382 | build_ffmpeg
383 | build_one
384 |
385 | #arm v7vfpv3
386 | EABIARCH=arm-linux-androideabi
387 | ARCH=arm
388 | CPU=armv7-a
389 | OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfpv3-d16 -marm -march=$CPU "
390 | PREFIX=$(pwd)/ffmpeg-build/armeabi-v7a
391 | OUT_LIBRARY=$PREFIX/libffmpeg.so
392 | ADDITIONAL_CONFIGURE_FLAG=
393 | SONAME=libffmpeg.so
394 | PREBUILT=$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-$COMPILATOR_VERSION/prebuilt/$OS_ARCH
395 | PLATFORM_VERSION=android-5
396 | setup_paths
397 | build_amr
398 | build_aac
399 | build_fribidi
400 | build_freetype2
401 | build_ass
402 | build_ffmpeg
403 | build_one
404 |
405 | #arm v7 + neon (neon also include vfpv3-32)
406 | EABIARCH=arm-linux-androideabi
407 | ARCH=arm
408 | CPU=armv7-a
409 | OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=neon -marm -march=$CPU -mtune=cortex-a8 -mthumb -D__thumb__ "
410 | PREFIX=$(pwd)/ffmpeg-build/armeabi-v7a-neon
411 | OUT_LIBRARY=../ffmpeg-build/armeabi-v7a/libffmpeg-neon.so
412 | ADDITIONAL_CONFIGURE_FLAG=--enable-neon
413 | SONAME=libffmpeg-neon.so
414 | PREBUILT=$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-$COMPILATOR_VERSION/prebuilt/$OS_ARCH
415 | PLATFORM_VERSION=android-9
416 | setup_paths
417 | build_amr
418 | build_aac
419 | build_fribidi
420 | build_freetype2
421 | build_ass
422 | build_ffmpeg
423 | build_one
424 |
425 |
426 | echo "BUILD SUCCESS"
427 |
--------------------------------------------------------------------------------
/library-jni/jni/convert.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | extern "C" {
7 | int __I420ToARGB(const uint8* src_y, int src_stride_y,
8 | const uint8* src_u, int src_stride_u,
9 | const uint8* src_v, int src_stride_v,
10 | uint8* dst_argb, int dst_stride_argb,
11 | int width, int height) {
12 | return libyuv::I420ToARGB(src_y,src_stride_y,
13 | src_u, src_stride_u,
14 | src_v, src_stride_v,
15 | dst_argb, dst_stride_argb,
16 | width, height);
17 | }
18 |
19 | int __NV12ToARGB(const uint8* src_y, int src_stride_y,
20 | const uint8* src_uv, int src_stride_uv,
21 | uint8* dst_argb, int dst_stride_argb,
22 | int width, int height) {
23 | return libyuv::NV12ToARGB(src_y, src_stride_y,
24 | src_uv, src_stride_uv,
25 | dst_argb, dst_stride_argb,
26 | width, height);
27 | }
28 |
29 | int __NV21ToARGB(const uint8* src_y, int src_stride_y,
30 | const uint8* src_uv, int src_stride_uv,
31 | uint8* dst_argb, int dst_stride_argb,
32 | int width, int height) {
33 | return libyuv::NV21ToARGB(src_y, src_stride_y,
34 | src_uv, src_stride_uv,
35 | dst_argb, dst_stride_argb,
36 | width, height);
37 | }
38 |
39 | int __BGRAToARGB(const uint8* src_frame, int src_stride_frame,
40 | uint8* dst_argb, int dst_stride_argb,
41 | int width, int height) {
42 | return libyuv::BGRAToARGB(src_frame, src_stride_frame,
43 | dst_argb, dst_stride_argb,
44 | width, height);
45 | }
46 |
47 | int __ARGBCopy(const uint8* src_argb, int src_stride_argb,
48 | uint8* dst_argb, int dst_stride_argb,
49 | int width, int height) {
50 | return libyuv::ARGBCopy(src_argb, src_stride_argb,
51 | dst_argb, dst_stride_argb,
52 | width, height);
53 | }
54 |
55 | int __ARGBScale(const uint8* src_argb, int src_stride_argb,
56 | int src_width, int src_height,
57 | uint8* dst_argb, int dst_stride_argb,
58 | int dst_width, int dst_height,
59 | enum __FilterMode filtering) {
60 | libyuv::FilterMode filterMode = static_cast(filtering);
61 | return libyuv::ARGBScale(src_argb, src_stride_argb,
62 | src_width, src_height,
63 | dst_argb, dst_stride_argb,
64 | dst_width, dst_height,
65 | filterMode);
66 | }
67 |
68 | int __ARGBToRGBA(const uint8* src_frame, int src_stride_frame,
69 | uint8* dst_argb, int dst_stride_argb,
70 | int width, int height) {
71 | return libyuv::ARGBToRGBA(src_frame, src_stride_frame,
72 | dst_argb, dst_stride_argb,
73 | width, height);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/library-jni/jni/convert.h:
--------------------------------------------------------------------------------
1 | #ifndef CONVERT_H_
2 | #define CONVERT_H_
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 | #include
9 |
10 | enum __FilterMode {
11 | __kFilterNone = 0, // Point sample; Fastest.
12 | __kFilterBilinear = 1, // Faster than box, but lower quality scaling down.
13 | __kFilterBox = 2 // Highest quality.
14 | };
15 |
16 | int __I420ToARGB(const uint8* src_y, int src_stride_y,
17 | const uint8* src_u, int src_stride_u,
18 | const uint8* src_v, int src_stride_v,
19 | uint8* dst_argb, int dst_stride_argb,
20 | int width, int height);
21 |
22 | int __NV12ToARGB(const uint8* src_y, int src_stride_y,
23 | const uint8* src_uv, int src_stride_uv,
24 | uint8* dst_argb, int dst_stride_argb,
25 | int width, int height);
26 | int __NV21ToARGB(const uint8* src_y, int src_stride_y,
27 | const uint8* src_uv, int src_stride_uv,
28 | uint8* dst_argb, int dst_stride_argb,
29 | int width, int height);
30 | int __BGRAToARGB(const uint8* src_frame, int src_stride_frame,
31 | uint8* dst_argb, int dst_stride_argb,
32 | int width, int height);
33 | int __ARGBCopy(const uint8* src_argb, int src_stride_argb,
34 | uint8* dst_argb, int dst_stride_argb,
35 | int width, int height);
36 |
37 | int __ARGBScale(const uint8* src_argb, int src_stride_argb,
38 | int src_width, int src_height,
39 | uint8* dst_argb, int dst_stride_argb,
40 | int dst_width, int dst_height,
41 | enum __FilterMode filtering);
42 |
43 | int __ARGBToRGBA(const uint8* src_frame, int src_stride_frame,
44 | uint8* dst_argb, int dst_stride_argb,
45 | int width, int height);
46 | #ifdef __cplusplus
47 | }
48 | #endif
49 |
50 | #endif /* CONVERT_H_ */
51 |
--------------------------------------------------------------------------------
/library-jni/jni/fetch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | (cd freetype2 && ./autogen.sh)
3 | (cd fribidi && autoreconf -ivf)
4 | (cd libass && autoreconf -ivf)
5 | (cd vo-aacenc && autoreconf -ivf)
6 | (cd vo-amrwbenc && autoreconf -ivf)
7 |
--------------------------------------------------------------------------------
/library-jni/jni/ffmpeg-jni.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ffmpeg-jni.c
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | /*android specific headers*/
20 | #include
21 | #include
22 | /*standard library*/
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 |
33 | #include "helpers.h"
34 | #include "player.h"
35 |
36 | /*for android logs*/
37 | #define LOG_TAG "FFmpegTest"
38 | #define LOG_LEVEL 10
39 | #define LOGI(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__);}
40 | #define LOGE(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);}
41 |
42 | #ifndef NELEM
43 | #define NELEM(x) ((int)(sizeof(x) / sizeof((x)[0])))
44 | #endif
45 |
46 | static int register_native_methods(JNIEnv* env,
47 | const char* class_name,
48 | JNINativeMethod* methods,
49 | int num_methods)
50 | {
51 | jclass clazz;
52 |
53 | clazz = (*env)->FindClass(env, class_name);
54 | if (clazz == NULL) {
55 | fprintf(stderr, "Native registration unable to find class '%s'\n",
56 | class_name);
57 | return JNI_FALSE;
58 | }
59 | if ((*env)->RegisterNatives(env, clazz, methods, num_methods) < 0) {
60 | fprintf(stderr, "RegisterNatives failed for '%s'\n", class_name);
61 | return JNI_FALSE;
62 | }
63 |
64 | return JNI_TRUE;
65 | }
66 |
67 | jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
68 | {
69 | JNIEnv* env = NULL;
70 | jint result = -1;
71 |
72 | if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
73 | fprintf(stderr, "ERROR: GetEnv failed\n");
74 | goto bail;
75 | }
76 | assert(env != NULL);
77 |
78 | if (register_native_methods(env,
79 | player_class_path_name,
80 | player_methods,
81 | NELEM(player_methods)) < 0) {
82 | fprintf(stderr, "ERROR: Exif native registration failed\n");
83 | goto bail;
84 | }
85 |
86 | /* success -- return valid version number */
87 | result = JNI_VERSION_1_4;
88 |
89 | bail:
90 | return result;
91 | }
92 |
93 | void JNI_OnUnload(JavaVM *vm, void *reserved)
94 | {
95 | }
96 |
97 |
98 |
--------------------------------------------------------------------------------
/library-jni/jni/helpers.c:
--------------------------------------------------------------------------------
1 | /*
2 | * helpers.c
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #include
20 |
21 | #include "helpers.h"
22 |
23 | jfieldID java_get_field(JNIEnv *env, char * class_name, JavaField field) {
24 | jclass clazz = (*env)->FindClass(env, class_name);
25 | jfieldID jField = (*env)->GetFieldID(env, clazz, field.name, field.signature);
26 | (*env)->DeleteLocalRef(env, clazz);
27 | return jField;
28 | }
29 |
30 | jmethodID java_get_method(JNIEnv *env, jclass class, JavaMethod method) {
31 | return (*env)->GetMethodID(env, class, method.name, method.signature);
32 | }
33 |
--------------------------------------------------------------------------------
/library-jni/jni/helpers.h:
--------------------------------------------------------------------------------
1 | /*
2 | * helpers.h
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #ifndef HELPERS_H_
20 | #define HELPERS_H_
21 |
22 | typedef struct {
23 | const char* name;
24 | const char* signature;
25 | } JavaMethod;
26 |
27 | typedef struct {
28 | char* name;
29 | char* signature;
30 | } JavaField;
31 |
32 | jfieldID java_get_field(JNIEnv *env, char * class_name, JavaField field);
33 | jmethodID java_get_method(JNIEnv *env, jclass class, JavaMethod method);
34 |
35 |
36 | #endif /* HELPERS_H_ */
37 |
--------------------------------------------------------------------------------
/library-jni/jni/jni-protocol.c:
--------------------------------------------------------------------------------
1 | /*
2 | * jni-protocol.c
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include "ffmpeg/libavformat/url.h"
24 |
25 | #include "jni-protocol.h"
26 |
27 | static const char *jni_reader_class_name = "com/appunite/ffmpeg/JniReader";
28 | static JavaVM *global_jvm;
29 |
30 | static int jni_read(URLContext *h, unsigned char *buf, int size) {
31 | int err = 0;
32 | JNIEnv* env;
33 | jclass jni_reader_class;
34 | jmethodID jni_reader_read;
35 | jobject jni_reader;
36 | jbyteArray byte_array;
37 | jbyte *jni_samples;
38 | if ((*global_jvm)->GetEnv(global_jvm, (void**) &env, JNI_VERSION_1_4)) {
39 | err = -1;
40 | goto end;
41 | }
42 | if (env == NULL) {
43 | err = -1;
44 | goto end;
45 | }
46 |
47 | jni_reader_class = (*env)->FindClass(env, jni_reader_class_name);
48 | if (jni_reader_class == NULL) {
49 | err = -1;
50 | goto end;
51 | }
52 |
53 | jni_reader_read = (*env)->GetMethodID(env, jni_reader_class, "read",
54 | "([B)I");
55 | if (jni_reader_read == NULL) {
56 | err = -1;
57 | goto end;
58 | }
59 |
60 | jni_reader = (jobject) h->priv_data;
61 |
62 | byte_array = (*env)->NewByteArray(env, size);
63 |
64 | err = (*env)->CallIntMethod(env, jni_reader, jni_reader_read, byte_array);
65 |
66 | jni_samples = (*env)->GetByteArrayElements(env, byte_array, NULL);
67 | memcpy(buf, jni_samples, size);
68 | (*env)->ReleaseByteArrayElements(env, byte_array, jni_samples, 0);
69 |
70 | (*env)->DeleteLocalRef(env, byte_array);
71 |
72 | end: return err >= 0 ? err : AVERROR(err);
73 | }
74 |
75 | static int jni_write(URLContext *h, const unsigned char *buf, int size) {
76 | int err = 0;
77 | JNIEnv* env;
78 | jclass jni_reader_class;
79 | jmethodID jni_reader_write;
80 | jobject jni_reader;
81 | jbyteArray byte_array;
82 | jbyte *jni_samples;
83 | if ((*global_jvm)->GetEnv(global_jvm, (void**) &env, JNI_VERSION_1_4)) {
84 | err = -1;
85 | goto end;
86 | }
87 | if (env == NULL) {
88 | err = -1;
89 | goto end;
90 | }
91 |
92 | jni_reader_class = (*env)->FindClass(env, jni_reader_class_name);
93 | if (jni_reader_class == NULL) {
94 | err = -1;
95 | goto end;
96 | }
97 |
98 | jni_reader_write = (*env)->GetMethodID(env, jni_reader_class, "write",
99 | "([B)I");
100 | if (jni_reader_write == NULL) {
101 | err = -1;
102 | goto end;
103 | }
104 |
105 | jni_reader = (jobject) h->priv_data;
106 |
107 | byte_array = (*env)->NewByteArray(env, size);
108 |
109 | jni_samples = (*env)->GetByteArrayElements(env, byte_array, NULL);
110 | memcpy(jni_samples, buf, size);
111 | (*env)->ReleaseByteArrayElements(env, byte_array, jni_samples, 0);
112 |
113 | err = (*env)->CallIntMethod(env, jni_reader, jni_reader_write, byte_array);
114 |
115 | (*env)->DeleteLocalRef(env, byte_array);
116 |
117 | end: return err >= 0 ? err : AVERROR(err);
118 | }
119 |
120 | static int jni_get_handle(URLContext *h) {
121 | return (intptr_t) h->priv_data;
122 | }
123 |
124 | static int jni_check(URLContext *h, int mask) {
125 | int err = 0;
126 | JNIEnv* env;
127 | jclass jni_reader_class;
128 | jmethodID jni_reader_check;
129 | jobject jni_reader;
130 |
131 | if ((*global_jvm)->GetEnv(global_jvm, (void**) &env, JNI_VERSION_1_4)) {
132 | err = -1;
133 | goto end;
134 | }
135 | if (env == NULL) {
136 | err = -1;
137 | goto end;
138 | }
139 |
140 | jni_reader_class = (*env)->FindClass(env, jni_reader_class_name);
141 | if (jni_reader_class == NULL) {
142 | err = -1;
143 | goto end;
144 | }
145 |
146 | jni_reader_check = (*env)->GetMethodID(env, jni_reader_class, "check",
147 | "(I)I");
148 | if (jni_reader_check == NULL) {
149 | err = -1;
150 | goto end;
151 | }
152 |
153 | jni_reader = (jobject) h->priv_data;
154 |
155 | err = (*env)->CallIntMethod(env, jni_reader, jni_reader_check, mask);
156 |
157 | end: return err >= 0 ? err : AVERROR(err);
158 | }
159 |
160 | static int jni_open2(URLContext *h, const char *url, int flags,
161 | AVDictionary **options) {
162 | int err = 0;
163 | JNIEnv* env;
164 | jclass jni_reader_class;
165 | jmethodID jni_reader_constructor;
166 | jstring url_java_string;
167 | jobject jni_reader;
168 |
169 | if ((*global_jvm)->GetEnv(global_jvm, (void**) &env, JNI_VERSION_1_4)) {
170 | err = -1;
171 | goto end;
172 | }
173 | if (env == NULL) {
174 | err = -1;
175 | goto end;
176 | }
177 |
178 | jni_reader_class = (*env)->FindClass(env, jni_reader_class_name);
179 | if (jni_reader_class == NULL) {
180 | err = -1;
181 | goto end;
182 | }
183 |
184 | jni_reader_constructor = (*env)->GetMethodID(env, jni_reader_class,
185 | "", "(Ljava/lang/String;I)V");
186 | if (jni_reader_constructor == NULL) {
187 | err = -1;
188 | goto end;
189 | }
190 |
191 | url_java_string = (*env)->NewStringUTF(env, url);
192 |
193 | if (url_java_string == NULL) {
194 | err = -1;
195 | goto end;
196 | }
197 |
198 | jni_reader = (*env)->NewObject(env, jni_reader_class,
199 | jni_reader_constructor, url_java_string, flags);
200 | if (jni_reader == NULL) {
201 | err = -1;
202 | goto free_url_java_string;
203 | }
204 |
205 | h->priv_data = (void *) (*env)->NewGlobalRef(env, jni_reader);
206 | if (h->priv_data == NULL) {
207 | err = -1;
208 | goto free_jni_reader;
209 | }
210 |
211 | free_jni_reader:
212 |
213 | (*env)->DeleteLocalRef(env, jni_reader);
214 |
215 | free_url_java_string:
216 |
217 | (*env)->DeleteLocalRef(env, url_java_string);
218 |
219 | end: return err >= 0 ? err : AVERROR(err);
220 | }
221 |
222 | static int jni_open(URLContext *h, const char *filename, int flags) {
223 | return jni_open2(h, filename, flags, NULL);
224 | }
225 |
226 | static int64_t jni_seek(URLContext *h, int64_t pos, int whence) {
227 | int64_t err = 0;
228 | JNIEnv* env;
229 | jclass jni_reader_class;
230 | jmethodID jni_reader_seek;
231 | jobject jni_reader;
232 |
233 | if ((*global_jvm)->GetEnv(global_jvm, (void**) &env, JNI_VERSION_1_4)) {
234 | err = -1;
235 | goto end;
236 | }
237 | if (env == NULL) {
238 | err = -1;
239 | goto end;
240 | }
241 |
242 | jni_reader_class = (*env)->FindClass(env, jni_reader_class_name);
243 | if (jni_reader_class == NULL) {
244 | err = -1;
245 | goto end;
246 | }
247 |
248 | jni_reader_seek = (*env)->GetMethodID(env, jni_reader_class, "seek",
249 | "(JI)J");
250 | if (jni_reader_seek == NULL) {
251 | err = -1;
252 | goto end;
253 | }
254 |
255 | jni_reader = (jobject) h->priv_data;
256 |
257 | err = (*env)->CallIntMethod(env, jni_reader, jni_reader_seek, pos, whence);
258 |
259 | end: return err >= 0 ? err : AVERROR(err);
260 | }
261 |
262 | static int jni_close(URLContext *h) {
263 | int err = 0;
264 | JNIEnv* env;
265 | jobject jni_reader;
266 |
267 | if ((*global_jvm)->GetEnv(global_jvm, (void**) &env, JNI_VERSION_1_4)) {
268 | err = -1;
269 | goto end;
270 | }
271 | if (env == NULL) {
272 | err = -1;
273 | goto end;
274 | }
275 |
276 | jni_reader = (jobject) h->priv_data;
277 |
278 | (*env)->DeleteGlobalRef(env, jni_reader);
279 |
280 | end: return err >= 0 ? err : AVERROR(err);
281 | }
282 |
283 | URLProtocol jni_protocol = { .name = "jni", .url_open2 = jni_open2,
284 | .url_open = jni_open, .url_read = jni_read, .url_write = jni_write,
285 | .url_seek = jni_seek, .url_close = jni_close, .url_get_file_handle =
286 | jni_get_handle, .url_check = jni_check, };
287 |
288 | void register_jni_protocol(JavaVM *jvm) {
289 | global_jvm = jvm;
290 | ffurl_register_protocol(&jni_protocol, sizeof(jni_protocol));
291 | }
292 |
--------------------------------------------------------------------------------
/library-jni/jni/jni-protocol.h:
--------------------------------------------------------------------------------
1 | /*
2 | * jni-protocol.h
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #ifndef JNI_PROTOCOL_H
20 | #define JNI_PROTOCOL_H
21 |
22 | void register_jni_protocol(JavaVM *jvm);
23 |
24 | #endif /* H_JNI_PROTOCOL */
25 |
--------------------------------------------------------------------------------
/library-jni/jni/nativetester-jni.c:
--------------------------------------------------------------------------------
1 | /*
2 | * nativetester-jni.c
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | /*android specific headers*/
20 | #include
21 | #include
22 |
23 | #include
24 | #include
25 |
26 | #include "nativetester.h"
27 |
28 | #ifndef NELEM
29 | #define NELEM(x) ((int)(sizeof(x) / sizeof((x)[0])))
30 | #endif
31 |
32 |
33 | #define LOG_TAG "NativeTester-jni"
34 | #define LOG_LEVEL 10
35 | #define LOGI(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__);}
36 | #define LOGE(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);}
37 |
38 | static int register_native_methods(JNIEnv* env,
39 | const char* class_name,
40 | JNINativeMethod* methods,
41 | int num_methods)
42 | {
43 | jclass clazz;
44 |
45 | clazz = (*env)->FindClass(env, class_name);
46 | if (clazz == NULL) {
47 | LOGE(1, "Native registration unable to find class '%s'\n",
48 | class_name);
49 | return JNI_FALSE;
50 | }
51 | if ((*env)->RegisterNatives(env, clazz, methods, num_methods) < 0) {
52 | LOGE(1, "RegisterNatives failed for '%s'\n", class_name);
53 | return JNI_FALSE;
54 | }
55 |
56 | return JNI_TRUE;
57 | }
58 |
59 | jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
60 | {
61 | JNIEnv* env = NULL;
62 | jint result = -1;
63 |
64 | if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
65 | LOGE(1, "ERROR: GetEnv failed\n");
66 | goto bail;
67 | }
68 | assert(env != NULL);
69 |
70 | if (register_native_methods(env,
71 | nativetester_class_path_name,
72 | nativetester_methods,
73 | NELEM(nativetester_methods)) < 0) {
74 | LOGE(1, "ERROR: Exif native registration failed\n");
75 | goto bail;
76 | }
77 |
78 | /* success -- return valid version number */
79 | result = JNI_VERSION_1_4;
80 |
81 | bail:
82 | return result;
83 | }
84 |
--------------------------------------------------------------------------------
/library-jni/jni/nativetester.c:
--------------------------------------------------------------------------------
1 | /*
2 | * nativetester.c
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | /*android specific headers*/
20 | #include
21 | #include
22 | #include
23 |
24 | #include
25 |
26 | #include "nativetester.h"
27 |
28 |
29 | #define LOG_TAG "NativeTester"
30 | #define LOG_LEVEL 10
31 | #define LOGI(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__);}
32 | #define LOGE(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);}
33 |
34 | jboolean jni_nativetester_is_neon(JNIEnv *env, jobject thiz) {
35 | uint64_t features;
36 | #ifdef FEATURE_NEON
37 |
38 | if (android_getCpuFamily() != ANDROID_CPU_FAMILY_ARM) {
39 | LOGI(5, "Not an ARM CPU\n");
40 | return JNI_FALSE;
41 | }
42 |
43 | features = android_getCpuFeatures();
44 |
45 | if ((features & ANDROID_CPU_ARM_FEATURE_ARMv7) == 0) {
46 | LOGI(5, "Not an ARMv7 CPU\n");
47 | return JNI_FALSE;
48 | }
49 |
50 | if ((features & ANDROID_CPU_ARM_FEATURE_NEON) == 0) {
51 | LOGI(5, "CPU doesn't support NEON\n");
52 | return JNI_FALSE;
53 | }
54 |
55 | return JNI_TRUE;
56 | #else
57 | return JNI_FALSE;
58 | #endif
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/library-jni/jni/nativetester.h:
--------------------------------------------------------------------------------
1 | /*
2 | * nativetester.h
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #ifndef NATIVETESTER_H_
20 | #define NATIVETESTER_H_
21 |
22 | static const char *nativetester_class_path_name = "com/appunite/ffmpeg/NativeTester";
23 |
24 | jboolean jni_nativetester_is_neon(JNIEnv *env, jobject thiz);
25 |
26 |
27 | static JNINativeMethod nativetester_methods[] = {
28 | {"isNeon", "()Z", (void*) jni_nativetester_is_neon},
29 | };
30 |
31 | #endif /* NATIVETESTER_H_ */
32 |
--------------------------------------------------------------------------------
/library-jni/jni/player.h:
--------------------------------------------------------------------------------
1 | /*
2 | * player.h
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #ifndef H_PLAYER
20 | #define H_PLAYER
21 |
22 | #include
23 |
24 | static JavaMethod empty_constructor = {"", "()V"};
25 |
26 | // InterruptedException
27 | static char *interrupted_exception_class_path_name = "java/lang/InterruptedException";
28 |
29 | // RuntimeException
30 | static char *runtime_exception_class_path_name = "java/lang/RuntimeException";
31 |
32 | // NotPlayingException
33 | static char *not_playing_exception_class_path_name = "com/appunite/ffmpeg/NotPlayingException";
34 |
35 | // Object
36 | static char *object_class_path_name = "java/lang/Object";
37 |
38 | // HashMap
39 | static char *hash_map_class_path_name = "java/util/HashMap";
40 | static char *map_class_path_name = "java/util/Map";
41 | static JavaMethod map_key_set = {"keySet", "()Ljava/util/Set;"};
42 | static JavaMethod map_get = {"get", "(Ljava/lang/Object;)Ljava/lang/Object;"};
43 | static JavaMethod map_put = {"put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"};
44 |
45 | // FFmpegStreamInfo.CodeType
46 | enum CodecType {
47 | CODEC_TYPE_UNKNOWN = 0,
48 | CODEC_TYPE_AUDIO = 1,
49 | CODEC_TYPE_VIDEO = 2,
50 | CODEC_TYPE_SUBTITLE = 3,
51 | CODEC_TYPE_ATTACHMENT = 4,
52 | CODEC_TYPE_NB = 5,
53 | CODEC_TYPE_DATA = 6
54 | };
55 |
56 | enum StreamNumber {
57 | NO_STREAM = -2,
58 | UNKNOWN_STREAM = -1,
59 | };
60 |
61 | // FFmpegStreamInfo
62 | static char *stream_info_class_path_name = "com/appunite/ffmpeg/FFmpegStreamInfo";
63 | static JavaMethod steram_info_set_metadata = {"setMetadata", "(Ljava/util/Map;)V"};
64 | static JavaMethod steram_info_set_media_type_internal = {"setMediaTypeInternal", "(I)V"};
65 | static JavaMethod stream_info_set_stream_number = {"setStreamNumber", "(I)V"};
66 |
67 |
68 | // Set
69 | static char *set_class_path_name = "java/util/Set";
70 | static JavaMethod set_iterator = {"iterator", "()Ljava/util/Iterator;"};
71 |
72 | // Iterator
73 | static char *iterator_class_path_name = "java/util/Iterator";
74 | static JavaMethod iterator_next = {"next", "()Ljava/lang/Object;"};
75 | static JavaMethod iterator_has_next = {"hasNext", "()Z"};
76 |
77 | static const struct {
78 | const char *name;
79 | int nb_channels;
80 | uint64_t layout;
81 | } channel_android_layout_map[] = {
82 | { "mono", 1, AV_CH_LAYOUT_MONO },
83 | { "stereo", 2, AV_CH_LAYOUT_STEREO },
84 | { "2.1", 3, AV_CH_LAYOUT_2POINT1 },
85 | { "4.0", 4, AV_CH_LAYOUT_4POINT0 },
86 | { "4.1", 5, AV_CH_LAYOUT_4POINT1 },
87 | { "5.1", 6, AV_CH_LAYOUT_5POINT1_BACK },
88 | { "6.0", 6, AV_CH_LAYOUT_6POINT0 },
89 | { "7.0(front)", 7, AV_CH_LAYOUT_7POINT0_FRONT },
90 | { "7.1", 8, AV_CH_LAYOUT_7POINT1 },
91 | };
92 |
93 |
94 | // FFmpegPlayer
95 | static char *player_class_path_name = "com/appunite/ffmpeg/FFmpegPlayer";
96 | static JavaField player_m_native_player = {"mNativePlayer", "I"};
97 | static JavaMethod player_on_update_time = {"onUpdateTime","(JJZ)V"};
98 | static JavaMethod player_prepare_audio_track = {"prepareAudioTrack", "(II)Landroid/media/AudioTrack;"};
99 | static JavaMethod player_prepare_frame = {"prepareFrame", "(II)Landroid/graphics/Bitmap;"};
100 | static JavaMethod player_set_stream_info = {"setStreamsInfo", "([Lcom/appunite/ffmpeg/FFmpegStreamInfo;)V"};
101 |
102 | // AudioTrack
103 | static char *android_track_class_path_name = "android/media/AudioTrack";
104 | static JavaMethod audio_track_write = {"write", "([BII)I"};
105 | static JavaMethod audio_track_pause = {"pause", "()V"};
106 | static JavaMethod audio_track_play = {"play", "()V"};
107 | static JavaMethod audio_track_flush = {"flush", "()V"};
108 | static JavaMethod audio_track_stop = {"stop", "()V"};
109 | static JavaMethod audio_track_get_channel_count = {"getChannelCount", "()I"};
110 | static JavaMethod audio_track_get_sample_rate = {"getSampleRate", "()I"};
111 |
112 |
113 | // Player
114 |
115 | int jni_player_init(JNIEnv *env, jobject thiz);
116 | void jni_player_dealloc(JNIEnv *env, jobject thiz);
117 |
118 | void jni_player_seek(JNIEnv *env, jobject thiz, jlong positionUs);
119 |
120 | void jni_player_pause(JNIEnv *env, jobject thiz);
121 | void jni_player_resume(JNIEnv *env, jobject thiz);
122 |
123 | int jni_player_set_data_source(JNIEnv *env, jobject thiz, jstring string,
124 | jobject dictionary, int video_stream_no, int audio_stream_no,
125 | int subtitle_stream_no);
126 | void jni_player_stop(JNIEnv *env, jobject thiz);
127 |
128 | void jni_player_render_frame_start(JNIEnv *env, jobject thiz);
129 | void jni_player_render_frame_stop(JNIEnv *env, jobject thiz);
130 |
131 | jlong jni_player_get_video_duration(JNIEnv *env, jobject thiz);
132 | void jni_player_render(JNIEnv *env, jobject thiz, jobject surface);
133 |
134 | static JNINativeMethod player_methods[] = {
135 |
136 | {"initNative", "()I", (void*) jni_player_init},
137 | {"deallocNative", "()V", (void*) jni_player_dealloc},
138 |
139 | {"seekNative", "(J)V", (void*) jni_player_seek},
140 |
141 | {"pauseNative", "()V", (void*) jni_player_pause},
142 | {"resumeNative", "()V", (void*) jni_player_resume},
143 |
144 | {"setDataSourceNative", "(Ljava/lang/String;Ljava/util/Map;III)I", (void*) jni_player_set_data_source},
145 | {"stopNative", "()V", (void*) jni_player_stop},
146 |
147 | {"renderFrameStart", "()V", (void*) jni_player_render_frame_start},
148 | {"renderFrameStop", "()V", (void*) jni_player_render_frame_stop},
149 |
150 | {"getVideoDurationNative", "()J", (void*) jni_player_get_video_duration},
151 | {"render", "(Landroid/view/Surface;)V", (void*) jni_player_render},
152 | };
153 |
154 | #endif
155 |
--------------------------------------------------------------------------------
/library-jni/jni/queue.c:
--------------------------------------------------------------------------------
1 | /*
2 | * queue.c
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #include "queue.h"
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #define FALSE 0
27 | #define TRUE (!(FALSE))
28 |
29 | struct _Queue {
30 | int next_to_write;
31 | int next_to_read;
32 | int *ready;
33 |
34 | int in_read;
35 |
36 | queue_free_func free_func;
37 |
38 | int is_custom_lock;
39 | int size;
40 | void ** tab;
41 | };
42 |
43 | int queue_get_next(Queue *queue, int value) {
44 | return (value + 1) % queue->size;
45 | }
46 |
47 | Queue *queue_init_with_custom_lock(int size, queue_fill_func fill_func,
48 | queue_free_func free_func, void *obj, void *free_obj, pthread_mutex_t *custom_lock,
49 | pthread_cond_t *custom_cond) {
50 | Queue *queue = malloc(sizeof(Queue));
51 | if (queue == NULL)
52 | return NULL;
53 |
54 | queue->next_to_write = 0;
55 | queue->next_to_read = 0;
56 | queue->ready = malloc(sizeof(*queue->ready) * size);
57 | if (queue->ready == NULL)
58 | goto free_queue;
59 |
60 | queue->in_read = FALSE;
61 |
62 | queue->free_func = free_func;
63 |
64 | queue->is_custom_lock = TRUE;
65 |
66 | queue->size = size;
67 |
68 | queue->tab = malloc(sizeof(*queue->tab) * size);
69 | if (queue->tab == NULL)
70 | goto free_ready;
71 | memset(queue->tab, 0, sizeof(*queue->tab) * size);
72 | int i;
73 | for (i = queue->size - 1; i >= 0; --i) {
74 | void * elem = fill_func(obj);
75 | if (elem == NULL)
76 | goto free_tabs;
77 | queue->tab[i] = elem;
78 | }
79 |
80 | goto end;
81 | free_tabs: for (i = queue->size - 1; i >= 0; --i) {
82 | void *elem = queue->tab[i];
83 | if (elem == NULL)
84 | continue;
85 | queue->free_func(free_obj, elem);
86 | }
87 |
88 | free_tab: free(queue->tab);
89 |
90 | free_ready: free(queue->ready);
91 |
92 | free_queue: free(queue);
93 | queue = NULL;
94 |
95 | end: return queue;
96 | }
97 |
98 | void queue_free(Queue *queue, pthread_mutex_t * mutex, pthread_cond_t *cond, void *free_obj) {
99 | pthread_mutex_lock(mutex);
100 | while (queue->in_read)
101 | pthread_cond_wait(cond, mutex);
102 |
103 | int i;
104 | for (i = queue->size - 1; i >= 0; --i) {
105 | void *elem = queue->tab[i];
106 | queue->free_func(free_obj, elem);
107 | }
108 | pthread_mutex_unlock(mutex);
109 |
110 | free(queue->tab);
111 |
112 | free(queue->ready);
113 |
114 | free(queue);
115 | }
116 |
117 | void *queue_push_start_already_locked(Queue *queue, pthread_mutex_t * mutex,
118 | pthread_cond_t *cond, int *to_write, QueueCheckFunc func,
119 | void *check_data, void *check_ret_data) {
120 | int next_next_to_write;
121 | while (1) {
122 | if (func == NULL)
123 | goto test;
124 | QueueCheckFuncRet check = func(queue, check_data, check_ret_data);
125 | if (check == QUEUE_CHECK_FUNC_RET_SKIP)
126 | return NULL;
127 | else if (check == QUEUE_CHECK_FUNC_RET_WAIT)
128 | goto wait;
129 | else if (check == QUEUE_CHECK_FUNC_RET_TEST)
130 | goto test;
131 | else
132 | assert(FALSE);
133 |
134 | test: next_next_to_write = queue_get_next(queue, queue->next_to_write);
135 | if (next_next_to_write != queue->next_to_read) {
136 | break;
137 | }
138 |
139 | wait: pthread_cond_wait(cond, mutex);
140 | }
141 | *to_write = queue->next_to_write;
142 | queue->ready[*to_write] = FALSE;
143 |
144 | queue->next_to_write = next_next_to_write;
145 |
146 | pthread_cond_broadcast(cond);
147 |
148 | end: return queue->tab[*to_write];
149 | }
150 |
151 | void *queue_push_start(Queue *queue, pthread_mutex_t * mutex,
152 | pthread_cond_t *cond, int *to_write, QueueCheckFunc func,
153 | void *check_data, void *check_ret_data) {
154 | void *ret;
155 | pthread_mutex_lock(mutex);
156 | ret = queue_push_start_already_locked(queue, mutex, cond, to_write, func,
157 | check_data, check_ret_data);
158 | pthread_mutex_unlock(mutex);
159 | return ret;
160 | }
161 |
162 | void queue_push_finish_already_locked(Queue *queue, pthread_mutex_t * mutex,
163 | pthread_cond_t *cond, int to_write) {
164 | queue->ready[to_write] = TRUE;
165 | pthread_cond_broadcast(cond);
166 | }
167 |
168 | void queue_push_finish(Queue *queue, pthread_mutex_t * mutex,
169 | pthread_cond_t *cond, int to_write) {
170 | pthread_mutex_lock(mutex);
171 | queue_push_finish_already_locked(queue, mutex, cond, to_write);
172 | pthread_mutex_unlock(mutex);
173 | }
174 |
175 | void *queue_pop_start_already_locked_non_block(Queue *queue) {
176 | assert(!queue->in_read);
177 | int to_read = queue->next_to_read;
178 | if (to_read == queue->next_to_write)
179 | return NULL;
180 | if (!queue->ready[to_read])
181 | return NULL;
182 |
183 | queue->in_read = TRUE;
184 | return queue->tab[to_read];
185 | }
186 |
187 | void *queue_pop_start_already_locked(Queue **queue, pthread_mutex_t * mutex,
188 | pthread_cond_t *cond, QueueCheckFunc func, void *check_data,
189 | void *check_ret_data) {
190 | int to_read;
191 | Queue *q;
192 | while (1) {
193 | if (func == NULL)
194 | goto test;
195 | QueueCheckFuncRet check = func(*queue, check_data, check_ret_data);
196 | if (check == QUEUE_CHECK_FUNC_RET_SKIP)
197 | goto skip;
198 | else if (check == QUEUE_CHECK_FUNC_RET_WAIT)
199 | goto wait;
200 | else if (check == QUEUE_CHECK_FUNC_RET_TEST)
201 | goto test;
202 | else
203 | assert(FALSE);
204 | test:
205 | q = *queue;
206 | assert(!q->in_read);
207 | if (q->next_to_read != q->next_to_write
208 | && q->ready[q->next_to_read])
209 | break;
210 | wait: pthread_cond_wait(cond, mutex);
211 | }
212 | q=*queue;
213 | to_read = q->next_to_read;
214 | q->in_read = TRUE;
215 |
216 | end:
217 |
218 | return q->tab[to_read];
219 |
220 | skip: return NULL;
221 | }
222 |
223 | void *queue_pop_start(Queue **queue, pthread_mutex_t * mutex,
224 | pthread_cond_t *cond, QueueCheckFunc func, void *check_data,
225 | void *check_ret_data) {
226 | void *ret;
227 | pthread_mutex_lock(mutex);
228 | ret = queue_pop_start_already_locked(queue, mutex, cond, func, check_data,
229 | check_ret_data);
230 | pthread_mutex_unlock(mutex);
231 | return ret;
232 | }
233 |
234 | void queue_pop_roll_back_already_locked(Queue *queue, pthread_mutex_t * mutex,
235 | pthread_cond_t *cond) {
236 | assert(queue->in_read);
237 | queue->in_read = FALSE;
238 |
239 | pthread_cond_broadcast(cond);
240 | }
241 |
242 | void queue_pop_roll_back(Queue *queue, pthread_mutex_t * mutex,
243 | pthread_cond_t *cond) {
244 | pthread_mutex_lock(mutex);
245 | queue_pop_roll_back_already_locked(queue, mutex, cond);
246 | pthread_mutex_unlock(mutex);
247 | }
248 |
249 | void queue_pop_finish_already_locked(Queue *queue, pthread_mutex_t * mutex,
250 | pthread_cond_t *cond) {
251 | assert(queue->in_read);
252 | queue->in_read = FALSE;
253 | queue->next_to_read = queue_get_next(queue, queue->next_to_read);
254 |
255 | pthread_cond_broadcast(cond);
256 | }
257 |
258 | void queue_pop_finish(Queue *queue, pthread_mutex_t * mutex,
259 | pthread_cond_t *cond) {
260 | pthread_mutex_lock(mutex);
261 | queue_pop_finish_already_locked(queue, mutex, cond);
262 | pthread_mutex_unlock(mutex);
263 | }
264 |
265 | int queue_get_size(Queue *queue) {
266 | return queue->size;
267 | }
268 |
269 | void queue_wait_for(Queue *queue, int size, pthread_mutex_t * mutex,
270 | pthread_cond_t *cond) {
271 | assert(queue->size >= size);
272 |
273 | pthread_mutex_lock(mutex);
274 | while (1) {
275 | int next = queue->next_to_read;
276 | int i;
277 | int all_ok = TRUE;
278 | for (i = 0; i < size; ++i) {
279 | if (next == queue->next_to_write
280 | || !queue->ready[queue->next_to_read]) {
281 | all_ok = FALSE;
282 | break;
283 | }
284 |
285 | next = queue_get_next(queue, next);
286 | }
287 |
288 | if (all_ok)
289 | break;
290 |
291 | pthread_cond_wait(cond, mutex);
292 | }
293 | pthread_mutex_unlock(mutex);
294 | }
295 |
296 |
--------------------------------------------------------------------------------
/library-jni/jni/queue.h:
--------------------------------------------------------------------------------
1 | /*
2 | * queue.h
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #ifndef QUEUE_H_
20 | #define QUEUE_H_
21 |
22 | #include
23 |
24 | typedef struct _Queue Queue;
25 |
26 | typedef void * (*queue_fill_func)(void * obj);
27 | typedef void (*queue_free_func)(void * obj, void *elem);
28 |
29 | typedef enum {
30 | QUEUE_CHECK_FUNC_RET_WAIT = -1,
31 | QUEUE_CHECK_FUNC_RET_TEST = 0,
32 | QUEUE_CHECK_FUNC_RET_SKIP = 1
33 | } QueueCheckFuncRet;
34 |
35 | typedef QueueCheckFuncRet (*QueueCheckFunc)(Queue *queue, void* check_data,
36 | void *check_ret_data);
37 |
38 | Queue *queue_init_with_custom_lock(int size, queue_fill_func fill_func,
39 | queue_free_func free_func, void *obj, void *free_obj,
40 | pthread_mutex_t *custom_lock, pthread_cond_t *custom_cond);
41 | void queue_free(Queue *queue, pthread_mutex_t * mutex, pthread_cond_t *cond,
42 | void *free_obj);
43 |
44 | void *queue_push_start_already_locked(Queue *queue, pthread_mutex_t * mutex,
45 | pthread_cond_t *cond, int *to_write, QueueCheckFunc func,
46 | void *check_data, void *check_ret_data);
47 | void *queue_push_start(Queue *queue, pthread_mutex_t * mutex,
48 | pthread_cond_t *cond, int *to_write, QueueCheckFunc func,
49 | void *check_data, void *check_ret_data);
50 | void queue_push_finish_already_locked(Queue *queue, pthread_mutex_t * mutex,
51 | pthread_cond_t *cond, int to_write);
52 | void queue_push_finish(Queue *queue, pthread_mutex_t * mutex,
53 | pthread_cond_t *cond, int to_write);
54 |
55 | void *queue_pop_start_already_locked_non_block(Queue *queue);
56 | void *queue_pop_start_already_locked(Queue **queue, pthread_mutex_t * mutex,
57 | pthread_cond_t *cond, QueueCheckFunc func, void *check_data,
58 | void *check_ret_data);
59 | void *queue_pop_start(Queue **queue, pthread_mutex_t * mutex,
60 | pthread_cond_t *cond, QueueCheckFunc func, void *check_data,
61 | void *check_ret_data);
62 | void queue_pop_roll_back_already_locked(Queue *queue, pthread_mutex_t * mutex,
63 | pthread_cond_t *cond);
64 | void queue_pop_roll_back(Queue *queue, pthread_mutex_t * mutex,
65 | pthread_cond_t *cond);
66 | void queue_pop_finish_already_locked(Queue *queue, pthread_mutex_t * mutex,
67 | pthread_cond_t *cond);
68 | void queue_pop_finish(Queue *queue, pthread_mutex_t * mutex,
69 | pthread_cond_t *cond);
70 |
71 | int queue_get_size(Queue *queue);
72 |
73 | void queue_wait_for(Queue *queue, int size, pthread_mutex_t * mutex,
74 | pthread_cond_t *cond);
75 |
76 | #endif /* QUEUE_H_ */
77 |
--------------------------------------------------------------------------------
/library-jni/jni/sync.h:
--------------------------------------------------------------------------------
1 | /*
2 | * sync.h
3 | * Copyright (c) 2013 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | #ifndef SYNC_H_
20 | #define SYNC_H_
21 |
22 | enum WaitFuncRet {
23 | WAIT_FUNC_RET_OK = 0,
24 | WAIT_FUNC_RET_SKIP = 1,
25 | };
26 |
27 | typedef enum WaitFuncRet (WaitFunc) (void *data , int64_t time, int stream_no);
28 |
29 |
30 | #endif /* SYNC_H_ */
31 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 15
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | minSdkVersion 9
9 | targetSdkVersion 17
10 | }
11 |
12 | buildTypes {
13 | release {
14 | minifyEnabled false
15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/library/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/library/src/main/java/com/appunite/ffmpeg/FFmpegDisplay.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FFmpegDisplay.java
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | package com.appunite.ffmpeg;
20 |
21 | public interface FFmpegDisplay {
22 |
23 | void setMpegPlayer(FFmpegPlayer fFmpegPlayer);
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/library/src/main/java/com/appunite/ffmpeg/FFmpegError.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FFmpegError.java
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | package com.appunite.ffmpeg;
20 |
21 | public class FFmpegError extends Throwable {
22 |
23 | public FFmpegError(int err) {
24 | super(String.format("FFmpegPlayer error %d", err));
25 | }
26 |
27 | /**
28 | *
29 | */
30 | private static final long serialVersionUID = 1L;
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/library/src/main/java/com/appunite/ffmpeg/FFmpegListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FFmpegListener.java
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | package com.appunite.ffmpeg;
20 |
21 | public interface FFmpegListener {
22 | void onFFDataSourceLoaded(FFmpegError err, FFmpegStreamInfo[] streams);
23 |
24 | void onFFResume(NotPlayingException result);
25 |
26 | void onFFPause(NotPlayingException err);
27 |
28 | void onFFStop();
29 |
30 | void onFFUpdateTime(long mCurrentTimeUs, long mVideoDurationUs, boolean isFinished);
31 |
32 | void onFFSeeked(NotPlayingException result);
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/library/src/main/java/com/appunite/ffmpeg/FFmpegPlayer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FFmpegPlayer.java
3 | * Copyright (c) 2012 Jacek Marchwicki
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | */
18 |
19 | package com.appunite.ffmpeg;
20 |
21 | import java.util.Map;
22 |
23 | import android.app.Activity;
24 | import android.graphics.Bitmap;
25 | import android.media.AudioFormat;
26 | import android.media.AudioManager;
27 | import android.media.AudioTrack;
28 | import android.os.AsyncTask;
29 | import android.view.Surface;
30 |
31 | public class FFmpegPlayer {
32 | private static class StopTask extends AsyncTask {
33 |
34 | private final FFmpegPlayer player;
35 |
36 | public StopTask(FFmpegPlayer player) {
37 | this.player = player;
38 | }
39 |
40 | @Override
41 | protected Void doInBackground(Void... params) {
42 | player.stopNative();
43 | return null;
44 | }
45 |
46 | @Override
47 | protected void onPostExecute(Void result) {
48 | if (player.mpegListener != null)
49 | player.mpegListener.onFFStop();
50 | }
51 |
52 | }
53 |
54 | private static class SetDataSourceTaskResult {
55 | FFmpegError error;
56 | FFmpegStreamInfo[] streams;
57 | }
58 |
59 | private static class SetDataSourceTask extends
60 | AsyncTask