【问题标题】:Android how to use libjpeg-turbo libraryAndroid如何使用libjpeg-turbo库
【发布时间】:2014-07-03 08:42:03
【问题描述】:

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

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

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

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

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

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 等价物?

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

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

在我的java代码中,我放了

private native int tjInitDecompress(); 

在 MainActivity 并在 onCreate 我添加

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

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

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

的实现

谢谢

【问题讨论】:

    标签: android android-ndk


    【解决方案1】:

    嗯,这是一堆工作,但我终于得到了一些工作,所以我想让任何有兴趣的人知道我是如何做到的。

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

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

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

    然后我为这样的 libjpg funs 创建了一个 jni 包装器 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 重命名为您的包和类才能正常工作

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

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

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

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

    然后在我的 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。

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

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

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

    【讨论】:

    • 首先,我为你的勇气和决心鼓掌。你真的在这里做了很大的工作。可惜你之前没有检查你的方位就冲进去了。 libjpeg-turbo 没有机会击败 Android 上的内置 Jpeg 解码器。特别是 - 在小图像上。 这个库在哪里很重要? 创建大(10MByte 或更多)Jpeg 图像;操作大型 Jpeg 图像(例如旋转和裁剪它们)。请注意,许多设备都具有对 Jpeg 编码/解码的硬件支持,这比任何 NEON 优化都要快得多。同样,这仅对大图像很重要。
    • 哦,生活和学习,至少我现在知道 jni 和 ndk
    • 所以@AlexCohn,压缩也是如此吗?我正在尝试用TJCompressor 替换内置的Bitmap.compress(CompressFormat.JPEG),我的图像确实很小(它们是大约40x40 的较大图像的图块)。我现在只能每秒压缩大约 10 个完整帧的瓦片(我要处理的图像大约 256 个瓦片),所以大约 2560 个小压缩,我希望通过使用它可以达到大约 20-30 fps libjpeg-turbo。如果这不可行,有什么建议可以在 Android 领域更好地执行 jpeg 压缩?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多