2012-06-14 33 views
5

私はちょっとしたAndroidアプリを使ってカメラの映像を(一連のJPEGとして)私のコンピューターにストリーミングしています。処理なしでは、フレームバッファは約18fpsでカメラプレビュー画像を受信する。私が追加するときAndroid用JNI JPEGエンコーダーが本当に遅いです

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

フレームレートは約7 fpsに低下します。だから私は自分のJPEGエンコーダをC言語で書いて少し速くすると思った。まあ、私は驚いた。私は今0.4 fpsを得ています!

私は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について読んでこの内容をベクトル化する必要があることだけです。うわ...

+2

誰かがすでにすべての賢明な最適化をした既製のエンコーダを使用して、論理的な最初のステップとなります。また、圧縮とデカップリングを併用することをお勧めします。 –

+1

Javaでメモリを割り当ててからネイティブで使用すると、パフォーマンスが低下します。ネイティブコード内でメモリの割り当てとファイルI/Oを実行することができます。共有していないのでJPEGコードにはコメントできませんが、ネイティブJPEGエンコーダ/デコーダは、すべてのものをネイティブ側に保つことで、Androidでうまく機能します。 – BitBank

+0

@Seva、それはJPEGを維持するつもりはありません - それは最終的にビデオ用のウェーブレットエンコーダの1つに変わってしまいますが、すべてを正しく最適化していることを確認するためのベースラインが必要です – Nick

答えて

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(); 
    } 
+1

私のポストの一番上に、それは実際に私が元来していることです。それは十分に速くはありません。私の電話機に搭載されている800 MHzプロセッサでは、18 fpsを維持するために、色のサンプルあたり約96クロックサイクルです。確かに何らかの形で可能でなければなりません。 – Nick

+0

私は、どの機能が最も多くの計算時間を費やしているかを確認することを提案します。単純に1つ以上の機能を残して、PC側で受信時間を測定するだけです。また、アンドロイド用のh264ストリーマーが存在することにも注意してください。http://code.google.com/p/ipcamera-for-android/ –

関連する問題