2

この投稿のおかげで、ndk-build を使用して libjpeg-turbo を正常にビルドできました: libjpeg-turbo for android

libjpeg-turbo の example.c で read_JPEG_file のようなネイティブ関数を取得し、Java コードから呼び出して Android アプリに使用したいと考えています。

誰かがそれを行う方法の例を教えてもらえますか? libjpeg-turbo ndk ビルド ライブラリを使用する Java のネイティブ メソッドを作成するにはどうすればよいですか?

ライブラリをロードできます

System.loadLibrary("libjpeg");

しかし、次は何ですか?ライブラリには、Java から呼び出すネイティブ メソッドはありません。

JNI ドキュメントに従って JNI c クラスを作成しようとしましたが、成功しませんでした。サンプルコードは、その方法を学ぶのに最適です。

編集:

テスト クラス NativeMethods を作成しました。

package com.test.app;

public class NativeMethods {

    private String filename = null;

    static {
        System.loadLibrary("jpeg"); // this represents compiled libjpeg-turbo under ndk
    }

    public NativeMethods(String jpegFilename) {
        this.filename = jpegFilename;
    }

    public native int computeNumberOfDCTS(String filename);
}

次に、javah を使用してネイティブ メソッドの C ヘッダーを生成します。結果は、以下com_test_app_NativeMethods.hを含むファイルです。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_test_app_NativeMethods */

#ifndef _Included_com_test_app_NativeMethods
#define _Included_com_test_app_NativeMethods
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_test_app_NativeMethods
 * Method:    computeNumberOfDCTS
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_test_app_NativeMethods_computeNumberOfDCTS
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

JPEGProcessing.c次に、ネイティブ関数の c 実装を次のように配置するという名前のファイルを作成しました。

#include "com_test_app_NativeMethods.h"

//that came from jpeglib example
struct my_error_mgr
{
    struct jpeg_error_mgr pub;
    jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr * my_error_ptr;

//routine that will replace the standard error_exit method
static void
my_error_exit (j_common_ptr cinfo)
{
    /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
    my_error_ptr myerr = (my_error_ptr) cinfo->err;

    (*cinfo->err->output_message) (cinfo);

    /* Return control to the setjmp point */
    longjmp(myerr->setjmp_buffer, 1);
}

JNIEXPORT jint JNICALL Java_com_test_app_NativeMethods_computeNumberOfDCTS
    (JNIEnv *env, jobject obj, jstring javaString)
{
    jint toReturn = 0;
    // struct representing jpeg image
    struct jpeg_decompress_struct  cinfo;
    // struct representing error manager; defined above
    struct my_error_mgr jerr;

    const char *filename = (*env)->GetStringUTFChars(env, javaString, 0);

    FILE * infile;

    if ((infile = fopen(filename, "rb")) == NULL) {
        fprintf(stderr, "can't open %s\n", filename);
        return -1;
    }

    cinfo.err = jpeg_std_error(&jerr.pub);
    jerr.pub.error_exit = my_error_exit;

    if (setjmp(jerr.setjmp_buffer)) {
        jpeg_destroy_decompress(&cinfo);
        fclose(infile);
        return -1;
    }

    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, infile);

    (void) jpeg_read_header(&cinfo, TRUE);

    // declare virtual arrays for DCT coefficients
    jvirt_barray_ptr* coeffs_array;
    // read DCT coefficients from jpeg
    coeffs_array = jpeg_read_coefficients(&cinfo);

    // fill virtual arrays.
    // ci represents component color
    // this cycle prints all dct coefficient of the jpeg in 8x8 blocks
    for (int ci = 0; ci < 3; ci++)
    {
        JBLOCKARRAY buffer_one;
        JCOEFPTR blockptr_one;
        jpeg_component_info* compptr_one;
        compptr_one = cinfo.comp_info + ci;

        for (int by = 1; by < (compptr_one->height_in_blocks - 1); by++) // we don't want to use the edges of the images
        {
            buffer_one = (cinfo.mem->access_virt_barray)((j_common_ptr)&cinfo, coeffs_array[ci], by, (JDIMENSION)1, FALSE);

            for (int bx = 1; bx < (compptr_one->width_in_blocks - 1); bx++) // we don't want to use the edges of the images
            {
                blockptr_one = buffer_one[0][bx];

                for (int bi = 1; bi < 64; bi++) // we don't want to use AC
                {
                    toReturn++;
                }
            }
        }
    }

    jpeg_destroy_decompress(&cinfo);
    fclose(infile);

    return toReturn;
}

ファイルJPEGProcessing.cとフォルダ内com_test_app_NativeMethods.hにありproject/jni/ます。同じ jni フォルダーにAndroid.mk、次の行を配置するファイルを作成しました。

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE    := JPEGProcessing
LOCAL_CFLAGS    := -Werror
LOCAL_SRC_FILES := JPEGProcessing.c

LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_LDLIBS    := -lm -llog -landroid
LOCAL_STATIC_LIBRARIES := libjpeg
include $(BUILD_SHARED_LIBRARY)

プロジェクト ディレクトリから ndk-build を実行した後、いくつかのエラーが発生しました。

jni/JPEGProcessing.c:7:27: error: field 'pub' has incomplete type
jni/JPEGProcessing.c:8:5: error: unknown type name 'jmp_buf'
jni/JPEGProcessing.c:14:16: error: unknown type name 'j_common_ptr'
jni/JPEGProcessing.c: In function 'Java_com_test_app_NativeMethods_computeNumberOfDCTS':
jni/JPEGProcessing.c:30:36: error: storage size of 'cinfo' isn't known
jni/JPEGProcessing.c:36:5: error: unknown type name 'FILE'
jni/JPEGProcessing.c:38:17: error: assignment makes pointer from integer without a cast [-Werror]
jni/JPEGProcessing.c:38:45: error: 'NULL' undeclared (first use in this function)
...

理解できません。コードをlibjpeg-turbo関数と組み合わせて作業ライブラリを取得し、Javaで使用するにはどうすればよいですか?

NDK の説明と例を読みましたが、まだわかりません。

編集:

シンプルなネイティブ メソッドを使用した NDK と JNI は問題なく動作します。テストとして、うまく機能する次の簡単な方法を使用しました。

#include "com_test_app_NativeMethods.h"

JNIEXPORT jint JNICALL Java_com_test_app_NativeMethods_computeNumberOfDCTS
    (JNIEnv *env, jobject obj, jstring javaString)
{
    jint toReturn = 0;

    const char *filename = (*env)->GetStringUTFChars(env, javaString, 0);
    const char *test = "test";

    if ( filename == test )
    {
        toReturn++;
    }

    return toReturn;
}

次のようにlibjpeg-turboのもので試しました:

#include "com_test_app_NativeMethods.h"
#include <stdio.h>
#include <setjmp.h>
#include <libjpeg-turbo/jpeglib.h>
#include <libjpeg-turbo/turbojpeg.h>
#include <libjpeg-turbo/jconfig.h>
#include <libjpeg-turbo/jmorecfg.h>
#include <libjpeg-turbo/jerror.h>

//that came from jpeglib example
struct my_error_mgr
{
    struct jpeg_error_mgr pub;
    jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr * my_error_ptr;

//routine that will replace the standard error_exit method
static void
my_error_exit (j_common_ptr cinfo)
{
    /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
    my_error_ptr myerr = (my_error_ptr) cinfo->err;

    (*cinfo->err->output_message) (cinfo);

    /* Return control to the setjmp point */
    longjmp(myerr->setjmp_buffer, 1);
}

JNIEXPORT jint JNICALL Java_com_test_app_NativeMethods_computeNumberOfDCTS
    (JNIEnv *env, jobject obj, jstring javaString)
{
    jint toReturn = 0;
    // struct representing jpeg image
    struct jpeg_decompress_struct  cinfo;
    // struct representing error manager; defined above
    struct my_error_mgr jerr;

    const char *filename = (*env)->GetStringUTFChars(env, javaString, 0);

    FILE * infile;

    if ((infile = fopen(filename, "rb")) == NULL) {
        // cannot open file
        return -1;
    }

    cinfo.err = jpeg_std_error(&jerr.pub);
    jerr.pub.error_exit = my_error_exit;

    if (setjmp(jerr.setjmp_buffer)) {
        jpeg_destroy_decompress(&cinfo);
        fclose(infile);
        return -1;
    }

    jpeg_create_decompress(&cinfo);

    jpeg_destroy_decompress(&cinfo);
    fclose(infile);

    return toReturn;
}

そして、エラーが発生します...:

Compile thumb  : JPEGProcessing <= JPEGProcessing.c
SharedLibrary  : libJPEGProcessing.so
/usr/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/JPEGProcessing/JPEGProcessing.o: in function Java_com_test_app_NativeMethods_computeNumberOfDCTS:jni/JPEGProcessing.c:50: error: undefined reference to 'jpeg_std_error'
/usr/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/JPEGProcessing/JPEGProcessing.o: in function Java_com_test_app_NativeMethods_computeNumberOfDCTS:jni/JPEGProcessing.c:59: error: undefined reference to 'jpeg_CreateDecompress'
/usr/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/JPEGProcessing/JPEGProcessing.o: in function Java_com_test_app_NativeMethods_computeNumberOfDCTS:jni/JPEGProcessing.c:61: error: undefined reference to 'jpeg_destroy_decompress'
/usr/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/JPEGProcessing/JPEGProcessing.o: in function Java_com_test_app_NativeMethods_computeNumberOfDCTS:jni/JPEGProcessing.c:54: error: undefined reference to 'jpeg_destroy_decompress'
collect2: ld returned 1 exit status
make: *** [obj/local/armeabi/libJPEGProcessing.so] Error 1

では、ndk でビルドされた libjpeg-turbo ライブラリでネイティブ コードを使用するにはどうすればよいでしょうか。

4

4 に答える 4

2

libjpeg_turbo は C ライブラリとしてコンパイルされ、Android ネイティブ コードは C++ プログラムとしてコンパイルされるため、リンケージ ディレクティブを介して C ライブラリを含める必要があります。

これを試して、

extern "C" {
#include "headers of libjpeg_turbo"
}
于 2013-03-05T09:19:38.767 に答える
1

すべてをネイティブ コードから実行する必要がある場合は、ネイティブ側でライブラリ用の独自のラッパーを作成できます。手順はおおよそ次のとおりです。

  • あなたが呼び出すクラスで:

    System.loadLibrary("libjpeg");

実装を提供せずに、Java 側で呼び出す必要があるネイティブ メソッドを宣言します。

public static native readJPEGFile();
  • 次に、javah コマンドを使用して、ネイティブ側でネイティブ関数を実装した C ファイルを作成できます。Java側でネイティブ関数を呼び出すと呼び出されます。関数とパラメーターのフル パスに注意してください。これらは javah コマンドによって自動的に生成されるため、変更しないでください。変更しないと機能しません。結果は次のようになります。

     extern "C" {
         JNIEXPORT void JNICALL Java_com_android_packagename_GL2JNILib_readJPEGFile(JNIEnv * env, jobject obj);
     };
    
    JNIEXPORT void JNICALL Java_com_android_packagename_GL2JNILib_readJPEGFile(JNIEnv * env, jobject obj) {
        // Call your library's function
     }
    
  • その後、ラッパー関数を含む共有ライブラリを jni フォルダーに作成する必要があります (存在しない場合は作成します)。これを行うには、Android.mk ファイルを作成し、ndk-build を実行して共有ライブラリ (.so ファイル) を生成します。考えられる Android.mk は次のようになりますが、名前と依存関係を確認する必要があります。

      LOCAL_PATH := $(call my-dir)
      include $(CLEAR_VARS)
      LOCAL_MODULE    := jpgturbo-wrapper
      LOCAL_CFLAGS    := -Werror
      LOCAL_SRC_FILES := jpgturboWrapper.cpp
      LOCAL_C_INCLUDES := $(LOCAL_PATH)
      LOCAL_LDLIBS    := -lm -llog -landroid
      LOCAL_STATIC_LIBRARIES := jpegturbo # write all the libraries your project depend on here, separated by white spaces
      include $(BUILD_SHARED_LIBRARY)
    
  • ndk-build を実行すると、.so ファイルが生成され、対応するフォルダーにコピーされます。

まず、NDK のドキュメント、特に提供されているサンプルを確認できます: http://developer.android.com/tools/sdk/ndk/index.html

場合によっては、github をすばやく検索して、同じライブラリを機能させる前に他の誰かが苦労したかどうかを確認したり、公式のサンプルよりも高度な例をいくつか確認したりすることもお勧めします。

于 2013-01-14T22:12:37.097 に答える
0

Android.mk を変更して libjpeg ヘッダーを含め、dlopen()コンパイル済みアーム libjpeg.so を使用する関数に関する情報を探してみてください。

于 2013-07-21T02:41:26.247 に答える