├── library
├── src
│ └── main
│ │ ├── jniLibs
│ │ ├── res
│ │ └── values
│ │ │ ├── styles.xml
│ │ │ └── attrs.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── appunite
│ │ └── ffmpeg
│ │ ├── FFmpegDisplay.java
│ │ ├── NativeTester.java
│ │ ├── FFmpegError.java
│ │ ├── FFmpegListener.java
│ │ ├── NotPlayingException.java
│ │ ├── FpsCounter.java
│ │ ├── JniReader.java
│ │ ├── FFmpegSurfaceView.java
│ │ ├── FFmpegStreamInfo.java
│ │ ├── ViewCompat.java
│ │ ├── SeekerView.java
│ │ └── FFmpegPlayer.java
├── lint.xml
└── build.gradle
├── settings.gradle
├── example
├── src
│ └── main
│ │ ├── res
│ │ ├── 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
│ │ └── layout
│ │ │ ├── main_list_item.xml
│ │ │ ├── main_activity.xml
│ │ │ └── video_surfaceview.xml
│ │ ├── java
│ │ └── com
│ │ │ └── ffmpegtest
│ │ │ ├── AppConstants.java
│ │ │ ├── UserPreferences.java
│ │ │ ├── adapter
│ │ │ ├── VideoItem.java
│ │ │ └── ItemsAdapter.java
│ │ │ ├── MainActivity.java
│ │ │ └── VideoActivity.java
│ │ └── AndroidManifest.xml
└── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── library-jni
└── jni
│ ├── android-ndk-profiler-3.1
│ ├── armeabi
│ │ └── libandprof.a
│ ├── armeabi-v7a
│ │ └── libandprof.a
│ ├── prof.h
│ └── android-ndk-profiler.mk
│ ├── fetch.sh
│ ├── Android-tropicssl.mk
│ ├── aes-protocol.h
│ ├── jni-protocol.h
│ ├── Application.mk
│ ├── sync.h
│ ├── blend.h
│ ├── nativetester.h
│ ├── helpers.h
│ ├── helpers.c
│ ├── nativetester.c
│ ├── convert.h
│ ├── nativetester-jni.c
│ ├── ffmpeg-jni.c
│ ├── convert.cpp
│ ├── queue.h
│ ├── blend.c
│ ├── Android.mk
│ ├── player.h
│ ├── jni-protocol.c
│ ├── queue.c
│ ├── aes-protocol.c
│ └── build_android.sh
├── .gitignore
├── .gitmodules
├── .travis.yml
├── README.md
├── gradlew
└── LICENSE
/library/src/main/jniLibs:
--------------------------------------------------------------------------------
1 | ../../../library-jni/libs/
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':library'
2 | include ':example'
3 |
--------------------------------------------------------------------------------
/library/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/example/src/main/res/menu/main_activity.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/HEAD/example/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/HEAD/example/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/HEAD/example/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/HEAD/example/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/HEAD/example/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/library-jni/jni/android-ndk-profiler-3.1/armeabi/libandprof.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/HEAD/library-jni/jni/android-ndk-profiler-3.1/armeabi/libandprof.a
--------------------------------------------------------------------------------
/library-jni/jni/android-ndk-profiler-3.1/armeabi-v7a/libandprof.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appunite/AndroidFFmpeg/HEAD/library-jni/jni/android-ndk-profiler-3.1/armeabi-v7a/libandprof.a
--------------------------------------------------------------------------------
/library/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/example/src/main/res/values/constans.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - .3gp
5 | - .mp4
6 | - .avi
7 | - .mov
8 |
9 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/example/src/main/res/layout/main_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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-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/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/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/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-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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/library/src/main/java/com/appunite/ffmpeg/NativeTester.java:
--------------------------------------------------------------------------------
1 | /*
2 | * NativeTester.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 | class NativeTester {
22 | static {
23 | System.loadLibrary("nativetester-jni");
24 | }
25 |
26 | native boolean isNeon();
27 | }
28 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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-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/src/main/java/com/appunite/ffmpeg/NotPlayingException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * NotPlayingException.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 NotPlayingException extends Exception {
22 | private static final long serialVersionUID = 1L;
23 |
24 | public NotPlayingException(String detailMessage, Throwable throwable) {
25 | super(detailMessage, throwable);
26 | }
27 |
28 | public NotPlayingException(String detailMessage) {
29 | super(detailMessage);
30 | }
31 |
32 | public NotPlayingException() {
33 | super();
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/example/src/main/res/layout/main_activity.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
15 |
16 |
20 |
28 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/library/src/main/java/com/appunite/ffmpeg/FpsCounter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FpsCounter.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 FpsCounter {
22 | private final int frameCount;
23 | private int counter = 0;
24 | boolean start = true;
25 |
26 | private long startTime = 0;
27 |
28 | private String tick = "- fps";
29 |
30 | public FpsCounter(int frameCount) {
31 | this.frameCount = frameCount;
32 | }
33 |
34 | public String tick() {
35 | if (this.start) {
36 | this.start = false;
37 | this.startTime = System.nanoTime();
38 | }
39 | if (this.counter++ < this.frameCount) {
40 | return this.tick;
41 | }
42 |
43 | long stopTime = System.nanoTime();
44 | double fps = (double) this.frameCount * (1000.0 * 1000.0 * 1000.0)
45 | / (double) (stopTime - this.startTime);
46 | this.startTime = stopTime;
47 | this.counter = 0;
48 |
49 | this.tick = String.format("%.2f fps", fps);
50 | return this.tick;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/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/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/src/main/java/com/appunite/ffmpeg/JniReader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * JniReader.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.io.UnsupportedEncodingException;
22 | import java.security.MessageDigest;
23 | import java.security.NoSuchAlgorithmException;
24 |
25 | import android.util.Log;
26 |
27 | public class JniReader {
28 |
29 | private static final String TAG = JniReader.class.getCanonicalName();
30 |
31 | private byte[] value = new byte[16];
32 | private int position;
33 |
34 | public JniReader(String url, int flags) {
35 | Log.d(TAG, String.format("Reading: %s", url));
36 | try {
37 | byte[] key = "dupadupadupadupa".getBytes("UTF-8");
38 |
39 | MessageDigest m = MessageDigest.getInstance("MD5");
40 | m.update(key);
41 | System.arraycopy(m.digest(), 0, value, 0, 16);
42 |
43 | } catch (UnsupportedEncodingException e) {
44 | throw new RuntimeException(e);
45 | } catch (NoSuchAlgorithmException e) {
46 | throw new RuntimeException(e);
47 | }
48 | position = 0;
49 | }
50 |
51 | public int read(byte[] buffer) {
52 | int end = position + buffer.length;
53 | if (end >= value.length)
54 | end = value.length;
55 |
56 | int length = end - position;
57 | System.arraycopy(value, position, buffer, 0, length);
58 | position += length;
59 |
60 | return length;
61 | }
62 |
63 | public int write(byte[] buffer) {
64 | return 0;
65 | }
66 |
67 | public int check(int mask) {
68 | return 0;
69 | }
70 |
71 | public long seek(long pos, int whence) {
72 | return -1;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/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/src/main/java/com/appunite/ffmpeg/FFmpegSurfaceView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FFmpegSurfaceView.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 android.content.Context;
22 | import android.graphics.PixelFormat;
23 | import android.util.AttributeSet;
24 | import android.view.Surface;
25 | import android.view.SurfaceHolder;
26 | import android.view.SurfaceView;
27 |
28 | public class FFmpegSurfaceView extends SurfaceView implements FFmpegDisplay,
29 | SurfaceHolder.Callback {
30 |
31 | public static enum ScaleType {
32 | CENTER_CROP, CENTER_INSIDE, FIT_XY
33 | }
34 |
35 | private FFmpegPlayer mMpegPlayer = null;
36 | private boolean mCreated = false;
37 |
38 | public FFmpegSurfaceView(Context context) {
39 | this(context, null, 0);
40 | }
41 |
42 | public FFmpegSurfaceView(Context context, AttributeSet attrs) {
43 | this(context, attrs, 0);
44 | }
45 |
46 | public FFmpegSurfaceView(Context context, AttributeSet attrs, int defStyle) {
47 | super(context, attrs, defStyle);
48 |
49 | SurfaceHolder holder = getHolder();
50 | holder.setFormat(PixelFormat.RGBA_8888);
51 | holder.addCallback(this);
52 | }
53 |
54 | @Override
55 | public void setMpegPlayer(FFmpegPlayer fFmpegPlayer) {
56 | if (mMpegPlayer != null)
57 | throw new RuntimeException(
58 | "setMpegPlayer could not be called twice");
59 |
60 | this.mMpegPlayer = fFmpegPlayer;
61 | }
62 |
63 | @Override
64 | public void surfaceChanged(SurfaceHolder holder, int format, int width,
65 | int height) {
66 |
67 | }
68 |
69 | @Override
70 | public void surfaceCreated(SurfaceHolder holder) {
71 | if (mCreated == true) {
72 | surfaceDestroyed(holder);
73 | }
74 |
75 | Surface surface = holder.getSurface();
76 | mMpegPlayer.render(surface);
77 | mCreated = true;
78 | }
79 |
80 | @Override
81 | public void surfaceDestroyed(SurfaceHolder holder) {
82 | this.mMpegPlayer.renderFrameStop();
83 | mCreated = false;
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/src/main/java/com/appunite/ffmpeg/FFmpegStreamInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * FFmpegStreamInfo.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.HashMap;
22 | import java.util.Locale;
23 | import java.util.Map;
24 |
25 | public class FFmpegStreamInfo {
26 | public enum CodecType {
27 | UNKNOWN, AUDIO, VIDEO, SUBTITLE, ATTACHMENT, NB, DATA;
28 | }
29 |
30 | private static Map sLocaleMap;
31 | static {
32 | String[] languages = Locale.getISOLanguages();
33 | sLocaleMap = new HashMap(languages.length);
34 | for (String language : languages) {
35 | Locale locale = new Locale(language);
36 | sLocaleMap.put(locale.getISO3Language(), locale);
37 | }
38 | }
39 |
40 | private Map mMetadata;
41 | private CodecType mMediaType;
42 | private int mStreamNumber;
43 |
44 | public void setMetadata(Map metadata) {
45 | this.mMetadata = metadata;
46 | }
47 |
48 | void setMediaTypeInternal(int mediaTypeInternal) {
49 | mMediaType = CodecType.values()[mediaTypeInternal];
50 | }
51 |
52 | void setStreamNumber(int streamNumber) {
53 | this.mStreamNumber = streamNumber;
54 | }
55 |
56 | public int getStreamNumber() {
57 | return this.mStreamNumber;
58 | }
59 |
60 | /**
61 | * Return stream language locale
62 | * @return locale or null if not known
63 | */
64 | public Locale getLanguage() {
65 | if (mMetadata == null)
66 | return null;
67 | String iso3Langugae = mMetadata.get("language");
68 | if (iso3Langugae == null)
69 | return null;
70 | return sLocaleMap.get(iso3Langugae);
71 | }
72 |
73 | public CodecType getMediaType() {
74 | return mMediaType;
75 | }
76 |
77 | public Map getMetadata() {
78 | return mMetadata;
79 | }
80 |
81 | @Override
82 | public String toString() {
83 | Locale language = getLanguage();
84 | String languageName = language == null ? "unknown" : language.getDisplayName();
85 | return new StringBuilder().
86 | append("{\n")
87 | .append("\tmediaType: ")
88 | .append(mMediaType)
89 | .append("\n")
90 | .append("\tlanguage: ")
91 | .append(languageName)
92 | .append("\n")
93 | .append("\tmetadata ")
94 | .append(mMetadata)
95 | .append("\n")
96 | .append("}")
97 | .toString();
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/library/src/main/java/com/appunite/ffmpeg/ViewCompat.java:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * Copyright (C) 2012 Jacek Marchwicki
4 | *
5 | * Extracted from View.java by:
6 | * Copyright (C) 2006 The Android Open Source Project
7 | *
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | */
20 |
21 | package com.appunite.ffmpeg;
22 |
23 | import android.annotation.TargetApi;
24 | import android.os.Build;
25 | import android.view.View;
26 | import android.view.View.MeasureSpec;
27 |
28 | public class ViewCompat {
29 |
30 | /**
31 | * Bits of {@link #getMeasuredWidthAndState()} and
32 | * {@link #getMeasuredWidthAndState()} that provide the actual measured size.
33 | */
34 | public static final int MEASURED_SIZE_MASK = 0x00ffffff;
35 |
36 | /**
37 | * Bit of {@link #getMeasuredWidthAndState()} and
38 | * {@link #getMeasuredWidthAndState()} that indicates the measured size
39 | * is smaller that the space the view would like to have.
40 | */
41 | public static final int MEASURED_STATE_TOO_SMALL = 0x01000000;
42 |
43 | /**
44 | * Bits of {@link #getMeasuredWidthAndState()} and
45 | * {@link #getMeasuredWidthAndState()} that provide the additional state bits.
46 | */
47 | public static final int MEASURED_STATE_MASK = 0xff000000;
48 |
49 | /**
50 | * Version of {@link #resolveSizeAndState(int, int, int)}
51 | * returning only the {@link #MEASURED_SIZE_MASK} bits of the result.
52 | */
53 | public static int resolveSize(int size, int measureSpec) {
54 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
55 | return View.resolveSize(size, measureSpec);
56 | }
57 | return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK;
58 | }
59 |
60 | /**
61 | * Utility to reconcile a desired size and state, with constraints imposed
62 | * by a MeasureSpec. Will take the desired size, unless a different size
63 | * is imposed by the constraints. The returned value is a compound integer,
64 | * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and
65 | * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the resulting
66 | * size is smaller than the size the view wants to be.
67 | *
68 | * @param size How big the view wants to be
69 | * @param measureSpec Constraints imposed by the parent
70 | * @return Size information bit mask as defined by
71 | * {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
72 | */
73 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
74 | public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
75 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
76 | return View.resolveSizeAndState(size, measureSpec, childMeasuredState);
77 | }
78 | int result = size;
79 | int specMode = MeasureSpec.getMode(measureSpec);
80 | int specSize = MeasureSpec.getSize(measureSpec);
81 | switch (specMode) {
82 | case MeasureSpec.UNSPECIFIED:
83 | result = size;
84 | break;
85 | case MeasureSpec.AT_MOST:
86 | if (specSize < size) {
87 | result = specSize | MEASURED_STATE_TOO_SMALL;
88 | } else {
89 | result = size;
90 | }
91 | break;
92 | case MeasureSpec.EXACTLY:
93 | result = specSize;
94 | break;
95 | }
96 | return result | (childMeasuredState&MEASURED_STATE_MASK);
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/src/main/java/com/appunite/ffmpeg/SeekerView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * SeekerView.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 android.content.Context;
22 | import android.content.res.TypedArray;
23 | import android.graphics.Canvas;
24 | import android.graphics.Color;
25 | import android.graphics.Paint;
26 | import android.graphics.Rect;
27 | import android.util.AttributeSet;
28 | import android.view.MotionEvent;
29 | import android.view.View;
30 | import com.appunite.ffmpeg.R;
31 |
32 | public class SeekerView extends View {
33 |
34 | public static interface OnProgressChangeListener {
35 | void onProgressChange(boolean finished, int currentValue, int maxValue);
36 | }
37 |
38 | private int mBorderWidth;
39 | private int mBorderColor;
40 | private int mBorderPadding;
41 |
42 | private int mBarMinHeight;
43 | private int mBarMinWidth;
44 | private int mBarColor;
45 |
46 | private Paint mBorderPaint = new Paint();
47 | private Paint mBarPaint = new Paint();
48 |
49 | private Rect mBorderRect = new Rect();
50 | private Rect mBarRect = new Rect();
51 | private OnProgressChangeListener mOnProgressChangeListener = null;
52 |
53 | private int mMaxValue = 100;
54 | private int mCurrentValue = 10;
55 |
56 | public void setOnProgressChangeListener(OnProgressChangeListener onProgressChangeListener) {
57 | this.mOnProgressChangeListener = onProgressChangeListener;
58 | }
59 |
60 | public SeekerView(Context context, AttributeSet attrs, int defStyle) {
61 | super(context, attrs, defStyle);
62 | TypedArray a = this.getContext().obtainStyledAttributes(attrs,
63 | R.styleable.SeekerView, defStyle, 0);
64 |
65 | final float scale = getResources().getDisplayMetrics().density;
66 |
67 | mBorderWidth = a.getDimensionPixelSize(
68 | R.styleable.SeekerView_borderWidth, (int) (1 * scale + 0.5f));
69 | mBorderColor = a.getColor(R.styleable.SeekerView_barColor, Color.CYAN);
70 | mBorderPadding = a.getColor(R.styleable.SeekerView_borderPadding,
71 | (int) (1 * scale + 0.5f));
72 |
73 | mBarMinHeight = a.getDimensionPixelSize(
74 | R.styleable.SeekerView_barMinHeight, (int) (10 * scale + 0.5f));
75 | mBarMinWidth = a.getDimensionPixelSize(
76 | R.styleable.SeekerView_barMinWidth, (int) (50 * scale + 0.5f));
77 | mBarColor = a.getColor(R.styleable.SeekerView_barColor, Color.BLUE);
78 |
79 | mBorderPaint.setDither(true);
80 | mBorderPaint.setColor(mBorderColor);
81 | mBorderPaint.setStyle(Paint.Style.STROKE);
82 | mBorderPaint.setStrokeJoin(Paint.Join.ROUND);
83 | mBorderPaint.setStrokeCap(Paint.Cap.ROUND);
84 | mBorderPaint.setStrokeWidth(mBorderWidth);
85 |
86 | mBarPaint.setDither(true);
87 | mBarPaint.setColor(mBarColor);
88 | mBarPaint.setStyle(Paint.Style.FILL);
89 | mBarPaint.setStrokeJoin(Paint.Join.ROUND);
90 | mBarPaint.setStrokeCap(Paint.Cap.ROUND);
91 |
92 | mMaxValue = a.getInt(R.styleable.SeekerView_maxValue, mMaxValue);
93 | mCurrentValue = a.getInt(R.styleable.SeekerView_currentValue, mCurrentValue);
94 | }
95 |
96 | public SeekerView(Context context, AttributeSet attrs) {
97 | this(context, attrs, 0);
98 | }
99 |
100 | public SeekerView(Context context) {
101 | this(context, null);
102 | }
103 |
104 | public void setMaxValue(int maxValue) {
105 | this.mMaxValue = maxValue;
106 | this.invalidate();
107 | }
108 |
109 | public int maxValue() {
110 | return mMaxValue;
111 | }
112 |
113 | public void setCurrentValue(int currentValue) {
114 | this.mCurrentValue = currentValue;
115 | this.invalidate();
116 | }
117 |
118 | public int currentValue() {
119 | return this.mCurrentValue;
120 | }
121 |
122 | @Override
123 | protected void onDraw(Canvas canvas) {
124 | super.onDraw(canvas);
125 | canvas.drawRect(mBorderRect, mBorderPaint);
126 | canvas.drawRect(mBarRect, mBarPaint);
127 | }
128 |
129 | @Override
130 | public boolean onTouchEvent(MotionEvent event) {
131 | int action = event.getActionMasked();
132 |
133 | boolean superResult = super.onTouchEvent(event);
134 | boolean grab = false;
135 | boolean finished = false;
136 |
137 | if (action == MotionEvent.ACTION_DOWN) {
138 | grab = true;
139 | } else if (action == MotionEvent.ACTION_MOVE) {
140 | grab = true;
141 | } else if (action == MotionEvent.ACTION_UP) {
142 | grab = true;
143 | finished = true;
144 | }
145 | if (grab) {
146 |
147 | float eventX = event.getX();
148 | int padding = mBorderWidth + mBorderPadding;
149 | int barLeft = padding;
150 | int barWidth = getWidth() - 2*padding;
151 | float x = eventX - barLeft;
152 | if (x < 0.0f)
153 | x = 0.0f;
154 | if (x > barWidth)
155 | x = barWidth;
156 | x /= (float)barWidth;
157 | mCurrentValue = (int) (mMaxValue * x);
158 |
159 | if (mOnProgressChangeListener != null) {
160 | mOnProgressChangeListener.onProgressChange(finished, mCurrentValue, mMaxValue);
161 | }
162 | calculateBarRect();
163 | this.invalidate();
164 | return true;
165 | } else {
166 | return superResult;
167 | }
168 | }
169 |
170 | @Override
171 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
172 | int dw = 0;
173 | int dh = 0;
174 |
175 | dw = (mBorderWidth + mBorderPadding) * 2 + mBarMinWidth;
176 | dh = (mBorderWidth + mBorderPadding) * 2 + mBarMinHeight;
177 | this.setMeasuredDimension(
178 | ViewCompat.resolveSizeAndState(dw, widthMeasureSpec, 0),
179 | ViewCompat.resolveSizeAndState(dh, heightMeasureSpec, 0));
180 | }
181 |
182 | private void calculateBarRect() {
183 | int width = getWidth();
184 | int height = getHeight();
185 | int barPadding = mBorderWidth + mBorderPadding;
186 |
187 | int maxBarWidth = width - barPadding;
188 | float pos = (float) mCurrentValue / mMaxValue;
189 | int barWidth = (int) (maxBarWidth * pos);
190 | mBarRect.set(
191 | barPadding,
192 | barPadding,
193 | barWidth,
194 | height - barPadding);
195 | }
196 |
197 | @Override
198 | protected void onLayout(boolean changed, int left, int top, int right,
199 | int bottom) {
200 | super.onLayout(changed, left, top, right, bottom);
201 |
202 | if (changed) {
203 | int width = right-left;
204 | int height = bottom-top;
205 | mBorderRect.set(0, 0, width, height);
206 | calculateBarRect();
207 | }
208 | }
209 |
210 | }
211 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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