我用于Android的JNI JPEG编码器非常慢

Nic*_*ick 5 profile optimization java-native-interface android jpeg

我正在开发一个小型Android应用程序,将一些摄像机镜头(作为一系列JPEG)传输到我的计算机.在没有处理的情况下,帧缓冲器以大约18fps的速度接收相机预览图像.当我加入

YuvImage yuv = new YuvImage(data, ImageFormat.NV21, dimensions.width, dimensions.height, null);
yuv.compressToJpeg(new Rect(0, 0, dimensions.width, dimensions.height), 40, out);
Run Code Online (Sandbox Code Playgroud)

帧速率降至约7 fps.所以我以为我会在C中编写自己的JPEG编码器并加快速度.好吧,我很惊讶.我现在得到0.4 fps!

所以现在我需要分析和优化我的C代码,但我真的不知道从哪里开始.我正在使用这些GCC标志:

-Wall -std=c99 -ffast-math -O3 -funroll-loops
Run Code Online (Sandbox Code Playgroud)

那里有什么我可以提高的吗?

除此之外,我的JPEG编码器只是一个简单的实现.写头信息,写量化和霍夫曼表,然后对数据进行熵编码.DCT正在使用AA&N的方法,我相信这是最快的方法.

也许JNI开销存在问题?

我使用以下方法在Java中分配内存:

frame_buffer = ByteBuffer.allocate(raw_preview_buffer_size).array();
jpeg_buffer = ByteBuffer.allocate(10000000).array();
Run Code Online (Sandbox Code Playgroud)

然后用这段代码拉进来(原谅意大利面条):

void Java_com_nechtan_limelight_activities_CameraPreview_handleFrame(JNIEnv* env, jobject this, jbyteArray nv21data, jbyteArray jpeg_buffer) {
    jboolean isCopyNV21;
    jboolean isCopyJPEG;
    int jpeg_size = 0;

    jbyte* nv21databytes = (*env)->GetByteArrayElements(env, nv21data, &isCopyNV21);
    jbyte* jpeg_buffer_bytes = (*env)->GetByteArrayElements(env, jpeg_buffer, &isCopyJPEG);

    if (nv21databytes != NULL) {
        if (jpeg_buffer_bytes != NULL) {
            jpeg_size = compressToJpeg((UCHAR*) nv21databytes, (UCHAR*) jpeg_buffer_bytes, 640, 480);
            (*env)->ReleaseByteArrayElements(env, jpeg_buffer, jpeg_buffer_bytes, 0);
            (*env)->ReleaseByteArrayElements(env, nv21data, nv21databytes, JNI_ABORT);
            }
        else {
            __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "JPEG data null!");
            }
        }
    else {
        __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NV21 data null!");
        }

    }
Run Code Online (Sandbox Code Playgroud)

我在这里做的事情效率低吗?分析JNI代码的好方法是什么?

除了那些东西,我唯一能想到的是,我将不得不阅读有关NEON和矢量化这些东西.啊...

小智 0

尝试使用内置编码器:

 private byte[] compressYuvToJpeg(final byte[] yuvData) {
    mJpegCompressionBuffer.reset();
    YuvImage yuvImage =
        new YuvImage(yuvData, ImageFormat.NV21, mPreviewWidth, mPreviewHeight, null);
    yuvImage.compressToJpeg(new Rect(0, 0, mPreviewWidth, mPreviewHeight), mJpegQuality,
        mJpegCompressionBuffer);
    return mJpegCompressionBuffer.toByteArray();
  }
Run Code Online (Sandbox Code Playgroud)