前一篇[原]如何用Android NDK编译FFmpeg我们知道了如何使用NDK来编译Android平台下使用的FFmpeg动态库。这篇文章我们就可以使用Android下的JNI来调用FFMpeg进行解码了。

一、编译出来可以使用的动态库,我们会看到如下输出则表示link完成了:

  

CC    libavcodec/log2_tab.oCC    libavutil/log2_tab.oCC    libswresample/log2_tab.oAR    libavcodec/libavcodec.aLD    libavutil/libavutil.so.52AR    libavutil/libavutil.aAR    libswresample/libswresample.aLD    libavcodec/libavcodec.so.55LD    libswresample/libswresample.so.0LD    libswscale/libswscale.so.2LD    libavformat/libavformat.so.55INSTALL    libavformat/libavformat.aINSTALL    libavformat/libavformat.soSTRIP    install-libavformat-sharedINSTALL    libavcodec/libavcodec.aINSTALL    libavcodec/libavcodec.soSTRIP    install-libavcodec-sharedINSTALL    libswresample/libswresample.aINSTALL    libswresample/libswresample.soSTRIP    install-libswresample-sharedINSTALL    libswscale/libswscale.aINSTALL    libswscale/libswscale.soSTRIP    install-libswscale-sharedINSTALL    libavutil/libavutil.aINSTALL    libavutil/libavutil.soSTRIP    install-libavutil-sharedINSTALL    libavformat/avformat.hINSTALL    libavformat/avio.hINSTALL    libavformat/version.hINSTALL    libavformat/libavformat.pcINSTALL    libavcodec/avcodec.hINSTALL    libavcodec/avfft.hINSTALL    libavcodec/dxva2.hINSTALL    libavcodec/old_codec_ids.hINSTALL    libavcodec/vaapi.hINSTALL    libavcodec/vda.hINSTALL    libavcodec/vdpau.hINSTALL    libavcodec/version.hINSTALL    libavcodec/xvmc.hINSTALL    libavcodec/libavcodec.pcINSTALL    libswresample/swresample.hINSTALL    libswresample/version.hINSTALL    libswresample/libswresample.pcINSTALL    libswscale/swscale.hINSTALL    libswscale/version.hINSTALL    libswscale/libswscale.pcINSTALL    libavutil/adler32.hINSTALL    libavutil/aes.hINSTALL    libavutil/attributes.hINSTALL    libavutil/audio_fifo.hINSTALL    libavutil/audioconvert.hINSTALL    libavutil/avassert.hINSTALL    libavutil/avstring.hINSTALL    libavutil/avutil.hINSTALL    libavutil/base64.hINSTALL    libavutil/blowfish.hINSTALL    libavutil/bprint.hINSTALL    libavutil/bswap.hINSTALL    libavutil/buffer.hINSTALL    libavutil/channel_layout.hINSTALL    libavutil/common.hINSTALL    libavutil/cpu.hINSTALL    libavutil/crc.hINSTALL    libavutil/error.hINSTALL    libavutil/eval.hINSTALL    libavutil/fifo.hINSTALL    libavutil/file.hINSTALL    libavutil/frame.hINSTALL    libavutil/hmac.hINSTALL    libavutil/imgutils.hINSTALL    libavutil/intfloat.hINSTALL    libavutil/intfloat_readwrite.hINSTALL    libavutil/intreadwrite.hINSTALL    libavutil/lfg.hINSTALL    libavutil/log.hINSTALL    libavutil/mathematics.hINSTALL    libavutil/md5.hINSTALL    libavutil/mem.hINSTALL    libavutil/murmur3.hINSTALL    libavutil/dict.hINSTALL    libavutil/old_pix_fmts.hINSTALL    libavutil/opt.hINSTALL    libavutil/parseutils.hINSTALL    libavutil/pixdesc.hINSTALL    libavutil/pixfmt.hINSTALL    libavutil/random_seed.hINSTALL    libavutil/rational.hINSTALL    libavutil/ripemd.hINSTALL    libavutil/samplefmt.hINSTALL    libavutil/sha.hINSTALL    libavutil/sha512.hINSTALL    libavutil/time.hINSTALL    libavutil/timecode.hINSTALL    libavutil/timestamp.hINSTALL    libavutil/version.hINSTALL    libavutil/xtea.hINSTALL    libavutil/lzo.hINSTALL    libavutil/avconfig.hINSTALL    libavutil/libavutil.pc link ffmpeg.

二、新建一个Android工程,在工程目录下新建一个jni文件夹,在文件夹下新建一个ffmpeg文件夹,用来放ffmpeg相关的头文件。在ffmpeg文件夹下新建Android.mk文件用来预先加载ffmpeg动态库。Android.mk文件内容如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := ffmpegLOCAL_SRC_FILES := /path/to/build/output/libffmpeg.soinclude $(PREBUILT_SHARED_LIBRARY)

三、在jni下新建Android.mk文件和Application.mk两个文件用来指定编译的顺序和编译的平台以及对应的cpu指令集。

Application.mkAPP_ABI := armeabiAPP_PLATFORM := android-9
Android.mk

include $(call all-subdir-makefiles)

四、编写JNI文件,用来绑定java文件与.c文件的交互,文件内容如下:

/* * ffmpeg_jni.c * *  Created on: Sep 1, 2014 *      Author: clarck */#include <stdlib.h>#include <string.h>#include <stdio.h>#include <jni.h>#include "../include/ffmpeg_logger.h"#include "../include/ffmpeg.h"// 指定要注册的类,对应完整的java类名#define JNIREG_CLASS "com/clarck/android/ffmpeg/MainActivity"JNIEXPORT void JNICALL native_setDataSource(JNIEnv *env, jclass classzz, jstring path) {    char *filepath = ffmpeg_jstringTostr(env, path);    ffmpeg_setDataSource(filepath);}//Java和JNI函数的绑定static JNINativeMethod method_table[] = {    { "setDataSource", "(Ljava/lang/String;)V", native_setDataSource }};//注冊native方法到java中static int registerNativeMethods(JNIEnv *env, const char *className,        JNINativeMethod *gMethods, int numMethods) {    jclass clazz;    clazz = (*env)->FindClass(env, className);    if (clazz == NULL) {        return JNI_FALSE;    }    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {        return JNI_FALSE;    }    return JNI_TRUE;}//調用註冊方法int register_ndk_load(JNIEnv *env) {    return registerNativeMethods(env, JNIREG_CLASS, method_table,            (int) (sizeof(method_table) / sizeof(method_table[0])));}JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {    JNIEnv *env = NULL;    jint result = -1;    if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {        return result;    }    register_ndk_load(env);    //返回JNI的版本    return JNI_VERSION_1_6;}

五、编写ffmpeg调用函数,内容如下:

/* * ffmpeg.c * *  Created on: Sep 1, 2014 *      Author: clarck */#include <jni.h>#include <android/native_window_jni.h>#include "../include/ffmpeg.h"#include "../include/ffmpeg_logger.h"#include "../ffmpeg/include/libavcodec/avcodec.h"#include "../ffmpeg/include/libavformat/avformat.h"#include "../ffmpeg/include/libavutil/pixfmt.h"#include "../ffmpeg/include/libswscale/swscale.h"char* ffmpeg_jstringTostr(JNIEnv* env, jstring jstr) {    char* pStr = NULL;    jclass jstrObj = (*env)->FindClass(env, "java/lang/String");    jstring encode = (*env)->NewStringUTF(env, "utf-8");    jmethodID methodId = (*env)->GetMethodID(env, jstrObj, "getBytes",            "(Ljava/lang/String;)[B");    jbyteArray byteArray = (jbyteArray) (*env)->CallObjectMethod(env, jstr,            methodId, encode);    jsize strLen = (*env)->GetArrayLength(env, byteArray);    jbyte *jBuf = (*env)->GetByteArrayElements(env, byteArray, JNI_FALSE);    if (jBuf > 0) {        pStr = (char*) malloc(strLen + 1);        if (!pStr) {            return NULL ;        }        memcpy(pStr, jBuf, strLen);        pStr[strLen] = 0;    }    (*env)->ReleaseByteArrayElements(env, byteArray, jBuf, 0);    return pStr;}void ffmpeg_setDataSource(char *file_path) {    LOGI("ffmpeg_setDataSource:%s", file_path);    AVFormatContext *pFormatCtx;    AVCodecContext *pCodecCtx;    AVCodec *pCodec;    AVFrame *pFrame, *pFrameYUV;    AVPacket *packet;    uint8_t *out_buffer;    static struct SwsContext *img_convert_ctx;    int videoStream, i, numBytes;    int ret, got_picture;    av_register_all();    pFormatCtx = avformat_alloc_context();    if (avformat_open_input(&pFormatCtx, file_path, NULL, NULL) != 0) {        LOGE("can't open the file. \n");        return;    }    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {        LOGE("Could't find stream infomation.\n");        return;    }    videoStream = 1;    for (i = 0; i < pFormatCtx->nb_streams; i++) {        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {            videoStream = i;        }    }    if (videoStream == -1) {        LOGE("Didn't find a video stream.\n");        return;    }    pCodecCtx = pFormatCtx->streams[videoStream]->codec;    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);    if (pCodec == NULL) {        LOGE("Codec not found.\n");        return;    }    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {        LOGE("Could not open codec.\n");        return;    }    pFrame = av_frame_alloc();    pFrameYUV = av_frame_alloc();    numBytes = avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width,            pCodecCtx->height);    out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));    avpicture_fill((AVPicture *) pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P,            pCodecCtx->width, pCodecCtx->height);    int y_size = pCodecCtx->width * pCodecCtx->height;    packet = (AVPacket *) malloc(sizeof(AVPacket));    av_new_packet(packet, y_size);    av_dump_format(pFormatCtx, 0, file_path, 0);    while (av_read_frame(pFormatCtx, packet) >= 0) {        if (packet->stream_index == videoStream) {            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,                    packet);            LOGI("avcodec_decode_video2 ret:%d", ret);            if (ret < 0) {                LOGE("decode error.\n");                return;            }            if (got_picture) {                //TODO 此处可以将解码出来的图片保存起来。            }        }        av_free_packet(packet);    }    av_free(out_buffer);    av_free(pFrameYUV);    avcodec_close(pCodecCtx);    avformat_close_input(&pFormatCtx);}

六、编写Android.mk用来编译相关的.c文件,内容如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)FFMPEG_PATH := ../ffmpegLOCAL_C_INCLUDES := $(LOCAL_PATH)/$(FFMPEG_PATH)/includeLOCAL_MODULE    := ffmpeg_playerLOCAL_SRC_FILES += ffmpeg_jni.c LOCAL_SRC_FILES += ffmpeg.cLOCAL_SHARED_LIBRARIES := ffmpegLOCAL_LDLIBS := -lloginclude $(BUILD_SHARED_LIBRARY)

七、编写java文件中相关执行调用方法

package com.clarck.android.ffmpeg;import android.app.Activity;import android.os.Bundle;public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                setDataSource("/sdcard/a.mp4");    }    public native void setDataSource(String path);        static {        System.loadLibrary("ffmpeg");        System.loadLibrary("ffmpeg_player");    }}

八、执行结果如下图:

[原]如何在Android用FFmpeg解码图像_第1张图片

更多相关文章

  1. Android利用SAX解析XML文件
  2. 【转】Android 虚拟机安装APK文件方法
  3. 新书内容连载(2):Android Activity的生命周期
  4. Android 根文件系统启动过程
  5. Android资源文件简介
  6. android 五大布局文件
  7. AndroidManifest配置文件介绍

随机推荐

  1. android手机端保存xml数据
  2. 线程
  3. Android追加写入文件的几种方法
  4. android中屏幕亮度相关设置
  5. Android(安卓)点击按钮,文本文字改变
  6. Android(安卓)获取XML,DRAWABLE资源
  7. android 指南针
  8. MTK Android(安卓)P(9.0) userdebug版本
  9. Anubis,一个支持Android(安卓)apk(Androi
  10. How to Enable USB Debugging Mode on An