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

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

  

CC    libavcodec/log2_tab.o
CC libavutil/log2_tab.o
CC libswresample/log2_tab.o
AR libavcodec/libavcodec.a
LD libavutil/libavutil.so.
AR libavutil/libavutil.a
AR libswresample/libswresample.a
LD libavcodec/libavcodec.so.
LD libswresample/libswresample.so.
LD libswscale/libswscale.so.
LD libavformat/libavformat.so.
INSTALL libavformat/libavformat.a
INSTALL libavformat/libavformat.so
STRIP install-libavformat-shared
INSTALL libavcodec/libavcodec.a
INSTALL libavcodec/libavcodec.so
STRIP install-libavcodec-shared
INSTALL libswresample/libswresample.a
INSTALL libswresample/libswresample.so
STRIP install-libswresample-shared
INSTALL libswscale/libswscale.a
INSTALL libswscale/libswscale.so
STRIP install-libswscale-shared
INSTALL libavutil/libavutil.a
INSTALL libavutil/libavutil.so
STRIP install-libavutil-shared
INSTALL libavformat/avformat.h
INSTALL libavformat/avio.h
INSTALL libavformat/version.h
INSTALL libavformat/libavformat.pc
INSTALL libavcodec/avcodec.h
INSTALL libavcodec/avfft.h
INSTALL libavcodec/dxva2.h
INSTALL libavcodec/old_codec_ids.h
INSTALL libavcodec/vaapi.h
INSTALL libavcodec/vda.h
INSTALL libavcodec/vdpau.h
INSTALL libavcodec/version.h
INSTALL libavcodec/xvmc.h
INSTALL libavcodec/libavcodec.pc
INSTALL libswresample/swresample.h
INSTALL libswresample/version.h
INSTALL libswresample/libswresample.pc
INSTALL libswscale/swscale.h
INSTALL libswscale/version.h
INSTALL libswscale/libswscale.pc
INSTALL libavutil/adler32.h
INSTALL libavutil/aes.h
INSTALL libavutil/attributes.h
INSTALL libavutil/audio_fifo.h
INSTALL libavutil/audioconvert.h
INSTALL libavutil/avassert.h
INSTALL libavutil/avstring.h
INSTALL libavutil/avutil.h
INSTALL libavutil/base64.h
INSTALL libavutil/blowfish.h
INSTALL libavutil/bprint.h
INSTALL libavutil/bswap.h
INSTALL libavutil/buffer.h
INSTALL libavutil/channel_layout.h
INSTALL libavutil/common.h
INSTALL libavutil/cpu.h
INSTALL libavutil/crc.h
INSTALL libavutil/error.h
INSTALL libavutil/eval.h
INSTALL libavutil/fifo.h
INSTALL libavutil/file.h
INSTALL libavutil/frame.h
INSTALL libavutil/hmac.h
INSTALL libavutil/imgutils.h
INSTALL libavutil/intfloat.h
INSTALL libavutil/intfloat_readwrite.h
INSTALL libavutil/intreadwrite.h
INSTALL libavutil/lfg.h
INSTALL libavutil/log.h
INSTALL libavutil/mathematics.h
INSTALL libavutil/md5.h
INSTALL libavutil/mem.h
INSTALL libavutil/murmur3.h
INSTALL libavutil/dict.h
INSTALL libavutil/old_pix_fmts.h
INSTALL libavutil/opt.h
INSTALL libavutil/parseutils.h
INSTALL libavutil/pixdesc.h
INSTALL libavutil/pixfmt.h
INSTALL libavutil/random_seed.h
INSTALL libavutil/rational.h
INSTALL libavutil/ripemd.h
INSTALL libavutil/samplefmt.h
INSTALL libavutil/sha.h
INSTALL libavutil/sha512.h
INSTALL libavutil/time.h
INSTALL libavutil/timecode.h
INSTALL libavutil/timestamp.h
INSTALL libavutil/version.h
INSTALL libavutil/xtea.h
INSTALL libavutil/lzo.h
INSTALL libavutil/avconfig.h
INSTALL 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 := ffmpeg
LOCAL_SRC_FILES := /path/to/build/output/libffmpeg.so
include $(PREBUILT_SHARED_LIBRARY)

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

Application.mk

APP_ABI := armeabi
APP_PLATFORM := android-
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) < ) {
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[])));
} JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
jint result = -; 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 > ) {
pStr = (char*) malloc(strLen + ); if (!pStr) {
return NULL ;
} memcpy(pStr, jBuf, strLen); pStr[strLen] = ;
} (*env)->ReleaseByteArrayElements(env, byteArray, jBuf, ); 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) != ) {
LOGE("can't open the file. \n");
return;
} if (avformat_find_stream_info(pFormatCtx, NULL) < ) {
LOGE("Could't find stream infomation.\n");
return;
} videoStream = ;
for (i = ; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
}
} if (videoStream == -) {
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) < ) {
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, , file_path, ); while (av_read_frame(pFormatCtx, packet) >= ) {
if (packet->stream_index == videoStream) {
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,
packet); LOGI("avcodec_decode_video2 ret:%d", ret); if (ret < ) {
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 := ../ffmpeg
LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(FFMPEG_PATH)/include LOCAL_MODULE := ffmpeg_player
LOCAL_SRC_FILES += ffmpeg_jni.c
LOCAL_SRC_FILES += ffmpeg.c LOCAL_SHARED_LIBRARIES := ffmpeg
LOCAL_LDLIBS := -llog include $(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. [原]如何在Android用FFmpeg+SDL2.0解码显示图像

    如何在Android上使用FFmpeg解码图像参考文章[原]如何在Android用FFmpeg解码图像 ,如何在Android上使用SDL2.0来显示图像参考[原]零基础学习SDL开发之在Androi ...

  2. [原]如何在Android用FFmpeg+SDL2.0解码图像线程

    关于如何在Android上用FFmpeg+SDL2.0解码显示图像参考[原]如何在Android用FFmpeg+SDL2.0解码显示图像 ,关于如何在Android使用FFmpeg+SDL2.0解码声 ...

  3. [原]如何在Android用FFmpeg+SDL2.0解码声音

    关于如何在Android上用FFmpeg+SDL2.0解码显示图像参考[原]如何在Android用FFmpeg+SDL2.0解码显示图像 ,本文是基于上述文章和[原]零基础学习视频解码之解码声音 来移 ...

  4. [原]如何在Android用FFmpeg+SDL2.0之同步音频

    同步音频的原理可以参考:http://dranger.com/ffmpeg/tutorial05.html  本文是在 [原]如何在Android用FFmpeg+SDL2.0之同步视频 的基础上面继续 ...

  5. [原]如何在Android用FFmpeg+SDL2.0之同步视频

    关于视频同步的原理可以参考http://dranger.com/ffmpeg/tutorial05.html 和 [原]基础学习视频解码之同步视频 这两篇文章,本文是在这两篇的基础上移植到了Andro ...

  6. Android开发之《ffmpeg解码mjpeg视频流》

    MJPEG格式和码流分析,MJPEG格式的一些简介 FFmpeg解码USB摄像头MJPEG输出:http://blog.csdn.net/light_in_dark/article/details/5 ...

  7. 最新FFMPEG解码流程

    FFMPEG解码流程: 1. 注册所有容器格式和CODEC:  av_register_all() 2. 打开文件:                    av_open_input_file() 3 ...

  8. MediaCodec在Android视频硬解码组件的应用

    https://yq.aliyun.com/articles/632892 云栖社区> 博客列表> 正文 MediaCodec在Android视频硬解码组件的应用   cheenc 201 ...

  9. FFmpeg开发笔记(四):ffmpeg解码的基本流程详解

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

随机推荐

  1. C#与数据库访问技术总结(六)之Command对象创建SQl语句代码示例

    Command对象创建SQl语句代码示例 说明:前面介绍了 Command 对象的方法和一些属性,回顾一下 Command对象主要用来执行SQL语句.利用Command对象,可以查询数据和修改数据. ...

  2. 简单理解ECMAScript2015中的Promise

    ECMAScript6中新增了Promise对象, 所谓Promise对象,即代表着一个还未完成,但将来某时会完成的操作(通常是异步操作).使用Promise对象,我们就可以避免陷入函数层层嵌套的‘回 ...

  3. C语言实现二叉树-利用二叉树统计单词数目

    昨天刚参加了腾讯2015年在线模拟考: 四道大题的第一题就是单词统计程序的设计思想: 为了记住这一天,我打算今天通过代码实现一下: 我将用到的核心数据结构是二叉树: (要是想了解简单二叉树的实现,可以 ...

  4. js围绕屏幕转圈的方块

    点击运动按钮后,方块会挨着浏览器的边,从左到右,从上到下转一圈. 这个我居然写了几天,我也是不想说什么咯. 完成代码一: <!-- Author: XiaoWen Create a file: ...

  5. paip.函数式编程方法概述以及总结

    paip.函数式编程方法概述以及总结 1     函数式编程:函数式风格..很多命令式语言里支持函数式编程风格 1.1      起源 (图灵机,Lisp机器, 神经网络计算机) 1.2      函 ...

  6. JNI技术基础(2)——从零开始编写JNI代码

    书接上文: <JNI技术基础(1)——从零开始编写JNI代码> 2.编译源程序HelloWorld.java并生成HelloWorld.class 3.生成头文件HelloWorld.h ...

  7. Liferay7 BPM门户开发之29: 核心kernel.util包下面的通用帮助类ParamUtil、GetterUtil使用

    与其闭门造车,不如直接开动原装.进口.免费的法拉利. -- 作者说 不多说废话,直接上代码. ParamUtil ParamUtil.GetterUtil是Liferay最重要的帮助类 ParamUt ...

  8. DES加密 java与.net可以相互加密解密的方法

    我.net程序员.今天和java的童鞋交互,单点登录的操作.采用了如下的加密和解密的方式.经过验证,完美结合.通过这个方法可以实现java和C#相互加密与解密 并能保持解密出来一致. 废话少说,上代码 ...

  9. Linux Buffers和Cached的区别(转)

    在linux下使用free命令查看内存使用情况,有buffers和cached两项,以下是它们的区别: buffers是为块设备设计的缓冲.比如磁盘读写,把分散的写操作集中进行,减少磁盘I/O,从而提 ...

  10. 【高德地图API】如何设置Marker的offset?

    一些朋友在往地图上添加标注的时候,往往会发现,图片的尖尖角对不上具体的点.比如,我要在上海东方明珠上扎一个点. 首先,我使用取点工具http://lbs.amap.com/console/show/p ...