summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-01-04 21:31:56 +0100
committerDenis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>2019-12-25 17:07:36 +0100
commite54cf2f04e3ff8e24c650187f580f7a2985793fa (patch)
tree899b70de2972d99ee280193e6096453a7b637b96
parentadd0cd6e1e9150832cb2a91c6f1f0f70e835be6a (diff)
downloadframeworks_base-e54cf2f04e3ff8e24c650187f580f7a2985793fa.tar.gz
frameworks_base-e54cf2f04e3ff8e24c650187f580f7a2985793fa.tar.bz2
frameworks_base-e54cf2f04e3ff8e24c650187f580f7a2985793fa.zip
Camera: Working barcode scanning with software rendering
Barcode scanner apps expect YUV as preview format. However, the software renderer cannot handle YUV. Thus, RGB 565 is used. Barcode scanner apps only need the first plane Y which is basically greyscale. The solution is a conversion from RGB to greyscale of preview frames that are requested by apps for processing. Apps request preview frames via onPreviewFrame(). The conversion is done using native code for optimal speed. The conversion algorithm is based on the implementations in the RGBLuminanceSource class of ZXing[1] and the RGB565LuminanceSource class of FastBarcodeScanner[2]. Signed-off-by: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> [1] https://github.com/zxing/zxing/blob/cc16a72c85e4958ce406af9547764e5eee9adb6e/core/src/main/java/com/google/zxing/RGBLuminanceSource.java [2] https://github.com/tschaumburg/FastBarcodeScanner/blob/5a4c166a722730d0099d4c6a1c15d312b93547da/tracking-barcode-scanner/src/main/java/dk/schaumburgit/trackingbarcodescanner/RGB565LuminanceSource.java
-rw-r--r--core/java/android/hardware/Camera.java22
-rw-r--r--core/jni/android_hardware_Camera.cpp43
2 files changed, 64 insertions, 1 deletions
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index dd15d388961..16727fec244 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1147,7 +1147,16 @@ public class Camera {
// Set to oneshot mode again.
setHasPreviewCallback(true, false);
}
- pCb.onPreviewFrame((byte[])msg.obj, mCamera);
+
+ byte[] luminances = (byte[])msg.obj;
+ if(getParameters().getPreviewFormat() == ImageFormat.RGB_565)
+ // Convert to greyscale
+ // Apps expect YUV as default format. Greyscale is
+ // only the first layer of YUV, but it's all that's
+ // needed by barcode scanner apps.
+ rgbToBw(luminances);
+
+ pCb.onPreviewFrame(luminances, mCamera);
}
return;
@@ -1216,6 +1225,17 @@ public class Camera {
}
}
+ private void rgbToBw(byte[] pixels)
+ {
+ Size previewsize = getParameters().getPreviewSize();
+ int height = previewsize.height;
+ int width = previewsize.width;
+
+ native_rgbToBw(pixels, width, height);
+ }
+
+ private native void native_rgbToBw(byte[] pixelBuffer, int bufWidth, int bufHeight);
+
private static void postEventFromNative(Object camera_ref,
int what, int arg1, int arg2, Object obj)
{
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 4cf317efc1c..3bb6af3b285 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -79,6 +79,8 @@ struct fields_t {
static fields_t fields;
static Mutex sLock;
+int bwDataSize = 0;
+
// provides persistent context for calls from native code to Java
class JNICameraContext: public CameraListener
{
@@ -933,6 +935,44 @@ static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz)
return env->NewStringUTF(params8.string());
}
+static void android_hardware_Camera_rgbToBw(JNIEnv *env, jobject thiz, jbyteArray pixelBuffer, jint bufWidth, jint bufHeight)
+{
+ int width = bufWidth;
+ int height = bufHeight;
+ int size = width * height;
+
+ static jbyte* pixeldata;
+ static jbyte* luminances;
+
+ if(bwDataSize != size) {
+ pixeldata = (jbyte *)malloc(size*2);
+ luminances = (jbyte *)malloc(size);
+ bwDataSize = size;
+ ALOGV("Allocated buffer of size %d", size);
+ }
+
+ env->GetByteArrayRegion(pixelBuffer, 0, size*2, pixeldata);
+
+ // Convert the entire image to grayscale
+ for (int y = 0; y < height; y++) {
+ int offset = y * width *2;
+ for (int x = 0; x < width *2; x+=2) {
+ jbyte pixel = pixeldata[offset +x];
+ jbyte pixel2 = pixeldata[offset +x + 1];
+ // little endian
+ // GGGBBBBB | RRRRRGGG
+ jbyte b = (jbyte)(pixel & 0x1f); // 5 bits
+ jbyte g = (jbyte)(((pixel >> 5) & 0x07) | ((pixel2 & 0x07) << 3)); // 6 bits
+ jbyte r = (jbyte)((pixel2 >> 3) & 0x1f); // 5 bits
+
+ // Calculate luminance cheaply, favoring green.
+ luminances[(offset + x)/2] = (jbyte)((r + g + b) << 1);
+ }
+ }
+
+ env->SetByteArrayRegion(pixelBuffer, 0, size, luminances);
+}
+
static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz)
{
ALOGV("reconnect");
@@ -1146,6 +1186,9 @@ static JNINativeMethod camMethods[] = {
{ "native_getParameters",
"()Ljava/lang/String;",
(void *)android_hardware_Camera_getParameters },
+ { "native_rgbToBw",
+ "([BII)V",
+ (void *)android_hardware_Camera_rgbToBw },
{ "reconnect",
"()V",
(void*)android_hardware_Camera_reconnect },