visual studio r17b r16 r13 que ndk android android-ndk

android - studio - ndk r13



Android cómo usar la biblioteca libjpeg-turbo (1)

finalmente logré construir biblioteca estática libjpeg-turbo gracias a este libjpeg-turbo para android ahora tengo un libjpeg.a y un libsimd.a generado por ndk-build

pero no he podido encontrar ninguna información sobre qué hacer a continuación? Estoy decodificando un jpeg desde un buffer (desde un socket) a un mapa de bits usando la construcción en BitmapFactory que funciona bien

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

¿Cómo reemplazo BitmapFactory.decodeByteArray con libjpeg-turbo?

codifico la transmisión en mi PC usando esto

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);

que funcionan bien, entonces creo que debe haber un equivalente de Android?

Leí esto https://wiki.linaro.org/BenjaminGaignard/libjpeg-turboAndSkia ¿Esto significa que la única forma de usarlo es reconstruir las fuentes de Android para que use libjpeg-turbo? He leído en alguna parte que hay una API de compatibilidad y una API nativa para libjpeg-turbo y estoy contento de usar cualquier API que sea más fácil ya que no me gusta reconstruir Android.

He intentado lo siguiente: bajo la raíz de mi proyecto, creé las carpetas jni / include y puse turbojpeg.h allí bajo la raíz del proyecto, creé las carpetas jni / prebuilt y puse libjpeg.a ahí

en mi código de Java, puse

private native int tjInitDecompress();

en MainActivity y en onCreate agrego

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

se construye y se ejecuta, pero se bloquea en tjInitDecompress

en el registro dice: No se encontró ninguna implementación para Lcom / example.jpegtest / MainActivity nativa; .tjInitDecompress () I

Gracias


Bueno, ha sido una montaña de trabajo, pero finalmente conseguí algo que funciona, así que quiero que cualquiera que esté interesado sepa cómo lo hice.

Primero construí la demostración de hello-jin como se describe aquí https://developer.android.com/tools/sdk/ndk/index.html

luego creé un nuevo proyecto, copié el jni y cambié los nombres del c func para que coincida con el nuevo paquete y el nombre de clase. no use - y _ en el nombre de su paquete o tendrá problemas. solo a-x0-9 es lo mejor.

luego copié todos los archivos libjpeg-turbo y dirs en jni y probé que ndk-build aún funcionaba

luego creé un jni wrapper para las diversiones libjpg como este 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); }

IMPORTANTE, tendrá que cambiar el nombre de com_design2112_fbmslpit_MainActivity a su paquete y clase para que esto funcione

agregue tjpegini-arm.c al archivo make de Android.mk luego ejecute ndk-build en el jni dir

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

y copie el .so al nombre y lugar correctos

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

luego en mi 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); }

eso es básicamente eso. puede mostrar el bmp de la manera que desee.

esto también me da una gran cantidad de trabajo para descubrir que no tengo ninguna experiencia jni ndk en absoluto. si alguien encuentra esto útil, envíeme una cerveza por correo electrónico.

ACTUALIZACIÓN, aquí están las noticias impactantes, está tomando 20ms para decodificar una imagen de 450x450. el construido en BitmapFactory.decodeByteArray lo hace en casi lo mismo!

si alguien más lo intenta y obtiene resultados diferentes, por favor, tome nota