您的位置:首页 > 其它

安卓调用ffmpeg

2015-10-14 13:45 555 查看
ffmpeg是个linux下很受欢迎的解码库,可惜对于安卓而言他并不是最好的,这里介绍了如何在安卓中使用

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>


测试



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: