美文网首页
NDK--JNI开发

NDK--JNI开发

作者: 佼佼者Mr | 来源:发表于2020-05-10 10:07 被阅读0次

使用JNI与Native code通信

什么事JNI?

JNI是Java native interface的缩写,它提供了若干api实现了Java和其他语言的通信

1.Java代码调用原生方法

2.声明原生方法

3.加载共享库

4.实现原生方法

JNI语法与规范

    数据类型

        JNI系统类型:JNIEnv(线程上下文)

        基本数据类型

        引用类型

        数组

动态库与静态库的区别

1.静态库文件比较大,动态库文件比较小

2.静态库需要在编译时被链接到目标代码中,动态库需要在运行时被链接到代码中

3.静态库类似于Android中的module,一旦打包apk需要重新编译

4.动态库类似与jar包,打包是不需要重新编译的。

选取:静态库体积比较大,但是加载速度快,动态库体积比较小,加载速度慢,想要以时间换空间使用静态库,以空间换时间使用动态库PORT

利用系统源码加载GIF动图

1.将系统源码复制到自己项目中(dgif_lib.c  gif_lib.h gif_lib_private.h gifalloc.c)

2.cmakeLists.txt链接jnigraphics库

target_link_libraries(# Specifies the target library.

        native-lib-parent

child

jnigraphics

        # Links the target library to the log library

# included in the NDK.

        ${log-lib})

3.创建GifNativeDecoder链接native层

4.native_lib.cpp代码

#include "gif_lib.h"

#define  argb(a, r, g, b) ( ((a) &0xff) <<24 ) | ( ((b) &0xff) <<16 ) | ( ((g) &0xff) <<8 ) | ((r) &0xff)

typedef struct GifBean {

//延时,(数组来保存)

    int *delays;

    //记录渲染的当前索引

    int current_frame;

    //总帧数

    int total_frames;

};

void drawFrame(GifFileType *pGifFileType, GifBean *gifBean, AndroidBitmapInfo info, void *pixels);

extern "C"

JNIEXPORT jlong JNICALL Java_com_example_mycmake_GifNativeDecoder_loadGifNative(

JNIEnv *env,

        jclass clazz, jstring gif_path_) {

//    const char *gif_path = env->GetStringUTFChars(gif_path_, 0);

//    int error;

//    //打开GIF文件,获取gifFileType结构体,保存了GIF所有信息

//    GifFileType *pGifFileType = DGifOpenFileName(gif_path, &error);

//    //初始化

//    DGifSlurp(pGifFileType);

////给gifBean分配内存

//    GifBean *gifBean = (GifBean *) malloc(sizeof(gifBean));

////清理内存

//    memset(gifBean, 0, sizeof(gifBean));

//    gifBean->delays = (int *) malloc(sizeof(int) *pGifFileType->ImageCount);

//    memset(gifBean->delays, 0, sizeof(int) *pGifFileType->ImageCount);

//    ExtensionBlock *extensionBlock;

//    //给结构体赋值

//    for (int i = 0; i < pGifFileType->ImageCount; i++) {

//        SavedImage image = pGifFileType->SavedImages[i];

//        for (int j = 0; j < image.ExtensionBlockCount; j++) {

//            if (image.ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE) {

//                //图形拓展块

//                extensionBlock = &image.ExtensionBlocks[j];

//                break;

//            }

//        }

//        if (extensionBlock) {

//            //获取当前帧的图形控制拓展块中的延迟时间(单位1/100秒:10ms)

//            gifBean->delays[i] = (extensionBlock->Bytes[2] << 8 | extensionBlock->Bytes[1]) * 10;

//        }

//        gifBean->total_frames = pGifFileType->ImageCount;

//        pGifFileType->UserData = gifBean;

//

//    }

//    env->ReleaseStringUTFChars(gif_path_, gif_path);

//    return (jlong) (pGifFileType);

    const char *gif_path = env->GetStringUTFChars(gif_path_, 0);

    int error;

    //打开gif文件,获取GifFileType结构体:保存了gif所有信息

    GifFileType *pGifFileType = DGifOpenFileName(gif_path, &error);

    //初始化

    DGifSlurp(pGifFileType);

    //给GifBean分配内存

    GifBean *gifBean = (GifBean *) malloc(sizeof(GifBean));

    //清理内存

    memset(gifBean, 0, sizeof(GifBean));

    //给延时时间数组分配内存

    gifBean->delays = (int *) malloc(sizeof(int) * pGifFileType->ImageCount);

    memset(gifBean->delays, 0, sizeof(int) * pGifFileType->ImageCount);

    //清理内存

    ExtensionBlock *extensionBlock;

    //给结构体赋值

    for (int i =0; i < pGifFileType->ImageCount; i++) {

//取出每一帧图像

        SavedImage frame = pGifFileType->SavedImages[i];

        for (int j =0; j < frame.ExtensionBlockCount; j++) {

if (frame.ExtensionBlocks[j].Function ==GRAPHICS_EXT_FUNC_CODE) {

//图形控制拓展块

                extensionBlock = &frame.ExtensionBlocks[j];

break;

            }

}

if (extensionBlock) {

//获取当前帧的图形控制拓展块中的延时时间(单位1/100 秒:10ms)

            //小端模式

            //Bytes[1] 低八位

            //Bytes[2] 高八位

            gifBean->delays[i] = (extensionBlock->Bytes[2] <<8 | extensionBlock->Bytes[1]) *10;

        }

}

gifBean->total_frames = pGifFileType->ImageCount;

    pGifFileType->UserData = gifBean;

    env->ReleaseStringUTFChars(gif_path_, gif_path);

    return (jlong) (pGifFileType);

}

/**

* 核心代码* @param pGifFileType

* @param gifBean

* @param info

* @param pixels

*/

void drawFrame(GifFileType *pGifFileType, GifBean *gifBean, AndroidBitmapInfo info, void *pixels) {

SavedImage savedImage = pGifFileType->SavedImages[gifBean->current_frame];

    GifImageDesc imageDesc = savedImage.ImageDesc;

    ColorMapObject *pColorMapObject = imageDesc.ColorMap;

    if (NULL == pColorMapObject) {

pColorMapObject = pGifFileType->SColorMap;

    }

//先偏移指针

    int *px = (int *) pixels;//图像首地址

    px = (int *) ((char *) px + info.stride * imageDesc.Top);

    int *line;//每一行的首地址

    int pointPixelIndex;//像素点的索引值

    GifByteType gifByteType;//颜色索引值

    GifColorType colorType;//颜色类型

    for (int y = imageDesc.Top; y < imageDesc.Top + imageDesc.Height; ++y) {

line = px;

        for (int x = imageDesc.Left; x < imageDesc.Left + imageDesc.Width; ++x) {

pointPixelIndex = (y - imageDesc.Top) * imageDesc.Width + (x - imageDesc.Left);

            gifByteType = savedImage.RasterBits[pointPixelIndex];

            //根据索引值到颜色列表中查找

            if (NULL != pColorMapObject) {

colorType = pColorMapObject->Colors[gifByteType];

                //给每行每个像素赋予颜色

                line[x] =argb(255, colorType.Red, colorType.Green, colorType.Blue);

            }

}

px = (int *) ((char *) px + info.stride);

    }

}

extern "C"

JNIEXPORT jint JNICALL

Java_com_example_mycmake_GifNativeDecoder_getWidth(JNIEnv *env,

                                                        jobject thiz,

                                                        jlong gif_pointer) {

GifFileType *pGifFileType = (GifFileType *)gif_pointer;

    return pGifFileType->SWidth;

}

extern "C"

JNIEXPORT jint JNICALL

Java_com_example_mycmake_GifNativeDecoder_getHeight(JNIEnv *env, jobject thiz, jlong gif_pointer) {

GifFileType *pGifFileType = (GifFileType *) gif_pointer;

    return pGifFileType->SHeight;

}

extern "C"

JNIEXPORT jint JNICALL

Java_com_example_mycmake_GifNativeDecoder_updateFrame(JNIEnv *env,

        jobject thiz,

        jobject m_bitmap,

        jlong gif_pointer) {

//    // TODO: implement updateFrame()

//    GifFileType *pGifFileType = (GifFileType *) gif_pointer;

//    GifBean *gifBean = (GifBean *) pGifFileType->UserData;

//

//    AndroidBitmapInfo info;

//    //通过bitmap获取AndroidBitmapInfo

//    AndroidBitmap_getInfo(env,m_bitmap,&info);

//    //指向像素缓冲区的指针

//    void *pixels;

//    //锁住bitmap

//    AndroidBitmap_lockPixels(env,m_bitmap,&pixels);

//    //偏移指针

//    //渲染绘制一帧图像

//    drawFrame(pGifFileType, gifBean, info, pixels);

//    gifBean->current_frame += 1;//渲染完当前帧+1

//    if(gifBean->current_frame>=gifBean->total_frames){

//        gifBean->current_frame=0;

//    }

//    AndroidBitmap_unlockPixels(env,m_bitmap);

//    return gifBean->delays[gifBean->current_frame];

    GifFileType *pGifFileType = (GifFileType *) gif_pointer;

    GifBean *gifBean = (GifBean *) pGifFileType->UserData;

    AndroidBitmapInfo info;

    //通过bitmap获取AndroidBitmapInfo

    AndroidBitmap_getInfo(env, m_bitmap, &info);

    //指向像素缓冲区的指针

    void *pixels;

    //锁住bitmap

    AndroidBitmap_lockPixels(env, m_bitmap, &pixels);

    //偏移指针

    //渲染绘制一帧图像

    drawFrame(pGifFileType, gifBean, info, pixels);

    gifBean->current_frame +=1;//渲染完当前帧+1

    if (gifBean->current_frame >= gifBean->total_frames) {

gifBean->current_frame =0;

    }

AndroidBitmap_unlockPixels(env, m_bitmap);

    return gifBean->delays[gifBean->current_frame];

}

5.Java层调用

class NativeLoadGifextends AsyncTask {

@Override

        protected void onPreExecute() {

super.onPreExecute();

        }

@Override

        protected void onPostExecute(Void aVoid) {

super.onPostExecute(aVoid);

            //加载到gif文件信息了

            //渲染图像delaytime

          int nextFrameRenderTime=gifNativeDecoder.updateFrame(mBitmap,gifNativeDecoder.getGifPointer());

            mHandler.sendEmptyMessageDelayed(1, nextFrameRenderTime);

        }

@Override

        protected VoiddoInBackground(Void... voids) {

//加载GIF图像

//            File file = new File(Environment.getExternalStorageState(), "demo.gif");

//            gifNativeDecoder=GifNativeDecoder.loag(file.getAbsolutePath());

//            int width=gifNativeDecoder.getWidth(gifNativeDecoder.getGifPointer());

//            int height=gifNativeDecoder.getHeight(gifNativeDecoder.getGifPointer());

//            mBitmap=Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);

            //加载gif图像

            File file =new File( Environment.getExternalStorageDirectory(),"demo.gif");

            Log.e("dsdfefefsfse",""+file.exists());

            if(file.exists()) {

gifNativeDecoder = GifNativeDecoder.loag(file.getAbsolutePath());

                int width =gifNativeDecoder.getWidth(gifNativeDecoder.getGifPointer());

                int height =gifNativeDecoder.getHeight(gifNativeDecoder.getGifPointer());

                mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

            }

return null;

        }

}

public void loadGif() {

nativeLoadGif.execute();

    }

HandlermHandler =new Handler() {

public void handleMessage(Message msg) {

mImageView.setImageBitmap(mBitmap);

            int nextFrameRenderTime =gifNativeDecoder.updateFrame(mBitmap, gifNativeDecoder.getGifPointer());

            mHandler.sendEmptyMessageDelayed(1, nextFrameRenderTime);

        }

};

相关文章

网友评论

      本文标题:NDK--JNI开发

      本文链接:https://www.haomeiwen.com/subject/wdeughtx.html