<작업환경> -윈도우10 -안드로이드 스튜디오 2.3.3 -필요 라이브러리 빌드된 ffmpeg 라이브러리 (ffmpeg 빌드하기 : http://gamdekong.tistory.com/103?category=776642 ) |
1. 안드로이드 프로젝트 생성
Android 에서 Project로 변경
2. NDK 설치
FIle -> Setting
설치되는 공간은 안드로이드 스튜디오가 설치된 폴더 안에 생성된다.
3. External Tools Setting
File -> Setting
external tools 셋팅창에서 +를 눌러 아래와 같이 추가한다.
ndk-build
- program 의 경로는 설치된 안드로이드 스튜디오에 있다.( ndk가 설치된곳)
- insert macro를 누르면 환경변수에 대한 설명이 나온다.
ndk-build clean
-clean만 추가시켜 준다.
javah
-javah 파일은 jdk가 설치된 곳에 있다.
-간혹 parameters가 문제가 될수 있는데 여기서 중요한것은 -classpath 옵션은 클래스가 있는 위치를 설정하는것이다.
-jni -classpath "$ProjectFileDir$/app/src/main/java/;$Classpath$" -v $FileClass$ 로 변경
$FileClass$ 는 패키지를 포함한 클래스 위치를 나타내는것으로 알고있다.
4. NDK Sample 작성
$Project/app/src/main/jni 디렉토리를 만들어 줍니다.
( javah를 이용하여 헤더를 만들어 넣을 폴더입니다. javah tools 에서 워킹 디렉토리의 대상이 됩니다.)
NDK.java 를 다음 내용으로 만듭니다.
- sample-ffmpeg 는 다음에 만들 c파일의 라이브러리 이름이 된다.
NDK 클래스에서 오른쪽 버튼을 누르고 javah를 클리하여 헤더파일을 만든다.
헤더파일이 만들어진것을 확인할 수 있다.
NDK클래스에 선언된 native 함수를 자동적으로 헤더파일에 추가해준다.
JNIEXPORT jint JNICALL Java_company_co_kr_ffmpegndk_NDK_scanning(JNIEnv *, jobject, jstring);
기본적으로
녹색 : 패키지명
적색 : 클래스명
청색 : 함수명
JNI문법은 따로 공부하자
5. ffmpeg 라이브러리 설정하기
기본적으로 미리 빌드된 ffmpeg 라이브러리는 포스팅 하기 편하게 프로젝트 폴더안에 넣었다.
이 라이브러리는 프로젝트 밖에 있어도 상관없다. 이 라이브러리를 이용해 so파일을 만들기 때문에
경로만 알고 있으면 된다.
여기서는 편하게 app/libs에 넣었다.
5-1 Android.mk 파일을 만들어 준다.
Android.mk 내용
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE:= libavcodec LOCAL_SRC_FILES:= lib/libavcodec-57.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE:= libavformat LOCAL_SRC_FILES:= lib/libavformat-57.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE:= libswscale LOCAL_SRC_FILES:= lib/libswscale-4.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE:= libavutil LOCAL_SRC_FILES:= lib/libavutil-55.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE:= libavfilter LOCAL_SRC_FILES:= lib/libavfilter-6.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE:= libswresample LOCAL_SRC_FILES:= lib/libswresample-2.so LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include include $(PREBUILT_SHARED_LIBRARY) | cs |
위와 같이 파일 생성후 내용을 입력해준다.
간단하게
LOCAL_PATH:= $(call my-dir) //LOCAL_PATH 에 현재 Android.mk파일이 있는 위치를 저장
include $(CLEAR_VARS) // 변수 초기화
LOCAL_MODULE:= libavcodec // 라이브러리 이름설정
LOCAL_SRC_FILES:= lib/libavcodec-57.so //소스파일 경로설정
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include // include 경로 설정
PREBUILT_SHARED_LIBRARY // 미리 만들어진 공유 라이브러리
더 공부를 위해서 Android.mk 내용 https://developer.android.com/ndk/guides/android_mk.html?hl=ko 참조한다.
5-2 $Project/app/build.gradle 에 추가.
여기서 src/main/libs안에 .so 파일이 떨어지고
src/main/libs 안에 있는 라이브러리를 가지고 apk파일을 생성한다.
경로는 수정 가능하다.
그리고 gradle 파일 수정후에는 항상 sync gradle을 해주자
5-3 $Project/app/src/main/jni/에 Android.mk 를 다음 내용으로 만들자
Android.mk 내용
1 2 3 4 5 6 7 8 9 | LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := sample-ffmpeg LOCAL_SRC_FILES := sample-ffmpeg.c LOCAL_LDLIBS := -llog LOCAL_SHARED_LIBRARIES := libavformat libavcodec libswscale libavutil libswresample libavfilter include $(BUILD_SHARED_LIBRARY) $(call import-add-path, D:\AndroidSample\FFmpegTest3\app) $(call import-module, libs) | cs |
여기서 주위점은
$(call import-module, libs) 에서 기존에 있는 라이브러리의 경로를 지정하는 것이다.
그런데 이 경로의 기준은 $NDK_MODULE_PATH 이다 기존에 ndk가 설치된 위치를 가르킨다.
그렇기 때문에 다른곳이 있다면 따로 추가를 해줘야한다.
$(call import-add-path, D:\AndroidSample\FFmpegTest3\app) 를 이용하여 프로젝트의 app폴더의 위치를 추가한다.
LOCAL_LDLIBS := -llog //NDK에서 제공하는 라이브러리
참조는 https://developer.android.com/ndk/guides/stable_apis.html?hl=ko
LOCAL_SHARED_LIBRARIES //공유라이브러리들의 이름을 적는다.
5-4 $Project/app/src/main/jni/에 Application.mk 만든다
Application.mk 내용
1 | APP_ABI=armeabi-v7a | cs |
5-5 JNI 작성
$Project/app/src/main/jni/에 sample-ffmpeg.c 를 만든다
sample-ffmpeg.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 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 | #include <jni.h> #include "libavformat/avformat.h" #include <android/log.h> #define LOG_TAG "FFmpegForAndroid" #define LOGI(...) __android_log_print(4, LOG_TAG, __VA_ARGS__); #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "libnav", __VA_ARGS__) #define LOGE(...) __android_log_print(6, LOG_TAG, __VA_ARGS__); JNIEXPORT jint JNICALL Java_company_co_kr_ffmpegndk_NDK_scanning(JNIEnv *env, jobject object, jstring filepath) { const char* nativeFilepath = (*env)->GetStringUTFChars( env, filepath , NULL ) ; //const char* nativeFilepath = "/storage/9016-4EF8/aaa.mkv"; AVFormatContext* avFormatContext = NULL; // muxer, demuxer, decoder, encoder 초기화 av_register_all(); // nativeFilepath로 avFormatContext 가져오기 if(avformat_open_input(&avFormatContext, nativeFilepath, NULL, NULL) < 0) { LOGE("Can't open input file '%s'", nativeFilepath); (*env)->ReleaseStringUTFChars(env, filepath, nativeFilepath); return -1; } // 유효한 스트림 정보 찾기 if(avformat_find_stream_info(avFormatContext, NULL) < 0) { LOGE("Failed to retrieve input stream information"); (*env)->ReleaseStringUTFChars(env, filepath, nativeFilepath); return -2; } // avFormatContext->nb_streams : 비디오 파일의 전체 스트림 수 for(unsigned int index = 0; index < avFormatContext->nb_streams; index++) { AVCodecParameters* avCodecParameters = avFormatContext->streams[index]->codecpar; if(avCodecParameters->codec_type == AVMEDIA_TYPE_VIDEO) { LOGI("------- Video info -------"); LOGI("codec_id : %d", avCodecParameters->codec_id); LOGI("bitrate : %lld", avCodecParameters->bit_rate); LOGI("width : %d / height : %d", avCodecParameters->width, avCodecParameters->height); } else if(avCodecParameters->codec_type == AVMEDIA_TYPE_AUDIO) { LOGI("------- Audio info -------"); LOGI("codec_id : %d", avCodecParameters->codec_id); LOGI("bitrate : %lld", avCodecParameters->bit_rate); LOGI("sample_rate : %d", avCodecParameters->sample_rate); LOGI("number of channels : %d", avCodecParameters->channels); } } // release if(avFormatContext != NULL) { avformat_close_input(&avFormatContext); } // release (*env)->ReleaseStringUTFChars(env, filepath, nativeFilepath); return 0; } | cs |
scanning 라는 JNI function 을 제작했으며, 넘겨진 영상파일 경로를 받아, 해당 영상정보를 로그로 출력한다.
5-6 JNI 컴파일
오른쪽 버튼을 눌러 ndk-build를 클릭하자
정상적으로 실행되었다면 libs 폴더에 라이브러리 파일이 생성된것을 확인할 수 있다.
6. AndroidManifest.xml 수정
AndroidManifest.xml 에 퍼미션 부분을 추가한다.
외장 저장 공간을 사용하기 위해서는 허가가 필요하다.
Android 6.0(마시멜로) 이상에서는 추가된 Runtime Permission 을 추가하여야 한다.
참고 사이트 : https://developer.android.com/training/permissions/requesting.html?hl=ko
7. MainActivity 수정
다음과 같이 수정한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | package company.co.kr.ffmpegndk; import android.os.Bundle; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.util.Log; import java.io.File; import java.io.IOException; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String filepath; try { filepath = new File(Environment.getExternalStorageDirectory(), "/sample-video.mp4").getCanonicalPath(); new NDK().scanning(filepath); } catch (IOException e) { Log.e("FFmpegForAndroid", "", e); } } } | cs |
8. App 실행
App을 실행해 본다
정상적이라면 아래와 비슷한 로그가 LogCat 에 출력된다.
1 2 3 4 5 6 7 8 9 10 | I/FFmpegForAndroid: ------- Video info ------- I/FFmpegForAndroid: codec_id : 28 I/FFmpegForAndroid: bitrate : 816549 I/FFmpegForAndroid: width : 640 / height : 640 I/FFmpegForAndroid: ------- Audio info ------- I/FFmpegForAndroid: codec_id : 86018 I/FFmpegForAndroid: bitrate : 126711 I/FFmpegForAndroid: sample_rate : 48000 I/FFmpegForAndroid: number of channels : 2 | cs |
9. 주의점
절대로 주위해야 할것은 오타이다.
나는 이 오타때문에 하루를 날렸다....
특히 언더바( _ ) 와 데쉬 ( - ) 구별을 잘하자!!!
참고사이트
http://whiteduck.tistory.com/130
'안드로이드 > ffmpeg' 카테고리의 다른 글
안드로이드에서 CMake를 이용하여 ffmpeg 라이브러리 사용하기(NDK) (0) | 2017.11.15 |
---|---|
ffmpeg for android 빌드 (2) | 2017.11.09 |