安卓调用ffmpeg
2015-10-14 13:45
555 查看
ffmpeg是个linux下很受欢迎的解码库,可惜对于安卓而言他并不是最好的,这里介绍了如何在安卓中使用
1.之前在ubuntu编译安装ffmpeg,试了下,感觉不错,ffmpeg的编译也是十分简单的,推荐在ubuntu中编译,我是在虚拟机编译后直接拿过来在win7使用的(这是由于笔记的配置较低,在虚拟机跑eclise等调试比较耗内存)
2.现在我们构建ndk的头文件和源文件
编写Java需要用的native函数
接着使用javah生成头文件,具体的步骤已经之前记录在博客里了
编写Android.mk和Application.mk,Application.mk不是必要的,只是我们在ndk使用C++时可能会出现检查错误
Android.mk
Application.mk
为了方便我编写了一个直接调用java函数的代码,用于直接输出log,当然还有LOGI
接着编译
测试
1.之前在ubuntu编译安装ffmpeg,试了下,感觉不错,ffmpeg的编译也是十分简单的,推荐在ubuntu中编译,我是在虚拟机编译后直接拿过来在win7使用的(这是由于笔记的配置较低,在虚拟机跑eclise等调试比较耗内存)
2.现在我们构建ndk的头文件和源文件
编写Java需要用的native函数
package com.zhku.demo2; import android.os.Bundle; import android.os.Environment; import android.support.v4.app.Fragment; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .add(R.id.container, new PlaceholderFragment()).commit(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } /** * A placeholder fragment containing a simple view. */ public static class PlaceholderFragment extends Fragment { private Button stop, pauseOrPlay, start; public PlaceholderFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container,false); pauseOrPlay = (Button) rootView.findViewById(R.id.PauseOrPlay); stop = (Button) rootView.findViewById(R.id.Stop); start = (Button) rootView.findViewById(R.id.Start); start.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { nativeInit(); String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/galleon.avi"; VideoPlayer(path); } }); pauseOrPlay.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub VideoPlayerPauseOrPlay(); } }); stop.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub VideoPlayerStop(); } }); nativeInit(); return rootView; } /** * * @param message */ private void onNativeMessage(final String message) { Log.i(MainActivity.class.toString(), "-->>" + message); } /** * * @param fileName * @return */ private native int VideoPlayer(String fileName); /** * * @return */ private native int VideoPlayerPauseOrPlay(); /** * Initializes the native code. */ private native void nativeInit(); /** * */ private native void VideoPlayerStop(); static { System.loadLibrary("avutil-54"); System.loadLibrary("swresample-1"); System.loadLibrary("avcodec-56"); System.loadLibrary("swscale-3"); System.loadLibrary("avformat-56"); System.loadLibrary("ffmpeg1"); } } }
接着使用javah生成头文件,具体的步骤已经之前记录在博客里了
编写Android.mk和Application.mk,Application.mk不是必要的,只是我们在ndk使用C++时可能会出现检查错误
Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ffmpeg1 LOCAL_SRC_FILES := com_zhku_demo2_MainActivity.cpp \ com_zhku_demo2_MainActivity_PlaceholderFragment.cpp LOCAL_LDLIBS := -llog -ljnigraphics -lz -landroid LOCAL_SHARED_LIBRARIES := libavformat libavcodec libswscale libavutil libwsresample include $(BUILD_SHARED_LIBRARY) $(call import-module,ffmpeg-2.8/android/arm)
Application.mk
APP_CFLAGS += -Wno-error=format-security
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <android/log.h> extern "C" { #include <libavutil/avutil.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> } /* Header for class com_zhku_demo2_MainActivity_PlaceholderFragment */ #ifndef _Included_com_zhku_demo2_MainActivity_PlaceholderFragment #define _Included_com_zhku_demo2_MainActivity_PlaceholderFragment #ifdef __cplusplus extern "C" { #endif #undef com_zhku_demo2_MainActivity_PlaceholderFragment_INITIALIZING #define com_zhku_demo2_MainActivity_PlaceholderFragment_INITIALIZING 0L #undef com_zhku_demo2_MainActivity_PlaceholderFragment_CREATED #define com_zhku_demo2_MainActivity_PlaceholderFragment_CREATED 1L #undef com_zhku_demo2_MainActivity_PlaceholderFragment_ACTIVITY_CREATED #define com_zhku_demo2_MainActivity_PlaceholderFragment_ACTIVITY_CREATED 2L #undef com_zhku_demo2_MainActivity_PlaceholderFragment_STOPPED #define com_zhku_demo2_MainActivity_PlaceholderFragment_STOPPED 3L #undef com_zhku_demo2_MainActivity_PlaceholderFragment_STARTED #define com_zhku_demo2_MainActivity_PlaceholderFragment_STARTED 4L #undef com_zhku_demo2_MainActivity_PlaceholderFragment_RESUMED #define com_zhku_demo2_MainActivity_PlaceholderFragment_RESUMED 5L #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "graduation", __VA_ARGS__)) AVFormatContext *pFormatCtx = NULL; int audioStream, delay_time, videoFlag = 0; AVCodecContext *aCodecCtx; AVCodec *aCodec; AVFrame *aFrame; AVPacket packet; int frameFinished = 0; int err_code; static jmethodID gOnNativeMessage = NULL; char msg[1024]; void LogMessageFromAndroid(JNIEnv*,const char *,jobject); /* * Class: com_zhku_demo2_MainActivity_PlaceholderFragment * Method: VideoPlayer * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_zhku_demo2_MainActivity_00024PlaceholderFragment_VideoPlayer (JNIEnv *, jobject, jstring); /* * Class: com_zhku_demo2_MainActivity_PlaceholderFragment * Method: VideoPlayerPauseOrPlay * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_zhku_demo2_MainActivity_00024PlaceholderFragment_VideoPlayerPauseOrPlay (JNIEnv *, jobject); /* * Class: com_zhku_demo2_MainActivity_PlaceholderFragment * Method: VideoPlayerStop * Signature: ()V */ JNIEXPORT void JNICALL Java_com_zhku_demo2_MainActivity_00024PlaceholderFragment_VideoPlayerStop (JNIEnv *, jobject); /* * Class: com_zhku_demo2_MainActivity_PlaceholderFragment * Method: nativeInit * Signature: ()V */ JNIEXPORT void JNICALL Java_com_zhku_demo2_MainActivity_00024PlaceholderFragment_nativeInit (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
#include "com_zhku_demo2_MainActivity_PlaceholderFragment.h" /* * Class: com_zhku_demo2_MainActivity_PlaceholderFragment * Method: nativeInit * Signature: ()V */ JNIEXPORT void JNICALL Java_com_zhku_demo2_MainActivity_00024PlaceholderFragment_nativeInit (JNIEnv *env, jobject obj) { if (NULL == gOnNativeMessage) { // Get the class from the object jclass clazz = env->GetObjectClass(obj); // Get the method id for the callback gOnNativeMessage = env->GetMethodID(clazz,"onNativeMessage","(Ljava/lang/String;)V"); // If method could not be found if (NULL == gOnNativeMessage) { // Get the exception class jclass exceptionClazz = env->FindClass("java/lang/RuntimeException"); // Throw exception env->ThrowNew(exceptionClazz, "Unable to find method"); } } LogMessageFromAndroid(env,"nativeInit finish",obj); } /** * Method: LogMessageFromAndroid * Signature: VOID * */ void LogMessageFromAndroid(JNIEnv *env,const char *format,jobject obj) { if(NULL != gOnNativeMessage) { // Prepare message char message[26]; sprintf(message, format); // Message from the C string jstring messageString = env->NewStringUTF(message); // Call the on native message method env->CallVoidMethod(obj, gOnNativeMessage, messageString); } } /* * Class: com_zhku_demo2_MainActivity_PlaceholderFragment * Method: VideoPlayer * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_zhku_demo2_MainActivity_00024PlaceholderFragment_VideoPlayer (JNIEnv *env, jobject obj, jstring str) { const char* fileName = env->GetStringUTFChars(str, NULL); av_register_all(); //LogMessageFromAndroid(env,fileName,obj); if((err_code = avformat_open_input(&pFormatCtx, "/storage/sdcard0/sample.mov",NULL, NULL)) != 0) { // 在安卓中经常出现无法打开文件的情况,所以可以使用 // av_strerror打印日志 av_strerror(err_code, msg, 1024); jclass exceptionClazz = env->FindClass("java/lang/RuntimeException"); env->ThrowNew(exceptionClazz, msg); return -1; } LogMessageFromAndroid(env,"VideoPlayer",obj); if(avformat_find_stream_info(pFormatCtx, NULL) < 0) { jclass exceptionClazz = env->FindClass("java/lang/RuntimeException"); env->ThrowNew(exceptionClazz, "Unable to avformat_find_stream_info"); return -1; } av_dump_format(pFormatCtx, -1, fileName, 0); int i = 0; for(i=0; i< pFormatCtx->nb_streams; i++) { if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){ audioStream = i; break; } } if(audioStream < 0)return -1; aCodecCtx = pFormatCtx->streams[audioStream]->codec; aCodec = avcodec_find_decoder(aCodecCtx->codec_id); if(avcodec_open2(aCodecCtx, aCodec, NULL) < 0)return -1; aFrame = avcodec_alloc_frame(); if(aFrame == NULL)return -1; int ret; while(videoFlag != -1) { if(av_read_frame(pFormatCtx, &packet) < 0)break; if(packet.stream_index == audioStream) { ret = avcodec_decode_audio4(aCodecCtx, aFrame, &frameFinished, &packet); if(ret > 0 && frameFinished) { int data_size = av_samples_get_buffer_size( aFrame->linesize,aCodecCtx->channels, aFrame->nb_samples,aCodecCtx->sample_fmt, 0); LOGI("audioDecodec :%d",data_size); } } usleep(50000); while(videoFlag != 0) { if(videoFlag == 1)//暂停 { sleep(1); }else if(videoFlag == -1) //停止 { break; } } av_free_packet(&packet); } av_free(aFrame); avcodec_close(aCodecCtx); avformat_close_input(&pFormatCtx); env->ReleaseStringUTFChars(str, fileName); } /* * Class: com_zhku_demo2_MainActivity_PlaceholderFragment * Method: VideoPlayerPauseOrPlay * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_zhku_demo2_MainActivity_00024PlaceholderFragment_VideoPlayerPauseOrPlay (JNIEnv *, jobject) { if(videoFlag == 1) { videoFlag = 0; }else if(videoFlag == 0) { videoFlag = 1; } return videoFlag; } /* * Class: com_zhku_demo2_MainActivity_PlaceholderFragment * Method: VideoPlayerStop * Signature: ()V */ JNIEXPORT void JNICALL Java_com_zhku_demo2_MainActivity_00024PlaceholderFragment_VideoPlayerStop (JNIEnv *, jobject) { videoFlag = -1; }
为了方便我编写了一个直接调用java函数的代码,用于直接输出log,当然还有LOGI
接着编译
F:\develop\android\adt-bundle-windows-x86-20140321\workspace\JNI\Demo2\jni>ndk-build APP_PLATFORM=android-9 [armeabi] Compile++ thumb: ffmpeg1 <= com_zhku_demo2_MainActivity_PlaceholderFragment.cpp F:/develop/android/adt-bundle-windows-x86-20140321/workspace/JNI/Demo2//jni/com_zhku_demo2_MainActivity_PlaceholderFragm ent.cpp: In function 'void LogMessageFromAndroid(JNIEnv*, char const*, jobject)': F:/develop/android/adt-bundle-windows-x86-20140321/workspace/JNI/Demo2//jni/com_zhku_demo2_MainActivity_PlaceholderFragm ent.cpp:39:30: warning: format not a string literal and no format arguments [-Wformat-security] F:/develop/android/adt-bundle-windows-x86-20140321/workspace/JNI/Demo2//jni/com_zhku_demo2_MainActivity_PlaceholderFragm ent.cpp: In function 'jint Java_com_zhku_demo2_MainActivity_00024PlaceholderFragment_VideoPlayer(JNIEnv*, jobject, jstri ng)': F:/develop/android/adt-bundle-windows-x86-20140321/workspace/JNI/Demo2//jni/com_zhku_demo2_MainActivity_PlaceholderFragm ent.cpp:89:14: warning: 'AVFrame* avcodec_alloc_frame()' is deprecated (declared at D:/ProgramFiles/android-ndk-r10/sour ces/ffmpeg-2.8/android/arm/include/libavcodec/avcodec.h:3927) [-Wdeprecated-declarations] F:/develop/android/adt-bundle-windows-x86-20140321/workspace/JNI/Demo2//jni/com_zhku_demo2_MainActivity_PlaceholderFragm ent.cpp:89:34: warning: 'AVFrame* avcodec_alloc_frame()' is deprecated (declared at D:/ProgramFiles/android-ndk-r10/sour ces/ffmpeg-2.8/android/arm/include/libavcodec/avcodec.h:3927) [-Wdeprecated-declarations] [armeabi] SharedLibrary : libffmpeg1.so [armeabi] Install : libffmpeg1.so => libs/armeabi/libffmpeg1.so [armeabi] Install : libavformat-56.so => libs/armeabi/libavformat-56.so [armeabi] Install : libavcodec-56.so => libs/armeabi/libavcodec-56.so [armeabi] Install : libswscale-3.so => libs/armeabi/libswscale-3.so [armeabi] Install : libavutil-54.so => libs/armeabi/libavutil-54.so [armeabi] Install : libswresample-1.so => libs/armeabi/libswresample-1.so F:\develop\android\adt-bundle-windows-x86-20140321\workspace\JNI\Demo2\jni>
测试
相关文章推荐
- Ubuntu apache配置虚拟路由
- (转)项目适配iOS9遇到的一些问题及解决办法
- Bandwidth Test
- 自定义Dialog 以加载进度为例
- 自己编写Makefile
- 什么?MindManager粘贴出错点这里
- 《架构之美》这本书的翻译版就是彻头彻尾的垃圾
- MFC框架各部分指针获取方式
- centos6.5下安装redmine或迁移
- Linux下PCIe驱动以及DMA机制
- JS学习之作用域
- UVa11987 Almost Union-Find
- centos7安装jdk1.7(rpm)
- jPlayer
- I.MX6 eMMC 中启动U-boot存放的首地址
- Java线程同步中关键字synchronized简述
- cannot set user id: Resource temporarily unavailable
- OpenCV的智能指针: Ptr
- 字符串匹配和汉字长度算法
- android 反编译与再编译