2012-06-14 32 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。所以我認爲我會用C編寫我自己的JPEG編碼器並加快速度。那麼我很驚喜。我現在得到0.4 fps!

所以現在我需要配置和優化我的C代碼,但我真的不知道從哪裏開始。我正在使用這些GCC標誌:

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

有沒有什麼我可以在那裏改進?

除此之外,我的JPEG編碼器只是一個簡單的實現。寫頭信息,寫量化和霍夫曼表,然後對數據進行熵編碼。 DCT正在使用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 - 它最終會變成視頻的小波編碼器之一,但我需要一個基線來確保我能夠正確地優化所有內容 – 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處理器,每個顏色樣本大約需要96個時鐘週期,以保持18 fps。它肯定有可能以某種方式或另一種方式。 – Nick

+0

我建議檢查哪個函數佔用最多的計算時間,只需在PC端丟棄一個或多個函數並測量接收時間即可。另外請注意,Android上有一個h264流光標,http://code.google.com/p/ipcamera-for-android/ –