pixpark/gpupixel

[BUG] Android: TargetRawDataOutput work wrong

lambiengcode opened this issue · 3 comments

Describe the bug
Only 0 and 255 in callback data, When I convert it to Bitmap, only black frame.

How To Reproduce the bug
Using TargetRawDataOutput instead of GPUPixelView in example project

Expected behavior
When I put the similar log for iOS or macOS it response multiple value between 0 and 255, but in android, just 0 and 255

Screenshots
If applicable, add screenshots to help explain your problem.

Running Information(please complete the following information):

  • GPUPixel Version using : 1.2.5
  • Operating System: Android 14 - HyperOS
  • Device Info: Xiaomi 11T 5G

Additional context
I write 2 function in JNI:

std::list<std::shared_ptr<Filter>>  filter_list_;
std::shared_ptr<SourceRawDataInput> gpuPixelRawInput;
std::shared_ptr<BeautyFaceFilter> beauty_face_filter_;
std::shared_ptr<TargetRawDataOutput> targetRawOutput_;
std::shared_ptr<FaceReshapeFilter> face_reshape_filter_;
std::shared_ptr<gpupixel::FaceMakeupFilter> lipstick_filter_;
std::shared_ptr<gpupixel::FaceMakeupFilter> blusher_filter_;

static const char* TAG = "FlutterRTCBeautyFilters";

extern "C" JNIEXPORT void JNICALL
Java_com_pixpark_gpupixel_GPUPixel_nativeInitSourceRawDataInput(JNIEnv* env, jclass, jobject source) {
    jobject globalSourceRef = env->NewGlobalRef(source);

    jclass cls = env->GetObjectClass(globalSourceRef);
    jmethodID mid = env->GetMethodID(cls, "onRawOutput", "([BII)V");

    if (!mid) return;

    gpuPixelRawInput = SourceRawDataInput::create();

    // Create filters
    lipstick_filter_ = LipstickFilter::create();
    blusher_filter_ = BlusherFilter::create();
    face_reshape_filter_ = FaceReshapeFilter::create();

    gpuPixelRawInput->RegLandmarkCallback([=](std::vector<float> landmarks) {
        lipstick_filter_->SetFaceLandmarks(landmarks);
        blusher_filter_->SetFaceLandmarks(landmarks);
        face_reshape_filter_->SetFaceLandmarks(landmarks);
    });

    targetRawOutput_ = TargetRawDataOutput::create();
    beauty_face_filter_ = BeautyFaceFilter::create();

    gpuPixelRawInput->setRotation(RotationMode::NoRotation);

    lipstick_filter_->setBlendLevel(0.1f);
    blusher_filter_->setBlendLevel(0.2f);
    face_reshape_filter_->setFaceSlimLevel(0.1f);
    face_reshape_filter_->setEyeZoomLevel(0.1f);
    beauty_face_filter_->setWhite(0.2f);

    JavaVM* jvm;
    env->GetJavaVM(&jvm);

    targetRawOutput_->setPixelsCallbck([jvm, globalSourceRef, mid](const uint8_t* data, int width, int height, int64_t ts) {
        __android_log_print(ANDROID_LOG_INFO, TAG, "Received output with height: %d, width: %d", height, width);
        JNIEnv* myNewEnv;
        JavaVMAttachArgs args;
        args.version = JNI_VERSION_1_6; 
        args.name = NULL; 
        args.group = NULL;
        jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>((void **) &myNewEnv), &args);

        for (int i = 0; i < width * height; i++) {
            __android_log_print(ANDROID_LOG_DEBUG, TAG, "Data[%d]: %d", i, data[i]);
        }

        size_t rgba_size = width * height * 4;

        uint8_t* argbData = (uint8_t*)malloc(rgba_size);

        // Convert RGBA to ARGB
        for (int i = 0; i < width * height; ++i) {
            argbData[i * 4 + 0] = data[i * 4 + 3];  // Alpha
            argbData[i * 4 + 1] = data[i * 4 + 0];  // Red
            argbData[i * 4 + 2] = data[i * 4 + 1];  // Green
            argbData[i * 4 + 3] = data[i * 4 + 2];  // Blue
        }

        jbyte* argb_byte = (jbyte*)argbData;
        jbyteArray jARGB = myNewEnv->NewByteArray(rgba_size);
        myNewEnv->SetByteArrayRegion(jARGB, 0, rgba_size, argb_byte);

        myNewEnv->CallVoidMethod(globalSourceRef, mid, jARGB, width, height);

        myNewEnv->DeleteLocalRef(jARGB);
    });

    gpuPixelRawInput->addTarget(lipstick_filter_)
        ->addTarget(blusher_filter_)
        ->addTarget(face_reshape_filter_)
        ->addTarget(beauty_face_filter_)
        ->addTarget(targetRawOutput_);
}

extern "C" void Java_com_pixpark_gpupixel_GPUPixel_nativeWaterbusUploadBytes(
        JNIEnv* env,
        jclass,
        jintArray jPixel,
        jint width,
        jint height,
        jint stride
        ) {
    int64_t  ts = Util::nowTimeMs();
    jint* pixels = env->GetIntArrayElements(jPixel, 0);
    gpuPixelRawInput->uploadBytes((uint8_t*)pixels, width, height, stride, ts);
    env->ReleaseIntArrayElements(jPixel, pixels, 0);
}

I referred to your jni code, and an opengl error occured when I ran the app."call to OpenGL ES API with no current context (logged once per thread)" How can I solve it?

I referred to your jni code, and an opengl error occured when I ran the app."call to OpenGL ES API with no current context (logged once per thread)" How can I solve it?

Managed to solve the gl thread error, and got correct output data with your Jni code, on XiaoMi9
A small problem: You used uint8_t* argbData = (uint8_t*)malloc(rgba_size); to allocate memory for the output data, and did not destroy it after using it, which results in a memory leak.