5

私は小さな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);

フレームレートは約7fpsに低下します。だから私は自分のJPEGエンコーダーをCで書いて、それを少しスピードアップしようと思いました。さて、私は驚きました。私は今0.4fpsを取得しています!

したがって、Cコードのプロファイルを作成して最適化する必要がありますが、どこから始めればよいのかよくわかりません。私はこれらのGCCフラグを使用しています:

-Wall -std=c99 -ffast-math -O3 -funroll-loops

そこで改善できることはありますか?

それ以外は、私のJPEGエンコーダーは単純な実装です。ヘッダー情報を書き込み、量子化テーブルとハフマンテーブルを書き込み、データをエントロピーエンコードします。DCTはAA&Nの方法を使用していますが、これが最も速い方法だと思います。

おそらく、JNIオーバーヘッドに問題がありますか?

私はJavaでメモリを割り当てています:

frame_buffer = ByteBuffer.allocate(raw_preview_buffer_size).array();
jpeg_buffer = ByteBuffer.allocate(10000000).array();

そして、このコードでそれを引き込みます(現時点ではスパゲッティを許してください):

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!");
        }

    }

私はここで非効率的なことをしていますか?JNIコードをプロファイリングする良い方法は何ですか?

それ以外に考えられるのは、NEONについて読んで、このことをベクトル化する必要があるということだけです。うーん...

4

1 に答える 1

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();
  }
于 2012-06-14T19:21:22.330 に答える