博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[原]如何在Android用FFmpeg解码图像
阅读量:5813 次
发布时间:2019-06-18

本文共 9670 字,大约阅读时间需要 32 分钟。

前一篇 我们知道了如何使用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 
#include
#include
#include
#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 
#include
#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");    }}

八、执行结果如下图:

 

转载地址:http://oivbx.baihongyu.com/

你可能感兴趣的文章
python 异常
查看>>
百度账号注销
查看>>
jquery画图插件jPainter
查看>>
真正努力的人,从来不焦虑
查看>>
Lua语言特色
查看>>
C# 单机Window 程序 sqlite 数据库实现
查看>>
JavaScript一些函数
查看>>
国务院关于积极推进“互联网+”行动的指导意见
查看>>
Matrix Factorization, Algorithms, Applications, and Avaliable packages
查看>>
图像配准转换
查看>>
mysql-This version of MySQL doesn’t yet support ‘LIMIT & IN/ALL/ANY/SOME 错误解决
查看>>
BIEE Demo(RPD创建 + 分析 +仪表盘 )
查看>>
Cocos2dx 3.0开发环境的搭建--Eclipse建立在Android工程
查看>>
iOS人脸识别核心代码(备用)
查看>>
基本概念复习
查看>>
C++:成员运算符重载函数和友元运算符重载函数的比较
查看>>
[Polymer] Introduction
查看>>
【iCore3 双核心板】例程三十:U_DISK_IAP_FPGA实验——更新升级FPGA
查看>>
前端技术的发展和趋势
查看>>
Android文件下载之进度检测
查看>>