2012-06-14 15 views
5

Sto lavorando ad una piccola app per Android per fare il flusso di alcune immagini della telecamera (come una serie di JPEG) sul mio computer. Senza elaborazione, il frame buffer riceve le immagini di anteprima della telecamera a circa 18 fps. Quando aggiungoIl mio codificatore JNI JPEG per Android è molto lento

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

il frame rate scende a circa 7 fps. Così ho pensato di scrivere il mio codificatore JPEG in C e di accelerarlo un po '. Beh, ho avuto una sorpresa. Ora sto ottenendo 0.4 fps!

Quindi ora ho bisogno di profilare e ottimizzare il mio codice C, ma non so davvero da dove cominciare. Sto usando questi flag GCC:

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

C'è qualcosa che posso migliorare lì?

Oltre a ciò, il mio codificatore JPEG è solo un'implementazione diretta. Scrivi informazioni di intestazione, scrivi quantizzazione e tabelle di Huffman, quindi entropia codifica i dati. Il DCT utilizza il metodo AA & N credo sia il modo più veloce per farlo.

Forse c'è un problema con l'overhead JNI?

Sto allocando la memoria in Java utilizzando:

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

e poi tirandolo con questo codice (pardon gli spaghetti al momento):

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

    } 

Sto facendo qualcosa di inefficiente Qui? Qual è un buon modo per profilare il codice JNI?

Oltre a queste cose, l'unica cosa che posso pensare è che dovrò leggere di NEON e vettorializzare questa roba. Ugh ...

+2

Utilizzando un encoder ready made, dove qualcuno ha già fatto tutta l'ottimizzazione sensibile, sarebbe il primo passo logico. Inoltre, potrebbe essere consigliabile disaccoppiare la compressione dall'acquisizione. –

+1

L'allocazione della memoria in Java e il suo utilizzo in formato nativo causano scarse prestazioni. È possibile eseguire l'allocazione di memoria e l'I/O di file all'interno del codice nativo, che funzionerà molto meglio. Non posso commentare il tuo codice JPEG perché non l'hai condiviso, ma il mio codificatore/decodificatore JPEG nativo funziona bene su Android mantenendo tutto sul lato nativo. – BitBank

+0

@Seva, non rimarrà JPEG - alla fine si trasformerà in uno dei codificatori wavelet per i video, ma ho bisogno di una linea di base per assicurarmi che tutto si ottimizzi correttamente – Nick

risposta

0

provare a utilizzare il costruire in encoder:

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

Nella parte superiore del mio post, questo è in realtà ciò che faccio in origine. Tuttavia non è abbastanza veloce.Con il processore a 800 MHz del mio telefono, si tratta di circa 96 cicli di clock per campione di colore al fine di mantenere 18 fps. Dovrebbe essere certamente possibile in un modo o nell'altro. – Nick

+0

Suggerisco di verificare quale funzione occupa il tempo massimo di calcolo, semplicemente lasciando fuori una o più funzioni e misurando il tempo di ricezione dal lato del pc. Nota anche che esiste una streamer h264 per Android, http://code.google.com/p/ipcamera-for-android/ –