Android如何使用libjpeg-turbo库 [英] Android how to use libjpeg-turbo library

查看:25
本文介绍了Android如何使用libjpeg-turbo库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

多亏了这个,我终于设法构建了 libjpeg-turbo 静态库libjpeg-turbo for android现在我有一个 libjpeg.a 和一个由 ndk-build 生成的 libsimd.a

i finally managed to build libjpeg-turbo static library thanks to this libjpeg-turbo for android now i have a libjpeg.a and a libsimd.a generated by ndk-build

但我找不到任何有关下一步做什么的信息?我正在使用 BitmapFactory 中的构建将 jpeg 从缓冲区(从套接字)解码为位图,效果很好

but i have not been able to find any info about what to do next? i'm decode a jpeg from a buffer (from a socket) to a bitmap using the build in BitmapFactory which works fine

byte[] jpgBits = new byte[jpgBitsLen];
dis.readFully(jpgBits);
Bitmap bmp = BitmapFactory.decodeByteArray(jpgBits, 0, jpgBitsLen);

如何用 libjpeg-turbo 替换 BitmapFactory.decodeByteArray?

how do i replace BitmapFactory.decodeByteArray with libjpeg-turbo?

我使用这个在我的电脑上对流进行编码

i encode the stream on my PC using this

tjhandle rmfdJpegCompressor = tjInitCompress();
tjCompress2(rmfdJpegCompressor, (unsigned char *)s_rmfdPixels, MFD_WH, 0, MFD_WH, TJPF_BGRX,
            &rmfdBits, &rmfdBitsLen, TJSAMP_420, RMFD_JPEG_QUALITY,
            0);
tjDestroy(rmfdJpegCompressor);

哪个工作正常,所以我认为必须有一个 android 等价物?

which work fine, so i think there must be an android equivalent?

我读过这个https://wiki.linaro.org/BenjaminGaignard/libjpeg-turboAndSkia这是否意味着使用它的唯一方法是重建 android 源代码以便它使用 libjpeg-turbo?我在某处读到了 libjpeg-turbo 的兼容性 api 和本机 api,我很乐意使用任何最简单的 api,因为我不喜欢重建 android

i read this https://wiki.linaro.org/BenjaminGaignard/libjpeg-turboAndSkia does this mean the only way to use it is to rebuild android sources so it uses libjpeg-turbo? i read somewhere there is a compatibility api and a native api for libjpeg-turbo and i'm happy to use whatever api is easiest since i don't fancy rebuilding android

我尝试了以下方法:在我的项目根目录下,我创建了文件夹 jni/include 并将 turbojpeg.h 放在那里在我的项目根目录下,我创建了文件夹 jni/prebuilt 并将 libjpeg.a 放在那里

i've tried the following: under my project root i created folders jni/include and put turbojpeg.h in there under my project root i created folders jni/prebuilt and put libjpeg.a in there

在我的java代码中,我放了

in my java code, i put

private native int tjInitDecompress(); 

在 MainActivity并在 onCreate 我添加

in MainActivity and in onCreate i add

int i = tjInitDecompress();
Log.d("MainActivity", "i="+i);

它构建并运行,但在 tjInitDecompress 时崩溃

it builds and runs but crashes at tjInitDecompress

在日志中它说:未找到本机 Lcom/example.jpegtest/MainActivity;.tjInitDecompress ()I

in the log it says: No implementation found for native Lcom/example.jpegtest/MainActivity;.tjInitDecompress ()I

谢谢

推荐答案

嗯,工作量很大,但我终于找到了一些工作,所以我想让任何有兴趣的人知道我是如何做到的.

well, its been a mountain of work but i finally got something working so i want to let anyone who's interested know how i did it.

首先我按照这里的描述构建了 hello-jin 演示https://developer.android.com/tools/sdk/ndk/index.html

first i built the hello-jin demo as described here https://developer.android.com/tools/sdk/ndk/index.html

然后我创建了一个新项目,复制了 jni 并更改了 c func 的名称以匹配新的包和类名.不要在你的包名中使用 - 和 _ 否则你会遇到问题.最好只有 a-x0-9.

then i created a new project, copied the jni and changed the names of the c func to match the new package and class name. don't use - and _ in your package name or you will have problems. just a-x0-9 is best.

然后我将所有 libjpeg-turbo 文件和目录复制到 jni 并测试 ndk-build 仍然有效

then i copied all the libjpeg-turbo file and dirs into jni and tested that ndk-build still worked

然后我为这样的 libjpg funs 创建了一个 jni 包装器tjpegini-arm.c

then i created a jni wrapper for the libjpg funs like this tjpegini-arm.c

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include <jni.h>
#include "turbojpeg.h"


/*
 * Class:     libjpegturbo_jniapi
 * Method:    tjInitDecompress
 * Signature: ()I
 */
//package com.design2112.fbmslpit
//public class MainActivity
jint JNICALL Java_com_design2112_fbmslpit_MainActivity_tjInitDecompress
  (JNIEnv *env, jobject thisObj)
{
    return (int)tjInitDecompress();
}


/*
 * Class:     libjpegturbo_jniapi
 * Method:    tjDecompressHeader2
 * Signature: (I[BI)I
 */
jint JNICALL Java_com_design2112_fbmslpit_MainActivity_tjDecompressHeader2
  (JNIEnv *env, jobject thisObj, jint handle, jbyteArray jpegBuf, jint jpegSize)
{
    jbyte *real_jpegBuf = (*env)->GetByteArrayElements(env, jpegBuf, 0);
    if (!real_jpegBuf) return -1;
    //jsize length = (*env)->GetArrayLength(env, real_jpegBuf);

    /*for (i = 0; i < length; i++) {
        sum += inCArray[i];
    }*/

    int width, height, jpegSubsamp;
    int ret =  tjDecompressHeader2((tjhandle)handle,
                (unsigned char *)real_jpegBuf, (unsigned long)jpegSize, &width, &height,
                &jpegSubsamp);
    if(ret!=0) {
        return 0;
    }

    // ok, so pack width and height together
    return width<<16 | height;
}

/*
 * Class:     libjpegturbo_jniapi
 * Method:    tjDecompress2
 * Signature: (I[BI[IIIIII)V
 */
void JNICALL Java_com_design2112_fbmslpit_MainActivity_tjDecompress2
  (JNIEnv *env, jobject thisObj, jint handle, jbyteArray jpegBuf, jint jpegSize, jintArray dstBuf,
  jint width, jint pitch, jint height, jint pixelFormat, jint flags)
{
    jbyte *real_jpegBuf = (*env)->GetByteArrayElements(env, jpegBuf, 0);
    if (!real_jpegBuf) return;
    jint *real_dstBuf = (*env)->GetIntArrayElements(env, dstBuf, 0);
    if (!real_dstBuf) return;

    jsize length = (*env)->GetArrayLength(env, jpegBuf);
    tjDecompress2((tjhandle)handle,
                (unsigned char *)real_jpegBuf, (unsigned long)jpegSize, (unsigned char *)real_dstBuf,
                 width, pitch, height, pixelFormat, flags);
}

/*
 * Class:     libjpegturbo_jniapi
 * Method:    tjDestroy
 * Signature: (I)V
 */
void JNICALL Java_com_design2112_fbmslpit_MainActivity_tjDestroy
  (JNIEnv *env, jobject thisObj, jint handle)
{
    tjDestroy((tjhandle)handle);
}

重要提示,您必须将 com_design2112_fbmslpit_MainActivity 重命名为您的包和类才能正常工作

IMPORTANT, you will have to rename com_design2112_fbmslpit_MainActivity to your package and class for this to work

将 tjpegini-arm.c 添加到 Android.mk makefile 然后在 jni 目录中运行 ndk-build

add tjpegini-arm.c to the Android.mk makefile then run ndk-build in the jni dir

ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk obj/local/armeabi/libjpeg.so  LOCAL_ARM_MODE=arm

并将 .so 复制到正确的名称和位置

and copy the .so to the right name and place

cp obj/local/armeabi/libjpeg.so ../libs/armeabi/libtjpegjni-arm.so

然后在我的 MainAvtivity.java 中

then in my MainAvtivity.java

public class MainActivity extends Activity {


    public native int tjInitDecompress();
    public native int tjDecompressHeader2(int handle, byte[] jpegBits, int jpegBitsLen);    
    public native void tjDecompress2(int handle, byte[] jpegBits,
            int jpegBitsLen, int[] outbuffer, int width, int pitch, int height,
            int pixelFormat, int flags);
    public native void tjDestroy(int handle);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            getFragmentManager().beginTransaction()
                    .add(R.id.container, new PlaceholderFragment())
                    .commit();
        }

        File sdcard = Environment.getExternalStorageDirectory();

        //Get the text file
        File file = new File(sdcard,"/Download/test.jpg");
        int jpegBitsLen = (int) file.length();
        byte[] jpegBits = new byte[jpegBitsLen];
        DataInputStream dis;
        try {
            dis = new DataInputStream(new FileInputStream(file));
            dis.readFully(jpegBits);
            dis.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.loadLibrary("tjpegjni-arm");

        int jpegDec = tjInitDecompress();

        int wh = tjDecompressHeader2(jpegDec, jpegBits, jpegBitsLen);
        int width = wh>>16;
        int height = wh&0x7fff;

        int[] buffer = new int[width*height];
        tjDecompress2(jpegDec, jpegBits, jpegBitsLen, buffer, width, 0/*pitch*/, height, 2 /*TJPF_RGBX*/, 0);

        tjDestroy(jpegDec);

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

    }

基本上就是这样.你可以以任何你想要的方式显示bmp.

that's basically it. you can display the bmp any way you want.

这对我来说也是一大堆工作,以弄清楚根本没有 jni ndk 经验.如果有人觉得这很有用,请给我发电子邮件.

this too me a shit load of work to figure out having no jni ndk experience at all. if someone finds this usefull, email me a beer.

更新,这是一个令人震惊的消息,解码 450x450 图像需要 20 毫秒.内置的 BitmapFactory.decodeByteArray 也差不多!

UPDATE, here's the shocking news, its taking 20ms to decode a 450x450 image. the built in BitmapFactory.decodeByteArray does it in about the same!

如果其他人尝试此操作并得到不同的结果,请记下

if anyone else tries this and gets different results, please make a note

这篇关于Android如何使用libjpeg-turbo库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆